/** * Processes the file. * * @return void */ public function process() { if ($this->ignored === true) { return; } if ($this->configCache['cache'] === false) { return parent::process(); } $hash = md5_file($this->path); $cache = Cache::get($this->path); if ($cache !== false && $cache['hash'] === $hash) { // We can't filter metrics, so just load all of them. $this->metrics = $cache['metrics']; if ($this->configCache['recordErrors'] === true) { // Replay the cached errors and warnings to filter out the ones // we don't need for this specific run. $this->configCache['cache'] = false; $this->replayErrors($cache['errors'], $cache['warnings']); $this->configCache['cache'] = true; } else { $this->errorCount = $cache['errorCount']; $this->warningCount = $cache['warningCount']; $this->fixableCount = $cache['fixableCount']; } if (PHP_CODESNIFFER_VERBOSITY > 0 || PHP_CODESNIFFER_CBF === true && empty($this->config->files) === false) { echo "[loaded from cache]... "; } $this->numTokens = $cache['numTokens']; $this->fromCache = true; return; } //end if if (PHP_CODESNIFFER_VERBOSITY > 1) { echo PHP_EOL; } parent::process(); $cache = array('hash' => $hash, 'errors' => $this->errors, 'warnings' => $this->warnings, 'metrics' => $this->metrics, 'errorCount' => $this->errorCount, 'warningCount' => $this->warningCount, 'fixableCount' => $this->fixableCount, 'numTokens' => $this->numTokens); Cache::set($this->path, $cache); // During caching, we don't filter out errors in any way, so // we need to do that manually now by replaying them. if ($this->configCache['recordErrors'] === true) { $this->configCache['cache'] = false; $this->replayErrors($this->errors, $this->warnings); $this->configCache['cache'] = true; } }
/** * Performs the run. * * @return int The number of errors and warnings found. */ private function run() { // The class that manages all reporters for the run. $this->reporter = new Reporter($this->config); // Include bootstrap files. foreach ($this->config->bootstrap as $bootstrap) { include $bootstrap; } if ($this->config->stdin === true) { $fileContents = $this->config->stdinContent; if ($fileContents === null) { $handle = fopen('php://stdin', 'r'); stream_set_blocking($handle, true); $fileContents = stream_get_contents($handle); fclose($handle); } $todo = new FileList($this->config, $this->ruleset); $dummy = new DummyFile($fileContents, $this->ruleset, $this->config); $todo->addFile($dummy->path, $dummy); $numFiles = 1; } else { if (empty($this->config->files) === true) { echo 'ERROR: You must supply at least one file or directory to process.' . PHP_EOL . PHP_EOL; $this->config->printUsage(); exit(0); } if (PHP_CODESNIFFER_VERBOSITY > 0) { echo 'Creating file list... '; } $todo = new FileList($this->config, $this->ruleset); $numFiles = count($todo); if (PHP_CODESNIFFER_VERBOSITY > 0) { echo "DONE ({$numFiles} files in queue)" . PHP_EOL; } if ($this->config->cache === true) { if (PHP_CODESNIFFER_VERBOSITY > 0) { echo 'Loading cache... '; } Cache::load($this->ruleset, $this->config); if (PHP_CODESNIFFER_VERBOSITY > 0) { $size = Cache::getSize(); echo "DONE ({$size} files in cache)" . PHP_EOL; } } } //end if // Turn all sniff errors into exceptions. set_error_handler(array($this, 'handleErrors')); // If verbosity is too high, turn off parallelism so the // debug output is clean. if (PHP_CODESNIFFER_VERBOSITY > 1) { $this->config->parallel = 1; } // If the PCNTL extension isn't installed, we can't fork. if (function_exists('pcntl_fork') === false) { $this->config->parallel = 1; } $lastDir = ''; if ($this->config->parallel === 1) { // Running normally. $numProcessed = 0; foreach ($todo as $path => $file) { $currDir = dirname($path); if ($lastDir !== $currDir) { if (PHP_CODESNIFFER_VERBOSITY > 0) { echo 'Changing into directory ' . Common::stripBasepath($currDir, $this->config->basepath) . PHP_EOL; } $lastDir = $currDir; } $this->processFile($file); $numProcessed++; $this->printProgress($file, $numFiles, $numProcessed); } } else { // Batching and forking. $childProcs = array(); $numFiles = count($todo); $numPerBatch = ceil($numFiles / $this->config->parallel); for ($batch = 0; $batch < $this->config->parallel; $batch++) { $startAt = $batch * $numPerBatch; if ($startAt >= $numFiles) { break; } $endAt = $startAt + $numPerBatch; if ($endAt > $numFiles) { $endAt = $numFiles; } $childOutFilename = tempnam(sys_get_temp_dir(), 'phpcs-child'); $pid = pcntl_fork(); if ($pid === -1) { throw new RuntimeException('Failed to create child process'); } else { if ($pid !== 0) { $childProcs[] = array('pid' => $pid, 'out' => $childOutFilename); } else { // Move forward to the start of the batch. $todo->rewind(); for ($i = 0; $i < $startAt; $i++) { $todo->next(); } // Reset the reporter to make sure only figures from this // file batch are recorded. $this->reporter->totalFiles = 0; $this->reporter->totalErrors = 0; $this->reporter->totalWarnings = 0; $this->reporter->totalFixable = 0; // Process the files. $pathsProcessed = array(); ob_start(); for ($i = $startAt; $i < $endAt; $i++) { $path = $todo->key(); $file = $todo->current(); $currDir = dirname($path); if ($lastDir !== $currDir) { if (PHP_CODESNIFFER_VERBOSITY > 0) { echo 'Changing into directory ' . Common::stripBasepath($currDir, $this->config->basepath) . PHP_EOL; } $lastDir = $currDir; } $this->processFile($file); $pathsProcessed[] = $path; $todo->next(); } $debugOutput = ob_get_contents(); ob_end_clean(); // Write information about the run to the filesystem // so it can be picked up by the main process. $childOutput = array('totalFiles' => $this->reporter->totalFiles, 'totalErrors' => $this->reporter->totalErrors, 'totalWarnings' => $this->reporter->totalWarnings, 'totalFixable' => $this->reporter->totalFixable, 'totalFixed' => $this->reporter->totalFixed); $output = '<' . '?php' . "\n" . ' $childOutput = '; $output .= var_export($childOutput, true); $output .= ";\n\$debugOutput = "; $output .= var_export($debugOutput, true); if ($this->config->cache === true) { $childCache = array(); foreach ($pathsProcessed as $path) { $childCache[$path] = Cache::get($path); } $output .= ";\n\$childCache = "; $output .= var_export($childCache, true); } $output .= ";\n?" . '>'; file_put_contents($childOutFilename, $output); exit($pid); } } //end if } //end for $this->processChildProcs($childProcs); } //end if restore_error_handler(); if (PHP_CODESNIFFER_VERBOSITY === 0 && $this->config->interactive === false && $this->config->showProgress === true) { echo PHP_EOL . PHP_EOL; } if ($this->config->cache === true) { Cache::save(); } $ignoreWarnings = Config::getConfigData('ignore_warnings_on_exit'); $ignoreErrors = Config::getConfigData('ignore_errors_on_exit'); $return = $this->reporter->totalErrors + $this->reporter->totalWarnings; if ($ignoreErrors !== null) { $ignoreErrors = (bool) $ignoreErrors; if ($ignoreErrors === true) { $return -= $this->reporter->totalErrors; } } if ($ignoreWarnings !== null) { $ignoreWarnings = (bool) $ignoreWarnings; if ($ignoreWarnings === true) { $return -= $this->reporter->totalWarnings; } } return $return; }