2012-02-21 22:16:52 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
2012-04-10 20:29:25 +02:00
|
|
|
* Manages aliases for commands with options.
|
2012-02-21 22:16:52 +01:00
|
|
|
*/
|
2014-07-21 23:49:15 +02:00
|
|
|
final class ArcanistAliasWorkflow extends ArcanistWorkflow {
|
2012-02-21 22:16:52 +01:00
|
|
|
|
Make Arcanist workflow names explicit
Summary:
Currently, adding a new workflow requires you to override ArcanistConfiguration, which is messy. Instead, just load everything that extends ArcanistBaseWorkflow.
Remove all the rules tying workflow names to class names through arcane incantations.
This has a very small performance cost in that we need to load every Workflow class every time now, but we don't hit __init__ and such anymore and it was pretty negligible on my machine (98ms vs 104ms or something).
Test Plan: Ran "arc help", "arc which", "arc diff", etc.
Reviewers: edward, vrana, btrahan
Reviewed By: edward
CC: aran, zeeg
Differential Revision: https://secure.phabricator.com/D3691
2012-10-17 17:35:03 +02:00
|
|
|
public function getWorkflowName() {
|
|
|
|
return 'alias';
|
|
|
|
}
|
|
|
|
|
2012-03-05 19:02:37 +01:00
|
|
|
public function getCommandSynopses() {
|
2012-02-21 22:16:52 +01:00
|
|
|
return phutil_console_format(<<<EOTEXT
|
|
|
|
**alias**
|
|
|
|
**alias** __command__
|
|
|
|
**alias** __command__ __target__ -- [__options__]
|
2012-03-05 19:02:37 +01:00
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCommandHelp() {
|
|
|
|
return phutil_console_format(<<<EOTEXT
|
2012-02-21 22:16:52 +01:00
|
|
|
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!
|
|
|
|
|
2012-05-24 02:52:37 +02:00
|
|
|
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.
|
|
|
|
|
2012-02-21 22:16:52 +01:00
|
|
|
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',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-10-19 01:10:06 +02:00
|
|
|
public static function getAliases(
|
|
|
|
ArcanistConfigurationManager $configuration_manager) {
|
|
|
|
|
|
|
|
$working_copy_config_aliases =
|
|
|
|
$configuration_manager->getProjectConfig('aliases');
|
2012-04-10 20:29:25 +02:00
|
|
|
if (!$working_copy_config_aliases) {
|
|
|
|
$working_copy_config_aliases = array();
|
|
|
|
}
|
2013-10-19 01:10:06 +02:00
|
|
|
$user_config_aliases = idx(
|
|
|
|
$configuration_manager->readUserConfigurationFile(),
|
|
|
|
'aliases',
|
|
|
|
array());
|
2012-04-10 20:29:25 +02:00
|
|
|
return $user_config_aliases + $working_copy_config_aliases;
|
2012-02-21 22:16:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function writeAliases(array $aliases) {
|
2013-10-19 01:10:06 +02:00
|
|
|
$config = $this->getConfigurationManager()->readUserConfigurationFile();
|
2012-02-21 22:16:52 +01:00
|
|
|
$config['aliases'] = $aliases;
|
2013-10-19 01:10:06 +02:00
|
|
|
$this->getConfigurationManager()->writeUserConfigurationFile($config);
|
2012-02-21 22:16:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function run() {
|
2013-10-19 01:10:06 +02:00
|
|
|
$aliases = self::getAliases($this->getConfigurationManager());
|
2012-02-21 22:16:52 +01:00
|
|
|
|
|
|
|
$argv = $this->getArgument('argv');
|
|
|
|
if (count($argv) == 0) {
|
2015-12-03 15:02:05 +01:00
|
|
|
$this->printAliases($aliases);
|
2012-02-21 22:16:52 +01:00
|
|
|
} else if (count($argv) == 1) {
|
2015-12-03 15:02:05 +01:00
|
|
|
$this->removeAlias($aliases, $argv[0]);
|
2012-02-21 22:16:52 +01:00
|
|
|
} else {
|
|
|
|
$arc_config = $this->getArcanistConfiguration();
|
2015-12-03 15:02:05 +01:00
|
|
|
$alias = $argv[0];
|
2012-02-21 22:16:52 +01:00
|
|
|
|
2015-12-03 15:02:05 +01:00
|
|
|
if ($arc_config->buildWorkflow($alias)) {
|
2012-02-21 22:16:52 +01:00
|
|
|
throw new ArcanistUsageException(
|
2015-05-13 10:05:15 +02:00
|
|
|
pht(
|
2015-12-03 15:02:05 +01:00
|
|
|
'You can not create an alias for "%s" because it is a '.
|
|
|
|
'builtin command. "%s" can only create new commands.',
|
|
|
|
"arc {$alias}",
|
2015-05-13 10:05:15 +02:00
|
|
|
'arc alias'));
|
2012-02-21 22:16:52 +01:00
|
|
|
}
|
|
|
|
|
2015-12-03 15:02:05 +01:00
|
|
|
$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}"));
|
|
|
|
}
|
2012-02-21 22:16:52 +01:00
|
|
|
|
2015-12-03 15:02:05 +01:00
|
|
|
$aliases[$alias] = $new_alias;
|
2012-02-21 22:16:52 +01:00
|
|
|
$this->writeAliases($aliases);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-24 02:52:37 +02:00
|
|
|
public static function isShellCommandAlias($command) {
|
|
|
|
return preg_match('/^!/', $command);
|
|
|
|
}
|
|
|
|
|
2012-02-21 22:16:52 +01:00
|
|
|
public static function resolveAliases(
|
|
|
|
$command,
|
|
|
|
ArcanistConfiguration $config,
|
2012-04-10 20:29:25 +02:00
|
|
|
array $argv,
|
2013-10-19 01:10:06 +02:00
|
|
|
ArcanistConfigurationManager $configuration_manager) {
|
2012-02-21 22:16:52 +01:00
|
|
|
|
2015-04-13 22:29:07 +02:00
|
|
|
$aliases = self::getAliases($configuration_manager);
|
2012-02-21 22:16:52 +01:00
|
|
|
if (!isset($aliases[$command])) {
|
|
|
|
return array(null, $argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
$new_command = head($aliases[$command]);
|
2012-05-24 02:52:37 +02:00
|
|
|
|
|
|
|
if (self::isShellCommandAlias($new_command)) {
|
|
|
|
return array($new_command, $argv);
|
|
|
|
}
|
|
|
|
|
2012-02-21 22:16:52 +01:00
|
|
|
$workflow = $config->buildWorkflow($new_command);
|
|
|
|
if (!$workflow) {
|
|
|
|
return array(null, $argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
$alias_argv = array_slice($aliases[$command], 1);
|
2012-08-08 21:58:27 +02:00
|
|
|
foreach (array_reverse($alias_argv) as $alias_arg) {
|
2012-02-21 22:16:52 +01:00
|
|
|
if (!in_array($alias_arg, $argv)) {
|
|
|
|
array_unshift($argv, $alias_arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return array($new_command, $argv);
|
|
|
|
}
|
|
|
|
|
2015-12-03 15:02:05 +01:00
|
|
|
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}"));
|
|
|
|
}
|
|
|
|
|
2012-02-21 22:16:52 +01:00
|
|
|
}
|