1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of PDepend. |
4
|
|
|
* |
5
|
|
|
* PHP Version 5 |
6
|
|
|
* |
7
|
|
|
* Copyright (c) 2008-2017 Manuel Pichler <[email protected]>. |
8
|
|
|
* All rights reserved. |
9
|
|
|
* |
10
|
|
|
* Redistribution and use in source and binary forms, with or without |
11
|
|
|
* modification, are permitted provided that the following conditions |
12
|
|
|
* are met: |
13
|
|
|
* |
14
|
|
|
* * Redistributions of source code must retain the above copyright |
15
|
|
|
* notice, this list of conditions and the following disclaimer. |
16
|
|
|
* |
17
|
|
|
* * Redistributions in binary form must reproduce the above copyright |
18
|
|
|
* notice, this list of conditions and the following disclaimer in |
19
|
|
|
* the documentation and/or other materials provided with the |
20
|
|
|
* distribution. |
21
|
|
|
* |
22
|
|
|
* * Neither the name of Manuel Pichler nor the names of his |
23
|
|
|
* contributors may be used to endorse or promote products derived |
24
|
|
|
* from this software without specific prior written permission. |
25
|
|
|
* |
26
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
27
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
28
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
29
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
30
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
31
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
32
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
33
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
34
|
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
35
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
36
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
37
|
|
|
* POSSIBILITY OF SUCH DAMAGE. |
38
|
|
|
* |
39
|
|
|
* @copyright 2008-2017 Manuel Pichler. All rights reserved. |
40
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License |
41
|
|
|
*/ |
42
|
|
|
|
43
|
|
|
namespace PDepend\TextUI; |
44
|
|
|
|
45
|
|
|
use Exception; |
46
|
|
|
use PDepend\Application; |
47
|
|
|
use PDepend\DbusUI\ResultPrinter as DbusResultPrinter; |
48
|
|
|
use PDepend\Util\ConfigurationInstance; |
49
|
|
|
use PDepend\Util\Log; |
50
|
|
|
use PDepend\Util\Workarounds; |
51
|
|
|
use RuntimeException; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Handles the command line stuff and starts the text ui runner. |
55
|
|
|
* |
56
|
|
|
* @copyright 2008-2017 Manuel Pichler. All rights reserved. |
57
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License |
58
|
|
|
*/ |
59
|
|
|
class Command |
60
|
|
|
{ |
61
|
|
|
/** |
62
|
|
|
* Marks a cli error exit. |
63
|
|
|
*/ |
64
|
|
|
const CLI_ERROR = 1742; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Marks an input error exit. |
68
|
|
|
*/ |
69
|
|
|
const INPUT_ERROR = 1743; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* The recieved cli options |
73
|
|
|
* |
74
|
|
|
* @var array<string, mixed> |
75
|
|
|
*/ |
76
|
|
|
private $options = array(); |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* The directories/files to be analyzed |
80
|
|
|
* |
81
|
|
|
* @var array<int, string> |
82
|
|
|
*/ |
83
|
|
|
private $source = array(); |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* The used text ui runner. |
87
|
|
|
* |
88
|
|
|
* @var Runner |
89
|
|
|
*/ |
90
|
|
|
private $runner = null; |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @var Application |
94
|
|
|
*/ |
95
|
|
|
private $application; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Performs the main cli process and returns the exit code. |
99
|
|
|
* |
100
|
|
|
* @return int |
101
|
|
|
*/ |
102
|
|
|
public function run() |
103
|
|
|
{ |
104
|
|
|
$this->application = new Application(); |
105
|
|
|
|
106
|
|
|
try { |
107
|
|
|
if ($this->parseArguments() === false) { |
108
|
|
|
$this->printHelp(); |
109
|
|
|
return self::CLI_ERROR; |
110
|
|
|
} |
111
|
|
|
} catch (Exception $e) { |
112
|
|
|
echo $e->getMessage(), PHP_EOL, PHP_EOL; |
113
|
|
|
|
114
|
|
|
$this->printHelp(); |
115
|
|
|
return self::CLI_ERROR; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
if (isset($this->options['--help'])) { |
119
|
|
|
$this->printHelp(); |
120
|
|
|
return Runner::SUCCESS_EXIT; |
121
|
|
|
} |
122
|
|
|
if (isset($this->options['--usage'])) { |
123
|
|
|
$this->printUsage(); |
124
|
|
|
return Runner::SUCCESS_EXIT; |
125
|
|
|
} |
126
|
|
|
if (isset($this->options['--version'])) { |
127
|
|
|
$this->printVersion(); |
128
|
|
|
return Runner::SUCCESS_EXIT; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$configurationFile = false; |
132
|
|
|
|
133
|
|
|
if (isset($this->options['--configuration'])) { |
134
|
|
|
$configurationFile = $this->options['--configuration']; |
135
|
|
|
|
136
|
|
|
if (false === file_exists($configurationFile)) { |
137
|
|
|
$configurationFile = getcwd() . '/' . $configurationFile; |
138
|
|
|
} |
139
|
|
|
if (false === file_exists($configurationFile)) { |
140
|
|
|
$configurationFile = $this->options['--configuration']; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
unset($this->options['--configuration']); |
144
|
|
|
} elseif (file_exists(getcwd() . '/pdepend.xml')) { |
145
|
|
|
$configurationFile = getcwd() . '/pdepend.xml'; |
146
|
|
|
} elseif (file_exists(getcwd() . '/pdepend.xml.dist')) { |
147
|
|
|
$configurationFile = getcwd() . '/pdepend.xml.dist'; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
if ($configurationFile) { |
151
|
|
|
try { |
152
|
|
|
$this->application->setConfigurationFile($configurationFile); |
153
|
|
|
} catch (Exception $e) { |
154
|
|
|
echo $e->getMessage(), PHP_EOL, PHP_EOL; |
155
|
|
|
|
156
|
|
|
$this->printHelp(); |
157
|
|
|
return self::CLI_ERROR; |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
// Create a new text ui runner |
162
|
|
|
$this->runner = $this->application->getRunner(); |
163
|
|
|
|
164
|
|
|
$this->assignArguments(); |
165
|
|
|
|
166
|
|
|
// Get a copy of all options |
167
|
|
|
$options = $this->options; |
168
|
|
|
|
169
|
|
|
// Get an array with all available log options |
170
|
|
|
$logOptions = $this->application->getAvailableLoggerOptions(); |
171
|
|
|
|
172
|
|
|
// Get an array with all available analyzer options |
173
|
|
|
$analyzerOptions = $this->application->getAvailableAnalyzerOptions(); |
174
|
|
|
|
175
|
|
|
foreach ($options as $option => $value) { |
176
|
|
|
if (isset($logOptions[$option])) { |
177
|
|
|
// Reduce received option list |
178
|
|
|
unset($options[$option]); |
179
|
|
|
// Register logger |
180
|
|
|
$this->runner->addReportGenerator(substr($option, 2), $value); |
181
|
|
|
} elseif (isset($analyzerOptions[$option])) { |
182
|
|
|
// Reduce received option list |
183
|
|
|
unset($options[$option]); |
184
|
|
|
|
185
|
|
|
if (isset($analyzerOptions[$option]['value']) && is_bool($value)) { |
186
|
|
|
echo 'Option ', $option, ' requires a value.', PHP_EOL; |
187
|
|
|
return self::INPUT_ERROR; |
188
|
|
|
} elseif ($analyzerOptions[$option]['value'] === 'file' |
189
|
|
|
&& file_exists($value) === false |
190
|
|
|
) { |
191
|
|
|
echo 'Specified file ', $option, '=', $value, |
192
|
|
|
' not exists.', PHP_EOL; |
193
|
|
|
|
194
|
|
|
return self::INPUT_ERROR; |
195
|
|
|
} elseif ($analyzerOptions[$option]['value'] === '*[,...]') { |
196
|
|
|
$value = array_map('trim', explode(',', $value)); |
197
|
|
|
} |
198
|
|
|
$this->runner->addOption(substr($option, 2), $value); |
199
|
|
|
} |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
if (isset($options['--without-annotations'])) { |
203
|
|
|
// Disable annotation parsing |
204
|
|
|
$this->runner->setWithoutAnnotations(); |
205
|
|
|
// Remove option |
206
|
|
|
unset($options['--without-annotations']); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
if (isset($options['--optimization'])) { |
210
|
|
|
// This option is deprecated. |
211
|
|
|
echo 'Option --optimization is ambiguous.', PHP_EOL; |
212
|
|
|
// Remove option |
213
|
|
|
unset($options['--optimization']); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
if (isset($options['--quiet'])) { |
217
|
|
|
$runSilent = true; |
218
|
|
|
unset($options['--quiet']); |
219
|
|
|
} else { |
220
|
|
|
$runSilent = false; |
221
|
|
|
$this->runner->addProcessListener(new ResultPrinter()); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
if (isset($options['--notify-me'])) { |
225
|
|
|
$this->runner->addProcessListener( |
226
|
|
|
new DbusResultPrinter() |
227
|
|
|
); |
228
|
|
|
unset($options['--notify-me']); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
if (count($options) > 0) { |
232
|
|
|
$this->printHelp(); |
233
|
|
|
echo "Unknown option '", key($options), "' given.", PHP_EOL; |
234
|
|
|
return self::CLI_ERROR; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
try { |
238
|
|
|
// Output current pdepend version and author |
239
|
|
|
if ($runSilent === false) { |
240
|
|
|
$this->printVersion(); |
241
|
|
|
$this->printWorkarounds(); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
$startTime = time(); |
245
|
|
|
|
246
|
|
|
$result = $this->runner->run(); |
247
|
|
|
|
248
|
|
|
if ($this->runner->hasParseErrors() === true) { |
249
|
|
|
$errors = $this->runner->getParseErrors(); |
250
|
|
|
|
251
|
|
|
printf( |
252
|
|
|
'%sThe following error%s occurred:%s', |
253
|
|
|
PHP_EOL, |
254
|
|
|
count($errors) > 1 ? 's' : '', |
255
|
|
|
PHP_EOL |
256
|
|
|
); |
257
|
|
|
|
258
|
|
|
foreach ($errors as $error) { |
259
|
|
|
echo $error, PHP_EOL; |
260
|
|
|
} |
261
|
|
|
echo PHP_EOL; |
262
|
|
|
} |
263
|
|
|
if ($runSilent === false) { |
264
|
|
|
$this->printStatistics($startTime); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
return $result; |
268
|
|
|
} catch (RuntimeException $e) { |
269
|
|
|
echo PHP_EOL, PHP_EOL, |
270
|
|
|
'Critical error:', PHP_EOL, |
271
|
|
|
'===============', PHP_EOL, |
272
|
|
|
$e->getMessage(), PHP_EOL; |
273
|
|
|
|
274
|
|
|
Log::debug($this->getErrorTrace($e)); |
275
|
|
|
|
276
|
|
|
for ($previous = $e->getPrevious(); $previous; $previous = $previous->getPrevious()) { |
277
|
|
|
Log::debug(PHP_EOL . 'Caused by:' . PHP_EOL . $this->getErrorTrace($previous)); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
return $e->getCode(); |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Parses the cli arguments. |
286
|
|
|
* |
287
|
|
|
* @return bool |
288
|
|
|
*/ |
289
|
|
|
protected function parseArguments() |
290
|
|
|
{ |
291
|
|
|
if (!isset($_SERVER['argv'])) { |
292
|
|
|
if (false === (boolean) ini_get('register_argc_argv')) { |
293
|
|
|
// @codeCoverageIgnoreStart |
294
|
|
|
echo 'Please enable register_argc_argv in your php.ini.'; |
295
|
|
|
} else { |
296
|
|
|
// @codeCoverageIgnoreEnd |
297
|
|
|
echo 'Unknown error, no $argv array available.'; |
298
|
|
|
} |
299
|
|
|
echo PHP_EOL, PHP_EOL; |
300
|
|
|
return false; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
$argv = $_SERVER['argv']; |
304
|
|
|
|
305
|
|
|
// Remove the pdepend command line file |
306
|
|
|
array_shift($argv); |
307
|
|
|
|
308
|
|
|
if (count($argv) === 0) { |
309
|
|
|
return false; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
// Last argument must be a list of source directories |
313
|
|
|
if (strpos(end($argv), '--') !== 0) { |
314
|
|
|
$this->source = explode(',', array_pop($argv)); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
for ($i = 0, $c = count($argv); $i < $c; ++$i) { |
318
|
|
|
// Is it an ini_set option? |
319
|
|
|
$arg = (string)$argv[$i]; |
320
|
|
|
if ($arg === '-d' && isset($argv[$i + 1])) { |
321
|
|
|
$arg = (string)$argv[++$i]; |
322
|
|
|
if (strpos($arg, '=') === false) { |
323
|
|
|
ini_set($arg, 'on'); |
324
|
|
|
} else { |
325
|
|
|
list($key, $value) = explode('=', $arg); |
326
|
|
|
|
327
|
|
|
ini_set($key, $value); |
328
|
|
|
} |
329
|
|
|
} elseif (strpos($arg, '=') === false) { |
330
|
|
|
$this->options[$arg] = true; |
331
|
|
|
} else { |
332
|
|
|
list($key, $value) = explode('=', $arg); |
333
|
|
|
|
334
|
|
|
$this->options[$key] = $value; |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
return true; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Assign CLI arguments to current runner instance |
343
|
|
|
* |
344
|
|
|
* @return void |
345
|
|
|
*/ |
346
|
|
|
protected function assignArguments() |
347
|
|
|
{ |
348
|
|
|
if ($this->source) { |
|
|
|
|
349
|
|
|
$this->runner->setSourceArguments($this->source); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
// Check for suffix option |
353
|
|
|
if (isset($this->options['--suffix'])) { |
354
|
|
|
// Get file extensions |
355
|
|
|
$extensions = explode(',', $this->options['--suffix']); |
356
|
|
|
// Set allowed file extensions |
357
|
|
|
$this->runner->setFileExtensions($extensions); |
358
|
|
|
|
359
|
|
|
unset($this->options['--suffix']); |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
// Check for ignore option |
363
|
|
|
if (isset($this->options['--ignore'])) { |
364
|
|
|
// Get exclude directories |
365
|
|
|
$directories = explode(',', $this->options['--ignore']); |
366
|
|
|
// Set exclude directories |
367
|
|
|
$this->runner->setExcludeDirectories($directories); |
368
|
|
|
|
369
|
|
|
unset($this->options['--ignore']); |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
// Check for exclude namespace option |
373
|
|
|
if (isset($this->options['--exclude'])) { |
374
|
|
|
// Get exclude directories |
375
|
|
|
$namespaces = explode(',', $this->options['--exclude']); |
376
|
|
|
// Set exclude namespace |
377
|
|
|
$this->runner->setExcludeNamespaces($namespaces); |
378
|
|
|
|
379
|
|
|
unset($this->options['--exclude']); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
// Check for the bad documentation option |
383
|
|
|
if (isset($this->options['--bad-documentation'])) { |
384
|
|
|
echo "Option --bad-documentation is ambiguous.", PHP_EOL; |
385
|
|
|
|
386
|
|
|
unset($this->options['--bad-documentation']); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
$configuration = $this->application->getConfiguration(); |
390
|
|
|
|
391
|
|
|
// Store in config registry |
392
|
|
|
ConfigurationInstance::set($configuration); |
393
|
|
|
|
394
|
|
|
if (isset($this->options['--debug'])) { |
395
|
|
|
unset($this->options['--debug']); |
396
|
|
|
|
397
|
|
|
Log::setSeverity(Log::DEBUG); |
398
|
|
|
} |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* Outputs the current PDepend version. |
403
|
|
|
* |
404
|
|
|
* @return void |
405
|
|
|
*/ |
406
|
|
|
protected function printVersion() |
407
|
|
|
{ |
408
|
|
|
$build = __DIR__ . '/../../../../../build.properties'; |
409
|
|
|
|
410
|
|
|
$version = '@package_version@'; |
411
|
|
|
if (file_exists($build)) { |
412
|
|
|
$data = @parse_ini_file($build); |
413
|
|
|
if (is_array($data)) { |
414
|
|
|
$version = $data['project.version']; |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
echo 'PDepend ', $version, PHP_EOL, PHP_EOL; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/** |
422
|
|
|
* If the current PHP installation requires some workarounds or limitations, |
423
|
|
|
* this method will output a message on STDOUT. |
424
|
|
|
* |
425
|
|
|
* @return void |
426
|
|
|
*/ |
427
|
|
|
protected function printWorkarounds() |
428
|
|
|
{ |
429
|
|
|
$workarounds = new Workarounds(); |
430
|
|
|
|
431
|
|
|
if ($workarounds->isNotRequired()) { |
432
|
|
|
return; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
echo 'Your PHP version requires some workaround:', PHP_EOL; |
436
|
|
|
foreach ($workarounds->getRequiredWorkarounds() as $workaround) { |
437
|
|
|
echo '- ', $workaround, PHP_EOL; |
438
|
|
|
} |
439
|
|
|
echo PHP_EOL; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Outputs the base usage of PDepend. |
444
|
|
|
* |
445
|
|
|
* @return void |
446
|
|
|
*/ |
447
|
|
|
protected function printUsage() |
448
|
|
|
{ |
449
|
|
|
$this->printVersion(); |
450
|
|
|
echo 'Usage: pdepend [options] [logger] <dir[,dir[,...]]>', PHP_EOL, PHP_EOL; |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Outputs the main help of PDepend. |
455
|
|
|
* |
456
|
|
|
* @return void |
457
|
|
|
*/ |
458
|
|
|
protected function printHelp() |
459
|
|
|
{ |
460
|
|
|
$this->printUsage(); |
461
|
|
|
|
462
|
|
|
$length = $this->printLogOptions(); |
463
|
|
|
$length = $this->printAnalyzerOptions($length); |
464
|
|
|
|
465
|
|
|
$this->printOption( |
466
|
|
|
'--configuration=<file>', |
467
|
|
|
'Optional PDepend configuration file.', |
468
|
|
|
$length |
469
|
|
|
); |
470
|
|
|
echo PHP_EOL; |
471
|
|
|
|
472
|
|
|
$this->printOption( |
473
|
|
|
'--suffix=<ext[,...]>', |
474
|
|
|
'List of valid PHP file extensions.', |
475
|
|
|
$length |
476
|
|
|
); |
477
|
|
|
$this->printOption( |
478
|
|
|
'--ignore=<dir[,...]>', |
479
|
|
|
'List of exclude directories.', |
480
|
|
|
$length |
481
|
|
|
); |
482
|
|
|
$this->printOption( |
483
|
|
|
'--exclude=<pkg[,...]>', |
484
|
|
|
'List of exclude namespaces.', |
485
|
|
|
$length |
486
|
|
|
); |
487
|
|
|
echo PHP_EOL; |
488
|
|
|
|
489
|
|
|
$this->printOption( |
490
|
|
|
'--without-annotations', |
491
|
|
|
'Do not parse doc comment annotations.', |
492
|
|
|
$length |
493
|
|
|
); |
494
|
|
|
echo PHP_EOL; |
495
|
|
|
|
496
|
|
|
$this->printOption('--quiet', 'Prints errors only.', $length); |
497
|
|
|
$this->printOption('--debug', 'Prints debugging information.', $length); |
498
|
|
|
$this->printOption('--help', 'Print this help text.', $length); |
499
|
|
|
$this->printOption('--version', 'Print the current version.', $length); |
500
|
|
|
|
501
|
|
|
$this->printDbusOption($length); |
502
|
|
|
|
503
|
|
|
$this->printOption('-d key[=value]', 'Sets a php.ini value.', $length); |
504
|
|
|
echo PHP_EOL; |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
/** |
508
|
|
|
* Prints all available log options and returns the length of the longest |
509
|
|
|
* option. |
510
|
|
|
* |
511
|
|
|
* @return int |
512
|
|
|
*/ |
513
|
|
|
protected function printLogOptions() |
514
|
|
|
{ |
515
|
|
|
$maxLength = 0; |
516
|
|
|
$options = array(); |
517
|
|
|
$logOptions = $this->application->getAvailableLoggerOptions(); |
518
|
|
|
foreach ($logOptions as $option => $info) { |
519
|
|
|
// Build log option identifier |
520
|
|
|
$identifier = sprintf('%s=<%s>', $option, $info['value']); |
521
|
|
|
// Store in options array |
522
|
|
|
$options[$identifier] = $info['message']; |
523
|
|
|
|
524
|
|
|
$length = strlen($identifier); |
525
|
|
|
if ($length > $maxLength) { |
526
|
|
|
$maxLength = $length; |
527
|
|
|
} |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
ksort($options); |
531
|
|
|
|
532
|
|
|
$last = null; |
533
|
|
|
foreach ($options as $option => $message) { |
534
|
|
|
$pos = strrpos($option, '-'); |
535
|
|
|
$current = substr($option, 0, $pos === false ? null : $pos); |
536
|
|
|
if ($last !== null && $last !== $current) { |
537
|
|
|
echo PHP_EOL; |
538
|
|
|
} |
539
|
|
|
$last = $current; |
540
|
|
|
|
541
|
|
|
$this->printOption($option, $message, $maxLength); |
542
|
|
|
} |
543
|
|
|
echo PHP_EOL; |
544
|
|
|
|
545
|
|
|
return $maxLength; |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
/** |
549
|
|
|
* Prints the analyzer options. |
550
|
|
|
* |
551
|
|
|
* @param int $length Length of the longest option. |
552
|
|
|
* |
553
|
|
|
* @return int |
554
|
|
|
*/ |
555
|
|
|
protected function printAnalyzerOptions($length) |
556
|
|
|
{ |
557
|
|
|
$options = $this->application->getAvailableAnalyzerOptions(); |
558
|
|
|
|
559
|
|
|
if (count($options) === 0) { |
560
|
|
|
return $length; |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
ksort($options); |
564
|
|
|
|
565
|
|
|
foreach ($options as $option => $info) { |
566
|
|
|
if (isset($info['value'])) { |
567
|
|
|
$option .= '=<' . $info['value'] . '>'; |
568
|
|
|
} else { |
569
|
|
|
$option .= '=<value>'; |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
$this->printOption($option, $info['message'], $length); |
573
|
|
|
} |
574
|
|
|
echo PHP_EOL; |
575
|
|
|
|
576
|
|
|
return $length; |
577
|
|
|
} |
578
|
|
|
|
579
|
|
|
/** |
580
|
|
|
* Prints a single option. |
581
|
|
|
* |
582
|
|
|
* @param string $option The option identifier. |
583
|
|
|
* @param string $message The option help message. |
584
|
|
|
* @param int $length The length of the longest option. |
585
|
|
|
* |
586
|
|
|
* @return void |
587
|
|
|
*/ |
588
|
|
|
private function printOption($option, $message, $length) |
589
|
|
|
{ |
590
|
|
|
// Ignore the phpunit xml option |
591
|
|
|
if (0 === strpos($option, '--phpunit-xml=')) { |
592
|
|
|
return; |
593
|
|
|
} |
594
|
|
|
|
595
|
|
|
// Calculate the max message length |
596
|
|
|
$mlength = 77 - $length; |
597
|
|
|
|
598
|
|
|
$option = str_pad($option, $length, ' ', STR_PAD_RIGHT); |
599
|
|
|
echo ' ', $option, ' '; |
600
|
|
|
|
601
|
|
|
$lines = explode(PHP_EOL, wordwrap($message, $mlength, PHP_EOL)); |
602
|
|
|
echo array_shift($lines); |
603
|
|
|
|
604
|
|
|
while (($line = array_shift($lines)) !== null) { |
605
|
|
|
echo PHP_EOL, str_repeat(' ', $length + 3), $line; |
606
|
|
|
} |
607
|
|
|
echo PHP_EOL; |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
/** |
611
|
|
|
* Optionally outputs the dbus option when the required extension |
612
|
|
|
* is loaded. |
613
|
|
|
* |
614
|
|
|
* @param int $length Padding length for the option. |
615
|
|
|
* |
616
|
|
|
* @return void |
617
|
|
|
*/ |
618
|
|
|
private function printDbusOption($length) |
619
|
|
|
{ |
620
|
|
|
if (extension_loaded("dbus") === false) { |
621
|
|
|
return; |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
$option = '--notify-me'; |
625
|
|
|
$message = 'Show a notification after analysis.'; |
626
|
|
|
|
627
|
|
|
$this->printOption($option, $message, $length); |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
/** |
631
|
|
|
* Main method that starts the command line runner. |
632
|
|
|
* |
633
|
|
|
* @return int The exit code. |
634
|
|
|
*/ |
635
|
|
|
public static function main() |
636
|
|
|
{ |
637
|
|
|
$command = new self(); |
638
|
|
|
|
639
|
|
|
return $command->run(); |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
/** |
643
|
|
|
* @param int $startTime |
644
|
|
|
* |
645
|
|
|
* @return void |
646
|
|
|
*/ |
647
|
|
|
private function printStatistics($startTime) |
648
|
|
|
{ |
649
|
|
|
$duration = time() - $startTime; |
650
|
|
|
$hours = intval($duration / 3600); |
651
|
|
|
$minutes = intval(($duration - $hours * 3600) / 60); |
652
|
|
|
$seconds = $duration % 60; |
653
|
|
|
echo PHP_EOL, 'Time: ', sprintf('%d:%02d:%02d', $hours, $minutes, $seconds); |
654
|
|
|
if (function_exists('memory_get_peak_usage')) { |
655
|
|
|
$memory = (memory_get_peak_usage(true) / (1024 * 1024)); |
656
|
|
|
printf('; Memory: %4.2fMb', $memory); |
657
|
|
|
} |
658
|
|
|
echo PHP_EOL; |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
/** |
662
|
|
|
* @param Exception|\Throwable $exception |
663
|
|
|
* |
664
|
|
|
* @return string |
665
|
|
|
*/ |
666
|
|
|
private function getErrorTrace($exception) |
667
|
|
|
{ |
668
|
|
|
return get_class($exception) . '(' . $exception->getMessage() . ')' . PHP_EOL . |
669
|
|
|
'## ' . $exception->getFile() .'(' . $exception->getLine() . ')' . PHP_EOL . |
670
|
|
|
$exception->getTraceAsString(); |
671
|
|
|
} |
672
|
|
|
} |
673
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.