Passed
Pull Request — master (#22)
by
unknown
12:11
created

ReportCommand   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 10
Bugs 2 Features 4
Metric Value
wmc 26
eloc 108
c 10
b 2
f 4
dl 0
loc 207
ccs 0
cts 90
cp 0
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 40 1
A groupDependenciesByLicense() 0 14 3
B outputFormattedLicenses() 0 41 6
A outputFormatPackages() 0 16 4
A execute() 0 21 3
A isValidLicenseByFilter() 0 7 2
A filterLicenses() 0 14 4
A lookUpLicenses() 0 13 3
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->filterLicenses(array_keys($groupedByName), $input->getOption('filter'));
84
        $licenses = $this->lookUpLicenses($licenses, $output, $shouldCache);
85
86
        /* @var License $license */
87
        $this->outputFormattedLicenses($output, $input, $licenses, $groupedByName);
88
89
        return 0;
90
    }
91
92
    private function isValidLicenseByFilter(string $licence, array $filters): bool
93
    {
94
        if ($filters !== []) {
95
            return in_array(strtolower($licence), array_map('strtolower', $filters));
96
        }
97
98
        return true;
99
    }
100
101
    /**
102
     * @param  Dependency[]  $dependencies
103
     * @return array
104
     */
105
    private function groupDependenciesByLicense(array $dependencies): array
106
    {
107
        $grouped = [];
108
109
        foreach ($dependencies as $dependency) {
110
            [$license] = $dependency->getLicenses();
111
112
            if (! isset($grouped[$license])) {
113
                $grouped[$license] = [];
114
            }
115
            $grouped[$license][] = $dependency;
116
        }
117
118
        return $grouped;
119
    }
120
121
    private function filterLicenses(array $licences, array $filters): array
122
    {
123
        if ($filters === []) {
124
            return $licences;
125
        }
126
127
        $validLicences = [];
128
        foreach ($licences as $license) {
129
            if ($this->isValidLicenseByFilter($license, $filters)) {
130
                $validLicences[] = $license;
131
            }
132
        }
133
134
        return $validLicences;
135
    }
136
137
    private function lookUpLicenses(array $licenses, OutputInterface $output, $useCache = true): array
138
    {
139
        if (! $useCache) {
140
            $this->licenseLookup->setCache(new NullAdapter);
141
        }
142
143
        $lookedUp = [];
144
        foreach ($licenses as $license) {
145
            $output->writeln("Looking up $license ...");
146
            $lookedUp[$license] = $this->licenseLookup->lookUp($license);
147
        }
148
149
        return $lookedUp;
150
    }
151
152
    /**
153
     * @param  OutputInterface  $output
154
     * @param  InputInterface  $input
155
     * @param  License[]  $licenses
156
     * @param  array  $groupedByName
157
     */
158
    protected function outputFormattedLicenses(OutputInterface $output, InputInterface $input, array $licenses, array $groupedByName): void
159
    {
160
        foreach ($licenses as $license) {
161
            $dependencies = $groupedByName[$license->getShortName()];
162
163
            $usageCount = count($dependencies);
164
            $headline = sprintf(PHP_EOL.'Count %d - %s (%s)', $usageCount, $license->getShortName(),
165
                $license->getSource());
166
            $output->writeln($headline);
167
            $licenseTable = new Table($output);
168
            $licenseTable->setHeaders(['CAN', 'CAN NOT', 'MUST']);
169
170
            $can = $license->getCan();
171
            $cannot = $license->getCannot();
172
            $must = $license->getMust();
173
            $columnWidth = max(count($can), count($cannot), count($must));
174
175
            $can = array_pad($can, $columnWidth, null);
176
            $cannot = array_pad($cannot, $columnWidth, null);
177
            $must = array_pad($must, $columnWidth, null);
178
179
            $inlineHeading = function ($key) {
180
                return is_string($key) ? $key : '';
181
            };
182
183
            $can = array_map_keys($can, $inlineHeading);
184
            $cannot = array_map_keys($cannot, $inlineHeading);
185
            $must = array_map_keys($must, $inlineHeading);
186
187
            for ($i = 0; $i < $columnWidth; $i++) {
188
                $licenseTable->addRow([
189
                    'CAN'    => $can[$i],
190
                    'CANNOT' => $cannot[$i],
191
                    'MUST'   => $must[$i],
192
                ]);
193
            }
194
            $licenseTable->render();
195
196
            if ($input->getOption('show-packages') || $output->isVerbose()) {
197
                $output->writeln('');
198
                $output->writeln($this->outputFormatPackages($input, $dependencies));
199
            }
200
        }
201
    }
202
203
    /**
204
     * Generates a output string for the 'show-packages' option.
205
     *
206
     * @param  InputInterface  $input
207
     * @param  array  $dependencies
208
     * @return string
209
     */
210
    protected function outputFormatPackages(InputInterface $input, array $dependencies): string
211
    {
212
        $packages = [];
213
        if ($input->getOption('grouped')) {
214
            foreach ($dependencies as $dependency) {
215
                $packages[] = $dependency->getName();
216
            }
217
218
            return 'packages: '.implode(', ', $packages);
219
        }
220
221
        foreach ($dependencies as $dependency) {
222
            $packages[] = sprintf('%s (%s)', $dependency->getName(), $dependency->getVersion());
223
        }
224
225
        return implode(PHP_EOL, $packages);
226
    }
227
}
228