Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Version control report base class for PHP_CodeSniffer.
|
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 Ben Selby <benmatselby@gmail.com>
|
Chris@0
|
10 * @copyright 2009-2014 SQLI <www.sqli.com>
|
Chris@0
|
11 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@0
|
12 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@0
|
13 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
14 */
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * Version control report base class for PHP_CodeSniffer.
|
Chris@0
|
18 *
|
Chris@0
|
19 * PHP version 5
|
Chris@0
|
20 *
|
Chris@0
|
21 * @category PHP
|
Chris@0
|
22 * @package PHP_CodeSniffer
|
Chris@0
|
23 * @author Ben Selby <benmatselby@gmail.com>
|
Chris@0
|
24 * @copyright 2009-2014 SQLI <www.sqli.com>
|
Chris@0
|
25 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@0
|
26 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@0
|
27 * @version Release: 1.2.2
|
Chris@0
|
28 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
29 */
|
Chris@0
|
30 abstract class PHP_CodeSniffer_Reports_VersionControl implements PHP_CodeSniffer_Report
|
Chris@0
|
31 {
|
Chris@0
|
32
|
Chris@0
|
33 /**
|
Chris@0
|
34 * The name of the report we want in the output.
|
Chris@0
|
35 *
|
Chris@0
|
36 * @var string
|
Chris@0
|
37 */
|
Chris@0
|
38 protected $reportName = 'VERSION CONTROL';
|
Chris@0
|
39
|
Chris@0
|
40 /**
|
Chris@0
|
41 * A cache of author stats collected during the run.
|
Chris@0
|
42 *
|
Chris@0
|
43 * @var array
|
Chris@0
|
44 */
|
Chris@0
|
45 private $_authorCache = array();
|
Chris@0
|
46
|
Chris@0
|
47 /**
|
Chris@0
|
48 * A cache of blame stats collected during the run.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @var array
|
Chris@0
|
51 */
|
Chris@0
|
52 private $_praiseCache = array();
|
Chris@0
|
53
|
Chris@0
|
54 /**
|
Chris@0
|
55 * A cache of source stats collected during the run.
|
Chris@0
|
56 *
|
Chris@0
|
57 * @var array
|
Chris@0
|
58 */
|
Chris@0
|
59 private $_sourceCache = array();
|
Chris@0
|
60
|
Chris@0
|
61
|
Chris@0
|
62 /**
|
Chris@0
|
63 * Generate a partial report for a single processed file.
|
Chris@0
|
64 *
|
Chris@0
|
65 * Function should return TRUE if it printed or stored data about the file
|
Chris@0
|
66 * and FALSE if it ignored the file. Returning TRUE indicates that the file and
|
Chris@0
|
67 * its data should be counted in the grand totals.
|
Chris@0
|
68 *
|
Chris@0
|
69 * @param array $report Prepared report data.
|
Chris@0
|
70 * @param PHP_CodeSniffer_File $phpcsFile The file being reported on.
|
Chris@0
|
71 * @param boolean $showSources Show sources?
|
Chris@0
|
72 * @param int $width Maximum allowed line width.
|
Chris@0
|
73 *
|
Chris@0
|
74 * @return boolean
|
Chris@0
|
75 */
|
Chris@0
|
76 public function generateFileReport(
|
Chris@0
|
77 $report,
|
Chris@0
|
78 PHP_CodeSniffer_File $phpcsFile,
|
Chris@0
|
79 $showSources=false,
|
Chris@0
|
80 $width=80
|
Chris@0
|
81 ) {
|
Chris@0
|
82 $blames = $this->getBlameContent($report['filename']);
|
Chris@0
|
83
|
Chris@0
|
84 foreach ($report['messages'] as $line => $lineErrors) {
|
Chris@0
|
85 $author = 'Unknown';
|
Chris@0
|
86 if (isset($blames[($line - 1)]) === true) {
|
Chris@0
|
87 $blameAuthor = $this->getAuthor($blames[($line - 1)]);
|
Chris@0
|
88 if ($blameAuthor !== false) {
|
Chris@0
|
89 $author = $blameAuthor;
|
Chris@0
|
90 }
|
Chris@0
|
91 }
|
Chris@0
|
92
|
Chris@0
|
93 if (isset($this->_authorCache[$author]) === false) {
|
Chris@0
|
94 $this->_authorCache[$author] = 0;
|
Chris@0
|
95 $this->_praiseCache[$author] = array(
|
Chris@0
|
96 'good' => 0,
|
Chris@0
|
97 'bad' => 0,
|
Chris@0
|
98 );
|
Chris@0
|
99 }
|
Chris@0
|
100
|
Chris@0
|
101 $this->_praiseCache[$author]['bad']++;
|
Chris@0
|
102
|
Chris@0
|
103 foreach ($lineErrors as $column => $colErrors) {
|
Chris@0
|
104 foreach ($colErrors as $error) {
|
Chris@0
|
105 $this->_authorCache[$author]++;
|
Chris@0
|
106
|
Chris@0
|
107 if ($showSources === true) {
|
Chris@0
|
108 $source = $error['source'];
|
Chris@0
|
109 if (isset($this->_sourceCache[$author][$source]) === false) {
|
Chris@0
|
110 $this->_sourceCache[$author][$source] = array(
|
Chris@0
|
111 'count' => 1,
|
Chris@0
|
112 'fixable' => $error['fixable'],
|
Chris@0
|
113 );
|
Chris@0
|
114 } else {
|
Chris@0
|
115 $this->_sourceCache[$author][$source]['count']++;
|
Chris@0
|
116 }
|
Chris@0
|
117 }
|
Chris@0
|
118 }
|
Chris@0
|
119 }
|
Chris@0
|
120
|
Chris@0
|
121 unset($blames[($line - 1)]);
|
Chris@0
|
122 }//end foreach
|
Chris@0
|
123
|
Chris@0
|
124 // No go through and give the authors some credit for
|
Chris@0
|
125 // all the lines that do not have errors.
|
Chris@0
|
126 foreach ($blames as $line) {
|
Chris@0
|
127 $author = $this->getAuthor($line);
|
Chris@0
|
128 if ($author === false) {
|
Chris@0
|
129 $author = 'Unknown';
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132 if (isset($this->_authorCache[$author]) === false) {
|
Chris@0
|
133 // This author doesn't have any errors.
|
Chris@0
|
134 if (PHP_CODESNIFFER_VERBOSITY === 0) {
|
Chris@0
|
135 continue;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@0
|
138 $this->_authorCache[$author] = 0;
|
Chris@0
|
139 $this->_praiseCache[$author] = array(
|
Chris@0
|
140 'good' => 0,
|
Chris@0
|
141 'bad' => 0,
|
Chris@0
|
142 );
|
Chris@0
|
143 }
|
Chris@0
|
144
|
Chris@0
|
145 $this->_praiseCache[$author]['good']++;
|
Chris@0
|
146 }//end foreach
|
Chris@0
|
147
|
Chris@0
|
148 return true;
|
Chris@0
|
149
|
Chris@0
|
150 }//end generateFileReport()
|
Chris@0
|
151
|
Chris@0
|
152
|
Chris@0
|
153 /**
|
Chris@0
|
154 * Prints the author of all errors and warnings, as given by "version control blame".
|
Chris@0
|
155 *
|
Chris@0
|
156 * @param string $cachedData Any partial report data that was returned from
|
Chris@0
|
157 * generateFileReport during the run.
|
Chris@0
|
158 * @param int $totalFiles Total number of files processed during the run.
|
Chris@0
|
159 * @param int $totalErrors Total number of errors found during the run.
|
Chris@0
|
160 * @param int $totalWarnings Total number of warnings found during the run.
|
Chris@0
|
161 * @param int $totalFixable Total number of problems that can be fixed.
|
Chris@0
|
162 * @param boolean $showSources Show sources?
|
Chris@0
|
163 * @param int $width Maximum allowed line width.
|
Chris@0
|
164 * @param boolean $toScreen Is the report being printed to screen?
|
Chris@0
|
165 *
|
Chris@0
|
166 * @return void
|
Chris@0
|
167 */
|
Chris@0
|
168 public function generate(
|
Chris@0
|
169 $cachedData,
|
Chris@0
|
170 $totalFiles,
|
Chris@0
|
171 $totalErrors,
|
Chris@0
|
172 $totalWarnings,
|
Chris@0
|
173 $totalFixable,
|
Chris@0
|
174 $showSources=false,
|
Chris@0
|
175 $width=80,
|
Chris@0
|
176 $toScreen=true
|
Chris@0
|
177 ) {
|
Chris@0
|
178 $errorsShown = ($totalErrors + $totalWarnings);
|
Chris@0
|
179 if ($errorsShown === 0) {
|
Chris@0
|
180 // Nothing to show.
|
Chris@0
|
181 return;
|
Chris@0
|
182 }
|
Chris@0
|
183
|
Chris@0
|
184 // Make sure the report width isn't too big.
|
Chris@0
|
185 $maxLength = 0;
|
Chris@0
|
186 foreach ($this->_authorCache as $author => $count) {
|
Chris@0
|
187 $maxLength = max($maxLength, strlen($author));
|
Chris@0
|
188 if ($showSources === true && isset($this->_sourceCache[$author]) === true) {
|
Chris@0
|
189 foreach ($this->_sourceCache[$author] as $source => $sourceData) {
|
Chris@0
|
190 if ($source === 'count') {
|
Chris@0
|
191 continue;
|
Chris@0
|
192 }
|
Chris@0
|
193
|
Chris@0
|
194 $maxLength = max($maxLength, (strlen($source) + 9));
|
Chris@0
|
195 }
|
Chris@0
|
196 }
|
Chris@0
|
197 }
|
Chris@0
|
198
|
Chris@0
|
199 $width = min($width, ($maxLength + 30));
|
Chris@0
|
200 $width = max($width, 70);
|
Chris@0
|
201 arsort($this->_authorCache);
|
Chris@0
|
202
|
Chris@0
|
203 echo PHP_EOL."\033[1m".'PHP CODE SNIFFER '.$this->reportName.' BLAME SUMMARY'."\033[0m".PHP_EOL;
|
Chris@0
|
204 echo str_repeat('-', $width).PHP_EOL."\033[1m";
|
Chris@0
|
205 if ($showSources === true) {
|
Chris@0
|
206 echo 'AUTHOR SOURCE'.str_repeat(' ', ($width - 43)).'(Author %) (Overall %) COUNT'.PHP_EOL;
|
Chris@0
|
207 echo str_repeat('-', $width).PHP_EOL;
|
Chris@0
|
208 } else {
|
Chris@0
|
209 echo 'AUTHOR'.str_repeat(' ', ($width - 34)).'(Author %) (Overall %) COUNT'.PHP_EOL;
|
Chris@0
|
210 echo str_repeat('-', $width).PHP_EOL;
|
Chris@0
|
211 }
|
Chris@0
|
212
|
Chris@0
|
213 echo "\033[0m";
|
Chris@0
|
214
|
Chris@0
|
215 if ($showSources === true) {
|
Chris@0
|
216 $maxSniffWidth = ($width - 15);
|
Chris@0
|
217
|
Chris@0
|
218 if ($totalFixable > 0) {
|
Chris@0
|
219 $maxSniffWidth -= 4;
|
Chris@0
|
220 }
|
Chris@0
|
221 }
|
Chris@0
|
222
|
Chris@0
|
223 $fixableSources = 0;
|
Chris@0
|
224
|
Chris@0
|
225 foreach ($this->_authorCache as $author => $count) {
|
Chris@0
|
226 if ($this->_praiseCache[$author]['good'] === 0) {
|
Chris@0
|
227 $percent = 0;
|
Chris@0
|
228 } else {
|
Chris@0
|
229 $total = ($this->_praiseCache[$author]['bad'] + $this->_praiseCache[$author]['good']);
|
Chris@0
|
230 $percent = round(($this->_praiseCache[$author]['bad'] / $total * 100), 2);
|
Chris@0
|
231 }
|
Chris@0
|
232
|
Chris@0
|
233 $overallPercent = '('.round((($count / $errorsShown) * 100), 2).')';
|
Chris@0
|
234 $authorPercent = '('.$percent.')';
|
Chris@0
|
235 $line = str_repeat(' ', (6 - strlen($count))).$count;
|
Chris@0
|
236 $line = str_repeat(' ', (12 - strlen($overallPercent))).$overallPercent.$line;
|
Chris@0
|
237 $line = str_repeat(' ', (11 - strlen($authorPercent))).$authorPercent.$line;
|
Chris@0
|
238 $line = $author.str_repeat(' ', ($width - strlen($author) - strlen($line))).$line;
|
Chris@0
|
239
|
Chris@0
|
240 if ($showSources === true) {
|
Chris@0
|
241 $line = "\033[1m$line\033[0m";
|
Chris@0
|
242 }
|
Chris@0
|
243
|
Chris@0
|
244 echo $line.PHP_EOL;
|
Chris@0
|
245
|
Chris@0
|
246 if ($showSources === true && isset($this->_sourceCache[$author]) === true) {
|
Chris@0
|
247 $errors = $this->_sourceCache[$author];
|
Chris@0
|
248 asort($errors);
|
Chris@0
|
249 $errors = array_reverse($errors);
|
Chris@0
|
250
|
Chris@0
|
251 foreach ($errors as $source => $sourceData) {
|
Chris@0
|
252 if ($source === 'count') {
|
Chris@0
|
253 continue;
|
Chris@0
|
254 }
|
Chris@0
|
255
|
Chris@0
|
256 $count = $sourceData['count'];
|
Chris@0
|
257
|
Chris@0
|
258 $srcLength = strlen($source);
|
Chris@0
|
259 if ($srcLength > $maxSniffWidth) {
|
Chris@0
|
260 $source = substr($source, 0, $maxSniffWidth);
|
Chris@0
|
261 }
|
Chris@0
|
262
|
Chris@0
|
263 $line = str_repeat(' ', (5 - strlen($count))).$count;
|
Chris@0
|
264
|
Chris@0
|
265 echo ' ';
|
Chris@0
|
266 if ($totalFixable > 0) {
|
Chris@0
|
267 echo '[';
|
Chris@0
|
268 if ($sourceData['fixable'] === true) {
|
Chris@0
|
269 echo 'x';
|
Chris@0
|
270 $fixableSources++;
|
Chris@0
|
271 } else {
|
Chris@0
|
272 echo ' ';
|
Chris@0
|
273 }
|
Chris@0
|
274
|
Chris@0
|
275 echo '] ';
|
Chris@0
|
276 }
|
Chris@0
|
277
|
Chris@0
|
278 echo $source;
|
Chris@0
|
279 if ($totalFixable > 0) {
|
Chris@0
|
280 echo str_repeat(' ', ($width - 18 - strlen($source)));
|
Chris@0
|
281 } else {
|
Chris@0
|
282 echo str_repeat(' ', ($width - 14 - strlen($source)));
|
Chris@0
|
283 }
|
Chris@0
|
284
|
Chris@0
|
285 echo $line.PHP_EOL;
|
Chris@0
|
286 }//end foreach
|
Chris@0
|
287 }//end if
|
Chris@0
|
288 }//end foreach
|
Chris@0
|
289
|
Chris@0
|
290 echo str_repeat('-', $width).PHP_EOL;
|
Chris@0
|
291 echo "\033[1m".'A TOTAL OF '.$errorsShown.' SNIFF VIOLATION';
|
Chris@0
|
292 if ($errorsShown !== 1) {
|
Chris@0
|
293 echo 'S';
|
Chris@0
|
294 }
|
Chris@0
|
295
|
Chris@0
|
296 echo ' WERE COMMITTED BY '.count($this->_authorCache).' AUTHOR';
|
Chris@0
|
297 if (count($this->_authorCache) !== 1) {
|
Chris@0
|
298 echo 'S';
|
Chris@0
|
299 }
|
Chris@0
|
300
|
Chris@0
|
301 echo "\033[0m";
|
Chris@0
|
302
|
Chris@0
|
303 if ($totalFixable > 0) {
|
Chris@0
|
304 if ($showSources === true) {
|
Chris@0
|
305 echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
|
Chris@0
|
306 echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m";
|
Chris@0
|
307 } else {
|
Chris@0
|
308 echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
|
Chris@0
|
309 echo "\033[1mPHPCBF CAN FIX $totalFixable OF THESE SNIFF VIOLATIONS AUTOMATICALLY\033[0m";
|
Chris@0
|
310 }
|
Chris@0
|
311 }
|
Chris@0
|
312
|
Chris@0
|
313 echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL;
|
Chris@0
|
314
|
Chris@0
|
315 if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) {
|
Chris@0
|
316 PHP_CodeSniffer_Reporting::printRunTime();
|
Chris@0
|
317 }
|
Chris@0
|
318
|
Chris@0
|
319 }//end generate()
|
Chris@0
|
320
|
Chris@0
|
321
|
Chris@0
|
322 /**
|
Chris@0
|
323 * Extract the author from a blame line.
|
Chris@0
|
324 *
|
Chris@0
|
325 * @param string $line Line to parse.
|
Chris@0
|
326 *
|
Chris@0
|
327 * @return mixed string or false if impossible to recover.
|
Chris@0
|
328 */
|
Chris@0
|
329 abstract protected function getAuthor($line);
|
Chris@0
|
330
|
Chris@0
|
331
|
Chris@0
|
332 /**
|
Chris@0
|
333 * Gets the blame output.
|
Chris@0
|
334 *
|
Chris@0
|
335 * @param string $filename File to blame.
|
Chris@0
|
336 *
|
Chris@0
|
337 * @return array
|
Chris@0
|
338 */
|
Chris@0
|
339 abstract protected function getBlameContent($filename);
|
Chris@0
|
340
|
Chris@0
|
341
|
Chris@0
|
342 }//end class
|