1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-08 13:51:01 +01:00
phorge-arcanist/src/workflow/ArcanistAliasWorkflow.php
epriestley 4a680c762b Tailor CLI feedback about "arc alias" to describe shell command aliases
Summary:
Fixes T9873. Instead of printing something like this:

> Aliased "arc ls" to "arc !ls".

...print this:

> Aliased "arc ls" to shell command "ls".

Test Plan:
  - Added shell commands and internal aliases.
  - Removed aliases.
  - Listed aliases.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9873

Differential Revision: https://secure.phabricator.com/D14651
2015-12-03 18:31:48 -08:00

243 lines
6.2 KiB
PHP

<?php
/**
* Manages aliases for commands with options.
*/
final class ArcanistAliasWorkflow extends ArcanistWorkflow {
public function getWorkflowName() {
return 'alias';
}
public function getCommandSynopses() {
return phutil_console_format(<<<EOTEXT
**alias**
**alias** __command__
**alias** __command__ __target__ -- [__options__]
EOTEXT
);
}
public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT
Supports: cli
Create an alias from __command__ to __target__ (optionally, with
__options__). For example:
arc alias fpatch patch -- --force
...will create a new 'arc' command, 'arc fpatch', which invokes
'arc patch --force ...' when run. NOTE: use "--" before specifying
options!
If you start 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'
You can now run "arc ls" and it will behave like "ls". Of course, this
example is silly and would make your life worse.
You can not overwrite builtins, including 'alias' itself. The builtin
will always execute, even if it was added after your alias.
To remove an alias, run:
arc alias fpatch
Without any arguments, 'arc alias' will list aliases.
EOTEXT
);
}
public function getArguments() {
return array(
'*' => 'argv',
);
}
public static function getAliases(
ArcanistConfigurationManager $configuration_manager) {
$working_copy_config_aliases =
$configuration_manager->getProjectConfig('aliases');
if (!$working_copy_config_aliases) {
$working_copy_config_aliases = array();
}
$user_config_aliases = idx(
$configuration_manager->readUserConfigurationFile(),
'aliases',
array());
return $user_config_aliases + $working_copy_config_aliases;
}
private function writeAliases(array $aliases) {
$config = $this->getConfigurationManager()->readUserConfigurationFile();
$config['aliases'] = $aliases;
$this->getConfigurationManager()->writeUserConfigurationFile($config);
}
public function run() {
$aliases = self::getAliases($this->getConfigurationManager());
$argv = $this->getArgument('argv');
if (count($argv) == 0) {
$this->printAliases($aliases);
} else if (count($argv) == 1) {
$this->removeAlias($aliases, $argv[0]);
} else {
$arc_config = $this->getArcanistConfiguration();
$alias = $argv[0];
if ($arc_config->buildWorkflow($alias)) {
throw new ArcanistUsageException(
pht(
'You can not create an alias for "%s" because it is a '.
'builtin command. "%s" can only create new commands.',
"arc {$alias}",
'arc alias'));
}
$new_alias = array_slice($argv, 1);
$command = implode(' ', $new_alias);
if (self::isShellCommandAlias($command)) {
echo tsprintf(
"%s\n",
pht(
'Aliased "%s" to shell command "%s".',
"arc {$alias}",
substr($command, 1)));
} else {
echo tsprintf(
"%s\n",
pht(
'Aliased "%s" to "%s".',
"arc {$alias}",
"arc {$command}"));
}
$aliases[$alias] = $new_alias;
$this->writeAliases($aliases);
}
return 0;
}
public static function isShellCommandAlias($command) {
return preg_match('/^!/', $command);
}
public static function resolveAliases(
$command,
ArcanistConfiguration $config,
array $argv,
ArcanistConfigurationManager $configuration_manager) {
$aliases = self::getAliases($configuration_manager);
if (!isset($aliases[$command])) {
return array(null, $argv);
}
$new_command = head($aliases[$command]);
if (self::isShellCommandAlias($new_command)) {
return array($new_command, $argv);
}
$workflow = $config->buildWorkflow($new_command);
if (!$workflow) {
return array(null, $argv);
}
$alias_argv = array_slice($aliases[$command], 1);
foreach (array_reverse($alias_argv) as $alias_arg) {
if (!in_array($alias_arg, $argv)) {
array_unshift($argv, $alias_arg);
}
}
return array($new_command, $argv);
}
private function printAliases(array $aliases) {
if (!$aliases) {
echo tsprintf(
"%s\n",
pht('You have not defined any aliases yet.'));
return;
}
$table = id(new PhutilConsoleTable())
->addColumn('input', array('title' => pht('Alias')))
->addColumn('command', array('title' => pht('Command')))
->addColumn('type', array('title' => pht('Type')));
ksort($aliases);
foreach ($aliases as $alias => $binding) {
$command = implode(' ', $binding);
if (self::isShellCommandAlias($command)) {
$command = substr($command, 1);
$type = pht('Shell Command');
} else {
$command = "arc {$command}";
$type = pht('Arcanist Command');
}
$row = array(
'input' => "arc {$alias}",
'type' => $type,
'command' => $command,
);
$table->addRow($row);
}
$table->draw();
}
private function removeAlias(array $aliases, $alias) {
if (empty($aliases[$alias])) {
echo tsprintf(
"%s\n",
pht('No alias "%s" to remove.', $alias));
return;
}
$command = implode(' ', $aliases[$alias]);
if (self::isShellCommandAlias($command)) {
echo tsprintf(
"%s\n",
pht(
'"%s" is currently aliased to shell command "%s".',
"arc {$alias}",
substr($command, 1)));
} else {
echo tsprintf(
"%s\n",
pht(
'"%s" is currently aliased to "%s".',
"arc {$alias}",
"arc {$command}"));
}
$ok = phutil_console_confirm(pht('Delete this alias?'));
if (!$ok) {
throw new ArcanistUserAbortException();
}
unset($aliases[$alias]);
$this->writeAliases($aliases);
echo tsprintf(
"%s\n",
pht(
'Removed alias "%s".',
"arc {$alias}"));
}
}