annotate vendor/squizlabs/php_codesniffer/src/Config.php @ 5:12f9dff5fda9 tip

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