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
|
|
|
*
|
|
|
|
* @group workflow
|
|
|
|
*/
|
|
|
|
final class ArcanistAliasWorkflow extends ArcanistBaseWorkflow {
|
|
|
|
|
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',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-04-10 20:29:25 +02:00
|
|
|
public static function getAliases($working_copy) {
|
|
|
|
$working_copy_config_aliases = $working_copy->getConfig('aliases');
|
|
|
|
if (!$working_copy_config_aliases) {
|
|
|
|
$working_copy_config_aliases = array();
|
|
|
|
}
|
|
|
|
$user_config_aliases =
|
|
|
|
idx(self::readUserConfigurationFile(), 'aliases', array());
|
|
|
|
return $user_config_aliases + $working_copy_config_aliases;
|
2012-02-21 22:16:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function writeAliases(array $aliases) {
|
|
|
|
$config = self::readUserConfigurationFile();
|
|
|
|
$config['aliases'] = $aliases;
|
|
|
|
self::writeUserConfigurationFile($config);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run() {
|
2012-04-10 20:29:25 +02:00
|
|
|
// We might not be in a working directory, so we don't want to require a
|
|
|
|
// working copy identity here.
|
|
|
|
$working_copy = ArcanistWorkingCopyIdentity::newFromPath(getcwd());
|
|
|
|
$aliases = self::getAliases($working_copy);
|
2012-02-21 22:16:52 +01:00
|
|
|
|
|
|
|
$argv = $this->getArgument('argv');
|
|
|
|
if (count($argv) == 0) {
|
|
|
|
if ($aliases) {
|
|
|
|
foreach ($aliases as $alias => $binding) {
|
|
|
|
echo phutil_console_format(
|
|
|
|
"**%s** %s\n",
|
|
|
|
$alias,
|
|
|
|
implode(' ' , $binding));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
echo "You haven't defined any aliases yet.\n";
|
|
|
|
}
|
|
|
|
} else if (count($argv) == 1) {
|
|
|
|
if (empty($aliases[$argv[0]])) {
|
|
|
|
echo "No alias '{$argv[0]}' to remove.\n";
|
|
|
|
} else {
|
|
|
|
echo phutil_console_format(
|
|
|
|
"'**arc %s**' is currently aliased to '**arc %s**'.",
|
|
|
|
$argv[0],
|
|
|
|
implode(' ', $aliases[$argv[0]]));
|
|
|
|
$ok = phutil_console_confirm('Delete this alias?');
|
|
|
|
if ($ok) {
|
|
|
|
$was = implode(' ', $aliases[$argv[0]]);
|
|
|
|
unset($aliases[$argv[0]]);
|
|
|
|
$this->writeAliases($aliases);
|
|
|
|
echo "Unaliased '{$argv[0]}' (was '{$was}').\n";
|
|
|
|
} else {
|
|
|
|
throw new ArcanistUserAbortException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$arc_config = $this->getArcanistConfiguration();
|
|
|
|
|
|
|
|
if ($arc_config->buildWorkflow($argv[0])) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"You can not create an alias for '{$argv[0]}' because it is a ".
|
|
|
|
"builtin command. 'arc alias' can only create new commands.");
|
|
|
|
}
|
|
|
|
|
|
|
|
$aliases[$argv[0]] = array_slice($argv, 1);
|
|
|
|
echo phutil_console_format(
|
|
|
|
"Aliased '**arc %s**' to '**arc %s**'.\n",
|
|
|
|
$argv[0],
|
|
|
|
implode(' ', $aliases[$argv[0]]));
|
|
|
|
|
|
|
|
$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,
|
|
|
|
ArcanistWorkingCopyIdentity $working_copy) {
|
2012-02-21 22:16:52 +01:00
|
|
|
|
2012-04-10 20:29:25 +02:00
|
|
|
$aliases = ArcanistAliasWorkflow::getAliases($working_copy);
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|