reorder code and files, remove the filtered source dir implementation
authorMichael Wallner <mike@php.net>
Sun, 8 Mar 2015 19:42:03 +0000 (20:42 +0100)
committerMichael Wallner <mike@php.net>
Mon, 9 Mar 2015 07:51:20 +0000 (08:51 +0100)
19 files changed:
Makefile
bin/pharext
src/pharext/Cli/Args.php [new file with mode: 0644]
src/pharext/Cli/Command.php [new file with mode: 0644]
src/pharext/CliArgs.php [deleted file]
src/pharext/CliCommand.php [deleted file]
src/pharext/FilteredSourceDir.php [deleted file]
src/pharext/GitSourceDir.php [deleted file]
src/pharext/Installer.php
src/pharext/Openssl/PrivateKey.php
src/pharext/Packager.php
src/pharext/PeclSourceDir.php [deleted file]
src/pharext/PharextSourceDir.php [deleted file]
src/pharext/SourceDir/Git.php [new file with mode: 0644]
src/pharext/SourceDir/Pecl.php [new file with mode: 0644]
src/pharext/SourceDir/Pharext.php [new file with mode: 0644]
src/pharext_install.tpl.php
src/pharext_packager.php
tests/src/pharext/FilteredSourceDirTest.php [deleted file]

index 10271865c90e708a9411e959da98c17f4c884db3..cc88f708d7f39c6fe91087971ffb2b1d709f994c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
 
 all: bin/pharext
 
-bin/pharext: src/* src/pharext/*
+bin/pharext: src/* src/pharext/* src/pharext/*/*
        @echo "Linting changed source files ... "
        @for file in $?; do php -l $$file | sed -ne '/^No syntax errors/!p' && exit $${PIPESTATUS[0]}; done
        @echo "Creating bin/pharext ... "
