Changeset View
Changeset View
Standalone View
Standalone View
src/parser/argument/PhutilArgumentParser.php
Show First 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | /* -( Parsing Arguments )-------------------------------------------------- */ | ||||
/** | /** | ||||
* Parse and consume a list of arguments, removing them from the argument | * Parse and consume a list of arguments, removing them from the argument | ||||
* vector but leaving unparsed arguments for later consumption. You can | * vector but leaving unparsed arguments for later consumption. You can | ||||
* retrieve unconsumed arguments directly with | * retrieve unconsumed arguments directly with | ||||
* @{method:getUnconsumedArgumentVector}. Doing a partial parse can make it | * @{method:getUnconsumedArgumentVector}. Doing a partial parse can make it | ||||
* easier to share common flags across scripts or workflows. | * easier to share common flags across scripts or workflows. | ||||
* | * | ||||
* @param list List of argument specs, see | * @param list List of argument specs, see | ||||
* @{class:PhutilArgumentSpecification}. | * @{class:PhutilArgumentSpecification}. | ||||
* @param bool Require flags appear before any non-flag arguments. | |||||
* @return this | * @return this | ||||
amckinley: Just a nitpick, but this spacing is all over the place. | |||||
* @task parse | * @task parse | ||||
*/ | */ | ||||
public function parsePartial(array $specs) { | public function parsePartial(array $specs, $initial_only = false) { | ||||
return $this->parseInternal($specs, false); | return $this->parseInternal($specs, false, $initial_only); | ||||
} | } | ||||
/** | /** | ||||
* @return this | * @return this | ||||
*/ | */ | ||||
private function parseInternal(array $specs, $correct_spelling) { | private function parseInternal( | ||||
array $specs, | |||||
$correct_spelling, | |||||
$initial_only) { | |||||
$specs = PhutilArgumentSpecification::newSpecsFromList($specs); | $specs = PhutilArgumentSpecification::newSpecsFromList($specs); | ||||
$this->mergeSpecs($specs); | $this->mergeSpecs($specs); | ||||
$specs_by_name = mpull($specs, null, 'getName'); | $specs_by_name = mpull($specs, null, 'getName'); | ||||
$specs_by_short = mpull($specs, null, 'getShortAlias'); | $specs_by_short = mpull($specs, null, 'getShortAlias'); | ||||
unset($specs_by_short[null]); | unset($specs_by_short[null]); | ||||
$argv = $this->argv; | $argv = $this->argv; | ||||
$len = count($argv); | $len = count($argv); | ||||
$is_initial = true; | |||||
for ($ii = 0; $ii < $len; $ii++) { | for ($ii = 0; $ii < $len; $ii++) { | ||||
$arg = $argv[$ii]; | $arg = $argv[$ii]; | ||||
$map = null; | $map = null; | ||||
$options = null; | $options = null; | ||||
if (!is_string($arg)) { | if (!is_string($arg)) { | ||||
// Non-string argument; pass it through as-is. | // Non-string argument; pass it through as-is. | ||||
} else if ($arg == '--') { | } else if ($arg == '--') { | ||||
// This indicates "end of flags". | // This indicates "end of flags". | ||||
break; | break; | ||||
} else if ($arg == '-') { | } else if ($arg == '-') { | ||||
// This is a normal argument (e.g., stdin). | // This is a normal argument (e.g., stdin). | ||||
continue; | continue; | ||||
} else if (!strncmp('--', $arg, 2)) { | } else if (!strncmp('--', $arg, 2)) { | ||||
$pre = '--'; | $pre = '--'; | ||||
$arg = substr($arg, 2); | $arg = substr($arg, 2); | ||||
$map = $specs_by_name; | $map = $specs_by_name; | ||||
$options = array_keys($specs_by_name); | $options = array_keys($specs_by_name); | ||||
} else if (!strncmp('-', $arg, 1) && strlen($arg) > 1) { | } else if (!strncmp('-', $arg, 1) && strlen($arg) > 1) { | ||||
$pre = '-'; | $pre = '-'; | ||||
$arg = substr($arg, 1); | $arg = substr($arg, 1); | ||||
$map = $specs_by_short; | $map = $specs_by_short; | ||||
} else { | |||||
$is_initial = false; | |||||
} | } | ||||
if ($map) { | if ($map) { | ||||
$val = null; | $val = null; | ||||
$parts = explode('=', $arg, 2); | $parts = explode('=', $arg, 2); | ||||
if (count($parts) == 2) { | if (count($parts) == 2) { | ||||
list($arg, $val) = $parts; | list($arg, $val) = $parts; | ||||
} | } | ||||
Show All 15 Lines | for ($ii = 0; $ii < $len; $ii++) { | ||||
$pre.$arg, | $pre.$arg, | ||||
$pre.$corrected))); | $pre.$corrected))); | ||||
$arg = $corrected; | $arg = $corrected; | ||||
} | } | ||||
} | } | ||||
if (isset($map[$arg])) { | if (isset($map[$arg])) { | ||||
if ($initial_only && !$is_initial) { | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'Argument "%s" appears after the first non-flag argument. '. | |||||
'This special argument must appear before other arguments.', | |||||
"{$pre}{$arg}")); | |||||
} | |||||
$spec = $map[$arg]; | $spec = $map[$arg]; | ||||
unset($argv[$ii]); | unset($argv[$ii]); | ||||
$param_name = $spec->getParamName(); | $param_name = $spec->getParamName(); | ||||
if ($val !== null) { | if ($val !== null) { | ||||
if ($param_name === null) { | if ($param_name === null) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | /* -( Parsing Arguments )-------------------------------------------------- */ | ||||
* render the exception in a user-friendly way. | * render the exception in a user-friendly way. | ||||
* | * | ||||
* @param list List of argument specs, see | * @param list List of argument specs, see | ||||
* @{class:PhutilArgumentSpecification}. | * @{class:PhutilArgumentSpecification}. | ||||
* @return this | * @return this | ||||
* @task parse | * @task parse | ||||
*/ | */ | ||||
public function parseFull(array $specs) { | public function parseFull(array $specs) { | ||||
$this->parseInternal($specs, true); | $this->parseInternal($specs, true, false); | ||||
if (count($this->argv)) { | if (count($this->argv)) { | ||||
$arg = head($this->argv); | $arg = head($this->argv); | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht("Unrecognized argument '%s'.", $arg)); | pht("Unrecognized argument '%s'.", $arg)); | ||||
} | } | ||||
if ($this->showHelp) { | if ($this->showHelp) { | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | public function getArg($name) { | ||||
return $this->specs[$name]->getDefault(); | return $this->specs[$name]->getDefault(); | ||||
} | } | ||||
public function getUnconsumedArgumentVector() { | public function getUnconsumedArgumentVector() { | ||||
return $this->argv; | return $this->argv; | ||||
} | } | ||||
public function setUnconsumedArgumentVector(array $argv) { | |||||
$this->argv = $argv; | |||||
return $this; | |||||
} | |||||
Not Done Inline ActionsThis is unused code which I'm assuming will get used in a coming revision. amckinley: This is unused code which I'm assuming will get used in a coming revision. | |||||
/* -( Command Help )------------------------------------------------------- */ | /* -( Command Help )------------------------------------------------------- */ | ||||
public function setSynopsis($synopsis) { | public function setSynopsis($synopsis) { | ||||
$this->synopsis = $synopsis; | $this->synopsis = $synopsis; | ||||
return $this; | return $this; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 326 Lines • Show Last 20 Lines |
Just a nitpick, but this spacing is all over the place.