Mercurial > hg > isophonics-drupal-site
comparison vendor/squizlabs/php_codesniffer/src/Config.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 * Stores the configuration used to run PHPCS and PHPCBF. | |
4 * | |
5 * Parses the command line to determine user supplied values | |
6 * and provides functions to access data stored in config files. | |
7 * | |
8 * @author Greg Sherwood <gsherwood@squiz.net> | |
9 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) | |
10 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | |
11 */ | |
12 | |
13 namespace PHP_CodeSniffer; | |
14 | |
15 use PHP_CodeSniffer\Exceptions\RuntimeException; | |
16 use PHP_CodeSniffer\Exceptions\DeepExitException; | |
17 | |
18 class Config | |
19 { | |
20 | |
21 /** | |
22 * The current version. | |
23 * | |
24 * @var string | |
25 */ | |
26 const VERSION = '3.4.0'; | |
27 | |
28 /** | |
29 * Package stability; either stable, beta or alpha. | |
30 * | |
31 * @var string | |
32 */ | |
33 const STABILITY = 'stable'; | |
34 | |
35 /** | |
36 * An array of settings that PHPCS and PHPCBF accept. | |
37 * | |
38 * This array is not meant to be accessed directly. Instead, use the settings | |
39 * as if they are class member vars so the __get() and __set() magic methods | |
40 * can be used to validate the values. For example, to set the verbosity level to | |
41 * level 2, use $this->verbosity = 2; instead of accessing this property directly. | |
42 * | |
43 * The list of settings are: | |
44 * | |
45 * string[] files The files and directories to check. | |
46 * string[] standards The standards being used for checking. | |
47 * int verbosity How verbose the output should be. | |
48 * 0: no unnecessary output | |
49 * 1: basic output for files being checked | |
50 * 2: ruleset and file parsing output | |
51 * 3: sniff execution output | |
52 * bool interactive Enable interactive checking mode. | |
53 * bool parallel Check files in parallel. | |
54 * bool cache Enable the use of the file cache. | |
55 * bool cacheFile A file where the cache data should be written | |
56 * bool colors Display colours in output. | |
57 * bool explain Explain the coding standards. | |
58 * bool local Process local files in directories only (no recursion). | |
59 * bool showSources Show sniff source codes in report output. | |
60 * bool showProgress Show basic progress information while running. | |
61 * bool quiet Quiet mode; disables progress and verbose output. | |
62 * bool annotations Process phpcs: annotations. | |
63 * int tabWidth How many spaces each tab is worth. | |
64 * string encoding The encoding of the files being checked. | |
65 * string[] sniffs The sniffs that should be used for checking. | |
66 * If empty, all sniffs in the supplied standards will be used. | |
67 * string[] exclude The sniffs that should be excluded from checking. | |
68 * If empty, all sniffs in the supplied standards will be used. | |
69 * string[] ignored Regular expressions used to ignore files and folders during checking. | |
70 * string reportFile A file where the report output should be written. | |
71 * string generator The documentation generator to use. | |
72 * string filter The filter to use for the run. | |
73 * string[] bootstrap One of more files to include before the run begins. | |
74 * int reportWidth The maximum number of columns that reports should use for output. | |
75 * Set to "auto" for have this value changed to the width of the terminal. | |
76 * int errorSeverity The minimum severity an error must have to be displayed. | |
77 * int warningSeverity The minimum severity a warning must have to be displayed. | |
78 * bool recordErrors Record the content of error messages as well as error counts. | |
79 * string suffix A suffix to add to fixed files. | |
80 * string basepath A file system location to strip from the paths of files shown in reports. | |
81 * bool stdin Read content from STDIN instead of supplied files. | |
82 * string stdinContent Content passed directly to PHPCS on STDIN. | |
83 * string stdinPath The path to use for content passed on STDIN. | |
84 * | |
85 * array<string, string> extensions File extensions that should be checked, and what tokenizer to use. | |
86 * E.g., array('inc' => 'PHP'); | |
87 * array<string, string|null> reports The reports to use for printing output after the run. | |
88 * The format of the array is: | |
89 * array( | |
90 * 'reportName1' => 'outputFile', | |
91 * 'reportName2' => null, | |
92 * ); | |
93 * If the array value is NULL, the report will be written to the screen. | |
94 * | |
95 * string[] unknown Any arguments gathered on the command line that are unknown to us. | |
96 * E.g., using `phpcs -c` will give array('c'); | |
97 * | |
98 * @var array<string, mixed> | |
99 */ | |
100 private $settings = [ | |
101 'files' => null, | |
102 'standards' => null, | |
103 'verbosity' => null, | |
104 'interactive' => null, | |
105 'parallel' => null, | |
106 'cache' => null, | |
107 'cacheFile' => null, | |
108 'colors' => null, | |
109 'explain' => null, | |
110 'local' => null, | |
111 'showSources' => null, | |
112 'showProgress' => null, | |
113 'quiet' => null, | |
114 'annotations' => null, | |
115 'tabWidth' => null, | |
116 'encoding' => null, | |
117 'extensions' => null, | |
118 'sniffs' => null, | |
119 'exclude' => null, | |
120 'ignored' => null, | |
121 'reportFile' => null, | |
122 'generator' => null, | |
123 'filter' => null, | |
124 'bootstrap' => null, | |
125 'reports' => null, | |
126 'basepath' => null, | |
127 'reportWidth' => null, | |
128 'errorSeverity' => null, | |
129 'warningSeverity' => null, | |
130 'recordErrors' => null, | |
131 'suffix' => null, | |
132 'stdin' => null, | |
133 'stdinContent' => null, | |
134 'stdinPath' => null, | |
135 'unknown' => null, | |
136 ]; | |
137 | |
138 /** | |
139 * Whether or not to kill the process when an unknown command line arg is found. | |
140 * | |
141 * If FALSE, arguments that are not command line options or file/directory paths | |
142 * will be ignored and execution will continue. These values will be stored in | |
143 * $this->unknown. | |
144 * | |
145 * @var boolean | |
146 */ | |
147 public $dieOnUnknownArg; | |
148 | |
149 /** | |
150 * The current command line arguments we are processing. | |
151 * | |
152 * @var string[] | |
153 */ | |
154 private $cliArgs = []; | |
155 | |
156 /** | |
157 * Command line values that the user has supplied directly. | |
158 * | |
159 * @var array<string, TRUE> | |
160 */ | |
161 private static $overriddenDefaults = []; | |
162 | |
163 /** | |
164 * Config file data that has been loaded for the run. | |
165 * | |
166 * @var array<string, string> | |
167 */ | |
168 private static $configData = null; | |
169 | |
170 /** | |
171 * The full path to the config data file that has been loaded. | |
172 * | |
173 * @var string | |
174 */ | |
175 private static $configDataFile = null; | |
176 | |
177 /** | |
178 * Automatically discovered executable utility paths. | |
179 * | |
180 * @var array<string, string> | |
181 */ | |
182 private static $executablePaths = []; | |
183 | |
184 | |
185 /** | |
186 * Get the value of an inaccessible property. | |
187 * | |
188 * @param string $name The name of the property. | |
189 * | |
190 * @return mixed | |
191 * @throws RuntimeException If the setting name is invalid. | |
192 */ | |
193 public function __get($name) | |
194 { | |
195 if (array_key_exists($name, $this->settings) === false) { | |
196 throw new RuntimeException("ERROR: unable to get value of property \"$name\""); | |
197 } | |
198 | |
199 return $this->settings[$name]; | |
200 | |
201 }//end __get() | |
202 | |
203 | |
204 /** | |
205 * Set the value of an inaccessible property. | |
206 * | |
207 * @param string $name The name of the property. | |
208 * @param mixed $value The value of the property. | |
209 * | |
210 * @return void | |
211 * @throws RuntimeException If the setting name is invalid. | |
212 */ | |
213 public function __set($name, $value) | |
214 { | |
215 if (array_key_exists($name, $this->settings) === false) { | |
216 throw new RuntimeException("Can't __set() $name; setting doesn't exist"); | |
217 } | |
218 | |
219 switch ($name) { | |
220 case 'reportWidth' : | |
221 // Support auto terminal width. | |
222 if ($value === 'auto' && preg_match('|\d+ (\d+)|', shell_exec('stty size 2>&1'), $matches) === 1) { | |
223 $value = (int) $matches[1]; | |
224 } else { | |
225 $value = (int) $value; | |
226 } | |
227 break; | |
228 case 'standards' : | |
229 $cleaned = []; | |
230 | |
231 // Check if the standard name is valid, or if the case is invalid. | |
232 $installedStandards = Util\Standards::getInstalledStandards(); | |
233 foreach ($value as $standard) { | |
234 foreach ($installedStandards as $validStandard) { | |
235 if (strtolower($standard) === strtolower($validStandard)) { | |
236 $standard = $validStandard; | |
237 break; | |
238 } | |
239 } | |
240 | |
241 $cleaned[] = $standard; | |
242 } | |
243 | |
244 $value = $cleaned; | |
245 break; | |
246 default : | |
247 // No validation required. | |
248 break; | |
249 }//end switch | |
250 | |
251 $this->settings[$name] = $value; | |
252 | |
253 }//end __set() | |
254 | |
255 | |
256 /** | |
257 * Check if the value of an inaccessible property is set. | |
258 * | |
259 * @param string $name The name of the property. | |
260 * | |
261 * @return bool | |
262 */ | |
263 public function __isset($name) | |
264 { | |
265 return isset($this->settings[$name]); | |
266 | |
267 }//end __isset() | |
268 | |
269 | |
270 /** | |
271 * Unset the value of an inaccessible property. | |
272 * | |
273 * @param string $name The name of the property. | |
274 * | |
275 * @return void | |
276 */ | |
277 public function __unset($name) | |
278 { | |
279 $this->settings[$name] = null; | |
280 | |
281 }//end __unset() | |
282 | |
283 | |
284 /** | |
285 * Get the array of all config settings. | |
286 * | |
287 * @return array<string, mixed> | |
288 */ | |
289 public function getSettings() | |
290 { | |
291 return $this->settings; | |
292 | |
293 }//end getSettings() | |
294 | |
295 | |
296 /** | |
297 * Set the array of all config settings. | |
298 * | |
299 * @param array<string, mixed> $settings The array of config settings. | |
300 * | |
301 * @return void | |
302 */ | |
303 public function setSettings($settings) | |
304 { | |
305 return $this->settings = $settings; | |
306 | |
307 }//end setSettings() | |
308 | |
309 | |
310 /** | |
311 * Creates a Config object and populates it with command line values. | |
312 * | |
313 * @param array $cliArgs An array of values gathered from CLI args. | |
314 * @param bool $dieOnUnknownArg Whether or not to kill the process when an | |
315 * unknown command line arg is found. | |
316 * | |
317 * @return void | |
318 */ | |
319 public function __construct(array $cliArgs=[], $dieOnUnknownArg=true) | |
320 { | |
321 if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { | |
322 // Let everything through during testing so that we can | |
323 // make use of PHPUnit command line arguments as well. | |
324 $this->dieOnUnknownArg = false; | |
325 } else { | |
326 $this->dieOnUnknownArg = $dieOnUnknownArg; | |
327 } | |
328 | |
329 if (empty($cliArgs) === true) { | |
330 $cliArgs = $_SERVER['argv']; | |
331 array_shift($cliArgs); | |
332 } | |
333 | |
334 $this->restoreDefaults(); | |
335 $this->setCommandLineValues($cliArgs); | |
336 | |
337 if (isset(self::$overriddenDefaults['standards']) === false) { | |
338 // They did not supply a standard to use. | |
339 // Look for a default ruleset in the current directory or higher. | |
340 $currentDir = getcwd(); | |
341 | |
342 $defaultFiles = [ | |
343 '.phpcs.xml', | |
344 'phpcs.xml', | |
345 '.phpcs.xml.dist', | |
346 'phpcs.xml.dist', | |
347 ]; | |
348 | |
349 do { | |
350 foreach ($defaultFiles as $defaultFilename) { | |
351 $default = $currentDir.DIRECTORY_SEPARATOR.$defaultFilename; | |
352 if (is_file($default) === true) { | |
353 $this->standards = [$default]; | |
354 break(2); | |
355 } | |
356 } | |
357 | |
358 $lastDir = $currentDir; | |
359 $currentDir = dirname($currentDir); | |
360 } while ($currentDir !== '.' && $currentDir !== $lastDir); | |
361 }//end if | |
362 | |
363 if (defined('STDIN') === false | |
364 || strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' | |
365 ) { | |
366 return; | |
367 } | |
368 | |
369 $handle = fopen('php://stdin', 'r'); | |
370 | |
371 // Check for content on STDIN. | |
372 if ($this->stdin === true | |
373 || (Util\Common::isStdinATTY() === false | |
374 && feof($handle) === false) | |
375 ) { | |
376 $readStreams = [$handle]; | |
377 $writeSteams = null; | |
378 | |
379 $fileContents = ''; | |
380 while (is_resource($handle) === true && feof($handle) === false) { | |
381 // Set a timeout of 200ms. | |
382 if (stream_select($readStreams, $writeSteams, $writeSteams, 0, 200000) === 0) { | |
383 break; | |
384 } | |
385 | |
386 $fileContents .= fgets($handle); | |
387 } | |
388 | |
389 if (trim($fileContents) !== '') { | |
390 $this->stdin = true; | |
391 $this->stdinContent = $fileContents; | |
392 self::$overriddenDefaults['stdin'] = true; | |
393 self::$overriddenDefaults['stdinContent'] = true; | |
394 } | |
395 }//end if | |
396 | |
397 fclose($handle); | |
398 | |
399 }//end __construct() | |
400 | |
401 | |
402 /** | |
403 * Set the command line values. | |
404 * | |
405 * @param array $args An array of command line arguments to set. | |
406 * | |
407 * @return void | |
408 */ | |
409 public function setCommandLineValues($args) | |
410 { | |
411 $this->cliArgs = $args; | |
412 $numArgs = count($args); | |
413 | |
414 for ($i = 0; $i < $numArgs; $i++) { | |
415 $arg = $this->cliArgs[$i]; | |
416 if ($arg === '') { | |
417 continue; | |
418 } | |
419 | |
420 if ($arg{0} === '-') { | |
421 if ($arg === '-') { | |
422 // Asking to read from STDIN. | |
423 $this->stdin = true; | |
424 self::$overriddenDefaults['stdin'] = true; | |
425 continue; | |
426 } | |
427 | |
428 if ($arg === '--') { | |
429 // Empty argument, ignore it. | |
430 continue; | |
431 } | |
432 | |
433 if ($arg{1} === '-') { | |
434 $this->processLongArgument(substr($arg, 2), $i); | |
435 } else { | |
436 $switches = str_split($arg); | |
437 foreach ($switches as $switch) { | |
438 if ($switch === '-') { | |
439 continue; | |
440 } | |
441 | |
442 $this->processShortArgument($switch, $i); | |
443 } | |
444 } | |
445 } else { | |
446 $this->processUnknownArgument($arg, $i); | |
447 }//end if | |
448 }//end for | |
449 | |
450 }//end setCommandLineValues() | |
451 | |
452 | |
453 /** | |
454 * Restore default values for all possible command line arguments. | |
455 * | |
456 * @return array | |
457 */ | |
458 public function restoreDefaults() | |
459 { | |
460 $this->files = []; | |
461 $this->standards = ['PEAR']; | |
462 $this->verbosity = 0; | |
463 $this->interactive = false; | |
464 $this->cache = false; | |
465 $this->cacheFile = null; | |
466 $this->colors = false; | |
467 $this->explain = false; | |
468 $this->local = false; | |
469 $this->showSources = false; | |
470 $this->showProgress = false; | |
471 $this->quiet = false; | |
472 $this->annotations = true; | |
473 $this->parallel = 1; | |
474 $this->tabWidth = 0; | |
475 $this->encoding = 'utf-8'; | |
476 $this->extensions = [ | |
477 'php' => 'PHP', | |
478 'inc' => 'PHP', | |
479 'js' => 'JS', | |
480 'css' => 'CSS', | |
481 ]; | |
482 $this->sniffs = []; | |
483 $this->exclude = []; | |
484 $this->ignored = []; | |
485 $this->reportFile = null; | |
486 $this->generator = null; | |
487 $this->filter = null; | |
488 $this->bootstrap = []; | |
489 $this->basepath = null; | |
490 $this->reports = ['full' => null]; | |
491 $this->reportWidth = 'auto'; | |
492 $this->errorSeverity = 5; | |
493 $this->warningSeverity = 5; | |
494 $this->recordErrors = true; | |
495 $this->suffix = ''; | |
496 $this->stdin = false; | |
497 $this->stdinContent = null; | |
498 $this->stdinPath = null; | |
499 $this->unknown = []; | |
500 | |
501 $standard = self::getConfigData('default_standard'); | |
502 if ($standard !== null) { | |
503 $this->standards = explode(',', $standard); | |
504 } | |
505 | |
506 $reportFormat = self::getConfigData('report_format'); | |
507 if ($reportFormat !== null) { | |
508 $this->reports = [$reportFormat => null]; | |
509 } | |
510 | |
511 $tabWidth = self::getConfigData('tab_width'); | |
512 if ($tabWidth !== null) { | |
513 $this->tabWidth = (int) $tabWidth; | |
514 } | |
515 | |
516 $encoding = self::getConfigData('encoding'); | |
517 if ($encoding !== null) { | |
518 $this->encoding = strtolower($encoding); | |
519 } | |
520 | |
521 $severity = self::getConfigData('severity'); | |
522 if ($severity !== null) { | |
523 $this->errorSeverity = (int) $severity; | |
524 $this->warningSeverity = (int) $severity; | |
525 } | |
526 | |
527 $severity = self::getConfigData('error_severity'); | |
528 if ($severity !== null) { | |
529 $this->errorSeverity = (int) $severity; | |
530 } | |
531 | |
532 $severity = self::getConfigData('warning_severity'); | |
533 if ($severity !== null) { | |
534 $this->warningSeverity = (int) $severity; | |
535 } | |
536 | |
537 $showWarnings = self::getConfigData('show_warnings'); | |
538 if ($showWarnings !== null) { | |
539 $showWarnings = (bool) $showWarnings; | |
540 if ($showWarnings === false) { | |
541 $this->warningSeverity = 0; | |
542 } | |
543 } | |
544 | |
545 $reportWidth = self::getConfigData('report_width'); | |
546 if ($reportWidth !== null) { | |
547 $this->reportWidth = $reportWidth; | |
548 } | |
549 | |
550 $showProgress = self::getConfigData('show_progress'); | |
551 if ($showProgress !== null) { | |
552 $this->showProgress = (bool) $showProgress; | |
553 } | |
554 | |
555 $quiet = self::getConfigData('quiet'); | |
556 if ($quiet !== null) { | |
557 $this->quiet = (bool) $quiet; | |
558 } | |
559 | |
560 $colors = self::getConfigData('colors'); | |
561 if ($colors !== null) { | |
562 $this->colors = (bool) $colors; | |
563 } | |
564 | |
565 if (defined('PHP_CODESNIFFER_IN_TESTS') === false) { | |
566 $cache = self::getConfigData('cache'); | |
567 if ($cache !== null) { | |
568 $this->cache = (bool) $cache; | |
569 } | |
570 | |
571 $parallel = self::getConfigData('parallel'); | |
572 if ($parallel !== null) { | |
573 $this->parallel = max((int) $parallel, 1); | |
574 } | |
575 } | |
576 | |
577 }//end restoreDefaults() | |
578 | |
579 | |
580 /** | |
581 * Processes a short (-e) command line argument. | |
582 * | |
583 * @param string $arg The command line argument. | |
584 * @param int $pos The position of the argument on the command line. | |
585 * | |
586 * @return void | |
587 */ | |
588 public function processShortArgument($arg, $pos) | |
589 { | |
590 switch ($arg) { | |
591 case 'h': | |
592 case '?': | |
593 ob_start(); | |
594 $this->printUsage(); | |
595 $output = ob_get_contents(); | |
596 ob_end_clean(); | |
597 throw new DeepExitException($output, 0); | |
598 case 'i' : | |
599 ob_start(); | |
600 Util\Standards::printInstalledStandards(); | |
601 $output = ob_get_contents(); | |
602 ob_end_clean(); | |
603 throw new DeepExitException($output, 0); | |
604 case 'v' : | |
605 if ($this->quiet === true) { | |
606 // Ignore when quiet mode is enabled. | |
607 break; | |
608 } | |
609 | |
610 $this->verbosity++; | |
611 self::$overriddenDefaults['verbosity'] = true; | |
612 break; | |
613 case 'l' : | |
614 $this->local = true; | |
615 self::$overriddenDefaults['local'] = true; | |
616 break; | |
617 case 's' : | |
618 $this->showSources = true; | |
619 self::$overriddenDefaults['showSources'] = true; | |
620 break; | |
621 case 'a' : | |
622 $this->interactive = true; | |
623 self::$overriddenDefaults['interactive'] = true; | |
624 break; | |
625 case 'e': | |
626 $this->explain = true; | |
627 self::$overriddenDefaults['explain'] = true; | |
628 break; | |
629 case 'p' : | |
630 if ($this->quiet === true) { | |
631 // Ignore when quiet mode is enabled. | |
632 break; | |
633 } | |
634 | |
635 $this->showProgress = true; | |
636 self::$overriddenDefaults['showProgress'] = true; | |
637 break; | |
638 case 'q' : | |
639 // Quiet mode disables a few other settings as well. | |
640 $this->quiet = true; | |
641 $this->showProgress = false; | |
642 $this->verbosity = 0; | |
643 | |
644 self::$overriddenDefaults['quiet'] = true; | |
645 break; | |
646 case 'm' : | |
647 $this->recordErrors = false; | |
648 self::$overriddenDefaults['recordErrors'] = true; | |
649 break; | |
650 case 'd' : | |
651 $ini = explode('=', $this->cliArgs[($pos + 1)]); | |
652 $this->cliArgs[($pos + 1)] = ''; | |
653 if (isset($ini[1]) === true) { | |
654 ini_set($ini[0], $ini[1]); | |
655 } else { | |
656 ini_set($ini[0], true); | |
657 } | |
658 break; | |
659 case 'n' : | |
660 if (isset(self::$overriddenDefaults['warningSeverity']) === false) { | |
661 $this->warningSeverity = 0; | |
662 self::$overriddenDefaults['warningSeverity'] = true; | |
663 } | |
664 break; | |
665 case 'w' : | |
666 if (isset(self::$overriddenDefaults['warningSeverity']) === false) { | |
667 $this->warningSeverity = $this->errorSeverity; | |
668 self::$overriddenDefaults['warningSeverity'] = true; | |
669 } | |
670 break; | |
671 default: | |
672 if ($this->dieOnUnknownArg === false) { | |
673 $unknown = $this->unknown; | |
674 $unknown[] = $arg; | |
675 $this->unknown = $unknown; | |
676 } else { | |
677 $this->processUnknownArgument('-'.$arg, $pos); | |
678 } | |
679 }//end switch | |
680 | |
681 }//end processShortArgument() | |
682 | |
683 | |
684 /** | |
685 * Processes a long (--example) command line argument. | |
686 * | |
687 * @param string $arg The command line argument. | |
688 * @param int $pos The position of the argument on the command line. | |
689 * | |
690 * @return void | |
691 */ | |
692 public function processLongArgument($arg, $pos) | |
693 { | |
694 switch ($arg) { | |
695 case 'help': | |
696 ob_start(); | |
697 $this->printUsage(); | |
698 $output = ob_get_contents(); | |
699 ob_end_clean(); | |
700 throw new DeepExitException($output, 0); | |
701 case 'version': | |
702 $output = 'PHP_CodeSniffer version '.self::VERSION.' ('.self::STABILITY.') '; | |
703 $output .= 'by Squiz (http://www.squiz.net)'.PHP_EOL; | |
704 throw new DeepExitException($output, 0); | |
705 case 'colors': | |
706 if (isset(self::$overriddenDefaults['colors']) === true) { | |
707 break; | |
708 } | |
709 | |
710 $this->colors = true; | |
711 self::$overriddenDefaults['colors'] = true; | |
712 break; | |
713 case 'no-colors': | |
714 if (isset(self::$overriddenDefaults['colors']) === true) { | |
715 break; | |
716 } | |
717 | |
718 $this->colors = false; | |
719 self::$overriddenDefaults['colors'] = true; | |
720 break; | |
721 case 'cache': | |
722 if (isset(self::$overriddenDefaults['cache']) === true) { | |
723 break; | |
724 } | |
725 | |
726 if (defined('PHP_CODESNIFFER_IN_TESTS') === false) { | |
727 $this->cache = true; | |
728 self::$overriddenDefaults['cache'] = true; | |
729 } | |
730 break; | |
731 case 'no-cache': | |
732 if (isset(self::$overriddenDefaults['cache']) === true) { | |
733 break; | |
734 } | |
735 | |
736 $this->cache = false; | |
737 self::$overriddenDefaults['cache'] = true; | |
738 break; | |
739 case 'ignore-annotations': | |
740 if (isset(self::$overriddenDefaults['annotations']) === true) { | |
741 break; | |
742 } | |
743 | |
744 $this->annotations = false; | |
745 self::$overriddenDefaults['annotations'] = true; | |
746 break; | |
747 case 'config-set': | |
748 if (isset($this->cliArgs[($pos + 1)]) === false | |
749 || isset($this->cliArgs[($pos + 2)]) === false | |
750 ) { | |
751 $error = 'ERROR: Setting a config option requires a name and value'.PHP_EOL.PHP_EOL; | |
752 $error .= $this->printShortUsage(true); | |
753 throw new DeepExitException($error, 3); | |
754 } | |
755 | |
756 $key = $this->cliArgs[($pos + 1)]; | |
757 $value = $this->cliArgs[($pos + 2)]; | |
758 $current = self::getConfigData($key); | |
759 | |
760 try { | |
761 $this->setConfigData($key, $value); | |
762 } catch (\Exception $e) { | |
763 throw new DeepExitException($e->getMessage().PHP_EOL, 3); | |
764 } | |
765 | |
766 $output = 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL; | |
767 | |
768 if ($current === null) { | |
769 $output .= "Config value \"$key\" added successfully".PHP_EOL; | |
770 } else { | |
771 $output .= "Config value \"$key\" updated successfully; old value was \"$current\"".PHP_EOL; | |
772 } | |
773 throw new DeepExitException($output, 0); | |
774 case 'config-delete': | |
775 if (isset($this->cliArgs[($pos + 1)]) === false) { | |
776 $error = 'ERROR: Deleting a config option requires the name of the option'.PHP_EOL.PHP_EOL; | |
777 $error .= $this->printShortUsage(true); | |
778 throw new DeepExitException($error, 3); | |
779 } | |
780 | |
781 $output = 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL; | |
782 | |
783 $key = $this->cliArgs[($pos + 1)]; | |
784 $current = self::getConfigData($key); | |
785 if ($current === null) { | |
786 $output .= "Config value \"$key\" has not been set".PHP_EOL; | |
787 } else { | |
788 try { | |
789 $this->setConfigData($key, null); | |
790 } catch (\Exception $e) { | |
791 throw new DeepExitException($e->getMessage().PHP_EOL, 3); | |
792 } | |
793 | |
794 $output .= "Config value \"$key\" removed successfully; old value was \"$current\"".PHP_EOL; | |
795 } | |
796 throw new DeepExitException($output, 0); | |
797 case 'config-show': | |
798 ob_start(); | |
799 $data = self::getAllConfigData(); | |
800 echo 'Using config file: '.self::$configDataFile.PHP_EOL.PHP_EOL; | |
801 $this->printConfigData($data); | |
802 $output = ob_get_contents(); | |
803 ob_end_clean(); | |
804 throw new DeepExitException($output, 0); | |
805 case 'runtime-set': | |
806 if (isset($this->cliArgs[($pos + 1)]) === false | |
807 || isset($this->cliArgs[($pos + 2)]) === false | |
808 ) { | |
809 $error = 'ERROR: Setting a runtime config option requires a name and value'.PHP_EOL.PHP_EOL; | |
810 $error .= $this->printShortUsage(true); | |
811 throw new DeepExitException($error, 3); | |
812 } | |
813 | |
814 $key = $this->cliArgs[($pos + 1)]; | |
815 $value = $this->cliArgs[($pos + 2)]; | |
816 $this->cliArgs[($pos + 1)] = ''; | |
817 $this->cliArgs[($pos + 2)] = ''; | |
818 self::setConfigData($key, $value, true); | |
819 if (isset(self::$overriddenDefaults['runtime-set']) === false) { | |
820 self::$overriddenDefaults['runtime-set'] = []; | |
821 } | |
822 | |
823 self::$overriddenDefaults['runtime-set'][$key] = true; | |
824 break; | |
825 default: | |
826 if (substr($arg, 0, 7) === 'sniffs=') { | |
827 if (isset(self::$overriddenDefaults['sniffs']) === true) { | |
828 break; | |
829 } | |
830 | |
831 $sniffs = explode(',', substr($arg, 7)); | |
832 foreach ($sniffs as $sniff) { | |
833 if (substr_count($sniff, '.') !== 2) { | |
834 $error = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL; | |
835 $error .= $this->printShortUsage(true); | |
836 throw new DeepExitException($error, 3); | |
837 } | |
838 } | |
839 | |
840 $this->sniffs = $sniffs; | |
841 self::$overriddenDefaults['sniffs'] = true; | |
842 } else if (substr($arg, 0, 8) === 'exclude=') { | |
843 if (isset(self::$overriddenDefaults['exclude']) === true) { | |
844 break; | |
845 } | |
846 | |
847 $sniffs = explode(',', substr($arg, 8)); | |
848 foreach ($sniffs as $sniff) { | |
849 if (substr_count($sniff, '.') !== 2) { | |
850 $error = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL; | |
851 $error .= $this->printShortUsage(true); | |
852 throw new DeepExitException($error, 3); | |
853 } | |
854 } | |
855 | |
856 $this->exclude = $sniffs; | |
857 self::$overriddenDefaults['exclude'] = true; | |
858 } else if (defined('PHP_CODESNIFFER_IN_TESTS') === false | |
859 && substr($arg, 0, 6) === 'cache=' | |
860 ) { | |
861 if ((isset(self::$overriddenDefaults['cache']) === true | |
862 && $this->cache === false) | |
863 || isset(self::$overriddenDefaults['cacheFile']) === true | |
864 ) { | |
865 break; | |
866 } | |
867 | |
868 // Turn caching on. | |
869 $this->cache = true; | |
870 self::$overriddenDefaults['cache'] = true; | |
871 | |
872 $this->cacheFile = Util\Common::realpath(substr($arg, 6)); | |
873 | |
874 // It may not exist and return false instead. | |
875 if ($this->cacheFile === false) { | |
876 $this->cacheFile = substr($arg, 6); | |
877 | |
878 $dir = dirname($this->cacheFile); | |
879 if (is_dir($dir) === false) { | |
880 $error = 'ERROR: The specified cache file path "'.$this->cacheFile.'" points to a non-existent directory'.PHP_EOL.PHP_EOL; | |
881 $error .= $this->printShortUsage(true); | |
882 throw new DeepExitException($error, 3); | |
883 } | |
884 | |
885 if ($dir === '.') { | |
886 // Passed cache file is a file in the current directory. | |
887 $this->cacheFile = getcwd().'/'.basename($this->cacheFile); | |
888 } else { | |
889 if ($dir{0} === '/') { | |
890 // An absolute path. | |
891 $dir = Util\Common::realpath($dir); | |
892 } else { | |
893 $dir = Util\Common::realpath(getcwd().'/'.$dir); | |
894 } | |
895 | |
896 if ($dir !== false) { | |
897 // Cache file path is relative. | |
898 $this->cacheFile = $dir.'/'.basename($this->cacheFile); | |
899 } | |
900 } | |
901 }//end if | |
902 | |
903 self::$overriddenDefaults['cacheFile'] = true; | |
904 | |
905 if (is_dir($this->cacheFile) === true) { | |
906 $error = 'ERROR: The specified cache file path "'.$this->cacheFile.'" is a directory'.PHP_EOL.PHP_EOL; | |
907 $error .= $this->printShortUsage(true); | |
908 throw new DeepExitException($error, 3); | |
909 } | |
910 } else if (substr($arg, 0, 10) === 'bootstrap=') { | |
911 $files = explode(',', substr($arg, 10)); | |
912 $bootstrap = []; | |
913 foreach ($files as $file) { | |
914 $path = Util\Common::realpath($file); | |
915 if ($path === false) { | |
916 $error = 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL; | |
917 $error .= $this->printShortUsage(true); | |
918 throw new DeepExitException($error, 3); | |
919 } | |
920 | |
921 $bootstrap[] = $path; | |
922 } | |
923 | |
924 $this->bootstrap = array_merge($this->bootstrap, $bootstrap); | |
925 self::$overriddenDefaults['bootstrap'] = true; | |
926 } else if (substr($arg, 0, 10) === 'file-list=') { | |
927 $fileList = substr($arg, 10); | |
928 $path = Util\Common::realpath($fileList); | |
929 if ($path === false) { | |
930 $error = 'ERROR: The specified file list "'.$fileList.'" does not exist'.PHP_EOL.PHP_EOL; | |
931 $error .= $this->printShortUsage(true); | |
932 throw new DeepExitException($error, 3); | |
933 } | |
934 | |
935 $files = file($path); | |
936 foreach ($files as $inputFile) { | |
937 $inputFile = trim($inputFile); | |
938 | |
939 // Skip empty lines. | |
940 if ($inputFile === '') { | |
941 continue; | |
942 } | |
943 | |
944 $this->processFilePath($inputFile); | |
945 } | |
946 } else if (substr($arg, 0, 11) === 'stdin-path=') { | |
947 if (isset(self::$overriddenDefaults['stdinPath']) === true) { | |
948 break; | |
949 } | |
950 | |
951 $this->stdinPath = Util\Common::realpath(substr($arg, 11)); | |
952 | |
953 // It may not exist and return false instead, so use whatever they gave us. | |
954 if ($this->stdinPath === false) { | |
955 $this->stdinPath = trim(substr($arg, 11)); | |
956 } | |
957 | |
958 self::$overriddenDefaults['stdinPath'] = true; | |
959 } else if (PHP_CODESNIFFER_CBF === false && substr($arg, 0, 12) === 'report-file=') { | |
960 if (isset(self::$overriddenDefaults['reportFile']) === true) { | |
961 break; | |
962 } | |
963 | |
964 $this->reportFile = Util\Common::realpath(substr($arg, 12)); | |
965 | |
966 // It may not exist and return false instead. | |
967 if ($this->reportFile === false) { | |
968 $this->reportFile = substr($arg, 12); | |
969 | |
970 $dir = dirname($this->reportFile); | |
971 if (is_dir($dir) === false) { | |
972 $error = 'ERROR: The specified report file path "'.$this->reportFile.'" points to a non-existent directory'.PHP_EOL.PHP_EOL; | |
973 $error .= $this->printShortUsage(true); | |
974 throw new DeepExitException($error, 3); | |
975 } | |
976 | |
977 if ($dir === '.') { | |
978 // Passed report file is a file in the current directory. | |
979 $this->reportFile = getcwd().'/'.basename($this->reportFile); | |
980 } else { | |
981 if ($dir{0} === '/') { | |
982 // An absolute path. | |
983 $dir = Util\Common::realpath($dir); | |
984 } else { | |
985 $dir = Util\Common::realpath(getcwd().'/'.$dir); | |
986 } | |
987 | |
988 if ($dir !== false) { | |
989 // Report file path is relative. | |
990 $this->reportFile = $dir.'/'.basename($this->reportFile); | |
991 } | |
992 } | |
993 }//end if | |
994 | |
995 self::$overriddenDefaults['reportFile'] = true; | |
996 | |
997 if (is_dir($this->reportFile) === true) { | |
998 $error = 'ERROR: The specified report file path "'.$this->reportFile.'" is a directory'.PHP_EOL.PHP_EOL; | |
999 $error .= $this->printShortUsage(true); | |
1000 throw new DeepExitException($error, 3); | |
1001 } | |
1002 } else if (substr($arg, 0, 13) === 'report-width=') { | |
1003 if (isset(self::$overriddenDefaults['reportWidth']) === true) { | |
1004 break; | |
1005 } | |
1006 | |
1007 $this->reportWidth = substr($arg, 13); | |
1008 self::$overriddenDefaults['reportWidth'] = true; | |
1009 } else if (substr($arg, 0, 9) === 'basepath=') { | |
1010 if (isset(self::$overriddenDefaults['basepath']) === true) { | |
1011 break; | |
1012 } | |
1013 | |
1014 self::$overriddenDefaults['basepath'] = true; | |
1015 | |
1016 if (substr($arg, 9) === '') { | |
1017 $this->basepath = null; | |
1018 break; | |
1019 } | |
1020 | |
1021 $this->basepath = Util\Common::realpath(substr($arg, 9)); | |
1022 | |
1023 // It may not exist and return false instead. | |
1024 if ($this->basepath === false) { | |
1025 $this->basepath = substr($arg, 9); | |
1026 } | |
1027 | |
1028 if (is_dir($this->basepath) === false) { | |
1029 $error = 'ERROR: The specified basepath "'.$this->basepath.'" points to a non-existent directory'.PHP_EOL.PHP_EOL; | |
1030 $error .= $this->printShortUsage(true); | |
1031 throw new DeepExitException($error, 3); | |
1032 } | |
1033 } else if ((substr($arg, 0, 7) === 'report=' || substr($arg, 0, 7) === 'report-')) { | |
1034 $reports = []; | |
1035 | |
1036 if ($arg[6] === '-') { | |
1037 // This is a report with file output. | |
1038 $split = strpos($arg, '='); | |
1039 if ($split === false) { | |
1040 $report = substr($arg, 7); | |
1041 $output = null; | |
1042 } else { | |
1043 $report = substr($arg, 7, ($split - 7)); | |
1044 $output = substr($arg, ($split + 1)); | |
1045 if ($output === false) { | |
1046 $output = null; | |
1047 } else { | |
1048 $dir = dirname($output); | |
1049 if (is_dir($dir) === false) { | |
1050 $error = 'ERROR: The specified '.$report.' report file path "'.$output.'" points to a non-existent directory'.PHP_EOL.PHP_EOL; | |
1051 $error .= $this->printShortUsage(true); | |
1052 throw new DeepExitException($error, 3); | |
1053 } | |
1054 | |
1055 if ($dir === '.') { | |
1056 // Passed report file is a filename in the current directory. | |
1057 $output = getcwd().'/'.basename($output); | |
1058 } else { | |
1059 if ($dir{0} === '/') { | |
1060 // An absolute path. | |
1061 $dir = Util\Common::realpath($dir); | |
1062 } else { | |
1063 $dir = Util\Common::realpath(getcwd().'/'.$dir); | |
1064 } | |
1065 | |
1066 if ($dir !== false) { | |
1067 // Report file path is relative. | |
1068 $output = $dir.'/'.basename($output); | |
1069 } | |
1070 } | |
1071 }//end if | |
1072 }//end if | |
1073 | |
1074 $reports[$report] = $output; | |
1075 } else { | |
1076 // This is a single report. | |
1077 if (isset(self::$overriddenDefaults['reports']) === true) { | |
1078 break; | |
1079 } | |
1080 | |
1081 $reportNames = explode(',', substr($arg, 7)); | |
1082 foreach ($reportNames as $report) { | |
1083 $reports[$report] = null; | |
1084 } | |
1085 }//end if | |
1086 | |
1087 // Remove the default value so the CLI value overrides it. | |
1088 if (isset(self::$overriddenDefaults['reports']) === false) { | |
1089 $this->reports = $reports; | |
1090 } else { | |
1091 $this->reports = array_merge($this->reports, $reports); | |
1092 } | |
1093 | |
1094 self::$overriddenDefaults['reports'] = true; | |
1095 } else if (substr($arg, 0, 7) === 'filter=') { | |
1096 if (isset(self::$overriddenDefaults['filter']) === true) { | |
1097 break; | |
1098 } | |
1099 | |
1100 $this->filter = substr($arg, 7); | |
1101 self::$overriddenDefaults['filter'] = true; | |
1102 } else if (substr($arg, 0, 9) === 'standard=') { | |
1103 $standards = trim(substr($arg, 9)); | |
1104 if ($standards !== '') { | |
1105 $this->standards = explode(',', $standards); | |
1106 } | |
1107 | |
1108 self::$overriddenDefaults['standards'] = true; | |
1109 } else if (substr($arg, 0, 11) === 'extensions=') { | |
1110 if (isset(self::$overriddenDefaults['extensions']) === true) { | |
1111 break; | |
1112 } | |
1113 | |
1114 $extensions = explode(',', substr($arg, 11)); | |
1115 $newExtensions = []; | |
1116 foreach ($extensions as $ext) { | |
1117 $slash = strpos($ext, '/'); | |
1118 if ($slash !== false) { | |
1119 // They specified the tokenizer too. | |
1120 list($ext, $tokenizer) = explode('/', $ext); | |
1121 $newExtensions[$ext] = strtoupper($tokenizer); | |
1122 continue; | |
1123 } | |
1124 | |
1125 if (isset($this->extensions[$ext]) === true) { | |
1126 $newExtensions[$ext] = $this->extensions[$ext]; | |
1127 } else { | |
1128 $newExtensions[$ext] = 'PHP'; | |
1129 } | |
1130 } | |
1131 | |
1132 $this->extensions = $newExtensions; | |
1133 self::$overriddenDefaults['extensions'] = true; | |
1134 } else if (substr($arg, 0, 7) === 'suffix=') { | |
1135 if (isset(self::$overriddenDefaults['suffix']) === true) { | |
1136 break; | |
1137 } | |
1138 | |
1139 $this->suffix = substr($arg, 7); | |
1140 self::$overriddenDefaults['suffix'] = true; | |
1141 } else if (substr($arg, 0, 9) === 'parallel=') { | |
1142 if (isset(self::$overriddenDefaults['parallel']) === true) { | |
1143 break; | |
1144 } | |
1145 | |
1146 $this->parallel = max((int) substr($arg, 9), 1); | |
1147 self::$overriddenDefaults['parallel'] = true; | |
1148 } else if (substr($arg, 0, 9) === 'severity=') { | |
1149 $this->errorSeverity = (int) substr($arg, 9); | |
1150 $this->warningSeverity = $this->errorSeverity; | |
1151 if (isset(self::$overriddenDefaults['errorSeverity']) === false) { | |
1152 self::$overriddenDefaults['errorSeverity'] = true; | |
1153 } | |
1154 | |
1155 if (isset(self::$overriddenDefaults['warningSeverity']) === false) { | |
1156 self::$overriddenDefaults['warningSeverity'] = true; | |
1157 } | |
1158 } else if (substr($arg, 0, 15) === 'error-severity=') { | |
1159 if (isset(self::$overriddenDefaults['errorSeverity']) === true) { | |
1160 break; | |
1161 } | |
1162 | |
1163 $this->errorSeverity = (int) substr($arg, 15); | |
1164 self::$overriddenDefaults['errorSeverity'] = true; | |
1165 } else if (substr($arg, 0, 17) === 'warning-severity=') { | |
1166 if (isset(self::$overriddenDefaults['warningSeverity']) === true) { | |
1167 break; | |
1168 } | |
1169 | |
1170 $this->warningSeverity = (int) substr($arg, 17); | |
1171 self::$overriddenDefaults['warningSeverity'] = true; | |
1172 } else if (substr($arg, 0, 7) === 'ignore=') { | |
1173 if (isset(self::$overriddenDefaults['ignored']) === true) { | |
1174 break; | |
1175 } | |
1176 | |
1177 // Split the ignore string on commas, unless the comma is escaped | |
1178 // using 1 or 3 slashes (\, or \\\,). | |
1179 $patterns = preg_split( | |
1180 '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/', | |
1181 substr($arg, 7) | |
1182 ); | |
1183 | |
1184 $ignored = []; | |
1185 foreach ($patterns as $pattern) { | |
1186 $pattern = trim($pattern); | |
1187 if ($pattern === '') { | |
1188 continue; | |
1189 } | |
1190 | |
1191 $ignored[$pattern] = 'absolute'; | |
1192 } | |
1193 | |
1194 $this->ignored = $ignored; | |
1195 self::$overriddenDefaults['ignored'] = true; | |
1196 } else if (substr($arg, 0, 10) === 'generator=' | |
1197 && PHP_CODESNIFFER_CBF === false | |
1198 ) { | |
1199 if (isset(self::$overriddenDefaults['generator']) === true) { | |
1200 break; | |
1201 } | |
1202 | |
1203 $this->generator = substr($arg, 10); | |
1204 self::$overriddenDefaults['generator'] = true; | |
1205 } else if (substr($arg, 0, 9) === 'encoding=') { | |
1206 if (isset(self::$overriddenDefaults['encoding']) === true) { | |
1207 break; | |
1208 } | |
1209 | |
1210 $this->encoding = strtolower(substr($arg, 9)); | |
1211 self::$overriddenDefaults['encoding'] = true; | |
1212 } else if (substr($arg, 0, 10) === 'tab-width=') { | |
1213 if (isset(self::$overriddenDefaults['tabWidth']) === true) { | |
1214 break; | |
1215 } | |
1216 | |
1217 $this->tabWidth = (int) substr($arg, 10); | |
1218 self::$overriddenDefaults['tabWidth'] = true; | |
1219 } else { | |
1220 if ($this->dieOnUnknownArg === false) { | |
1221 $eqPos = strpos($arg, '='); | |
1222 try { | |
1223 if ($eqPos === false) { | |
1224 $this->values[$arg] = $arg; | |
1225 } else { | |
1226 $value = substr($arg, ($eqPos + 1)); | |
1227 $arg = substr($arg, 0, $eqPos); | |
1228 $this->values[$arg] = $value; | |
1229 } | |
1230 } catch (RuntimeException $e) { | |
1231 // Value is not valid, so just ignore it. | |
1232 } | |
1233 } else { | |
1234 $this->processUnknownArgument('--'.$arg, $pos); | |
1235 } | |
1236 }//end if | |
1237 break; | |
1238 }//end switch | |
1239 | |
1240 }//end processLongArgument() | |
1241 | |
1242 | |
1243 /** | |
1244 * Processes an unknown command line argument. | |
1245 * | |
1246 * Assumes all unknown arguments are files and folders to check. | |
1247 * | |
1248 * @param string $arg The command line argument. | |
1249 * @param int $pos The position of the argument on the command line. | |
1250 * | |
1251 * @return void | |
1252 */ | |
1253 public function processUnknownArgument($arg, $pos) | |
1254 { | |
1255 // We don't know about any additional switches; just files. | |
1256 if ($arg{0} === '-') { | |
1257 if ($this->dieOnUnknownArg === false) { | |
1258 return; | |
1259 } | |
1260 | |
1261 $error = "ERROR: option \"$arg\" not known".PHP_EOL.PHP_EOL; | |
1262 $error .= $this->printShortUsage(true); | |
1263 throw new DeepExitException($error, 3); | |
1264 } | |
1265 | |
1266 $this->processFilePath($arg); | |
1267 | |
1268 }//end processUnknownArgument() | |
1269 | |
1270 | |
1271 /** | |
1272 * Processes a file path and add it to the file list. | |
1273 * | |
1274 * @param string $path The path to the file to add. | |
1275 * | |
1276 * @return void | |
1277 */ | |
1278 public function processFilePath($path) | |
1279 { | |
1280 // If we are processing STDIN, don't record any files to check. | |
1281 if ($this->stdin === true) { | |
1282 return; | |
1283 } | |
1284 | |
1285 $file = Util\Common::realpath($path); | |
1286 if (file_exists($file) === false) { | |
1287 if ($this->dieOnUnknownArg === false) { | |
1288 return; | |
1289 } | |
1290 | |
1291 $error = 'ERROR: The file "'.$path.'" does not exist.'.PHP_EOL.PHP_EOL; | |
1292 $error .= $this->printShortUsage(true); | |
1293 throw new DeepExitException($error, 3); | |
1294 } else { | |
1295 // Can't modify the files array directly because it's not a real | |
1296 // class member, so need to use this little get/modify/set trick. | |
1297 $files = $this->files; | |
1298 $files[] = $file; | |
1299 $this->files = $files; | |
1300 self::$overriddenDefaults['files'] = true; | |
1301 } | |
1302 | |
1303 }//end processFilePath() | |
1304 | |
1305 | |
1306 /** | |
1307 * Prints out the usage information for this script. | |
1308 * | |
1309 * @return void | |
1310 */ | |
1311 public function printUsage() | |
1312 { | |
1313 echo PHP_EOL; | |
1314 | |
1315 if (PHP_CODESNIFFER_CBF === true) { | |
1316 $this->printPHPCBFUsage(); | |
1317 } else { | |
1318 $this->printPHPCSUsage(); | |
1319 } | |
1320 | |
1321 echo PHP_EOL; | |
1322 | |
1323 }//end printUsage() | |
1324 | |
1325 | |
1326 /** | |
1327 * Prints out the short usage information for this script. | |
1328 * | |
1329 * @param bool $return If TRUE, the usage string is returned | |
1330 * instead of output to screen. | |
1331 * | |
1332 * @return string|void | |
1333 */ | |
1334 public function printShortUsage($return=false) | |
1335 { | |
1336 if (PHP_CODESNIFFER_CBF === true) { | |
1337 $usage = 'Run "phpcbf --help" for usage information'; | |
1338 } else { | |
1339 $usage = 'Run "phpcs --help" for usage information'; | |
1340 } | |
1341 | |
1342 $usage .= PHP_EOL.PHP_EOL; | |
1343 | |
1344 if ($return === true) { | |
1345 return $usage; | |
1346 } | |
1347 | |
1348 echo $usage; | |
1349 | |
1350 }//end printShortUsage() | |
1351 | |
1352 | |
1353 /** | |
1354 * Prints out the usage information for PHPCS. | |
1355 * | |
1356 * @return void | |
1357 */ | |
1358 public function printPHPCSUsage() | |
1359 { | |
1360 echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]'.PHP_EOL; | |
1361 echo ' [--cache[=<cacheFile>]] [--no-cache] [--tab-width=<tabWidth>]'.PHP_EOL; | |
1362 echo ' [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>]'.PHP_EOL; | |
1363 echo ' [--report-width=<reportWidth>] [--basepath=<basepath>] [--bootstrap=<bootstrap>]'.PHP_EOL; | |
1364 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL; | |
1365 echo ' [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL; | |
1366 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>]'.PHP_EOL; | |
1367 echo ' [--encoding=<encoding>] [--parallel=<processes>] [--generator=<generator>]'.PHP_EOL; | |
1368 echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--ignore-annotations]'.PHP_EOL; | |
1369 echo ' [--stdin-path=<stdinPath>] [--file-list=<fileList>] <file> - ...'.PHP_EOL; | |
1370 echo PHP_EOL; | |
1371 echo ' - Check STDIN instead of local files and directories'.PHP_EOL; | |
1372 echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL; | |
1373 echo ' -w Print both warnings and errors (this is the default)'.PHP_EOL; | |
1374 echo ' -l Local directory only, no recursion'.PHP_EOL; | |
1375 echo ' -s Show sniff codes in all reports'.PHP_EOL; | |
1376 echo ' -a Run interactively'.PHP_EOL; | |
1377 echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL; | |
1378 echo ' -p Show progress of the run'.PHP_EOL; | |
1379 echo ' -q Quiet mode; disables progress and verbose output'.PHP_EOL; | |
1380 echo ' -m Stop error messages from being recorded'.PHP_EOL; | |
1381 echo ' (saves a lot of memory, but stops many reports from being used)'.PHP_EOL; | |
1382 echo ' -v Print processed files'.PHP_EOL; | |
1383 echo ' -vv Print ruleset and token output'.PHP_EOL; | |
1384 echo ' -vvv Print sniff processing information'.PHP_EOL; | |
1385 echo ' -i Show a list of installed coding standards'.PHP_EOL; | |
1386 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; | |
1387 echo PHP_EOL; | |
1388 echo ' --help Print this help message'.PHP_EOL; | |
1389 echo ' --version Print version information'.PHP_EOL; | |
1390 echo ' --colors Use colors in output'.PHP_EOL; | |
1391 echo ' --no-colors Do not use colors in output (this is the default)'.PHP_EOL; | |
1392 echo ' --cache Cache results between runs'.PHP_EOL; | |
1393 echo ' --no-cache Do not cache results between runs (this is the default)'.PHP_EOL; | |
1394 echo ' --ignore-annotations Ignore all phpcs: annotations in code comments'.PHP_EOL; | |
1395 echo PHP_EOL; | |
1396 echo ' <cacheFile> Use a specific file for caching (uses a temporary file by default)'.PHP_EOL; | |
1397 echo ' <basepath> A path to strip from the front of file paths inside reports'.PHP_EOL; | |
1398 echo ' <bootstrap> A comma separated list of files to run before processing begins'.PHP_EOL; | |
1399 echo ' <file> One or more files and/or directories to check'.PHP_EOL; | |
1400 echo ' <fileList> A file containing a list of files and/or directories to check (one per line)'.PHP_EOL; | |
1401 echo ' <encoding> The encoding of the files being checked (default is utf-8)'.PHP_EOL; | |
1402 echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL; | |
1403 echo ' The type of the file can be specified using: ext/type'.PHP_EOL; | |
1404 echo ' e.g., module/php,es/js'.PHP_EOL; | |
1405 echo ' <generator> Uses either the "HTML", "Markdown" or "Text" generator'.PHP_EOL; | |
1406 echo ' (forces documentation generation instead of checking)'.PHP_EOL; | |
1407 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL; | |
1408 echo ' <processes> How many files should be checked simultaneously (default is 1)'.PHP_EOL; | |
1409 echo ' <report> Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL; | |
1410 echo ' "json", "junit", "emacs", "source", "summary", "diff"'.PHP_EOL; | |
1411 echo ' "svnblame", "gitblame", "hgblame" or "notifysend" report'.PHP_EOL; | |
1412 echo ' (the "full" report is printed by default)'.PHP_EOL; | |
1413 echo ' <reportFile> Write the report to the specified file path'.PHP_EOL; | |
1414 echo ' <reportWidth> How many columns wide screen reports should be printed'.PHP_EOL; | |
1415 echo ' or set to "auto" to use current screen width, where supported'.PHP_EOL; | |
1416 echo ' <severity> The minimum severity required to display an error or warning'.PHP_EOL; | |
1417 echo ' <sniffs> A comma separated list of sniff codes to include or exclude from checking'.PHP_EOL; | |
1418 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; | |
1419 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL; | |
1420 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL; | |
1421 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL; | |
1422 | |
1423 }//end printPHPCSUsage() | |
1424 | |
1425 | |
1426 /** | |
1427 * Prints out the usage information for PHPCBF. | |
1428 * | |
1429 * @return void | |
1430 */ | |
1431 public function printPHPCBFUsage() | |
1432 { | |
1433 echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--ignore-annotations] [--bootstrap=<bootstrap>]'.PHP_EOL; | |
1434 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--suffix=<suffix>]'.PHP_EOL; | |
1435 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL; | |
1436 echo ' [--tab-width=<tabWidth>] [--encoding=<encoding>] [--parallel=<processes>]'.PHP_EOL; | |
1437 echo ' [--basepath=<basepath>] [--extensions=<extensions>] [--ignore=<patterns>]'.PHP_EOL; | |
1438 echo ' [--stdin-path=<stdinPath>] [--file-list=<fileList>] <file> - ...'.PHP_EOL; | |
1439 echo PHP_EOL; | |
1440 echo ' - Fix STDIN instead of local files and directories'.PHP_EOL; | |
1441 echo ' -n Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL; | |
1442 echo ' -w Fix both warnings and errors (on by default)'.PHP_EOL; | |
1443 echo ' -l Local directory only, no recursion'.PHP_EOL; | |
1444 echo ' -p Show progress of the run'.PHP_EOL; | |
1445 echo ' -q Quiet mode; disables progress and verbose output'.PHP_EOL; | |
1446 echo ' -v Print processed files'.PHP_EOL; | |
1447 echo ' -vv Print ruleset and token output'.PHP_EOL; | |
1448 echo ' -vvv Print sniff processing information'.PHP_EOL; | |
1449 echo ' -i Show a list of installed coding standards'.PHP_EOL; | |
1450 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; | |
1451 echo PHP_EOL; | |
1452 echo ' --help Print this help message'.PHP_EOL; | |
1453 echo ' --version Print version information'.PHP_EOL; | |
1454 echo ' --ignore-annotations Ignore all phpcs: annotations in code comments'.PHP_EOL; | |
1455 echo PHP_EOL; | |
1456 echo ' <basepath> A path to strip from the front of file paths inside reports'.PHP_EOL; | |
1457 echo ' <bootstrap> A comma separated list of files to run before processing begins'.PHP_EOL; | |
1458 echo ' <file> One or more files and/or directories to fix'.PHP_EOL; | |
1459 echo ' <fileList> A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL; | |
1460 echo ' <encoding> The encoding of the files being fixed (default is utf-8)'.PHP_EOL; | |
1461 echo ' <extensions> A comma separated list of file extensions to fix'.PHP_EOL; | |
1462 echo ' The type of the file can be specified using: ext/type'.PHP_EOL; | |
1463 echo ' e.g., module/php,es/js'.PHP_EOL; | |
1464 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL; | |
1465 echo ' <processes> How many files should be fixed simultaneously (default is 1)'.PHP_EOL; | |
1466 echo ' <severity> The minimum severity required to fix an error or warning'.PHP_EOL; | |
1467 echo ' <sniffs> A comma separated list of sniff codes to include or exclude from fixing'.PHP_EOL; | |
1468 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; | |
1469 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL; | |
1470 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL; | |
1471 echo ' <suffix> Write modified files to a filename using this suffix'.PHP_EOL; | |
1472 echo ' ("diff" and "patch" are not used in this mode)'.PHP_EOL; | |
1473 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL; | |
1474 | |
1475 }//end printPHPCBFUsage() | |
1476 | |
1477 | |
1478 /** | |
1479 * Get a single config value. | |
1480 * | |
1481 * @param string $key The name of the config value. | |
1482 * | |
1483 * @return string|null | |
1484 * @see setConfigData() | |
1485 * @see getAllConfigData() | |
1486 */ | |
1487 public static function getConfigData($key) | |
1488 { | |
1489 $phpCodeSnifferConfig = self::getAllConfigData(); | |
1490 | |
1491 if ($phpCodeSnifferConfig === null) { | |
1492 return null; | |
1493 } | |
1494 | |
1495 if (isset($phpCodeSnifferConfig[$key]) === false) { | |
1496 return null; | |
1497 } | |
1498 | |
1499 return $phpCodeSnifferConfig[$key]; | |
1500 | |
1501 }//end getConfigData() | |
1502 | |
1503 | |
1504 /** | |
1505 * Get the path to an executable utility. | |
1506 * | |
1507 * @param string $name The name of the executable utility. | |
1508 * | |
1509 * @return string|null | |
1510 * @see getConfigData() | |
1511 */ | |
1512 public static function getExecutablePath($name) | |
1513 { | |
1514 $data = self::getConfigData($name.'_path'); | |
1515 if ($data !== null) { | |
1516 return $data; | |
1517 } | |
1518 | |
1519 if ($name === "php") { | |
1520 // For php, we know the executable path. There's no need to look it up. | |
1521 return PHP_BINARY; | |
1522 } | |
1523 | |
1524 if (array_key_exists($name, self::$executablePaths) === true) { | |
1525 return self::$executablePaths[$name]; | |
1526 } | |
1527 | |
1528 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
1529 $cmd = 'where '.escapeshellarg($name).' 2> nul'; | |
1530 } else { | |
1531 $cmd = 'which '.escapeshellarg($name).' 2> /dev/null'; | |
1532 } | |
1533 | |
1534 $result = exec($cmd, $output, $retVal); | |
1535 if ($retVal !== 0) { | |
1536 $result = null; | |
1537 } | |
1538 | |
1539 self::$executablePaths[$name] = $result; | |
1540 return $result; | |
1541 | |
1542 }//end getExecutablePath() | |
1543 | |
1544 | |
1545 /** | |
1546 * Set a single config value. | |
1547 * | |
1548 * @param string $key The name of the config value. | |
1549 * @param string|null $value The value to set. If null, the config | |
1550 * entry is deleted, reverting it to the | |
1551 * default value. | |
1552 * @param boolean $temp Set this config data temporarily for this | |
1553 * script run. This will not write the config | |
1554 * data to the config file. | |
1555 * | |
1556 * @return bool | |
1557 * @see getConfigData() | |
1558 * @throws RuntimeException If the config file can not be written. | |
1559 */ | |
1560 public static function setConfigData($key, $value, $temp=false) | |
1561 { | |
1562 if (isset(self::$overriddenDefaults['runtime-set']) === true | |
1563 && isset(self::$overriddenDefaults['runtime-set'][$key]) === true | |
1564 ) { | |
1565 return false; | |
1566 } | |
1567 | |
1568 if ($temp === false) { | |
1569 $path = ''; | |
1570 if (is_callable('\Phar::running') === true) { | |
1571 $path = \Phar::running(false); | |
1572 } | |
1573 | |
1574 if ($path !== '') { | |
1575 $configFile = dirname($path).DIRECTORY_SEPARATOR.'CodeSniffer.conf'; | |
1576 } else { | |
1577 $configFile = dirname(__DIR__).DIRECTORY_SEPARATOR.'CodeSniffer.conf'; | |
1578 if (is_file($configFile) === false | |
1579 && strpos('@data_dir@', '@data_dir') === false | |
1580 ) { | |
1581 // If data_dir was replaced, this is a PEAR install and we can | |
1582 // use the PEAR data dir to store the conf file. | |
1583 $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; | |
1584 } | |
1585 } | |
1586 | |
1587 if (is_file($configFile) === true | |
1588 && is_writable($configFile) === false | |
1589 ) { | |
1590 $error = 'ERROR: Config file '.$configFile.' is not writable'.PHP_EOL.PHP_EOL; | |
1591 throw new DeepExitException($error, 3); | |
1592 } | |
1593 }//end if | |
1594 | |
1595 $phpCodeSnifferConfig = self::getAllConfigData(); | |
1596 | |
1597 if ($value === null) { | |
1598 if (isset($phpCodeSnifferConfig[$key]) === true) { | |
1599 unset($phpCodeSnifferConfig[$key]); | |
1600 } | |
1601 } else { | |
1602 $phpCodeSnifferConfig[$key] = $value; | |
1603 } | |
1604 | |
1605 if ($temp === false) { | |
1606 $output = '<'.'?php'."\n".' $phpCodeSnifferConfig = '; | |
1607 $output .= var_export($phpCodeSnifferConfig, true); | |
1608 $output .= "\n?".'>'; | |
1609 | |
1610 if (file_put_contents($configFile, $output) === false) { | |
1611 $error = 'ERROR: Config file '.$configFile.' could not be written'.PHP_EOL.PHP_EOL; | |
1612 throw new DeepExitException($error, 3); | |
1613 } | |
1614 | |
1615 self::$configDataFile = $configFile; | |
1616 } | |
1617 | |
1618 self::$configData = $phpCodeSnifferConfig; | |
1619 | |
1620 // If the installed paths are being set, make sure all known | |
1621 // standards paths are added to the autoloader. | |
1622 if ($key === 'installed_paths') { | |
1623 $installedStandards = Util\Standards::getInstalledStandardDetails(); | |
1624 foreach ($installedStandards as $name => $details) { | |
1625 Autoload::addSearchPath($details['path'], $details['namespace']); | |
1626 } | |
1627 } | |
1628 | |
1629 return true; | |
1630 | |
1631 }//end setConfigData() | |
1632 | |
1633 | |
1634 /** | |
1635 * Get all config data. | |
1636 * | |
1637 * @return array<string, string> | |
1638 * @see getConfigData() | |
1639 */ | |
1640 public static function getAllConfigData() | |
1641 { | |
1642 if (self::$configData !== null) { | |
1643 return self::$configData; | |
1644 } | |
1645 | |
1646 $path = ''; | |
1647 if (is_callable('\Phar::running') === true) { | |
1648 $path = \Phar::running(false); | |
1649 } | |
1650 | |
1651 if ($path !== '') { | |
1652 $configFile = dirname($path).DIRECTORY_SEPARATOR.'CodeSniffer.conf'; | |
1653 } else { | |
1654 $configFile = dirname(__DIR__).DIRECTORY_SEPARATOR.'CodeSniffer.conf'; | |
1655 if (is_file($configFile) === false | |
1656 && strpos('@data_dir@', '@data_dir') === false | |
1657 ) { | |
1658 $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; | |
1659 } | |
1660 } | |
1661 | |
1662 if (is_file($configFile) === false) { | |
1663 self::$configData = []; | |
1664 return []; | |
1665 } | |
1666 | |
1667 if (is_readable($configFile) === false) { | |
1668 $error = 'ERROR: Config file '.$configFile.' is not readable'.PHP_EOL.PHP_EOL; | |
1669 throw new DeepExitException($error, 3); | |
1670 } | |
1671 | |
1672 include $configFile; | |
1673 self::$configDataFile = $configFile; | |
1674 self::$configData = $phpCodeSnifferConfig; | |
1675 return self::$configData; | |
1676 | |
1677 }//end getAllConfigData() | |
1678 | |
1679 | |
1680 /** | |
1681 * Prints out the gathered config data. | |
1682 * | |
1683 * @param array $data The config data to print. | |
1684 * | |
1685 * @return void | |
1686 */ | |
1687 public function printConfigData($data) | |
1688 { | |
1689 $max = 0; | |
1690 $keys = array_keys($data); | |
1691 foreach ($keys as $key) { | |
1692 $len = strlen($key); | |
1693 if (strlen($key) > $max) { | |
1694 $max = $len; | |
1695 } | |
1696 } | |
1697 | |
1698 if ($max === 0) { | |
1699 return; | |
1700 } | |
1701 | |
1702 $max += 2; | |
1703 ksort($data); | |
1704 foreach ($data as $name => $value) { | |
1705 echo str_pad($name.': ', $max).$value.PHP_EOL; | |
1706 } | |
1707 | |
1708 }//end printConfigData() | |
1709 | |
1710 | |
1711 }//end class |