index 76396714bb29123affc8317d1e3c3176596f018f..c0c47e4762f0c695e129d539cfc19ab25de5214d 100755 (executable)
Binary files a/bin/pharext and b/bin/pharext differ
diff --git a/src/pharext/Cli/Args.php b/src/pharext/Cli/Args.php
new file mode 100644 (file)
index 0000000..49d85ab
--- /dev/null
@@ -0,0 +1,332 @@
+<?php
+
+namespace pharext\Cli;
+
+/**
+ * Command line arguments
+ */
+class Args implements \ArrayAccess
+{
+       /**
+        * Optional option
+        */
+       const OPTIONAL = 0x000;
+       
+       /**
+        * Required Option
+        */
+       const REQUIRED = 0x001;
+       
+       /**
+        * Only one value, even when used multiple times
+        */
+       const SINGLE = 0x000;
+       
+       /**
+        * Aggregate an array, when used multiple times
+        */
+       const MULTI = 0x010;
+       
+       /**
+        * Option takes no argument
+        */
+       const NOARG = 0x000;
+       
+       /**
+        * Option requires an argument
+        */
+       const REQARG = 0x100;
+       
+       /**
+        * Option takes an optional argument
+        */
+       const OPTARG = 0x200;
+       
+       /**
+        * Option halts processing
+        */
+       const HALT = 0x10000000;
+       
+       /**
+        * Original option spec
+        * @var array
+        */
+       private $orig = [];
+       
+       /**
+        * Compiled spec
+        * @var array
+        */
+       private $spec = [];
+       
+       /**
+        * Parsed args
+        * @var array
+        */
+       private $args = [];
+
+       /**
+        * Compile the original spec
+        * @param array $spec
+        */
+       public function __construct(array $spec = null) {
+               $this->compile($spec);
+       }
+       
+       /**
+        * Compile the original spec
+        * @param array $spec
+        * @return pharext\CliArgs self
+        */
+       public function compile(array $spec = null) {
+               $this->orig = array_merge($this->orig, (array) $spec);
+               foreach ((array) $spec as $arg) {
+                       if (isset($arg[0])) { 
+                               $this->spec["-".$arg[0]] = $arg;
+                       }
+                       $this->spec["--".$arg[1]] = $arg;
+               }
+               return $this;
+       }
+       
+       /**
+        * Get original spec
+        * @return array
+        */
+       public function getSpec() {
+               return $this->orig;
+       }
+       
+       /**
+        * Get compiled spec
+        * @return array
+        */
+       public function getCompiledSpec() {
+               return $this->spec;
+       }
+       
+       /**
+        * Parse command line arguments according to the compiled spec.
+        * 
+        * The Generator yields any parsing errors.
+        * Parsing will stop when all arguments are processed or the first option
+        * flagged CliArgs::HALT was encountered.
+        * 
+        * @param int $argc
+        * @param array $argv
+        * @return Generator
+        */
+       public function parse($argc, array $argv) {
+               for ($i = 0; $i < $argc; ++$i) {
+                       $o = $argv[$i];
+                       
+                       if ($o{0} === '-' && strlen($o) > 2 && $o{1} !== '-') {
+                               // multiple short opts, .e.g -vps
+                               $argc += strlen($o) - 2;
+                               array_splice($argv, $i, 1, array_map(function($s) {
+                                       return "-$s";
+                               }, str_split(substr($o, 1))));
+                               $o = $argv[$i];
+                       } elseif ($o{0} === '-' && strlen($o) > 2 && $o{1} === '-' && 0 < ($eq = strpos($o, "="))) {
+                               $argc++;
+                               array_splice($argv, $i, 1, [
+                                       substr($o, 0, $eq++),
+                                       substr($o, $eq)
+                               ]);
+                               $o = $argv[$i];
+                       }
+
+                       if (!isset($this->spec[$o])) {
+                               yield sprintf("Unknown option %s", $o);
+                       } elseif (!$this->optAcceptsArg($o)) {
+                               $this[$o] = true;
+                       } elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) {
+                               $this[$o] = $argv[++$i];
+                       } elseif ($this->optRequiresArg($o)) {
+                               yield sprintf("Option --%s requires an argument", $this->optLongName($o));
+                       } else {
+                               // OPTARG
+                               $this[$o] = $this->optDefaultArg($o);
+                       }
+                       
+                       if ($this->optHalts($o)) {
+                               return;
+                       }
+               }
+       }
+       
+       /**
+        * Validate that all required options were given.
+        * 
+        * The Generator yields any validation errors.
+        * 
+        * @return Generator
+        */
+       public function validate() {
+               $required = array_filter($this->orig, function($spec) {
+                       return $spec[3] & self::REQUIRED;
+               });
+               foreach ($required as $req) {
+                       if (!isset($this[$req[0]])) {
+                               yield sprintf("Option --%s is required", $req[1]);
+                       }
+               }
+       }
+       
+       /**
+        * Retreive the default argument of an option
+        * @param string $o
+        * @return mixed
+        */
+       private function optDefaultArg($o) {
+               $o = $this->opt($o);
+               if (isset($this->spec[$o][4])) {
+                       return $this->spec[$o][4];
+               }
+               return null;
+       }
+       
+       /**
+        * Retrieve the help message of an option
+        * @param string $o
+        * @return string
+        */
+       private function optHelp($o) {
+               $o = $this->opt($o);
+               if (isset($this->spec[$o][2])) {
+                       return $this->spec[$o][2];
+               }
+               return "";
+       }
+
+       /**
+        * Retrieve option's flags
+        * @param string $o
+        * @return int
+        */
+       private function optFlags($o) {
+               $o = $this->opt($o);
+               if (isset($this->spec[$o])) {
+                       return $this->spec[$o][3];
+               }
+               return null;
+       }
+       
+       /**
+        * Check whether an option is flagged for halting argument processing
+        * @param string $o
+        * @return boolean
+        */
+       private function optHalts($o) {
+               return $this->optFlags($o) & self::HALT;
+       }
+       
+       /**
+        * Check whether an option needs an argument
+        * @param string $o
+        * @return boolean
+        */
+       private function optRequiresArg($o) {
+               return $this->optFlags($o) & self::REQARG;
+       }
+       
+       /**
+        * Check wether an option accepts any argument
+        * @param string $o
+        * @return boolean
+        */
+       private function optAcceptsArg($o) {
+               return $this->optFlags($o) & 0xf00;
+       }
+       
+       /**
+        * Check whether an option can be used more than once
+        * @param string $o
+        * @return boolean
+        */
+       private function optIsMulti($o) {
+               return $this->optFlags($o) & self::MULTI;
+       }
+       
+       /**
+        * Retreive the long name of an option
+        * @param string $o
+        * @return string
+        */
+       private function optLongName($o) {
+               $o = $this->opt($o);
+               return $this->spec[$o][1];
+       }
+       
+       /**
+        * Retreive the short name of an option
+        * @param string $o
+        * @return string
+        */
+       private function optShortName($o) {
+               $o = $this->opt($o);
+               return $this->spec[$o][0];
+       }
+       
+       /**
+        * Retreive the canonical name (--long-name) of an option
+        * @param string $o
+        * @return string
+        */
+       private function opt($o) {
+               if ($o{0} !== '-') {
+                       if (strlen($o) > 1) {
+                               $o = "-$o";
+                       }
+                       $o = "-$o";
+               }
+               return $o;
+       }
+       
+       /**@+
+        * Implements ArrayAccess and virtual properties
+        */
+       function offsetExists($o) {
+               $o = $this->opt($o);
+               return isset($this->args[$o]);
+       }
+       function __isset($o) {
+               return $this->offsetExists($o);
+       }
+       function offsetGet($o) {
+               $o = $this->opt($o);
+               if (isset($this->args[$o])) {
+                       return $this->args[$o];
+               }
+               return $this->optDefaultArg($o);
+       }
+       function __get($o) {
+               return $this->offsetGet($o);
+       }
+       function offsetSet($o, $v) {
+               $osn = $this->optShortName($o);
+               $oln = $this->optLongName($o);
+               if ($this->optIsMulti($o)) {
+                       if (isset($osn)) {
+                               $this->args["-$osn"][] = $v;
+                       }
+                       $this->args["--$oln"][] = $v;
+               } else {
+                       if (isset($osn)) {
+                               $this->args["-$osn"] = $v;
+                       }
+                       $this->args["--$oln"] = $v;
+               }
+       }
+       function __set($o, $v) {
+               $this->offsetSet($o, $v);
+       }
+       function offsetUnset($o) {
+               unset($this->args["-".$this->optShortName($o)]);
+               unset($this->args["--".$this->optLongName($o)]);
+       }
+       function __unset($o) {
+               $this->offsetUnset($o);
+       }
+       /**@-*/
+}
diff --git a/src/pharext/Cli/Command.php b/src/pharext/Cli/Command.php
new file mode 100644 (file)
index 0000000..0ec52ff
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+
+namespace pharext\Cli;
+
+use pharext\Cli\Args as CliArgs;
+
+require_once "pharext/Version.php";
+
+trait Command
+{
+       /**
+        * Command line arguments
+        * @var pharext\CliArgs
+        */
+       private $args;
+       
+       /**
+        * @inheritdoc
+        * @see \pharext\Command::getArgs()
+        */
+       public function getArgs() {
+               return $this->args;
+       }
+
+       /**
+        * Output pharext vX.Y.Z header
+        */
+       function header() {
+               printf("pharext v%s (c) Michael Wallner <mike@php.net>\n\n", 
+                       \pharext\VERSION);
+       }
+       
+       /**
+        * @inheritdoc
+        * @see \pharext\Command::info()
+        */
+       public function info($fmt) {
+               if (!$this->args->quiet) {
+                       vprintf($fmt, array_slice(func_get_args(), 1));
+               }
+       }
+
+       /**
+        * @inheritdoc
+        * @see \pharext\Command::error()
+        */
+       public function error($fmt) {
+               if (!$this->args->quiet) {
+                       if (!isset($fmt)) {
+                               $fmt = "%s\n";
+                               $arg = error_get_last()["message"];
+                       } else {
+                               $arg = array_slice(func_get_args(), 1);
+                       }
+                       vfprintf(STDERR, "ERROR: $fmt", $arg);
+               }
+       }
+
+       /**
+        * Output command line help message
+        * @param string $prog
+        */
+       public function help($prog) {
+               printf("Usage:\n\n  \$ %s", $prog);
+               
+               $flags = [];
+               $required = [];
+               $optional = [];
+               foreach ($this->args->getSpec() as $spec) {
+                       if ($spec[3] & CliArgs::REQARG) {
+                               if ($spec[3] & CliArgs::REQUIRED) {
+                                       $required[] = $spec;
+                               } else {
+                                       $optional[] = $spec;
+                               }
+                       } else {
+                               $flags[] = $spec;
+                       }
+               }
+       
+               if ($flags) {
+                       printf(" [-%s]", implode("", array_column($flags, 0)));
+               }
+               foreach ($required as $req) {
+                       printf(" -%s <arg>", $req[0]);
+               }
+               if ($optional) {
+                       printf(" [-%s <arg>]", implode("|-", array_column($optional, 0)));
+               }
+               printf("\n\n");
+               $spc = $this->args->getSpec();
+               $max = max(array_map("strlen", array_column($spc, 1)));
+               $max += $max % 8 + 2;
+               foreach ($spc as $spec) {
+                       if (isset($spec[0])) {
+                               printf("    -%s|", $spec[0]);
+                       } else {
+                               printf("    ");
+                       }
+                       printf("--%s ", $spec[1]);
+                       if ($spec[3] & CliArgs::REQARG) {
+                               printf("<arg>  ");
+                       } elseif ($spec[3] & CliArgs::OPTARG) {
+                               printf("[<arg>]");
+                       } else {
+                               printf("       ");
+                       }
+                       printf("%s%s", str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0])), $spec[2]);
+                       if ($spec[3] & CliArgs::REQUIRED) {
+                               printf(" (REQUIRED)");
+                       }
+                       if (isset($spec[4])) {
+                               printf(" [%s]", $spec[4]);
+                       }
+                       printf("\n");
+               }
+               printf("\n");
+       }
+       
+       /**
+        * Create temporary file/directory name
+        * @param string $prefix
+        * @param string $suffix
+        */
+       private function tempname($prefix, $suffix = null) {
+               if (!isset($suffix)) {
+                       $suffix = uniqid();
+               }
+               return sprintf("%s/%s.%s", sys_get_temp_dir(), $prefix, $suffix);
+       }
+
+       /**
+        * Create a new temp directory
+        * @param string $prefix
+        * @return string
+        */
+       private function newtemp($prefix) {
+               $temp = $this->tempname($prefix);
+               if (!is_dir($temp)) {
+                       if (!mkdir($temp, 0700, true)) {
+                               $this->error(null);
+                               exit(3);
+                       }
+               }
+               return $temp;
+       }
+
+       /**
+        * rm -r
+        * @param string $dir
+        */
+       private function rm($dir) {
+               foreach (scandir($dir) as $entry) {
+                       if ($entry === "." || $entry === "..") {
+                               continue;
+                       } elseif (is_dir("$dir/$entry")) {
+                               $this->rm("$dir/$entry");
+                       } elseif (!unlink("$dir/$entry")) {
+                               $this->error(null);
+                       }
+               }
+               if (!rmdir($dir)) {
+                       $this->error(null);
+               }
+       }
+}
diff --git a/src/pharext/CliArgs.php b/src/pharext/CliArgs.php
deleted file mode 100644 (file)
index 717bc00..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-<?php
-
-namespace pharext;
-
-/**
- * Command line arguments
- */
-class CliArgs implements \ArrayAccess
-{
-       /**
-        * Optional option
-        */
-       const OPTIONAL = 0x000;
-       
-       /**
-        * Required Option
-        */
-       const REQUIRED = 0x001;
-       
-       /**
-        * Only one value, even when used multiple times
-        */
-       const SINGLE = 0x000;
-       
-       /**
-        * Aggregate an array, when used multiple times
-        */
-       const MULTI = 0x010;
-       
-       /**
-        * Option takes no argument
-        */
-       const NOARG = 0x000;
-       
-       /**
-        * Option requires an argument
-        */
-       const REQARG = 0x100;
-       
-       /**
-        * Option takes an optional argument
-        */
-       const OPTARG = 0x200;
-       
-       /**
-        * Option halts processing
-        */
-       const HALT = 0x10000000;
-       
-       /**
-        * Original option spec
-        * @var array
-        */
-       private $orig = [];
-       
-       /**
-        * Compiled spec
-        * @var array
-        */
-       private $spec = [];
-       
-       /**
-        * Parsed args
-        * @var array
-        */
-       private $args = [];
-
-       /**
-        * Compile the original spec
-        * @param array $spec
-        */
-       public function __construct(array $spec = null) {
-               $this->compile($spec);
-       }
-       
-       /**
-        * Compile the original spec
-        * @param array $spec
-        * @return pharext\CliArgs self
-        */
-       public function compile(array $spec = null) {
-               $this->orig = array_merge($this->orig, (array) $spec);
-               foreach ((array) $spec as $arg) {
-                       if (isset($arg[0])) { 
-                               $this->spec["-".$arg[0]] = $arg;
-                       }
-                       $this->spec["--".$arg[1]] = $arg;
-               }
-               return $this;
-       }
-       
-       /**
-        * Get original spec
-        * @return array
-        */
-       public function getSpec() {
-               return $this->orig;
-       }
-       
-       /**
-        * Get compiled spec
-        * @return array
-        */
-       public function getCompiledSpec() {
-               return $this->spec;
-       }
-       
-       /**
-        * Parse command line arguments according to the compiled spec.
-        * 
-        * The Generator yields any parsing errors.
-        * Parsing will stop when all arguments are processed or the first option
-        * flagged CliArgs::HALT was encountered.
-        * 
-        * @param int $argc
-        * @param array $argv
-        * @return Generator
-        */
-       public function parse($argc, array $argv) {
-               for ($i = 0; $i < $argc; ++$i) {
-                       $o = $argv[$i];
-                       
-                       if ($o{0} === '-' && strlen($o) > 2 && $o{1} !== '-') {
-                               // multiple short opts, .e.g -vps
-                               $argc += strlen($o) - 2;
-                               array_splice($argv, $i, 1, array_map(function($s) {
-                                       return "-$s";
-                               }, str_split(substr($o, 1))));
-                               $o = $argv[$i];
-                       } elseif ($o{0} === '-' && strlen($o) > 2 && $o{1} === '-' && 0 < ($eq = strpos($o, "="))) {
-                               $argc++;
-                               array_splice($argv, $i, 1, [
-                                       substr($o, 0, $eq++),
-                                       substr($o, $eq)
-                               ]);
-                               $o = $argv[$i];
-                       }
-
-                       if (!isset($this->spec[$o])) {
-                               yield sprintf("Unknown option %s", $o);
-                       } elseif (!$this->optAcceptsArg($o)) {
-                               $this[$o] = true;
-                       } elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) {
-                               $this[$o] = $argv[++$i];
-                       } elseif ($this->optRequiresArg($o)) {
-                               yield sprintf("Option --%s requires an argument", $this->optLongName($o));
-                       } else {
-                               // OPTARG
-                               $this[$o] = $this->optDefaultArg($o);
-                       }
-                       
-                       if ($this->optHalts($o)) {
-                               return;
-                       }
-               }
-       }
-       
-       /**
-        * Validate that all required options were given.
-        * 
-        * The Generator yields any validation errors.
-        * 
-        * @return Generator
-        */
-       public function validate() {
-               $required = array_filter($this->orig, function($spec) {
-                       return $spec[3] & self::REQUIRED;
-               });
-               foreach ($required as $req) {
-                       if (!isset($this[$req[0]])) {
-                               yield sprintf("Option --%s is required", $req[1]);
-                       }
-               }
-       }
-       
-       /**
-        * Retreive the default argument of an option
-        * @param string $o
-        * @return mixed
-        */
-       private function optDefaultArg($o) {
-               $o = $this->opt($o);
-               if (isset($this->spec[$o][4])) {
-                       return $this->spec[$o][4];
-               }
-               return null;
-       }
-       
-       /**
-        * Retrieve the help message of an option
-        * @param string $o
-        * @return string
-        */
-       private function optHelp($o) {
-               $o = $this->opt($o);
-               if (isset($this->spec[$o][2])) {
-                       return $this->spec[$o][2];
-               }
-               return "";
-       }
-
-       /**
-        * Retrieve option's flags
-        * @param string $o
-        * @return int
-        */
-       private function optFlags($o) {
-               $o = $this->opt($o);
-               if (isset($this->spec[$o])) {
-                       return $this->spec[$o][3];
-               }
-               return null;
-       }
-       
-       /**
-        * Check whether an option is flagged for halting argument processing
-        * @param string $o
-        * @return boolean
-        */
-       private function optHalts($o) {
-               return $this->optFlags($o) & self::HALT;
-       }
-       
-       /**
-        * Check whether an option needs an argument
-        * @param string $o
-        * @return boolean
-        */
-       private function optRequiresArg($o) {
-               return $this->optFlags($o) & self::REQARG;
-       }
-       
-       /**
-        * Check wether an option accepts any argument
-        * @param string $o
-        * @return boolean
-        */
-       private function optAcceptsArg($o) {
-               return $this->optFlags($o) & 0xf00;
-       }
-       
-       /**
-        * Check whether an option can be used more than once
-        * @param string $o
-        * @return boolean
-        */
-       private function optIsMulti($o) {
-               return $this->optFlags($o) & self::MULTI;
-       }
-       
-       /**
-        * Retreive the long name of an option
-        * @param string $o
-        * @return string
-        */
-       private function optLongName($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][1];
-       }
-       
-       /**
-        * Retreive the short name of an option
-        * @param string $o
-        * @return string
-        */
-       private function optShortName($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][0];
-       }
-       
-       /**
-        * Retreive the canonical name (--long-name) of an option
-        * @param string $o
-        * @return string
-        */
-       private function opt($o) {
-               if ($o{0} !== '-') {
-                       if (strlen($o) > 1) {
-                               $o = "-$o";
-                       }
-                       $o = "-$o";
-               }
-               return $o;
-       }
-       
-       /**@+
-        * Implements ArrayAccess and virtual properties
-        */
-       function offsetExists($o) {
-               $o = $this->opt($o);
-               return isset($this->args[$o]);
-       }
-       function __isset($o) {
-               return $this->offsetExists($o);
-       }
-       function offsetGet($o) {
-               $o = $this->opt($o);
-               if (isset($this->args[$o])) {
-                       return $this->args[$o];
-               }
-               return $this->optDefaultArg($o);
-       }
-       function __get($o) {
-               return $this->offsetGet($o);
-       }
-       function offsetSet($o, $v) {
-               $osn = $this->optShortName($o);
-               $oln = $this->optLongName($o);
-               if ($this->optIsMulti($o)) {
-                       if (isset($osn)) {
-                               $this->args["-$osn"][] = $v;
-                       }
-                       $this->args["--$oln"][] = $v;
-               } else {
-                       if (isset($osn)) {
-                               $this->args["-$osn"] = $v;
-                       }
-                       $this->args["--$oln"] = $v;
-               }
-       }
-       function __set($o, $v) {
-               $this->offsetSet($o, $v);
-       }
-       function offsetUnset($o) {
-               unset($this->args["-".$this->optShortName($o)]);
-               unset($this->args["--".$this->optLongName($o)]);
-       }
-       function __unset($o) {
-               $this->offsetUnset($o);
-       }
-       /**@-*/
-}
diff --git a/src/pharext/CliCommand.php b/src/pharext/CliCommand.php
deleted file mode 100644 (file)
index 9ae9989..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-
-namespace pharext;
-
-require_once __DIR__."/Version.php";
-
-trait CliCommand
-{
-       /**
-        * Command line arguments
-        * @var pharext\CliArgs
-        */
-       private $args;
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\Command::getArgs()
-        */
-       public function getArgs() {
-               return $this->args;
-       }
-
-       /**
-        * Output pharext vX.Y.Z header
-        */
-       function header() {
-               printf("pharext v%s (c) Michael Wallner <mike@php.net>\n\n", VERSION);
-       }
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\Command::info()
-        */
-       public function info($fmt) {
-               if (!$this->args->quiet) {
-                       vprintf($fmt, array_slice(func_get_args(), 1));
-               }
-       }
-
-       /**
-        * @inheritdoc
-        * @see \pharext\Command::error()
-        */
-       public function error($fmt) {
-               if (!$this->args->quiet) {
-                       if (!isset($fmt)) {
-                               $fmt = "%s\n";
-                               $arg = error_get_last()["message"];
-                       } else {
-                               $arg = array_slice(func_get_args(), 1);
-                       }
-                       vfprintf(STDERR, "ERROR: $fmt", $arg);
-               }
-       }
-
-       /**
-        * Output command line help message
-        * @param string $prog
-        */
-       public function help($prog) {
-               printf("Usage:\n\n  \$ %s", $prog);
-               
-               $flags = [];
-               $required = [];
-               $optional = [];
-               foreach ($this->args->getSpec() as $spec) {
-                       if ($spec[3] & CliArgs::REQARG) {
-                               if ($spec[3] & CliArgs::REQUIRED) {
-                                       $required[] = $spec;
-                               } else {
-                                       $optional[] = $spec;
-                               }
-                       } else {
-                               $flags[] = $spec;
-                       }
-               }
-       
-               if ($flags) {
-                       printf(" [-%s]", implode("", array_column($flags, 0)));
-               }
-               foreach ($required as $req) {
-                       printf(" -%s <arg>", $req[0]);
-               }
-               if ($optional) {
-                       printf(" [-%s <arg>]", implode("|-", array_column($optional, 0)));
-               }
-               printf("\n\n");
-               $spc = $this->args->getSpec();
-               $max = max(array_map("strlen", array_column($spc, 1)));
-               $max += $max % 8 + 2;
-               foreach ($spc as $spec) {
-                       if (isset($spec[0])) {
-                               printf("    -%s|", $spec[0]);
-                       } else {
-                               printf("    ");
-                       }
-                       printf("--%s ", $spec[1]);
-                       if ($spec[3] & CliArgs::REQARG) {
-                               printf("<arg>  ");
-                       } elseif ($spec[3] & CliArgs::OPTARG) {
-                               printf("[<arg>]");
-                       } else {
-                               printf("       ");
-                       }
-                       printf("%s%s", str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0])), $spec[2]);
-                       if ($spec[3] & CliArgs::REQUIRED) {
-                               printf(" (REQUIRED)");
-                       }
-                       if (isset($spec[4])) {
-                               printf(" [%s]", $spec[4]);
-                       }
-                       printf("\n");
-               }
-               printf("\n");
-       }
-       
-       /**
-        * Create temporary file/directory name
-        * @param string $prefix
-        * @param string $suffix
-        */
-       private function tempname($prefix, $suffix = null) {
-               if (!isset($suffix)) {
-                       $suffix = uniqid();
-               }
-               return sprintf("%s/%s.%s", sys_get_temp_dir(), $prefix, $suffix);
-       }
-
-       /**
-        * Create a new temp directory
-        * @param string $prefix
-        * @return string
-        */
-       private function newtemp($prefix) {
-               $temp = $this->tempname($prefix);
-               if (!is_dir($temp)) {
-                       if (!mkdir($temp, 0700, true)) {
-                               $this->error(null);
-                               exit(3);
-                       }
-               }
-               return $temp;
-       }
-
-       /**
-        * rm -r
-        * @param string $dir
-        */
-       private function rm($dir) {
-               foreach (scandir($dir) as $entry) {
-                       if ($entry === "." || $entry === "..") {
-                               continue;
-                       } elseif (is_dir("$dir/$entry")) {
-                               $this->rm("$dir/$entry");
-                       } elseif (!unlink("$dir/$entry")) {
-                               $this->error(null);
-                       }
-               }
-               if (!rmdir($dir)) {
-                       $this->error(null);
-               }
-       }
-}
diff --git a/src/pharext/FilteredSourceDir.php b/src/pharext/FilteredSourceDir.php
deleted file mode 100644 (file)
index 859df5c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-namespace pharext;
-
-/**
- * Generic filtered source directory
- */
-class FilteredSourceDir extends \FilterIterator implements SourceDir
-{
-       /**
-        * The Packager command
-        * @var pharext\Command
-        */
-       private $cmd;
-       
-       /**
-        * Base directory
-        * @var string
-        */
-       private $path;
-       
-       /**
-        * Exclude filters
-        * @var array
-        */
-       private $filter = [".git/*", ".hg/*"];
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\SourceDir::__construct()
-        */
-       public function __construct(Command $cmd, $path) {
-               $this->cmd = $cmd;
-               $this->path = $path;
-               parent::__construct(
-                       new \RecursiveIteratorIterator(
-                               new \RecursiveDirectoryIterator($path,
-                                       \FilesystemIterator::KEY_AS_PATHNAME |
-                                       \FilesystemIterator::CURRENT_AS_FILEINFO |
-                                       \FilesystemIterator::SKIP_DOTS
-                               )
-                       )
-               );
-               foreach ([".gitignore", ".hgignore"] as $ignore) {
-                       if (file_exists("$path/$ignore")) {
-                               $this->filter = array_merge($this->filter, 
-                                       array_map(function($pat) {
-                                               $pat = trim($pat);
-                                               if (substr($pat, -1) == '/') {
-                                                       $pat .= '*';
-                                               }
-                                               return $pat;
-                                       }, file("$path/$ignore", 
-                                               FILE_IGNORE_NEW_LINES |
-                                               FILE_SKIP_EMPTY_LINES
-                                       ))
-                               );
-                       }
-               }
-       }
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\SourceDir::getBaseDir()
-        */
-       public function getBaseDir() {
-               return $this->path;
-       }
-       
-       /**
-        * Implements FilterIterator
-        * @see FilterIterator::accept()
-        */
-       public function accept() {
-               $fn = $this->key();
-               if (is_dir($fn)) {
-                       if ($this->cmd->getArgs()->verbose) {
-                               $this->info("Excluding %s\n", $fn);
-                       }
-                       return false;
-               }
-               $pl = strlen($this->path) + 1;
-               $pn = substr($this->key(), $pl);
-               foreach ($this->filter as $pat) {
-                       if (fnmatch($pat, $pn)) {
-                               if ($this->cmd->getArgs()->verbose) {
-                                       $this->info("Excluding %s\n", $pn);
-                               }
-                               return false;
-                       }
-               }
-               if ($this->cmd->getArgs()->verbose) {
-                       $this->info("Packaging %s\n", $pn);
-               }
-               return true;
-       }
-}
\ No newline at end of file
diff --git a/src/pharext/GitSourceDir.php b/src/pharext/GitSourceDir.php
deleted file mode 100644 (file)
index f18f97f..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace pharext;
-
-/**
- * Extension source directory which is a git repo
- */
-class GitSourceDir implements \IteratorAggregate, SourceDir
-{
-       /**
-        * The Packager command
-        * @var pharext\Command
-        */
-       private $cmd;
-       
-       /**
-        * Base directory
-        * @var string
-        */
-       private $path;
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\SourceDir::__construct()
-        */
-       public function __construct(Command $cmd, $path) {
-               $this->cmd = $cmd;
-               $this->path = $path;
-       }
-
-       /**
-        * @inheritdoc
-        * @see \pharext\SourceDir::getBaseDir()
-        */
-       public function getBaseDir() {
-               return $this->path;
-       }
-       
-       /**
-        * Generate a list of files by `git ls-files`
-        * @return Generator
-        */
-       private function generateFiles() {
-               $pwd = getcwd();
-               chdir($this->path);
-               if (($pipe = popen("git ls-files", "r"))) {
-                       while (!feof($pipe)) {
-                               if (strlen($file = trim(fgets($pipe)))) {
-                                       if ($this->cmd->getArgs()->verbose) {
-                                               $this->cmd->info("Packaging %s\n", $file);
-                                       }
-                                       if (!($realpath = realpath($file))) {
-                                               $this->cmd->error("File %s does not exist\n", $file);
-                                       }
-                                       yield $realpath;
-                               }
-                       }
-                       pclose($pipe);
-               }
-               chdir($pwd);
-       }
-       
-       /**
-        * Implements IteratorAggregate
-        * @see IteratorAggregate::getIterator()
-        */
-       public function getIterator() {
-               return $this->generateFiles();
-       }
-}
index ed8221113a2105a0a400967f250bc8719c66e94c..589abd611a3384d888826271324cb3aba08d5dfd 100644 (file)
@@ -3,6 +3,8 @@
 namespace pharext;
 
 use Phar;
