From eb2c17b22d341aab784dadbb4f80fc9e992eff3a Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 6 Mar 2015 16:51:57 +0100 Subject: [PATCH] Ship your dependencies as phars inside the phar Madness didn't stop, just have a look: $ cd pecl_http.git $ pharext -qps ../propro.git $ pharext -qps ../raphf.git $ pharext -qps . $ ./pecl_http-2.4.0dev.ext.phar --sudo Output: Installing propro-1.0.1.ext.phar ... Running phpize ... OK Running configure ... OK Running make ... OK Running install ... OK Cleaning up /tmp/propro-1.0.1.ext.phar.54f9cbc1488a0 ... Don't forget to activiate the extension in your php.ini! Installing raphf-1.0.5.ext.phar ... Running phpize ... OK Running configure ... OK Running make ... OK Running install ... OK Cleaning up /tmp/raphf-1.0.5.ext.phar.54f9cbc148a50 ... Don't forget to activiate the extension in your php.ini! Installing pecl_http-2.4.0dev.ext.phar ... Running phpize ... OK Running configure ... OK Running make ... OK Running install ... OK Cleaning up /tmp/pecl_http-2.4.0dev.ext.phar.54f9cbc14869f ... Don't forget to activiate the extension in your php.ini! --- bin/pharext | Bin 36120 -> 37537 bytes src/pharext/Installer.php | 98 +++++++++++++++++++--------------- src/pharext/Packager.php | 27 ++++++---- src/pharext/PeclSourceDir.php | 62 +++++++++++++++------ src/pharext_installer.php | 4 +- src/pharext_packager.php | 4 +- 6 files changed, 121 insertions(+), 74 deletions(-) diff --git a/bin/pharext b/bin/pharext index 30306c5d052ca0d58d83ceaa3ade2553823a96cd..8de8858ad01c58da9154fa238aa4a3275df75b23 100755 GIT binary patch delta 2445 zcma)8U2GIp6mAy;cKNYbfu&u_bh<6G+jbWb5w>;-~fYxwtD_VN#o&s5Gm*u0n@ z9$FXh`@?o#WBo~+Urcr!9?PpVk)V!YXhu%SsyZW)NMs;@b{6QQLCGM~5}GLs+75ta z)}%yD=OsnB@QX9jQBt&H=pU8)q%bjTTIx^ch&`+_GO8Ac0!gG9aK&;+!GbhiS&$7s zC<{A5HhylXeYQcnThoalLiR~EbqEwM!eVwdE}~B~b|JpRUr)4EY3Fl37O1ObyTt+pZlhO=ktGW&-S@ML32LGvh zZI1}>KXz_!7?uZmHXwSGq)&`b@X+?4&tI-=-X8HiQ!fgYqNZv=V6TW~=C@h*5U2?k zcPz<>BYOljaIaY=;_d zOny3H92*0S+{D#Pf-K$`G$U&&@?IA|psm!+q*yE_J!=5jCV^pI0tg~Vw@cSlhKxh> zfQix!e|6}EApAfeJJb1$hNxgeSTkQW)V7ioHCx&0HCQ<^FwxwGbZ~i))`@C3z)=qb ze)W-kymfHTp=z^+qw8+_B7?>lu^Ten$$GnBVR1+~^w3z!tBJG0-EtM`YJOU%r4~Nr zK;^!je+D{5GB}F5rP_H#4x@-$YI;h|kyx>y%Y0)`N7o3HgQztqBn{9CiOcs~-sRzsHt!VLF(miwcz`ueOdN{5*gScL9< zH9VED3h+&OdHjA4gA;@@Ks%K-3osj^0I%?2&Lp#e>)->@GMOURQpvLrNR34LZnK4C zciM`a5!X^s26*Vnl1B85RAXU7n_}t0nB5-Sl u<{7%^?o9a?XCDiV|NMr$_{tBr?2|{jkF5T3>e_{gZ+!4S&7R?r;r{>)6bEep delta 1224 zcmZ`(O>7fK6t=S$cdhX_ zAxbtxRS!t~MLdvFda5e8RH~}3glIVg4j|wH2vjb;lmkLSJ(LULfYg~;JF+U(vi-d8 z=lj0*BmZzkTD&a%vJjVMufm0RCpWj^A93?0-px&WqCN7qH58h?`euyVrgyupLm`ol zTv7rjx8I%paR$Cmyw3}6Cc3!!Cn3O4G8_5%y&#j@d$Gm+a5$;)ly8&mk%yrm#_jK~ zetil{$t^tgBAJcdt;M*#68h@SwJ`g^Uhv>l%Kv0v8_T;R8wkQ0~h*dzE zrWRfIYczl=lwhNz6I^laNvvCrX;<@DFB`O|rOHKv;1iU2E7Y*<56i`JDwD~e8AXPN z>DE;Oq+fxXz3G)I!R93V-5c{)_obz@c+^x{v?`f?MV3AGVQ=B+%+&zl{Cpdn8aTF1 zK-Pndkr*b`L>;T)dN-TJyhQ@M&Kxb3Va=Y6@H*Ed$+Ew4*U@lWBfM#2!>N`71ehKC z4DJq&v;`y_&8p~)XrK>$qBEfaSg_WmkWvF>y$?@O?n1X>X-V#KF~sEZ6l zajEPQgG?hvgH7s^X=vFRJGtB$pJ33JTCi-)_Hcj|_w|vg<5BdfbcE7;w^(eao+x?h%H?P(SM7(b+OWexDP z0)nS3C*K%=`SEn5AyJ$$ggc`C!l5%Cz{S2+==GXmpSKAfduze-x?y;t1(v)hd)@=< z=ROsFI@cq62(yK@ z*LICO^q=eXC(n@;{}+Uz3&Y8UBR_pHW8c`g^io-uQ1*s4{I+OF?C)Uj?$O=<0xoNk AZ~y=R diff --git a/src/pharext/Installer.php b/src/pharext/Installer.php index 57bbf06..19aad72 100644 --- a/src/pharext/Installer.php +++ b/src/pharext/Installer.php @@ -59,10 +59,25 @@ class Installer implements Command * @see \pharext\Command::run() */ public function run($argc, array $argv) { - if (($hook = stream_resolve_include_path("pharext_install.php"))) { - $callable = include $hook; - if (is_callable($callable)) { - $recv = $callable($this); + $this->cwd = getcwd(); + $this->tmp = $this->tempname(basename(Phar::running(false))); + + $phar = new Phar(Phar::running(false)); + foreach ($phar as $entry) { + if (fnmatch("*.ext.phar*", $entry->getBaseName())) { + $temp = $this->newtemp($entry->getBaseName()); + $phar->extractTo($temp, $entry->getFilename(), true); + $phars[$temp] = new Phar($temp."/".$entry->getFilename()); + } + } + $phars[$this->tmp] = $phar; + + foreach ($phars as $phar) { + if (($hook = $phar["pharext_install.php"])) { + $callable = include $phar["pharext_install.php"]; + if (is_callable($callable)) { + $recv[] = $callable($this); + } } } @@ -96,19 +111,39 @@ class Installer implements Command } if (isset($recv)) { - $recv($this); + foreach ($recv as $r) { + $r($this); + } + } + foreach ($phars as $temp => $phar) { + $this->installPackage($phar, $temp); } - - $this->installPackage(); + } + + private function newtemp($prefix) { + $temp = $this->tempname($prefix); + if (!is_dir($temp)) { + if (!mkdir($temp, 0750, true)) { + $this->error(null); + exit(3); + } + } + return $temp; } /** * Prepares, configures, builds and installs the extension */ - private function installPackage() { - $this->extract(); + private function installPackage(Phar $phar, $temp) { + $this->info("Installing %s ... \n", basename($phar->getAlias())); + try { + $phar->extractTo($temp, null, true); + } catch (\Exception $e) { + $this->error("%s\n", $e->getMessage()); + exit(3); + } - if (!chdir($this->tmp)) { + if (!chdir($temp)) { $this->error(null); exit(4); } @@ -119,50 +154,25 @@ class Installer implements Command $this->exec("make", $this->args->verbose ? "make -j3" : "make -sj3"); $this->exec("install", $this->args->verbose ? "make install" : "make -s install", true); - $this->cleanup(); + $this->cleanup($temp); - $this->info("\nDon't forget to activiate the extension in your php.ini!\n"); + $this->info("Don't forget to activiate the extension in your php.ini!\n\n"); } /** * Perform any cleanups */ - private function cleanup() { - if (is_dir($this->tmp)) { + private function cleanup($temp = null) { + if (!isset($temp)) { + $temp = $this->tmp; + } + if (is_dir($temp)) { chdir($this->cwd); - $this->info("Cleaning up %s ...\n", $this->tmp); - $this->rm($this->tmp); + $this->info("Cleaning up %s ...\n", $temp); + $this->rm($temp); } } - /** - * Extract the phar to a temporary directory - */ - private function extract() { - if (!$file = Phar::running(false)) { - $this->error("Did your run the ext.phar?\n"); - exit(3); - } - - $temp = $this->tempname(basename($file)); - if (!is_dir($temp)) { - if (!mkdir($temp, 0750, true)) { - $this->error(null); - exit(3); - } - } - $this->tmp = $temp; - $this->cwd = getcwd(); - - try { - $phar = new Phar($file); - $phar->extractTo($temp, null, true); - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(3); - } - } - /** * rm -r * @param string $dir diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index 0b133e3..f27c38a 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -64,17 +64,21 @@ class Packager implements Command $this->help($prog); exit; } - - if ($this->args["source"]) { - if ($this->args["pecl"]) { - $this->source = new PeclSourceDir($this, $this->args["source"]); - } elseif ($this->args["git"]) { - $this->source = new GitSourceDir($this, $this->args["source"]); - } elseif (realpath($this->args["source"]."/pharext_package.php")) { - $this->source = new PharextSourceDir($this, $this->args["source"]); - } else { - $this->source = new FilteredSourceDir($this, $this->args["source"]); + + try { + if ($this->args["source"]) { + if ($this->args["pecl"]) { + $this->source = new PeclSourceDir($this, $this->args["source"]); + } elseif ($this->args["git"]) { + $this->source = new GitSourceDir($this, $this->args["source"]); + } elseif (realpath($this->args["source"]."/pharext_package.php")) { + $this->source = new PharextSourceDir($this, $this->args["source"]); + } else { + $this->source = new FilteredSourceDir($this, $this->args["source"]); + } } + } catch (\Exception $e) { + $errs[] = $e->getMessage(); } foreach ($this->args->validate() as $error) { @@ -88,6 +92,7 @@ class Packager implements Command foreach ($errs as $err) { $this->error("%s\n", $err); } + printf("\n"); if (!$this->args["quiet"]) { $this->help($prog); } @@ -119,7 +124,7 @@ class Packager implements Command $this->info("Creating phar %s ...%s", $pkgtemp, $this->args->verbose ? "\n" : " "); try { - $package = new Phar($pkgtemp, 0, "ext.phar"); + $package = new Phar($pkgtemp); $package->startBuffering(); $package->buildFromIterator($this->source, $this->source->getBaseDir()); $package->buildFromIterator($this->bundle()); diff --git a/src/pharext/PeclSourceDir.php b/src/pharext/PeclSourceDir.php index ca065ad..1e6d86e 100644 --- a/src/pharext/PeclSourceDir.php +++ b/src/pharext/PeclSourceDir.php @@ -36,6 +36,9 @@ class PeclSourceDir implements \IteratorAggregate, SourceDir * @see \pharext\SourceDir::__construct() */ public function __construct(Command $cmd, $path) { + if (!realpath("$path/package.xml")) { + throw new \Exception("Missing package.xml in $path"); + } $sxe = simplexml_load_file("$path/package.xml"); $sxe->registerXPathNamespace("pecl", $sxe->getDocNamespaces()[""]); @@ -54,18 +57,6 @@ class PeclSourceDir implements \IteratorAggregate, SourceDir } } - if (($configure = $sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption"))) { - $this->hook = tmpfile(); - ob_start(function($s) { - fwrite($this->hook, $s); - return null; - }); - call_user_func(function() use ($configure) { - include __DIR__."/../pharext_install.tpl.php"; - }); - ob_end_flush(); - } - $this->cmd = $cmd; $this->sxe = $sxe; $this->path = $path; @@ -91,15 +82,56 @@ class PeclSourceDir implements \IteratorAggregate, SourceDir } return trim($path, "/"); } + + /** + * Render installer hook + * @param array $configure + * @return string + */ + private static function loadHook($configure, $dependencies) { + return include __DIR__."/../pharext_install.tpl.php"; + } + + /** + * Create installer hook + * @return resource + */ + private function generateHooks() { + $dependencies = $this->sxe->xpath("/pecl:package/pecl:dependencies/pecl:required/pecl:package"); + foreach ($dependencies as $key => $dep) { + if (($glob = glob("{$this->path}/{$dep->name}-*.ext.phar*"))) { + usort($glob, function($a, $b) { + return version_compare( + substr($a, strpos(".ext.phar", $a)), + substr($b, strpos(".ext.phar", $b)) + ); + }); + yield realpath($this->path."/".end($glob)); + } else { + unset($dependencies[$key]); + } + } + $configure = $this->sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption"); + if ($configure) { + $fd = tmpfile(); + ob_start(function($s) use($fd){ + fwrite($fd, $s); + return null; + }); + self::loadHook($configure, $dependencies); + ob_end_flush(); + rewind($fd); + yield "pharext_install.php" => $fd; + } + } /** * Generate a list of files from the package.xml * @return Generator */ private function generateFiles() { - if ($this->hook) { - rewind($this->hook); - yield "pharext_install.php" => $this->hook; + foreach ($this->generateHooks() as $file => $hook) { + yield $file => $hook; } foreach ($this->sxe->xpath("//pecl:file") as $file) { $path = $this->path ."/". $this->dirOf($file) ."/". $file["name"]; diff --git a/src/pharext_installer.php b/src/pharext_installer.php index 90c9f50..89e44a3 100644 --- a/src/pharext_installer.php +++ b/src/pharext_installer.php @@ -3,9 +3,9 @@ * The installer sub-stub for extension phars */ -function __autoload($c) { +spl_autoload_register(function($c) { return include strtr($c, "\\_", "//") . ".php"; -} +}); $installer = new pharext\Installer(); $installer->run($argc, $argv); diff --git a/src/pharext_packager.php b/src/pharext_packager.php index b72da8a..125db61 100644 --- a/src/pharext_packager.php +++ b/src/pharext_packager.php @@ -3,9 +3,9 @@ * The packager sub-stub for bin/pharext */ -function __autoload($c) { +spl_autoload_register(function($c) { return include strtr($c, "\\_", "//") . ".php"; -} +}); $packager = new pharext\Packager(); $packager->run($argc, $argv); -- 2.30.2