Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistLintWorkflow.php
| Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | return phutil_console_format(<<<EOTEXT | ||||
| are specified, lint will be run on all files which have been modified. | are specified, lint will be run on all files which have been modified. | ||||
| EOTEXT | EOTEXT | ||||
| ); | ); | ||||
| } | } | ||||
| public function getArguments() { | public function getArguments() { | ||||
| return array( | return array( | ||||
| 'lintall' => array( | 'lintall' => array( | ||||
| 'help' => | 'help' => pht( | ||||
| 'Show all lint warnings, not just those on changed lines. When '. | 'Show all lint warnings, not just those on changed lines. When '. | ||||
| 'paths are specified, this is the default behavior.', | 'paths are specified, this is the default behavior.'), | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'only-changed' => true, | 'only-changed' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'only-changed' => array( | 'only-changed' => array( | ||||
| 'help' => | 'help' => pht( | ||||
| 'Show lint warnings just on changed lines. When no paths are '. | 'Show lint warnings just on changed lines. When no paths are '. | ||||
| 'specified, this is the default. This differs from only-new '. | 'specified, this is the default. This differs from only-new '. | ||||
| 'in cases where line modifications introduce lint on other '. | 'in cases where line modifications introduce lint on other '. | ||||
| 'unmodified lines.', | 'unmodified lines.'), | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'lintall' => true, | 'lintall' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'rev' => array( | 'rev' => array( | ||||
| 'param' => 'revision', | 'param' => 'revision', | ||||
| 'help' => 'Lint changes since a specific revision.', | 'help' => pht('Lint changes since a specific revision.'), | ||||
| 'supports' => array( | 'supports' => array( | ||||
| 'git', | 'git', | ||||
| 'hg', | 'hg', | ||||
| ), | ), | ||||
| 'nosupport' => array( | 'nosupport' => array( | ||||
| 'svn' => 'Lint does not currently support --rev in SVN.', | 'svn' => pht('Lint does not currently support %s in SVN.', '--rev'), | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'output' => array( | 'output' => array( | ||||
| 'param' => 'format', | 'param' => 'format', | ||||
| 'help' => | 'help' => pht( | ||||
| "With 'summary', show lint warnings in a more compact format. ". | "With 'summary', show lint warnings in a more compact format. ". | ||||
| "With 'json', show lint warnings in machine-readable JSON format. ". | "With 'json', show lint warnings in machine-readable JSON format. ". | ||||
| "With 'none', show no lint warnings. ". | "With 'none', show no lint warnings. ". | ||||
| "With 'compiler', show lint warnings in suitable for your editor. ". | "With 'compiler', show lint warnings in suitable for your editor. ". | ||||
| "With 'xml', show lint warnings in the Checkstyle XML format.", | "With 'xml', show lint warnings in the Checkstyle XML format."), | ||||
| ), | ), | ||||
| 'only-new' => array( | 'only-new' => array( | ||||
| 'param' => 'bool', | 'param' => 'bool', | ||||
| 'supports' => array('git', 'hg'), // TODO: svn | 'supports' => array('git', 'hg'), // TODO: svn | ||||
| 'help' => 'Display only messages not present in the original code.', | 'help' => pht( | ||||
| 'Display only messages not present in the original code.'), | |||||
| ), | ), | ||||
| 'engine' => array( | 'engine' => array( | ||||
| 'param' => 'classname', | 'param' => 'classname', | ||||
| 'help' => | 'help' => pht('Override configured lint engine for this project.'), | ||||
| 'Override configured lint engine for this project.', | |||||
| ), | ), | ||||
| 'apply-patches' => array( | 'apply-patches' => array( | ||||
| 'help' => | 'help' => pht( | ||||
| 'Apply patches suggested by lint to the working copy without '. | 'Apply patches suggested by lint to the working copy without '. | ||||
| 'prompting.', | 'prompting.'), | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'never-apply-patches' => true, | 'never-apply-patches' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'never-apply-patches' => array( | 'never-apply-patches' => array( | ||||
| 'help' => 'Never apply patches suggested by lint.', | 'help' => pht('Never apply patches suggested by lint.'), | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'apply-patches' => true, | 'apply-patches' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'amend-all' => array( | 'amend-all' => array( | ||||
| 'help' => | 'help' => pht( | ||||
| 'When linting git repositories, amend HEAD with all patches '. | 'When linting git repositories, amend HEAD with all patches '. | ||||
| 'suggested by lint without prompting.', | 'suggested by lint without prompting.'), | ||||
| ), | ), | ||||
| 'amend-autofixes' => array( | 'amend-autofixes' => array( | ||||
| 'help' => | 'help' => pht( | ||||
| 'When linting git repositories, amend HEAD with autofix '. | 'When linting git repositories, amend HEAD with autofix '. | ||||
| 'patches suggested by lint without prompting.', | 'patches suggested by lint without prompting.'), | ||||
| ), | ), | ||||
| 'everything' => array( | 'everything' => array( | ||||
| 'help' => 'Lint all files in the project.', | 'help' => pht('Lint all files in the project.'), | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'cache' => '--everything lints all files', | 'cache' => pht('%s lints all files', '--everything'), | ||||
| 'rev' => '--everything lints all files', | 'rev' => pht('%s lints all files', '--everything'), | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'severity' => array( | 'severity' => array( | ||||
| 'param' => 'string', | 'param' => 'string', | ||||
| 'help' => | 'help' => pht( | ||||
| "Set minimum message severity. One of: '". | "Set minimum message severity. One of: %s. Defaults to '%s'.", | ||||
| sprintf( | |||||
| "'%s'", | |||||
| implode( | implode( | ||||
| "', '", | "', '", | ||||
| array_keys(ArcanistLintSeverity::getLintSeverities())). | array_keys(ArcanistLintSeverity::getLintSeverities()))), | ||||
| "'. Defaults to '".self::DEFAULT_SEVERITY."'.", | self::DEFAULT_SEVERITY), | ||||
| ), | ), | ||||
| 'cache' => array( | 'cache' => array( | ||||
| 'param' => 'bool', | 'param' => 'bool', | ||||
| 'help' => | 'help' => pht( | ||||
| "0 to disable cache, 1 to enable. The default value is ". | "%d to disable cache, %d to enable. The default value is determined ". | ||||
| "determined by 'arc.lint.cache' in configuration, which defaults ". | "by '%s' in configuration, which defaults to off. See notes in '%s'.", | ||||
| "to off. See notes in 'arc.lint.cache'.", | 0, | ||||
| 1, | |||||
| 'arc.lint.cache', | |||||
| 'arc.lint.cache'), | |||||
| ), | ), | ||||
| '*' => 'paths', | '*' => 'paths', | ||||
| ); | ); | ||||
| } | } | ||||
| public function requiresAuthentication() { | public function requiresAuthentication() { | ||||
| return (bool)$this->getArgument('only-new'); | return (bool)$this->getArgument('only-new'); | ||||
| } | } | ||||
| Show All 22 Lines | public function run() { | ||||
| $engine = $this->newLintEngine($this->getArgument('engine')); | $engine = $this->newLintEngine($this->getArgument('engine')); | ||||
| $rev = $this->getArgument('rev'); | $rev = $this->getArgument('rev'); | ||||
| $paths = $this->getArgument('paths'); | $paths = $this->getArgument('paths'); | ||||
| $use_cache = $this->getArgument('cache', null); | $use_cache = $this->getArgument('cache', null); | ||||
| $everything = $this->getArgument('everything'); | $everything = $this->getArgument('everything'); | ||||
| if ($everything && $paths) { | if ($everything && $paths) { | ||||
| throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
| 'You can not specify paths with --everything. The --everything '. | pht( | ||||
| 'flag lints every file.'); | 'You can not specify paths with %s. The %s flag lints every file.', | ||||
| '--everything', | |||||
| '--everything')); | |||||
| } | } | ||||
| if ($use_cache === null) { | if ($use_cache === null) { | ||||
| $use_cache = (bool)$configuration_manager->getConfigFromAnySource( | $use_cache = (bool)$configuration_manager->getConfigFromAnySource( | ||||
| 'arc.lint.cache', | 'arc.lint.cache', | ||||
| false); | false); | ||||
| } | } | ||||
| if ($rev && $paths) { | if ($rev && $paths) { | ||||
| throw new ArcanistUsageException('Specify either --rev or paths.'); | throw new ArcanistUsageException( | ||||
| pht('Specify either %s or paths.', '--rev')); | |||||
| } | } | ||||
| // NOTE: When the user specifies paths, we imply --lintall and show all | // NOTE: When the user specifies paths, we imply --lintall and show all | ||||
| // warnings for the paths in question. This is easier to deal with for | // warnings for the paths in question. This is easier to deal with for | ||||
| // us and less confusing for users. | // us and less confusing for users. | ||||
| $this->shouldLintAll = $paths ? true : false; | $this->shouldLintAll = $paths ? true : false; | ||||
| if ($this->getArgument('lintall')) { | if ($this->getArgument('lintall')) { | ||||
| Show All 34 Lines | if ($use_cache) { | ||||
| $messages = idx($cache[$path], $file_hashes[$abs_path]); | $messages = idx($cache[$path], $file_hashes[$abs_path]); | ||||
| if ($messages !== null) { | if ($messages !== null) { | ||||
| $cached[$path] = $messages; | $cached[$path] = $messages; | ||||
| } | } | ||||
| } | } | ||||
| if ($cached) { | if ($cached) { | ||||
| $console->writeErr( | $console->writeErr( | ||||
| pht("Using lint cache, use '--cache 0' to disable it.")."\n"); | "%s\n", | ||||
| pht( | |||||
| "Using lint cache, use '%s' to disable it.", | |||||
| '--cache 0')); | |||||
| } | } | ||||
| $engine->setCachedResults($cached); | $engine->setCachedResults($cached); | ||||
| } | } | ||||
| // Propagate information about which lines changed to the lint engine. | // Propagate information about which lines changed to the lint engine. | ||||
| // This is used so that the lint engine can drop warning messages | // This is used so that the lint engine can drop warning messages | ||||
| // concerning lines that weren't in the change. | // concerning lines that weren't in the change. | ||||
| ▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | foreach ($results as $result) { | ||||
| // TODO: Improve the behavior here, make it more like | // TODO: Improve the behavior here, make it more like | ||||
| // difference_render(). | // difference_render(). | ||||
| list(, $stdout, $stderr) = | list(, $stdout, $stderr) = | ||||
| exec_manual('diff -u %s %s', $old_file, $new_file); | exec_manual('diff -u %s %s', $old_file, $new_file); | ||||
| $console->writeOut('%s', $stdout); | $console->writeOut('%s', $stdout); | ||||
| $console->writeErr('%s', $stderr); | $console->writeErr('%s', $stderr); | ||||
| $prompt = phutil_console_format( | $prompt = pht( | ||||
| 'Apply this patch to __%s__?', | 'Apply this patch to %s?', | ||||
| $result->getPath()); | phutil_console_format('__%s__', $result->getPath())); | ||||
| if (!$console->confirm($prompt, $default_no = false)) { | if (!$console->confirm($prompt, $default_no = false)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| $patcher->writePatchToDisk(); | $patcher->writePatchToDisk(); | ||||
| $wrote_to_disk = true; | $wrote_to_disk = true; | ||||
| $file_hashes[$old_file] = md5_file($old_file); | $file_hashes[$old_file] = md5_file($old_file); | ||||
| } | } | ||||
| } | } | ||||
| $console->writeOut('%s', $renderer->renderPostamble()); | $console->writeOut('%s', $renderer->renderPostamble()); | ||||
| if ($wrote_to_disk && $this->shouldAmendChanges) { | if ($wrote_to_disk && $this->shouldAmendChanges) { | ||||
| if ($this->shouldAmendWithoutPrompt || | if ($this->shouldAmendWithoutPrompt || | ||||
| ($this->shouldAmendAutofixesWithoutPrompt && $all_autofix)) { | ($this->shouldAmendAutofixesWithoutPrompt && $all_autofix)) { | ||||
| $console->writeOut( | $console->writeOut( | ||||
| "<bg:yellow>** LINT NOTICE **</bg> Automatically amending HEAD ". | "<bg:yellow>** %s **</bg> %s\n", | ||||
| "with lint patches.\n"); | pht('LINT NOTICE'), | ||||
| pht('Automatically amending HEAD with lint patches.')); | |||||
| $amend = true; | $amend = true; | ||||
| } else { | } else { | ||||
| $amend = $console->confirm('Amend HEAD with lint patches?'); | $amend = $console->confirm(pht('Amend HEAD with lint patches?')); | ||||
| } | } | ||||
| if ($amend) { | if ($amend) { | ||||
| if ($repository_api instanceof ArcanistGitAPI) { | if ($repository_api instanceof ArcanistGitAPI) { | ||||
| // Add the changes to the index before amending | // Add the changes to the index before amending | ||||
| $repository_api->execxLocal('add -u'); | $repository_api->execxLocal('add -u'); | ||||
| } | } | ||||
| $repository_api->amendCommit(); | $repository_api->amendCommit(); | ||||
| } else { | } else { | ||||
| throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
| pht( | |||||
| 'Sort out the lint changes that were applied to the working '. | 'Sort out the lint changes that were applied to the working '. | ||||
| 'copy and relint.'); | 'copy and relint.')); | ||||
| } | } | ||||
| } | } | ||||
| if ($this->getArgument('output') == 'json') { | if ($this->getArgument('output') == 'json') { | ||||
| // NOTE: Required by save_lint.php in Phabricator. | // NOTE: Required by save_lint.php in Phabricator. | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 97 Lines • Show Last 20 Lines | |||||