Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10360408
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/workflow/ArcanistLintersWorkflow.php b/src/workflow/ArcanistLintersWorkflow.php
index 9932f3b9..600d1019 100644
--- a/src/workflow/ArcanistLintersWorkflow.php
+++ b/src/workflow/ArcanistLintersWorkflow.php
@@ -1,306 +1,306 @@
<?php
/**
* List available linters.
*/
final class ArcanistLintersWorkflow extends ArcanistWorkflow {
public function getWorkflowName() {
return 'linters';
}
public function getCommandSynopses() {
return phutil_console_format(<<<EOTEXT
**linters** [__options__] [__name__]
EOTEXT
);
}
public function getCommandHelp() {
return phutil_console_format(pht(<<<EOTEXT
Supports: cli
List the available and configured linters, with information about
what they do and which versions are installed.
if __name__ is provided, the linter with that name will be displayed.
EOTEXT
));
}
public function getArguments() {
return array(
'verbose' => array(
'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'.
+ 'Search for linters. Search is case-insensitive, and is performed '.
'against name and description of each linter.'),
),
'*' => 'exact',
);
}
public function run() {
$console = PhutilConsole::getConsole();
$linters = id(new PhutilClassMapQuery())
->setAncestorClass('ArcanistLinter')
->execute();
try {
$built = $this->newLintEngine()->buildLinters();
} catch (ArcanistNoEngineException $ex) {
$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['name'], '-'),
$linter['short']);
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;
}
$additional = $linter['additional'];
foreach ($additional as $title => $body) {
$console->writeOut(
"\n%s**%s**\n\n",
$pad,
$title);
// TODO: This should maybe use `tsprintf`.
// See some discussion in D14563.
echo $body;
}
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
// different rulesets on different groups of files, so these linters do not
// necessarily have unique classes or types.
$groups = array();
foreach ($built as $linter) {
$groups[get_class($linter)][] = $linter;
}
$linter_info = array();
foreach ($linters as $key => $linter) {
$installed = idx($groups, $key, array());
$exception = null;
if ($installed) {
$status = 'configured';
try {
$version = head($installed)->getVersion();
} catch (Exception $ex) {
$status = 'error';
$exception = $ex;
}
} else {
$status = 'available';
$version = null;
}
$linter_info[$key] = array(
'name' => $linter->getLinterConfigurationName(),
'class' => get_class($linter),
'status' => $status,
'version' => $version,
'short' => $linter->getInfoName(),
'uri' => $linter->getInfoURI(),
'description' => $linter->getInfoDescription(),
'exception' => $exception,
'options' => $linter->getLinterConfigurationOptions(),
'additional' => $linter->getAdditionalInformation(),
);
}
return isort($linter_info, 'short');
}
private function filterByNames(array $linters, array $search_terms) {
$filtered = array();
foreach ($linters as $key => $linter) {
$name = $linter['name'];
$short = $linter['short'];
$description = $linter['description'];
foreach ($search_terms as $term) {
if (stripos($name, $term) !== false ||
stripos($short, $term) !== false ||
stripos($description, $term) !== false) {
$filtered[$key] = $linter;
}
}
}
return $filtered;
}
private function findExactNames(array $linters, array $names) {
$filtered = array();
foreach ($linters as $key => $linter) {
$name = $linter['name'];
foreach ($names as $term) {
if (strcasecmp($name, $term) == 0) {
$filtered[$key] = $linter;
}
}
}
return $filtered;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 06:34 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034184
Default Alt Text
(8 KB)
Attached To
Mode
R118 Arcanist - fork
Attached
Detach File
Event Timeline
Log In to Comment