Passed
Pull Request — master (#22)
by
unknown
02:20
created

ReportCommand   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 8
Bugs 1 Features 4
Metric Value
wmc 24
eloc 102
c 8
b 1
f 4
dl 0
loc 193
ccs 0
cts 83
cp 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A groupDependenciesByLicense() 0 14 3
A configure() 0 40 1
B outputFormattedLicenses() 0 42 7
A outputFormatPackages() 0 16 4
A execute() 0 20 3
A isValidLicenseByFilter() 0 7 2
A lookUpLicenses() 0 15 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Dominikb\ComposerLicenseChecker;
6
7
use Dominikb\ComposerLicenseChecker\Contracts\DependencyLoaderAware;
8
use Dominikb\ComposerLicenseChecker\Contracts\LicenseLookupAware;
9
use Dominikb\ComposerLicenseChecker\Traits\DependencyLoaderAwareTrait;
10
use Dominikb\ComposerLicenseChecker\Traits\LicenseLookupAwareTrait;
11
use Symfony\Component\Cache\Adapter\NullAdapter;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Helper\Table;
14
use Symfony\Component\Console\Input\InputDefinition;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Input\InputOption;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
class ReportCommand extends Command implements LicenseLookupAware, DependencyLoaderAware
20
{
21
    use LicenseLookupAwareTrait, DependencyLoaderAwareTrait;
22
23
    protected static $defaultName = 'report';
24
25
    protected function configure()
26
    {
27
        $this->setDefinition(new InputDefinition([
28
            new InputOption(
29
                'project-path',
30
                'p',
31
                InputOption::VALUE_OPTIONAL,
32
                'Path to directory of composer.json file',
33
                realpath('.')
34
            ),
35
            new InputOption(
36
                'composer',
37
                'c',
38
                InputOption::VALUE_OPTIONAL,
39
                'Path to composer executable',
40
                realpath('./vendor/bin/composer')
41
            ),
42
            new InputOption(
43
                'no-cache',
44
                null,
45
                InputOption::VALUE_NONE,
46
                'Disables caching of license lookups'
47
            ),
48
            new InputOption(
49
                'show-packages',
50
                null,
51
                InputOption::VALUE_NONE,
52
                'Shows the packages for each license.'
53
            ),
54
            new InputOption(
55
                'grouped',
56
                null,
57
                InputOption::VALUE_NONE,
58
                'Display the packages grouped. Only valid with the \'show-packages\' option.'
59
            ),
60
            new InputOption(
61
                'filter',
62
                null,
63
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
64
                'Filter for specific licences.'
65
            ),
66
        ]));
67
    }
68
69
    protected function execute(InputInterface $input, OutputInterface $output): int
70
    {
71
        if ($input->getOption('grouped') && ! $input->getOption('show-packages')) {
72
            throw new \InvalidArgumentException('The option "grouped" is only allowed with "show-packages" option');
73
        }
74
75
        $dependencies = $this->dependencyLoader->loadDependencies(
76
            $input->getOption('composer'),
77
            $input->getOption('project-path')
78
        );
79
80
        $groupedByName = $this->groupDependenciesByLicense($dependencies);
81
82
        $shouldCache = ! $input->getOption('no-cache');
83
        $licenses = $this->lookUpLicenses(array_keys($groupedByName), $input, $output, $shouldCache);
84
85
        /* @var License $license */
86
        $this->outputFormattedLicenses($output, $input, $licenses, $groupedByName);
87
88
        return 0;
89
    }
90
91
    private function isValidLicenseByFilter(string $licence, InputInterface $input): bool
92
    {
93
        if ($input->getOption('filter') !== []) {
94
            return in_array(strtolower($licence), array_map('strtolower', $input->getOption('filter')));
95
        }
96
97
        return true;
98
    }
99
100
    /**
101
     * @param  Dependency[]  $dependencies
102
     * @return array
103
     */
104
    private function groupDependenciesByLicense(array $dependencies): array
105
    {
106
        $grouped = [];
107
108
        foreach ($dependencies as $dependency) {
109
            [$license] = $dependency->getLicenses();
110
111
            if (! isset($grouped[$license])) {
112
                $grouped[$license] = [];
113
            }
114
            $grouped[$license][] = $dependency;
115
        }
116
117
        return $grouped;
118
    }
119
120
    private function lookUpLicenses(array $licenses, InputInterface $input, OutputInterface $output, $useCache = true): array
121
    {
122
        if (! $useCache) {
123
            $this->licenseLookup->setCache(new NullAdapter);
124
        }
125
126
        $lookedUp = [];
127
        foreach ($licenses as $license) {
128
            if ($this->isValidLicenseByFilter($license, $input)) {
129
                $output->writeln("Looking up $license ...");
130
                $lookedUp[$license] = $this->licenseLookup->lookUp($license);
131
            }
132
        }
133
134
        return $lookedUp;
135
    }
136
137
    /**
138
     * @param  OutputInterface  $output
139
     * @param  InputInterface  $input
140
     * @param  License[]  $licenses
141
     * @param  array  $groupedByName
142
     */
143
    protected function outputFormattedLicenses(OutputInterface $output, InputInterface $input, array $licenses, array $groupedByName): void
144
    {
145
        foreach ($licenses as $license) {
146
            $dependencies = $groupedByName[$license->getShortName()];
147
148
            $usageCount = count($dependencies);
149
            $headline = sprintf(PHP_EOL.'Count %d - %s (%s)', $usageCount, $license->getShortName(),
150
                $license->getSource());
151
            $output->writeln($headline);
152
            $licenseTable = new Table($output);
153
            $licenseTable->setHeaders(['CAN', 'CAN NOT', 'MUST']);
154
155
            $can = $license->getCan();
156
            $cannot = $license->getCannot();
157
            $must = $license->getMust();
158
            $columnWidth = max(count($can), count($cannot), count($must));
159
160
            $can = array_pad($can, $columnWidth, null);
161
            $cannot = array_pad($cannot, $columnWidth, null);
162
            $must = array_pad($must, $columnWidth, null);
163
164
            $inlineHeading = function ($key) {
165
                return is_string($key) ? $key : '';
166
            };
167
168
            $can = array_map_keys($can, $inlineHeading);
169
            $cannot = array_map_keys($cannot, $inlineHeading);
170
            $must = array_map_keys($must, $inlineHeading);
171
172
            for ($i = 0; $i < $columnWidth; $i++) {
173
                $licenseTable->addRow([
174
                    'CAN'    => $can[$i],
175
                    'CANNOT' => $cannot[$i],
176
                    'MUST'   => $must[$i],
177
                ]);
178
            }
179
            $licenseTable->render();
180
181
            if ($input->getOption('show-packages') || $output->isVerbose()) {
182
                if ($out = $this->outputFormatPackages($input, $dependencies)) {
183
                    $output->writeln('');
184
                    $output->writeln($out);
185
                }
186
            }
187
        }
188
    }
189
190
    /**
191
     * Generates a output string for the 'show-packages' option.
192
     * @param  InputInterface  $input
193
     * @param  array  $dependencies
194
     * @return string
195
     */
196
    protected function outputFormatPackages(InputInterface $input, array $dependencies): string
197
    {
198
        $packages = [];
199
        if ($input->getOption('grouped')) {
200
            foreach ($dependencies as $dependency) {
201
                $packages[] = $dependency->getName();
202
            }
203
204
            return 'packages: '.implode(', ', $packages);
205
        }
206
207
        foreach ($dependencies as $dependency) {
208
            $packages[] = sprintf('%s (%s)', $dependency->getName(), $dependency->getVersion());
209
        }
210
211
        return implode(PHP_EOL, $packages);
212
    }
213
}
214