Completed
Push — master ( 4544d3...e2a407 )
by Dominik
01:29
created

CheckCommand   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
dl 0
loc 128
rs 10
c 0
b 0
f 0
wmc 14
lcom 1
cbo 13

6 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 31 1
A execute() 0 15 1
A ensureCommandCanBeExecuted() 0 10 3
A determineViolations() 0 7 1
A handleViolations() 0 13 4
A reportViolators() 0 21 4
1
<?php
2
3
namespace Dominikb\ComposerLicenseChecker;
4
5
use Dominikb\ComposerLicenseChecker\Contracts\DependencyLoaderAware;
6
use Dominikb\ComposerLicenseChecker\Traits\DependencyLoaderAwareTrait;
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Input\InputDefinition;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Logger\ConsoleLogger;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Dominikb\ComposerLicenseChecker\Contracts\LicenseLookupAware;
14
use Dominikb\ComposerLicenseChecker\Traits\LicenseLookupAwareTrait;
15
use Dominikb\ComposerLicenseChecker\Contracts\LicenseConstraintAware;
16
use Dominikb\ComposerLicenseChecker\Traits\LicenseConstraintAwareTrait;
17
use Dominikb\ComposerLicenseChecker\Exceptions\CommandExecutionException;
18
19
class CheckCommand extends Command implements LicenseLookupAware, LicenseConstraintAware, DependencyLoaderAware
20
{
21
    use LicenseLookupAwareTrait, LicenseConstraintAwareTrait, DependencyLoaderAwareTrait;
22
23
    const LINES_BEFORE_DEPENDENCY_VERSIONS = 2;
24
25
    protected static $defaultName = 'check';
26
27
    /** @var ConsoleLogger */
28
    private $logger;
29
30
    protected function configure()
31
    {
32
        $this->setDefinition(new InputDefinition([
33
            new InputOption(
34
                'project-path',
35
                'p',
36
                InputOption::VALUE_OPTIONAL,
37
                'Path to directory of composer.json file',
38
                realpath('.')
39
            ),
40
            new InputOption(
41
                'composer',
42
                'c',
43
                InputOption::VALUE_OPTIONAL,
44
                'Path to composer executable',
45
                realpath('./vendor/bin/composer')
46
            ),
47
            new InputOption(
48
                'whitelist',
49
                'w',
50
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
51
                'Set a list of licenses you want to permit for usage'
52
            ),
53
            new InputOption(
54
                'blacklist',
55
                'b',
56
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
57
                'Set a list of licenses you want to forbid for usage'
58
            )
59
        ]));
60
    }
61
62
    /**
63
     * @throws CommandExecutionException
64
     */
65
    public function execute(InputInterface $input, OutputInterface $output): void
66
    {
67
        $this->logger = new ConsoleLogger($output);
68
69
        $this->ensureCommandCanBeExecuted();
70
71
        $dependencies = $this->dependencyLoader->loadDependencies(
72
            $input->getOption('composer'),
73
            $input->getOption('project-path')
74
        );
75
76
        $violations = $this->determineViolations($dependencies, $input->getOption('blacklist'), $input->getOption('whitelist'));
77
78
        $this->handleViolations($violations);
79
    }
80
81
    /**
82
     * @throws CommandExecutionException
83
     */
84
    private function ensureCommandCanBeExecuted(): void
85
    {
86
        if (! $this->licenseLookup) {
87
            throw new CommandExecutionException('LicenseLookup must be set via setLicenseLookup() before the command can be executed!');
88
        }
89
90
        if (! $this->dependencyLoader) {
91
            throw new CommandExecutionException('DependencyLoader must be set via setDependencyLoader() before the command can be executed!');
92
        }
93
    }
94
95
    private function determineViolations(array $dependencies, array $blacklist, array $whitelist): array
96
    {
97
        $this->licenseConstraintHandler->setBlacklist($blacklist);
98
        $this->licenseConstraintHandler->setWhitelist($whitelist);
99
100
        return $this->licenseConstraintHandler->detectViolations($dependencies);
101
    }
102
103
    /**
104
     * @param ConstraintViolation[] $violations
105
     *
106
     *@throws CommandExecutionException
107
*/
108
    private function handleViolations(array $violations): void
109
    {
110
        foreach ($violations as $violation) {
111
            if ($violation->hasViolators()) {
112
                $this->logger->error($violation->getTitle());
113
                $this->reportViolators($violation->getViolators());
114
            }
115
        }
116
117
        if ($this->logger->hasErrored()) {
118
            throw new CommandExecutionException('Violators found during execution!');
119
        }
120
    }
121
122
    /**
123
     * @param Dependency[] $violators
124
     */
125
    private function reportViolators(array $violators): void
126
    {
127
        $byLicense = [];
128
        foreach ($violators as $violator) {
129
            $license = $violator->getLicenses()[0];
130
131
            if (! isset($byLicense[$license])) {
132
                $byLicense[$license] = [];
133
            }
134
            $byLicense[$license][] = $violator;
135
        }
136
137
        foreach ($byLicense as $license => $violators) {
138
            $violatorNames = array_map(function (Dependency $dependency) {
139
                return sprintf('"%s"', $dependency->getName());
140
            }, $violators);
141
142
            $this->logger->notice("$license:");
143
            $this->logger->info(implode(',', $violatorNames));
144
        }
145
    }
146
}
147