* @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence * @version CVS: $Id$ * @link http://pear.php.net/package/PHP_CodeSniffer */ if (is_file(dirname(__FILE__).'/../CodeSniffer.php') === true) { include_once dirname(__FILE__).'/../CodeSniffer.php'; } else { include_once 'PHP/CodeSniffer.php'; } /** * A class to process command line phpcs scripts. * * @category PHP * @package PHP_CodeSniffer * @author Greg Sherwood * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence * @version Release: 1.1.0 * @link http://pear.php.net/package/PHP_CodeSniffer */ class PHP_CodeSniffer_CLI { /** * Exits if the minimum requirements of PHP_CodSniffer are not met. * * @return array */ public function checkRequirements() { // Check the PHP version. if (version_compare(PHP_VERSION, '5.1.2') === -1) { echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL; exit(2); } if (extension_loaded('tokenizer') === false) { echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL; exit(2); } }//end checkRequirements() /** * Get a list of default values for all possible command line arguments. * * @return array */ public function getDefaults() { // The default values for config settings. $defaults['files'] = array(); $defaults['standard'] = null; $defaults['verbosity'] = 0; $defaults['local'] = false; $defaults['extensions'] = array(); $defaults['ignored'] = array(); $defaults['generator'] = ''; $defaults['report'] = PHP_CodeSniffer::getConfigData('report_format'); if ($defaults['report'] === null) { $defaults['report'] = 'full'; } $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings'); if ($showWarnings === null) { $defaults['showWarnings'] = true; } else { $defaults['showWarnings'] = (bool) $showWarnings; } $tabWidth = PHP_CodeSniffer::getConfigData('tab_width'); if ($tabWidth === null) { $defaults['tabWidth'] = 0; } else { $defaults['tabWidth'] = (int) $tabWidth; } return $defaults; }//end getDefaults() /** * Process the command line arguments and returns the values. * * @return array */ public function getCommandLineValues() { $values = $this->getDefaults(); for ($i = 1; $i < $_SERVER['argc']; $i++) { $arg = $_SERVER['argv'][$i]; if ($arg{0} === '-') { if ($arg{1} === '-') { $values = $this->processLongArgument(substr($arg, 2), $i, $values); } else { $switches = str_split($arg); foreach ($switches as $switch) { if ($switch === '-') { continue; } $values = $this->processShortArgument($switch, $values); } } } else { $values = $this->processUnknownArgument($arg, $i, $values); } }//end for return $values; }//end getCommandLineValues() /** * Processes a sort (-e) command line argument. * * @param string $arg The command line argument. * @param array $values An array of values determined from CLI args. * * @return array The updated CLI values. * @see getCommandLineValues() */ public function processShortArgument($arg, $values) { switch ($arg) { case 'h': case '?': $this->printUsage(); exit(0); break; case 'i' : $this->printInstalledStandards(); exit(0); break; case 'v' : $values['verbosity']++; break; case 'l' : $values['local'] = true; break; case 'n' : $values['showWarnings'] = false; break; case 'w' : $values['showWarnings'] = true; break; default: $values = $this->processUnknownArgument('-'.$arg, $values); }//end switch return $values; }//end processShortArgument() /** * Processes a long (--example) command line argument. * * @param string $arg The command line argument. * @param int $pos The position of the argument on the command line. * @param array $values An array of values determined from CLI args. * * @return array The updated CLI values. * @see getCommandLineValues() */ public function processLongArgument($arg, $pos, $values) { switch ($arg) { case 'help': $this->printUsage(); exit(0); break; case 'version': echo 'PHP_CodeSniffer version 1.1.0 (stable) '; echo 'by Squiz Pty Ltd. (http://www.squiz.net)'.PHP_EOL; exit(0); break; case 'config-set': $key = $_SERVER['argv'][($pos + 1)]; $value = $_SERVER['argv'][($pos + 2)]; PHP_CodeSniffer::setConfigData($key, $value); exit(0); break; case 'config-delete': $key = $_SERVER['argv'][($pos + 1)]; PHP_CodeSniffer::setConfigData($key, null); exit(0); break; case 'config-show': $data = PHP_CodeSniffer::getAllConfigData(); print_r($data); exit(0); break; default: if (substr($arg, 0, 7) === 'report=') { $values['report'] = substr($arg, 7); $validReports = array( 'full', 'xml', 'checkstyle', 'csv', 'summary', ); if (in_array($values['report'], $validReports) === false) { echo 'ERROR: Report type "'.$report.'" not known.'.PHP_EOL; exit(2); } } else if (substr($arg, 0, 9) === 'standard=') { $values['standard'] = substr($arg, 9); } else if (substr($arg, 0, 11) === 'extensions=') { $values['extensions'] = explode(',', substr($arg, 11)); } else if (substr($arg, 0, 7) === 'ignore=') { // Split the ignore string on commas, unless the comma is escaped // using 1 or 3 slashes (\, or \\\,). $values['ignored'] = preg_split('/(?<=(?processUnknownArgument('--'.$arg, $values); }//end if break; }//end switch return $values; }//end processLongArgument() /** * Processes an unknown command line argument. * * Assumes all unknown arguments are files and folders to check. * * @param string $arg The command line argument. * @param int $pos The position of the argument on the command line. * @param array $values An array of values determined from CLI args. * * @return array The updated CLI values. * @see getCommandLineValues() */ public function processUnknownArgument($arg, $pos, $values) { // We don't know about any additional switches; just files. if ($arg{0} === '-') { echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL; $this->printUsage(); exit(2); } $file = realpath($arg); if (file_exists($file) === false) { echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL; $this->printUsage(); exit(2); } else { $values['files'][] = $file; } return $values; }//end processUnknownArgument() /** * Runs PHP_CodeSniffer over files are directories. * * @param array $values An array of values determined from CLI args. * * @return int The number of error and warning messages shown. * @see getCommandLineValues() */ public function process($values=array()) { if (empty($values) === true) { $values = $this->getCommandLineValues(); } if ($values['generator'] !== '') { $phpcs = new PHP_CodeSniffer($values['verbosity']); $phpcs->generateDocs($values['standard'], $values['files'], $values['generator']); exit(0); } if (empty($values['files']) === true) { echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL; $this->printUsage(); exit(2); } $values['standard'] = $this->validateStandard($values['standard']); if (PHP_CodeSniffer::isInstalledStandard($values['standard']) === false) { // They didn't select a valid coding standard, so help them // out by letting them know which standards are installed. echo 'ERROR: the "'.$values['standard'].'" coding standard is not installed. '; $this->printInstalledStandards(); exit(2); } $phpcs = new PHP_CodeSniffer($values['verbosity'], $values['tabWidth']); // Set file extensions if they were specified. Otherwise, // let PHP_CodeSniffer decide on the defaults. if (empty($values['extensions']) === false) { $phpcs->setAllowedFileExtensions($values['extensions']); } // Set ignore patterns if they were specified. if (empty($values['ignored']) === false) { $phpcs->setIgnorePatterns($values['ignored']); } $phpcs->process($values['files'], $values['standard'], array(), $values['local']); return $this->printErrorReport($phpcs, $values['report'], $values['showWarnings']); }//end process() /** * Prints the error report. * * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing * the errors. * @param string $report The type of report to print. * @param bool $showWarnings TRUE if warnings should also be printed. * * @return int The number of error and warning messages shown. */ public function printErrorReport($phpcs, $report, $showWarnings) { switch ($report) { case 'xml': $numErrors = $phpcs->printXMLErrorReport($showWarnings); break; case 'checkstyle': $numErrors = $phpcs->printCheckstyleErrorReport($showWarnings); break; case 'csv': $numErrors = $phpcs->printCSVErrorReport($showWarnings); break; case 'summary': $numErrors = $phpcs->printErrorReportSummary($showWarnings); break; default: $numErrors = $phpcs->printErrorReport($showWarnings); break; } return $numErrors; }//end printErrorReport() /** * Convert the passed standard into a valid standard. * * Checks things like default values and case. * * @param string $standard The standard to validate. * * @return string */ public function validateStandard($standard) { if ($standard === null) { // They did not supply a standard to use. // Try to get the default from the config system. $standard = PHP_CodeSniffer::getConfigData('default_standard'); if ($standard === null) { $standard = 'PEAR'; } } // Check if the standard name is valid. If not, check that the case // was not entered incorrectly. if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { $installedStandards = PHP_CodeSniffer::getInstalledStandards(); foreach ($installedStandards as $validStandard) { if (strtolower($standard) === strtolower($validStandard)) { $standard = $validStandard; break; } } } return $standard; }//end validateStandard() /** * Prints out the usage information for this script. * * @return void */ public function printUsage() { echo 'Usage: phpcs [-nwlvi] [--report=] [--standard=]'.PHP_EOL; echo ' [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL; echo ' [--generator=] [--extensions=]'.PHP_EOL; echo ' [--ignore=] [--tab-width=] ...'.PHP_EOL; echo ' -n Do not print warnings'.PHP_EOL; echo ' -w Print both warnings and errors (on by default)'.PHP_EOL; echo ' -l Local directory only, no recursion'.PHP_EOL; echo ' -v[v][v] Print verbose output'.PHP_EOL; echo ' -i Show a list of installed coding standards'.PHP_EOL; echo ' --help Print this help message'.PHP_EOL; echo ' --version Print version information'.PHP_EOL; echo ' One or more files and/or directories to check'.PHP_EOL; echo ' A comma separated list of file extensions to check'.PHP_EOL; echo ' (only valid if checking a directory)'.PHP_EOL; echo ' A comma separated list of patterns that are used'.PHP_EOL; echo ' to ignore directories and files'.PHP_EOL; echo ' The name of the coding standard to use'.PHP_EOL; echo ' The number of spaces each tab represents'.PHP_EOL; echo ' The name of a doc generator to use'.PHP_EOL; echo ' (forces doc generation instead of checking)'.PHP_EOL; echo ' Print either the "full", "xml", "checkstyle",'.PHP_EOL; echo ' "csv" or "summary" report'.PHP_EOL; echo ' (the "full" report is printed by default)'.PHP_EOL; }//end printUsage() /** * Prints out a list of installed coding standards. * * @return void */ public function printInstalledStandards() { $installedStandards = PHP_CodeSniffer::getInstalledStandards(); $numStandards = count($installedStandards); if ($numStandards === 0) { echo 'No coding standards are installed.'.PHP_EOL; } else { $lastStandard = array_pop($installedStandards); if ($numStandards === 1) { echo 'The only coding standard installed is $lastStandard'.PHP_EOL; } else { $standardList = implode(', ', $installedStandards); $standardList .= ' and '.$lastStandard; echo 'The installed coding standards are '.$standardList.PHP_EOL; } } }//end printInstalledStandards() }//end class ?>