Passed
Pull Request — master (#467)
by
unknown
04:08
created

ComposerOrchestrator::getVersion()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 20
rs 9.9332
cc 3
nc 4
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Composer;
16
17
use Humbug\PhpScoper\Autoload\ScoperAutoloadGenerator;
18
use Humbug\PhpScoper\Whitelist;
19
use KevinGH\Box\Console\IO\IO;
20
use KevinGH\Box\Console\Logger\CompilerLogger;
21
use function KevinGH\Box\FileSystem\dump_file;
22
use function KevinGH\Box\FileSystem\file_contents;
23
use KevinGH\Box\NotInstantiable;
24
use const PHP_EOL;
25
use function preg_replace;
26
use RuntimeException;
27
use function str_replace;
28
use Symfony\Component\Console\Output\OutputInterface;
29
use Symfony\Component\Process\Exception\ProcessFailedException;
30
use Symfony\Component\Process\ExecutableFinder;
31
use Symfony\Component\Process\Process;
32
use function trim;
33
34
/**
35
 * @private
36
 */
37
final class ComposerOrchestrator
38
{
39
    use NotInstantiable;
40
41
    public static function getVersion(): string
42
    {
43
        $composerExecutable = self::retrieveComposerExecutable();
44
        $command = [$composerExecutable, '--version'];
45
46
        $getVersionProcess = new Process($command);
47
48
        $getVersionProcess->run();
49
50
        if (false === $getVersionProcess->isSuccessful()) {
51
            new ProcessFailedException($getVersionProcess);
52
        }
53
54
        $output = $getVersionProcess->getOutput();
55
56
        if (preg_match('/^Composer version ([^\\s]+)/', $output, $match) > 0) {
57
            return $match[1];
58
        }
59
60
        throw new RuntimeException('Could not determine the Composer version.');
61
    }
62
63
    public static function dumpAutoload(
64
        Whitelist $whitelist,
65
        string $prefix,
66
        bool $excludeDevFiles,
67
        IO $io = null
68
    ): void {
69
        if (null === $io) {
70
            $io = IO::createNull();
71
        }
72
73
        $logger = new CompilerLogger($io);
74
75
        $composerExecutable = self::retrieveComposerExecutable();
76
77
        self::dumpAutoloader($composerExecutable, true === $excludeDevFiles, $logger);
78
79
        if ('' !== $prefix) {
80
            $autoloadFile = self::retrieveAutoloadFile($composerExecutable, $logger);
81
82
            $autoloadContents = self::generateAutoloadStatements(
83
                $whitelist,
84
                $prefix,
85
                file_contents($autoloadFile)
86
            );
87
88
            dump_file($autoloadFile, $autoloadContents);
89
        }
90
    }
91
92
    private static function generateAutoloadStatements(Whitelist $whitelist, string $prefix, string $autoload): string
0 ignored issues
show
Unused Code introduced by
The parameter $prefix is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

92
    private static function generateAutoloadStatements(Whitelist $whitelist, /** @scrutinizer ignore-unused */ string $prefix, string $autoload): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
93
    {
94
        if ([] === $whitelist->toArray()) {
95
            return $autoload;
96
        }
97
98
        $autoload = str_replace('<?php', '', $autoload);
99
100
        $autoload = preg_replace(
101
            '/return (ComposerAutoloaderInit.+::getLoader\(\));/',
102
            '\$loader = $1;',
103
            $autoload
104
        );
105
106
        $whitelistStatements = (new ScoperAutoloadGenerator($whitelist))->dump();
107
108
        $whitelistStatements = preg_replace(
109
            '/scoper\-autoload\.php \@generated by PhpScoper/',
110
            '@generated by Humbug Box',
111
            $whitelistStatements
112
        );
113
114
        $whitelistStatements = preg_replace(
115
            '/(\s*\\$loader \= .*)/',
116
            $autoload,
117
            $whitelistStatements
118
        );
119
120
        return preg_replace(
121
            '/\n{2,}/m',
122
            PHP_EOL.PHP_EOL,
123
            $whitelistStatements
124
        );
125
    }
126
127
    private static function retrieveComposerExecutable(): string
128
    {
129
        $executableFinder = new ExecutableFinder();
130
        $executableFinder->addSuffix('.phar');
131
132
        if (null === $composer = $executableFinder->find('composer')) {
133
            throw new RuntimeException('Could not find a Composer executable.');
134
        }
135
136
        return $composer;
137
    }
138
139
    private static function dumpAutoloader(string $composerExecutable, bool $noDev, CompilerLogger $logger): void
140
    {
141
        $composerCommand = [$composerExecutable, 'dump-autoload', '--classmap-authoritative'];
142
143
        if (true === $noDev) {
144
            $composerCommand[] = '--no-dev';
145
        }
146
147
        if (null !== $verbosity = self::retrieveSubProcessVerbosity($logger->getIO())) {
148
            $composerCommand[] = $verbosity;
149
        }
150
151
        if ($logger->getIO()->isDecorated()) {
152
            $composerCommand[] = '--ansi';
153
        }
154
155
        $dumpAutoloadProcess = new Process($composerCommand);
156
157
        $logger->log(
158
            CompilerLogger::CHEVRON_PREFIX,
159
            $dumpAutoloadProcess->getCommandLine(),
160
            OutputInterface::VERBOSITY_VERBOSE
161
        );
162
163
        $dumpAutoloadProcess->run();
164
165
        if (false === $dumpAutoloadProcess->isSuccessful()) {
166
            throw new RuntimeException(
167
                'Could not dump the autoloader.',
168
                0,
169
                new ProcessFailedException($dumpAutoloadProcess)
170
            );
171
        }
172
173
        if ('' !== $output = $dumpAutoloadProcess->getOutput()) {
174
            $logger->getIO()->writeln($output, OutputInterface::VERBOSITY_VERBOSE);
175
        }
176
177
        if ('' !== $output = $dumpAutoloadProcess->getErrorOutput()) {
178
            $logger->getIO()->writeln($output, OutputInterface::VERBOSITY_VERBOSE);
179
        }
180
    }
181
182
    private static function retrieveAutoloadFile(string $composerExecutable, CompilerLogger $logger): string
183
    {
184
        $command = [$composerExecutable, 'config', 'vendor-dir'];
185
186
        if ($logger->getIO()->isDecorated()) {
187
            $command[] = '--ansi';
188
        }
189
190
        $vendorDirProcess = new Process($command);
191
192
        $logger->log(
193
            CompilerLogger::CHEVRON_PREFIX,
194
            $vendorDirProcess->getCommandLine(),
195
            OutputInterface::VERBOSITY_VERBOSE
196
        );
197
198
        $vendorDirProcess->run();
199
200
        if (false === $vendorDirProcess->isSuccessful()) {
201
            new ProcessFailedException($vendorDirProcess);
202
        }
203
204
        return trim($vendorDirProcess->getOutput()).'/autoload.php';
205
    }
206
207
    private static function retrieveSubProcessVerbosity(IO $io): ?string
208
    {
209
        if ($io->isDebug()) {
210
            return '-vvv';
211
        }
212
213
        if ($io->isVeryVerbose()) {
214
            return '-v';
215
        }
216
217
        return null;
218
    }
219
}
220