1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | /* |
||||
6 | * This file is part of the humbug/php-scoper package. |
||||
7 | * |
||||
8 | * Copyright (c) 2017 Théo FIDRY <[email protected]>, |
||||
9 | * Pádraic Brady <[email protected]> |
||||
10 | * |
||||
11 | * For the full copyright and license information, please view the LICENSE |
||||
12 | * file that was distributed with this source code. |
||||
13 | */ |
||||
14 | |||||
15 | namespace Humbug\PhpScoper\Console\Command; |
||||
16 | |||||
17 | use Fidry\Console\Application\Application; |
||||
18 | use Fidry\Console\Command\Command; |
||||
19 | use Fidry\Console\Command\CommandAware; |
||||
20 | use Fidry\Console\Command\CommandAwareness; |
||||
21 | use Fidry\Console\Command\Configuration as CommandConfiguration; |
||||
22 | use Fidry\Console\ExitCode; |
||||
23 | use Fidry\Console\Input\IO; |
||||
24 | use Humbug\PhpScoper\Configuration\Configuration; |
||||
25 | use Humbug\PhpScoper\Configuration\ConfigurationFactory; |
||||
26 | use Humbug\PhpScoper\Console\ConfigLoader; |
||||
27 | use Humbug\PhpScoper\Console\ConsoleScoper; |
||||
28 | use Humbug\PhpScoper\Scoper\ScoperFactory; |
||||
29 | use InvalidArgumentException; |
||||
30 | use Symfony\Component\Console\Exception\RuntimeException; |
||||
31 | use Symfony\Component\Console\Input\InputArgument; |
||||
32 | use Symfony\Component\Console\Input\InputOption; |
||||
33 | use Symfony\Component\Filesystem\Filesystem; |
||||
34 | use Symfony\Component\Filesystem\Path; |
||||
35 | use function array_map; |
||||
36 | use function is_dir; |
||||
37 | use function is_writable; |
||||
38 | use function Safe\getcwd; |
||||
39 | use function Safe\sprintf; |
||||
40 | use const DIRECTORY_SEPARATOR; |
||||
41 | |||||
42 | /** |
||||
43 | * @private |
||||
44 | */ |
||||
45 | final class AddPrefixCommand implements Command, CommandAware |
||||
46 | { |
||||
47 | use CommandAwareness; |
||||
48 | |||||
49 | private const PATH_ARG = 'paths'; |
||||
50 | private const PREFIX_OPT = 'prefix'; |
||||
51 | private const OUTPUT_DIR_OPT = 'output-dir'; |
||||
52 | private const FORCE_OPT = 'force'; |
||||
53 | private const STOP_ON_FAILURE_OPT = 'stop-on-failure'; |
||||
54 | private const CONFIG_FILE_OPT = 'config'; |
||||
55 | 16 | private const NO_CONFIG_OPT = 'no-config'; |
|||
56 | |||||
57 | 16 | private Filesystem $fileSystem; |
|||
58 | private ScoperFactory $scoperFactory; |
||||
59 | 16 | private bool $init = false; |
|||
60 | 16 | private Application $application; |
|||
61 | private ConfigurationFactory $configFactory; |
||||
62 | |||||
63 | public function __construct( |
||||
64 | Filesystem $fileSystem, |
||||
65 | ScoperFactory $scoperFactory, |
||||
66 | 16 | Application $application, |
|||
67 | ConfigurationFactory $configFactory |
||||
68 | 16 | ) { |
|||
69 | $this->fileSystem = $fileSystem; |
||||
70 | $this->scoperFactory = $scoperFactory; |
||||
71 | 16 | $this->application = $application; |
|||
72 | 16 | $this->configFactory = $configFactory; |
|||
73 | 16 | } |
|||
74 | 16 | ||||
75 | 16 | public function getConfiguration(): CommandConfiguration |
|||
76 | 16 | { |
|||
77 | return new CommandConfiguration( |
||||
78 | 16 | 'add-prefix', |
|||
79 | 16 | 'Goes through all the PHP files found in the given paths to apply the given prefix to namespaces & FQNs.', |
|||
80 | 16 | '', |
|||
81 | 16 | [ |
|||
82 | 16 | new InputArgument( |
|||
83 | self::PATH_ARG, |
||||
84 | 16 | InputArgument::IS_ARRAY, |
|||
85 | 16 | 'The path(s) to process.', |
|||
86 | 16 | ), |
|||
87 | 16 | ], |
|||
88 | 16 | [ |
|||
89 | 16 | ChangeableDirectory::createOption(), |
|||
90 | new InputOption( |
||||
91 | 16 | self::PREFIX_OPT, |
|||
92 | 16 | 'p', |
|||
93 | 16 | InputOption::VALUE_REQUIRED, |
|||
94 | 16 | 'The namespace prefix to add.', |
|||
95 | 16 | '', |
|||
96 | ), |
||||
97 | 16 | new InputOption( |
|||
98 | 16 | self::OUTPUT_DIR_OPT, |
|||
99 | 16 | 'o', |
|||
100 | 16 | InputOption::VALUE_REQUIRED, |
|||
101 | 16 | 'The output directory in which the prefixed code will be dumped.', |
|||
102 | 'build', |
||||
103 | 16 | ), |
|||
104 | 16 | new InputOption( |
|||
105 | 16 | self::FORCE_OPT, |
|||
106 | 16 | 'f', |
|||
107 | 16 | InputOption::VALUE_NONE, |
|||
108 | 16 | 'Deletes any existing content in the output directory without any warning.', |
|||
109 | 16 | ), |
|||
110 | new InputOption( |
||||
111 | self::STOP_ON_FAILURE_OPT, |
||||
112 | 16 | 's', |
|||
113 | 16 | InputOption::VALUE_NONE, |
|||
114 | 16 | 'Stops on failure.', |
|||
115 | 16 | ), |
|||
116 | 16 | new InputOption( |
|||
117 | self::CONFIG_FILE_OPT, |
||||
118 | 'c', |
||||
119 | InputOption::VALUE_REQUIRED, |
||||
120 | sprintf( |
||||
0 ignored issues
–
show
|
|||||
121 | 'Configuration file. Will use "%s" if found by default.', |
||||
122 | ConfigurationFactory::DEFAULT_FILE_NAME, |
||||
123 | ), |
||||
124 | 14 | ), |
|||
125 | new InputOption( |
||||
126 | 14 | self::NO_CONFIG_OPT, |
|||
127 | 14 | null, |
|||
128 | InputOption::VALUE_NONE, |
||||
129 | 14 | 'Do not look for a configuration file.', |
|||
130 | ), |
||||
131 | 14 | ], |
|||
132 | 14 | ); |
|||
133 | 14 | } |
|||
134 | |||||
135 | 14 | public function execute(IO $io): int |
|||
136 | 12 | { |
|||
137 | $io->newLine(); |
||||
138 | 12 | ||||
139 | ChangeableDirectory::changeWorkingDirectory($io); |
||||
140 | |||||
141 | // Only get current working directory _after_ we changed to the desired |
||||
142 | 12 | // working directory |
|||
143 | 12 | $cwd = getcwd(); |
|||
144 | 12 | ||||
145 | $paths = $this->getPathArguments($io, $cwd); |
||||
146 | $outputDir = $this->getOutputDir($io, $cwd); |
||||
147 | 12 | ||||
148 | 12 | $this->checkOutputDir($io, $outputDir); |
|||
149 | 12 | ||||
150 | $config = $this->retrieveConfig($io, $paths, $cwd); |
||||
151 | |||||
152 | $this->getScoper()->scope( |
||||
153 | 12 | $io, |
|||
154 | 12 | $config, |
|||
155 | 12 | $paths, |
|||
156 | 12 | $outputDir, |
|||
157 | 12 | $io->getOption(self::STOP_ON_FAILURE_OPT)->asBoolean(), |
|||
158 | 12 | ); |
|||
159 | 12 | ||||
160 | 12 | return ExitCode::SUCCESS; |
|||
161 | } |
||||
162 | |||||
163 | /** |
||||
164 | * @return non-empty-string |
||||
0 ignored issues
–
show
|
|||||
165 | */ |
||||
166 | private function getOutputDir(IO $io, string $cwd): string |
||||
167 | { |
||||
168 | return $this->canonicalizePath( |
||||
169 | $io->getOption(self::OUTPUT_DIR_OPT)->asString(), |
||||
170 | 12 | $cwd, |
|||
171 | ); |
||||
172 | 12 | } |
|||
173 | |||||
174 | private function checkOutputDir(IO $io, string $outputDir): void |
||||
175 | { |
||||
176 | if (!$this->fileSystem->exists($outputDir)) { |
||||
177 | return; |
||||
178 | 12 | } |
|||
179 | |||||
180 | self::checkPathIsWriteable($outputDir); |
||||
181 | |||||
182 | $canDeleteFile = self::canDeleteOutputDir($io, $outputDir); |
||||
183 | |||||
184 | if (!$canDeleteFile) { |
||||
185 | throw new RuntimeException('Cannot delete the output directory. Interrupting the process.'); |
||||
186 | } |
||||
187 | |||||
188 | 12 | $this->fileSystem->remove($outputDir); |
|||
189 | } |
||||
190 | 12 | ||||
191 | private static function checkPathIsWriteable(string $path): void |
||||
192 | 12 | { |
|||
193 | 12 | if (!is_writable($path)) { |
|||
194 | throw new RuntimeException( |
||||
195 | 12 | sprintf( |
|||
0 ignored issues
–
show
The function
Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
196 | 12 | 'Expected "<comment>%s</comment>" to be writeable.', |
|||
197 | $path, |
||||
198 | 12 | ), |
|||
199 | 12 | ); |
|||
200 | } |
||||
201 | } |
||||
202 | |||||
203 | 12 | private static function canDeleteOutputDir(IO $io, string $outputDir): bool |
|||
204 | 12 | { |
|||
205 | 12 | if ($io->getOption(self::FORCE_OPT)->asBoolean()) { |
|||
206 | 12 | return true; |
|||
207 | 12 | } |
|||
208 | 12 | ||||
209 | 12 | $question = sprintf( |
|||
0 ignored issues
–
show
The function
Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
210 | 12 | is_dir($outputDir) |
|||
211 | 12 | ? 'The output directory "<comment>%s</comment>" already exists. Continuing will erase its content, do you wish to proceed?' |
|||
212 | : 'Expected "<comment>%s</comment>" to be a directory but found a file instead. It will be removed, do you wish to proceed?', |
||||
213 | $outputDir, |
||||
214 | ); |
||||
215 | 12 | ||||
216 | return $io->confirm($question, false); |
||||
217 | 12 | } |
|||
218 | 12 | ||||
219 | /** |
||||
220 | * @param list<non-empty-string> $paths |
||||
0 ignored issues
–
show
The type
Humbug\PhpScoper\Console\Command\list was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
221 | 12 | */ |
|||
222 | private function retrieveConfig(IO $io, array $paths, string $cwd): Configuration |
||||
223 | { |
||||
224 | 12 | $configLoader = new ConfigLoader( |
|||
225 | $this->getCommandRegistry(), |
||||
226 | 12 | $this->fileSystem, |
|||
227 | $this->configFactory, |
||||
228 | ); |
||||
229 | |||||
230 | return $configLoader->loadConfig( |
||||
231 | $io, |
||||
232 | $io->getOption(self::PREFIX_OPT)->asString(), |
||||
233 | $io->getOption(self::NO_CONFIG_OPT)->asBoolean(), |
||||
234 | $this->getConfigFilePath($io, $cwd), |
||||
235 | ConfigurationFactory::DEFAULT_FILE_NAME, |
||||
236 | 12 | $this->init, |
|||
237 | $paths, |
||||
238 | $cwd, |
||||
239 | ); |
||||
240 | } |
||||
241 | |||||
242 | /** |
||||
243 | * @return non-empty-string|null |
||||
0 ignored issues
–
show
|
|||||
244 | */ |
||||
245 | private function getConfigFilePath(IO $io, string $cwd): ?string |
||||
246 | { |
||||
247 | 12 | $configFilePath = (string) $io->getOption(self::CONFIG_FILE_OPT)->asNullableString(); |
|||
248 | 2 | ||||
249 | 2 | return '' === $configFilePath ? null : $this->canonicalizePath($configFilePath, $cwd); |
|||
250 | 2 | } |
|||
251 | 2 | ||||
252 | 2 | /** |
|||
253 | * @return list<non-empty-string> List of absolute canonical paths |
||||
254 | 2 | */ |
|||
255 | 2 | private function getPathArguments(IO $io, string $cwd): array |
|||
256 | { |
||||
257 | return array_map( |
||||
0 ignored issues
–
show
|
|||||
258 | 2 | fn (string $path) => $this->canonicalizePath($path, $cwd), |
|||
259 | $io->getArgument(self::PATH_ARG)->asNonEmptyStringList(), |
||||
260 | ); |
||||
261 | } |
||||
262 | 2 | ||||
263 | /** |
||||
264 | 2 | * @return non-empty-string Absolute canonical path |
|||
0 ignored issues
–
show
|
|||||
265 | */ |
||||
266 | private function canonicalizePath(string $path, string $cwd): string |
||||
267 | 12 | { |
|||
268 | $canonicalPath = Path::canonicalize( |
||||
269 | 12 | $this->fileSystem->isAbsolutePath($path) |
|||
270 | 11 | ? $path |
|||
271 | : $cwd.DIRECTORY_SEPARATOR.$path, |
||||
272 | ); |
||||
273 | |||||
274 | 14 | if ('' === $canonicalPath) { |
|||
275 | throw new InvalidArgumentException('Cannot canonicalize empty path and empty working directory'); |
||||
276 | 14 | } |
|||
277 | |||||
278 | 14 | return $canonicalPath; |
|||
279 | 13 | } |
|||
280 | |||||
281 | private function getScoper(): ConsoleScoper |
||||
282 | 14 | { |
|||
283 | return new ConsoleScoper( |
||||
284 | $this->fileSystem, |
||||
285 | 14 | $this->application, |
|||
286 | $this->scoperFactory, |
||||
287 | 14 | ); |
|||
288 | 14 | } |
|||
289 | } |
||||
290 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.