Drupal investigation

phpcs-svn-pre-commit 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * A commit hook for SVN.
  5. *
  6. * PHP version 5
  7. *
  8. * @category PHP
  9. * @package PHP_CodeSniffer
  10. * @author Jack Bates <ms419@freezone.co.uk>
  11. * @author Greg Sherwood <gsherwood@squiz.net>
  12. * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
  13. * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  14. * @link http://pear.php.net/package/PHP_CodeSniffer
  15. */
  16. if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) {
  17. include_once dirname(__FILE__).'/../CodeSniffer/CLI.php';
  18. } else {
  19. include_once 'PHP/CodeSniffer/CLI.php';
  20. }
  21. define('PHP_CODESNIFFER_SVNLOOK', '/usr/bin/svnlook');
  22. /**
  23. * A class to process command line options.
  24. *
  25. * @category PHP
  26. * @package PHP_CodeSniffer
  27. * @author Jack Bates <ms419@freezone.co.uk>
  28. * @author Greg Sherwood <gsherwood@squiz.net>
  29. * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
  30. * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  31. * @version Release: @package_version@
  32. * @link http://pear.php.net/package/PHP_CodeSniffer
  33. */
  34. class PHP_CodeSniffer_SVN_Hook extends PHP_CodeSniffer_CLI
  35. {
  36. /**
  37. * Get a list of default values for all possible command line arguments.
  38. *
  39. * @return array
  40. */
  41. public function getDefaults()
  42. {
  43. $defaults = parent::getDefaults();
  44. $defaults['svnArgs'] = array();
  45. return $defaults;
  46. }//end getDefaults()
  47. /**
  48. * Processes an unknown command line argument.
  49. *
  50. * Assumes all unknown arguments are files and folders to check.
  51. *
  52. * @param string $arg The command line argument.
  53. * @param int $pos The position of the argument on the command line.
  54. *
  55. * @return void
  56. */
  57. public function processUnknownArgument($arg, $pos)
  58. {
  59. $this->values['svnArgs'][] = escapeshellarg($arg);
  60. }//end processUnknownArgument()
  61. /**
  62. * Runs PHP_CodeSniffer over files are directories.
  63. *
  64. * @param array $values An array of values determined from CLI args.
  65. *
  66. * @return int The number of error and warning messages shown.
  67. * @see getCommandLineValues()
  68. */
  69. public function process($values=array())
  70. {
  71. if (empty($values) === true) {
  72. $values = $this->getCommandLineValues();
  73. } else {
  74. $values = array_merge($this->getDefaults(), $values);
  75. $this->values = $values;
  76. }
  77. // Get list of files in this transaction.
  78. $command = PHP_CODESNIFFER_SVNLOOK.' changed '.implode(' ', $values['svnArgs']);
  79. $handle = popen($command, 'r');
  80. if ($handle === false) {
  81. echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL;
  82. exit(2);
  83. }
  84. $contents = stream_get_contents($handle);
  85. fclose($handle);
  86. // Do not check deleted paths.
  87. $contents = preg_replace('/^D.*/m', null, $contents);
  88. // Drop the four characters representing the action which precede the path on
  89. // each line.
  90. $contents = preg_replace('/^.{4}/m', null, $contents);
  91. $values['standard'] = $this->validateStandard($values['standard']);
  92. foreach ($values['standard'] as $standard) {
  93. if (PHP_CodeSniffer::isInstalledStandard($standard) === false) {
  94. // They didn't select a valid coding standard, so help them
  95. // out by letting them know which standards are installed.
  96. echo 'ERROR: the "'.$standard.'" coding standard is not installed. ';
  97. $this->printInstalledStandards();
  98. exit(2);
  99. }
  100. }
  101. $phpcs = new PHP_CodeSniffer(
  102. $values['verbosity'],
  103. $values['tabWidth'],
  104. $values['encoding']
  105. );
  106. // Set file extensions if they were specified. Otherwise,
  107. // let PHP_CodeSniffer decide on the defaults.
  108. if (empty($values['extensions']) === false) {
  109. $phpcs->setAllowedFileExtensions($values['extensions']);
  110. } else {
  111. $phpcs->setAllowedFileExtensions(array_keys($phpcs->defaultFileExtensions));
  112. }
  113. // Set ignore patterns if they were specified.
  114. if (empty($values['ignored']) === false) {
  115. $phpcs->setIgnorePatterns($values['ignored']);
  116. }
  117. // Set some convenience member vars.
  118. if ($values['errorSeverity'] === null) {
  119. $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV;
  120. } else {
  121. $this->errorSeverity = $values['errorSeverity'];
  122. }
  123. if ($values['warningSeverity'] === null) {
  124. $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV;
  125. } else {
  126. $this->warningSeverity = $values['warningSeverity'];
  127. }
  128. if (empty($values['reports']) === true) {
  129. $this->values['reports']['full'] = $values['reportFile'];
  130. }
  131. // Initialize PHP_CodeSniffer listeners but don't process any files.
  132. $phpcs->setCli($this);
  133. $phpcs->initStandard($values['standard'], $values['sniffs']);
  134. // Need double quotes around the following regex beause the vertical whitespace
  135. // char is not always treated correctly for whatever reason.
  136. foreach (preg_split("/\v|\n/", $contents, -1, PREG_SPLIT_NO_EMPTY) as $path) {
  137. // No need to process folders as each changed file is checked.
  138. if (substr($path, -1) === '/') {
  139. continue;
  140. }
  141. // We need to check ignore rules ourself because they are
  142. // not checked when processing a single file.
  143. if ($phpcs->shouldProcessFile($path, dirname($path)) === false) {
  144. continue;
  145. }
  146. // Get the contents of each file, as it would be after this transaction.
  147. $command = PHP_CODESNIFFER_SVNLOOK.' cat '.implode(' ', $values['svnArgs']).' '.escapeshellarg($path);
  148. $handle = popen($command, 'r');
  149. if ($handle === false) {
  150. echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL;
  151. exit(2);
  152. }
  153. $contents = stream_get_contents($handle);
  154. fclose($handle);
  155. $phpcs->processFile($path, $contents);
  156. }//end foreach
  157. return $this->printErrorReport(
  158. $phpcs,
  159. $values['reports'],
  160. $values['showSources'],
  161. $values['reportFile'],
  162. $values['reportWidth']
  163. );
  164. }//end process()
  165. /**
  166. * Prints out the usage information for this script.
  167. *
  168. * @return void
  169. */
  170. public function printUsage()
  171. {
  172. parent::printUsage();
  173. echo PHP_EOL;
  174. echo ' Each additional argument is passed to the `svnlook changed ...`'.PHP_EOL;
  175. echo ' and `svnlook cat ...` commands. The report is printed on standard output,'.PHP_EOL;
  176. echo ' however Subversion displays only standard error to the user, so in a'.PHP_EOL;
  177. echo ' pre-commit hook, this script should be invoked as follows:'.PHP_EOL;
  178. echo PHP_EOL;
  179. echo ' '.basename($_SERVER['argv'][0]).' ... "$REPOS" -t "$TXN" >&2 || exit 1'.PHP_EOL;
  180. }//end printUsage()
  181. }//end class
  182. $phpcs = new PHP_CodeSniffer_SVN_Hook();
  183. PHP_CodeSniffer_Reporting::startTiming();
  184. $phpcs->checkRequirements();
  185. $numErrors = $phpcs->process();
  186. if ($numErrors !== 0) {
  187. exit(1);
  188. }