annotate vendor/squizlabs/php_codesniffer/CodeSniffer/CLI.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * A class to process command line phpcs scripts.
Chris@0 4 *
Chris@0 5 * PHP version 5
Chris@0 6 *
Chris@0 7 * @category PHP
Chris@0 8 * @package PHP_CodeSniffer
Chris@0 9 * @author Greg Sherwood <gsherwood@squiz.net>
Chris@0 10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
Chris@0 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@0 12 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 13 */
Chris@0 14
Chris@0 15 error_reporting(E_ALL | E_STRICT);
Chris@0 16
Chris@0 17 // Make sure version id constant is available.
Chris@0 18 if (defined('PHP_VERSION_ID') === false) {
Chris@0 19 $version = explode('.', PHP_VERSION);
Chris@0 20 define('PHP_VERSION_ID', (int) (($version[0] * 10000) + ($version[1] * 100) + $version[2]));
Chris@0 21 unset($version);
Chris@0 22 }
Chris@0 23
Chris@0 24 // Make sure that we autoload all dependencies if running via Composer.
Chris@0 25 if (PHP_VERSION_ID >= 50302) {
Chris@0 26 if (file_exists($a = dirname(__FILE__).'/../../../autoload.php') === true) {
Chris@0 27 include_once $a;
Chris@0 28 } else if (file_exists($a = dirname(__FILE__).'/../vendor/autoload.php') === true) {
Chris@0 29 include_once $a;
Chris@0 30 }
Chris@0 31 }
Chris@0 32
Chris@0 33 if (file_exists($a = dirname(__FILE__).'/../CodeSniffer.php') === true) {
Chris@0 34 // Running from a git clone.
Chris@0 35 include_once $a;
Chris@0 36 } else {
Chris@0 37 // PEAR installed.
Chris@0 38 include_once 'PHP/CodeSniffer.php';
Chris@0 39 }
Chris@0 40
Chris@0 41 /**
Chris@0 42 * A class to process command line phpcs scripts.
Chris@0 43 *
Chris@0 44 * @category PHP
Chris@0 45 * @package PHP_CodeSniffer
Chris@0 46 * @author Greg Sherwood <gsherwood@squiz.net>
Chris@0 47 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
Chris@0 48 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@0 49 * @version Release: @package_version@
Chris@0 50 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 51 */
Chris@0 52 class PHP_CodeSniffer_CLI
Chris@0 53 {
Chris@0 54
Chris@0 55 /**
Chris@0 56 * An array of all values specified on the command line.
Chris@0 57 *
Chris@0 58 * @var array
Chris@0 59 */
Chris@0 60 protected $values = array();
Chris@0 61
Chris@0 62 /**
Chris@0 63 * The minimum severity level errors must have to be displayed.
Chris@0 64 *
Chris@0 65 * @var bool
Chris@0 66 */
Chris@0 67 public $errorSeverity = 0;
Chris@0 68
Chris@0 69 /**
Chris@0 70 * The minimum severity level warnings must have to be displayed.
Chris@0 71 *
Chris@0 72 * @var bool
Chris@0 73 */
Chris@0 74 public $warningSeverity = 0;
Chris@0 75
Chris@0 76 /**
Chris@0 77 * Whether or not to kill the process when an unknown command line arg is found.
Chris@0 78 *
Chris@0 79 * If FALSE, arguments that are not command line options or file/directory paths
Chris@0 80 * will be ignored and execution will continue.
Chris@0 81 *
Chris@0 82 * @var bool
Chris@0 83 */
Chris@0 84 public $dieOnUnknownArg = true;
Chris@0 85
Chris@0 86 /**
Chris@0 87 * An array of the current command line arguments we are processing.
Chris@0 88 *
Chris@0 89 * @var array
Chris@0 90 */
Chris@0 91 private $_cliArgs = array();
Chris@0 92
Chris@0 93
Chris@0 94 /**
Chris@0 95 * Run the PHPCS script.
Chris@0 96 *
Chris@0 97 * @return array
Chris@0 98 */
Chris@0 99 public function runphpcs()
Chris@0 100 {
Chris@0 101 if (defined('PHP_CODESNIFFER_CBF') === false) {
Chris@0 102 define('PHP_CODESNIFFER_CBF', false);
Chris@0 103 }
Chris@0 104
Chris@0 105 if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) {
Chris@0 106 include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php';
Chris@0 107 } else {
Chris@0 108 include_once 'PHP/CodeSniffer/Reporting.php';
Chris@0 109 }
Chris@0 110
Chris@0 111 PHP_CodeSniffer_Reporting::startTiming();
Chris@0 112 $this->checkRequirements();
Chris@0 113 $numErrors = $this->process();
Chris@0 114 if ($numErrors === 0) {
Chris@0 115 exit(0);
Chris@0 116 } else {
Chris@0 117 exit(1);
Chris@0 118 }
Chris@0 119
Chris@0 120 }//end runphpcs()
Chris@0 121
Chris@0 122
Chris@0 123 /**
Chris@0 124 * Run the PHPCBF script.
Chris@0 125 *
Chris@0 126 * @return array
Chris@0 127 */
Chris@0 128 public function runphpcbf()
Chris@0 129 {
Chris@0 130 if (defined('PHP_CODESNIFFER_CBF') === false) {
Chris@0 131 define('PHP_CODESNIFFER_CBF', true);
Chris@0 132 }
Chris@0 133
Chris@0 134 if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) {
Chris@0 135 include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php';
Chris@0 136 } else {
Chris@0 137 include_once 'PHP/CodeSniffer/Reporting.php';
Chris@0 138 }
Chris@0 139
Chris@0 140 PHP_CodeSniffer_Reporting::startTiming();
Chris@0 141 $this->checkRequirements();
Chris@0 142
Chris@0 143 $this->dieOnUnknownArg = false;
Chris@0 144
Chris@0 145 // Override some of the command line settings that might break the fixes.
Chris@0 146 $cliValues = $this->getCommandLineValues();
Chris@0 147 $cliValues['verbosity'] = 0;
Chris@0 148 $cliValues['showProgress'] = false;
Chris@0 149 $cliValues['generator'] = '';
Chris@0 150 $cliValues['explain'] = false;
Chris@0 151 $cliValues['interactive'] = false;
Chris@0 152 $cliValues['showSources'] = false;
Chris@0 153 $cliValues['reportFile'] = null;
Chris@0 154 $cliValues['reports'] = array();
Chris@0 155
Chris@0 156 $suffix = '';
Chris@0 157 if (isset($cliValues['suffix']) === true) {
Chris@0 158 $suffix = $cliValues['suffix'];
Chris@0 159 }
Chris@0 160
Chris@0 161 $allowPatch = true;
Chris@0 162 if (isset($cliValues['no-patch']) === true || empty($cliValues['files']) === true) {
Chris@0 163 // They either asked for this,
Chris@0 164 // or they are using STDIN, which can't use diff.
Chris@0 165 $allowPatch = false;
Chris@0 166 }
Chris@0 167
Chris@0 168 if ($suffix === '' && $allowPatch === true) {
Chris@0 169 // Using the diff/patch tools.
Chris@0 170 $diffFile = getcwd().'/phpcbf-fixed.diff';
Chris@0 171 $cliValues['reports'] = array('diff' => $diffFile);
Chris@0 172 if (file_exists($diffFile) === true) {
Chris@0 173 unlink($diffFile);
Chris@0 174 }
Chris@0 175 } else {
Chris@0 176 // Replace the file without the patch command
Chris@0 177 // or writing to a file with a new suffix.
Chris@0 178 $cliValues['reports'] = array('cbf' => null);
Chris@0 179 $cliValues['phpcbf-suffix'] = $suffix;
Chris@0 180 }
Chris@0 181
Chris@0 182 $numErrors = $this->process($cliValues);
Chris@0 183
Chris@0 184 if ($suffix === '' && $allowPatch === true) {
Chris@0 185 if (file_exists($diffFile) === false) {
Chris@0 186 // Nothing to fix.
Chris@0 187 if ($numErrors === 0) {
Chris@0 188 // And no errors reported.
Chris@0 189 $exit = 0;
Chris@0 190 } else {
Chris@0 191 // Errors we can't fix.
Chris@0 192 $exit = 2;
Chris@0 193 }
Chris@0 194 } else {
Chris@0 195 if (filesize($diffFile) < 10) {
Chris@0 196 // Empty or bad diff file.
Chris@0 197 if ($numErrors === 0) {
Chris@0 198 // And no errors reported.
Chris@0 199 $exit = 0;
Chris@0 200 } else {
Chris@0 201 // Errors we can't fix.
Chris@0 202 $exit = 2;
Chris@0 203 }
Chris@0 204 } else {
Chris@0 205 $cmd = "patch -p0 -ui \"$diffFile\"";
Chris@0 206 $output = array();
Chris@0 207 $retVal = null;
Chris@0 208 exec($cmd, $output, $retVal);
Chris@0 209
Chris@0 210 if ($retVal === 0) {
Chris@0 211 // Everything went well.
Chris@0 212 $filesPatched = count($output);
Chris@0 213 echo "Patched $filesPatched file";
Chris@0 214 if ($filesPatched > 1) {
Chris@0 215 echo 's';
Chris@0 216 }
Chris@0 217
Chris@0 218 echo PHP_EOL;
Chris@0 219 $exit = 1;
Chris@0 220 } else {
Chris@0 221 print_r($output);
Chris@0 222 echo "Returned: $retVal".PHP_EOL;
Chris@0 223 $exit = 3;
Chris@0 224 }
Chris@0 225 }//end if
Chris@0 226
Chris@0 227 unlink($diffFile);
Chris@0 228 }//end if
Chris@0 229 } else {
Chris@0 230 // File are being patched manually, so we can't tell
Chris@0 231 // how many errors were fixed.
Chris@0 232 $exit = 1;
Chris@0 233 }//end if
Chris@0 234
Chris@0 235 if ($exit === 0) {
Chris@0 236 echo 'No fixable errors were found'.PHP_EOL;
Chris@0 237 } else if ($exit === 2) {
Chris@0 238 echo 'PHPCBF could not fix all the errors found'.PHP_EOL;
Chris@0 239 }
Chris@0 240
Chris@0 241 PHP_CodeSniffer_Reporting::printRunTime();
Chris@0 242 exit($exit);
Chris@0 243
Chris@0 244 }//end runphpcbf()
Chris@0 245
Chris@0 246
Chris@0 247 /**
Chris@0 248 * Exits if the minimum requirements of PHP_CodSniffer are not met.
Chris@0 249 *
Chris@0 250 * @return array
Chris@0 251 */
Chris@0 252 public function checkRequirements()
Chris@0 253 {
Chris@0 254 // Check the PHP version.
Chris@0 255 if (PHP_VERSION_ID < 50102) {
Chris@0 256 echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL;
Chris@0 257 exit(2);
Chris@0 258 }
Chris@0 259
Chris@0 260 if (extension_loaded('tokenizer') === false) {
Chris@0 261 echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL;
Chris@0 262 exit(2);
Chris@0 263 }
Chris@0 264
Chris@0 265 }//end checkRequirements()
Chris@0 266
Chris@0 267
Chris@0 268 /**
Chris@0 269 * Get a list of default values for all possible command line arguments.
Chris@0 270 *
Chris@0 271 * @return array
Chris@0 272 */
Chris@0 273 public function getDefaults()
Chris@0 274 {
Chris@0 275 if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
Chris@0 276 return array();
Chris@0 277 }
Chris@0 278
Chris@0 279 // The default values for config settings.
Chris@0 280 $defaults['files'] = array();
Chris@0 281 $defaults['standard'] = null;
Chris@0 282 $defaults['verbosity'] = 0;
Chris@0 283 $defaults['interactive'] = false;
Chris@0 284 $defaults['colors'] = false;
Chris@0 285 $defaults['explain'] = false;
Chris@0 286 $defaults['local'] = false;
Chris@0 287 $defaults['showSources'] = false;
Chris@0 288 $defaults['extensions'] = array();
Chris@0 289 $defaults['sniffs'] = array();
Chris@0 290 $defaults['exclude'] = array();
Chris@0 291 $defaults['ignored'] = array();
Chris@0 292 $defaults['reportFile'] = null;
Chris@0 293 $defaults['generator'] = '';
Chris@0 294 $defaults['reports'] = array();
Chris@0 295 $defaults['bootstrap'] = array();
Chris@0 296 $defaults['errorSeverity'] = null;
Chris@0 297 $defaults['warningSeverity'] = null;
Chris@0 298 $defaults['stdin'] = null;
Chris@0 299 $defaults['stdinPath'] = '';
Chris@0 300
Chris@0 301 $reportFormat = PHP_CodeSniffer::getConfigData('report_format');
Chris@0 302 if ($reportFormat !== null) {
Chris@0 303 $defaults['reports'][$reportFormat] = null;
Chris@0 304 }
Chris@0 305
Chris@0 306 $tabWidth = PHP_CodeSniffer::getConfigData('tab_width');
Chris@0 307 if ($tabWidth === null) {
Chris@0 308 $defaults['tabWidth'] = 0;
Chris@0 309 } else {
Chris@0 310 $defaults['tabWidth'] = (int) $tabWidth;
Chris@0 311 }
Chris@0 312
Chris@0 313 $encoding = PHP_CodeSniffer::getConfigData('encoding');
Chris@0 314 if ($encoding === null) {
Chris@0 315 $defaults['encoding'] = 'iso-8859-1';
Chris@0 316 } else {
Chris@0 317 $defaults['encoding'] = strtolower($encoding);
Chris@0 318 }
Chris@0 319
Chris@0 320 $severity = PHP_CodeSniffer::getConfigData('severity');
Chris@0 321 if ($severity !== null) {
Chris@0 322 $defaults['errorSeverity'] = (int) $severity;
Chris@0 323 $defaults['warningSeverity'] = (int) $severity;
Chris@0 324 }
Chris@0 325
Chris@0 326 $severity = PHP_CodeSniffer::getConfigData('error_severity');
Chris@0 327 if ($severity !== null) {
Chris@0 328 $defaults['errorSeverity'] = (int) $severity;
Chris@0 329 }
Chris@0 330
Chris@0 331 $severity = PHP_CodeSniffer::getConfigData('warning_severity');
Chris@0 332 if ($severity !== null) {
Chris@0 333 $defaults['warningSeverity'] = (int) $severity;
Chris@0 334 }
Chris@0 335
Chris@0 336 $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings');
Chris@0 337 if ($showWarnings !== null) {
Chris@0 338 $showWarnings = (bool) $showWarnings;
Chris@0 339 if ($showWarnings === false) {
Chris@0 340 $defaults['warningSeverity'] = 0;
Chris@0 341 }
Chris@0 342 }
Chris@0 343
Chris@0 344 $reportWidth = PHP_CodeSniffer::getConfigData('report_width');
Chris@0 345 if ($reportWidth !== null) {
Chris@0 346 $defaults['reportWidth'] = $this->_validateReportWidth($reportWidth);
Chris@0 347 } else {
Chris@0 348 // Use function defaults.
Chris@0 349 $defaults['reportWidth'] = null;
Chris@0 350 }
Chris@0 351
Chris@0 352 $showProgress = PHP_CodeSniffer::getConfigData('show_progress');
Chris@0 353 if ($showProgress === null) {
Chris@0 354 $defaults['showProgress'] = false;
Chris@0 355 } else {
Chris@0 356 $defaults['showProgress'] = (bool) $showProgress;
Chris@0 357 }
Chris@0 358
Chris@0 359 $quiet = PHP_CodeSniffer::getConfigData('quiet');
Chris@0 360 if ($quiet === null) {
Chris@0 361 $defaults['quiet'] = false;
Chris@0 362 } else {
Chris@0 363 $defaults['quiet'] = (bool) $quiet;
Chris@0 364 }
Chris@0 365
Chris@0 366 $colors = PHP_CodeSniffer::getConfigData('colors');
Chris@0 367 if ($colors === null) {
Chris@0 368 $defaults['colors'] = false;
Chris@0 369 } else {
Chris@0 370 $defaults['colors'] = (bool) $colors;
Chris@0 371 }
Chris@0 372
Chris@0 373 if (PHP_CodeSniffer::isPharFile(dirname(dirname(__FILE__))) === true) {
Chris@0 374 // If this is a phar file, check for the standard in the config.
Chris@0 375 $standard = PHP_CodeSniffer::getConfigData('standard');
Chris@0 376 if ($standard !== null) {
Chris@0 377 $defaults['standard'] = $standard;
Chris@0 378 }
Chris@0 379 }
Chris@0 380
Chris@0 381 return $defaults;
Chris@0 382
Chris@0 383 }//end getDefaults()
Chris@0 384
Chris@0 385
Chris@0 386 /**
Chris@0 387 * Gets the processed command line values.
Chris@0 388 *
Chris@0 389 * If the values have not yet been set, the values will be sourced
Chris@0 390 * from the command line arguments.
Chris@0 391 *
Chris@0 392 * @return array
Chris@0 393 */
Chris@0 394 public function getCommandLineValues()
Chris@0 395 {
Chris@0 396 if (empty($this->values) === false) {
Chris@0 397 return $this->values;
Chris@0 398 }
Chris@0 399
Chris@0 400 $args = $_SERVER['argv'];
Chris@0 401 array_shift($args);
Chris@0 402
Chris@0 403 $this->setCommandLineValues($args);
Chris@0 404
Chris@0 405 // Check for content on STDIN.
Chris@0 406 $handle = fopen('php://stdin', 'r');
Chris@0 407 if (stream_set_blocking($handle, false) === true) {
Chris@0 408 $fileContents = '';
Chris@0 409 while (($line = fgets($handle)) !== false) {
Chris@0 410 $fileContents .= $line;
Chris@0 411 usleep(10);
Chris@0 412 }
Chris@0 413
Chris@0 414 stream_set_blocking($handle, true);
Chris@0 415 fclose($handle);
Chris@0 416 if (trim($fileContents) !== '') {
Chris@0 417 $this->values['stdin'] = $fileContents;
Chris@0 418 }
Chris@0 419 }
Chris@0 420
Chris@0 421 return $this->values;
Chris@0 422
Chris@0 423 }//end getCommandLineValues()
Chris@0 424
Chris@0 425
Chris@0 426 /**
Chris@0 427 * Set the command line values.
Chris@0 428 *
Chris@0 429 * @param array $args An array of command line arguments to process.
Chris@0 430 *
Chris@0 431 * @return void
Chris@0 432 */
Chris@0 433 public function setCommandLineValues($args)
Chris@0 434 {
Chris@0 435 if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
Chris@0 436 $this->values = array(
Chris@0 437 'stdin' => null,
Chris@0 438 'quiet' => true,
Chris@0 439 );
Chris@0 440 } else if (empty($this->values) === true) {
Chris@0 441 $this->values = $this->getDefaults();
Chris@0 442 }
Chris@0 443
Chris@0 444 $this->_cliArgs = $args;
Chris@0 445 $numArgs = count($args);
Chris@0 446
Chris@0 447 for ($i = 0; $i < $numArgs; $i++) {
Chris@0 448 $arg = $this->_cliArgs[$i];
Chris@0 449 if ($arg === '') {
Chris@0 450 continue;
Chris@0 451 }
Chris@0 452
Chris@0 453 if ($arg{0} === '-') {
Chris@0 454 if ($arg === '-' || $arg === '--') {
Chris@0 455 // Empty argument, ignore it.
Chris@0 456 continue;
Chris@0 457 }
Chris@0 458
Chris@0 459 if ($arg{1} === '-') {
Chris@0 460 $this->processLongArgument(substr($arg, 2), $i);
Chris@0 461 } else {
Chris@0 462 $switches = str_split($arg);
Chris@0 463 foreach ($switches as $switch) {
Chris@0 464 if ($switch === '-') {
Chris@0 465 continue;
Chris@0 466 }
Chris@0 467
Chris@0 468 $this->processShortArgument($switch, $i);
Chris@0 469 }
Chris@0 470 }
Chris@0 471 } else {
Chris@0 472 $this->processUnknownArgument($arg, $i);
Chris@0 473 }//end if
Chris@0 474 }//end for
Chris@0 475
Chris@0 476 }//end setCommandLineValues()
Chris@0 477
Chris@0 478
Chris@0 479 /**
Chris@0 480 * Processes a short (-e) command line argument.
Chris@0 481 *
Chris@0 482 * @param string $arg The command line argument.
Chris@0 483 * @param int $pos The position of the argument on the command line.
Chris@0 484 *
Chris@0 485 * @return void
Chris@0 486 */
Chris@0 487 public function processShortArgument($arg, $pos)
Chris@0 488 {
Chris@0 489 switch ($arg) {
Chris@0 490 case 'h':
Chris@0 491 case '?':
Chris@0 492 $this->printUsage();
Chris@0 493 exit(0);
Chris@0 494 case 'i' :
Chris@0 495 $this->printInstalledStandards();
Chris@0 496 exit(0);
Chris@0 497 case 'v' :
Chris@0 498 if ($this->values['quiet'] === true) {
Chris@0 499 // Ignore when quiet mode is enabled.
Chris@0 500 break;
Chris@0 501 }
Chris@0 502
Chris@0 503 if (isset($this->values['verbosity']) === false) {
Chris@0 504 $this->values['verbosity'] = 1;
Chris@0 505 } else {
Chris@0 506 $this->values['verbosity']++;
Chris@0 507 }
Chris@0 508 break;
Chris@0 509 case 'l' :
Chris@0 510 $this->values['local'] = true;
Chris@0 511 break;
Chris@0 512 case 's' :
Chris@0 513 $this->values['showSources'] = true;
Chris@0 514 break;
Chris@0 515 case 'a' :
Chris@0 516 $this->values['interactive'] = true;
Chris@0 517 break;
Chris@0 518 case 'e':
Chris@0 519 $this->values['explain'] = true;
Chris@0 520 break;
Chris@0 521 case 'p' :
Chris@0 522 if ($this->values['quiet'] === true) {
Chris@0 523 // Ignore when quiet mode is enabled.
Chris@0 524 break;
Chris@0 525 }
Chris@0 526
Chris@0 527 $this->values['showProgress'] = true;
Chris@0 528 break;
Chris@0 529 case 'q' :
Chris@0 530 // Quiet mode disables a few other settings as well.
Chris@0 531 $this->values['quiet'] = true;
Chris@0 532 $this->values['showProgress'] = false;
Chris@0 533 $this->values['verbosity'] = 0;
Chris@0 534 break;
Chris@0 535 case 'd' :
Chris@0 536 $ini = explode('=', $this->_cliArgs[($pos + 1)]);
Chris@0 537 $this->_cliArgs[($pos + 1)] = '';
Chris@0 538 if (isset($ini[1]) === true) {
Chris@0 539 ini_set($ini[0], $ini[1]);
Chris@0 540 } else {
Chris@0 541 ini_set($ini[0], true);
Chris@0 542 }
Chris@0 543 break;
Chris@0 544 case 'n' :
Chris@0 545 $this->values['warningSeverity'] = 0;
Chris@0 546 break;
Chris@0 547 case 'w' :
Chris@0 548 $this->values['warningSeverity'] = null;
Chris@0 549 break;
Chris@0 550 default:
Chris@0 551 if ($this->dieOnUnknownArg === false) {
Chris@0 552 $this->values[$arg] = $arg;
Chris@0 553 } else {
Chris@0 554 $this->processUnknownArgument('-'.$arg, $pos);
Chris@0 555 }
Chris@0 556 }//end switch
Chris@0 557
Chris@0 558 }//end processShortArgument()
Chris@0 559
Chris@0 560
Chris@0 561 /**
Chris@0 562 * Processes a long (--example) command line argument.
Chris@0 563 *
Chris@0 564 * @param string $arg The command line argument.
Chris@0 565 * @param int $pos The position of the argument on the command line.
Chris@0 566 *
Chris@0 567 * @return void
Chris@0 568 */
Chris@0 569 public function processLongArgument($arg, $pos)
Chris@0 570 {
Chris@0 571 switch ($arg) {
Chris@0 572 case 'help':
Chris@0 573 $this->printUsage();
Chris@0 574 exit(0);
Chris@0 575 case 'version':
Chris@0 576 echo 'PHP_CodeSniffer version '.PHP_CodeSniffer::VERSION.' ('.PHP_CodeSniffer::STABILITY.') ';
Chris@0 577 echo 'by Squiz (http://www.squiz.net)'.PHP_EOL;
Chris@0 578 exit(0);
Chris@0 579 case 'colors':
Chris@0 580 $this->values['colors'] = true;
Chris@0 581 break;
Chris@0 582 case 'no-colors':
Chris@0 583 $this->values['colors'] = false;
Chris@0 584 break;
Chris@0 585 case 'config-set':
Chris@0 586 if (isset($this->_cliArgs[($pos + 1)]) === false
Chris@0 587 || isset($this->_cliArgs[($pos + 2)]) === false
Chris@0 588 ) {
Chris@0 589 echo 'ERROR: Setting a config option requires a name and value'.PHP_EOL.PHP_EOL;
Chris@0 590 $this->printUsage();
Chris@0 591 exit(0);
Chris@0 592 }
Chris@0 593
Chris@0 594 $key = $this->_cliArgs[($pos + 1)];
Chris@0 595 $value = $this->_cliArgs[($pos + 2)];
Chris@0 596 $current = PHP_CodeSniffer::getConfigData($key);
Chris@0 597
Chris@0 598 try {
Chris@0 599 PHP_CodeSniffer::setConfigData($key, $value);
Chris@0 600 } catch (Exception $e) {
Chris@0 601 echo $e->getMessage().PHP_EOL;
Chris@0 602 exit(2);
Chris@0 603 }
Chris@0 604
Chris@0 605 if ($current === null) {
Chris@0 606 echo "Config value \"$key\" added successfully".PHP_EOL;
Chris@0 607 } else {
Chris@0 608 echo "Config value \"$key\" updated successfully; old value was \"$current\"".PHP_EOL;
Chris@0 609 }
Chris@0 610 exit(0);
Chris@0 611 case 'config-delete':
Chris@0 612 if (isset($this->_cliArgs[($pos + 1)]) === false) {
Chris@0 613 echo 'ERROR: Deleting a config option requires the name of the option'.PHP_EOL.PHP_EOL;
Chris@0 614 $this->printUsage();
Chris@0 615 exit(0);
Chris@0 616 }
Chris@0 617
Chris@0 618 $key = $this->_cliArgs[($pos + 1)];
Chris@0 619 $current = PHP_CodeSniffer::getConfigData($key);
Chris@0 620 if ($current === null) {
Chris@0 621 echo "Config value \"$key\" has not been set".PHP_EOL;
Chris@0 622 } else {
Chris@0 623 try {
Chris@0 624 PHP_CodeSniffer::setConfigData($key, null);
Chris@0 625 } catch (Exception $e) {
Chris@0 626 echo $e->getMessage().PHP_EOL;
Chris@0 627 exit(2);
Chris@0 628 }
Chris@0 629
Chris@0 630 echo "Config value \"$key\" removed successfully; old value was \"$current\"".PHP_EOL;
Chris@0 631 }
Chris@0 632 exit(0);
Chris@0 633 case 'config-show':
Chris@0 634 $data = PHP_CodeSniffer::getAllConfigData();
Chris@0 635 $this->printConfigData($data);
Chris@0 636 exit(0);
Chris@0 637 case 'runtime-set':
Chris@0 638 if (isset($this->_cliArgs[($pos + 1)]) === false
Chris@0 639 || isset($this->_cliArgs[($pos + 2)]) === false
Chris@0 640 ) {
Chris@0 641 echo 'ERROR: Setting a runtime config option requires a name and value'.PHP_EOL.PHP_EOL;
Chris@0 642 $this->printUsage();
Chris@0 643 exit(0);
Chris@0 644 }
Chris@0 645
Chris@0 646 $key = $this->_cliArgs[($pos + 1)];
Chris@0 647 $value = $this->_cliArgs[($pos + 2)];
Chris@0 648 $this->_cliArgs[($pos + 1)] = '';
Chris@0 649 $this->_cliArgs[($pos + 2)] = '';
Chris@0 650 PHP_CodeSniffer::setConfigData($key, $value, true);
Chris@0 651 break;
Chris@0 652 default:
Chris@0 653 if (substr($arg, 0, 7) === 'sniffs=') {
Chris@0 654 $sniffs = explode(',', substr($arg, 7));
Chris@0 655 foreach ($sniffs as $sniff) {
Chris@0 656 if (substr_count($sniff, '.') !== 2) {
Chris@0 657 echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
Chris@0 658 $this->printUsage();
Chris@0 659 exit(2);
Chris@0 660 }
Chris@0 661 }
Chris@0 662
Chris@0 663 $this->values['sniffs'] = $sniffs;
Chris@0 664 } else if (substr($arg, 0, 8) === 'exclude=') {
Chris@0 665 $sniffs = explode(',', substr($arg, 8));
Chris@0 666 foreach ($sniffs as $sniff) {
Chris@0 667 if (substr_count($sniff, '.') !== 2) {
Chris@0 668 echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
Chris@0 669 $this->printUsage();
Chris@0 670 exit(2);
Chris@0 671 }
Chris@0 672 }
Chris@0 673
Chris@0 674 $this->values['exclude'] = $sniffs;
Chris@0 675 } else if (substr($arg, 0, 10) === 'bootstrap=') {
Chris@0 676 $files = explode(',', substr($arg, 10));
Chris@0 677 foreach ($files as $file) {
Chris@0 678 $path = PHP_CodeSniffer::realpath($file);
Chris@0 679 if ($path === false) {
Chris@0 680 echo 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
Chris@0 681 $this->printUsage();
Chris@0 682 exit(2);
Chris@0 683 }
Chris@0 684
Chris@0 685 $this->values['bootstrap'][] = $path;
Chris@0 686 }
Chris@0 687 } else if (substr($arg, 0, 10) === 'file-list=') {
Chris@0 688 $fileList = substr($arg, 10);
Chris@0 689 $path = PHP_CodeSniffer::realpath($fileList);
Chris@0 690 if ($path === false) {
Chris@0 691 echo 'ERROR: The specified file list "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
Chris@0 692 $this->printUsage();
Chris@0 693 exit(2);
Chris@0 694 }
Chris@0 695
Chris@0 696 $files = file($path);
Chris@0 697 foreach ($files as $inputFile) {
Chris@0 698 $inputFile = trim($inputFile);
Chris@0 699
Chris@0 700 // Skip empty lines.
Chris@0 701 if ($inputFile === '') {
Chris@0 702 continue;
Chris@0 703 }
Chris@0 704
Chris@0 705 $realFile = PHP_CodeSniffer::realpath($inputFile);
Chris@0 706 if ($realFile === false) {
Chris@0 707 echo 'ERROR: The specified file "'.$inputFile.'" does not exist'.PHP_EOL.PHP_EOL;
Chris@0 708 $this->printUsage();
Chris@0 709 exit(2);
Chris@0 710 }
Chris@0 711
Chris@0 712 $this->values['files'][] = $realFile;
Chris@0 713 }
Chris@0 714 } else if (substr($arg, 0, 11) === 'stdin-path=') {
Chris@0 715 $this->values['stdinPath'] = PHP_CodeSniffer::realpath(substr($arg, 11));
Chris@0 716
Chris@0 717 // It may not exist and return false instead, so just use whatever they gave us.
Chris@0 718 if ($this->values['stdinPath'] === false) {
Chris@0 719 $this->values['stdinPath'] = trim(substr($arg, 11));
Chris@0 720 }
Chris@0 721 } else if (substr($arg, 0, 12) === 'report-file=') {
Chris@0 722 $this->values['reportFile'] = PHP_CodeSniffer::realpath(substr($arg, 12));
Chris@0 723
Chris@0 724 // It may not exist and return false instead.
Chris@0 725 if ($this->values['reportFile'] === false) {
Chris@0 726 $this->values['reportFile'] = substr($arg, 12);
Chris@0 727
Chris@0 728 $dir = dirname($this->values['reportFile']);
Chris@0 729 if (is_dir($dir) === false) {
Chris@0 730 echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
Chris@0 731 $this->printUsage();
Chris@0 732 exit(2);
Chris@0 733 }
Chris@0 734
Chris@0 735 if ($dir === '.') {
Chris@0 736 // Passed report file is a file in the current directory.
Chris@0 737 $this->values['reportFile'] = getcwd().'/'.basename($this->values['reportFile']);
Chris@0 738 } else {
Chris@0 739 if ($dir{0} === '/') {
Chris@0 740 // An absolute path.
Chris@0 741 $dir = PHP_CodeSniffer::realpath($dir);
Chris@0 742 } else {
Chris@0 743 $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir);
Chris@0 744 }
Chris@0 745
Chris@0 746 if ($dir !== false) {
Chris@0 747 // Report file path is relative.
Chris@0 748 $this->values['reportFile'] = $dir.'/'.basename($this->values['reportFile']);
Chris@0 749 }
Chris@0 750 }
Chris@0 751 }//end if
Chris@0 752
Chris@0 753 if (is_dir($this->values['reportFile']) === true) {
Chris@0 754 echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" is a directory'.PHP_EOL.PHP_EOL;
Chris@0 755 $this->printUsage();
Chris@0 756 exit(2);
Chris@0 757 }
Chris@0 758 } else if (substr($arg, 0, 13) === 'report-width=') {
Chris@0 759 $this->values['reportWidth'] = $this->_validateReportWidth(substr($arg, 13));
Chris@0 760 } else if (substr($arg, 0, 7) === 'report='
Chris@0 761 || substr($arg, 0, 7) === 'report-'
Chris@0 762 ) {
Chris@0 763 if ($arg[6] === '-') {
Chris@0 764 // This is a report with file output.
Chris@0 765 $split = strpos($arg, '=');
Chris@0 766 if ($split === false) {
Chris@0 767 $report = substr($arg, 7);
Chris@0 768 $output = null;
Chris@0 769 } else {
Chris@0 770 $report = substr($arg, 7, ($split - 7));
Chris@0 771 $output = substr($arg, ($split + 1));
Chris@0 772 if ($output === false) {
Chris@0 773 $output = null;
Chris@0 774 } else {
Chris@0 775 $dir = dirname($output);
Chris@0 776 if ($dir === '.') {
Chris@0 777 // Passed report file is a filename in the current directory.
Chris@0 778 $output = getcwd().'/'.basename($output);
Chris@0 779 } else {
Chris@0 780 if ($dir{0} === '/') {
Chris@0 781 // An absolute path.
Chris@0 782 $dir = PHP_CodeSniffer::realpath($dir);
Chris@0 783 } else {
Chris@0 784 $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir);
Chris@0 785 }
Chris@0 786
Chris@0 787 if ($dir !== false) {
Chris@0 788 // Report file path is relative.
Chris@0 789 $output = $dir.'/'.basename($output);
Chris@0 790 }
Chris@0 791 }
Chris@0 792 }//end if
Chris@0 793 }//end if
Chris@0 794 } else {
Chris@0 795 // This is a single report.
Chris@0 796 $report = substr($arg, 7);
Chris@0 797 $output = null;
Chris@0 798 }//end if
Chris@0 799
Chris@0 800 $this->values['reports'][$report] = $output;
Chris@0 801 } else if (substr($arg, 0, 9) === 'standard=') {
Chris@0 802 $standards = trim(substr($arg, 9));
Chris@0 803 if ($standards !== '') {
Chris@0 804 $this->values['standard'] = explode(',', $standards);
Chris@0 805 }
Chris@0 806 } else if (substr($arg, 0, 11) === 'extensions=') {
Chris@0 807 if (isset($this->values['extensions']) === false) {
Chris@0 808 $this->values['extensions'] = array();
Chris@0 809 }
Chris@0 810
Chris@0 811 $this->values['extensions'] = array_merge($this->values['extensions'], explode(',', substr($arg, 11)));
Chris@0 812 } else if (substr($arg, 0, 9) === 'severity=') {
Chris@0 813 $this->values['errorSeverity'] = (int) substr($arg, 9);
Chris@0 814 $this->values['warningSeverity'] = $this->values['errorSeverity'];
Chris@0 815 } else if (substr($arg, 0, 15) === 'error-severity=') {
Chris@0 816 $this->values['errorSeverity'] = (int) substr($arg, 15);
Chris@0 817 } else if (substr($arg, 0, 17) === 'warning-severity=') {
Chris@0 818 $this->values['warningSeverity'] = (int) substr($arg, 17);
Chris@0 819 } else if (substr($arg, 0, 7) === 'ignore=') {
Chris@0 820 // Split the ignore string on commas, unless the comma is escaped
Chris@0 821 // using 1 or 3 slashes (\, or \\\,).
Chris@0 822 $ignored = preg_split(
Chris@0 823 '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/',
Chris@0 824 substr($arg, 7)
Chris@0 825 );
Chris@0 826 foreach ($ignored as $pattern) {
Chris@0 827 $pattern = trim($pattern);
Chris@0 828 if ($pattern === '') {
Chris@0 829 continue;
Chris@0 830 }
Chris@0 831
Chris@0 832 $this->values['ignored'][$pattern] = 'absolute';
Chris@0 833 }
Chris@0 834 } else if (substr($arg, 0, 10) === 'generator=') {
Chris@0 835 $this->values['generator'] = substr($arg, 10);
Chris@0 836 } else if (substr($arg, 0, 9) === 'encoding=') {
Chris@0 837 $this->values['encoding'] = strtolower(substr($arg, 9));
Chris@0 838 } else if (substr($arg, 0, 10) === 'tab-width=') {
Chris@0 839 $this->values['tabWidth'] = (int) substr($arg, 10);
Chris@0 840 } else {
Chris@0 841 if ($this->dieOnUnknownArg === false) {
Chris@0 842 $eqPos = strpos($arg, '=');
Chris@0 843 if ($eqPos === false) {
Chris@0 844 $this->values[$arg] = $arg;
Chris@0 845 } else {
Chris@0 846 $value = substr($arg, ($eqPos + 1));
Chris@0 847 $arg = substr($arg, 0, $eqPos);
Chris@0 848 $this->values[$arg] = $value;
Chris@0 849 }
Chris@0 850 } else {
Chris@0 851 $this->processUnknownArgument('--'.$arg, $pos);
Chris@0 852 }
Chris@0 853 }//end if
Chris@0 854
Chris@0 855 break;
Chris@0 856 }//end switch
Chris@0 857
Chris@0 858 }//end processLongArgument()
Chris@0 859
Chris@0 860
Chris@0 861 /**
Chris@0 862 * Processes an unknown command line argument.
Chris@0 863 *
Chris@0 864 * Assumes all unknown arguments are files and folders to check.
Chris@0 865 *
Chris@0 866 * @param string $arg The command line argument.
Chris@0 867 * @param int $pos The position of the argument on the command line.
Chris@0 868 *
Chris@0 869 * @return void
Chris@0 870 */
Chris@0 871 public function processUnknownArgument($arg, $pos)
Chris@0 872 {
Chris@0 873 // We don't know about any additional switches; just files.
Chris@0 874 if ($arg{0} === '-') {
Chris@0 875 if ($this->dieOnUnknownArg === false) {
Chris@0 876 return;
Chris@0 877 }
Chris@0 878
Chris@0 879 echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL;
Chris@0 880 $this->printUsage();
Chris@0 881 exit(2);
Chris@0 882 }
Chris@0 883
Chris@0 884 $file = PHP_CodeSniffer::realpath($arg);
Chris@0 885 if (file_exists($file) === false) {
Chris@0 886 if ($this->dieOnUnknownArg === false) {
Chris@0 887 return;
Chris@0 888 }
Chris@0 889
Chris@0 890 echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL;
Chris@0 891 $this->printUsage();
Chris@0 892 exit(2);
Chris@0 893 } else {
Chris@0 894 $this->values['files'][] = $file;
Chris@0 895 }
Chris@0 896
Chris@0 897 }//end processUnknownArgument()
Chris@0 898
Chris@0 899
Chris@0 900 /**
Chris@0 901 * Runs PHP_CodeSniffer over files and directories.
Chris@0 902 *
Chris@0 903 * @param array $values An array of values determined from CLI args.
Chris@0 904 *
Chris@0 905 * @return int The number of error and warning messages shown.
Chris@0 906 * @see getCommandLineValues()
Chris@0 907 */
Chris@0 908 public function process($values=array())
Chris@0 909 {
Chris@0 910 if (empty($values) === true) {
Chris@0 911 $values = $this->getCommandLineValues();
Chris@0 912 } else {
Chris@0 913 $values = array_merge($this->getDefaults(), $values);
Chris@0 914 $this->values = $values;
Chris@0 915 }
Chris@0 916
Chris@0 917 if ($values['generator'] !== '') {
Chris@0 918 $phpcs = new PHP_CodeSniffer($values['verbosity']);
Chris@0 919 if ($values['standard'] === null) {
Chris@0 920 $values['standard'] = $this->validateStandard(null);
Chris@0 921 }
Chris@0 922
Chris@0 923 foreach ($values['standard'] as $standard) {
Chris@0 924 $phpcs->generateDocs(
Chris@0 925 $standard,
Chris@0 926 $values['sniffs'],
Chris@0 927 $values['generator']
Chris@0 928 );
Chris@0 929 }
Chris@0 930
Chris@0 931 exit(0);
Chris@0 932 }
Chris@0 933
Chris@0 934 // If no standard is supplied, get the default.
Chris@0 935 $values['standard'] = $this->validateStandard($values['standard']);
Chris@0 936 foreach ($values['standard'] as $standard) {
Chris@0 937 if (PHP_CodeSniffer::isInstalledStandard($standard) === false) {
Chris@0 938 // They didn't select a valid coding standard, so help them
Chris@0 939 // out by letting them know which standards are installed.
Chris@0 940 echo 'ERROR: the "'.$standard.'" coding standard is not installed. ';
Chris@0 941 $this->printInstalledStandards();
Chris@0 942 exit(2);
Chris@0 943 }
Chris@0 944 }
Chris@0 945
Chris@0 946 if ($values['explain'] === true) {
Chris@0 947 foreach ($values['standard'] as $standard) {
Chris@0 948 $this->explainStandard($standard);
Chris@0 949 }
Chris@0 950
Chris@0 951 exit(0);
Chris@0 952 }
Chris@0 953
Chris@0 954 $phpcs = new PHP_CodeSniffer($values['verbosity'], null, null, null);
Chris@0 955 $phpcs->setCli($this);
Chris@0 956 $phpcs->initStandard($values['standard'], $values['sniffs'], $values['exclude']);
Chris@0 957 $values = $this->values;
Chris@0 958
Chris@0 959 $phpcs->setTabWidth($values['tabWidth']);
Chris@0 960 $phpcs->setEncoding($values['encoding']);
Chris@0 961 $phpcs->setInteractive($values['interactive']);
Chris@0 962
Chris@0 963 // Set file extensions if they were specified. Otherwise,
Chris@0 964 // let PHP_CodeSniffer decide on the defaults.
Chris@0 965 if (empty($values['extensions']) === false) {
Chris@0 966 $phpcs->setAllowedFileExtensions($values['extensions']);
Chris@0 967 }
Chris@0 968
Chris@0 969 // Set ignore patterns if they were specified.
Chris@0 970 if (empty($values['ignored']) === false) {
Chris@0 971 $ignorePatterns = array_merge($phpcs->getIgnorePatterns(), $values['ignored']);
Chris@0 972 $phpcs->setIgnorePatterns($ignorePatterns);
Chris@0 973 }
Chris@0 974
Chris@0 975 // Set some convenience member vars.
Chris@0 976 if ($values['errorSeverity'] === null) {
Chris@0 977 $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV;
Chris@0 978 } else {
Chris@0 979 $this->errorSeverity = $values['errorSeverity'];
Chris@0 980 }
Chris@0 981
Chris@0 982 if ($values['warningSeverity'] === null) {
Chris@0 983 $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV;
Chris@0 984 } else {
Chris@0 985 $this->warningSeverity = $values['warningSeverity'];
Chris@0 986 }
Chris@0 987
Chris@0 988 if (empty($values['reports']) === true) {
Chris@0 989 $values['reports']['full'] = $values['reportFile'];
Chris@0 990 $this->values['reports'] = $values['reports'];
Chris@0 991 }
Chris@0 992
Chris@0 993 // Include bootstrap files.
Chris@0 994 foreach ($values['bootstrap'] as $bootstrap) {
Chris@0 995 include $bootstrap;
Chris@0 996 }
Chris@0 997
Chris@0 998 $phpcs->processFiles($values['files'], $values['local']);
Chris@0 999
Chris@0 1000 if (empty($values['files']) === true || $values['stdin'] !== null) {
Chris@0 1001 $fileContents = $values['stdin'];
Chris@0 1002 if ($fileContents === null) {
Chris@0 1003 // Check if they are passing in the file contents.
Chris@0 1004 $handle = fopen('php://stdin', 'r');
Chris@0 1005 stream_set_blocking($handle, true);
Chris@0 1006 $fileContents = stream_get_contents($handle);
Chris@0 1007 fclose($handle);
Chris@0 1008 }
Chris@0 1009
Chris@0 1010 if ($fileContents === '') {
Chris@0 1011 // No files and no content passed in.
Chris@0 1012 echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL;
Chris@0 1013 $this->printUsage();
Chris@0 1014 exit(2);
Chris@0 1015 } else {
Chris@0 1016 $this->values['stdin'] = $fileContents;
Chris@0 1017 $phpcs->processFile('STDIN', $fileContents);
Chris@0 1018 }
Chris@0 1019 }
Chris@0 1020
Chris@0 1021 // Interactive runs don't require a final report and it doesn't really
Chris@0 1022 // matter what the retun value is because we know it isn't being read
Chris@0 1023 // by a script.
Chris@0 1024 if ($values['interactive'] === true) {
Chris@0 1025 return 0;
Chris@0 1026 }
Chris@0 1027
Chris@0 1028 return $this->printErrorReport(
Chris@0 1029 $phpcs,
Chris@0 1030 $values['reports'],
Chris@0 1031 $values['showSources'],
Chris@0 1032 $values['reportFile'],
Chris@0 1033 $values['reportWidth']
Chris@0 1034 );
Chris@0 1035
Chris@0 1036 }//end process()
Chris@0 1037
Chris@0 1038
Chris@0 1039 /**
Chris@0 1040 * Prints the error report for the run.
Chris@0 1041 *
Chris@0 1042 * Note that this function may actually print multiple reports
Chris@0 1043 * as the user may have specified a number of output formats.
Chris@0 1044 *
Chris@0 1045 * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing
Chris@0 1046 * the errors.
Chris@0 1047 * @param array $reports A list of reports to print.
Chris@0 1048 * @param bool $showSources TRUE if report should show error sources
Chris@0 1049 * (not used by all reports).
Chris@0 1050 * @param string $reportFile A default file to log report output to.
Chris@0 1051 * @param int $reportWidth How wide the screen reports should be.
Chris@0 1052 *
Chris@0 1053 * @return int The number of error and warning messages shown.
Chris@0 1054 */
Chris@0 1055 public function printErrorReport(
Chris@0 1056 PHP_CodeSniffer $phpcs,
Chris@0 1057 $reports,
Chris@0 1058 $showSources,
Chris@0 1059 $reportFile,
Chris@0 1060 $reportWidth
Chris@0 1061 ) {
Chris@0 1062 if (empty($reports) === true) {
Chris@0 1063 $reports['full'] = $reportFile;
Chris@0 1064 }
Chris@0 1065
Chris@0 1066 $errors = 0;
Chris@0 1067 $warnings = 0;
Chris@0 1068 $toScreen = false;
Chris@0 1069
Chris@0 1070 foreach ($reports as $report => $output) {
Chris@0 1071 if ($output === null) {
Chris@0 1072 $output = $reportFile;
Chris@0 1073 }
Chris@0 1074
Chris@0 1075 if ($reportFile === null) {
Chris@0 1076 $toScreen = true;
Chris@0 1077 }
Chris@0 1078
Chris@0 1079 // We don't add errors here because the number of
Chris@0 1080 // errors reported by each report type will always be the
Chris@0 1081 // same, so we really just need 1 number.
Chris@0 1082 $result = $phpcs->reporting->printReport(
Chris@0 1083 $report,
Chris@0 1084 $showSources,
Chris@0 1085 $this->values,
Chris@0 1086 $output,
Chris@0 1087 $reportWidth
Chris@0 1088 );
Chris@0 1089
Chris@0 1090 $errors = $result['errors'];
Chris@0 1091 $warnings = $result['warnings'];
Chris@0 1092 }//end foreach
Chris@0 1093
Chris@0 1094 // Only print timer output if no reports were
Chris@0 1095 // printed to the screen so we don't put additional output
Chris@0 1096 // in something like an XML report. If we are printing to screen,
Chris@0 1097 // the report types would have already worked out who should
Chris@0 1098 // print the timer info.
Chris@0 1099 if (PHP_CODESNIFFER_INTERACTIVE === false
Chris@0 1100 && ($toScreen === false
Chris@0 1101 || (($errors + $warnings) === 0 && $this->values['showProgress'] === true))
Chris@0 1102 ) {
Chris@0 1103 PHP_CodeSniffer_Reporting::printRunTime();
Chris@0 1104 }
Chris@0 1105
Chris@0 1106 // They should all return the same value, so it
Chris@0 1107 // doesn't matter which return value we end up using.
Chris@0 1108 $ignoreWarnings = PHP_CodeSniffer::getConfigData('ignore_warnings_on_exit');
Chris@0 1109 $ignoreErrors = PHP_CodeSniffer::getConfigData('ignore_errors_on_exit');
Chris@0 1110
Chris@0 1111 $return = ($errors + $warnings);
Chris@0 1112 if ($ignoreErrors !== null) {
Chris@0 1113 $ignoreErrors = (bool) $ignoreErrors;
Chris@0 1114 if ($ignoreErrors === true) {
Chris@0 1115 $return -= $errors;
Chris@0 1116 }
Chris@0 1117 }
Chris@0 1118
Chris@0 1119 if ($ignoreWarnings !== null) {
Chris@0 1120 $ignoreWarnings = (bool) $ignoreWarnings;
Chris@0 1121 if ($ignoreWarnings === true) {
Chris@0 1122 $return -= $warnings;
Chris@0 1123 }
Chris@0 1124 }
Chris@0 1125
Chris@0 1126 return $return;
Chris@0 1127
Chris@0 1128 }//end printErrorReport()
Chris@0 1129
Chris@0 1130
Chris@0 1131 /**
Chris@0 1132 * Convert the passed standards into valid standards.
Chris@0 1133 *
Chris@0 1134 * Checks things like default values and case.
Chris@0 1135 *
Chris@0 1136 * @param array $standards The standards to validate.
Chris@0 1137 *
Chris@0 1138 * @return array
Chris@0 1139 */
Chris@0 1140 public function validateStandard($standards)
Chris@0 1141 {
Chris@0 1142 if ($standards === null) {
Chris@0 1143 // They did not supply a standard to use.
Chris@0 1144 // Look for a default ruleset in the current directory or higher.
Chris@0 1145 $currentDir = getcwd();
Chris@0 1146
Chris@0 1147 do {
Chris@0 1148 $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml';
Chris@0 1149 if (is_file($default) === true) {
Chris@0 1150 return array($default);
Chris@0 1151 }
Chris@0 1152
Chris@0 1153 $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml.dist';
Chris@0 1154 if (is_file($default) === true) {
Chris@0 1155 return array($default);
Chris@0 1156 }
Chris@0 1157
Chris@0 1158 $lastDir = $currentDir;
Chris@0 1159 $currentDir = dirname($currentDir);
Chris@0 1160 } while ($currentDir !== '.' && $currentDir !== $lastDir);
Chris@0 1161
Chris@0 1162 // Try to get the default from the config system.
Chris@0 1163 $standard = PHP_CodeSniffer::getConfigData('default_standard');
Chris@0 1164 if ($standard === null) {
Chris@0 1165 // Product default standard.
Chris@0 1166 $standard = 'PEAR';
Chris@0 1167 }
Chris@0 1168
Chris@0 1169 return explode(',', $standard);
Chris@0 1170 }//end if
Chris@0 1171
Chris@0 1172 $cleaned = array();
Chris@0 1173 $standards = (array) $standards;
Chris@0 1174
Chris@0 1175 // Check if the standard name is valid, or if the case is invalid.
Chris@0 1176 $installedStandards = PHP_CodeSniffer::getInstalledStandards();
Chris@0 1177 foreach ($standards as $standard) {
Chris@0 1178 foreach ($installedStandards as $validStandard) {
Chris@0 1179 if (strtolower($standard) === strtolower($validStandard)) {
Chris@0 1180 $standard = $validStandard;
Chris@0 1181 break;
Chris@0 1182 }
Chris@0 1183 }
Chris@0 1184
Chris@0 1185 $cleaned[] = $standard;
Chris@0 1186 }
Chris@0 1187
Chris@0 1188 return $cleaned;
Chris@0 1189
Chris@0 1190 }//end validateStandard()
Chris@0 1191
Chris@0 1192
Chris@0 1193 /**
Chris@0 1194 * Prints a report showing the sniffs contained in a standard.
Chris@0 1195 *
Chris@0 1196 * @param string $standard The standard to validate.
Chris@0 1197 *
Chris@0 1198 * @return void
Chris@0 1199 */
Chris@0 1200 public function explainStandard($standard)
Chris@0 1201 {
Chris@0 1202 $phpcs = new PHP_CodeSniffer();
Chris@0 1203 $phpcs->process(array(), $standard);
Chris@0 1204 $sniffs = $phpcs->getSniffs();
Chris@0 1205 $sniffs = array_keys($sniffs);
Chris@0 1206 sort($sniffs);
Chris@0 1207
Chris@0 1208 ob_start();
Chris@0 1209
Chris@0 1210 $lastStandard = '';
Chris@0 1211 $lastCount = '';
Chris@0 1212 $sniffCount = count($sniffs);
Chris@0 1213 $sniffs[] = '___';
Chris@0 1214
Chris@0 1215 echo PHP_EOL."The $standard standard contains $sniffCount sniffs".PHP_EOL;
Chris@0 1216
Chris@0 1217 ob_start();
Chris@0 1218
Chris@0 1219 foreach ($sniffs as $sniff) {
Chris@0 1220 $parts = explode('_', str_replace('\\', '_', $sniff));
Chris@0 1221 if ($lastStandard === '') {
Chris@0 1222 $lastStandard = $parts[0];
Chris@0 1223 }
Chris@0 1224
Chris@0 1225 if ($parts[0] !== $lastStandard) {
Chris@0 1226 $sniffList = ob_get_contents();
Chris@0 1227 ob_end_clean();
Chris@0 1228
Chris@0 1229 echo PHP_EOL.$lastStandard.' ('.$lastCount.' sniffs)'.PHP_EOL;
Chris@0 1230 echo str_repeat('-', (strlen($lastStandard.$lastCount) + 10));
Chris@0 1231 echo PHP_EOL;
Chris@0 1232 echo $sniffList;
Chris@0 1233
Chris@0 1234 $lastStandard = $parts[0];
Chris@0 1235 $lastCount = 0;
Chris@0 1236
Chris@0 1237 ob_start();
Chris@0 1238 }
Chris@0 1239
Chris@0 1240 echo ' '.$parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5).PHP_EOL;
Chris@0 1241 $lastCount++;
Chris@0 1242 }//end foreach
Chris@0 1243
Chris@0 1244 ob_end_clean();
Chris@0 1245
Chris@0 1246 }//end explainStandard()
Chris@0 1247
Chris@0 1248
Chris@0 1249 /**
Chris@0 1250 * Prints out the gathered config data.
Chris@0 1251 *
Chris@0 1252 * @param array $data The config data to print.
Chris@0 1253 *
Chris@0 1254 * @return void
Chris@0 1255 */
Chris@0 1256 public function printConfigData($data)
Chris@0 1257 {
Chris@0 1258 $max = 0;
Chris@0 1259 $keys = array_keys($data);
Chris@0 1260 foreach ($keys as $key) {
Chris@0 1261 $len = strlen($key);
Chris@0 1262 if (strlen($key) > $max) {
Chris@0 1263 $max = $len;
Chris@0 1264 }
Chris@0 1265 }
Chris@0 1266
Chris@0 1267 if ($max === 0) {
Chris@0 1268 return;
Chris@0 1269 }
Chris@0 1270
Chris@0 1271 $max += 2;
Chris@0 1272 ksort($data);
Chris@0 1273 foreach ($data as $name => $value) {
Chris@0 1274 echo str_pad($name.': ', $max).$value.PHP_EOL;
Chris@0 1275 }
Chris@0 1276
Chris@0 1277 }//end printConfigData()
Chris@0 1278
Chris@0 1279
Chris@0 1280 /**
Chris@0 1281 * Prints out the usage information for this script.
Chris@0 1282 *
Chris@0 1283 * @return void
Chris@0 1284 */
Chris@0 1285 public function printUsage()
Chris@0 1286 {
Chris@0 1287 if (PHP_CODESNIFFER_CBF === true) {
Chris@0 1288 $this->printPHPCBFUsage();
Chris@0 1289 } else {
Chris@0 1290 $this->printPHPCSUsage();
Chris@0 1291 }
Chris@0 1292
Chris@0 1293 }//end printUsage()
Chris@0 1294
Chris@0 1295
Chris@0 1296 /**
Chris@0 1297 * Prints out the usage information for PHPCS.
Chris@0 1298 *
Chris@0 1299 * @return void
Chris@0 1300 */
Chris@0 1301 public function printPHPCSUsage()
Chris@0 1302 {
Chris@0 1303 echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors] [--stdin-path=<stdinPath>]'.PHP_EOL;
Chris@0 1304 echo ' [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>] ...'.PHP_EOL;
Chris@0 1305 echo ' [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>]'.PHP_EOL;
Chris@0 1306 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
Chris@0 1307 echo ' [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
Chris@0 1308 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--encoding=<encoding>]'.PHP_EOL;
Chris@0 1309 echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL;
Chris@0 1310 echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL;
Chris@0 1311 echo ' Set runtime value (see --config-set) '.PHP_EOL;
Chris@0 1312 echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL;
Chris@0 1313 echo ' -w Print both warnings and errors (this is the default)'.PHP_EOL;
Chris@0 1314 echo ' -l Local directory only, no recursion'.PHP_EOL;
Chris@0 1315 echo ' -s Show sniff codes in all reports'.PHP_EOL;
Chris@0 1316 echo ' -a Run interactively'.PHP_EOL;
Chris@0 1317 echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL;
Chris@0 1318 echo ' -p Show progress of the run'.PHP_EOL;
Chris@0 1319 echo ' -q Quiet mode; disables progress and verbose output'.PHP_EOL;
Chris@0 1320 echo ' -v[v][v] Print verbose output'.PHP_EOL;
Chris@0 1321 echo ' -i Show a list of installed coding standards'.PHP_EOL;
Chris@0 1322 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
Chris@0 1323 echo ' --help Print this help message'.PHP_EOL;
Chris@0 1324 echo ' --version Print version information'.PHP_EOL;
Chris@0 1325 echo ' --colors Use colors in output'.PHP_EOL;
Chris@0 1326 echo ' --no-colors Do not use colors in output (this is the default)'.PHP_EOL;
Chris@0 1327 echo ' <file> One or more files and/or directories to check'.PHP_EOL;
Chris@0 1328 echo ' <fileList> A file containing a list of files and/or directories to check (one per line)'.PHP_EOL;
Chris@0 1329 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL;
Chris@0 1330 echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL;
Chris@0 1331 echo ' <encoding> The encoding of the files being checked (default is iso-8859-1)'.PHP_EOL;
Chris@0 1332 echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL;
Chris@0 1333 echo ' (extension filtering only valid when checking a directory)'.PHP_EOL;
Chris@0 1334 echo ' The type of the file can be specified using: ext/type'.PHP_EOL;
Chris@0 1335 echo ' e.g., module/php,es/js'.PHP_EOL;
Chris@0 1336 echo ' <generator> Uses either the "HTML", "Markdown" or "Text" generator'.PHP_EOL;
Chris@0 1337 echo ' (forces documentation generation instead of checking)'.PHP_EOL;
Chris@0 1338 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL;
Chris@0 1339 echo ' <report> Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL;
Chris@0 1340 echo ' "json", "emacs", "source", "summary", "diff", "junit"'.PHP_EOL;
Chris@0 1341 echo ' "svnblame", "gitblame", "hgblame" or "notifysend" report'.PHP_EOL;
Chris@0 1342 echo ' (the "full" report is printed by default)'.PHP_EOL;
Chris@0 1343 echo ' <reportFile> Write the report to the specified file path'.PHP_EOL;
Chris@0 1344 echo ' <reportWidth> How many columns wide screen reports should be printed'.PHP_EOL;
Chris@0 1345 echo ' or set to "auto" to use current screen width, where supported'.PHP_EOL;
Chris@0 1346 echo ' <sniffs> A comma separated list of sniff codes to include or exclude during checking'.PHP_EOL;
Chris@0 1347 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL;
Chris@0 1348 echo ' <severity> The minimum severity required to display an error or warning'.PHP_EOL;
Chris@0 1349 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL;
Chris@0 1350 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL;
Chris@0 1351
Chris@0 1352 }//end printPHPCSUsage()
Chris@0 1353
Chris@0 1354
Chris@0 1355 /**
Chris@0 1356 * Prints out the usage information for PHPCBF.
Chris@0 1357 *
Chris@0 1358 * @return void
Chris@0 1359 */
Chris@0 1360 public function printPHPCBFUsage()
Chris@0 1361 {
Chris@0 1362 echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--stdin-path=<stdinPath>]'.PHP_EOL;
Chris@0 1363 echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--suffix=<suffix>]'.PHP_EOL;
Chris@0 1364 echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
Chris@0 1365 echo ' [--tab-width=<tabWidth>] [--encoding=<encoding>]'.PHP_EOL;
Chris@0 1366 echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL;
Chris@0 1367 echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL;
Chris@0 1368 echo ' -n Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL;
Chris@0 1369 echo ' -w Fix both warnings and errors (on by default)'.PHP_EOL;
Chris@0 1370 echo ' -l Local directory only, no recursion'.PHP_EOL;
Chris@0 1371 echo ' -i Show a list of installed coding standards'.PHP_EOL;
Chris@0 1372 echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
Chris@0 1373 echo ' --help Print this help message'.PHP_EOL;
Chris@0 1374 echo ' --version Print version information'.PHP_EOL;
Chris@0 1375 echo ' --no-patch Do not make use of the "diff" or "patch" programs'.PHP_EOL;
Chris@0 1376 echo ' <file> One or more files and/or directories to fix'.PHP_EOL;
Chris@0 1377 echo ' <fileList> A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL;
Chris@0 1378 echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL;
Chris@0 1379 echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL;
Chris@0 1380 echo ' <encoding> The encoding of the files being fixed (default is iso-8859-1)'.PHP_EOL;
Chris@0 1381 echo ' <extensions> A comma separated list of file extensions to fix'.PHP_EOL;
Chris@0 1382 echo ' (extension filtering only valid when checking a directory)'.PHP_EOL;
Chris@0 1383 echo ' The type of the file can be specified using: ext/type'.PHP_EOL;
Chris@0 1384 echo ' e.g., module/php,es/js'.PHP_EOL;
Chris@0 1385 echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL;
Chris@0 1386 echo ' <sniffs> A comma separated list of sniff codes to include or exclude during fixing'.PHP_EOL;
Chris@0 1387 echo ' (all sniffs must be part of the specified standard)'.PHP_EOL;
Chris@0 1388 echo ' <severity> The minimum severity required to fix an error or warning'.PHP_EOL;
Chris@0 1389 echo ' <standard> The name or path of the coding standard to use'.PHP_EOL;
Chris@0 1390 echo ' <suffix> Write modified files to a filename using this suffix'.PHP_EOL;
Chris@0 1391 echo ' ("diff" and "patch" are not used in this mode)'.PHP_EOL;
Chris@0 1392 echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL;
Chris@0 1393
Chris@0 1394 }//end printPHPCBFUsage()
Chris@0 1395
Chris@0 1396
Chris@0 1397 /**
Chris@0 1398 * Prints out a list of installed coding standards.
Chris@0 1399 *
Chris@0 1400 * @return void
Chris@0 1401 */
Chris@0 1402 public function printInstalledStandards()
Chris@0 1403 {
Chris@0 1404 $installedStandards = PHP_CodeSniffer::getInstalledStandards();
Chris@0 1405 $numStandards = count($installedStandards);
Chris@0 1406
Chris@0 1407 if ($numStandards === 0) {
Chris@0 1408 echo 'No coding standards are installed.'.PHP_EOL;
Chris@0 1409 } else {
Chris@0 1410 $lastStandard = array_pop($installedStandards);
Chris@0 1411 if ($numStandards === 1) {
Chris@0 1412 echo "The only coding standard installed is $lastStandard".PHP_EOL;
Chris@0 1413 } else {
Chris@0 1414 $standardList = implode(', ', $installedStandards);
Chris@0 1415 $standardList .= ' and '.$lastStandard;
Chris@0 1416 echo 'The installed coding standards are '.$standardList.PHP_EOL;
Chris@0 1417 }
Chris@0 1418 }
Chris@0 1419
Chris@0 1420 }//end printInstalledStandards()
Chris@0 1421
Chris@0 1422
Chris@0 1423 /**
Chris@0 1424 * Set report width based on terminal width.
Chris@0 1425 *
Chris@0 1426 * @param int $width The width of the report. If "auto" then will
Chris@0 1427 * be replaced by the terminal width.
Chris@0 1428 *
Chris@0 1429 * @return int
Chris@0 1430 */
Chris@0 1431 private function _validateReportWidth($width)
Chris@0 1432 {
Chris@0 1433 if ($width === 'auto'
Chris@0 1434 && preg_match('|\d+ (\d+)|', shell_exec('stty size 2>&1'), $matches) === 1
Chris@0 1435 ) {
Chris@0 1436 return (int) $matches[1];
Chris@0 1437 }
Chris@0 1438
Chris@0 1439 return (int) $width;
Chris@0 1440
Chris@0 1441 }//end _validateReportWidth()
Chris@0 1442
Chris@0 1443
Chris@0 1444 }//end class