Exemple #1
0
 public function willLintPaths(array $paths)
 {
     $program = false;
     $ret_value = 0;
     $last_line = system("which checkCpp", $ret_value);
     if ($ret_value == 0) {
         $program = $last_line;
     } else {
         if (file_exists(self::PROGRAM)) {
             $program = self::PROGRAM;
         }
     }
     if ($program) {
         $futures = array();
         foreach ($paths as $p) {
             $futures[$p] = new ExecFuture("%s --lint %s 2>&1", $program, $this->getEngine()->getFilePathOnDisk($p));
         }
         foreach (Futures($futures)->limit(8) as $p => $f) {
             list($stdout, $stderr) = $f->resolvex();
             $raw = json_decode($stdout, true);
             if (!is_array($raw)) {
                 throw new Exception("checkCpp returned invalid JSON!" . "Stdout: {$stdout} Stderr: {$stderr}");
             }
             foreach ($raw as $err) {
                 $this->addLintMessage(ArcanistLintMessage::newFromDictionary(array('path' => $err['file'], 'line' => $err['line'], 'char' => 0, 'name' => $err['name'], 'description' => $err['info'], 'code' => $this->getLinterName(), 'severity' => ArcanistLintSeverity::SEVERITY_WARNING)));
             }
         }
     }
     return;
 }
 public function lintPath($path)
 {
     $lint_for_path = idx($this->lintByPath, $path);
     if (!$lint_for_path) {
         return;
     }
     foreach ($lint_for_path as $lint) {
         $this->addLintMessage(ArcanistLintMessage::newFromDictionary($lint));
     }
 }
 public final function run()
 {
     $linters = $this->buildLinters();
     if (!$linters) {
         throw new ArcanistNoEffectException(pht('No linters to run.'));
     }
     foreach ($linters as $key => $linter) {
         $linter->setLinterID($key);
     }
     $linters = msort($linters, 'getLinterPriority');
     foreach ($linters as $linter) {
         $linter->setEngine($this);
     }
     $have_paths = false;
     foreach ($linters as $linter) {
         if ($linter->getPaths()) {
             $have_paths = true;
             break;
         }
     }
     if (!$have_paths) {
         throw new ArcanistNoEffectException(pht('No paths are lintable.'));
     }
     $versions = array($this->getCacheVersion());
     foreach ($linters as $linter) {
         $version = get_class($linter) . ':' . $linter->getCacheVersion();
         $symbols = id(new PhutilSymbolLoader())->setType('class')->setName(get_class($linter))->selectSymbolsWithoutLoading();
         $symbol = idx($symbols, 'class$' . get_class($linter));
         if ($symbol) {
             $version .= ':' . md5_file(phutil_get_library_root($symbol['library']) . '/' . $symbol['where']);
         }
         $versions[] = $version;
     }
     $this->cacheVersion = crc32(implode("\n", $versions));
     $runnable = $this->getRunnableLinters($linters);
     $this->stopped = array();
     $exceptions = $this->executeLinters($runnable);
     foreach ($runnable as $linter) {
         foreach ($linter->getLintMessages() as $message) {
             if (!$this->isSeverityEnabled($message->getSeverity())) {
                 continue;
             }
             if (!$this->isRelevantMessage($message)) {
                 continue;
             }
             $message->setGranularity($linter->getCacheGranularity());
             $result = $this->getResultForPath($message->getPath());
             $result->addMessage($message);
         }
     }
     if ($this->cachedResults) {
         foreach ($this->cachedResults as $path => $messages) {
             $messages = idx($messages, $this->cacheVersion, array());
             $repository_version = idx($messages, 'repository_version');
             unset($messages['stopped']);
             unset($messages['repository_version']);
             foreach ($messages as $message) {
                 $use_cache = $this->shouldUseCache(idx($message, 'granularity'), $repository_version);
                 if ($use_cache) {
                     $this->getResultForPath($path)->addMessage(ArcanistLintMessage::newFromDictionary($message));
                 }
             }
         }
     }
     foreach ($this->results as $path => $result) {
         $disk_path = $this->getFilePathOnDisk($path);
         $result->setFilePathOnDisk($disk_path);
         if (isset($this->fileData[$path])) {
             $result->setData($this->fileData[$path]);
         } else {
             if ($disk_path && Filesystem::pathExists($disk_path)) {
                 // TODO: this may cause us to, e.g., load a large binary when we only
                 // raised an error about its filename. We could refine this by looking
                 // through the lint messages and doing this load only if any of them
                 // have original/replacement text or something like that.
                 try {
                     $this->fileData[$path] = Filesystem::readFile($disk_path);
                     $result->setData($this->fileData[$path]);
                 } catch (FilesystemException $ex) {
                     // Ignore this, it's noncritical that we access this data and it
                     // might be unreadable or a directory or whatever else for plenty
                     // of legitimate reasons.
                 }
             }
         }
     }
     if ($exceptions) {
         throw new PhutilAggregateException(pht('Some linters failed:'), $exceptions);
     }
     return $this->results;
 }
 /**
  * Run the regex on the output of the script.
  *
  * @task lint
  */
 public function lintPath($path)
 {
     $output = idx($this->output, $path);
     if (!strlen($output)) {
         // No output, but it exited 0, so just move on.
         return;
     }
     $matches = null;
     if (!preg_match_all($this->regex, $output, $matches, PREG_SET_ORDER)) {
         // Output with no matches. This might be a configuration error, but more
         // likely it's something like "No lint errors." and the user just hasn't
         // written a sufficiently powerful/ridiculous regexp to capture it into an
         // 'ignore' group. Don't make them figure this out; advanced users can
         // capture 'throw' to handle this case.
         return;
     }
     foreach ($matches as $match) {
         if (!empty($match['throw'])) {
             $throw = $match['throw'];
             throw new ArcanistUsageException(pht("%s: configuration captured a '%s' named capturing group, " . "'%s'. Script output:\n%s", __CLASS__, 'throw', $throw, $output));
         }
         if (!empty($match['halt'])) {
             $this->stopAllLinters();
             break;
         }
         if (!empty($match['stop'])) {
             break;
         }
         if (!empty($match['ignore'])) {
             continue;
         }
         list($line, $char) = $this->getMatchLineAndChar($match, $path);
         $dict = array('path' => idx($match, 'file', $path), 'line' => $line, 'char' => $char, 'code' => idx($match, 'code', $this->getLinterName()), 'severity' => $this->getMatchSeverity($match), 'name' => idx($match, 'name', 'Lint'), 'description' => idx($match, 'message', pht('Undefined Lint Message')));
         $original = idx($match, 'original');
         if ($original !== null) {
             $dict['original'] = $original;
         }
         $replacement = idx($match, 'replacement');
         if ($replacement !== null) {
             $dict['replacement'] = $replacement;
         }
         $lint = ArcanistLintMessage::newFromDictionary($dict);
         $this->addLintMessage($lint);
     }
 }
 public final function run()
 {
     $linters = $this->buildLinters();
     if (!$linters) {
         throw new ArcanistNoEffectException('No linters to run.');
     }
     $linters = msort($linters, 'getLinterPriority');
     foreach ($linters as $linter) {
         $linter->setEngine($this);
     }
     $have_paths = false;
     foreach ($linters as $linter) {
         if ($linter->getPaths()) {
             $have_paths = true;
             break;
         }
     }
     if (!$have_paths) {
         throw new ArcanistNoEffectException('No paths are lintable.');
     }
     $versions = array($this->getCacheVersion());
     foreach ($linters as $linter) {
         $version = get_class($linter) . ':' . $linter->getCacheVersion();
         $symbols = id(new PhutilSymbolLoader())->setType('class')->setName(get_class($linter))->selectSymbolsWithoutLoading();
         $symbol = idx($symbols, 'class$' . get_class($linter));
         if ($symbol) {
             $version .= ':' . md5_file(phutil_get_library_root($symbol['library']) . '/' . $symbol['where']);
         }
         $versions[] = $version;
     }
     $this->cacheVersion = crc32(implode("\n", $versions));
     $this->stopped = array();
     $exceptions = array();
     foreach ($linters as $linter_name => $linter) {
         if (!is_string($linter_name)) {
             $linter_name = get_class($linter);
         }
         try {
             if (!$linter->canRun()) {
                 continue;
             }
             $paths = $linter->getPaths();
             foreach ($paths as $key => $path) {
                 // Make sure each path has a result generated, even if it is empty
                 // (i.e., the file has no lint messages).
                 $result = $this->getResultForPath($path);
                 if (isset($this->stopped[$path])) {
                     unset($paths[$key]);
                 }
                 if (isset($this->cachedResults[$path][$this->cacheVersion])) {
                     $cached_result = $this->cachedResults[$path][$this->cacheVersion];
                     $use_cache = $this->shouldUseCache($linter->getCacheGranularity(), idx($cached_result, 'repository_version'));
                     if ($use_cache) {
                         unset($paths[$key]);
                         if (idx($cached_result, 'stopped') == $linter_name) {
                             $this->stopped[$path] = $linter_name;
                         }
                     }
                 }
             }
             $paths = array_values($paths);
             if ($paths) {
                 $profiler = PhutilServiceProfiler::getInstance();
                 $call_id = $profiler->beginServiceCall(array('type' => 'lint', 'linter' => $linter_name, 'paths' => $paths));
                 try {
                     $linter->willLintPaths($paths);
                     foreach ($paths as $path) {
                         $linter->willLintPath($path);
                         $linter->lintPath($path);
                         if ($linter->didStopAllLinters()) {
                             $this->stopped[$path] = $linter_name;
                         }
                     }
                 } catch (Exception $ex) {
                     $profiler->endServiceCall($call_id, array());
                     throw $ex;
                 }
                 $profiler->endServiceCall($call_id, array());
             }
         } catch (Exception $ex) {
             $exceptions[$linter_name] = $ex;
         }
     }
     $exceptions += $this->didRunLinters($linters);
     foreach ($linters as $linter) {
         foreach ($linter->getLintMessages() as $message) {
             if (!$this->isSeverityEnabled($message->getSeverity())) {
                 continue;
             }
             if (!$this->isRelevantMessage($message)) {
                 continue;
             }
             $message->setGranularity($linter->getCacheGranularity());
             $result = $this->getResultForPath($message->getPath());
             $result->addMessage($message);
         }
     }
     if ($this->cachedResults) {
         foreach ($this->cachedResults as $path => $messages) {
             $messages = idx($messages, $this->cacheVersion, array());
             $repository_version = idx($messages, 'repository_version');
             unset($messages['stopped']);
             unset($messages['repository_version']);
             foreach ($messages as $message) {
                 $use_cache = $this->shouldUseCache(idx($message, 'granularity'), $repository_version);
                 if ($use_cache) {
                     $this->getResultForPath($path)->addMessage(ArcanistLintMessage::newFromDictionary($message));
                 }
             }
         }
     }
     foreach ($this->results as $path => $result) {
         $disk_path = $this->getFilePathOnDisk($path);
         $result->setFilePathOnDisk($disk_path);
         if (isset($this->fileData[$path])) {
             $result->setData($this->fileData[$path]);
         } else {
             if ($disk_path && Filesystem::pathExists($disk_path)) {
                 // TODO: this may cause us to, e.g., load a large binary when we only
                 // raised an error about its filename. We could refine this by looking
                 // through the lint messages and doing this load only if any of them
                 // have original/replacement text or something like that.
                 try {
                     $this->fileData[$path] = Filesystem::readFile($disk_path);
                     $result->setData($this->fileData[$path]);
                 } catch (FilesystemException $ex) {
                     // Ignore this, it's noncritical that we access this data and it
                     // might be unreadable or a directory or whatever else for plenty
                     // of legitimate reasons.
                 }
             }
         }
     }
     if ($exceptions) {
         throw new PhutilAggregateException('Some linters failed:', $exceptions);
     }
     return $this->results;
 }
Exemple #6
0
 protected function raiseLintAtLine($line, $char, $code, $desc, $original = null, $replacement = null)
 {
     $dict = array('path' => $this->getActivePath(), 'line' => $line, 'char' => $char, 'code' => $this->getLintMessageFullCode($code), 'severity' => $this->getLintMessageSeverity($code), 'name' => $this->getLintMessageName($code), 'description' => $desc);
     if ($original !== null) {
         $dict['original'] = $original;
     }
     if ($replacement !== null) {
         $dict['replacement'] = $replacement;
     }
     return $this->addLintMessage(ArcanistLintMessage::newFromDictionary($dict));
 }