Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -15,9 +15,11 @@ 'ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase.php', 'ArcanistAliasFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAliasFunctionXHPASTLinterRule.php', 'ArcanistAliasFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAliasFunctionXHPASTLinterRuleTestCase.php', - 'ArcanistAliasWorkflow' => 'workflow/ArcanistAliasWorkflow.php', + 'ArcanistAliasWorkflow' => 'toolset/ArcanistAliasWorkflow.php', 'ArcanistAmendWorkflow' => 'workflow/ArcanistAmendWorkflow.php', 'ArcanistAnoidWorkflow' => 'workflow/ArcanistAnoidWorkflow.php', + 'ArcanistArcToolset' => 'toolset/ArcanistArcToolset.php', + 'ArcanistArcWorkflow' => 'workflow/ArcanistArcWorkflow.php', 'ArcanistArrayCombineXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayCombineXHPASTLinterRule.php', 'ArcanistArrayCombineXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArrayCombineXHPASTLinterRuleTestCase.php', 'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php', @@ -96,7 +98,6 @@ 'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConcatenationOperatorXHPASTLinterRuleTestCase.php', 'ArcanistConduitCall' => 'conduit/ArcanistConduitCall.php', 'ArcanistConduitEngine' => 'conduit/ArcanistConduitEngine.php', - 'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php', 'ArcanistConfigurationDrivenLintEngine' => 'lint/engine/ArcanistConfigurationDrivenLintEngine.php', 'ArcanistConfigurationDrivenUnitTestEngine' => 'unit/engine/ArcanistConfigurationDrivenUnitTestEngine.php', 'ArcanistConfigurationManager' => 'configuration/ArcanistConfigurationManager.php', @@ -186,7 +187,6 @@ 'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php', 'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php', 'ArcanistHardpointLoader' => 'loader/ArcanistHardpointLoader.php', - 'ArcanistHelpWorkflow' => 'workflow/ArcanistHelpWorkflow.php', 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php', 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php', 'ArcanistHgClientChannel' => 'hgdaemon/ArcanistHgClientChannel.php', @@ -310,6 +310,7 @@ 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php', 'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php', 'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php', + 'ArcanistPhageToolset' => 'toolset/ArcanistPhageToolset.php', 'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php', 'ArcanistPhpLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpLinterTestCase.php', 'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php', @@ -317,6 +318,7 @@ 'ArcanistPhpunitTestResultParser' => 'unit/parser/ArcanistPhpunitTestResultParser.php', 'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php', 'ArcanistPhutilLibraryLinter' => 'lint/linter/ArcanistPhutilLibraryLinter.php', + 'ArcanistPhutilWorkflow' => 'toolset/ArcanistPhutilWorkflow.php', 'ArcanistPhutilXHPASTLinterStandard' => 'lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPlusOperatorOnStringsXHPASTLinterRule.php', 'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php', @@ -361,7 +363,7 @@ 'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php', 'ArcanistSetting' => 'configuration/ArcanistSetting.php', 'ArcanistSettings' => 'configuration/ArcanistSettings.php', - 'ArcanistShellCompleteWorkflow' => 'workflow/ArcanistShellCompleteWorkflow.php', + 'ArcanistShellCompleteWorkflow' => 'toolset/ArcanistShellCompleteWorkflow.php', 'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php', 'ArcanistSlownessXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSlownessXHPASTLinterRule.php', 'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php', @@ -389,6 +391,7 @@ 'ArcanistTodoCommentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTodoCommentXHPASTLinterRule.php', 'ArcanistTodoCommentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTodoCommentXHPASTLinterRuleTestCase.php', 'ArcanistTodoWorkflow' => 'workflow/ArcanistTodoWorkflow.php', + 'ArcanistToolset' => 'toolset/ArcanistToolset.php', 'ArcanistUSEnglishTranslation' => 'internationalization/ArcanistUSEnglishTranslation.php', 'ArcanistUnableToParseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnableToParseXHPASTLinterRule.php', 'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule.php', @@ -425,10 +428,10 @@ 'ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase.php', 'ArcanistVariableVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableVariableXHPASTLinterRule.php', 'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableVariableXHPASTLinterRuleTestCase.php', - 'ArcanistVersionWorkflow' => 'workflow/ArcanistVersionWorkflow.php', + 'ArcanistVersionWorkflow' => 'toolset/ArcanistVersionWorkflow.php', 'ArcanistWeldWorkflow' => 'workflow/ArcanistWeldWorkflow.php', 'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php', - 'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php', + 'ArcanistWorkflow' => 'toolset/ArcanistWorkflow.php', 'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php', 'ArcanistWorkingCopyStateRef' => 'ref/ArcanistWorkingCopyStateRef.php', 'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/ArcanistXHPASTLintNamingHook.php', @@ -467,6 +470,8 @@ 'ArcanistAliasWorkflow' => 'ArcanistWorkflow', 'ArcanistAmendWorkflow' => 'ArcanistWorkflow', 'ArcanistAnoidWorkflow' => 'ArcanistWorkflow', + 'ArcanistArcToolset' => 'ArcanistToolset', + 'ArcanistArcWorkflow' => 'ArcanistWorkflow', 'ArcanistArrayCombineXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistArrayCombineXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -545,7 +550,6 @@ 'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistConduitCall' => 'Phobject', 'ArcanistConduitEngine' => 'Phobject', - 'ArcanistConfiguration' => 'Phobject', 'ArcanistConfigurationDrivenLintEngine' => 'ArcanistLintEngine', 'ArcanistConfigurationDrivenUnitTestEngine' => 'ArcanistUnitTestEngine', 'ArcanistConfigurationManager' => 'Phobject', @@ -635,7 +639,6 @@ 'ArcanistHLintLinter' => 'ArcanistExternalLinter', 'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistHardpointLoader' => 'Phobject', - 'ArcanistHelpWorkflow' => 'ArcanistWorkflow', 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistHgClientChannel' => 'PhutilProtocolChannel', @@ -759,6 +762,7 @@ 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistPasteWorkflow' => 'ArcanistWorkflow', 'ArcanistPatchWorkflow' => 'ArcanistWorkflow', + 'ArcanistPhageToolset' => 'ArcanistToolset', 'ArcanistPhpLinter' => 'ArcanistExternalLinter', 'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistPhpcsLinter' => 'ArcanistExternalLinter', @@ -766,6 +770,7 @@ 'ArcanistPhpunitTestResultParser' => 'ArcanistTestResultParser', 'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow', 'ArcanistPhutilLibraryLinter' => 'ArcanistLinter', + 'ArcanistPhutilWorkflow' => 'PhutilArgumentWorkflow', 'ArcanistPhutilXHPASTLinterStandard' => 'ArcanistLinterStandard', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', @@ -838,6 +843,7 @@ 'ArcanistTodoCommentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistTodoCommentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistTodoWorkflow' => 'ArcanistWorkflow', + 'ArcanistToolset' => 'Phobject', 'ArcanistUSEnglishTranslation' => 'PhutilTranslation', 'ArcanistUnableToParseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', Index: src/configuration/ArcanistConfiguration.php =================================================================== --- src/configuration/ArcanistConfiguration.php +++ /dev/null @@ -1,187 +0,0 @@ -buildAllWorkflows(), $command); - - if (!$workflow) { - return null; - } - - return clone $workflow; - } - - public function buildAllWorkflows() { - return id(new PhutilClassMapQuery()) - ->setAncestorClass('ArcanistWorkflow') - ->setUniqueMethod('getWorkflowName') - ->execute(); - } - - final public function isValidWorkflow($workflow) { - return (bool)$this->buildWorkflow($workflow); - } - - public function willRunWorkflow($command, ArcanistWorkflow $workflow) { - // This is a hook. - } - - public function didRunWorkflow($command, ArcanistWorkflow $workflow, $err) { - - // This is a hook. - } - - public function didAbortWorkflow($command, $workflow, Exception $ex) { - // This is a hook. - } - - public function getCustomArgumentsForCommand($command) { - return array(); - } - - final public function selectWorkflow( - &$command, - array &$args, - ArcanistConfigurationManager $configuration_manager, - PhutilConsole $console) { - - // First, try to build a workflow with the exact name provided. We always - // pick an exact match, and do not allow aliases to override it. - $workflow = $this->buildWorkflow($command); - if ($workflow) { - return $workflow; - } - - // If the user has an alias, like 'arc alias dhelp diff help', look it up - // and substitute it. We do this only after trying to resolve the workflow - // normally to prevent you from doing silly things like aliasing 'alias' - // to something else. - $aliases = ArcanistAliasWorkflow::getAliases($configuration_manager); - list($new_command, $args) = ArcanistAliasWorkflow::resolveAliases( - $command, - $this, - $args, - $configuration_manager); - - $full_alias = idx($aliases, $command, array()); - $full_alias = implode(' ', $full_alias); - - // Run shell command aliases. - if (ArcanistAliasWorkflow::isShellCommandAlias($new_command)) { - $shell_cmd = substr($full_alias, 1); - - $console->writeLog( - "[%s: 'arc %s' -> $ %s]", - pht('alias'), - $command, - $shell_cmd); - - if ($args) { - $err = phutil_passthru('%C %Ls', $shell_cmd, $args); - } else { - $err = phutil_passthru('%C', $shell_cmd); - } - - exit($err); - } - - // Run arc command aliases. - if ($new_command) { - $workflow = $this->buildWorkflow($new_command); - if ($workflow) { - $console->writeLog( - "[%s: 'arc %s' -> 'arc %s']\n", - pht('alias'), - $command, - $full_alias); - $command = $new_command; - return $workflow; - } - } - - $all = array_keys($this->buildAllWorkflows()); - - // We haven't found a real command or an alias, so try to locate a command - // by unique prefix. - $prefixes = $this->expandCommandPrefix($command, $all); - - if (count($prefixes) == 1) { - $command = head($prefixes); - return $this->buildWorkflow($command); - } else if (count($prefixes) > 1) { - $this->raiseUnknownCommand($command, $prefixes); - } - - - // We haven't found a real command, alias, or unique prefix. Try similar - // spellings. - $corrected = PhutilArgumentSpellingCorrector::newCommandCorrector() - ->correctSpelling($command, $all); - if (count($corrected) == 1) { - $console->writeErr( - pht( - "(Assuming '%s' is the British spelling of '%s'.)", - $command, - head($corrected))."\n"); - $command = head($corrected); - return $this->buildWorkflow($command); - } else if (count($corrected) > 1) { - $this->raiseUnknownCommand($command, $corrected); - } - - $this->raiseUnknownCommand($command); - } - - private function raiseUnknownCommand($command, array $maybe = array()) { - $message = pht("Unknown command '%s'. Try '%s'.", $command, 'arc help'); - if ($maybe) { - $message .= "\n\n".pht('Did you mean:')."\n"; - sort($maybe); - foreach ($maybe as $other) { - $message .= " ".$other."\n"; - } - } - throw new ArcanistUsageException($message); - } - - private function expandCommandPrefix($command, array $options) { - $is_prefix = array(); - foreach ($options as $option) { - if (strncmp($option, $command, strlen($command)) == 0) { - $is_prefix[$option] = true; - } - } - - return array_keys($is_prefix); - } - -} Index: src/configuration/ArcanistConfigurationManager.php =================================================================== --- src/configuration/ArcanistConfigurationManager.php +++ src/configuration/ArcanistConfigurationManager.php @@ -146,6 +146,10 @@ return $this; } + public function getRuntimeConfig($key, $default = null) { + return idx($this->runtimeConfig, $key, $default); + } + /* -( Read/write config )--------------------------------------------------- */ public function readLocalArcConfig() { Index: src/toolset/ArcanistAliasWorkflow.php =================================================================== --- src/toolset/ArcanistAliasWorkflow.php +++ src/toolset/ArcanistAliasWorkflow.php @@ -9,46 +9,50 @@ return 'alias'; } - public function getCommandSynopses() { - return phutil_console_format(<<getToolsetName()); } public function getArguments() { @@ -75,7 +79,7 @@ $this->getConfigurationManager()->writeUserConfigurationFile($config); } - public function run() { + public function runWorkflow() { $aliases = self::getAliases($this->getConfigurationManager()); $argv = $this->getArgument('argv'); Index: src/toolset/ArcanistArcToolset.php =================================================================== --- /dev/null +++ src/toolset/ArcanistArcToolset.php @@ -0,0 +1,26 @@ + 'conduit-uri', + 'param' => 'uri', + 'help' => pht('Connect to Phabricator install specified by __uri__.'), + ), + array( + 'name' => 'conduit-token', + 'param' => 'token', + 'help' => pht('Use a specific authentication token.'), + ), + array( + 'name' => 'anonymous', + 'help' => pht('Run workflow as a public user, without authenticating.'), + ), + ); + } + +} Index: src/toolset/ArcanistPhageToolset.php =================================================================== --- /dev/null +++ src/toolset/ArcanistPhageToolset.php @@ -0,0 +1,8 @@ +workflow = $workflow; + return $this; + } + + public function getWorkflow() { + return $this->workflow; + } + + public function isExecutable() { + return true; + } + + public function execute(PhutilArgumentParser $args) { + return $this->getWorkflow()->executeWorkflow($args); + } + +} Index: src/toolset/ArcanistShellCompleteWorkflow.php =================================================================== --- src/toolset/ArcanistShellCompleteWorkflow.php +++ src/toolset/ArcanistShellCompleteWorkflow.php @@ -5,22 +5,24 @@ */ final class ArcanistShellCompleteWorkflow extends ArcanistWorkflow { + public function supportsToolset(ArcanistToolset $toolset) { + return true; + } + public function getWorkflowName() { return 'shell-complete'; } - public function getCommandSynopses() { - return phutil_console_format(<<getPhobjectClassConstant('TOOLSETKEY'); + } + + final public static function newToolsetMap() { + $toolsets = id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getToolsetKey') + ->execute(); + + return $toolsets; + } + + public function getToolsetArguments() { + return array(); + } + +} Index: src/toolset/ArcanistVersionWorkflow.php =================================================================== --- src/toolset/ArcanistVersionWorkflow.php +++ src/toolset/ArcanistVersionWorkflow.php @@ -5,26 +5,31 @@ */ final class ArcanistVersionWorkflow extends ArcanistWorkflow { + public function supportsToolset(ArcanistToolset $toolset) { + return true; + } + public function getWorkflowName() { return 'version'; } - public function getCommandSynopses() { - return phutil_console_format(<<getToolsetKey()); } public function run() { + // TODO: Show the toolset version, not just the "arc" version. + $console = PhutilConsole::getConsole(); if (!Filesystem::binaryExists('git')) { Index: src/toolset/ArcanistWorkflow.php =================================================================== --- /dev/null +++ src/toolset/ArcanistWorkflow.php @@ -0,0 +1,88 @@ +setName($this->getWorkflowName()) + ->setWorkflow($this); + } + + final public function getToolset() { + return $this->toolset; + } + + final public function setToolset(ArcanistToolset $toolset) { + $this->toolset = $toolset; + return $this; + } + + final protected function getToolsetKey() { + return $this->getToolset()->getToolsetKey(); + } + + final public function executeWorkflow(PhutilArgumentParser $args) { + $this->arguments = $args; + $caught = null; + + try { + $err = $this->runWorkflow($args); + } catch (Exception $ex) { + $caught = $ex; + } + + try { + $this->runWorkflowCleanup(); + } catch (Exception $ex) { + phlog($ex); + } + + if ($caught) { + throw $caught; + } + + return $err; + } + + final public function getArgument($key, $default = null) { + // TOOLSETS: This is a stub for now. + return $default; + + return $this->arguments->getArg($key, $default); + } + +} Index: src/workflow/ArcanistArcWorkflow.php =================================================================== --- src/workflow/ArcanistArcWorkflow.php +++ src/workflow/ArcanistArcWorkflow.php @@ -33,7 +33,7 @@ * @task scratch Scratch Files * @task phabrep Phabricator Repositories */ -abstract class ArcanistWorkflow extends Phobject { +abstract class ArcanistArcWorkflow extends ArcanistWorkflow { const COMMIT_DISABLE = 0; const COMMIT_ALLOW = 1; @@ -52,8 +52,6 @@ private $userName; private $repositoryAPI; private $configurationManager; - private $arguments = array(); - private $passedArguments = array(); private $command; private $stashed; @@ -72,11 +70,9 @@ private $changeCache = array(); private $conduitEngine; - - public function __construct() {} - - - abstract public function run(); + final public function supportsToolset(ArcanistToolset $toolset) { + return ($toolset->getToolsetKey() === 'arc'); + } /** * Finalizes any cleanup operations that need to occur regardless of @@ -86,27 +82,6 @@ $this->finalizeWorkingCopy(); } - /** - * Return the command used to invoke this workflow from the command like, - * e.g. "help" for @{class:ArcanistHelpWorkflow}. - * - * @return string The command a user types to invoke this workflow. - */ - abstract public function getWorkflowName(); - - /** - * Return console formatted string with all command synopses. - * - * @return string 6-space indented list of available command synopses. - */ - abstract public function getCommandSynopses(); - - /** - * Return console formatted string with command help printed in `arc help`. - * - * @return string 10-space indented help to use the command. - */ - abstract public function getCommandHelp(); /* -( Conduit )------------------------------------------------------------ */ @@ -610,169 +585,6 @@ return $workflow; } - final public function getArgument($key, $default = null) { - return idx($this->arguments, $key, $default); - } - - final public function getPassedArguments() { - return $this->passedArguments; - } - - final public function getCompleteArgumentSpecification() { - $spec = $this->getArguments(); - $arc_config = $this->getArcanistConfiguration(); - $command = $this->getCommand(); - $spec += $arc_config->getCustomArgumentsForCommand($command); - - return $spec; - } - - final public function parseArguments(array $args) { - $this->passedArguments = $args; - - $spec = $this->getCompleteArgumentSpecification(); - - $dict = array(); - - $more_key = null; - if (!empty($spec['*'])) { - $more_key = $spec['*']; - unset($spec['*']); - $dict[$more_key] = array(); - } - - $short_to_long_map = array(); - foreach ($spec as $long => $options) { - if (!empty($options['short'])) { - $short_to_long_map[$options['short']] = $long; - } - } - - foreach ($spec as $long => $options) { - if (!empty($options['repeat'])) { - $dict[$long] = array(); - } - } - - $more = array(); - $size = count($args); - for ($ii = 0; $ii < $size; $ii++) { - $arg = $args[$ii]; - $arg_name = null; - $arg_key = null; - if ($arg == '--') { - $more = array_merge( - $more, - array_slice($args, $ii + 1)); - break; - } else if (!strncmp($arg, '--', 2)) { - $arg_key = substr($arg, 2); - $parts = explode('=', $arg_key, 2); - if (count($parts) == 2) { - list($arg_key, $val) = $parts; - - array_splice($args, $ii, 1, array('--'.$arg_key, $val)); - $size++; - } - - if (!array_key_exists($arg_key, $spec)) { - $corrected = PhutilArgumentSpellingCorrector::newFlagCorrector() - ->correctSpelling($arg_key, array_keys($spec)); - if (count($corrected) == 1) { - PhutilConsole::getConsole()->writeErr( - pht( - "(Assuming '%s' is the British spelling of '%s'.)", - '--'.$arg_key, - '--'.head($corrected))."\n"); - $arg_key = head($corrected); - } else { - throw new ArcanistUsageException( - pht( - "Unknown argument '%s'. Try '%s'.", - $arg_key, - 'arc help')); - } - } - } else if (!strncmp($arg, '-', 1)) { - $arg_key = substr($arg, 1); - if (empty($short_to_long_map[$arg_key])) { - throw new ArcanistUsageException( - pht( - "Unknown argument '%s'. Try '%s'.", - $arg_key, - 'arc help')); - } - $arg_key = $short_to_long_map[$arg_key]; - } else { - $more[] = $arg; - continue; - } - - $options = $spec[$arg_key]; - if (empty($options['param'])) { - $dict[$arg_key] = true; - } else { - if ($ii == $size - 1) { - throw new ArcanistUsageException( - pht( - "Option '%s' requires a parameter.", - $arg)); - } - if (!empty($options['repeat'])) { - $dict[$arg_key][] = $args[$ii + 1]; - } else { - $dict[$arg_key] = $args[$ii + 1]; - } - $ii++; - } - } - - if ($more) { - if ($more_key) { - $dict[$more_key] = $more; - } else { - $example = reset($more); - throw new ArcanistUsageException( - pht( - "Unrecognized argument '%s'. Try '%s'.", - $example, - 'arc help')); - } - } - - foreach ($dict as $key => $value) { - if (empty($spec[$key]['conflicts'])) { - continue; - } - foreach ($spec[$key]['conflicts'] as $conflict => $more) { - if (isset($dict[$conflict])) { - if ($more) { - $more = ': '.$more; - } else { - $more = '.'; - } - // TODO: We'll always display these as long-form, when the user might - // have typed them as short form. - throw new ArcanistUsageException( - pht( - "Arguments '%s' and '%s' are mutually exclusive", - "--{$key}", - "--{$conflict}").$more); - } - } - } - - $this->arguments = $dict; - - $this->didParseArguments(); - - return $this; - } - - protected function didParseArguments() { - // Override this to customize workflow argument behavior. - } - final public function getWorkingCopy() { $working_copy = $this->getConfigurationManager()->getWorkingCopyIdentity(); if (!$working_copy) { @@ -1301,31 +1113,6 @@ return $this->changeCache[$path]; } - final public function willRunWorkflow() { - $spec = $this->getCompleteArgumentSpecification(); - foreach ($this->arguments as $arg => $value) { - if (empty($spec[$arg])) { - continue; - } - $options = $spec[$arg]; - if (!empty($options['supports'])) { - $system_name = $this->getRepositoryAPI()->getSourceControlSystemName(); - if (!in_array($system_name, $options['supports'])) { - $extended_info = null; - if (!empty($options['nosupport'][$system_name])) { - $extended_info = ' '.$options['nosupport'][$system_name]; - } - throw new ArcanistUsageException( - pht( - "Option '%s' is not supported under %s.", - "--{$arg}", - $system_name). - $extended_info); - } - } - } - } - final protected function normalizeRevisionID($revision_id) { return preg_replace('/^D/i', '', $revision_id); } Index: src/workflow/ArcanistHelpWorkflow.php =================================================================== --- src/workflow/ArcanistHelpWorkflow.php +++ /dev/null @@ -1,221 +0,0 @@ - array( - 'help' => pht('Print detailed information about each command.'), - ), - '*' => 'command', - ); - } - - public function run() { - - $arc_config = $this->getArcanistConfiguration(); - $workflows = $arc_config->buildAllWorkflows(); - ksort($workflows); - - $target = null; - if ($this->getArgument('command')) { - $target = head($this->getArgument('command')); - if (empty($workflows[$target])) { - throw new ArcanistUsageException( - pht( - "Unrecognized command '%s'. Try '%s'.", - $target, - 'arc help')); - } - } - - $cmdref = array(); - foreach ($workflows as $command => $workflow) { - if ($target && $target != $command) { - continue; - } - if (!$target && !$this->getArgument('full')) { - $cmdref[] = $workflow->getCommandSynopses(); - continue; - } - $optref = array(); - $arguments = $workflow->getArguments(); - - $config_arguments = $arc_config->getCustomArgumentsForCommand($command); - - // This juggling is to put the extension arguments after the normal - // arguments, and make sure the normal arguments aren't overwritten. - ksort($arguments); - ksort($config_arguments); - foreach ($config_arguments as $argument => $spec) { - if (empty($arguments[$argument])) { - $arguments[$argument] = $spec; - } - } - - foreach ($arguments as $argument => $spec) { - if ($argument == '*') { - continue; - } - if (!empty($spec['hide'])) { - continue; - } - if (isset($spec['param'])) { - if (isset($spec['short'])) { - $optref[] = phutil_console_format( - ' __--%s__ __%s__, __-%s__ __%s__', - $argument, - $spec['param'], - $spec['short'], - $spec['param']); - } else { - $optref[] = phutil_console_format( - ' __--%s__ __%s__', - $argument, - $spec['param']); - } - } else { - if (isset($spec['short'])) { - $optref[] = phutil_console_format( - ' __--%s__, __-%s__', - $argument, - $spec['short']); - } else { - $optref[] = phutil_console_format( - ' __--%s__', - $argument); - } - } - - if (isset($config_arguments[$argument])) { - $optref[] = ' '. - pht('(This is a custom option for this project.)'); - } - - if (isset($spec['supports'])) { - $optref[] = ' '. - pht('Supports: %s', implode(', ', $spec['supports'])); - } - - if (isset($spec['help'])) { - $docs = $spec['help']; - } else { - $docs = pht('This option is not documented.'); - } - $docs = phutil_console_wrap($docs, 14); - $optref[] = "{$docs}\n"; - } - if ($optref) { - $optref = implode("\n", $optref); - $optref = "\n\n".$optref; - } else { - $optref = "\n"; - } - - $cmdref[] = - $workflow->getCommandSynopses()."\n". - $workflow->getCommandHelp(). - $optref; - } - $cmdref = implode("\n\n", $cmdref); - - if ($target) { - echo "\n".$cmdref."\n"; - return; - } - - $self = 'arc'; - echo phutil_console_format(<<getArgument('full')) { - echo pht( - "Run '%s' to get commands and options descriptions.\n", - 'arc help --full'); - return; - } - - echo phutil_console_format(<<getArgument('argv'); if (count($argv) > 1) { throw new ArcanistUsageException(