From: Michael Wallner Date: Sun, 8 Mar 2015 19:42:03 +0000 (+0100) Subject: reorder code and files, remove the filtered source dir implementation X-Git-Tag: v2.0.0~12 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=26683702fdc53d2431ae2bc5081439ac12685d1b;hp=50e5714c543ed50557a1b644c6df27b8d298b6e1;p=pharext%2Fpharext reorder code and files, remove the filtered source dir implementation --- diff --git a/Makefile b/Makefile index 1027186..cc88f70 100644 --- 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 ... " diff --git a/bin/pharext b/bin/pharext index 7639671..c0c47e4 100755 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 index 0000000..49d85ab --- /dev/null +++ b/src/pharext/Cli/Args.php @@ -0,0 +1,332 @@ +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 index 0000000..0ec52ff --- /dev/null +++ b/src/pharext/Cli/Command.php @@ -0,0 +1,166 @@ +args; + } + + /** + * Output pharext vX.Y.Z header + */ + function header() { + printf("pharext v%s (c) Michael Wallner \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 ", $req[0]); + } + if ($optional) { + printf(" [-%s ]", 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(" "); + } elseif ($spec[3] & CliArgs::OPTARG) { + printf("[]"); + } 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 index 717bc00..0000000 --- a/src/pharext/CliArgs.php +++ /dev/null @@ -1,332 +0,0 @@ -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 index 9ae9989..0000000 --- a/src/pharext/CliCommand.php +++ /dev/null @@ -1,163 +0,0 @@ -args; - } - - /** - * Output pharext vX.Y.Z header - */ - function header() { - printf("pharext v%s (c) Michael Wallner \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 ", $req[0]); - } - if ($optional) { - printf(" [-%s ]", 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(" "); - } elseif ($spec[3] & CliArgs::OPTARG) { - printf("[]"); - } 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 index 859df5c..0000000 --- a/src/pharext/FilteredSourceDir.php +++ /dev/null @@ -1,97 +0,0 @@ -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 index f18f97f..0000000 --- a/src/pharext/GitSourceDir.php +++ /dev/null @@ -1,70 +0,0 @@ -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/Installer.php b/src/pharext/Installer.php index ed82211..589abd6 100644 --- a/src/pharext/Installer.php +++ b/src/pharext/Installer.php @@ -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 diff --git a/src/pharext/Openssl/PrivateKey.php b/src/pharext/Openssl/PrivateKey.php index 1d3aed1..470983d 100644 --- a/src/pharext/Openssl/PrivateKey.php +++ b/src/pharext/Openssl/PrivateKey.php @@ -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) diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index 28b7050..f268765 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -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 index dd19171..0000000 --- a/src/pharext/PeclSourceDir.php +++ /dev/null @@ -1,152 +0,0 @@ -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 index e0d9a2a..0000000 --- a/src/pharext/PharextSourceDir.php +++ /dev/null @@ -1,32 +0,0 @@ -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 index 0000000..a16b1e6 --- /dev/null +++ b/src/pharext/SourceDir/Git.php @@ -0,0 +1,73 @@ +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 index 0000000..a9150ce --- /dev/null +++ b/src/pharext/SourceDir/Pecl.php @@ -0,0 +1,155 @@ +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 index 0000000..2675a78 --- /dev/null +++ b/src/pharext/SourceDir/Pharext.php @@ -0,0 +1,61 @@ +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); + } +} diff --git a/src/pharext_install.tpl.php b/src/pharext_install.tpl.php index 9bf8271..04d84b2 100644 --- a/src/pharext_install.tpl.php +++ b/src/pharext_install.tpl.php @@ -5,6 +5,8 @@ */ namespace pharext; +use pharext\Cli\Args as CliArgs; + return function(Installer $installer) { $args = $installer->getArgs(); diff --git a/src/pharext_packager.php b/src/pharext_packager.php index 125db61..f85c2f1 100644 --- a/src/pharext_packager.php +++ b/src/pharext_packager.php @@ -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 index c561583..0000000 --- a/tests/src/pharext/FilteredSourceDirTest.php +++ /dev/null @@ -1,41 +0,0 @@ -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