Page MenuHomePhorge

No OneTemporary

diff --git a/src/lint/linter/ArcanistCSSLintLinter.php b/src/lint/linter/ArcanistCSSLintLinter.php
index 4c587357..45bb0f4e 100644
--- a/src/lint/linter/ArcanistCSSLintLinter.php
+++ b/src/lint/linter/ArcanistCSSLintLinter.php
@@ -1,121 +1,121 @@
<?php
/**
* Uses "CSS Lint" to detect checkstyle errors in css code.
*/
final class ArcanistCSSLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'CSSLint';
}
public function getInfoURI() {
return 'http://csslint.net';
}
public function getInfoDescription() {
return pht('Use `csslint` to detect issues with CSS source files.');
}
public function getLinterName() {
return 'CSSLint';
}
public function getLinterConfigurationName() {
return 'csslint';
}
- public function getMandatoryFlags() {
+ protected function getMandatoryFlags() {
return array(
'--format=lint-xml',
'--quiet',
);
}
- public function getDefaultFlags() {
+ protected function getDefaultFlags() {
return $this->getDeprecatedConfiguration('lint.csslint.options', array());
}
public function getDefaultBinary() {
return $this->getDeprecatedConfiguration('lint.csslint.bin', 'csslint');
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^v(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install CSSLint using `npm install -g csslint`.');
}
public function shouldExpectCommandErrors() {
return true;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$report_dom = new DOMDocument();
$ok = @$report_dom->loadXML($stdout);
if (!$ok) {
return false;
}
$files = $report_dom->getElementsByTagName('file');
$messages = array();
foreach ($files as $file) {
foreach ($file->childNodes as $child) {
if (!($child instanceof DOMElement)) {
continue;
}
$data = $this->getData($path);
$lines = explode("\n", $data);
$name = $child->getAttribute('reason');
$severity = ($child->getAttribute('severity') == 'warning')
? ArcanistLintSeverity::SEVERITY_WARNING
: ArcanistLintSeverity::SEVERITY_ERROR;
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($child->getAttribute('line'));
$message->setChar($child->getAttribute('char'));
$message->setCode('CSSLint');
$message->setDescription($child->getAttribute('reason'));
$message->setSeverity($severity);
if ($child->hasAttribute('line') && $child->getAttribute('line') > 0) {
$line = $lines[$child->getAttribute('line') - 1];
$text = substr($line, $child->getAttribute('char') - 1);
$message->setOriginalText($text);
}
$messages[] = $message;
}
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
// NOTE: We can't figure out which rule generated each message, so we
// can not customize severities. I opened a pull request to add this
// ability; see:
//
// https://github.com/stubbornella/csslint/pull/409
throw new Exception(
pht(
"CSSLint does not currently support custom severity levels, because ".
"rules can't be identified from messages in output. ".
"See Pull Request #409."));
}
}
diff --git a/src/lint/linter/ArcanistCSharpLinter.php b/src/lint/linter/ArcanistCSharpLinter.php
index c43bde4b..3d466568 100644
--- a/src/lint/linter/ArcanistCSharpLinter.php
+++ b/src/lint/linter/ArcanistCSharpLinter.php
@@ -1,248 +1,248 @@
<?php
/**
* C# linter for Arcanist.
*/
final class ArcanistCSharpLinter extends ArcanistLinter {
private $runtimeEngine;
private $cslintEngine;
private $cslintHintPath;
private $loaded;
private $discoveryMap;
private $futures;
const SUPPORTED_VERSION = 1;
public function getLinterName() {
return 'C#';
}
public function getLinterConfigurationName() {
return 'csharp';
}
public function getLinterConfigurationOptions() {
$options = parent::getLinterConfigurationOptions();
$options['discovery'] = array(
'type' => 'map<string, list<string>>',
'help' => pht('Provide a discovery map.'),
);
// TODO: This should probably be replaced with "bin" when this moves
// to extend ExternalLinter.
$options['binary'] = array(
'type' => 'string',
'help' => pht('Override default binary.'),
);
return $options;
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'discovery':
$this->discoveryMap = $value;
return;
case 'binary':
$this->cslintHintPath = $value;
return;
}
parent::setLinterConfigurationValue($key, $value);
}
- public function getLintCodeFromLinterConfigurationKey($code) {
+ protected function getLintCodeFromLinterConfigurationKey($code) {
return $code;
}
public function setCustomSeverityMap(array $map) {
foreach ($map as $code => $severity) {
if (substr($code, 0, 2) === 'SA' && $severity == 'disabled') {
throw new Exception(
"In order to keep StyleCop integration with IDEs and other tools ".
"consistent with Arcanist results, you aren't permitted to ".
"disable StyleCop rules within '.arclint'. ".
"Instead configure the severity using the StyleCop settings dialog ".
"(usually accessible from within your IDE). StyleCop settings ".
"for your project will be used when linting for Arcanist.");
}
}
return parent::setCustomSeverityMap($map);
}
/**
* Determines what executables and lint paths to use. Between platforms
* this also changes whether the lint engine is run under .NET or Mono. It
* also ensures that all of the required binaries are available for the lint
* to run successfully.
*
* @return void
*/
private function loadEnvironment() {
if ($this->loaded) {
return;
}
// Determine runtime engine (.NET or Mono).
if (phutil_is_windows()) {
$this->runtimeEngine = '';
} else if (Filesystem::binaryExists('mono')) {
$this->runtimeEngine = 'mono ';
} else {
throw new Exception('Unable to find Mono and you are not on Windows!');
}
// Determine cslint path.
$cslint = $this->cslintHintPath;
if ($cslint !== null && file_exists($cslint)) {
$this->cslintEngine = Filesystem::resolvePath($cslint);
} else if (Filesystem::binaryExists('cslint.exe')) {
$this->cslintEngine = 'cslint.exe';
} else {
throw new Exception('Unable to locate cslint.');
}
// Determine cslint version.
$ver_future = new ExecFuture(
'%C -v',
$this->runtimeEngine.$this->cslintEngine);
list($err, $stdout, $stderr) = $ver_future->resolve();
if ($err !== 0) {
throw new Exception(
'You are running an old version of cslint. Please '.
'upgrade to version '.self::SUPPORTED_VERSION.'.');
}
$ver = (int)$stdout;
if ($ver < self::SUPPORTED_VERSION) {
throw new Exception(
'You are running an old version of cslint. Please '.
'upgrade to version '.self::SUPPORTED_VERSION.'.');
} else if ($ver > self::SUPPORTED_VERSION) {
throw new Exception(
'Arcanist does not support this version of cslint (it is '.
'newer). You can try upgrading Arcanist with `arc upgrade`.');
}
$this->loaded = true;
}
public function lintPath($path) {}
public function willLintPaths(array $paths) {
$this->loadEnvironment();
$futures = array();
// Bulk linting up into futures, where the number of files
// is based on how long the command is.
$current_paths = array();
foreach ($paths as $path) {
// If the current paths for the command, plus the next path
// is greater than 6000 characters (less than the Windows
// command line limit), then finalize this future and add it.
$total = 0;
foreach ($current_paths as $current_path) {
$total += strlen($current_path) + 3; // Quotes and space.
}
if ($total + strlen($path) > 6000) {
// %s won't pass through the JSON correctly
// under Windows. This is probably because not only
// does the JSON have quotation marks in the content,
// but because there'll be a lot of escaping and
// double escaping because the JSON also contains
// regular expressions. cslint supports passing the
// settings JSON through base64-encoded to mitigate
// this issue.
$futures[] = new ExecFuture(
'%C --settings-base64=%s -r=. %Ls',
$this->runtimeEngine.$this->cslintEngine,
base64_encode(json_encode($this->discoveryMap)),
$current_paths);
$current_paths = array();
}
// Append the path to the current paths array.
$current_paths[] = $this->getEngine()->getFilePathOnDisk($path);
}
// If we still have paths left in current paths, then we need to create
// a future for those too.
if (count($current_paths) > 0) {
$futures[] = new ExecFuture(
'%C --settings-base64=%s -r=. %Ls',
$this->runtimeEngine.$this->cslintEngine,
base64_encode(json_encode($this->discoveryMap)),
$current_paths);
$current_paths = array();
}
$this->futures = $futures;
}
public function didRunLinters() {
if ($this->futures) {
$futures = id(new FutureIterator($this->futures))
->limit(8);
foreach ($futures as $future) {
$this->resolveFuture($future);
}
}
}
protected function resolveFuture(Future $future) {
list($stdout) = $future->resolvex();
$all_results = json_decode($stdout);
foreach ($all_results as $results) {
if ($results === null || $results->Issues === null) {
return;
}
foreach ($results->Issues as $issue) {
$message = new ArcanistLintMessage();
$message->setPath($results->FileName);
$message->setLine($issue->LineNumber);
$message->setCode($issue->Index->Code);
$message->setName($issue->Index->Name);
$message->setChar($issue->Column);
$message->setOriginalText($issue->OriginalText);
$message->setReplacementText($issue->ReplacementText);
$desc = @vsprintf($issue->Index->Message, $issue->Parameters);
if ($desc === false) {
$desc = $issue->Index->Message;
}
$message->setDescription($desc);
$severity = ArcanistLintSeverity::SEVERITY_ADVICE;
switch ($issue->Index->Severity) {
case 0:
$severity = ArcanistLintSeverity::SEVERITY_ADVICE;
break;
case 1:
$severity = ArcanistLintSeverity::SEVERITY_AUTOFIX;
break;
case 2:
$severity = ArcanistLintSeverity::SEVERITY_WARNING;
break;
case 3:
$severity = ArcanistLintSeverity::SEVERITY_ERROR;
break;
case 4:
$severity = ArcanistLintSeverity::SEVERITY_DISABLED;
break;
}
$severity_override = $this->getLintMessageSeverity($issue->Index->Code);
if ($severity_override !== null) {
$severity = $severity_override;
}
$message->setSeverity($severity);
$this->addLintMessage($message);
}
}
}
protected function getDefaultMessageSeverity($code) {
return null;
}
}
diff --git a/src/lint/linter/ArcanistChmodLinter.php b/src/lint/linter/ArcanistChmodLinter.php
index 7ba4609e..cca739b7 100644
--- a/src/lint/linter/ArcanistChmodLinter.php
+++ b/src/lint/linter/ArcanistChmodLinter.php
@@ -1,133 +1,133 @@
<?php
/**
* Ensures that files are not executable unless they are either binary or
* contain a shebang.
*/
final class ArcanistChmodLinter extends ArcanistLinter {
const LINT_INVALID_EXECUTABLE = 1;
public function getInfoName() {
return 'Chmod';
}
public function getInfoDescription() {
return pht(
'Checks the permissions on files and ensures that they are not made to '.
'be executable unnecessarily. In particular, a file should not be '.
'executable unless it is either binary or contain a shebang.');
}
public function getLinterName() {
return 'CHMOD';
}
public function getLinterConfigurationName() {
return 'chmod';
}
- public function shouldLintBinaryFiles() {
+ protected function shouldLintBinaryFiles() {
return true;
}
public function getLintNameMap() {
return array(
self::LINT_INVALID_EXECUTABLE => pht('Invalid Executable'),
);
}
public function getLintSeverityMap() {
return array(
self::LINT_INVALID_EXECUTABLE => ArcanistLintSeverity::SEVERITY_WARNING,
);
}
public function lintPath($path) {
if (is_executable($path)) {
if ($this->getEngine()->isBinaryFile($path)) {
$mime = Filesystem::getMimeType($path);
switch ($mime) {
// Archives
case 'application/jar':
case 'application/java-archive':
case 'application/x-bzip2':
case 'application/x-gzip':
case 'application/x-rar-compressed':
case 'application/x-tar':
case 'application/zip':
// Audio
case 'audio/midi':
case 'audio/mpeg':
case 'audio/mp4':
case 'audio/x-wav':
// Fonts
case 'application/vnd.ms-fontobject':
case 'application/x-font-ttf':
case 'application/x-woff':
// Images
case 'application/x-shockwave-flash':
case 'image/gif':
case 'image/jpeg':
case 'image/png':
case 'image/tiff':
case 'image/x-icon':
case 'image/x-ms-bmp':
// Miscellaneous
case 'application/msword':
case 'application/pdf':
case 'application/postscript':
case 'application/rtf':
case 'application/vnd.ms-excel':
case 'application/vnd.ms-powerpoint':
// Video
case 'video/mpeg':
case 'video/quicktime':
case 'video/x-flv':
case 'video/x-msvideo':
case 'video/x-ms-wmv':
$this->raiseLintAtPath(
self::LINT_INVALID_EXECUTABLE,
pht("'%s' files should not be executable.", $mime));
return;
}
// Path is a binary file, which makes it a valid executable.
return;
} else if ($this->getShebang($path)) {
// Path contains a shebang, which makes it a valid executable.
return;
} else {
$this->raiseLintAtPath(
self::LINT_INVALID_EXECUTABLE,
pht(
'Executable files should either be binary or contain a shebang.'));
}
}
}
/**
* Returns the path's shebang.
*
* @param string
* @return string|null
*/
private function getShebang($path) {
$line = head(phutil_split_lines($this->getEngine()->loadData($path), true));
$matches = array();
if (preg_match('/^#!(.*)$/', $line, $matches)) {
return $matches[1];
} else {
return null;
}
}
}
diff --git a/src/lint/linter/ArcanistFilenameLinter.php b/src/lint/linter/ArcanistFilenameLinter.php
index e5ba19c5..b9867c5a 100644
--- a/src/lint/linter/ArcanistFilenameLinter.php
+++ b/src/lint/linter/ArcanistFilenameLinter.php
@@ -1,56 +1,56 @@
<?php
/**
* Stifles creativity in choosing imaginative file names.
*/
final class ArcanistFilenameLinter extends ArcanistLinter {
const LINT_BAD_FILENAME = 1;
public function getInfoName() {
return pht('Filename');
}
public function getInfoDescription() {
return pht(
'Stifles developer creativity by requiring files have uninspired names '.
'containing only letters, numbers, period, hyphen and underscore.');
}
public function getLinterName() {
return 'NAME';
}
public function getLinterConfigurationName() {
return 'filename';
}
- public function shouldLintBinaryFiles() {
+ protected function shouldLintBinaryFiles() {
return true;
}
public function getLintNameMap() {
return array(
self::LINT_BAD_FILENAME => pht('Bad Filename'),
);
}
public function lintPath($path) {
if (!preg_match('@^[a-z0-9./\\\\_-]+$@i', $path)) {
$this->raiseLintAtPath(
self::LINT_BAD_FILENAME,
pht(
'Name files using only letters, numbers, period, hyphen and '.
'underscore.'));
}
}
- public function shouldLintDirectories() {
+ protected function shouldLintDirectories() {
return true;
}
- public function shouldLintSymbolicLinks() {
+ protected function shouldLintSymbolicLinks() {
return true;
}
}
diff --git a/src/lint/linter/ArcanistFlake8Linter.php b/src/lint/linter/ArcanistFlake8Linter.php
index ed5bbdc3..658a6dd6 100644
--- a/src/lint/linter/ArcanistFlake8Linter.php
+++ b/src/lint/linter/ArcanistFlake8Linter.php
@@ -1,132 +1,132 @@
<?php
/**
* Uses "flake8" to detect various errors in Python code.
* Requires version 1.7.0 or newer of flake8.
*/
final class ArcanistFlake8Linter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Flake8';
}
public function getInfoURI() {
return 'https://pypi.python.org/pypi/flake8';
}
public function getInfoDescription() {
return pht(
'Uses `flake8` to run several linters (PyFlakes, pep8, and a McCabe '.
'complexity checker) on Python source files.');
}
public function getLinterName() {
return 'flake8';
}
public function getLinterConfigurationName() {
return 'flake8';
}
- public function getDefaultFlags() {
+ protected function getDefaultFlags() {
return $this->getDeprecatedConfiguration('lint.flake8.options', array());
}
public function getDefaultBinary() {
$prefix = $this->getDeprecatedConfiguration('lint.flake8.prefix');
$bin = $this->getDeprecatedConfiguration('lint.flake8.bin', 'flake8');
if ($prefix) {
return $prefix.'/'.$bin;
} else {
return $bin;
}
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+(?:\.\d+)?)\b/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install flake8 using `easy_install flake8`.');
}
public function shouldExpectCommandErrors() {
return true;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
// stdin:2: W802 undefined name 'foo' # pyflakes
// stdin:3:1: E302 expected 2 blank lines, found 1 # pep8
$regexp = '/^(.*?):(\d+):(?:(\d+):)? (\S+) (.*)$/';
if (!preg_match($regexp, $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[2]);
if (!empty($matches[3])) {
$message->setChar($matches[3]);
}
$message->setCode($matches[4]);
$message->setName($this->getLinterName().' '.$matches[3]);
$message->setDescription($matches[5]);
$message->setSeverity($this->getLintMessageSeverity($matches[4]));
$messages[] = $message;
}
if ($err && !$messages) {
return false;
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^C/', $code)) {
// "C": Cyclomatic complexity
return ArcanistLintSeverity::SEVERITY_ADVICE;
} else if (preg_match('/^W/', $code)) {
// "W": PEP8 Warning
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
// "E": PEP8 Error
// "F": PyFlakes Error
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^(E|W|C|F)\d+$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid flake8 '.
'lint code like "%s", or "%s", or "%s", or "%s".',
$code,
'E225',
'W291',
'F811',
'C901'));
}
return $code;
}
}
diff --git a/src/lint/linter/ArcanistHLintLinter.php b/src/lint/linter/ArcanistHLintLinter.php
index 4c2a5efb..312110d4 100644
--- a/src/lint/linter/ArcanistHLintLinter.php
+++ b/src/lint/linter/ArcanistHLintLinter.php
@@ -1,111 +1,111 @@
<?php
/**
* Calls `hlint` and parses its results.
*/
final class ArcanistHLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'HLint';
}
public function getInfoURI() {
return 'https://github.com/ndmitchell/hlint';
}
public function getInfoDescription() {
return pht('HLint is a linter for Haskell code.');
}
public function getLinterName() {
return 'HLINT';
}
public function getLinterConfigurationName() {
return 'hlint';
}
public function getDefaultBinary() {
return 'hlint';
}
public function getInstallInstructions() {
return pht('Install hlint with `cabal install hlint`.');
}
public function supportsReadDataFromStdin() {
return true;
}
public function getReadDataFromStdinFilename() {
return '-';
}
public function shouldExpectCommandErrors() {
return true;
}
- public function getMandatoryFlags() {
+ protected function getMandatoryFlags() {
return array('--json');
}
public function getVersion() {
list($stdout, $stderr) = execx(
'%C --version', $this->getExecutableCommand());
$matches = null;
if (preg_match('@HLint v(.*),@', $stdout, $matches)) {
return $matches[1];
}
return null;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$json = phutil_json_decode($stdout);
$messages = array();
foreach ($json as $fix) {
if ($fix === null) {
return;
}
$message = new ArcanistLintMessage();
$message->setCode($this->getLinterName());
$message->setPath($path);
$message->setLine($fix['startLine']);
$message->setChar($fix['startColumn']);
$message->setName($fix['hint']);
$message->setOriginalText($fix['from']);
$message->setReplacementText($fix['to']);
/* Some improvements may slightly change semantics, so attach
all necessary notes too. */
$notes = '';
foreach ($fix['note'] as $note) {
$notes .= ' **NOTE**: '.trim($note, '"').'.';
}
$message->setDescription(
pht(
'In module `%s`, declaration `%s`.%s',
$fix['module'], $fix['decl'], $notes));
switch ($fix['severity']) {
case 'Error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
case 'Warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
return $messages;
}
}
diff --git a/src/lint/linter/ArcanistPEP8Linter.php b/src/lint/linter/ArcanistPEP8Linter.php
index 2d76e3f7..51608277 100644
--- a/src/lint/linter/ArcanistPEP8Linter.php
+++ b/src/lint/linter/ArcanistPEP8Linter.php
@@ -1,130 +1,130 @@
<?php
/**
* Uses "pep8.py" to enforce PEP8 rules for Python.
*/
final class ArcanistPEP8Linter extends ArcanistExternalLinter {
public function getInfoName() {
return 'pep8';
}
public function getInfoURI() {
return 'https://pypi.python.org/pypi/pep8';
}
public function getInfoDescription() {
return pht(
'pep8 is a tool to check your Python code against some of the '.
'style conventions in PEP 8.');
}
public function getLinterName() {
return 'PEP8';
}
public function getLinterConfigurationName() {
return 'pep8';
}
- public function getDefaultFlags() {
+ protected function getDefaultFlags() {
return $this->getDeprecatedConfiguration('lint.pep8.options', array());
}
public function shouldUseInterpreter() {
return ($this->getDefaultBinary() !== 'pep8');
}
public function getDefaultInterpreter() {
return 'python2.6';
}
public function getDefaultBinary() {
if (Filesystem::binaryExists('pep8')) {
return 'pep8';
}
$old_prefix = $this->getDeprecatedConfiguration('lint.pep8.prefix');
$old_bin = $this->getDeprecatedConfiguration('lint.pep8.bin');
if ($old_prefix || $old_bin) {
$old_bin = nonempty($old_bin, 'pep8');
return $old_prefix.'/'.$old_bin;
}
$arc_root = dirname(phutil_get_library_root('arcanist'));
return $arc_root.'/externals/pep8/pep8.py';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install PEP8 using `easy_install pep8`.');
}
public function shouldExpectCommandErrors() {
return true;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match('/^(.*?):(\d+):(\d+): (\S+) (.*)$/', $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[2]);
$message->setChar($matches[3]);
$message->setCode($matches[4]);
$message->setName('PEP8 '.$matches[4]);
$message->setDescription($matches[5]);
$message->setSeverity($this->getLintMessageSeverity($matches[4]));
$messages[] = $message;
}
if ($err && !$messages) {
return false;
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^W/', $code)) {
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^(E|W)\d+$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid PEP8 '.
'lint code like "%s" or "%s".',
$code,
'E101',
'W291'));
}
return $code;
}
}
diff --git a/src/lint/linter/ArcanistPhpLinter.php b/src/lint/linter/ArcanistPhpLinter.php
index e4851e83..5a0e4dc5 100644
--- a/src/lint/linter/ArcanistPhpLinter.php
+++ b/src/lint/linter/ArcanistPhpLinter.php
@@ -1,85 +1,85 @@
<?php
/**
* Uses "php -l" to detect syntax errors in PHP code.
*/
final class ArcanistPhpLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'php -l';
}
public function getInfoURI() {
return 'http://php.net/';
}
public function getInfoDescription() {
return pht(
'Checks for syntax errors in php files.');
}
public function getLinterName() {
return 'PHP';
}
public function getLinterConfigurationName() {
return 'php';
}
- public function getMandatoryFlags() {
+ protected function getMandatoryFlags() {
return array('-l');
}
public function getInstallInstructions() {
return pht('Install PHP.');
}
public function getDefaultBinary() {
return 'php';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^PHP (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function shouldExpectCommandErrors() {
return true;
}
public function supportsReadDataFromStdin() {
return false;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
// Older versions of php had both on $stdout, newer ones split it
// Combine $stdout and $stderr for consistency
$stdout = $stderr."\n".$stdout;
$matches = array();
$regex = '/^(?<type>.+?) error:\s+(?<error>.*?)\s+in\s+(?<file>.*?)'.
'\s+on line\s+(?<line>\d*)$/m';
if (preg_match($regex, $stdout, $matches)) {
$type = strtolower($matches['type']);
$message = new ArcanistLintMessage();
$message->setPath($matches['file']);
$message->setLine($matches['line']);
$message->setCode('php.'.$type);
$message->setDescription('This file contains a '.$type.' error: '.
$matches['error'].' on line '.$matches['line']);
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
// php -l only returns the first error
return array($message);
}
return array();
}
}
diff --git a/src/lint/linter/ArcanistPhpcsLinter.php b/src/lint/linter/ArcanistPhpcsLinter.php
index 870d1860..e9aefe45 100644
--- a/src/lint/linter/ArcanistPhpcsLinter.php
+++ b/src/lint/linter/ArcanistPhpcsLinter.php
@@ -1,140 +1,140 @@
<?php
/**
* Uses "PHP_CodeSniffer" to detect checkstyle errors in PHP code.
*/
final class ArcanistPhpcsLinter extends ArcanistExternalLinter {
private $reports;
public function getInfoName() {
return 'PHP_CodeSniffer';
}
public function getInfoURI() {
return 'http://pear.php.net/package/PHP_CodeSniffer/';
}
public function getInfoDescription() {
return pht(
'PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and '.
'detects violations of a defined set of coding standards.');
}
public function getLinterName() {
return 'PHPCS';
}
public function getLinterConfigurationName() {
return 'phpcs';
}
public function getMandatoryFlags() {
return array('--report=xml');
}
public function getInstallInstructions() {
return pht('Install PHPCS with `pear install PHP_CodeSniffer`.');
}
- public function getDefaultFlags() {
+ protected function getDefaultFlags() {
$options = $this->getDeprecatedConfiguration('lint.phpcs.options', array());
$standard = $this->getDeprecatedConfiguration('lint.phpcs.standard');
if (!empty($standard)) {
if (is_array($options)) {
$options[] = '--standard='.$standard;
} else {
$options .= ' --standard='.$standard;
}
}
return $options;
}
public function getDefaultBinary() {
return $this->getDeprecatedConfiguration('lint.phpcs.bin', 'phpcs');
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^PHP_CodeSniffer version (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function shouldExpectCommandErrors() {
return true;
}
public function supportsReadDataFromStdin() {
return true;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
// NOTE: Some version of PHPCS after 1.4.6 stopped printing a valid, empty
// XML document to stdout in the case of no errors. If PHPCS exits with
// error 0, just ignore output.
if (!$err) {
return array();
}
$report_dom = new DOMDocument();
$ok = @$report_dom->loadXML($stdout);
if (!$ok) {
return false;
}
$files = $report_dom->getElementsByTagName('file');
$messages = array();
foreach ($files as $file) {
foreach ($file->childNodes as $child) {
if (!($child instanceof DOMElement)) {
continue;
}
if ($child->tagName == 'error') {
$prefix = 'E';
} else {
$prefix = 'W';
}
$code = 'PHPCS.'.$prefix.'.'.$child->getAttribute('source');
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($child->getAttribute('line'));
$message->setChar($child->getAttribute('column'));
$message->setCode($code);
$message->setDescription($child->nodeValue);
$message->setSeverity($this->getLintMessageSeverity($code));
$messages[] = $message;
}
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^PHPCS\\.W\\./', $code)) {
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^PHPCS\\.(E|W)\\./', $code)) {
throw new Exception(
"Invalid severity code '{$code}', should begin with 'PHPCS.'.");
}
return $code;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Jan 19 2025, 22:03 (6 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1129207
Default Alt Text
(34 KB)

Event Timeline