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 ... "
--- /dev/null
+<?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);
+ }
+ /**@-*/
+}
--- /dev/null
+<?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);
+ }
+ }
+}
+++ /dev/null
-<?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);
- }
- /**@-*/
-}
+++ /dev/null
-<?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);
- }
- }
-}
+++ /dev/null
-<?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
+++ /dev/null
-<?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();
- }
-}
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
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)
namespace pharext;
use Phar;
+use pharext\Cli\Args as CliArgs;
+use pharext\Cli\Command as CliCommand;
/**
* The extension packaging command executed by bin/pharext
$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",
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,
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],
]);
}
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) {
* @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();
+
}
}
$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());
+++ /dev/null
-<?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();
- }
-}
+++ /dev/null
-<?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
--- /dev/null
+<?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();
+ }
+}
--- /dev/null
+<?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();
+ }
+}
--- /dev/null
+<?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);
+ }
+}
*/
namespace pharext;
+use pharext\Cli\Args as CliArgs;
+
return function(Installer $installer) {
$args = $installer->getArgs();
<?php foreach ($configure as $cfg) : ?>
/**
* The packager sub-stub for bin/pharext
*/
-
spl_autoload_register(function($c) {
return include strtr($c, "\\_", "//") . ".php";
});
+++ /dev/null
-<?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