mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-22 23:02:41 +01:00
arc linters: Filter by name, make display one-line
Summary: allow searching/filtering linters displayed by name. Test Plan: `$ arc linters --verbose --search JSon --search ruby` (Lots of text about many linters) `$ arc linters --search JSon ruby` (error message) `$ arc linters python` (no results, "try --search"). `$ arc linters ruby` (Verbose text about the "ruby" linter). Reviewers: joshuaspence, #blessed_reviewers, epriestley Reviewed By: joshuaspence, #blessed_reviewers, epriestley Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D10706
This commit is contained in:
parent
18e32d6ec7
commit
1ed98937c4
1 changed files with 196 additions and 119 deletions
|
@ -11,7 +11,7 @@ final class ArcanistLintersWorkflow extends ArcanistWorkflow {
|
||||||
|
|
||||||
public function getCommandSynopses() {
|
public function getCommandSynopses() {
|
||||||
return phutil_console_format(<<<EOTEXT
|
return phutil_console_format(<<<EOTEXT
|
||||||
**linters** [__options__]
|
**linters** [__options__] [__name__]
|
||||||
EOTEXT
|
EOTEXT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ EOTEXT
|
||||||
Supports: cli
|
Supports: cli
|
||||||
List the available and configured linters, with information about
|
List the available and configured linters, with information about
|
||||||
what they do and which versions are installed.
|
what they do and which versions are installed.
|
||||||
|
|
||||||
|
if __name__ is provided, the linter with that name will be displayed.
|
||||||
EOTEXT
|
EOTEXT
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -30,6 +32,14 @@ EOTEXT
|
||||||
'verbose' => array(
|
'verbose' => array(
|
||||||
'help' => pht('Show detailed information, including options.'),
|
'help' => pht('Show detailed information, including options.'),
|
||||||
),
|
),
|
||||||
|
'search' => array(
|
||||||
|
'param' => 'search',
|
||||||
|
'repeat' => true,
|
||||||
|
'help' => pht(
|
||||||
|
'Search for linters. Search is case-insensitive, and is performed'.
|
||||||
|
'against name and description of each linter.'),
|
||||||
|
),
|
||||||
|
'*' => 'exact',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +56,164 @@ EOTEXT
|
||||||
$built = array();
|
$built = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$linter_info = $this->getLintersInfo($linters, $built);
|
||||||
|
|
||||||
|
$status_map = $this->getStatusMap();
|
||||||
|
$pad = ' ';
|
||||||
|
|
||||||
|
$color_map = array(
|
||||||
|
'configured' => 'green',
|
||||||
|
'available' => 'yellow',
|
||||||
|
'error' => 'red',
|
||||||
|
);
|
||||||
|
|
||||||
|
$is_verbose = $this->getArgument('verbose');
|
||||||
|
$exact = $this->getArgument('exact');
|
||||||
|
$search_terms = $this->getArgument('search');
|
||||||
|
|
||||||
|
if ($exact && $search_terms) {
|
||||||
|
throw new ArcanistUsageException(
|
||||||
|
'Specify either search expression or exact name');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exact) {
|
||||||
|
$linter_info = $this->findExactNames($linter_info, $exact);
|
||||||
|
if (!$linter_info) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'No match found. Try `%s %s` to search for a linter.',
|
||||||
|
'arc linters --search',
|
||||||
|
$exact[0]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$is_verbose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($search_terms) {
|
||||||
|
$linter_info = $this->filterByNames($linter_info, $search_terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($linter_info as $key => $linter) {
|
||||||
|
$status = $linter['status'];
|
||||||
|
$color = $color_map[$status];
|
||||||
|
$text = $status_map[$status];
|
||||||
|
$print_tail = false;
|
||||||
|
|
||||||
|
$console->writeOut(
|
||||||
|
"<bg:".$color.">** %s **</bg> **%s** (%s)\n",
|
||||||
|
$text,
|
||||||
|
nonempty($linter['short'], '-'),
|
||||||
|
$linter['name']);
|
||||||
|
|
||||||
|
if ($linter['exception']) {
|
||||||
|
$console->writeOut(
|
||||||
|
"\n%s**%s**\n%s\n",
|
||||||
|
$pad,
|
||||||
|
get_class($linter['exception']),
|
||||||
|
phutil_console_wrap(
|
||||||
|
$linter['exception']->getMessage(),
|
||||||
|
strlen($pad)));
|
||||||
|
$print_tail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_verbose) {
|
||||||
|
$version = $linter['version'];
|
||||||
|
$uri = $linter['uri'];
|
||||||
|
if ($version || $uri) {
|
||||||
|
$console->writeOut("\n");
|
||||||
|
$print_tail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($version) {
|
||||||
|
$console->writeOut("%s%s **%s**\n", $pad, pht('Version'), $version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($uri) {
|
||||||
|
$console->writeOut("%s__%s__\n", $pad, $linter['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$description = $linter['description'];
|
||||||
|
if ($description) {
|
||||||
|
$console->writeOut(
|
||||||
|
"\n%s\n",
|
||||||
|
phutil_console_wrap($linter['description'], strlen($pad)));
|
||||||
|
$print_tail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = $linter['options'];
|
||||||
|
if ($options) {
|
||||||
|
$console->writeOut(
|
||||||
|
"\n%s**%s**\n\n",
|
||||||
|
$pad,
|
||||||
|
pht('Configuration Options'));
|
||||||
|
|
||||||
|
$last_option = last_key($options);
|
||||||
|
foreach ($options as $option => $option_spec) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s__%s__ (%s)\n",
|
||||||
|
$pad,
|
||||||
|
$option,
|
||||||
|
$option_spec['type']);
|
||||||
|
|
||||||
|
$console->writeOut(
|
||||||
|
"%s\n",
|
||||||
|
phutil_console_wrap(
|
||||||
|
$option_spec['help'],
|
||||||
|
strlen($pad) + 2));
|
||||||
|
|
||||||
|
if ($option != $last_option) {
|
||||||
|
$console->writeOut("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$print_tail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($print_tail) {
|
||||||
|
$console->writeOut("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$is_verbose) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s\n",
|
||||||
|
pht('(Run `%s` for more details.)', 'arc linters --verbose'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get human-readable linter statuses, padded to fixed width.
|
||||||
|
*
|
||||||
|
* @return map<string, string> Human-readable linter status names.
|
||||||
|
*/
|
||||||
|
private function getStatusMap() {
|
||||||
|
$text_map = array(
|
||||||
|
'configured' => pht('CONFIGURED'),
|
||||||
|
'available' => pht('AVAILABLE'),
|
||||||
|
'error' => pht('ERROR'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$sizes = array();
|
||||||
|
foreach ($text_map as $key => $string) {
|
||||||
|
$sizes[$key] = phutil_utf8_console_strlen($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
$longest = max($sizes);
|
||||||
|
foreach ($text_map as $key => $string) {
|
||||||
|
if ($sizes[$key] < $longest) {
|
||||||
|
$text_map[$key] .= str_repeat(' ', $longest - $sizes[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$text_map['padding'] = str_repeat(' ', $longest);
|
||||||
|
|
||||||
|
return $text_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLintersInfo(array $linters, array $built) {
|
||||||
// Note that an engine can emit multiple linters of the same class to run
|
// Note that an engine can emit multiple linters of the same class to run
|
||||||
// different rulesets on different groups of files, so these linters do not
|
// different rulesets on different groups of files, so these linters do not
|
||||||
// necessarily have unique classes or types.
|
// necessarily have unique classes or types.
|
||||||
|
@ -85,131 +253,40 @@ EOTEXT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$linter_info = isort($linter_info, 'short');
|
return isort($linter_info, 'short');
|
||||||
|
|
||||||
$status_map = $this->getStatusMap();
|
|
||||||
$pad = ' ';
|
|
||||||
|
|
||||||
$color_map = array(
|
|
||||||
'configured' => 'green',
|
|
||||||
'available' => 'yellow',
|
|
||||||
'error' => 'red',
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($linter_info as $key => $linter) {
|
|
||||||
$status = $linter['status'];
|
|
||||||
$color = $color_map[$status];
|
|
||||||
$text = $status_map[$status];
|
|
||||||
$print_tail = false;
|
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
"<bg:".$color.">** %s **</bg> **%s** (%s)\n",
|
|
||||||
$text,
|
|
||||||
nonempty($linter['short'], '-'),
|
|
||||||
$linter['name']);
|
|
||||||
|
|
||||||
if ($linter['exception']) {
|
|
||||||
$console->writeOut(
|
|
||||||
"\n%s**%s**\n%s\n",
|
|
||||||
$pad,
|
|
||||||
get_class($linter['exception']),
|
|
||||||
phutil_console_wrap(
|
|
||||||
$linter['exception']->getMessage(),
|
|
||||||
strlen($pad)));
|
|
||||||
$print_tail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = $linter['version'];
|
|
||||||
$uri = $linter['uri'];
|
|
||||||
if ($version || $uri) {
|
|
||||||
$console->writeOut("\n");
|
|
||||||
$print_tail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($version) {
|
|
||||||
$console->writeOut("%s%s **%s**\n", $pad, pht('Version'), $version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uri) {
|
|
||||||
$console->writeOut("%s__%s__\n", $pad, $linter['uri']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$description = $linter['description'];
|
|
||||||
if ($description) {
|
|
||||||
$console->writeOut(
|
|
||||||
"\n%s\n",
|
|
||||||
phutil_console_wrap($linter['description'], strlen($pad)));
|
|
||||||
$print_tail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = $linter['options'];
|
|
||||||
if ($options && $this->getArgument('verbose')) {
|
|
||||||
$console->writeOut(
|
|
||||||
"\n%s**%s**\n\n",
|
|
||||||
$pad,
|
|
||||||
pht('Configuration Options'));
|
|
||||||
|
|
||||||
$last_option = last_key($options);
|
|
||||||
foreach ($options as $option => $option_spec) {
|
|
||||||
$console->writeOut(
|
|
||||||
"%s__%s__ (%s)\n",
|
|
||||||
$pad,
|
|
||||||
$option,
|
|
||||||
$option_spec['type']);
|
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
"%s\n",
|
|
||||||
phutil_console_wrap(
|
|
||||||
$option_spec['help'],
|
|
||||||
strlen($pad) + 2));
|
|
||||||
|
|
||||||
if ($option != $last_option) {
|
|
||||||
$console->writeOut("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$print_tail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($print_tail) {
|
|
||||||
$console->writeOut("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->getArgument('verbose')) {
|
|
||||||
$console->writeOut(
|
|
||||||
"%s\n",
|
|
||||||
pht('(Run `%s` for more details.)', 'arc linters --verbose'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function filterByNames(array $linters, array $search_terms) {
|
||||||
|
$filtered = array();
|
||||||
|
|
||||||
/**
|
foreach ($linters as $key => $linter) {
|
||||||
* Get human-readable linter statuses, padded to fixed width.
|
$name = $linter['name'];
|
||||||
*
|
$short = $linter['short'];
|
||||||
* @return map<string, string> Human-readable linter status names.
|
$description = $linter['description'];
|
||||||
*/
|
foreach ($search_terms as $term) {
|
||||||
private function getStatusMap() {
|
if (stripos($name, $term) !== false ||
|
||||||
$text_map = array(
|
stripos($short, $term) !== false ||
|
||||||
'configured' => pht('CONFIGURED'),
|
stripos($description, $term) !== false) {
|
||||||
'available' => pht('AVAILABLE'),
|
$filtered[$key] = $linter;
|
||||||
'error' => pht('ERROR'),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
$sizes = array();
|
|
||||||
foreach ($text_map as $key => $string) {
|
|
||||||
$sizes[$key] = phutil_utf8_console_strlen($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
$longest = max($sizes);
|
|
||||||
foreach ($text_map as $key => $string) {
|
|
||||||
if ($sizes[$key] < $longest) {
|
|
||||||
$text_map[$key] .= str_repeat(' ', $longest - $sizes[$key]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $filtered;
|
||||||
|
}
|
||||||
|
|
||||||
$text_map['padding'] = str_repeat(' ', $longest);
|
private function findExactNames(array $linters, array $names) {
|
||||||
|
$filtered = array();
|
||||||
|
|
||||||
return $text_map;
|
foreach ($linters as $key => $linter) {
|
||||||
|
$name = $linter['name'];
|
||||||
|
|
||||||
|
foreach ($names as $term) {
|
||||||
|
if (strcasecmp($name, $term) == 0) {
|
||||||
|
$filtered[$key] = $linter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue