From 395c15e630632c06c3eac64f015521a2e5b85ca2 Mon Sep 17 00:00:00 2001 From: Lajos Veres Date: Tue, 9 Jul 2013 12:46:59 +0100 Subject: [PATCH] add css lint --- src/lint/engine/ComprehensiveLintEngine.php | 3 + src/lint/linter/ArcanistCSSLintLinter.php | 122 ++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/lint/linter/ArcanistCSSLintLinter.php diff --git a/src/lint/engine/ComprehensiveLintEngine.php b/src/lint/engine/ComprehensiveLintEngine.php index e8a104d2..c138e0c2 100644 --- a/src/lint/engine/ComprehensiveLintEngine.php +++ b/src/lint/engine/ComprehensiveLintEngine.php @@ -48,6 +48,9 @@ final class ComprehensiveLintEngine extends ArcanistLintEngine { $linters[] = id(new ArcanistJSHintLinter()) ->setPaths(preg_grep('/\.js$/', $paths)); + $linters[] = id(new ArcanistCSSLintLinter()) + ->setPaths(preg_grep('/\.css$/', $paths)); + return $linters; } diff --git a/src/lint/linter/ArcanistCSSLintLinter.php b/src/lint/linter/ArcanistCSSLintLinter.php new file mode 100644 index 00000000..fa336374 --- /dev/null +++ b/src/lint/linter/ArcanistCSSLintLinter.php @@ -0,0 +1,122 @@ +getEngine()->getWorkingCopy(); + + $options = $working_copy->getConfig('lint.csslint.options'); + + return $options; + } + + private function getCSSLintPath() { + $working_copy = $this->getEngine()->getWorkingCopy(); + $bin = $working_copy->getConfig('lint.csslint.bin'); + + if ($bin === null) { + $bin = 'csslint'; + } + + return $bin; + } + + public function willLintPaths(array $paths) { + $csslint_bin = $this->getCSSLintPath(); + $csslint_options = $this->getCSSLintOptions(); + $futures = array(); + + foreach ($paths as $path) { + $filepath = $this->getEngine()->getFilePathOnDisk($path); + $this->reports[$path] = new TempFile(); + $futures[$path] = new ExecFuture('%C %C --format=lint-xml >%s %s', + $csslint_bin, + $csslint_options, + $this->reports[$path], + $filepath); + } + + foreach (Futures($futures)->limit(8) as $path => $future) { + $this->results[$path] = $future->resolve(); + } + + libxml_use_internal_errors(true); + } + + public function lintPath($path) { + list($rc, $stdout) = $this->results[$path]; + + $report = Filesystem::readFile($this->reports[$path]); + + if ($report) { + $report_dom = new DOMDocument(); + libxml_clear_errors(); + $report_dom->loadXML($report); + } + if (!$report || libxml_get_errors()) { + throw new ArcanistUsageException('CSS Linter failed to load ' . + 'reporting file. Something happened when running csslint. ' . + "Output:\n$stdout" . + "\nTry running lint with --trace flag to get more details."); + } + + $files = $report_dom->getElementsByTagName('file'); + foreach ($files as $file) { + foreach ($file->childNodes as $child) { + if (!($child instanceof DOMElement)) { + continue; + } + + $data = $this->getData($path); + $lines = explode("\n", $data); + $name = $this->getLinterName() . ' - ' . $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($child->getAttribute('severity')); + $message->setName($name); + $message->setDescription($child->getAttribute('reason')."\nEvidence:".$child->getAttribute('evidence')); + $message->setSeverity($severity); + + if($child->hasAttribute('line')){ + $line = $lines[$child->getAttribute('line') - 1]; + $text = substr($line, $child->getAttribute('char') - 1); + $message->setOriginalText($text); + } + $this->addLintMessage($message); + } + } + } +}