Passed
Push — master ( 830897...939e6f )
by Kyle
01:43 queued 35s
created

CommandLineOptions::ignoreErrorsOnExit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of PHP Mess Detector.
4
 *
5
 * Copyright (c) Manuel Pichler <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * Licensed under BSD License
9
 * For full copyright and license information, please see the LICENSE file.
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @author Manuel Pichler <[email protected]>
13
 * @copyright Manuel Pichler. All rights reserved.
14
 * @license https://opensource.org/licenses/bsd-license.php BSD License
15
 * @link http://phpmd.org/
16
 */
17
18
namespace PHPMD\TextUI;
19
20
use PHPMD\Renderer\AnsiRenderer;
21
use PHPMD\Renderer\GitHubRenderer;
22
use PHPMD\Renderer\HTMLRenderer;
23
use PHPMD\Renderer\JSONRenderer;
24
use PHPMD\Renderer\TextRenderer;
25
use PHPMD\Renderer\XMLRenderer;
26
use PHPMD\Rule;
27
28
/**
29
 * This is a helper class that collects the specified cli arguments and puts them
30
 * into accessible properties.
31
 *
32
 * @SuppressWarnings(PHPMD.LongVariable)
33
 */
34
class CommandLineOptions
35
{
36
    /**
37
     * Error code for invalid input
38
     */
39
    const INPUT_ERROR = 23;
40
41
    /**
42
     * The minimum rule priority.
43
     *
44
     * @var integer
45
     */
46
    protected $minimumPriority = Rule::LOWEST_PRIORITY;
47
48
    /**
49
     * The maximum rule priority.
50
     *
51
     * @var integer
52
     */
53
    protected $maximumPriority = Rule::HIGHEST_PRIORITY;
54
55
    /**
56
     * A php source code filename or directory.
57
     *
58
     * @var string
59
     */
60
    protected $inputPath;
61
62
    /**
63
     * The specified report format.
64
     *
65
     * @var string
66
     */
67
    protected $reportFormat;
68
69
    /**
70
     * An optional filename for the generated report.
71
     *
72
     * @var string
73
     */
74
    protected $reportFile;
75
76
    /**
77
     * Additional report files.
78
     *
79
     * @var array
80
     */
81
    protected $reportFiles = array();
82
83
    /**
84
     * A ruleset filename or a comma-separated string of ruleset filenames.
85
     *
86
     * @var string
87
     */
88
    protected $ruleSets;
89
90
    /**
91
     * File name of a PHPUnit code coverage report.
92
     *
93
     * @var string
94
     */
95
    protected $coverageReport;
96
97
    /**
98
     * A string of comma-separated extensions for valid php source code filenames.
99
     *
100
     * @var string
101
     */
102
    protected $extensions;
103
104
    /**
105
     * A string of comma-separated pattern that is used to exclude directories.
106
     *
107
     * Use asterisks to exclude by pattern. For example *src/foo/*.php or *src/foo/*
108
     *
109
     * @var string
110
     */
111
    protected $ignore;
112
113
    /**
114
     * Should the shell show the current phpmd version?
115
     *
116
     * @var boolean
117
     */
118
    protected $version = false;
119
120
    /**
121
     * Should PHPMD run in strict mode?
122
     *
123
     * @var boolean
124
     * @since 1.2.0
125
     */
126
    protected $strict = false;
127
128
    /**
129
     * Should PHPMD exit without error code even if error is found?
130
     *
131
     * @var boolean
132
     * @since 2.10.0
133
     */
134
    protected $ignoreErrorsOnExit = false;
135
136
    /**
137
     * Should PHPMD exit without error code even if violation is found?
138
     *
139
     * @var boolean
140
     */
141
    protected $ignoreViolationsOnExit = false;
142
143
    /**
144
     * List of available rule-sets.
145
     *
146 41
     * @var array(string)
147
     */
148
    protected $availableRuleSets = array();
149 41
150
    /**
151 41
     * Constructs a new command line options instance.
152
     *
153 41
     * @param string[] $args
154 41
     * @param string[] $availableRuleSets
155 41
     * @throws \InvalidArgumentException
156 41
     */
157 41
    public function __construct(array $args, array $availableRuleSets = array())
158 41
    {
159 1
        // Remove current file name
160 1
        array_shift($args);
161 41
162 41
        $this->availableRuleSets = $availableRuleSets;
163 41
164 1
        $arguments = array();
165 1
        while (($arg = array_shift($args)) !== null) {
166 41
            switch ($arg) {
167 41
                case '--min-priority':
168 4
                case '--minimum-priority':
169 4
                case '--minimumpriority':
170 41
                    $this->minimumPriority = (int)array_shift($args);
171 41
                    break;
172 6
                case '--max-priority':
173 5
                case '--maximum-priority':
174 41
                case '--maximumpriority':
175 1
                    $this->maximumPriority = (int)array_shift($args);
176 1
                    break;
177 41
                case '--report-file':
178 1
                case '--reportfile':
179
                    $this->reportFile = array_shift($args);
180 1
                    break;
181 1
                case '--input-file':
182 41
                case '--inputfile':
183
                    array_unshift($arguments, $this->readInputFile(array_shift($args)));
184
                    break;
185 41
                case '--coverage':
186 1
                    $this->coverageReport = array_shift($args);
187
                    break;
188 1
                case '--extensions':
189 1
                    $this->logDeprecated('extensions', 'suffixes');
190 41
                    /* Deprecated: We use the suffixes option now */
191
                    $this->extensions = array_shift($args);
192
                    break;
193 41
                case '--suffixes':
194 1
                    $this->extensions = array_shift($args);
195
                    break;
196 1
                case '--ignore':
197 40
                    $this->logDeprecated('ignore', 'exclude');
198 1
                    /* Deprecated: We use the exclude option now */
199 1
                    $this->ignore = array_shift($args);
200 40
                    break;
201
                case '--exclude':
202
                    $this->ignore = array_shift($args);
203 40
                    break;
204 1
                case '--version':
205 1
                    $this->version = true;
206 40
207 40
                    return;
208 40
                case '--strict':
209 40
                    $this->strict = true;
210 4
                    break;
211 4
                case '--not-strict':
212 4
                    $this->strict = false;
213
                    break;
214 40
                case '--ignore-errors-on-exit':
215 40
                    $this->ignoreErrorsOnExit = true;
216
                    break;
217
                case '--ignore-violations-on-exit':
218
                    $this->ignoreViolationsOnExit = true;
219 39
                    break;
220 1
                case '--reportfile-html':
221
                case '--reportfile-text':
222
                case '--reportfile-xml':
223 38
                case '--reportfile-json':
224 38
                    preg_match('(^\-\-reportfile\-(xml|html|text|json)$)', $arg, $match);
225 38
                    $this->reportFiles[$match[1]] = array_shift($args);
226 38
                    break;
227
                default:
228
                    $arguments[] = $arg;
229
                    break;
230
            }
231
        }
232
233 6
        if (count($arguments) < 3) {
234
            throw new \InvalidArgumentException($this->usage(), self::INPUT_ERROR);
235 6
        }
236
237
        $this->inputPath = (string)array_shift($arguments);
238
        $this->reportFormat = (string)array_shift($arguments);
239
        $this->ruleSets = (string)array_shift($arguments);
240
    }
241
242
    /**
243 2
     * Returns a php source code filename or directory.
244
     *
245 2
     * @return string
246
     */
247
    public function getInputPath()
248
    {
249
        return $this->inputPath;
250
    }
251
252
    /**
253
     * Returns the specified report format.
254 4
     *
255
     * @return string
256 4
     */
257
    public function getReportFormat()
258
    {
259
        return $this->reportFormat;
260
    }
261
262
    /**
263
     * Returns the output filename for a generated report or <b>null</b> when
264
     * the report should be displayed in STDOUT.
265 8
     *
266
     * @return string
267 8
     */
268
    public function getReportFile()
269
    {
270
        return $this->reportFile;
271
    }
272
273
    /**
274
     * Returns a hash with report files specified for different renderers. The
275 6
     * key represents the report format and the value the report file location.
276
     *
277 6
     * @return array
278
     */
279
    public function getReportFiles()
280
    {
281
        return $this->reportFiles;
282
    }
283
284
    /**
285 6
     * Returns a ruleset filename or a comma-separated string of ruleset
286
     *
287 6
     * @return string
288
     */
289
    public function getRuleSets()
290
    {
291
        return $this->ruleSets;
292
    }
293
294
    /**
295 5
     * Returns the minimum rule priority.
296
     *
297 5
     * @return integer
298
     */
299
    public function getMinimumPriority()
300
    {
301
        return $this->minimumPriority;
302
    }
303
304
    /**
305
     * Returns the maximum rule priority.
306 6
     *
307
     * @return integer
308 6
     */
309
    public function getMaximumPriority()
310
    {
311
        return $this->maximumPriority;
312
    }
313
314
    /**
315
     * Returns the file name of a supplied code coverage report or <b>NULL</b>
316
     * if the user has not supplied the --coverage option.
317 4
     *
318
     * @return string
319 4
     */
320
    public function getCoverageReport()
321
    {
322
        return $this->coverageReport;
323
    }
324
325
    /**
326
     * Returns a string of comma-separated extensions for valid php source code
327
     * filenames or <b>null</b> when this argument was not set.
328 4
     *
329
     * @return string
330 4
     */
331
    public function getExtensions()
332
    {
333
        return $this->extensions;
334
    }
335
336
    /**
337
     * Returns string of comma-separated pattern that is used to exclude
338 6
     * directories or <b>null</b> when this argument was not set.
339
     *
340 6
     * @return string
341
     */
342
    public function getIgnore()
343
    {
344
        return $this->ignore;
345
    }
346
347
    /**
348
     * Was the <b>--version</b> passed to PHPMD's command line interface?
349 6
     *
350
     * @return boolean
351 6
     */
352
    public function hasVersion()
353
    {
354
        return $this->version;
355
    }
356
357
    /**
358
     * Was the <b>--strict</b> option passed to PHPMD's command line interface?
359 6
     *
360
     * @return boolean
361 6
     * @since 1.2.0
362
     */
363
    public function hasStrict()
364
    {
365
        return $this->strict;
366
    }
367
368
    /**
369
     * Was the <b>--ignore-errors-on-exit</b> passed to PHPMD's command line interface?
370
     *
371
     * @return boolean
372
     * @since 2.10.0
373
     */
374
    public function ignoreErrorsOnExit()
375
    {
376
        return $this->ignoreErrorsOnExit;
377
    }
378
379
    /**
380 13
     * Was the <b>--ignore-violations-on-exit</b> passed to PHPMD's command line interface?
381
     *
382 13
     * @return boolean
383
     */
384 13
    public function ignoreViolationsOnExit()
385 13
    {
386 1
        return $this->ignoreViolationsOnExit;
387 12
    }
388 1
389 11
    /**
390 5
     * Creates a report renderer instance based on the user's command line
391 6
     * argument.
392
     *
393 6
     * Valid renderers are:
394 1
     * <ul>
395
     *   <li>xml</li>
396 5
     *   <li>html</li>
397
     *   <li>text</li>
398
     *   <li>json</li>
399
     * </ul>
400
     *
401
     * @param string $reportFormat
402
     * @return \PHPMD\AbstractRenderer
403 1
     * @throws \InvalidArgumentException When the specified renderer does not exist.
404
     */
405 1
    public function createRenderer($reportFormat = null)
406
    {
407
        $reportFormat = $reportFormat ?: $this->reportFormat;
408
409
        switch ($reportFormat) {
410
            case 'xml':
411 5
                return $this->createXmlRenderer();
412
            case 'html':
413 5
                return $this->createHtmlRenderer();
414
            case 'text':
415
                return $this->createTextRenderer();
416
            case 'json':
417
                return $this->createJsonRenderer();
418
            case 'ansi':
419 1
                return $this->createAnsiRenderer();
420
            case 'github':
421 1
                return $this->createGitHubRenderer();
422
            default:
423
                return $this->createCustomRenderer();
424
        }
425
    }
426
427 1
    /**
428
     * @return \PHPMD\Renderer\XMLRenderer
429 1
     */
430
    protected function createXmlRenderer()
431
    {
432
        return new XMLRenderer();
433
    }
434
435
    /**
436
     * @return \PHPMD\Renderer\TextRenderer
437
     */
438
    protected function createTextRenderer()
439
    {
440
        return new TextRenderer();
441
    }
442
443
    /**
444 5
     * @return \PHPMD\Renderer\AnsiRenderer
445
     */
446 5
    protected function createAnsiRenderer()
447 1
    {
448 1
        return new AnsiRenderer();
449 1
    }
450
451
    /**
452
     * @return \PHPMD\Renderer\GitHubRenderer
453 4
     */
454 1
    protected function createGitHubRenderer()
455
    {
456
        return new GitHubRenderer();
457
    }
458 3
459
    /**
460 3
     * @return \PHPMD\Renderer\HTMLRenderer
461 3
     */
462 1
    protected function createHtmlRenderer()
463 1
    {
464 1
        return new HTMLRenderer();
465 1
    }
466
467 1
    /**
468
     * @return \PHPMD\Renderer\JSONRenderer
469
     */
470 2
    protected function createJsonRenderer()
471
    {
472 2
        return new JSONRenderer();
473
    }
474 2
475
    /**
476
     * @return \PHPMD\AbstractRenderer
477
     * @throws \InvalidArgumentException
478
     */
479
    protected function createCustomRenderer()
480
    {
481
        if ('' === $this->reportFormat) {
482 4
            throw new \InvalidArgumentException(
483
                'Can\'t create report with empty format.',
484 4
                self::INPUT_ERROR
485
            );
486
        }
487
488
        if (class_exists($this->reportFormat)) {
489
            return new $this->reportFormat();
490
        }
491
492
        // Try to load a custom renderer
493 4
        $fileName = strtr($this->reportFormat, '_\\', '//') . '.php';
494 4
495 4
        $fileHandle = @fopen($fileName, 'r', true);
496 4
        if (is_resource($fileHandle) === false) {
497 4
            throw new \InvalidArgumentException(
498 4
                sprintf(
499 4
                    'Can\'t find the custom report class: %s',
500 4
                    $this->reportFormat
501 4
                ),
502 4
                self::INPUT_ERROR
503 4
            );
504 4
        }
505 4
        @fclose($fileHandle);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
506 4
507 4
        include_once $fileName;
508 4
509
        return new $this->reportFormat();
510
    }
511
512
    /**
513
     * Returns usage information for the PHPMD command line interface.
514
     *
515
     * @return string
516 4
     */
517
    public function usage()
518 4
    {
519 4
        $availableRenderers = $this->getListOfAvailableRenderers();
520
521 4
        return 'Mandatory arguments:' . \PHP_EOL .
522 4
            '1) A php source code filename or directory. Can be a comma-' .
523 4
            'separated string' . \PHP_EOL .
524
            '2) A report format' . \PHP_EOL .
525
            '3) A ruleset filename or a comma-separated string of ruleset' .
526
            'filenames' . \PHP_EOL . \PHP_EOL .
527 4
            'Example: phpmd /path/to/source format ruleset' . \PHP_EOL . \PHP_EOL .
528
            'Available formats: ' . $availableRenderers . '.' . \PHP_EOL .
529 4
            'Available rulesets: ' . implode(', ', $this->availableRuleSets) . '.' . \PHP_EOL . \PHP_EOL .
530 4
            'Optional arguments that may be put after the mandatory arguments:' .
531
            \PHP_EOL .
532
            '--minimumpriority: rule priority threshold; rules with lower ' .
533
            'priority than this will not be used' . \PHP_EOL .
534
            '--reportfile: send report output to a file; default to STDOUT' .
535
            \PHP_EOL .
536
            '--suffixes: comma-separated string of valid source code ' .
537
            'filename extensions, e.g. php,phtml' . \PHP_EOL .
538
            '--exclude: comma-separated string of patterns that are used to ' .
539
            'ignore directories. Use asterisks to exclude by pattern. ' .
540
            'For example *src/foo/*.php or *src/foo/*' . \PHP_EOL .
541
            '--strict: also report those nodes with a @SuppressWarnings ' .
542
            'annotation' . \PHP_EOL .
543 2
            '--ignore-errors-on-exit: will exit with a zero code, ' .
544
            'even on error' . \PHP_EOL .
545 2
            '--ignore-violations-on-exit: will exit with a zero code, ' .
546 2
            'even if any violations are found' . \PHP_EOL;
547
    }
548
549
    /**
550
     * Get a list of available renderers
551 2
     *
552 2
     * @return string The list of renderers found.
553
     */
554
    protected function getListOfAvailableRenderers()
555
    {
556
        $renderersDirPathName = __DIR__ . '/../Renderer';
557
        $renderers = array();
558
559
        foreach (scandir($renderersDirPathName) as $rendererFileName) {
560
            if (preg_match('/^(\w+)Renderer.php$/i', $rendererFileName, $rendererName)) {
561
                $renderers[] = strtolower($rendererName[1]);
562
            }
563
        }
564
565 6
        sort($renderers);
566
567 6
        if (count($renderers) > 1) {
568 5
            return implode(', ', $renderers);
569
        }
570 1
571
        return array_pop($renderers);
572
    }
573
574
    /**
575
     * Logs a deprecated option to the current user interface.
576
     *
577
     * @param string $deprecatedName
578
     * @param string $newName
579
     * @return void
580
     */
581
    protected function logDeprecated($deprecatedName, $newName)
582
    {
583
        $message = sprintf(
584
            'The --%s option is deprecated, please use --%s instead.',
585
            $deprecatedName,
586
            $newName
587
        );
588
589
        fwrite(STDERR, $message . PHP_EOL . PHP_EOL);
590
    }
591
592
    /**
593
     * This method takes the given input file, reads the newline separated paths
594
     * from that file and creates a comma separated string of the file paths. If
595
     * the given <b>$inputFile</b> not exists, this method will throw an
596
     * exception.
597
     *
598
     * @param string $inputFile Specified input file name.
599
     * @return string
600
     * @throws \InvalidArgumentException If the specified input file does not exist.
601
     * @since 1.1.0
602
     */
603
    protected function readInputFile($inputFile)
604
    {
605
        if (file_exists($inputFile)) {
606
            return implode(',', array_map('trim', file($inputFile)));
607
        }
608
        throw new \InvalidArgumentException("Input file '{$inputFile}' not exists.");
609
    }
610
}
611