Created
June 5, 2017 20:47
-
-
Save pentagonal/1734a6a320c1ea6a37f91deb5cc60e1d to your computer and use it in GitHub Desktop.
Just Simple Shell Arg Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Pentagonal\RujakLegi; | |
/** | |
* Class Collection | |
* @package Pentagonal\RujakLegi | |
*/ | |
class Collection implements \ArrayAccess, \IteratorAggregate, \Countable | |
{ | |
/** | |
* @var array | |
*/ | |
protected $data = []; | |
/** | |
* Collection constructor. | |
* @param array $args | |
*/ | |
public function __construct(array $args = []) | |
{ | |
$this->data = $args; | |
} | |
/** | |
* Set Value | |
* | |
* @param mixed $name | |
* @param mixed $value | |
*/ | |
public function set($name, $value) | |
{ | |
$this->data[$name] = $value; | |
} | |
/** | |
* Returnig Multiple | |
* | |
* @param array $keys | |
* @return array | |
*/ | |
public function getMultiple(array $keys) | |
{ | |
$retVal = []; | |
foreach ($keys as $value) { | |
$retVal[] = $this->get($value, false); | |
} | |
return $retVal; | |
} | |
/** | |
* Save Data | |
*/ | |
public function save() | |
{ | |
if (func_num_args() > 1) { | |
$this->set(func_get_arg(0), func_get_arg(1)); | |
} | |
} | |
/** | |
* Replace content data | |
* | |
* @param array $replace | |
*/ | |
public function replace(array $replace) | |
{ | |
foreach ($replace as $key => $value) { | |
$this->set($key, $value); | |
} | |
} | |
/** | |
* Check if key exists | |
* | |
* @param mixed $name | |
* @return bool | |
*/ | |
public function exist($name) | |
{ | |
return array_key_exists($name, $this->data); | |
} | |
/** | |
* @param mixed $name | |
* @return bool | |
*/ | |
public function exists($name) | |
{ | |
return $this->exist($name); | |
} | |
/** | |
* @param mixed $key | |
*/ | |
public function remove($key) | |
{ | |
unset($this->data[$key]); | |
} | |
/** | |
* @param mixed $key | |
*/ | |
public function delete($key) | |
{ | |
$this->remove($key); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function pop() | |
{ | |
return array_pop($this->data); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function shift() | |
{ | |
return array_shift($this->data); | |
} | |
/** | |
* @param array $data | |
*/ | |
public function prepend(array $data) | |
{ | |
$this->data = $data + $this->data; | |
} | |
/** | |
* @param array $data | |
*/ | |
public function append(array $data) | |
{ | |
$this->data = $this->data + $data; | |
} | |
/** | |
* @param array $data | |
* @param mixed $_ optional | |
* @return int | |
*/ | |
public function unshift($data, $_ = null) | |
{ | |
if (func_num_args() > 1) { | |
return array_unshift($this->data, $data, $_); | |
} | |
return array_unshift($this->data, $data); | |
} | |
/** | |
* @param array $data | |
* @param mixed $_ optional | |
* @return int | |
*/ | |
public function push($data, $_ = null) | |
{ | |
if (func_num_args() > 1) { | |
return array_push($this->data, $data, $_); | |
} | |
return array_push($this->data, $data); | |
} | |
/** | |
* @return array | |
*/ | |
public function values() | |
{ | |
return array_values($this->data); | |
} | |
/** | |
* @return array | |
*/ | |
public function data() | |
{ | |
return $this->data; | |
} | |
/** | |
* @return array | |
*/ | |
public function keys() | |
{ | |
return array_keys($this->data); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function key() | |
{ | |
return key($this->data); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function next() | |
{ | |
return next($this->data); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function reset() | |
{ | |
return reset($this->data); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function prev() | |
{ | |
return prev($this->data); | |
} | |
/** | |
* @param int|null $numReq | |
* @return mixed | |
*/ | |
public function rand($numReq = null) | |
{ | |
if ($numReq) { | |
return array_rand($this->data); | |
} | |
return array_rand($this->data); | |
} | |
/** | |
* @param null|int $sort_flags | |
* @return bool | |
*/ | |
public function sort($sort_flags = null) | |
{ | |
return sort($this->data, $sort_flags); | |
} | |
/** | |
* @param null|int $sort_flags | |
* @return bool | |
*/ | |
public function rsort($sort_flags = null) | |
{ | |
return rsort($this->data, $sort_flags); | |
} | |
/** | |
* @param null|int $sort_flags | |
* @return bool | |
*/ | |
public function ksort($sort_flags = null) | |
{ | |
return ksort($this->data, $sort_flags); | |
} | |
/** | |
* @param null|int $sort_flags | |
* @return bool | |
*/ | |
public function krsort($sort_flags = null) | |
{ | |
return krsort($this->data, $sort_flags); | |
} | |
/** | |
* Get Data | |
* | |
* @param mixed $name | |
* @param mixed $default | |
* @return mixed | |
*/ | |
public function get($name, $default = null) | |
{ | |
return $this->exist($name) | |
? $this->data[$name] | |
: $default; | |
} | |
/** | |
* @param mixed $offset | |
* @return bool | |
*/ | |
public function offsetExists($offset) | |
{ | |
return $this->exist($offset); | |
} | |
/** | |
* @param mixed $offset | |
* @return mixed | |
*/ | |
public function offsetGet($offset) | |
{ | |
return $this->get($offset); | |
} | |
/** | |
* @param mixed $offset | |
* @param mixed $value | |
*/ | |
public function offsetSet($offset, $value) | |
{ | |
$this->set($offset, $value); | |
} | |
/** | |
* @param mixed $offset | |
*/ | |
public function offsetUnset($offset) | |
{ | |
$this->remove($offset); | |
} | |
/** | |
* Clearing The Data | |
*/ | |
public function clear() | |
{ | |
$this->data = []; | |
} | |
/** | |
* @return int | |
*/ | |
public function count() | |
{ | |
return count($this->data); | |
} | |
/** | |
* @return bool | |
*/ | |
public function isEmpty() | |
{ | |
return $this->count() === 0; | |
} | |
/** | |
* Get If Values contains | |
* | |
* @param mixed $index | |
* @return mixed|null | |
*/ | |
public function indexOf($index) | |
{ | |
$key = array_search($index, $this->data, true); | |
return $key ? $this->get($key) : null; | |
} | |
/** | |
* @return \ArrayIterator | |
*/ | |
public function getIterator() | |
{ | |
return new \ArrayIterator($this->data()); | |
} | |
/** | |
* @return \Generator | |
*/ | |
public function getGenerator() | |
{ | |
yield $this->data(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Pentagonal\RujakLegi; | |
/** | |
* Class ContextArgument | |
* @package Pentagonal\RujakLegi | |
*/ | |
class ContextArgument implements \ArrayAccess | |
{ | |
/** | |
* @var Collection | |
*/ | |
protected $collection; | |
/** | |
* ContextArgument constructor. | |
* @param string $shortContext | |
* @param string $longContext | |
* @param bool $needAttribute | |
* @param string $description | |
* @param \Closure|null $callBack | |
*/ | |
public function __construct( | |
$shortContext, | |
$longContext, | |
$needAttribute, | |
$description = '', | |
\Closure $callBack = null | |
) { | |
$this->collection = new Collection( | |
[ | |
'short' => $shortContext, | |
'long' => $longContext, | |
'need_argument' => $needAttribute, | |
'description' => (is_string($description) ? $description : print_r($description, true)), | |
'callback' => $callBack | |
] | |
); | |
} | |
/** | |
* Get Short Name | |
* | |
* @return string | |
*/ | |
public function getShort() | |
{ | |
return $this->collection['short']; | |
} | |
/** | |
* Get Long Name | |
* | |
* @return string | |
*/ | |
public function getLong() | |
{ | |
return $this->collection['long']; | |
} | |
/** | |
* is Need Arguments | |
* | |
* @return bool | |
*/ | |
public function getIsNeedArgument() | |
{ | |
return $this->collection['need_argument']; | |
} | |
/** | |
* Get Context Description | |
* | |
* @return string | |
*/ | |
public function getDescription() | |
{ | |
return $this->collection['description']; | |
} | |
/** | |
* Get Closure Callback | |
* | |
* @return \Closure|null | |
*/ | |
public function getCallback() | |
{ | |
return $this->collection['callback']; | |
} | |
/** | |
* @return array|null | |
*/ | |
public function getArguments() | |
{ | |
return $this->collection['arguments']; | |
} | |
/** | |
* @param array $values | |
*/ | |
public function setValues(array $values) | |
{ | |
$this->collection->set('arguments', $values); | |
} | |
/** | |
* Clear Arguments Collection | |
*/ | |
public function clearValues() | |
{ | |
$this->collection->remove('arguments'); | |
} | |
/** | |
* @param string $name | |
* @param mixed $default | |
* @return mixed | |
*/ | |
public function get($name, $default = null) | |
{ | |
return $this->collection->get($name, $default); | |
} | |
/** | |
* Get String | |
* | |
* @param string $name | |
* @return mixed | |
*/ | |
public function __get($name) | |
{ | |
return $this->collection->get($name); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function offsetGet($offset) | |
{ | |
return $this->get($offset); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function offsetExists($offset) | |
{ | |
return $this->collection->exist($offset); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function offsetSet($offset, $value) | |
{ | |
// no operation | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function offsetUnset($offset) | |
{ | |
// no operation | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace { | |
use Pentagonal\RujakLegi\ShellArguments; | |
class ExampleShell | |
{ | |
/** | |
* @var ShellArguments | |
*/ | |
protected $arg; | |
/** | |
* ExampleShell Constructor | |
* | |
* @param array $argv | |
*/ | |
public function __construct(array $argv) | |
{ | |
$this->arg = new ShellArguments(APP_NAME, $argv); | |
$c =& $this; | |
$this->arg | |
->setBanner( | |
<<<EOF | |
_ _ _ _ _ _ _ _ _ _ | |
/ \ / \ / \ / \ / \ / \ / \ / \ / \ / \ | |
( M | A | T | A | N | E | | I | K | U ) | |
\_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ | |
EOF | |
) | |
->showVersionBuild(true) | |
->onBeforeRun(function () use ($c) { | |
$c->showBeforeRun(); | |
}); | |
} | |
/** | |
* Run Context On Before Run | |
*/ | |
protected function showBeforeRun() | |
{ | |
echo "Hi....!\n"; | |
} | |
/** | |
* @return ShellArguments | |
*/ | |
public function run() | |
{ | |
return $this | |
->process() | |
->arg | |
->run(); | |
} | |
} | |
if (php_sapi() === 'cli') { | |
$exampleArg = new ExampleShell($argv); | |
// run | |
$shellArg = $exampleArg->run(); | |
// do do do do do | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Pentagonal\RujakLegi; | |
/** | |
* Class ShellArguments | |
* @package Pentagonal\RujakLegi | |
*/ | |
class ShellArguments | |
{ | |
/** | |
* @var array | |
*/ | |
protected $foreGroundColor = [ | |
// Set up shell colors | |
'black' => '0;30', | |
'dark_gray' => '1;30', | |
'blue' => '0;34', | |
'light_blue' => '1;34', | |
'green' => '0;32', | |
'light_green'=> '1;32', | |
'cyan' => '0;36', | |
'light_cyan' => '1;36', | |
'red' => '0;31', | |
'light_red' => '1;31', | |
'purple' => '0;35', | |
'light_purple' => '1;35', | |
'brown' => '0;33', | |
'yellow' => '1;33', | |
'light_gray' => '0;37', | |
'white' => '1;37', | |
]; | |
/** | |
* @var array | |
*/ | |
protected $backgroundColors = [ | |
'black' => '40', | |
'red' => '41', | |
'green' => '42', | |
'yellow' => '43', | |
'blue' => '44', | |
'magenta' => '45', | |
'cyan' => '46', | |
'light_gray' => '47', | |
]; | |
const VERSION = '1.0-beta'; | |
/** | |
* @var string|int | |
*/ | |
protected $version; | |
/** | |
* @var string | |
*/ | |
protected $banner; | |
/** | |
* @var string | |
*/ | |
protected $appName; | |
/** | |
* @var string | |
*/ | |
protected $file; | |
/** | |
* @var string | |
*/ | |
protected $fileReal; | |
/** | |
* @var Database | |
*/ | |
protected $db; | |
/** | |
* @var array | |
*/ | |
protected $args; | |
/** | |
* @var array | |
*/ | |
protected $argumentsOriginal; | |
/** | |
* @var Collection | |
*/ | |
protected $validArguments; | |
/** | |
* @var Collection | |
*/ | |
protected $ignoredArguments; | |
/** | |
* @var Collection[]|Collection | |
*/ | |
protected $invalidArgumentsLists; | |
/** | |
* @var Collection|ContextArgument[]|array[] | |
*/ | |
protected $allContextCollection; | |
/** | |
* @var array | |
*/ | |
protected $contextKeyCollection = []; | |
/** | |
* @var bool | |
*/ | |
protected $paused = false; | |
/** | |
* Auto Resume Time in Seconds | |
* @var int | |
*/ | |
protected $autoResumeTime = 5; | |
/** | |
* @var bool | |
*/ | |
protected $verbose = false; | |
/** | |
* @var bool | |
*/ | |
protected $verboseDebug = false; | |
/** | |
* @var bool | |
*/ | |
protected $quiet = false; | |
/** | |
* @var string | |
*/ | |
protected $currentContext; | |
/** | |
* @var \Closure | |
*/ | |
protected $onBeforeExecute; | |
/** | |
* @var \Closure | |
*/ | |
protected $onAfterExecute; | |
/** | |
* @var \Closure | |
*/ | |
protected $onBeforeRun; | |
/** | |
* @var \Closure | |
*/ | |
protected $onAfterRun; | |
/** | |
* @var \Closure | |
*/ | |
protected $onPause; | |
/** | |
* @var \Closure | |
*/ | |
protected $onResume; | |
/** | |
* @var \Closure | |
*/ | |
protected $onBeforeContext; | |
/** | |
* @var \Closure | |
*/ | |
protected $onAfterContext; | |
/** | |
* @var float | |
*/ | |
protected $timeStart; | |
/** | |
* @var int bytes memory usage | |
*/ | |
protected $memoryStart; | |
/** | |
* @var string | |
*/ | |
protected $infoUsage = '{{file}} [--options=[arguments]|-options [arguments]]'; | |
/** | |
* @var int | |
*/ | |
protected $tabIndent = 2; | |
/** | |
* @var bool | |
*/ | |
protected $showVersionBuild = false; | |
/** | |
* Task constructor. | |
* @param string $appName | |
* @param array $argv | |
*/ | |
public function __construct($appName, array $argv) | |
{ | |
$this->setName($appName); | |
$this->args = $argv; | |
$this->argumentsOriginal = $argv; | |
$this->validArguments = new Collection(); | |
$this->ignoredArguments = new Collection(); | |
$this->invalidArgumentsLists = new Collection(); | |
$this->version = static::VERSION; | |
$this->allContextCollection = new Collection([ | |
'h' => new ContextArgument('h', 'help', false), | |
'q' => new ContextArgument('q', 'quiet', false), | |
'V' => new ContextArgument('V', 'version', false), | |
'v' => new ContextArgument('v', 'verbose', false), | |
'vv' => new ContextArgument('vv', 'debug', false), | |
]); | |
$this->init(); | |
$this->timeStart = @microtime(true); | |
$this->memoryStart = \memory_get_usage(true); | |
} | |
/** | |
* @param string $status | |
* @return ShellArguments | |
*/ | |
public function showVersionBuild($status) | |
{ | |
$this->showVersionBuild = (bool) $status; | |
return $this; | |
} | |
/** | |
* Is Show Version Build | |
* | |
* @return bool | |
*/ | |
public function isShownVersionBuild() | |
{ | |
return (bool) $this->showVersionBuild; | |
} | |
/** | |
* @return array | |
*/ | |
public function getArguments() | |
{ | |
return $this->args; | |
} | |
/** | |
* @return array | |
*/ | |
public function getOriginalArguments() | |
{ | |
return $this->argumentsOriginal; | |
} | |
/** | |
* @return bool | |
*/ | |
public function isCLIMode() | |
{ | |
return php_sapi_name() == 'cli'; | |
} | |
/** | |
* Get Phar | |
* | |
* @return string | |
* @throws \Exception | |
*/ | |
public function getPhar() | |
{ | |
static $phar; | |
if (isset($phar)) { | |
return $phar; | |
} | |
if (!class_exists('Phar')) { | |
throw new \Exception( | |
'Phar is not loaded by php', | |
E_ERROR | |
); | |
} | |
$phar = \Phar::running(false); | |
return $phar?: null; | |
} | |
/** | |
* @return array | |
*/ | |
public function getPharSignature() | |
{ | |
$PharFile = $this->getPhar(); | |
if ($PharFile) { | |
$Phar = new \Phar( | |
$this->getPhar(), | |
\Phar::CURRENT_AS_FILEINFO || \Phar::FOLLOW_SYMLINKS | |
); | |
return $Phar->getSignature(); | |
} | |
return null; | |
} | |
/** | |
* Initialize | |
*/ | |
private function init() | |
{ | |
$this | |
->setContext( | |
'V', | |
'version', | |
false, | |
'Show Application Version', | |
function () { | |
$additional = ''; | |
if ($this->isShownVersionBuild()) { | |
$signature = $this->getPharSignature(); | |
if (is_array($signature)) { | |
$hash = !empty($signature['hash']) | |
? strtolower($signature['hash']) | |
: null; | |
$type = !empty($signature['hash_type']) | |
? $signature['hash_type'] | |
: null; | |
if ($hash) { | |
$hash = $this->color($hash, 'brown'); | |
$additional = " build {$hash}"; | |
$type = $type | |
? ' '. $this->color("[{$type}]", 'blue') | |
: ''; | |
$additional .= $type; | |
} | |
} | |
} | |
$this | |
->show( | |
( | |
$this->color($this->getName(), 'green') | |
. ' version ' . | |
$this->color($this->getVersion(), 'brown') | |
. $additional | |
), | |
true | |
) | |
->stop(0); | |
} | |
) | |
->setContext( | |
'h', | |
'help', | |
false, | |
'Display this help message.', | |
function () { | |
$this | |
->show($this->getBanner(), true) | |
->show( | |
( | |
$this->color($this->getName(), 'green') | |
. ' version ' . | |
$this->color($this->getVersion(), 'brown') | |
), | |
true | |
) | |
->newLine() | |
->show( | |
$this->color('Usage : ', 'brown'), | |
true | |
) | |
->indent() | |
->show( | |
// show usage | |
str_replace( | |
[ | |
'{{file}}', | |
'{{file.real}}' | |
], | |
[ | |
$this->getFile(), | |
$this->getRealFile() | |
], | |
print_r($this->infoUsage, true) | |
), | |
true | |
) | |
->newLine() | |
->show( | |
$this->color('Options : ', 'brown'), | |
true | |
); | |
$allContext = $this->getAllContext(); | |
$longest = 0; | |
foreach ($allContext as $value) { | |
$contextString = '-' | |
. $value->getShort() | |
. ', --' | |
. $value->getLong(); | |
$length = strlen($contextString); | |
if ($longest < $length) { | |
$longest = $length; | |
} | |
} | |
$longest += 2; | |
foreach ($allContext as $value) { | |
$contextString = '-' | |
. $value->getShort() | |
. ', --' | |
. $value->getLong(); | |
$length = strlen($contextString); | |
$length = $longest - $length; | |
$this | |
->indent() | |
->show( | |
$this->color($contextString, 'green') | |
) | |
->indent($length) | |
->show($value->getDescription(), true); | |
if ($value->getIsNeedArgument()) { | |
$this | |
->indent($longest+2) | |
->show( | |
'-' . $value->getShort() . ' [arguments], ', | |
true | |
) | |
->indent($longest+2) | |
->show( | |
'--' . $value->getLong() .'=[arguments]', | |
true | |
); | |
} | |
} | |
$this | |
->newLine() | |
->stop(0); | |
} | |
) | |
->setContext( | |
'v', | |
'verbose', | |
false, | |
'Show verbose mode on application' | |
) | |
->setContext( | |
'vv', | |
'debug', | |
false, | |
'Debug mode, display all debug with verbose mode' | |
) | |
->setContext( | |
'q', | |
'quiet', | |
false, | |
'Do not output any message' | |
); | |
} | |
/** | |
* All Context Collection | |
* | |
* @return Collection|ContextArgument[] | |
*/ | |
public function getAllContext() | |
{ | |
return $this->allContextCollection; | |
} | |
/** | |
* Get Path File executed | |
* @return string | |
*/ | |
public function getFile() | |
{ | |
return $this->file; | |
} | |
/** | |
* Get RealPath File executed | |
* | |
* @return string | |
*/ | |
public function getRealFile() | |
{ | |
return $this->fileReal; | |
} | |
/** | |
* Create Interactive | |
* | |
* @param \Closure $closure | |
* @return bool|mixed | |
*/ | |
public function interactiveLoop( | |
\Closure $closure | |
) { | |
$last_line = false; | |
if ($closure instanceof \Closure) { | |
$fp = @fopen('php://stdin', 'r'); | |
while (!$last_line) { | |
$next_line = fgets($fp, 512); // read the special file to get the user input from keyboard | |
$stopped = null; | |
$closureCallback = $closure->bindTo($this); | |
$closureCallbackRetVal = $closureCallback($next_line, $stopped); | |
if ($stopped || !is_bool($stopped)) { | |
if ($fp) { | |
@fclose($fp); | |
$fp = null; | |
} | |
return $closureCallbackRetVal; | |
} | |
} | |
if ($fp) { | |
@fclose($fp); | |
} | |
} | |
return false; | |
} | |
/** | |
* @param string $data | |
* @param bool $withNewLine | |
* @return ShellArguments | |
*/ | |
public function show($data, $withNewLine = false) | |
{ | |
$data = print_r($data, true); | |
echo $data; | |
$this->newLine($withNewLine ? 1 : 0); | |
return $this; | |
} | |
/** | |
* Create New Line | |
* | |
* @param int $count | |
* @return ShellArguments | |
*/ | |
public function newLine($count = 1) | |
{ | |
if (!is_numeric($count)) { | |
return $this; | |
} | |
$count = abs(intval($count)); | |
$count = $count > 0 ? $count : 0; | |
echo ($count ? str_repeat(PHP_EOL, $count) : ''); | |
return $this; | |
} | |
/** | |
* Indentation count | |
* | |
* @param int $count | |
* @return ShellArguments | |
*/ | |
public function indent($count = null) | |
{ | |
if ($count === null) { | |
$count = $this->getTabIndent(); | |
} | |
if (!is_numeric($count)) { | |
return $this; | |
} | |
$count = abs(intval($count)); | |
$count = $count > 0 ? $count : 0; | |
echo ($count ? str_repeat(' ', $count) : ''); | |
return $this; | |
} | |
/** | |
* Create Colorize | |
* | |
* @param string $string | |
* @param null|string $foreground_color | |
* @param null|string $background_color | |
* @return string | |
*/ | |
public function color($string, $foreground_color = null, $background_color = null) | |
{ | |
$string = print_r($string, true); | |
$colored_string = ""; | |
/** | |
* Check if given foreground color found | |
*/ | |
if ($foreground_color && isset($this->foreGroundColor[$foreground_color])) { | |
$colored_string .= "\033[" . $this->foreGroundColor[$foreground_color] . "m"; | |
} | |
/** | |
* Check if given background color found | |
*/ | |
if ($background_color && isset($this->backgroundColors[$background_color])) { | |
$colored_string .= "\033[" . $this->backgroundColors[$background_color] . "m"; | |
} | |
// Add string and end coloring | |
$colored_string .= $string . "\033[0m"; | |
return $colored_string; | |
} | |
/** | |
* Set Application Name | |
* | |
* @param string $name | |
* @return ShellArguments | |
*/ | |
public function setName($name) | |
{ | |
if (!is_string($name) && !is_numeric($name)) { | |
throw new \InvalidArgumentException( | |
sprintf( | |
'Application Name must be as a string %s given', | |
gettype($name) | |
) | |
); | |
} | |
$this->appName = $name; | |
return $this; | |
} | |
/** | |
* Get Application Name | |
* | |
* @return string | |
*/ | |
public function getName() | |
{ | |
return $this->appName; | |
} | |
/** | |
* Set Tab Indent for help | |
* | |
* @param int $count | |
* @return ShellArguments | |
*/ | |
public function setIndent($count = 4) | |
{ | |
if (!is_numeric($count)) { | |
return $this; | |
} | |
$this->tabIndent = abs(intval($count)); | |
$this->tabIndent = $this->tabIndent < 0 ? $this->tabIndent : 0; | |
return $this; | |
} | |
/** | |
* @return int | |
*/ | |
public function getTabIndent() | |
{ | |
return $this->tabIndent; | |
} | |
/** | |
* Set Description | |
* you can create custom banner on | |
* @link http://www.network-science.de/ascii/ | |
* | |
* @param string $banner | |
* @return ShellArguments | |
*/ | |
public function setBanner($banner) | |
{ | |
if (!is_string($banner)) { | |
$banner = print_r($banner); | |
} | |
$this->banner = $banner; | |
return $this; | |
} | |
/** | |
* Get description stored | |
* | |
* @return string | |
*/ | |
public function getBanner() | |
{ | |
return $this->banner; | |
} | |
/** | |
* @param string $version | |
* @return ShellArguments | |
*/ | |
public function setVersion($version) | |
{ | |
$this->version = $version; | |
return $this; | |
} | |
/** | |
* Get Version | |
* | |
* @return int|string | |
*/ | |
public function getVersion() | |
{ | |
return $this->version; | |
} | |
/** | |
* Get Valid Arguments | |
* | |
* @return Collection | |
*/ | |
public function getValidArguments() | |
{ | |
return $this->validArguments; | |
} | |
/** | |
* Get Ignored Arguments | |
* | |
* @return Collection | |
*/ | |
public function getIgnoreArguments() | |
{ | |
return $this->ignoredArguments; | |
} | |
/** | |
* @return Collection | |
*/ | |
public function getInvalidArgumentsValuable() | |
{ | |
return $this->invalidArgumentsLists; | |
} | |
/** | |
* Get Context | |
* | |
* @param $short | |
* @return array|mixed|null|ContextArgument | |
*/ | |
public function getContext($short) | |
{ | |
if (!$short || !is_string($short)) { | |
return null; | |
} | |
if (isset($this->allContextCollection[$short])) { | |
return $this->allContextCollection[$short]; | |
} | |
if (isset($this->contextKeyCollection[$short])) { | |
return isset($this->allContextCollection[$this->contextKeyCollection[$short]]) | |
? $this->allContextCollection[$this->contextKeyCollection[$short]] | |
: null; | |
} | |
return null; | |
} | |
/** | |
* Get Context Name for name | |
* | |
* @param string $short | |
* @return string|null | |
*/ | |
public function getContextNameFor($short) | |
{ | |
$context = $this->getContext($short); | |
if (!$context) { | |
return null; | |
} | |
return $context->getLong(); | |
} | |
/** | |
* Get Short context name | |
* | |
* @param string $short | |
* @return string|null | |
*/ | |
public function getContextShort($short) | |
{ | |
$context = $this->getContext($short); | |
if (!$context) { | |
return null; | |
} | |
return $context->getShort(); | |
} | |
/** | |
* Is Context need Arguments Value | |
* | |
* @param string $short | |
* @return bool|null | |
*/ | |
public function getContextNeedArguments($short) | |
{ | |
$context = $this->getContext($short); | |
if (!$context) { | |
return null; | |
} | |
return (bool) $context->getIsNeedArgument(); | |
} | |
/** | |
* Get Context Description | |
* | |
* @param string $short | |
* @return string|null | |
*/ | |
public function getContextDescription($short) | |
{ | |
$context = $this->getContext($short); | |
if (!$context) { | |
return null; | |
} | |
return $context->getDescription(); | |
} | |
/** | |
* Get Context Callback | |
* | |
* @param string $short | |
* @return \Closure|bool|null | |
*/ | |
public function getContextCallback($short) | |
{ | |
$context = $this->getContext($short); | |
if (!$context) { | |
return null; | |
} | |
return $context->getCallback()?: false; | |
} | |
/** | |
* Get Context Name currently In Progress | |
* | |
* @return string | |
*/ | |
public function getCurrentContextName() | |
{ | |
return $this->currentContext; | |
} | |
/** | |
* Get Context Name currently In Progress | |
* | |
* @return string | |
*/ | |
public function getCurrentContext() | |
{ | |
$context = $this->getContext($this->getCurrentContextName()); | |
return $context ?: null; | |
} | |
/** | |
* Stop Execution | |
* | |
* @return ShellArguments | |
*/ | |
public function pause() | |
{ | |
$this->paused = false; | |
return $this; | |
} | |
/** | |
* Resume Exec | |
* | |
* @return ShellArguments | |
*/ | |
public function resume() | |
{ | |
$this->paused = false; | |
return $this; | |
} | |
/** | |
* Check if on pause | |
* | |
* @return bool | |
*/ | |
public function isPaused() | |
{ | |
return $this->paused; | |
} | |
/** | |
* Stop CLI | |
* @param int $code | |
*/ | |
public function stop($code = 0) | |
{ | |
exit($code); | |
} | |
/** | |
* @param string $short | |
* @return bool | |
*/ | |
public function isContextExists($short) | |
{ | |
return (bool) $this->getContext($short); | |
} | |
/** | |
* @param string $short | |
* @param \Closure $closure | |
* @return ShellArguments | |
* @throws \InvalidArgumentException | |
*/ | |
public function setCallback($short, \Closure $closure) | |
{ | |
if ($this->isContextExists($short)) { | |
if (isset($this->allContextCollection[$short])) { | |
$this->allContextCollection[$short][2] = $closure; | |
} elseif (isset($this->contextKeyCollection[$short])) { | |
isset($this->allContextCollection[$this->contextKeyCollection[$short]]) && | |
$this->allContextCollection[$this->contextKeyCollection[$short]] = $closure; | |
} | |
return $this; | |
} | |
throw new \InvalidArgumentException( | |
sprintf('Context %s is not exists!', $short), | |
E_USER_ERROR | |
); | |
} | |
/** | |
* @param string $short | |
* @param string $long | |
* @param bool $needValue | |
* @param string $description | |
* @param \Closure|null $closure | |
* @return ShellArguments | |
*/ | |
public function setContext( | |
$short, | |
$long, | |
$needValue = false, | |
$description = '', | |
\Closure $closure = null | |
) { | |
if (!$closure) { | |
$this->allContextCollection[$short] = new ContextArgument( | |
$short, | |
$long, | |
(bool)$needValue, | |
$description | |
); | |
return $this; | |
} | |
$this->allContextCollection[$short] = new ContextArgument( | |
$short, | |
$long, | |
(bool)$needValue, | |
$description, | |
$closure | |
); | |
return $this; | |
} | |
/** | |
* Parse Arguments CLI | |
* @return ShellArguments | |
*/ | |
protected function parseArguments() | |
{ | |
$this->args = $this->argumentsOriginal; | |
$this->file = array_shift($this->args); | |
$this->fileReal = realpath($this->file)?: $this->file; | |
return $this->parseCommand(); | |
} | |
/** | |
* Parse The ARGS command | |
*/ | |
protected function parseCommand() | |
{ | |
$lastCommand = null; | |
$lastCommandLatest = $lastCommand; | |
$args = $this->args; | |
$aliases_key = []; | |
/** | |
* @var ContextArgument $value | |
*/ | |
foreach ($this->allContextCollection as $key => $value) { | |
$name = $value->getLong(); | |
$aliases_key[$name] = [$key, $value->getIsNeedArgument()]; | |
$this->contextKeyCollection[$name] = $key; | |
} | |
/** | |
* Parse Arguments | |
*/ | |
foreach ($args as $value) { | |
if (! $lastCommand) { | |
if ($value && $value[0] == '-') { | |
if (preg_match('`(?P<pos>[\-]{1,2})(?P<name>[a-z0-9\-\_]+)?\=(?P<value>.*?)$`i', $value, $match) | |
&& !empty($match['name']) | |
) { | |
$length_pos = strlen($match['pos']); | |
$name = $match['name']; | |
if ($length_pos === 1) { | |
$named = isset($this->allContextCollection[$name]) | |
? $this->allContextCollection[$name]->getLong() | |
: null; | |
} else { | |
$named = isset($aliases_key[$name]) | |
? $name | |
: null; | |
} | |
if ($named) { | |
$this->validArguments[$named] = $match['value']; | |
} else { | |
$this->ignoredArguments[$name] = $match['value']; | |
} | |
continue; | |
} | |
if (preg_match('`(?P<pos>[\-]{1,2})(?P<name>[a-z0-9\-\_]+)`i', $value, $matches)) { | |
$length_pos = strlen($matches['pos']); | |
$name = $matches['name']; | |
$isNeedValue = null; | |
if ($length_pos === 1) { | |
$named = isset($this->allContextCollection[$name]) | |
? $this->allContextCollection[$name]->getLong() | |
: null; | |
} else { | |
$named = isset($aliases_key[$name]) | |
? $name | |
: null; | |
} | |
if ($named && !empty($aliases_key[$named][1])) { | |
$isNeedValue = true; | |
} | |
$lastCommandLatest = $named?:$name; | |
if ($isNeedValue) { | |
$lastCommand = $named; | |
continue; | |
} | |
if ($named) { | |
$this->validArguments[$lastCommandLatest] = null; | |
} else { | |
if (!isset($this->invalidArgumentsLists[$lastCommandLatest])) { | |
$this->invalidArgumentsLists[$lastCommandLatest] = new Collection(); | |
} | |
} | |
} | |
continue; | |
} | |
if (!isset($this->invalidArgumentsLists[$lastCommandLatest])) { | |
$this->invalidArgumentsLists[$lastCommandLatest] = new Collection(); | |
} | |
if (isset($this->ignoredArguments[$lastCommandLatest])) { | |
$this->invalidArgumentsLists[$lastCommandLatest]->push($value); | |
} | |
} | |
if (isset($aliases_key[$lastCommand])) { | |
$this->validArguments[$lastCommand] = $value; | |
} else { | |
if (!isset($this->ignoredArguments[$lastCommandLatest])) { | |
if (!isset($this->invalidArgumentsLists[$lastCommandLatest])) { | |
$this->invalidArgumentsLists[$lastCommandLatest] = new Collection(); | |
} | |
$this->invalidArgumentsLists[$lastCommandLatest]->push($value); | |
} | |
} | |
$lastCommand = null; | |
} | |
return $this; | |
} | |
/** | |
* Set Auto Resume Time In second | |
* | |
* @param int $second | |
* @return ShellArguments | |
* @throws \InvalidArgumentException | |
*/ | |
public function setAutoResume($second) | |
{ | |
if (!is_numeric($second)) { | |
throw new \InvalidArgumentException( | |
"Time to auto resume must be as a numeric values!" | |
); | |
} | |
$this->autoResumeTime = abs($second); | |
$this->autoResumeTime = $this->autoResumeTime < 0 | |
? 0 | |
: ( | |
$this->autoResumeTime < 30 // max 30 seconds | |
? 30 | |
: $this->autoResumeTime | |
); | |
return $this; | |
} | |
/** | |
* @return int|float | |
*/ | |
public function getAutoResumeTime() | |
{ | |
return $this->autoResumeTime; | |
} | |
/** | |
* Callback call when before run | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onBeforeRun(\Closure $closure) | |
{ | |
$this->onBeforeRun = $closure; | |
return $this; | |
} | |
/** | |
* Callback call when after all run | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onAfterRun(\Closure $closure) | |
{ | |
$this->onAfterRun = $closure; | |
return $this; | |
} | |
/** | |
* Callback call when before execute | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onBeforeExecute(\Closure $closure) | |
{ | |
$this->onBeforeExecute = $closure; | |
return $this; | |
} | |
/** | |
* Callback call when after all execute | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onAfterExecute(\Closure $closure) | |
{ | |
$this->onAfterExecute = $closure; | |
return $this; | |
} | |
/** | |
* Callback Call when Paused Each Procedure | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onPause(\Closure $closure) | |
{ | |
$this->onPause = $closure; | |
return $this; | |
} | |
/** | |
* Callback Call when Resume Each Procedure | |
* | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function onResume(\Closure $closure) | |
{ | |
$this->onResume = $closure; | |
return $this; | |
} | |
/** | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function beforeRunningContext(\Closure $closure) | |
{ | |
$this->onBeforeContext = $closure; | |
return $this; | |
} | |
/** | |
* @param \Closure $closure | |
* @return ShellArguments | |
*/ | |
public function afterRunningContext(\Closure $closure) | |
{ | |
$this->onAfterContext = $closure; | |
return $this; | |
} | |
/** | |
* @param int $code | |
*/ | |
private function internalShowVersion($code = 0) | |
{ | |
$context = $this->getContext('version'); | |
$callback = $context->getCallBack(); | |
$this->currentContext = 'version'; | |
if ($callback instanceof \Closure) { | |
$callback($context); | |
} | |
$this->stop($code); | |
} | |
/** | |
* @param int $code | |
*/ | |
private function internalShowHelp($code = 0) | |
{ | |
$context = $this->getContext('help'); | |
$callback = $context->getCallBack(); | |
$this->currentContext = 'help'; | |
if ($callback instanceof \Closure) { | |
$callback($context); | |
} | |
$this->stop($code); | |
} | |
/** | |
* @return bool | |
*/ | |
public function isDebug() | |
{ | |
return $this->verboseDebug; | |
} | |
/** | |
* @return bool | |
*/ | |
public function isVerbose() | |
{ | |
return $this->verbose; | |
} | |
/** | |
* @return bool | |
*/ | |
public function isQuiet() | |
{ | |
return $this->quiet; | |
} | |
/** | |
* Run Application | |
* | |
* @return ShellArguments | |
*/ | |
public function run() | |
{ | |
// re - set again | |
$this->timeStart = @microtime(true); | |
$this->memoryStart = \memory_get_usage(true); | |
// doing parse | |
$this->parseArguments(); | |
// get arguments call | |
$args = $this->getValidArguments(); | |
/** | |
* debug & verbose | |
*/ | |
$this->verboseDebug = $args->exist('debug'); | |
$this->verbose = $this->verboseDebug || $args->exist('verbose'); | |
$this->quiet = $args->exist('quiet'); | |
// remove unused | |
unset($args['debug'], $args['verbose'], $args['quiet']); | |
if ($this->onBeforeExecute instanceof \Closure) { | |
$beforeExecute = $this->onBeforeExecute->bindTo($this); | |
$beforeExecute(); | |
} | |
if ($args->exist('version')) { | |
$this->internalShowVersion(); | |
return $this; | |
} | |
$the_arguments = $this->getArguments(); | |
if (empty($the_arguments) || $args->exist('help')) { | |
$this->internalShowHelp(0); | |
return $this; | |
} | |
if ($args->isEmpty()) { | |
$argument = $this->args; | |
$current = ''; | |
foreach ($argument as $value) { | |
if (in_array( | |
ltrim($value, '-'), | |
['v', 'V', 'vv', 'version', 'verbose', 'debug', 'help', 'h']) | |
) { | |
continue; | |
} | |
$current = $value; | |
break; | |
} | |
if ($current) { | |
$this | |
->newLine() | |
->show('[') | |
->indent() | |
->show( | |
$this->color('Invalid Option ', null, 'red') | |
. ' : ' | |
. $this->color($current, 'blue'), | |
false | |
) | |
->indent() | |
->show(']', true) | |
->internalShowHelp(1); | |
} else { | |
$this->internalShowHelp(0); | |
} | |
} | |
unset($args['help'], $args['version']); | |
if ($this->onBeforeRun instanceof \Closure) { | |
$beforeRun = $this->onBeforeRun->bindTo($this); | |
$beforeRun(); | |
} | |
foreach ($args as $key => $value) { | |
if (isset($this->contextKeyCollection[$key])) { | |
$this->currentContext = $key; | |
$context = $this->allContextCollection[$this->contextKeyCollection[$key]]; | |
$valueContext = [$value]; | |
if (isset($this->invalidArgumentsLists[$key]) | |
&& !$this->invalidArgumentsLists[$key]->isEmpty() | |
) { | |
$data = clone $this->invalidArgumentsLists[$key]; | |
$data->unshift($value); | |
$valueContext = $data->data(); | |
} | |
$context->setValues($valueContext); | |
if ($this->onBeforeContext instanceof \Closure) { | |
$before = $this->onBeforeContext->bindTo($this); | |
$before(clone $context); | |
} | |
if ($context['callback'] instanceof \Closure) { | |
$callback = $context['callback']->bindTo($this); | |
$callback(clone $context); | |
} | |
// after context | |
if ($this->onAfterContext instanceof \Closure) { | |
$after = $this->onAfterContext->bindTo($this); | |
$after(clone $context); | |
} | |
$hasResume = false; | |
// paused | |
if ($this->isPaused()) { | |
$hasResume = true; | |
if ($this->onPause instanceof \Closure) { | |
$pause = $this->onPause->bindTo($this); | |
$pause(clone $context); | |
} | |
} | |
// if still paused | |
if ($this->paused) { | |
if ($this->autoResumeTime > 0) { | |
sleep($this->autoResumeTime); | |
} | |
$this->resume(); | |
} | |
// if contains paused & go resume | |
if ($hasResume && $this->onResume instanceof \Closure) { | |
$resume = $this->onResume->bindTo($this); | |
$resume(clone $context); | |
} | |
} | |
} | |
if ($this->onAfterRun instanceof \Closure) { | |
$afterRun = $this->onAfterRun->bindTo($this); | |
$afterRun(); | |
} | |
if ($this->onAfterExecute instanceof \Closure) { | |
$onAfterExecute = $this->onAfterExecute->bindTo($this); | |
$onAfterExecute(); | |
} | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Packing As Phar
fileName :
box.json
fileName :
build-phar.sh