diff --git a/src/difference/ArcanistDiffUtils.php b/src/difference/ArcanistDiffUtils.php index 38207ff5..4006235e 100644 --- a/src/difference/ArcanistDiffUtils.php +++ b/src/difference/ArcanistDiffUtils.php @@ -1,332 +1,332 @@ '; $highlight_c = ''; $n = strlen($str); for ($i = 0; $i < $n; $i++) { if ($p == $e) { do { if (empty($intra_stack)) { $buf .= substr($str, $i); break 2; } $stack = array_shift($intra_stack); $s = $e; $e += $stack[1]; } while ($stack[0] == 0); } if (!$highlight && !$tag && !$ent && $p == $s) { $buf .= $highlight_o; $highlight = true; } if ($str[$i] == '<') { $tag = true; if ($highlight) { $buf .= $highlight_c; } } if (!$tag) { if ($str[$i] == '&') { $ent = true; } if ($ent && $str[$i] == ';') { $ent = false; } if (!$ent) { $p++; } } $buf .= $str[$i]; if ($tag && $str[$i] == '>') { $tag = false; if ($highlight) { $buf .= $highlight_o; } } if ($highlight && ($p == $e || $i == $n - 1)) { $buf .= $highlight_c; $highlight = false; } } return $buf; } private static function collapseIntralineRuns($runs) { $count = count($runs); for ($ii = 0; $ii < $count - 1; $ii++) { if ($runs[$ii][0] == $runs[$ii + 1][0]) { $runs[$ii + 1][1] += $runs[$ii][1]; unset($runs[$ii]); } } return array_values($runs); } public static function buildLevenshteinDifferenceString($o, $n) { $olt = strlen($o); $nlt = strlen($n); if (!$olt) { return str_repeat('i', $nlt); } if (!$nlt) { return str_repeat('d', $olt); } $min = min($olt, $nlt); $t_start = microtime(true); $pre = 0; while ($pre < $min && $o[$pre] == $n[$pre]) { $pre++; } $end = 0; while ($end < $min && $o[($olt - 1) - $end] == $n[($nlt - 1) - $end]) { $end++; } if ($end + $pre >= $min) { $end = min($end, $min - $pre); $prefix = str_repeat('s', $pre); $suffix = str_repeat('s', $end); $infix = null; if ($olt > $nlt) { $infix = str_repeat('d', $olt - ($end + $pre)); } else if ($nlt > $olt) { $infix = str_repeat('i', $nlt - ($end + $pre)); } return $prefix.$infix.$suffix; } if ($min - ($end + $pre) > 80) { $max = max($olt, $nlt); return str_repeat('x', $min) . str_repeat($olt < $nlt ? 'i' : 'd', $max - $min); } $prefix = str_repeat('s', $pre); $suffix = str_repeat('s', $end); $o = substr($o, $pre, $olt - $end - $pre); $n = substr($n, $pre, $nlt - $end - $pre); $ol = strlen($o); $nl = strlen($n); $m = array_fill(0, $ol + 1, array_fill(0, $nl + 1, array())); - $T_D = 'd'; - $T_I = 'i'; - $T_S = 's'; - $T_X = 'x'; + $t_d = 'd'; + $t_i = 'i'; + $t_s = 's'; + $t_x = 'x'; $m[0][0] = array( 0, null); for ($ii = 1; $ii <= $ol; $ii++) { $m[$ii][0] = array( $ii * 1000, - $T_D); + $t_d); } for ($jj = 1; $jj <= $nl; $jj++) { $m[0][$jj] = array( $jj * 1000, - $T_I); + $t_i); } $ii = 1; do { $jj = 1; do { if ($o[$ii - 1] == $n[$jj - 1]) { $sub_t_cost = $m[$ii - 1][$jj - 1][0] + 0; - $sub_t = $T_S; + $sub_t = $t_s; } else { $sub_t_cost = $m[$ii - 1][$jj - 1][0] + 2000; - $sub_t = $T_X; + $sub_t = $t_x; } if ($m[$ii - 1][$jj - 1][1] != $sub_t) { $sub_t_cost += 1; } $del_t_cost = $m[$ii - 1][$jj][0] + 1000; - if ($m[$ii - 1][$jj][1] != $T_D) { + if ($m[$ii - 1][$jj][1] != $t_d) { $del_t_cost += 1; } $ins_t_cost = $m[$ii][$jj - 1][0] + 1000; - if ($m[$ii][$jj - 1][1] != $T_I) { + if ($m[$ii][$jj - 1][1] != $t_i) { $ins_t_cost += 1; } if ($sub_t_cost <= $del_t_cost && $sub_t_cost <= $ins_t_cost) { $m[$ii][$jj] = array( $sub_t_cost, $sub_t); } else if ($ins_t_cost <= $del_t_cost) { $m[$ii][$jj] = array( $ins_t_cost, - $T_I); + $t_i); } else { $m[$ii][$jj] = array( $del_t_cost, - $T_D); + $t_d); } } while ($jj++ < $nl); } while ($ii++ < $ol); $result = ''; $ii = $ol; $jj = $nl; do { $r = $m[$ii][$jj][1]; $result .= $r; switch ($r) { - case $T_S: - case $T_X: + case $t_s: + case $t_x: $ii--; $jj--; break; - case $T_I: + case $t_i: $jj--; break; - case $T_D: + case $t_d: $ii--; break; } } while ($ii || $jj); return $prefix.strrev($result).$suffix; } } diff --git a/src/lint/linter/ArcanistJSHintLinter.php b/src/lint/linter/ArcanistJSHintLinter.php index e01e43cd..7aa9c561 100644 --- a/src/lint/linter/ArcanistJSHintLinter.php +++ b/src/lint/linter/ArcanistJSHintLinter.php @@ -1,155 +1,161 @@ ArcanistLintSeverity::SEVERITY_ERROR ); } public function getLintNameMap() { return array( self::JSHINT_ERROR => "JSHint Error" ); } public function getJSHintOptions() { $working_copy = $this->getEngine()->getWorkingCopy(); $options = '--reporter '.dirname(realpath(__FILE__)).'/reporter.js'; $config = $working_copy->getConfig('lint.jshint.config'); if ($config !== null) { - $config = Filesystem::resolvePath($config, $working_copy->getProjectRoot()); + $config = Filesystem::resolvePath( + $config, + $working_copy->getProjectRoot()); if (!Filesystem::pathExists($config)) { throw new ArcanistUsageException( - "Unable to find custom options file defined by 'lint.jshint.config'. ". - "Make sure that the path is correct."); + "Unable to find custom options file defined by ". + "'lint.jshint.config'. Make sure that the path is correct."); } $options .= ' --config '.$config; } return $options; } private function getJSHintPath() { $working_copy = $this->getEngine()->getWorkingCopy(); $prefix = $working_copy->getConfig('lint.jshint.prefix'); $bin = $working_copy->getConfig('lint.jshint.bin'); if ($bin === null) { $bin = "jshint"; } if ($prefix !== null) { $bin = $prefix."/".$bin; if (!Filesystem::pathExists($bin)) { throw new ArcanistUsageException( "Unable to find JSHint binary in a specified directory. Make sure ". "that 'lint.jshint.prefix' and 'lint.jshint.bin' keys are set ". - "correctly. If you'd rather use a copy of JSHint installed globally, ". - "you can just remove these keys from your .arcconfig"); + "correctly. If you'd rather use a copy of JSHint installed ". + "globally, you can just remove these keys from your .arcconfig"); } return $bin; } // Look for globally installed JSHint $cmd = (phutil_is_windows()) ? 'where %s' : 'which %s'; list($err) = exec_manual($cmd, $bin); if ($err) { throw new ArcanistUsageException( "JSHint does not appear to be installed on this system. Install it ". "(e.g., with 'npm install jshint -g') or configure ". "'lint.jshint.prefix' in your .arcconfig to point to the directory ". "where it resides."); } return $bin; } public function willLintPaths(array $paths) { $jshint_bin = $this->getJSHintPath(); $jshint_options = $this->getJSHintOptions(); $futures = array(); foreach ($paths as $path) { $filepath = $this->getEngine()->getFilePathOnDisk($path); - $futures[$path] = new ExecFuture("{$jshint_bin} {$filepath} ${jshint_options}"); + $futures[$path] = new ExecFuture( + "%s %s %C", + $jshint_bin, + $filepath, + $jshint_options); } foreach (Futures($futures)->limit(8) as $path => $future) { $this->results[$path] = $future->resolve(); } } public function lintPath($path) { list($rc, $stdout, $stderr) = $this->results[$path]; if ($rc === 0) { return; } $errors = json_decode($stdout); if (!is_array($errors)) { // Something went wrong and we can't decode the output. Exit abnormally. throw new ArcanistUsageException( "JSHint returned unparseable output.\n". "stdout:\n\n{$stdout}". "stderr:\n\n{$stderr}"); } foreach ($errors as $err) { $this->raiseLintAtLine( $err->line, $err->col, self::JSHINT_ERROR, $err->reason); } } } diff --git a/src/lint/linter/ArcanistPyFlakesLinter.php b/src/lint/linter/ArcanistPyFlakesLinter.php index 87054330..7f9bb842 100644 --- a/src/lint/linter/ArcanistPyFlakesLinter.php +++ b/src/lint/linter/ArcanistPyFlakesLinter.php @@ -1,104 +1,106 @@ getEngine()->getWorkingCopy(); $pyflakes_path = $working_copy->getConfig('lint.pyflakes.path'); $pyflakes_prefix = $working_copy->getConfig('lint.pyflakes.prefix'); // Default to just finding pyflakes in the users path $pyflakes_bin = 'pyflakes'; $python_path = ''; // If a pyflakes path was specified, then just use that as the // pyflakes binary and assume that the libraries will be imported // correctly. // // If no pyflakes path was specified and a pyflakes prefix was // specified, then use the binary from this prefix and add it to // the PYTHONPATH environment variable so that the libs are imported // correctly. This is useful when pyflakes is installed into a // non-default location. if ($pyflakes_path !== null) { $pyflakes_bin = $pyflakes_path; } else if ($pyflakes_prefix !== null) { $pyflakes_bin = $pyflakes_prefix.'/bin/pyflakes'; $python_path = $pyflakes_prefix.'/lib/python2.6/site-packages:'; } $options = $this->getPyFlakesOptions(); $f = new ExecFuture( "/usr/bin/env PYTHONPATH=%s\$PYTHONPATH ". "{$pyflakes_bin} {$options}", $python_path); $f->write($this->getData($path)); try { list($stdout, $_) = $f->resolvex(); } catch (CommandException $e) { // PyFlakes will return an exit code of 1 if warnings/errors // are found but print nothing to stderr in this case. Therefore, // if we see any output on stderr or a return code other than 1 or 0, // pyflakes failed. if ($e->getError() !== 1 || $e->getStderr() !== '') { throw $e; } else { $stdout = $e->getStdout(); } } $lines = explode("\n", $stdout); $messages = array(); foreach ($lines as $line) { $matches = null; if (!preg_match('/^(.*?):(\d+): (.*)$/', $line, $matches)) { continue; } foreach ($matches as $key => $match) { $matches[$key] = trim($match); } $severity = ArcanistLintSeverity::SEVERITY_WARNING; $description = $matches[3]; - if (preg_match('/(^undefined|^duplicate|before assignment$)/', $description)) { + + $error_regexp = '/(^undefined|^duplicate|before assignment$)/'; + if (preg_match($error_regexp, $description)) { $severity = ArcanistLintSeverity::SEVERITY_ERROR; } $message = new ArcanistLintMessage(); $message->setPath($path); $message->setLine($matches[2]); $message->setCode($this->getLinterName()); $message->setDescription($description); $message->setSeverity($severity); $this->addLintMessage($message); } } }