Passed
Push — master ( 165520...cfabca )
by Théo
12:07 queued 10:05
created

ConfigLoader::generateRandomPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Humbug\PhpScoper\Console;
6
7
use Fidry\Console\Command\CommandRegistry;
8
use Fidry\Console\IO;
9
use Humbug\PhpScoper\Configuration;
10
use Symfony\Component\Console\Exception\RuntimeException;
11
use Symfony\Component\Console\Input\StringInput;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Filesystem\Filesystem;
14
use function bin2hex;
15
use function count;
16
use function file_exists;
17
use function random_bytes;
18
use function Safe\sprintf;
19
use function trim;
20
use const DIRECTORY_SEPARATOR;
21
22
/**
23
 * @private
24
 */
25
final class ConfigLoader
26
{
27
    private CommandRegistry $commandRegistry;
28
    private Filesystem $fileSystem;
29
30
    public function __construct(
31
        CommandRegistry $commandRegistry,
32
        Filesystem $fileSystem
33
    ) {
34
        $this->commandRegistry = $commandRegistry;
35
        $this->fileSystem = $fileSystem;
36
    }
37
38
    /**
39
     * @param string[] $paths
40
     */
41
    public function loadConfig(
42
        IO $io,
43
        string $prefix,
44
        bool $noConfig,
45
        ?string $configFilePath,
46
        string $defaultConfigFilePath,
47
        bool $isInitCommandExecuted,
48
        array $paths,
49
        string $cwd
50
    ): Configuration
51
    {
52
        $prefix = trim($prefix);
53
54
        if ($noConfig) {
55
            return self::loadConfigWithoutConfigFile(
56
                $io,
57
                $prefix,
58
                $paths,
59
                $cwd,
60
            );
61
        }
62
63
        if (null === $configFilePath && !$isInitCommandExecuted) {
64
            $configFilePath = $this->loadDefaultConfig(
65
                $io,
66
                $this->makeAbsolutePath($defaultConfigFilePath, $cwd),
67
            );
68
69
            if (null === $configFilePath) {
70
                return $this->loadConfig(
71
                    $io,
72
                    $prefix,
73
                    $noConfig,
74
                    $configFilePath,
75
                    $defaultConfigFilePath,
76
                    true,
77
                    $paths,
78
                    $cwd,
79
                );
80
            }
81
        } elseif (null !== $configFilePath) {
82
            $configFilePath = $this->makeAbsolutePath(
83
                $configFilePath,
84
                $cwd,
85
            );
86
        }
87
88
        self::logConfigFilePathFound($io, $configFilePath);
89
90
        return self::loadConfiguration($configFilePath, $prefix, $paths, $cwd);
91
    }
92
93
    /**
94
     * @param string[] $paths
95
     */
96
    private static function loadConfigWithoutConfigFile(
97
        IO $io,
98
        string $prefix,
99
        array $paths,
100
        string $cwd
101
    ): Configuration
102
    {
103
        $io->writeln(
104
            'Loading without configuration file.',
105
            OutputInterface::VERBOSITY_DEBUG
106
        );
107
108
        return self::loadConfiguration(null, $prefix, $paths, $cwd);
109
    }
110
111
    /**
112
     * @return string|null Config file path when found otherwise executes the init command
113
     */
114
    private function loadDefaultConfig(IO $io, string $defaultConfigFilePath): ?string
115
    {
116
        $configFilePath = $defaultConfigFilePath;
117
118
        if (file_exists($configFilePath)) {
119
            return $configFilePath;
120
        }
121
122
        $initInput = new StringInput('');
123
        $initInput->setInteractive($io->isInteractive());
124
125
        $this->commandRegistry
126
            ->getCommand('init')
127
            ->execute(
128
                new IO(
129
                    $initInput,
130
                    $io->getOutput(),
131
                ),
132
            );
133
134
        $io->writeln(
135
            sprintf(
136
                'Config file "<comment>%s</comment>" not found. Skipping.',
137
                $configFilePath,
138
            ),
139
            OutputInterface::VERBOSITY_DEBUG,
140
        );
141
142
        return null;
143
    }
144
145
    private static function logConfigFilePathFound(IO $io, ?string $configFilePath): void
146
    {
147
        if (null === $configFilePath) {
148
            $io->writeln(
149
                'Loading without configuration file.',
150
                OutputInterface::VERBOSITY_DEBUG,
151
            );
152
153
            return;
154
        }
155
156
        if (false === file_exists($configFilePath)) {
157
            throw new RuntimeException(
158
                sprintf(
159
                    'Could not find the configuration file "%s".',
160
                    $configFilePath,
161
                ),
162
            );
163
        }
164
165
        $io->writeln(
166
            sprintf(
167
                'Using the configuration file "%s".',
168
                $configFilePath,
169
            ),
170
            OutputInterface::VERBOSITY_DEBUG,
171
        );
172
    }
173
174
    /**
175
     * @param string[] $paths
176
     */
177
    private static function loadConfiguration(
178
        ?string $configFilePath,
179
        string $prefix,
180
        array $paths,
181
        string $cwd
182
    ): Configuration
183
    {
184
        return self::configurePaths(
185
            self::configurePrefix(
186
                Configuration::load($configFilePath, $paths),
187
                $prefix,
188
            ),
189
            $cwd,
190
        );
191
    }
192
193
    private static function configurePrefix(Configuration $config, string $prefix): Configuration
194
    {
195
        if ('' !== $prefix) {
196
            return $config->withPrefix($prefix);
197
        }
198
199
        if (null === $config->getPrefix()) {
200
            return $config->withPrefix(self::generateRandomPrefix());
201
        }
202
203
        return $config;
204
    }
205
206
    private static function configurePaths(
207
        Configuration $config,
208
        string $cwd
209
    ): Configuration
210
    {
211
        // Use the current working directory as the path if no file has been
212
        // found
213
        if (0 === count($config->getFilesWithContents())) {
214
            return $config->withPaths([$cwd]);
215
        }
216
217
        return $config;
218
    }
219
220
    private static function generateRandomPrefix(): string
221
    {
222
        return '_PhpScoper'.bin2hex(random_bytes(6));
223
    }
224
225
    private function makeAbsolutePath(
226
        string $path,
227
        string $cwd
228
    ): string
229
    {
230
        if (false === $this->fileSystem->isAbsolutePath($path)) {
231
            $path = $cwd.DIRECTORY_SEPARATOR.$path;
232
        }
233
234
        return $path;
235
    }
236
}
237