Changeset View
Changeset View
Standalone View
Standalone View
src/toolset/workflow/ArcanistAliasWorkflow.php
- This file was added.
<?php | |||||
/** | |||||
* Manages aliases for commands with options. | |||||
*/ | |||||
final class ArcanistAliasWorkflow extends ArcanistWorkflow { | |||||
public function getWorkflowName() { | |||||
return 'alias'; | |||||
} | |||||
public function supportsToolset(ArcanistToolset $toolset) { | |||||
return true; | |||||
} | |||||
public function getWorkflowInformation() { | |||||
$help = pht(<<<EOTEXT | |||||
Create an alias from __command__ to __target__ (optionally, with __options__). | |||||
Aliases allow you to create shorthands for commands and sets of flags you | |||||
commonly use, like defining "arc draft" as a shorthand for "arc diff --draft". | |||||
**Creating Aliases** | |||||
You can define "arc draft" as a shorthand for "arc diff --draft" like this: | |||||
$ arc alias draft diff -- --draft | |||||
Now, when you run "arc draft", the command will function like | |||||
"arc diff --draft". | |||||
<bg:yellow> NOTE: </bg> Make sure you use "--" before specifying any flags you | |||||
want to pass to the command! Otherwise, the flags will be interpreted as flags | |||||
to "arc alias". | |||||
**Listing Aliases** | |||||
Without any arguments, "arc alias" will list aliases. | |||||
**Removing Aliases** | |||||
To remove an alias, run: | |||||
$ arc alias <alias-name> | |||||
You will be prompted to remove the alias. | |||||
**Shell Commands** | |||||
If you begin an alias with "!", the remainder of the alias will be invoked as | |||||
a shell command. For example, if you want to implement "arc ls", you can do so | |||||
like this: | |||||
$ arc alias ls '!ls' | |||||
When run, "arc ls" will now behave like "ls". | |||||
**Multiple Toolsets** | |||||
This workflow supports any toolset, even though the examples in this help text | |||||
use "arc". If you are working with another toolset, use the binary for that | |||||
toolset define aliases for it: | |||||
$ phage alias ... | |||||
Aliases are bound to the toolset which was used to define them. If you define | |||||
an "arc draft" alias, that does not also define a "phage draft" alias. | |||||
**Builtins** | |||||
You can not overwrite the behavior of builtin workflows, including "alias" | |||||
itself, and if you install a new workflow it will take precedence over any | |||||
existing aliases with the same name. | |||||
EOTEXT | |||||
); | |||||
return $this->newWorkflowInformation() | |||||
->addExample(pht('**alias**')) | |||||
->addExample(pht('**alias** __command__')) | |||||
->addExample(pht('**alias** __command__ __target__ -- [__options__]')) | |||||
->setHelp($help); | |||||
} | |||||
public function getWorkflowArguments() { | |||||
return array( | |||||
$this->newWorkflowArgument('json') | |||||
->setHelp(pht('Output aliases in JSON format.')), | |||||
$this->newWorkflowArgument('argv') | |||||
->setWildcard(true), | |||||
); | |||||
} | |||||
public function runWorkflow() { | |||||
$argv = $this->getArgument('argv'); | |||||
$is_list = false; | |||||
$is_delete = false; | |||||
if (!$argv) { | |||||
$is_list = true; | |||||
} else if (count($argv) === 1) { | |||||
$is_delete = true; | |||||
} | |||||
$is_json = $this->getArgument('json'); | |||||
if ($is_json && !$is_list) { | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'The "--json" argument may only be used when listing aliases.')); | |||||
} | |||||
if ($is_list) { | |||||
return $this->runListAliases(); | |||||
} | |||||
if ($is_delete) { | |||||
return $this->runDeleteAlias($argv[0]); | |||||
} | |||||
return $this->runCreateAlias($argv); | |||||
} | |||||
private function runListAliases() { | |||||
// TOOLSETS: Actually list aliases. | |||||
return 1; | |||||
} | |||||
private function runDeleteAlias($alias) { | |||||
// TOOLSETS: Actually delete aliases. | |||||
return 1; | |||||
} | |||||
private function runCreateAlias(array $argv) { | |||||
$trigger = array_shift($argv); | |||||
$this->validateAliasTrigger($trigger); | |||||
$alias = id(new ArcanistAlias()) | |||||
->setToolset($this->getToolsetKey()) | |||||
->setTrigger($trigger) | |||||
->setCommand($argv); | |||||
$aliases = $this->readAliasesForWrite(); | |||||
// TOOLSETS: Check if the user already has an alias for this trigger, and | |||||
// prompt them to overwrite it. Needs prompting to work. | |||||
$aliases[] = $alias; | |||||
$this->writeAliases($aliases); | |||||
// TOOLSETS: Print out a confirmation that we added the alias. | |||||
return 0; | |||||
} | |||||
private function validateAliasTrigger($trigger) { | |||||
$workflows = $this->getRuntime()->getWorkflows(); | |||||
if (isset($workflows[$trigger])) { | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'You can not define an alias for "%s" because it is a builtin '. | |||||
'workflow for the current toolset ("%s"). The "alias" workflow '. | |||||
'can only define new commands as aliases; it can not redefine '. | |||||
'existing commands to mean something else.', | |||||
$trigger, | |||||
$this->getToolsetKey())); | |||||
} | |||||
} | |||||
private function getEditScope() { | |||||
return ArcanistConfigurationSource::SCOPE_USER; | |||||
} | |||||
private function getAliasesConfigKey() { | |||||
return ArcanistArcConfigurationEngineExtension::KEY_ALIASES; | |||||
} | |||||
private function readAliasesForWrite() { | |||||
$key = $this->getAliasesConfigKey(); | |||||
$scope = $this->getEditScope(); | |||||
$source_list = $this->getConfigurationSourceList(); | |||||
return $source_list->getConfigFromScopes($key, array($scope)); | |||||
} | |||||
private function writeAliases(array $aliases) { | |||||
assert_instances_of($aliases, 'ArcanistAlias'); | |||||
$key = $this->getAliasesConfigKey(); | |||||
$scope = $this->getEditScope(); | |||||
$source_list = $this->getConfigurationSourceList(); | |||||
$source = $source_list->getWritableSourceFromScope($scope); | |||||
$option = $source_list->getConfigOption($key); | |||||
$option->writeValue($source, $aliases); | |||||
} | |||||
} |