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