1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-10-24 17:48:50 +02:00
phorge-arcanist/src/lint/linter/ArcanistLinter.php

226 lines
4.9 KiB
PHP
Raw Normal View History

2011-01-10 00:22:25 +01:00
<?php
/**
* Implements lint rules, like syntax checks for a specific language.
*
* @group linter
* @stable
*/
2011-01-10 00:22:25 +01:00
abstract class ArcanistLinter {
const GRANULARITY_FILE = 1;
const GRANULARITY_DIRECTORY = 2;
const GRANULARITY_REPOSITORY = 3;
const GRANULARITY_GLOBAL = 4;
2011-01-10 00:22:25 +01:00
protected $paths = array();
protected $data = array();
protected $engine;
protected $activePath;
protected $messages = array();
protected $stopAllLinters = false;
private $customSeverityMap = array();
private $config = array();
2011-01-10 00:22:25 +01:00
public function setCustomSeverityMap(array $map) {
$this->customSeverityMap = $map;
return $this;
}
public function setConfig(array $config) {
$this->config = $config;
return $this;
}
protected function getConfig($key, $default = null) {
return idx($this->config, $key, $default);
}
2011-01-10 00:22:25 +01:00
public function getActivePath() {
return $this->activePath;
}
public function stopAllLinters() {
$this->stopAllLinters = true;
return $this;
}
public function didStopAllLinters() {
return $this->stopAllLinters;
}
public function addPath($path) {
$this->paths[$path] = $path;
return $this;
}
public function setPaths(array $paths) {
$this->paths = $paths;
return $this;
}
2011-01-10 00:22:25 +01:00
public function getPaths() {
return array_values($this->paths);
}
public function addData($path, $data) {
$this->data[$path] = $data;
return $this;
}
protected function getData($path) {
if (!array_key_exists($path, $this->data)) {
$this->data[$path] = $this->getEngine()->loadData($path);
2011-01-10 00:22:25 +01:00
}
return $this->data[$path];
}
public function setEngine(ArcanistLintEngine $engine) {
2011-01-10 00:22:25 +01:00
$this->engine = $engine;
return $this;
}
protected function getEngine() {
return $this->engine;
}
public function getCacheVersion() {
return 0;
}
2011-01-10 00:22:25 +01:00
public function getLintMessageFullCode($short_code) {
return $this->getLinterName().$short_code;
}
public function getLintMessageSeverity($code) {
$map = $this->customSeverityMap;
if (isset($map[$code])) {
return $map[$code];
}
$map = $this->getLintSeverityMap();
if (isset($map[$code])) {
return $map[$code];
}
return ArcanistLintSeverity::SEVERITY_ERROR;
}
public function isMessageEnabled($code) {
return ($this->getLintMessageSeverity($code) !==
ArcanistLintSeverity::SEVERITY_DISABLED);
}
2011-01-10 00:22:25 +01:00
public function getLintMessageName($code) {
$map = $this->getLintNameMap();
if (isset($map[$code])) {
return $map[$code];
}
return "Unknown lint message!";
}
protected function addLintMessage(ArcanistLintMessage $message) {
if (!$this->getEngine()->getCommitHookMode()) {
$root = $this->getEngine()->getWorkingCopy()->getProjectRoot();
$path = Filesystem::resolvePath($message->getPath(), $root);
$message->setPath(Filesystem::readablePath($path, $root));
}
2011-01-10 00:22:25 +01:00
$this->messages[] = $message;
return $message;
}
public function getLintMessages() {
return $this->messages;
}
protected function newLintAtLine($line, $char, $code, $desc) {
return id(new ArcanistLintMessage())
->setPath($this->getActivePath())
->setLine($line)
->setChar($char)
->setCode($this->getLintMessageFullCode($code))
->setSeverity($this->getLintMessageSeverity($code))
->setName($this->getLintMessageName($code))
->setDescription($desc);
}
2011-01-10 00:22:25 +01:00
protected function raiseLintAtLine(
$line,
$char,
$code,
$desc,
$original = null,
$replacement = null) {
$message = $this->newLintAtLine($line, $char, $code, $desc)
->setOriginalText($original)
->setReplacementText($replacement);
2011-01-10 00:22:25 +01:00
return $this->addLintMessage($message);
2011-01-10 00:22:25 +01:00
}
protected function raiseLintAtPath(
$code,
$desc) {
return $this->raiseLintAtLine(null, null, $code, $desc, null, null);
}
protected function raiseLintAtOffset(
$offset,
$code,
$desc,
$original = null,
$replacement = null) {
$path = $this->getActivePath();
$engine = $this->getEngine();
if ($offset === null) {
$line = null;
$char = null;
} else {
list($line, $char) = $engine->getLineAndCharFromOffset($path, $offset);
}
2011-01-10 00:22:25 +01:00
return $this->raiseLintAtLine(
$line + 1,
$char + 1,
$code,
$desc,
$original,
$replacement);
}
public function willLintPath($path) {
$this->stopAllLinters = false;
$this->activePath = $path;
}
public function canRun() {
return true;
}
2011-01-10 00:22:25 +01:00
abstract public function willLintPaths(array $paths);
abstract public function lintPath($path);
abstract public function getLinterName();
Add "ArcanistSingleLintEngine" and "ArcanistScriptAndRegexLinter" Summary: Request from @csilvers. Allow installs to get most linter features with regexes, configuration and external scripts if they are hesitant to write phutil libraries. - Add "ArcanistSingleLintEngine", which implements the smallest possible engine behavior (run one linter on every path). - Add "ArcanistScriptAndRegexLinter", which uses a script and a regex to parse lint output from other scripts. Depends on D2618. Test Plan: Basics: $ arc set-config lint.engine ArcanistSingleLintEngine Set key 'lint.engine' = 'ArcanistSingleLintEngine'. $ arc set-config lint.engine.single.linter ArcanistScriptAndRegexLinter Set key 'lint.engine.single.linter' = 'ArcanistScriptAndRegexLinter'. $ arc set-config linter.scriptandregex.script 'echo derp #' Set key 'linter.scriptandregex.script' = 'echo derp #'. $ arc set-config linter.scriptandregex.regex '/^(?P<message>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<message>.*)$/m'. $ arc lint >>> Lint for .arcconfig: Error (S&RX) Lint derp 1 { 2 "project_id" : "arcanist", 3 "conduit_uri" : "https://secure.phabricator.com/", Throw: $ arc set-config linter.scriptandregex.regex '/^(?P<throw>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<throw>.*)$/m' (was '/^(?P<message>.*)$/m'). $ arc lint Usage Exception: ArcanistScriptAndRegexLinter: configuration captured a 'throw' named capturing group, 'derp'. Script output: derp Ignore: $ arc set-config linter.scriptandregex.regex '/^(?P<ignore>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<ignore>.*)$/m' (was '/^(?P<throw>.*)$/m'). $ arc lint OKAY No lint warnings. Severity: $ arc set-config linter.scriptandregex.regex '/^(?P<warning>.)(?P<message>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<warning>.)(?P<message>.*)$/m' (was '/^(?P<ignore>.*)$/m'). $ arc lint >>> Lint for src/lint/engine/single/ArcanistSingleLintEngine.php: Warning (S&RX) Lint erp 1 <?php 2 3 /* Reviewers: csilvers, btrahan, vrana Reviewed By: csilvers CC: aran Differential Revision: https://secure.phabricator.com/D2619
2012-05-31 21:09:01 +02:00
public function didRunLinters() {
// This is a hook.
}
Add "ArcanistSingleLintEngine" and "ArcanistScriptAndRegexLinter" Summary: Request from @csilvers. Allow installs to get most linter features with regexes, configuration and external scripts if they are hesitant to write phutil libraries. - Add "ArcanistSingleLintEngine", which implements the smallest possible engine behavior (run one linter on every path). - Add "ArcanistScriptAndRegexLinter", which uses a script and a regex to parse lint output from other scripts. Depends on D2618. Test Plan: Basics: $ arc set-config lint.engine ArcanistSingleLintEngine Set key 'lint.engine' = 'ArcanistSingleLintEngine'. $ arc set-config lint.engine.single.linter ArcanistScriptAndRegexLinter Set key 'lint.engine.single.linter' = 'ArcanistScriptAndRegexLinter'. $ arc set-config linter.scriptandregex.script 'echo derp #' Set key 'linter.scriptandregex.script' = 'echo derp #'. $ arc set-config linter.scriptandregex.regex '/^(?P<message>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<message>.*)$/m'. $ arc lint >>> Lint for .arcconfig: Error (S&RX) Lint derp 1 { 2 "project_id" : "arcanist", 3 "conduit_uri" : "https://secure.phabricator.com/", Throw: $ arc set-config linter.scriptandregex.regex '/^(?P<throw>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<throw>.*)$/m' (was '/^(?P<message>.*)$/m'). $ arc lint Usage Exception: ArcanistScriptAndRegexLinter: configuration captured a 'throw' named capturing group, 'derp'. Script output: derp Ignore: $ arc set-config linter.scriptandregex.regex '/^(?P<ignore>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<ignore>.*)$/m' (was '/^(?P<throw>.*)$/m'). $ arc lint OKAY No lint warnings. Severity: $ arc set-config linter.scriptandregex.regex '/^(?P<warning>.)(?P<message>.*)$/m' Set key 'linter.scriptandregex.regex' = '/^(?P<warning>.)(?P<message>.*)$/m' (was '/^(?P<ignore>.*)$/m'). $ arc lint >>> Lint for src/lint/engine/single/ArcanistSingleLintEngine.php: Warning (S&RX) Lint erp 1 <?php 2 3 /* Reviewers: csilvers, btrahan, vrana Reviewed By: csilvers CC: aran Differential Revision: https://secure.phabricator.com/D2619
2012-05-31 21:09:01 +02:00
public function getLintSeverityMap() {
return array();
}
public function getLintNameMap() {
return array();
}
2011-01-10 00:22:25 +01:00
public function getCacheGranularity() {
return self::GRANULARITY_FILE;
}
2011-01-10 00:22:25 +01:00
}