Passed
Pull Request — master (#22)
by
unknown
03:00 queued 21s
created

ReportCommand::groupDependenciesByLicense()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 7
c 2
b 0
f 1
dl 0
loc 14
ccs 0
cts 8
cp 0
rs 10
cc 3
nc 3
nop 1
crap 12
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.'
59
            ),
60
            new InputOption(
61
                'filter',
62
                null,
63
                InputOption::VALUE_REQUIRED,
64
                'Filter for specific licences.'
65
            ),
66
        ]));
67
    }
68
69
    protected function execute(InputInterface $input, OutputInterface $output): int
70
    {
71
        $dependencies = $this->dependencyLoader->loadDependencies(
72
            $input->getOption('composer'),
73
            $input->getOption('project-path')
74
        );
75
76
        $groupedByName = $this->groupDependenciesByLicense($dependencies);
77
78
        $shouldCache = ! $input->getOption('no-cache');
79
        $licenses = $this->lookUpLicenses(array_keys($groupedByName), $output, $shouldCache);
80
81
        /* @var License $license */
82
        $this->outputFormattedLicenses($output, $input, $licenses, $groupedByName);
83
84
        return 0;
85
    }
86
87
    /**
88
     * @param  Dependency[]  $dependencies
89
     * @return array
90
     */
91
    private function groupDependenciesByLicense(array $dependencies): array
92
    {
93
        $grouped = [];
94
95
        foreach ($dependencies as $dependency) {
96
            [$license] = $dependency->getLicenses();
97
98
            if (! isset($grouped[$license])) {
99
                $grouped[$license] = [];
100
            }
101
            $grouped[$license][] = $dependency;
102
        }
103
104
        return $grouped;
105
    }
106
107
    private function lookUpLicenses(array $licenses, OutputInterface $output, $useCache = true): array
108
    {
109
        if (! $useCache) {
110
            $this->licenseLookup->setCache(new NullAdapter);
111
        }
112
113
        $lookedUp = [];
114
        foreach ($licenses as $license) {
115
            $output->writeln("Looking up $license ...");
116
            $lookedUp[$license] = $this->licenseLookup->lookUp($license);
117
        }
118
119
        return $lookedUp;
120
    }
121
122
    /**
123
     * @param  OutputInterface  $output
124
     * @param  InputInterface  $input
125
     * @param  License[]  $licenses
126
     * @param  array  $groupedByName
127
     */
128
    protected function outputFormattedLicenses(OutputInterface $output, InputInterface $input, array $licenses, array $groupedByName): void
129
    {
130
        foreach ($licenses as $license) {
131
            if ($input->getOption('filter')) {
132
                $licenses = explode(',', $input->getOption('filter'));
133
                $licenses = array_map(function ($licence) {
134
                    return trim($licence);
135
                }, $licenses);
136
137
                if (! in_array($license->getShortName(), $licenses)) {
138
                    $output->writeln(sprintf("Skipped %s", $license->getShortName()), OutputInterface::VERBOSITY_VERY_VERBOSE);
139
                    continue;
140
                }
141
            }
142
143
            $dependencies = $groupedByName[$license->getShortName()];
144
145
            $usageCount = count($dependencies);
146
            $headline = sprintf(PHP_EOL.'Count %d - %s (%s)', $usageCount, $license->getShortName(),
147
                $license->getSource());
148
            $output->writeln($headline);
149
            $licenseTable = new Table($output);
150
            $licenseTable->setHeaders(['CAN', 'CAN NOT', 'MUST']);
151
152
            $can = $license->getCan();
153
            $cannot = $license->getCannot();
154
            $must = $license->getMust();
155
            $columnWidth = max(count($can), count($cannot), count($must));
156
157
            $can = array_pad($can, $columnWidth, null);
158
            $cannot = array_pad($cannot, $columnWidth, null);
159
            $must = array_pad($must, $columnWidth, null);
160
161
            $inlineHeading = function ($key) {
162
                return is_string($key) ? $key : '';
163
            };
164
165
            $can = array_map_keys($can, $inlineHeading);
166
            $cannot = array_map_keys($cannot, $inlineHeading);
167
            $must = array_map_keys($must, $inlineHeading);
168
169
            for ($i = 0; $i < $columnWidth; $i++) {
170
                $licenseTable->addRow([
171
                    'CAN'    => $can[$i],
172
                    'CANNOT' => $cannot[$i],
173
                    'MUST'   => $must[$i],
174
                ]);
175
            }
176
            $licenseTable->render();
177
178
            if ($input->getOption('show-packages') || $output->isVerbose()) {
179
                $output->writeln('');
180
181
                if ($input->getOption('grouped')) {
182
                    $output->write('packages: ');
183
                    $packages = [];
184
                    foreach ($dependencies as $dependency) {
185
                        $packages[] = $dependency->getName();
186
                    }
187
188
                    $output->write(implode(', ', $packages));
189
                    continue;
190
                }
191
192
                foreach ($dependencies as $dependency) {
193
                    $output->writeln(sprintf('%s (%s)', $dependency->getName(), $dependency->getVersion()));
194
                }
195
            }
196
        }
197
    }
198
}
199