+use pharext\Cli\Args as CliArgs;
+use pharext\Cli\Command as CliCommand;
 
 /**
  * The extension install command executed by the extension phar
index 1d3aed1e6d3d2a035ce2a7e1933e0d1590a88f7d..470983da3972ccf8c21634c7602a7a3e9a000730 100644 (file)
@@ -4,19 +4,38 @@ namespace pharext\Openssl;
 
 class PrivateKey
 {
+       /**
+        * OpenSSL pkey resource
+        * @var resource
+        */
        private $key;
-       
+
+       /**
+        * Read a private key
+        * @param string $file
+        * @param string $password
+        * @throws \Exception
+        */
        function __construct($file, $password) {
                $this->key = openssl_pkey_get_private("file://$file", $password);
                if (!is_resource($this->key)) {
                        throw new \Exception("Could not load private key");
                }
        }
-       
+
+       /**
+        * Sign the PHAR
+        * @param \Phar $package
+        */
        function sign(\Phar $package) {
                $package->setSignatureAlgorithm(\Phar::OPENSSL, $this->key);
        }
-       
+
+       /**
+        * Export the public key to a file
+        * @param string $file
+        * @throws \Exception
+        */
        function exportPublicKey($file) {
                if (!file_put_contents("$file.tmp", openssl_pkey_get_details($this->key)["key"])
                ||      !rename("$file.tmp", $file)
index 28b705069ed8d9f01c9534362bdb381b2ab73619..f2687654f673a8623bc2e2ed8a704ea42b6a86d4 100644 (file)
@@ -3,6 +3,8 @@
 namespace pharext;
 
 use Phar;
+use pharext\Cli\Args as CliArgs;
+use pharext\Cli\Command as CliCommand;
 
 /**
  * The extension packaging command executed by bin/pharext
@@ -24,8 +26,6 @@ class Packager implements Command
                $this->args = new CliArgs([
                        ["h", "help", "Display this help",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
-                       [null, "signature", "Dump signature",
-                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
                        ["v", "verbose", "More output",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
                        ["q", "quiet", "Less output",
@@ -36,9 +36,9 @@ class Packager implements Command
                                CliArgs::REQUIRED|CliArgs::SINGLE|CliArgs::REQARG],
                        ["s", "source", "Extension source directory",
                                CliArgs::REQUIRED|CliArgs::SINGLE|CliArgs::REQARG],
-                       ["g", "git", "Use `git ls-files` instead of the standard ignore filter",
+                       ["g", "git", "Use `git ls-tree` to determine file list",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
-                       ["p", "pecl", "Use PECL package.xml instead of the standard ignore filter",
+                       ["p", "pecl", "Use PECL package.xml to determine file list, name and release",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
                        ["d", "dest", "Destination directory",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG,
@@ -47,8 +47,10 @@ class Packager implements Command
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
                        ["Z", "bzip", "Create additional PHAR compressed with bzip",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
-                       ["S", "sign", "Sign the *.ext.phar with a private key",
-                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG]
+                       ["S", "sign", "Sign the PHAR with a private key",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG],
+                       [null, "signature", "Dump signature",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
                ]);
        }
        
@@ -75,13 +77,11 @@ class Packager implements Command
                try {
                        if ($this->args["source"]) {
                                if ($this->args["pecl"]) {
-                                       $this->source = new PeclSourceDir($this, $this->args["source"]);
+                                       $this->source = new SourceDir\Pecl($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"]);
+                                       $this->source = new SourceDir\Git($this, $this->args["source"]);
                                } else {
-                                       $this->source = new FilteredSourceDir($this, $this->args["source"]);
+                                       $this->source = new SourceDir\Pharext($this, $this->args["source"]);
                                }
                        }
                } catch (\Exception $e) {
@@ -126,10 +126,11 @@ class Packager implements Command
         * @return Generator
         */
        private function bundle() {
-               foreach (scandir(__DIR__) as $entry) {
-                       if (fnmatch("*.php", $entry)) {
-                               yield "pharext/$entry" => __DIR__."/$entry";
-                       }
+               $rdi = new \RecursiveDirectoryIterator(__DIR__);
+               $rii = new \RecursiveIteratorIterator($rdi);
+               for ($rii->rewind(); $rii->valid(); $rii->next()) {
+                       yield "pharext/". $rii->getSubPathname() => $rii->key();
+                       
                }
        }
        
@@ -167,7 +168,7 @@ class Packager implements Command
 
                        $package->startBuffering();
                        $package->buildFromIterator($this->source, $this->source->getBaseDir());
-                       $package->buildFromIterator($this->bundle());
+                       $package->buildFromIterator($this->bundle(__DIR__));
                        $package->addFile(__DIR__."/../pharext_installer.php", "pharext_installer.php");
                        $package->setDefaultStub("pharext_installer.php");
                        $package->setStub("#!/usr/bin/php -dphar.readonly=1\n".$package->getStub());
diff --git a/src/pharext/PeclSourceDir.php b/src/pharext/PeclSourceDir.php
deleted file mode 100644 (file)
index dd19171..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-
-namespace pharext;
-
-/**
- * A PECL extension source directory containing a v2 package.xml
- */
-class PeclSourceDir implements \IteratorAggregate, SourceDir
-{
-       /**
-        * The Packager command
-        * @var pharext\Packager
-        */
-       private $cmd;
-       
-       /**
-        * The package.xml
-        * @var SimpleXmlElement
-        */
-       private $sxe;
-       
-       /**
-        * The base directory
-        * @var string
-        */
-       private $path;
-       
-       /**
-        * @inheritdoc
-        * @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()[""]);
-               
-               $args = $cmd->getArgs();
-               if (!isset($args->name)) {
-                       $name = (string) $sxe->xpath("/pecl:package/pecl:name")[0];
-                       foreach ($args->parse(2, ["--name", $name]) as $error) {
-                               $cmd->error("%s\n", $error);
-                       }
-               }
-               
-               if (!isset($args->release)) {
-                       $release = (string) $sxe->xpath("/pecl:package/pecl:version/pecl:release")[0];
-                       foreach ($args->parse(2, ["--release", $release]) as $error) {
-                               $cmd->error("%s\n", $error);
-                       }
-               }
-               
-               $this->cmd = $cmd;
-               $this->sxe = $sxe;
-               $this->path = $path;
-       }
-       
-       /**
-        * @inheritdoc
-        * @see \pharext\SourceDir::getBaseDir()
-        */
-       public function getBaseDir() {
-               return $this->path;
-       }
-       
-       /**
-        * Compute the path of a file by parent dir nodes
-        * @param \SimpleXMLElement $ele
-        * @return string
-        */
-       private function dirOf($ele) {
-               $path = "";
-               while (($ele = current($ele->xpath(".."))) && $ele->getName() == "dir") {
-                       $path = trim($ele["name"], "/") ."/". $path ;
-               }
-               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() {
-               foreach ($this->generateHooks() as $file => $hook) {
-                       if ($this->cmd->getArgs()->verbose) {
-                               $this->cmd->info("Packaging %s\n", is_string($hook) ? $hook : $file);
-                       }
-                       yield $file => $hook;
-               }
-               foreach ($this->sxe->xpath("//pecl:file") as $file) {
-                       $path = $this->path ."/". $this->dirOf($file) ."/". $file["name"];
-                       if ($this->cmd->getArgs()->verbose) {
-                               $this->cmd->info("Packaging %s\n", $path);
-                       }
-                       if (!($realpath = realpath($path))) {
-                               $this->cmd->error("File %s does not exist", $path);
-                       }
-                       yield $realpath;
-               }
-       }
-       
-       /**
-        * Implements IteratorAggregate
-        * @see IteratorAggregate::getIterator()
-        */
-       public function getIterator() {
-               return $this->generateFiles();
-       }
-}
diff --git a/src/pharext/PharextSourceDir.php b/src/pharext/PharextSourceDir.php
deleted file mode 100644 (file)
index e0d9a2a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-namespace pharext;
-
-class PharextSourceDir implements \IteratorAggregate, SourceDir
-{
-       private $cmd;
-       private $path;
-       private $iter;
-       
-       public function __construct(Command $cmd, $path) {
-               $this->cmd = $cmd;
-               $this->path = $path;
-               
-               $callable = include "$path/pharext_package.php";
-               if (!is_callable($callable)) {
-                       throw new \Exception("Package hook did not return a callable");
-               }
-               $this->iter = $callable($cmd, $path);
-       }
-       
-       public function getBaseDir() {
-               return $this->path;
-       }
-       
-       public function getIterator() {
-               if (!is_callable($this->iter)) {
-                       throw new \Exception("Package hook callback did not return a callable");
-               } 
-               return call_user_func($this->iter, $this->cmd, $this->path);
-       } 
-}
\ No newline at end of file
diff --git a/src/pharext/SourceDir/Git.php b/src/pharext/SourceDir/Git.php
new file mode 100644 (file)
index 0000000..a16b1e6
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+
+namespace pharext\SourceDir;
+
+use pharext\Command;
+use pharext\SourceDir;
+
+/**
+ * Extension source directory which is a git repo
+ */
+class Git implements \IteratorAggregate, SourceDir
+{
+       /**
+        * The Packager command
+        * @var pharext\Command
+        */
+       private $cmd;
+       
+       /**
+        * Base directory
+        * @var string
+        */
+       private $path;
+       
+       /**
+        * @inheritdoc
+        * @see \pharext\SourceDir::__construct()
+        */
+       public function __construct(Command $cmd, $path) {
+               $this->cmd = $cmd;
+               $this->path = $path;
+       }
+
+       /**
+        * @inheritdoc
+        * @see \pharext\SourceDir::getBaseDir()
+        */
+       public function getBaseDir() {
+               return $this->path;
+       }
+       
+       /**
+        * Generate a list of files by `git ls-files`
+        * @return Generator
+        */
+       private function generateFiles() {
+               $pwd = getcwd();
+               chdir($this->path);
+               if (($pipe = popen("git ls-files", "r"))) {
+                       while (!feof($pipe)) {
+                               if (strlen($file = trim(fgets($pipe)))) {
+                                       if ($this->cmd->getArgs()->verbose) {
+                                               $this->cmd->info("Packaging %s\n", $file);
+                                       }
+                                       if (!($realpath = realpath($file))) {
+                                               $this->cmd->error("File %s does not exist\n", $file);
+                                       }
+                                       yield $realpath;
+                               }
+                       }
+                       pclose($pipe);
+               }
+               chdir($pwd);
+       }
+       
+       /**
+        * Implements IteratorAggregate
+        * @see IteratorAggregate::getIterator()
+        */
+       public function getIterator() {
+               return $this->generateFiles();
+       }
+}
diff --git a/src/pharext/SourceDir/Pecl.php b/src/pharext/SourceDir/Pecl.php
new file mode 100644 (file)
index 0000000..a9150ce
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+
+namespace pharext\SourceDir;
+
+use pharext\Command;
+use pharext\SourceDir;
+
+/**
+ * A PECL extension source directory containing a v2 package.xml
+ */
+class Pecl implements \IteratorAggregate, SourceDir
+{
+       /**
+        * The Packager command
+        * @var pharext\Packager
+        */
+       private $cmd;
+       
+       /**
+        * The package.xml
+        * @var SimpleXmlElement
+        */
+       private $sxe;
+       
+       /**
+        * The base directory
+        * @var string
+        */
+       private $path;
+       
+       /**
+        * @inheritdoc
+        * @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()[""]);
+               
+               $args = $cmd->getArgs();
+               if (!isset($args->name)) {
+                       $name = (string) $sxe->xpath("/pecl:package/pecl:name")[0];
+                       foreach ($args->parse(2, ["--name", $name]) as $error) {
+                               $cmd->error("%s\n", $error);
+                       }
+               }
+               
+               if (!isset($args->release)) {
+                       $release = (string) $sxe->xpath("/pecl:package/pecl:version/pecl:release")[0];
+                       foreach ($args->parse(2, ["--release", $release]) as $error) {
+                               $cmd->error("%s\n", $error);
+                       }
+               }
+               
+               $this->cmd = $cmd;
+               $this->sxe = $sxe;
+               $this->path = $path;
+       }
+       
+       /**
+        * @inheritdoc
+        * @see \pharext\SourceDir::getBaseDir()
+        */
+       public function getBaseDir() {
+               return $this->path;
+       }
+       
+       /**
+        * Compute the path of a file by parent dir nodes
+        * @param \SimpleXMLElement $ele
+        * @return string
+        */
+       private function dirOf($ele) {
+               $path = "";
+               while (($ele = current($ele->xpath(".."))) && $ele->getName() == "dir") {
+                       $path = trim($ele["name"], "/") ."/". $path ;
+               }
+               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 \Generator
+        */
+       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() {
+               foreach ($this->generateHooks() as $file => $hook) {
+                       if ($this->cmd->getArgs()->verbose) {
+                               $this->cmd->info("Packaging %s\n", is_string($hook) ? $hook : $file);
+                       }
+                       yield $file => $hook;
+               }
+               foreach ($this->sxe->xpath("//pecl:file") as $file) {
+                       $path = $this->path ."/". $this->dirOf($file) ."/". $file["name"];
+                       if ($this->cmd->getArgs()->verbose) {
+                               $this->cmd->info("Packaging %s\n", $path);
+                       }
+                       if (!($realpath = realpath($path))) {
+                               $this->cmd->error("File %s does not exist", $path);
+                       }
+                       yield $realpath;
+               }
+       }
+       
+       /**
+        * Implements IteratorAggregate
+        * @see IteratorAggregate::getIterator()
+        */
+       public function getIterator() {
+               return $this->generateFiles();
+       }
+}
diff --git a/src/pharext/SourceDir/Pharext.php b/src/pharext/SourceDir/Pharext.php
new file mode 100644 (file)
index 0000000..2675a78
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+namespace pharext\SourceDir;
+
+use pharext\Command;
+use pharext\SourceDir;
+
+/**
+ * A source directory containing pharext_package.php and eventually pharext_install.php
+ */
+class Pharext implements \IteratorAggregate, SourceDir
+{
+       /**
+        * @var pharext\Command
+        */
+       private $cmd;
+       
+       /**
+        * @var string
+        */
+       private $path;
+       
+       /**
+        * @var callable
+        */
+       private $iter;
+
+       /**
+        * @inheritdoc
+        * @see \pharext\SourceDir::__construct()
+        */
+               public function __construct(Command $cmd, $path) {
+               $this->cmd = $cmd;
+               $this->path = $path;
+               
+               $callable = include "$path/pharext_package.php";
+               if (!is_callable($callable)) {
+                       throw new \Exception("Package hook did not return a callable");
+               }
+               $this->iter = $callable($cmd, $path);
+       }
+
+       /**
+        * @inheritdoc
+        * @see \pharext\SourceDir::getBaseDir()
+        */
+       public function getBaseDir() {
+               return $this->path;
+       }
+
+       /**
+        * Implements IteratorAggregate
+        * @see IteratorAggregate::getIterator()
+        */
+       public function getIterator() {
+               if (!is_callable($this->iter)) {
+                       return new Git($this->cmd, $this->path);
+               } 
+               return call_user_func($this->iter, $this->cmd, $this->path);
+       } 
+}
index 9bf82716d70dfc3b92ed462ffc195df1c2a5435b..04d84b257dff5c0e43736b2db797a06b2ff24bea 100644 (file)
@@ -5,6 +5,8 @@
  */
 namespace pharext;
 
+use pharext\Cli\Args as CliArgs;
+
 return function(Installer $installer) {
        $args = $installer->getArgs();
        <?php foreach ($configure as $cfg) : ?>
index 125db61bdea9bdda248c463e4e8780aa3327067e..f85c2f18bdf76da25196cf77abcc141947b945c3 100644 (file)
@@ -2,7 +2,6 @@
 /**
  * The packager sub-stub for bin/pharext
  */
-
 spl_autoload_register(function($c) {
        return include strtr($c, "\\_", "//") . ".php";
 });
diff --git a/tests/src/pharext/FilteredSourceDirTest.php b/tests/src/pharext/FilteredSourceDirTest.php
deleted file mode 100644 (file)
index c561583..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace pharext;
-
-require __DIR__."/../../autoload.php";
-
-class Cmd2 implements Command
-{
-       use CliCommand;
-       function __construct() {
-               $this->args = new CliArgs;
-       }
-       function run($argc, array $argv) {
-       }
-}
-
-class FilteredSourceDirTest extends \PHPUnit_Framework_TestCase
-{
-       /**
-        * @var FilteredSourceDir
-        */
-       protected $source;
-       
-       protected function setUp() {
-               $this->source = new FilteredSourceDir(new Cmd2, ".");
-       }
-       
-       public function testIterator() {
-               $gitdir = new GitSourceDir(new Cmd2, ".");
-               $gitfiles = iterator_to_array($gitdir);
-               sort($gitfiles);
-               
-               $filtered = array_values(iterator_to_array($this->source));
-               $fltfiles = array_map(function($fi) {
-                       return $fi->getRealpath();
-               }, $filtered);
-               sort($fltfiles);
-               $this->assertEquals(array(), array_diff($gitfiles, $fltfiles));
-               $this->assertEquals($gitfiles, $fltfiles);
-       }
-}
\ No newline at end of file