mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-22 06:42:41 +01:00
Add an "arc alias" command
Summary: Allow users to easily define aliased arc commands. This is easier than making them muck around with shell stuff, and lets me do stuff like "arc alias adiff diff -- --auto" so I can test --auto more easily. There are some limitations here (for example, you can't put --trace in an alias because it gets parsed too early) but I think it's a reasonable starting point. Test Plan: Set, listed, removed and used aliases. Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T896 Differential Revision: https://secure.phabricator.com/D1653
This commit is contained in:
parent
964bdb63ba
commit
b058efbb51
11 changed files with 239 additions and 14 deletions
|
@ -164,15 +164,40 @@ try {
|
|||
}
|
||||
|
||||
$command = strtolower($args[0]);
|
||||
$args = array_slice($args, 1);
|
||||
$workflow = $config->buildWorkflow($command);
|
||||
if (!$workflow) {
|
||||
|
||||
// If the user has an alias, like 'arc alias dhelp diff help', look it up
|
||||
// and substitute it. We do this only after trying to resolve the workflow
|
||||
// normally to prevent you from doing silly things like aliasing 'alias'
|
||||
// to something else.
|
||||
|
||||
list($new_command, $args) = ArcanistAliasWorkflow::resolveAliases(
|
||||
$command,
|
||||
$config,
|
||||
$args);
|
||||
|
||||
if ($new_command) {
|
||||
$workflow = $config->buildWorkflow($new_command);
|
||||
}
|
||||
|
||||
if (!$workflow) {
|
||||
throw new ArcanistUsageException(
|
||||
"Unknown command '{$command}'. Try 'arc help'.");
|
||||
} else {
|
||||
if ($config_trace_mode) {
|
||||
$aliases = ArcanistAliasWorkflow::getAliases();
|
||||
$target = implode(' ', idx($aliases, $command, array()));
|
||||
echo "[alias: 'arc {$command}' -> 'arc {$target}']\n";
|
||||
}
|
||||
$command = $new_command;
|
||||
}
|
||||
}
|
||||
$workflow->setArcanistConfiguration($config);
|
||||
$workflow->setCommand($command);
|
||||
$workflow->setWorkingDirectory($working_directory);
|
||||
$workflow->parseArguments(array_slice($args, 1));
|
||||
$workflow->parseArguments($args);
|
||||
|
||||
$need_working_copy = $workflow->requiresWorkingCopy();
|
||||
$need_conduit = $workflow->requiresConduit();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
phutil_register_library_map(array(
|
||||
'class' =>
|
||||
array(
|
||||
'ArcanistAliasWorkflow' => 'workflow/alias',
|
||||
'ArcanistAmendWorkflow' => 'workflow/amend',
|
||||
'ArcanistApacheLicenseLinter' => 'lint/linter/apachelicense',
|
||||
'ArcanistApacheLicenseLinterTestCase' => 'lint/linter/apachelicense/__tests__',
|
||||
|
@ -116,6 +117,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'requires_class' =>
|
||||
array(
|
||||
'ArcanistAliasWorkflow' => 'ArcanistBaseWorkflow',
|
||||
'ArcanistAmendWorkflow' => 'ArcanistBaseWorkflow',
|
||||
'ArcanistApacheLicenseLinter' => 'ArcanistLicenseLinter',
|
||||
'ArcanistApacheLicenseLinterTestCase' => 'ArcanistLinterTestCase',
|
||||
|
|
|
@ -100,6 +100,10 @@ class ArcanistConfiguration {
|
|||
return $workflows;
|
||||
}
|
||||
|
||||
final public function isValidWorkflow($workflow) {
|
||||
return (bool)$this->buildWorkflow($workflow);
|
||||
}
|
||||
|
||||
public function willRunWorkflow($command, ArcanistBaseWorkflow $workflow) {
|
||||
// This is a hook.
|
||||
}
|
||||
|
|
153
src/workflow/alias/ArcanistAliasWorkflow.php
Normal file
153
src/workflow/alias/ArcanistAliasWorkflow.php
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show which revision or revisions are in the working copy.
|
||||
*
|
||||
* @group workflow
|
||||
*/
|
||||
final class ArcanistAliasWorkflow extends ArcanistBaseWorkflow {
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**alias**
|
||||
**alias** __command__
|
||||
**alias** __command__ __target__ -- [__options__]
|
||||
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!
|
||||
|
||||
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() {
|
||||
$config = self::readUserConfigurationFile();
|
||||
return idx($config, 'aliases');
|
||||
}
|
||||
|
||||
private function writeAliases(array $aliases) {
|
||||
$config = self::readUserConfigurationFile();
|
||||
$config['aliases'] = $aliases;
|
||||
self::writeUserConfigurationFile($config);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
|
||||
$aliases = self::getAliases();
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
public static function resolveAliases(
|
||||
$command,
|
||||
ArcanistConfiguration $config,
|
||||
array $argv) {
|
||||
|
||||
$aliases = ArcanistAliasWorkflow::getAliases();
|
||||
if (!isset($aliases[$command])) {
|
||||
return array(null, $argv);
|
||||
}
|
||||
|
||||
$new_command = head($aliases[$command]);
|
||||
$workflow = $config->buildWorkflow($new_command);
|
||||
if (!$workflow) {
|
||||
return array(null, $argv);
|
||||
}
|
||||
|
||||
$alias_argv = array_slice($aliases[$command], 1);
|
||||
foreach ($alias_argv as $alias_arg) {
|
||||
if (!in_array($alias_arg, $argv)) {
|
||||
array_unshift($argv, $alias_arg);
|
||||
}
|
||||
}
|
||||
|
||||
return array($new_command, $argv);
|
||||
}
|
||||
|
||||
}
|
17
src/workflow/alias/__init__.php
Normal file
17
src/workflow/alias/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('arcanist', 'exception/usage');
|
||||
phutil_require_module('arcanist', 'exception/usage/userabort');
|
||||
phutil_require_module('arcanist', 'workflow/base');
|
||||
|
||||
phutil_require_module('phutil', 'console');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('ArcanistAliasWorkflow.php');
|
|
@ -952,6 +952,17 @@ abstract class ArcanistBaseWorkflow {
|
|||
return $user_config;
|
||||
}
|
||||
|
||||
|
||||
public static function writeUserConfigurationFile($config) {
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
$path = self::getUserConfigurationFileLocation();
|
||||
Filesystem::writeFile($path, $json);
|
||||
execx('chmod 600 %s', $path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a message to stderr so that '--json' flags or stdout which is meant
|
||||
* to be piped somewhere aren't disrupted.
|
||||
|
|
|
@ -21,6 +21,7 @@ phutil_require_module('phutil', 'console');
|
|||
phutil_require_module('phutil', 'filesystem');
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'moduleutils');
|
||||
phutil_require_module('phutil', 'parser/json');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -110,14 +110,8 @@ EOTEXT
|
|||
'cert' => $info['certificate'],
|
||||
);
|
||||
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
echo "Writing ~/.arcrc...\n";
|
||||
|
||||
$path = self::getUserConfigurationFileLocation();
|
||||
Filesystem::writeFile($path, $json);
|
||||
execx('chmod 600 %s', $path);
|
||||
self::writeUserConfigurationFile($config);
|
||||
|
||||
echo phutil_console_format(
|
||||
"<bg:green>** SUCCESS! **</bg> Certificate installed.\n");
|
||||
|
|
|
@ -11,9 +11,6 @@ phutil_require_module('arcanist', 'workflow/base');
|
|||
|
||||
phutil_require_module('phutil', 'conduit/client');
|
||||
phutil_require_module('phutil', 'console');
|
||||
phutil_require_module('phutil', 'filesystem');
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'parser/json');
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
|
||||
|
||||
|
|
|
@ -93,13 +93,33 @@ EOTEXT
|
|||
$complete[] = $name;
|
||||
}
|
||||
|
||||
// Also permit autocompletion of "arc alias" commands.
|
||||
foreach (ArcanistAliasWorkflow::getAliases() as $key => $value) {
|
||||
$complete[] = $key;
|
||||
}
|
||||
|
||||
echo implode(' ', $complete)."\n";
|
||||
return 0;
|
||||
} else {
|
||||
$workflow = $arc_config->buildWorkflow($argv[1]);
|
||||
if (!$workflow) {
|
||||
return 1;
|
||||
list($new_command, $new_args) = ArcanistAliasWorkflow::resolveAliases(
|
||||
$argv[1],
|
||||
$arc_config,
|
||||
array_slice($argv, 2));
|
||||
if ($new_command) {
|
||||
$workflow = $arc_config->buildWorkflow($new_command);
|
||||
}
|
||||
if (!$workflow) {
|
||||
return 1;
|
||||
} else {
|
||||
$argv = array_merge(
|
||||
array($argv[0]),
|
||||
array($new_command),
|
||||
$new_args);
|
||||
}
|
||||
}
|
||||
|
||||
$arguments = $workflow->getArguments();
|
||||
|
||||
$prev = idx($argv, $pos - 1, null);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
phutil_require_module('arcanist', 'repository/api/base');
|
||||
phutil_require_module('arcanist', 'workflow/alias');
|
||||
phutil_require_module('arcanist', 'workflow/base');
|
||||
phutil_require_module('arcanist', 'workingcopyidentity');
|
||||
|
||||
|
|
Loading…
Reference in a new issue