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