Mercurial > hg > isophonics-drupal-site
comparison vendor/squizlabs/php_codesniffer/src/Reporter.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
1 <?php | |
2 /** | |
3 * Manages reporting of errors and warnings. | |
4 * | |
5 * @author Greg Sherwood <gsherwood@squiz.net> | |
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) | |
7 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | |
8 */ | |
9 | |
10 namespace PHP_CodeSniffer; | |
11 | |
12 use PHP_CodeSniffer\Reports\Report; | |
13 use PHP_CodeSniffer\Files\File; | |
14 use PHP_CodeSniffer\Exceptions\RuntimeException; | |
15 use PHP_CodeSniffer\Exceptions\DeepExitException; | |
16 use PHP_CodeSniffer\Util\Common; | |
17 | |
18 class Reporter | |
19 { | |
20 | |
21 /** | |
22 * The config data for the run. | |
23 * | |
24 * @var \PHP_CodeSniffer\Config | |
25 */ | |
26 public $config = null; | |
27 | |
28 /** | |
29 * Total number of files that contain errors or warnings. | |
30 * | |
31 * @var integer | |
32 */ | |
33 public $totalFiles = 0; | |
34 | |
35 /** | |
36 * Total number of errors found during the run. | |
37 * | |
38 * @var integer | |
39 */ | |
40 public $totalErrors = 0; | |
41 | |
42 /** | |
43 * Total number of warnings found during the run. | |
44 * | |
45 * @var integer | |
46 */ | |
47 public $totalWarnings = 0; | |
48 | |
49 /** | |
50 * Total number of errors/warnings that can be fixed. | |
51 * | |
52 * @var integer | |
53 */ | |
54 public $totalFixable = 0; | |
55 | |
56 /** | |
57 * Total number of errors/warnings that were fixed. | |
58 * | |
59 * @var integer | |
60 */ | |
61 public $totalFixed = 0; | |
62 | |
63 /** | |
64 * When the PHPCS run started. | |
65 * | |
66 * @var float | |
67 */ | |
68 public static $startTime = 0; | |
69 | |
70 /** | |
71 * A cache of report objects. | |
72 * | |
73 * @var array | |
74 */ | |
75 private $reports = []; | |
76 | |
77 /** | |
78 * A cache of opened temporary files. | |
79 * | |
80 * @var array | |
81 */ | |
82 private $tmpFiles = []; | |
83 | |
84 | |
85 /** | |
86 * Initialise the reporter. | |
87 * | |
88 * All reports specified in the config will be created and their | |
89 * output file (or a temp file if none is specified) initialised by | |
90 * clearing the current contents. | |
91 * | |
92 * @param \PHP_CodeSniffer\Config $config The config data for the run. | |
93 * | |
94 * @return void | |
95 * @throws RuntimeException If a report is not available. | |
96 */ | |
97 public function __construct(Config $config) | |
98 { | |
99 $this->config = $config; | |
100 | |
101 foreach ($config->reports as $type => $output) { | |
102 if ($output === null) { | |
103 $output = $config->reportFile; | |
104 } | |
105 | |
106 $reportClassName = ''; | |
107 if (strpos($type, '.') !== false) { | |
108 // This is a path to a custom report class. | |
109 $filename = realpath($type); | |
110 if ($filename === false) { | |
111 $error = "ERROR: Custom report \"$type\" not found".PHP_EOL; | |
112 throw new DeepExitException($error, 3); | |
113 } | |
114 | |
115 $reportClassName = Autoload::loadFile($filename); | |
116 } else if (class_exists('PHP_CodeSniffer\Reports\\'.ucfirst($type)) === true) { | |
117 // PHPCS native report. | |
118 $reportClassName = 'PHP_CodeSniffer\Reports\\'.ucfirst($type); | |
119 } else if (class_exists($type) === true) { | |
120 // FQN of a custom report. | |
121 $reportClassName = $type; | |
122 } else { | |
123 // OK, so not a FQN, try and find the report using the registered namespaces. | |
124 $registeredNamespaces = Autoload::getSearchPaths(); | |
125 $trimmedType = ltrim($type, '\\'); | |
126 | |
127 foreach ($registeredNamespaces as $nsPrefix) { | |
128 if ($nsPrefix === '') { | |
129 continue; | |
130 } | |
131 | |
132 if (class_exists($nsPrefix.'\\'.$trimmedType) === true) { | |
133 $reportClassName = $nsPrefix.'\\'.$trimmedType; | |
134 break; | |
135 } | |
136 } | |
137 }//end if | |
138 | |
139 if ($reportClassName === '') { | |
140 $error = "ERROR: Class file for report \"$type\" not found".PHP_EOL; | |
141 throw new DeepExitException($error, 3); | |
142 } | |
143 | |
144 $reportClass = new $reportClassName(); | |
145 if (false === ($reportClass instanceof Report)) { | |
146 throw new RuntimeException('Class "'.$reportClassName.'" must implement the "PHP_CodeSniffer\Report" interface.'); | |
147 } | |
148 | |
149 $this->reports[$type] = [ | |
150 'output' => $output, | |
151 'class' => $reportClass, | |
152 ]; | |
153 | |
154 if ($output === null) { | |
155 // Using a temp file. | |
156 // This needs to be set in the constructor so that all | |
157 // child procs use the same report file when running in parallel. | |
158 $this->tmpFiles[$type] = tempnam(sys_get_temp_dir(), 'phpcs'); | |
159 file_put_contents($this->tmpFiles[$type], ''); | |
160 } else { | |
161 file_put_contents($output, ''); | |
162 } | |
163 }//end foreach | |
164 | |
165 }//end __construct() | |
166 | |
167 | |
168 /** | |
169 * Generates and prints final versions of all reports. | |
170 * | |
171 * Returns TRUE if any of the reports output content to the screen | |
172 * or FALSE if all reports were silently printed to a file. | |
173 * | |
174 * @return bool | |
175 */ | |
176 public function printReports() | |
177 { | |
178 $toScreen = false; | |
179 foreach ($this->reports as $type => $report) { | |
180 if ($report['output'] === null) { | |
181 $toScreen = true; | |
182 } | |
183 | |
184 $this->printReport($type); | |
185 } | |
186 | |
187 return $toScreen; | |
188 | |
189 }//end printReports() | |
190 | |
191 | |
192 /** | |
193 * Generates and prints a single final report. | |
194 * | |
195 * @param string $report The report type to print. | |
196 * | |
197 * @return void | |
198 */ | |
199 public function printReport($report) | |
200 { | |
201 $reportClass = $this->reports[$report]['class']; | |
202 $reportFile = $this->reports[$report]['output']; | |
203 | |
204 if ($reportFile !== null) { | |
205 $filename = $reportFile; | |
206 $toScreen = false; | |
207 } else { | |
208 if (isset($this->tmpFiles[$report]) === true) { | |
209 $filename = $this->tmpFiles[$report]; | |
210 } else { | |
211 $filename = null; | |
212 } | |
213 | |
214 $toScreen = true; | |
215 } | |
216 | |
217 $reportCache = ''; | |
218 if ($filename !== null) { | |
219 $reportCache = file_get_contents($filename); | |
220 } | |
221 | |
222 ob_start(); | |
223 $reportClass->generate( | |
224 $reportCache, | |
225 $this->totalFiles, | |
226 $this->totalErrors, | |
227 $this->totalWarnings, | |
228 $this->totalFixable, | |
229 $this->config->showSources, | |
230 $this->config->reportWidth, | |
231 $this->config->interactive, | |
232 $toScreen | |
233 ); | |
234 $generatedReport = ob_get_contents(); | |
235 ob_end_clean(); | |
236 | |
237 if ($this->config->colors !== true || $reportFile !== null) { | |
238 $generatedReport = preg_replace('`\033\[[0-9;]+m`', '', $generatedReport); | |
239 } | |
240 | |
241 if ($reportFile !== null) { | |
242 if (PHP_CODESNIFFER_VERBOSITY > 0) { | |
243 echo $generatedReport; | |
244 } | |
245 | |
246 file_put_contents($reportFile, $generatedReport.PHP_EOL); | |
247 } else { | |
248 echo $generatedReport; | |
249 if ($filename !== null && file_exists($filename) === true) { | |
250 unlink($filename); | |
251 unset($this->tmpFiles[$report]); | |
252 } | |
253 } | |
254 | |
255 }//end printReport() | |
256 | |
257 | |
258 /** | |
259 * Caches the result of a single processed file for all reports. | |
260 * | |
261 * The report content that is generated is appended to the output file | |
262 * assigned to each report. This content may be an intermediate report format | |
263 * and not reflect the final report output. | |
264 * | |
265 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file that has been processed. | |
266 * | |
267 * @return void | |
268 */ | |
269 public function cacheFileReport(File $phpcsFile) | |
270 { | |
271 if (isset($this->config->reports) === false) { | |
272 // This happens during unit testing, or any time someone just wants | |
273 // the error data and not the printed report. | |
274 return; | |
275 } | |
276 | |
277 $reportData = $this->prepareFileReport($phpcsFile); | |
278 $errorsShown = false; | |
279 | |
280 foreach ($this->reports as $type => $report) { | |
281 $reportClass = $report['class']; | |
282 | |
283 ob_start(); | |
284 $result = $reportClass->generateFileReport($reportData, $phpcsFile, $this->config->showSources, $this->config->reportWidth); | |
285 if ($result === true) { | |
286 $errorsShown = true; | |
287 } | |
288 | |
289 $generatedReport = ob_get_contents(); | |
290 ob_end_clean(); | |
291 | |
292 if ($report['output'] === null) { | |
293 // Using a temp file. | |
294 if (isset($this->tmpFiles[$type]) === false) { | |
295 // When running in interactive mode, the reporter prints the full | |
296 // report many times, which will unlink the temp file. So we need | |
297 // to create a new one if it doesn't exist. | |
298 $this->tmpFiles[$type] = tempnam(sys_get_temp_dir(), 'phpcs'); | |
299 file_put_contents($this->tmpFiles[$type], ''); | |
300 } | |
301 | |
302 file_put_contents($this->tmpFiles[$type], $generatedReport, (FILE_APPEND | LOCK_EX)); | |
303 } else { | |
304 file_put_contents($report['output'], $generatedReport, (FILE_APPEND | LOCK_EX)); | |
305 }//end if | |
306 }//end foreach | |
307 | |
308 if ($errorsShown === true || PHP_CODESNIFFER_CBF === true) { | |
309 $this->totalFiles++; | |
310 $this->totalErrors += $reportData['errors']; | |
311 $this->totalWarnings += $reportData['warnings']; | |
312 | |
313 // When PHPCBF is running, we need to use the fixable error values | |
314 // after the report has run and fixed what it can. | |
315 if (PHP_CODESNIFFER_CBF === true) { | |
316 $this->totalFixable += $phpcsFile->getFixableCount(); | |
317 $this->totalFixed += $phpcsFile->getFixedCount(); | |
318 } else { | |
319 $this->totalFixable += $reportData['fixable']; | |
320 } | |
321 } | |
322 | |
323 }//end cacheFileReport() | |
324 | |
325 | |
326 /** | |
327 * Generate summary information to be used during report generation. | |
328 * | |
329 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file that has been processed. | |
330 * | |
331 * @return array | |
332 */ | |
333 public function prepareFileReport(File $phpcsFile) | |
334 { | |
335 $report = [ | |
336 'filename' => Common::stripBasepath($phpcsFile->getFilename(), $this->config->basepath), | |
337 'errors' => $phpcsFile->getErrorCount(), | |
338 'warnings' => $phpcsFile->getWarningCount(), | |
339 'fixable' => $phpcsFile->getFixableCount(), | |
340 'messages' => [], | |
341 ]; | |
342 | |
343 if ($report['errors'] === 0 && $report['warnings'] === 0) { | |
344 // Prefect score! | |
345 return $report; | |
346 } | |
347 | |
348 if ($this->config->recordErrors === false) { | |
349 $message = 'Errors are not being recorded but this report requires error messages. '; | |
350 $message .= 'This report will not show the correct information.'; | |
351 $report['messages'][1][1] = [ | |
352 [ | |
353 'message' => $message, | |
354 'source' => 'Internal.RecordErrors', | |
355 'severity' => 5, | |
356 'fixable' => false, | |
357 'type' => 'ERROR', | |
358 ], | |
359 ]; | |
360 return $report; | |
361 } | |
362 | |
363 $errors = []; | |
364 | |
365 // Merge errors and warnings. | |
366 foreach ($phpcsFile->getErrors() as $line => $lineErrors) { | |
367 foreach ($lineErrors as $column => $colErrors) { | |
368 $newErrors = []; | |
369 foreach ($colErrors as $data) { | |
370 $newErrors[] = [ | |
371 'message' => $data['message'], | |
372 'source' => $data['source'], | |
373 'severity' => $data['severity'], | |
374 'fixable' => $data['fixable'], | |
375 'type' => 'ERROR', | |
376 ]; | |
377 } | |
378 | |
379 $errors[$line][$column] = $newErrors; | |
380 } | |
381 | |
382 ksort($errors[$line]); | |
383 }//end foreach | |
384 | |
385 foreach ($phpcsFile->getWarnings() as $line => $lineWarnings) { | |
386 foreach ($lineWarnings as $column => $colWarnings) { | |
387 $newWarnings = []; | |
388 foreach ($colWarnings as $data) { | |
389 $newWarnings[] = [ | |
390 'message' => $data['message'], | |
391 'source' => $data['source'], | |
392 'severity' => $data['severity'], | |
393 'fixable' => $data['fixable'], | |
394 'type' => 'WARNING', | |
395 ]; | |
396 } | |
397 | |
398 if (isset($errors[$line]) === false) { | |
399 $errors[$line] = []; | |
400 } | |
401 | |
402 if (isset($errors[$line][$column]) === true) { | |
403 $errors[$line][$column] = array_merge( | |
404 $newWarnings, | |
405 $errors[$line][$column] | |
406 ); | |
407 } else { | |
408 $errors[$line][$column] = $newWarnings; | |
409 } | |
410 }//end foreach | |
411 | |
412 ksort($errors[$line]); | |
413 }//end foreach | |
414 | |
415 ksort($errors); | |
416 $report['messages'] = $errors; | |
417 return $report; | |
418 | |
419 }//end prepareFileReport() | |
420 | |
421 | |
422 }//end class |