diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -197,7 +197,7 @@ 'ArcanistFutureLinter' => 'lint/linter/ArcanistFutureLinter.php', 'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php', 'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php', - 'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php', + 'ArcanistGetConfigWorkflow' => 'toolset/workflow/ArcanistGetConfigWorkflow.php', 'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php', 'ArcanistGitCommitMessageHardpointLoader' => 'loader/ArcanistGitCommitMessageHardpointLoader.php', 'ArcanistGitHardpointLoader' => 'loader/ArcanistGitHardpointLoader.php', @@ -360,6 +360,7 @@ 'ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase.php', 'ArcanistProjectConfigurationSource' => 'config/source/ArcanistProjectConfigurationSource.php', 'ArcanistPrompt' => 'toolset/ArcanistPrompt.php', + 'ArcanistPromptsWorkflow' => 'toolset/workflow/ArcanistPromptsWorkflow.php', 'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php', 'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php', 'ArcanistPuppetLintLinter' => 'lint/linter/ArcanistPuppetLintLinter.php', @@ -399,7 +400,7 @@ 'ArcanistSelfMemberReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSelfMemberReferenceXHPASTLinterRuleTestCase.php', 'ArcanistSemicolonSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSemicolonSpacingXHPASTLinterRule.php', 'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSemicolonSpacingXHPASTLinterRuleTestCase.php', - 'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php', + 'ArcanistSetConfigWorkflow' => 'toolset/workflow/ArcanistSetConfigWorkflow.php', 'ArcanistSetting' => 'configuration/ArcanistSetting.php', 'ArcanistSettings' => 'configuration/ArcanistSettings.php', 'ArcanistShellCompleteWorkflow' => 'toolset/workflow/ArcanistShellCompleteWorkflow.php', @@ -1299,6 +1300,7 @@ 'ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistProjectConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource', 'ArcanistPrompt' => 'Phobject', + 'ArcanistPromptsWorkflow' => 'ArcanistWorkflow', 'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistPuppetLintLinter' => 'ArcanistExternalLinter', diff --git a/src/runtime/ArcanistRuntime.php b/src/runtime/ArcanistRuntime.php --- a/src/runtime/ArcanistRuntime.php +++ b/src/runtime/ArcanistRuntime.php @@ -139,6 +139,14 @@ try { return $args->parseWorkflowsFull($phutil_workflows); } catch (PhutilArgumentUsageException $usage_exception) { + + // TODO: This is very, very hacky; we're trying to let errors like + // "you passed the wrong arguments" through but fall back to classic + // mode if the workflow itself doesn't exist. + if (!preg_match('/invalid command/i', $usage_exception->getMessage())) { + throw $usage_exception; + } + $log->writeHint( pht('(::)'), pht( diff --git a/src/toolset/workflow/ArcanistAliasWorkflow.php b/src/toolset/workflow/ArcanistAliasWorkflow.php --- a/src/toolset/workflow/ArcanistAliasWorkflow.php +++ b/src/toolset/workflow/ArcanistAliasWorkflow.php @@ -77,7 +77,7 @@ return $this->newWorkflowInformation() ->addExample(pht('**alias**')) ->addExample(pht('**alias** __command__')) - ->addExample(pht('**alias** __command__ __target__ -- [__options__]')) + ->addExample(pht('**alias** __command__ __target__ -- [__arguments__]')) ->setHelp($help); } diff --git a/src/toolset/workflow/ArcanistGetConfigWorkflow.php b/src/toolset/workflow/ArcanistGetConfigWorkflow.php new file mode 100644 --- /dev/null +++ b/src/toolset/workflow/ArcanistGetConfigWorkflow.php @@ -0,0 +1,149 @@ +newWorkflowInformation() + ->addExample('**get-config** [__options__] --') + ->addExample('**get-config** [__options__] -- __name__') + ->setHelp($help); + } + + public function getWorkflowArguments() { + return array( + $this->newWorkflowArgument('verbose') + ->setHelp( + pht('Show detailed information about settings.')), + $this->newWorkflowArgument('argv') + ->setWildcard(true), + ); + } + + public function runWorkflow() { + $argv = $this->getArgument('argv'); + $is_verbose = $this->getArgument('verbose'); + + if (count($argv) > 1) { + throw new ArcanistUsageException( + pht( + 'Specify at most one setting name to read.')); + } + + $source_list = $this->getConfigurationSourceList(); + $config_engine = $this->getConfigurationEngine(); + + $options_map = $config_engine->newConfigOptionsMap(); + + $all_keys = array(); + $alias_map = array(); + foreach ($options_map as $key => $config_option) { + $all_keys[$key] = $key; + foreach ($config_option->getAliases() as $alias) { + $alias_map[$alias] = $key; + } + } + + foreach ($source_list->getSources() as $source) { + foreach ($source->getAllKeys() as $key) { + $all_keys[$key] = $key; + } + } + + ksort($all_keys); + + $defaults_map = $config_engine->newDefaults(); + + foreach ($all_keys as $key) { + $option = idx($options_map, $key); + + if ($option) { + $option_summary = $option->getSummary(); + $option_help = $option->getHelp(); + } else { + $option_summary = pht('(This option is unrecognized.)'); + $option_help = $option_summary; + } + + if ($option) { + $formatter = $option; + } else { + $formatter = new ArcanistWildConfigOption(); + } + + if (!$is_verbose) { + echo tsprintf( + "**%s**\n%R\n\n", + $key, + $option_summary); + } else { + echo tsprintf( + "**%s**\n\n%R\n\n", + $key, + $option_help); + } + + // TODO: Allow options to specify that we can't render values, replacing + // everything. Currently, "aliases" prints out "run aliases" over and + // over again when listing every source. It would be cleaner to print + // one block of help and then more useful summaries (like just the + // aliases each source defines). + + // NOTE: We can only get configuration from a SourceList if the option is + // a recognized option, so skip this part if the option isn't known. + if ($option) { + $value = $source_list->getConfig($key); + $display_value = $formatter->getDisplayValueFromValue($value); + + echo tsprintf("%s: %s\n", pht('Value'), $display_value); + + $default_value = idx($defaults_map, $key); + $display_default = $formatter->getDisplayValueFromValue($default_value); + + echo tsprintf("%s: %s\n", pht('Default'), $display_default); + } + + foreach ($source_list->getSources() as $source) { + if ($source->hasValueForKey($key)) { + $source_value = $source->getValueForKey($key); + $source_value = $formatter->getValueFromStorageValue($source_value); + $source_display = $formatter->getDisplayValueFromValue($source_value); + } else { + $source_display = pht('-'); + } + + echo tsprintf( + "%s: %s\n", + $source->getSourceDisplayName(), + $source_display); + } + } + + // if (!$verbose) { + // $console->writeOut( + // "(%s)\n", + // pht('Run with %s for more details.', '--verbose')); + // } + + return 0; + } + +} diff --git a/src/toolset/workflow/ArcanistPromptsWorkflow.php b/src/toolset/workflow/ArcanistPromptsWorkflow.php new file mode 100644 --- /dev/null +++ b/src/toolset/workflow/ArcanistPromptsWorkflow.php @@ -0,0 +1,80 @@ + +EOTEXT +); + + return $this->newWorkflowInformation() + ->addExample(pht('**prompts** __workflow__')) + ->setHelp($help); + } + + public function getWorkflowArguments() { + return array( + $this->newWorkflowArgument('argv') + ->setWildcard(true), + ); + } + + public function runWorkflow() { + $argv = $this->getArgument('argv'); + + if (!$argv) { + throw new PhutilArgumentUsageException( + pht('Provide a workflow to list prompts for.')); + } + + $runtime = $this->getRuntime(); + $workflows = $runtime->getWorkflows(); + + $workflow_key = array_shift($argv); + $workflow = idx($workflows, $workflow_key); + + if (!$workflow) { + throw new PhutilArgumentUsageException( + pht( + 'Workflow "%s" is unknown. Supported workflows are: %s.', + $workflow_key, + implode(', ', array_keys($workflows)))); + } + + $prompts = $workflow->getPromptMap(); + if (!$prompts) { + echo tsprintf( + "%s\n", + pht('This workflow can not prompt.')); + return 0; + } + + foreach ($prompts as $prompt) { + echo tsprintf( + "**%s**\n", + $prompt->getKey()); + echo tsprintf( + "%s\n", + $prompt->getDescription()); + } + + return 0; + } + +} diff --git a/src/workflow/ArcanistSetConfigWorkflow.php b/src/toolset/workflow/ArcanistSetConfigWorkflow.php rename from src/workflow/ArcanistSetConfigWorkflow.php rename to src/toolset/workflow/ArcanistSetConfigWorkflow.php --- a/src/workflow/ArcanistSetConfigWorkflow.php +++ b/src/toolset/workflow/ArcanistSetConfigWorkflow.php @@ -5,40 +5,42 @@ */ final class ArcanistSetConfigWorkflow extends ArcanistWorkflow { - public function getWorkflowName() { - return 'set-config'; + public function supportsToolset(ArcanistToolset $toolset) { + return true; } - public function getCommandSynopses() { - return phutil_console_format(<<newWorkflowInformation() + ->addExample('**set-config** [__options__] -- __name__ __value__') + ->setHelp($help); } - public function getArguments() { + public function getWorkflowArguments() { return array( - 'local' => array( - 'help' => pht('Set a local config value instead of a user one.'), - ), - '*' => 'argv', + $this->newWorkflowArgument('local') + ->setHelp( + pht( + 'Write to local storage (in the current working copy) instead '. + 'of user storage (in your home directory).')), + $this->newWorkflowArgument('argv') + ->setWildcard(true), ); } @@ -46,7 +48,7 @@ return $this->getArgument('local'); } - public function run() { + public function runWorkflow() { $argv = $this->getArgument('argv'); if (count($argv) != 2) { throw new ArcanistUsageException( diff --git a/src/workflow/ArcanistGetConfigWorkflow.php b/src/workflow/ArcanistGetConfigWorkflow.php deleted file mode 100644 --- a/src/workflow/ArcanistGetConfigWorkflow.php +++ /dev/null @@ -1,173 +0,0 @@ - array( - 'help' => pht('Show detailed information about options.'), - ), - '*' => 'argv', - ); - } - - public function desiresRepositoryAPI() { - return true; - } - - public function run() { - $argv = $this->getArgument('argv'); - $verbose = $this->getArgument('verbose'); - - $settings = new ArcanistSettings(); - - $configuration_manager = $this->getConfigurationManager(); - $configs = array( - ArcanistConfigurationManager::CONFIG_SOURCE_LOCAL => - $configuration_manager->readLocalArcConfig(), - ArcanistConfigurationManager::CONFIG_SOURCE_PROJECT => - $this->getWorkingCopy()->readProjectConfig(), - ArcanistConfigurationManager::CONFIG_SOURCE_USER => - $configuration_manager->readUserArcConfig(), - ArcanistConfigurationManager::CONFIG_SOURCE_SYSTEM => - $configuration_manager->readSystemArcConfig(), - ArcanistConfigurationManager::CONFIG_SOURCE_DEFAULT => - $configuration_manager->readDefaultConfig(), - ); - - if ($argv) { - $keys = $argv; - } else { - $keys = array_mergev(array_map('array_keys', $configs)); - $keys = array_merge($keys, $settings->getAllKeys()); - $keys = array_unique($keys); - sort($keys); - } - - $console = PhutilConsole::getConsole(); - $multi = (count($keys) > 1); - - foreach ($keys as $key) { - $console->writeOut("**%s**\n\n", $key); - - if ($verbose) { - $help = $settings->getHelp($key); - if (!$help) { - $help = pht( - '(This configuration value is not recognized by arc. It may '. - 'be misspelled or out of date.)'); - } - - $console->writeOut("%s\n\n", phutil_console_wrap($help, 4)); - - $console->writeOut( - "%s: %s\n\n", - sprintf('% 20.20s', pht('Example Value')), - $settings->getExample($key)); - - } - - $values = array(); - foreach ($configs as $config_key => $config) { - if (array_key_exists($key, $config)) { - $values[$config_key] = $config[$key]; - } else { - // If we didn't find a value, look for a legacy value. - $source_project = ArcanistConfigurationManager::CONFIG_SOURCE_PROJECT; - if ($config_key === $source_project) { - $legacy_name = $settings->getLegacyName($key); - if (array_key_exists($legacy_name, $config)) { - $values[$config_key] = $config[$legacy_name]; - } - } - } - } - - $console->writeOut( - '%s: ', - sprintf('% 20.20s', pht('Current Value'))); - - if ($values) { - $value = head($values); - $value = $settings->formatConfigValueForDisplay($key, $value); - $console->writeOut("%s\n", $value); - } else { - $console->writeOut("-\n"); - } - - $console->writeOut( - '%s: ', - sprintf('% 20.20s', pht('Current Source'))); - - if ($values) { - $source = head_key($values); - $console->writeOut("%s\n", $source); - } else { - $console->writeOut("-\n"); - } - - if ($verbose) { - $console->writeOut("\n"); - - foreach ($configs as $name => $config) { - $have_value = false; - if (array_key_exists($name, $values)) { - $have_value = true; - $value = $values[$name]; - } - - $console->writeOut( - '%s: ', - sprintf('% 20.20s', pht('%s Value', $name))); - - if ($have_value) { - $console->writeOut( - "%s\n", - $settings->formatConfigValueForDisplay($key, $value)); - } else { - $console->writeOut("-\n"); - } - } - } - - if ($multi) { - echo "\n"; - } - } - - if (!$verbose) { - $console->writeOut( - "(%s)\n", - pht('Run with %s for more details.', '--verbose')); - } - - return 0; - } - -}