getEngine()->getWorkingCopy(); $code_map = array( ArcanistLintSeverity::SEVERITY_ERROR => $working_copy->getConfig('lint.pylint.codes.error'), ArcanistLintSeverity::SEVERITY_WARNING => $working_copy->getConfig('lint.pylint.codes.warning'), ArcanistLintSeverity::SEVERITY_ADVICE => $working_copy->getConfig('lint.pylint.codes.advice'), ); foreach ($code_map as $sev => $codes) { if ($codes !== null) { foreach ($codes as $code_re) { if (preg_match("/{$code_re}/", $code)) { return $sev; } } } } // If the message code doesn't match any of the provided regex's, // then just disable it. return ArcanistLintSeverity::SEVERITY_DISABLED; } private function getPyLintPath() { $pylint_bin = "pylint"; // Use the PyLint prefix specified in the config file $working_copy = $this->getEngine()->getWorkingCopy(); $prefix = $working_copy->getConfig('lint.pylint.prefix'); if ($prefix !== null) { $pylint_bin = $prefix."/bin/".$pylint_bin; } return $pylint_bin; } private function getPyLintPythonPath() { // Get non-default install locations for pylint and its dependencies // libraries. $working_copy = $this->getEngine()->getWorkingCopy(); $prefixes = array( $working_copy->getConfig('lint.pylint.prefix'), $working_copy->getConfig('lint.pylint.logilab_astng.prefix'), $working_copy->getConfig('lint.pylint.logilab_common.prefix'), ); // Add the libraries to the python search path $python_path = array(); foreach ($prefixes as $prefix) { if ($prefix !== null) { $python_path[] = $prefix.'/lib/python2.6/site-packages'; } } $python_path[] = ''; return implode(":", $python_path); } private function getPyLintOptions() { // Options to pass the PyLint // - '-rn': don't print lint report/summary at end // - '-iy': show message codes for lint warnings/errors $options = array('-rn', '-iy'); // Add any options defined in the config file for PyLint $working_copy = $this->getEngine()->getWorkingCopy(); $config_options = $working_copy->getConfig('lint.pylint.options'); if ($config_options !== null) { $options += $config_options; } return implode(" ", $options); } public function willLintPaths(array $paths) { return; } public function getLinterName() { return 'PyLint'; } public function getLintSeverityMap() { return array(); } public function getLintNameMap() { return array(); } public function lintPath($path) { $pylint_bin = $this->getPyLintPath(); $python_path = $this->getPyLintPythonPath(); $options = $this->getPyLintOptions(); $path_on_disk = $this->getEngine()->getFilePathOnDisk($path); try { list($stdout, $_) = execx( "/usr/bin/env PYTHONPATH=%s\$PYTHONPATH ". "{$pylint_bin} {$options} {$path_on_disk}", $python_path); } catch (CommandException $e) { // PyLint will return a non-zero exit code if warnings/errors are found. // Therefore we detect command failure by checking that the stderr is // some non-expected value. if ($e->getStderr() !== "No config file found, ". "using default configuration\n") { throw $e; } $stdout = $e->getStdout(); } $lines = explode("\n", $stdout); $messages = array(); foreach ($lines as $line) { $matches = null; if (!preg_match('/([A-Z]\d+): *(\d+): *(.*)$/', $line, $matches)) { continue; } foreach ($matches as $key => $match) { $matches[$key] = trim($match); } $message = new ArcanistLintMessage(); $message->setPath($path); $message->setLine($matches[2]); $message->setCode($matches[1]); $message->setName($this->getLinterName()." ".$matches[1]); $message->setDescription($matches[3]); $message->setSeverity($this->getMessageCodeSeverity($matches[1])); $this->addLintMessage($message); } } }