annotate vendor/squizlabs/php_codesniffer/src/Config.php @ 19:fa3358dc1485 tip

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