9ca97264c480923817c1b5e1f808954888c8cf33
[pharext/pharext] / src / pharext / SourceDir / Pecl.php
1 <?php
2
3 namespace pharext\SourceDir;
4
5 use pharext\Command;
6 use pharext\Exception;
7 use pharext\SourceDir;
8
9 /**
10 * A PECL extension source directory containing a v2 package.xml
11 */
12 class Pecl implements \IteratorAggregate, SourceDir
13 {
14 /**
15 * The Packager command
16 * @var pharext\Packager
17 */
18 private $cmd;
19
20 /**
21 * The package.xml
22 * @var SimpleXmlElement
23 */
24 private $sxe;
25
26 /**
27 * The base directory
28 * @var string
29 */
30 private $path;
31
32 /**
33 * @inheritdoc
34 * @see \pharext\SourceDir::__construct()
35 */
36 public function __construct(Command $cmd, $path) {
37 if (realpath("$path/package2.xml")) {
38 $sxe = simplexml_load_file("$path/package2.xml");
39 } elseif (realpath("$path/package.xml")) {
40 $sxe = simplexml_load_file("$path/package.xml");
41 } else {
42 throw new Exception("Missing package.xml in $path");
43 }
44 $sxe->registerXPathNamespace("pecl", $sxe->getDocNamespaces()[""]);
45
46 $args = $cmd->getArgs();
47 if (!isset($args->name)) {
48 $name = (string) $sxe->xpath("/pecl:package/pecl:name")[0];
49 foreach ($args->parse(2, ["--name", $name]) as $error) {
50 $cmd->warn("%s\n", $error);
51 }
52 }
53
54 if (!isset($args->release)) {
55 $release = (string) $sxe->xpath("/pecl:package/pecl:version/pecl:release")[0];
56 foreach ($args->parse(2, ["--release", $release]) as $error) {
57 $cmd->warn("%s\n", $error);
58 }
59 }
60 if (!isset($args->zend)) {
61 if ($sxe->xpath("/pecl:package/pecl:zendextsrcrelease")) {
62 foreach ($args->parse(1, ["--zend"]) as $error) {
63 $cmd->warn("%s\n", $error);
64 }
65 }
66 }
67
68 $this->cmd = $cmd;
69 $this->sxe = $sxe;
70 $this->path = $path;
71 }
72
73 /**
74 * @inheritdoc
75 * @see \pharext\SourceDir::getBaseDir()
76 */
77 public function getBaseDir() {
78 return $this->path;
79 }
80
81 /**
82 * Compute the path of a file by parent dir nodes
83 * @param \SimpleXMLElement $ele
84 * @return string
85 */
86 private function dirOf($ele) {
87 $path = "";
88 while (($ele = current($ele->xpath(".."))) && $ele->getName() == "dir") {
89 $path = trim($ele["name"], "/") ."/". $path ;
90 }
91 return trim($path, "/");
92 }
93
94 /**
95 * Render installer hook
96 * @param array $configure
97 * @return string
98 */
99 private static function loadHook($configure, $dependencies) {
100 require_once "pharext/Version.php";
101 return include __DIR__."/../../pharext_install.tpl.php";
102 }
103
104 /**
105 * Create installer hook
106 * @return \Generator
107 */
108 private function generateHooks() {
109 $dependencies = $this->sxe->xpath("/pecl:package/pecl:dependencies/pecl:required/pecl:package");
110 foreach ($dependencies as $key => $dep) {
111 if (($glob = glob("{$this->path}/{$dep->name}-*.ext.phar*"))) {
112 usort($glob, function($a, $b) {
113 return version_compare(
114 substr($a, strpos(".ext.phar", $a)),
115 substr($b, strpos(".ext.phar", $b))
116 );
117 });
118 yield end($glob);
119 } else {
120 unset($dependencies[$key]);
121 }
122 }
123 $configure = $this->sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption");
124 if ($configure) {
125 $fd = tmpfile();
126 ob_start(function($s) use($fd){
127 fwrite($fd, $s);
128 return null;
129 });
130 self::loadHook($configure, $dependencies);
131 ob_end_flush();
132 rewind($fd);
133 yield "pharext_install.php" => $fd;
134 }
135 }
136
137 /**
138 * Generate a list of files from the package.xml
139 * @return Generator
140 */
141 private function generateFiles() {
142 foreach ($this->generateHooks() as $file => $hook) {
143 if ($this->cmd->getArgs()->verbose) {
144 $this->cmd->info("Packaging %s\n", is_scalar($hook) ? $hook : $file);
145 }
146 yield $file => $hook;
147 }
148 foreach ($this->sxe->xpath("//pecl:file") as $file) {
149 $path = $this->path ."/". $this->dirOf($file) ."/". $file["name"];
150 if ($this->cmd->getArgs()->verbose) {
151 $this->cmd->info("Packaging %s\n", substr($path, strlen($this->path)));
152 }
153 if (!($realpath = realpath($path))) {
154 $this->cmd->warn("File %s does not exist", $path);
155 }
156 yield $realpath;
157 }
158 }
159
160 /**
161 * Implements IteratorAggregate
162 * @see IteratorAggregate::getIterator()
163 */
164 public function getIterator() {
165 return $this->generateFiles();
166 }
167 }