From: Michael Wallner Date: Fri, 6 Mar 2015 15:51:57 +0000 (+0100) Subject: Ship your dependencies as phars inside the phar X-Git-Tag: v1.1.0~5 X-Git-Url: https://git.m6w6.name/?p=pharext%2Fpharext;a=commitdiff_plain;h=eb2c17b22d341aab784dadbb4f80fc9e992eff3a 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! --- diff --git a/bin/pharext b/bin/pharext index 30306c5..8de8858 100755 Binary files a/bin/pharext and b/bin/pharext differ 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);