Total Complexity | 54 |
Total Lines | 901 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Build often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Build, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
30 | final class Build extends Configurable |
||
31 | { |
||
32 | /** |
||
33 | * {@inheritdoc} |
||
34 | */ |
||
35 | protected function configure(): void |
||
36 | { |
||
37 | parent::configure(); |
||
38 | |||
39 | $this->setName('build'); |
||
40 | $this->setDescription('Builds a new PHAR'); |
||
41 | $this->setHelp( |
||
42 | <<<HELP |
||
43 | The <info>%command.name%</info> command will build a new Phar based on a variety of settings. |
||
44 | <comment> |
||
45 | This command relies on a configuration file for loading |
||
46 | Phar packaging settings. If a configuration file is not |
||
47 | specified through the <info>--configuration|-c</info> option, one of |
||
48 | the following files will be used (in order): <info>box.json, |
||
49 | box.json.dist</info> |
||
50 | </comment> |
||
51 | The configuration file is actually a JSON object saved to a file. |
||
52 | Note that all settings are optional. |
||
53 | <comment> |
||
54 | { |
||
55 | "algorithm": ?, |
||
56 | "alias": ?, |
||
57 | "banner": ?, |
||
58 | "banner-file": ?, |
||
59 | "base-path": ?, |
||
60 | "blacklist": ?, |
||
61 | "bootstrap": ?, |
||
62 | "chmod": ?, |
||
63 | "compactors": ?, |
||
64 | "compression": ?, |
||
65 | "datetime": ?, |
||
66 | "datetime_format": ?, |
||
67 | "directories": ?, |
||
68 | "directories-bin": ?, |
||
69 | "extract": ?, |
||
70 | "files": ?, |
||
71 | "files-bin": ?, |
||
72 | "finder": ?, |
||
73 | "finder-bin": ?, |
||
74 | "git-version": ?, |
||
75 | "intercept": ?, |
||
76 | "key": ?, |
||
77 | "key-pass": ?, |
||
78 | "main": ?, |
||
79 | "map": ?, |
||
80 | "metadata": ?, |
||
81 | "mimetypes": ?, |
||
82 | "mung": ?, |
||
83 | "not-found": ?, |
||
84 | "output": ?, |
||
85 | "replacements": ?, |
||
86 | "shebang": ?, |
||
87 | "stub": ?, |
||
88 | "web": ? |
||
89 | } |
||
90 | </comment> |
||
91 | |||
92 | |||
93 | |||
94 | The <info>algorithm</info> <comment>(string, integer)</comment> setting is the signing algorithm to |
||
95 | use when the Phar is built <comment>(Phar::setSignatureAlgorithm())</comment>. It can an |
||
96 | integer value (the value of the constant), or the name of the Phar |
||
97 | constant. The following is a list of the signature algorithms listed |
||
98 | on the help page: |
||
99 | <comment> |
||
100 | - MD5 (Phar::MD5) |
||
101 | - SHA1 (Phar::SHA1) |
||
102 | - SHA256 (Phar::SHA256) |
||
103 | - SHA512 (Phar::SHA512) |
||
104 | - OPENSSL (Phar::OPENSSL) |
||
105 | </comment> |
||
106 | The <info>alias</info> <comment>(string)</comment> setting is used when generating a new stub to call |
||
107 | the <comment>Phar::mapPhar()</comment> method. This makes it easier to refer to files in |
||
108 | the Phar. |
||
109 | |||
110 | The <info>annotations</info> <comment>(boolean, object)</comment> setting is used to enable compacting |
||
111 | annotations in PHP source code. By setting it to <info>true</info>, all Doctrine-style |
||
112 | annotations are compacted in PHP files. You may also specify a list of |
||
113 | annotations to ignore, which will be stripped while protecting the |
||
114 | remaining annotations: |
||
115 | <comment> |
||
116 | { |
||
117 | "annotations": { |
||
118 | "ignore": [ |
||
119 | "author", |
||
120 | "package", |
||
121 | "version", |
||
122 | "see" |
||
123 | ] |
||
124 | } |
||
125 | } |
||
126 | </comment> |
||
127 | You may want to see this website for a list of annotations which are |
||
128 | commonly ignored: |
||
129 | <comment> |
||
130 | https://github.com/herrera-io/php-annotations |
||
131 | </comment> |
||
132 | The <info>banner</info> <comment>(string)</comment> setting is the banner comment that will be used when |
||
133 | a new stub is generated. The value of this setting must not already be |
||
134 | enclosed within a comment block, as it will be automatically done for |
||
135 | you. |
||
136 | |||
137 | The <info>banner-file</info> <comment>(string)</comment> setting is like <info>stub-banner</info>, except it is a |
||
138 | path to the file that will contain the comment. Like <info>stub-banner</info>, the |
||
139 | comment must not already be enclosed in a comment block. |
||
140 | |||
141 | The <info>base-path</info> <comment>(string)</comment> setting is used to specify where all of the |
||
142 | relative file paths should resolve to. This does not, however, alter |
||
143 | where the built Phar will be stored <comment>(see: <info>output</info>)</comment>. By default, the |
||
144 | base path is the directory containing the configuration file. |
||
145 | |||
146 | The <info>blacklist</info> <comment>(string, array)</comment> setting is a list of files that must |
||
147 | not be added. The files blacklisted are the ones found using the other |
||
148 | available configuration settings: <info>directories, directories-bin, files, |
||
149 | files-bin, finder, finder-bin</info>. Note that directory separators are |
||
150 | automatically corrected to the platform specific version. |
||
151 | |||
152 | Assuming that the base directory path is <comment>/home/user/project</comment>: |
||
153 | <comment> |
||
154 | { |
||
155 | "blacklist": [ |
||
156 | "path/to/file/1" |
||
157 | "path/to/file/2" |
||
158 | ], |
||
159 | "directories": ["src"] |
||
160 | } |
||
161 | </comment> |
||
162 | The following files will be blacklisted: |
||
163 | <comment> |
||
164 | - /home/user/project/src/path/to/file/1 |
||
165 | - /home/user/project/src/path/to/file/2 |
||
166 | </comment> |
||
167 | But not these files: |
||
168 | <comment> |
||
169 | - /home/user/project/src/another/path/to/file/1 |
||
170 | - /home/user/project/src/another/path/to/file/2 |
||
171 | </comment> |
||
172 | The <info>bootstrap</info> <comment>(string)</comment> setting allows you to specify a PHP file that |
||
173 | will be loaded before the <info>build</info> or <info>add</info> commands are used. This is |
||
174 | useful for loading third-party file contents compacting classes that |
||
175 | were configured using the <info>compactors</info> setting. |
||
176 | |||
177 | The <info>chmod</info> <comment>(string)</comment> setting is used to change the file permissions of |
||
178 | the newly built Phar. The string contains an octal value: <comment>0755</comment>. You |
||
179 | must prefix the mode with zero if you specify the mode in decimal. |
||
180 | |||
181 | The <info>compactors</info> <comment>(string, array)</comment> setting is a list of file contents |
||
182 | compacting classes that must be registered. A file compacting class |
||
183 | is used to reduce the size of a specific file type. The following is |
||
184 | a simple example: |
||
185 | <comment> |
||
186 | use Herrera\\Box\\Compactor\\CompactorInterface; |
||
187 | |||
188 | class MyCompactor implements CompactorInterface |
||
189 | { |
||
190 | public function compact(\$contents) |
||
191 | { |
||
192 | return trim(\$contents); |
||
193 | } |
||
194 | |||
195 | public function supports(\$file) |
||
196 | { |
||
197 | return (bool) preg_match('/\.txt/', \$file); |
||
198 | } |
||
199 | } |
||
200 | </comment> |
||
201 | The following compactors are included with Box: |
||
202 | <comment> |
||
203 | - Herrera\\Box\\Compactor\\Json |
||
204 | - Herrera\\Box\\Compactor\\Php |
||
205 | </comment> |
||
206 | The <info>compression</info> <comment>(string, integer)</comment> setting is the compression algorithm |
||
207 | to use when the Phar is built. The compression affects the individual |
||
208 | files within the Phar, and not the Phar as a whole <comment>(Phar::compressFiles())</comment>. |
||
209 | The following is a list of the signature algorithms listed on the help |
||
210 | page: |
||
211 | <comment> |
||
212 | - BZ2 (Phar::BZ2) |
||
213 | - GZ (Phar::GZ) |
||
214 | - NONE (Phar::NONE) |
||
215 | </comment> |
||
216 | The <info>directories</info> <comment>(string, array)</comment> setting is a list of directory paths |
||
217 | relative to <info>base-path</info>. All files ending in <comment>.php</comment> will be automatically |
||
218 | compacted, have their placeholder values replaced, and added to the |
||
219 | Phar. Files listed in the <info>blacklist</info> setting will not be added. |
||
220 | |||
221 | The <info>directories-bin</info> <comment>(string, array)</comment> setting is similar to <info>directories</info>, |
||
222 | except all file types are added to the Phar unmodified. This is suitable |
||
223 | for directories containing images or other binary data. |
||
224 | |||
225 | The <info>extract</info> <comment>(boolean)</comment> setting determines whether or not the generated |
||
226 | stub should include a class to extract the phar. This class would be |
||
227 | used if the phar is not available. (Increases stub file size.) |
||
228 | |||
229 | The <info>files</info> <comment>(string, array)</comment> setting is a list of files paths relative to |
||
230 | <info>base-path</info>. Each file will be compacted, have their placeholder files |
||
231 | replaced, and added to the Phar. This setting is not affected by the |
||
232 | <info>blacklist</info> setting. |
||
233 | |||
234 | The <info>files-bin</info> <comment>(string, array)</comment> setting is similar to <info>files</info>, except that |
||
235 | all files are added to the Phar unmodified. This is suitable for files |
||
236 | such as images or those that contain binary data. |
||
237 | |||
238 | The <info>finder</info> <comment>(array)</comment> setting is a list of JSON objects. Each object key |
||
239 | is a name, and each value an argument for the methods in the |
||
240 | <comment>Symfony\\Component\\Finder\\Finder</comment> class. If an array of values is provided |
||
241 | for a single key, the method will be called once per value in the array. |
||
242 | Note that the paths specified for the "in" method are relative to |
||
243 | <info>base-path</info>. |
||
244 | |||
245 | The <info>finder-bin</info> <comment>(array)</comment> setting performs the same function, except all |
||
246 | files found by the finder will be treated as binary files, leaving them |
||
247 | unmodified. |
||
248 | <comment> |
||
249 | It may be useful to know that Box imports files in the following order: |
||
250 | |||
251 | - finder |
||
252 | - finder-bin |
||
253 | - directories |
||
254 | - directories-bin |
||
255 | - files |
||
256 | - files-bin |
||
257 | </comment> |
||
258 | The <info>datetime</info> <comment>(string)</comment> setting is the name of a placeholder value that |
||
259 | will be replaced in all non-binary files by the current datetime. |
||
260 | |||
261 | Example: <comment>2015-01-28 14:55:23</comment> |
||
262 | |||
263 | The <info>datetime_format</info> <comment>(string)</comment> setting accepts a valid PHP date format. It can be used to change the format for the <info>datetime</info> setting. |
||
264 | |||
265 | Example: <comment>Y-m-d H:i:s</comment> |
||
266 | |||
267 | The <info>git-commit</info> <comment>(string)</comment> setting is the name of a placeholder value that |
||
268 | will be replaced in all non-binary files by the current Git commit hash |
||
269 | of the repository. |
||
270 | |||
271 | Example: <comment>e558e335f1d165bc24d43fdf903cdadd3c3cbd03</comment> |
||
272 | |||
273 | The <info>git-commit-short</info> <comment>(string)</comment> setting is the name of a placeholder value |
||
274 | that will be replaced in all non-binary files by the current Git short |
||
275 | commit hash of the repository. |
||
276 | |||
277 | Example: <comment>e558e33</comment> |
||
278 | |||
279 | The <info>git-tag</info> <comment>(string)</comment> setting is the name of a placeholder value that will |
||
280 | be replaced in all non-binary files by the current Git tag of the |
||
281 | repository. |
||
282 | |||
283 | Examples: |
||
284 | <comment> |
||
285 | - 2.0.0 |
||
286 | - 2.0.0-2-ge558e33 |
||
287 | </comment> |
||
288 | The <info>git-version</info> <comment>(string)</comment> setting is the name of a placeholder value that |
||
289 | will be replaced in all non-binary files by the one of the following (in |
||
290 | order): |
||
291 | |||
292 | - The git repository's most recent tag. |
||
293 | - The git repository's current short commit hash. |
||
294 | |||
295 | The short commit hash will only be used if no tag is available. |
||
296 | |||
297 | The <info>intercept</info> <comment>(boolean)</comment> setting is used when generating a new stub. If |
||
298 | setting is set to <comment>true</comment>, the <comment>Phar::interceptFileFuncs();</comment> method will be |
||
299 | called in the stub. |
||
300 | |||
301 | The <info>key</info> <comment>(string)</comment> setting is used to specify the path to the private key |
||
302 | file. The private key file will be used to sign the Phar using the |
||
303 | <comment>OPENSSL</comment> signature algorithm. If an absolute path is not provided, the |
||
304 | path will be relative to the current working directory. |
||
305 | |||
306 | The <info>key-pass</info> <comment>(string, boolean)</comment> setting is used to specify the passphrase |
||
307 | for the private <info>key</info>. If a <comment>string</comment> is provided, it will be used as is as |
||
308 | the passphrase. If <comment>true</comment> is provided, you will be prompted for the |
||
309 | passphrase. |
||
310 | |||
311 | The <info>main</info> <comment>(string)</comment> setting is used to specify the file (relative to |
||
312 | <info>base-path</info>) that will be run when the Phar is executed from the command |
||
313 | line. If the file was not added by any of the other file adding settings, |
||
314 | it will be automatically added after it has been compacted and had its |
||
315 | placeholder values replaced. Also, the #! line will be automatically |
||
316 | removed if present. |
||
317 | |||
318 | The <info>map</info> <comment>(array)</comment> setting is used to change where some (or all) files are |
||
319 | stored inside the phar. The key is a beginning of the relative path that |
||
320 | will be matched against the file being added to the phar. If the key is |
||
321 | a match, the matched segment will be replaced with the value. If the key |
||
322 | is empty, the value will be prefixed to all paths (except for those |
||
323 | already matched by an earlier key). |
||
324 | |||
325 | <comment> |
||
326 | { |
||
327 | "map": [ |
||
328 | { "my/test/path": "src/Test" }, |
||
329 | { "": "src/Another" } |
||
330 | ] |
||
331 | } |
||
332 | </comment> |
||
333 | |||
334 | (with the files) |
||
335 | |||
336 | <comment> |
||
337 | 1. my/test/path/file.php |
||
338 | 2. my/test/path/some/other.php |
||
339 | 3. my/test/another.php |
||
340 | </comment> |
||
341 | |||
342 | (will be stored as) |
||
343 | |||
344 | <comment> |
||
345 | 1. src/Test/file.php |
||
346 | 2. src/Test/some/other.php |
||
347 | 3. src/Another/my/test/another.php |
||
348 | </comment> |
||
349 | |||
350 | The <info>metadata</info> <comment>(any)</comment> setting can be any value. This value will be stored as |
||
351 | metadata that can be retrieved from the built Phar <comment>(Phar::getMetadata())</comment>. |
||
352 | |||
353 | The <info>mimetypes</info> <comment>(object)</comment> setting is used when generating a new stub. It is |
||
354 | a map of file extensions and their mimetypes. To see a list of the default |
||
355 | mapping, please visit: |
||
356 | |||
357 | <comment>http://www.php.net/manual/en/phar.webphar.php</comment> |
||
358 | |||
359 | The <info>mung</info> <comment>(array)</comment> setting is used when generating a new stub. It is a list |
||
360 | of server variables to modify for the Phar. This setting is only useful |
||
361 | when the <info>web</info> setting is enabled. |
||
362 | |||
363 | The <info>not-found</info> <comment>(string)</comment> setting is used when generating a new stub. It |
||
364 | specifies the file that will be used when a file is not found inside the |
||
365 | Phar. This setting is only useful when <info>web</info> setting is enabled. |
||
366 | |||
367 | The <info>output</info> <comment>(string)</comment> setting specifies the file name and path of the newly |
||
368 | built Phar. If the value of the setting is not an absolute path, the path |
||
369 | will be relative to the current working directory. |
||
370 | |||
371 | The <info>replacements</info> <comment>(object)</comment> setting is a map of placeholders and their |
||
372 | values. The placeholders are replaced in all non-binary files with the |
||
373 | specified values. |
||
374 | |||
375 | The <info>shebang</info> <comment>(string)</comment> setting is used to specify the shebang line used |
||
376 | when generating a new stub. By default, this line is used: |
||
377 | |||
378 | <comment>#!/usr/bin/env php</comment> |
||
379 | |||
380 | The shebang line can be removed altogether if <comment>false</comment> or an empty string |
||
381 | is provided. |
||
382 | |||
383 | The <info>stub</info> <comment>(string, boolean)</comment> setting is used to specify the location of a |
||
384 | stub file, or if one should be generated. If a path is provided, the stub |
||
385 | file will be used as is inside the Phar. If <comment>true</comment> is provided, a new stub |
||
386 | will be generated. If <comment>false (or nothing)</comment> is provided, the default stub |
||
387 | used by the Phar class will be used. |
||
388 | |||
389 | The <info>web</info> <comment>(boolean)</comment> setting is used when generating a new stub. If <comment>true</comment> is |
||
390 | provided, <comment>Phar::webPhar()</comment> will be called in the stub. |
||
391 | HELP |
||
392 | ); |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * {@inheritdoc} |
||
397 | */ |
||
398 | protected function execute(InputInterface $input, OutputInterface $output): void |
||
399 | { |
||
400 | $io = new SymfonyStyle($input, $output); |
||
401 | |||
402 | $io->writeln($this->getApplication()->getHelp()); |
||
403 | $io->writeln(''); |
||
404 | |||
405 | $config = $this->getConfig($input); |
||
406 | $path = $config->getOutputPath(); |
||
407 | |||
408 | $logger = new BuildLogger($io); |
||
409 | |||
410 | $this->loadBootstrapFile($config, $logger); |
||
411 | $this->removeExistingPhar($config, $logger); |
||
412 | |||
413 | $logger->logStartBuilding($path); |
||
414 | |||
415 | $this->createPhar($path, $config, $input, $output, $logger); |
||
416 | |||
417 | $this->correctPermissions($path, $config, $logger); |
||
418 | |||
419 | $logger->log( |
||
420 | BuildLogger::STAR_PREFIX, |
||
421 | 'Done.' |
||
422 | ); |
||
423 | |||
424 | if (false === file_exists($path)) { |
||
425 | $io->warning('The archive was not generated because it did not have any contents.'); |
||
426 | } |
||
427 | } |
||
428 | |||
429 | private function createPhar( |
||
430 | string $path, |
||
431 | Configuration $config, |
||
432 | InputInterface $input, |
||
433 | OutputInterface $output, |
||
434 | BuildLogger $logger |
||
435 | ): void { |
||
436 | $box = Box::create($path); |
||
437 | |||
438 | $box->getPhar()->startBuffering(); |
||
439 | |||
440 | $this->setReplacementValues($config, $box, $logger); |
||
441 | $this->registerCompactors($config, $box, $logger); |
||
442 | $this->alertAboutMappedPaths($config, $logger); |
||
443 | |||
444 | $this->addFiles($config, $box, $logger); |
||
445 | |||
446 | $main = $this->registerMainScript($config, $box, $logger); |
||
447 | |||
448 | $this->registerStub($config, $box, $main, $logger); |
||
449 | $this->configureMetadata($config, $box, $logger); |
||
450 | $this->configureCompressionAlgorithm($config, $box, $logger); |
||
451 | |||
452 | $box->getPhar()->stopBuffering(); |
||
453 | |||
454 | $this->signPhar($config, $box, $path, $input, $output, $logger); |
||
455 | } |
||
456 | |||
457 | private function loadBootstrapFile(Configuration $config, BuildLogger $logger): void |
||
458 | { |
||
459 | $file = $config->getBootstrapFile(); |
||
460 | |||
461 | if (null === $file) { |
||
462 | return; |
||
463 | } |
||
464 | |||
465 | $logger->log( |
||
466 | BuildLogger::QUESTION_MARK_PREFIX, |
||
467 | sprintf( |
||
468 | 'Loading the bootstrap file "%s".', |
||
469 | $file |
||
470 | ), |
||
471 | OutputInterface::VERBOSITY_VERBOSE |
||
472 | ); |
||
473 | |||
474 | $config->loadBootstrap(); |
||
475 | } |
||
476 | |||
477 | private function removeExistingPhar(Configuration $config, BuildLogger $logger): void |
||
478 | { |
||
479 | $path = $config->getOutputPath(); |
||
480 | |||
481 | if (false === file_exists($path)) { |
||
482 | return; |
||
483 | } |
||
484 | |||
485 | $logger->log( |
||
486 | BuildLogger::QUESTION_MARK_PREFIX, |
||
487 | sprintf( |
||
488 | 'Removing the existing PHAR "%s".', |
||
489 | $path |
||
490 | ), |
||
491 | OutputInterface::VERBOSITY_VERBOSE |
||
492 | ); |
||
493 | |||
494 | (new Filesystem())->remove($path); |
||
495 | } |
||
496 | |||
497 | private function setReplacementValues(Configuration $config, Box $box, BuildLogger $logger): void |
||
498 | { |
||
499 | $values = $config->getProcessedReplacements(); |
||
500 | |||
501 | if ([] === $values) { |
||
502 | return; |
||
503 | } |
||
504 | |||
505 | $logger->log( |
||
506 | BuildLogger::QUESTION_MARK_PREFIX, |
||
507 | 'Setting replacement values.', |
||
508 | OutputInterface::VERBOSITY_VERBOSE |
||
509 | ); |
||
510 | |||
511 | foreach ($values as $key => $value) { |
||
512 | $logger->log( |
||
513 | BuildLogger::PLUS_PREFIX, |
||
514 | sprintf( |
||
515 | '%s: %s', |
||
516 | $key, |
||
517 | $value |
||
518 | ), |
||
519 | OutputInterface::VERBOSITY_VERBOSE |
||
520 | ); |
||
521 | } |
||
522 | |||
523 | $box->setValues($values); |
||
524 | } |
||
525 | |||
526 | private function registerCompactors(Configuration $config, Box $box, BuildLogger $logger): void |
||
527 | { |
||
528 | $compactors = $config->getCompactors(); |
||
529 | |||
530 | if ([] === $compactors) { |
||
531 | return; |
||
532 | } |
||
533 | |||
534 | $logger->log( |
||
535 | BuildLogger::QUESTION_MARK_PREFIX, |
||
536 | 'Registering compactors.', |
||
537 | OutputInterface::VERBOSITY_VERBOSE |
||
538 | ); |
||
539 | |||
540 | foreach ($compactors as $compactor) { |
||
541 | $logger->log( |
||
542 | BuildLogger::PLUS_PREFIX, |
||
543 | get_class($compactor), |
||
544 | OutputInterface::VERBOSITY_VERBOSE |
||
545 | ); |
||
546 | |||
547 | $box->addCompactor($compactor); |
||
548 | } |
||
549 | } |
||
550 | |||
551 | private function alertAboutMappedPaths(Configuration $config, BuildLogger $logger): void |
||
552 | { |
||
553 | $map = $config->getMap(); |
||
554 | |||
555 | if ([] === $map) { |
||
556 | return; |
||
557 | } |
||
558 | |||
559 | $logger->log( |
||
560 | BuildLogger::QUESTION_MARK_PREFIX, |
||
561 | 'Mapping paths.', |
||
562 | OutputInterface::VERBOSITY_VERBOSE |
||
563 | ); |
||
564 | |||
565 | foreach ($map as $item) { |
||
566 | foreach ($item as $match => $replace) { |
||
567 | if (empty($match)) { |
||
568 | $match = '(all)'; |
||
569 | } |
||
570 | |||
571 | $logger->log( |
||
572 | BuildLogger::MINUS_PREFIX, |
||
573 | sprintf( |
||
574 | '%s <info>></info> %s', |
||
575 | $match, |
||
576 | $replace |
||
577 | ), |
||
578 | OutputInterface::VERBOSITY_VERBOSE |
||
579 | ); |
||
580 | } |
||
581 | } |
||
582 | } |
||
583 | |||
584 | private function addFiles(Configuration $config, Box $box, BuildLogger $logger): void |
||
585 | { |
||
586 | if ([] !== ($iterators = $config->getFilesIterators())) { |
||
587 | $logger->log( |
||
588 | BuildLogger::QUESTION_MARK_PREFIX, |
||
589 | 'Adding finder files.', |
||
590 | OutputInterface::VERBOSITY_VERBOSE |
||
591 | ); |
||
592 | |||
593 | foreach ($iterators as $iterator) { |
||
594 | $this->addFilesToBox($config, $box, $iterator, null, false, $logger); |
||
595 | } |
||
596 | } |
||
597 | |||
598 | if ([] !== ($iterators = $config->getBinaryIterators())) { |
||
599 | $logger->log( |
||
600 | BuildLogger::QUESTION_MARK_PREFIX, |
||
601 | 'Adding binary finder files.', |
||
602 | OutputInterface::VERBOSITY_VERBOSE |
||
603 | ); |
||
604 | |||
605 | foreach ($iterators as $iterator) { |
||
606 | $this->addFilesToBox($config, $box, $iterator, null, true, $logger); |
||
607 | } |
||
608 | } |
||
609 | |||
610 | $this->addFilesToBox( |
||
611 | $config, |
||
612 | $box, |
||
613 | $config->getDirectoriesIterator(), |
||
614 | 'Adding directories.', |
||
615 | false, |
||
616 | $logger |
||
617 | ); |
||
618 | |||
619 | $this->addFilesToBox( |
||
620 | $config, |
||
621 | $box, |
||
622 | $config->getBinaryDirectoriesIterator(), |
||
623 | 'Adding binary directories.', |
||
624 | true, |
||
625 | $logger |
||
626 | ); |
||
627 | |||
628 | $this->addFilesToBox( |
||
629 | $config, |
||
630 | $box, |
||
631 | $config->getFilesIterator(), |
||
632 | 'Adding files.', |
||
633 | false, |
||
634 | $logger |
||
635 | ); |
||
636 | |||
637 | $this->addFilesToBox( |
||
638 | $config, |
||
639 | $box, |
||
640 | $config->getBinaryFilesIterator(), |
||
641 | 'Adding binary files.', |
||
642 | true, |
||
643 | $logger |
||
644 | ); |
||
645 | } |
||
646 | |||
647 | private function registerMainScript(Configuration $config, Box $box, BuildLogger $logger): ?string |
||
648 | { |
||
649 | $main = $config->getMainScriptPath(); |
||
650 | |||
651 | if (null === $main) { |
||
652 | return null; |
||
653 | } |
||
654 | |||
655 | $logger->log( |
||
656 | BuildLogger::QUESTION_MARK_PREFIX, |
||
657 | sprintf( |
||
658 | 'Adding main file: %s', |
||
659 | $config->getBasePath().DIRECTORY_SEPARATOR.$main |
||
660 | ), |
||
661 | OutputInterface::VERBOSITY_VERBOSE |
||
662 | ); |
||
663 | |||
664 | $mapper = $config->getMapper(); |
||
665 | $pharPath = $mapper($main); |
||
666 | |||
667 | if (null !== $pharPath) { |
||
668 | $logger->log( |
||
669 | BuildLogger::CHEVRON_PREFIX, |
||
670 | $pharPath, |
||
671 | OutputInterface::VERBOSITY_VERBOSE |
||
672 | ); |
||
673 | |||
674 | $main = $pharPath; |
||
675 | } |
||
676 | |||
677 | $box->addFromString( |
||
678 | $main, |
||
679 | $config->getMainScriptContent() |
||
680 | ); |
||
681 | |||
682 | return $main; |
||
683 | } |
||
684 | |||
685 | private function registerStub(Configuration $config, Box $box, ?string $main, BuildLogger $logger): void |
||
715 | ); |
||
716 | } |
||
717 | } |
||
718 | |||
719 | private function configureMetadata(Configuration $config, Box $box, BuildLogger $logger): void |
||
720 | { |
||
721 | if (null !== ($metadata = $config->getMetadata())) { |
||
722 | $logger->log( |
||
723 | BuildLogger::QUESTION_MARK_PREFIX, |
||
724 | 'Setting metadata.', |
||
725 | OutputInterface::VERBOSITY_VERBOSE |
||
726 | ); |
||
727 | |||
728 | $box->getPhar()->setMetadata($metadata); |
||
729 | } |
||
730 | } |
||
731 | |||
732 | private function configureCompressionAlgorithm(Configuration $config, Box $box, BuildLogger $logger): void |
||
733 | { |
||
734 | if (null !== ($algorithm = $config->getCompressionAlgorithm())) { |
||
735 | $logger->log( |
||
736 | BuildLogger::QUESTION_MARK_PREFIX, |
||
737 | 'Compressing.', |
||
738 | OutputInterface::VERBOSITY_VERBOSE |
||
739 | ); |
||
740 | |||
741 | $box->getPhar()->compressFiles($algorithm); |
||
742 | } |
||
743 | } |
||
744 | |||
745 | private function signPhar( |
||
746 | Configuration $config, |
||
747 | Box $box, |
||
748 | string $path, |
||
749 | InputInterface $input, |
||
750 | OutputInterface $output, |
||
751 | BuildLogger $logger |
||
752 | ): void { |
||
753 | // sign using private key, if applicable |
||
754 | //TODO: check that out |
||
755 | if (file_exists($path.'.pubkey')) { |
||
756 | unlink($path.'.pubkey'); |
||
757 | } |
||
758 | |||
759 | $key = $config->getPrivateKeyPath(); |
||
760 | |||
761 | if (null === $key) { |
||
762 | if (null !== ($algorithm = $config->getSigningAlgorithm())) { |
||
763 | $box->getPhar()->setSignatureAlgorithm($algorithm); |
||
764 | } |
||
765 | |||
766 | return; |
||
767 | } |
||
768 | |||
769 | $logger->log( |
||
770 | BuildLogger::QUESTION_MARK_PREFIX, |
||
771 | 'Signing using a private key.', |
||
772 | OutputInterface::VERBOSITY_VERBOSE |
||
773 | ); |
||
774 | |||
775 | $passphrase = $config->getPrivateKeyPassphrase(); |
||
776 | |||
777 | if ($config->isPrivateKeyPrompt()) { |
||
778 | if (false === $input->isInteractive()) { |
||
779 | throw new RuntimeException( |
||
780 | sprintf( |
||
781 | 'Accessing to the private key "%s" requires a passphrase but none provided. Either ' |
||
782 | .'provide one or run this command in interactive mode.', |
||
783 | $key |
||
784 | ) |
||
785 | ); |
||
786 | } |
||
787 | |||
788 | /** @var $dialog QuestionHelper */ |
||
789 | $dialog = $this->getHelper('question'); |
||
790 | |||
791 | $question = new Question('Private key passphrase:'); |
||
792 | $question->setHidden(false); |
||
793 | $question->setHiddenFallback(false); |
||
794 | |||
795 | $passphrase = $dialog->ask($input, $output, $question); |
||
796 | |||
797 | $output->writeln(''); |
||
798 | } |
||
799 | |||
800 | $box->signUsingFile($key, $passphrase); |
||
801 | } |
||
802 | |||
803 | private function correctPermissions(string $path, Configuration $config, BuildLogger $logger): void |
||
804 | { |
||
805 | if (null !== ($chmod = $config->getFileMode())) { |
||
806 | $logger->log( |
||
807 | BuildLogger::QUESTION_MARK_PREFIX, |
||
808 | 'Setting file permissions.', |
||
809 | OutputInterface::VERBOSITY_VERBOSE |
||
810 | ); |
||
811 | |||
812 | chmod($path, $chmod); |
||
813 | } |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * Adds files using an iterator. |
||
818 | * |
||
819 | * @param Configuration $config |
||
820 | * @param Box $box |
||
821 | * @param iterable|SplFileInfo[] $iterator the iterator |
||
822 | * @param string $message the message to announce |
||
823 | * @param bool $binary Should the adding be binary-safe? |
||
824 | * @param BuildLogger $logger |
||
825 | */ |
||
826 | private function addFilesToBox( |
||
827 | Configuration $config, |
||
828 | Box $box, |
||
829 | ?iterable $iterator, |
||
830 | ?string $message, |
||
831 | bool $binary, |
||
832 | BuildLogger $logger |
||
833 | ): void { |
||
834 | static $count = 0; |
||
835 | |||
836 | if (null === $iterator) { |
||
837 | return; |
||
838 | } |
||
839 | |||
840 | if (null !== $message) { |
||
841 | $logger->log(BuildLogger::QUESTION_MARK_PREFIX, $message); |
||
842 | } |
||
843 | |||
844 | $box = $binary ? $box->getPhar() : $box; |
||
845 | $mapper = $config->getMapper(); |
||
846 | |||
847 | foreach ($iterator as $file) { |
||
848 | // @var $file SplFileInfo |
||
849 | |||
850 | // Forces garbadge collection from time to time |
||
851 | if (0 === (++$count % 100)) { |
||
852 | gc_collect_cycles(); |
||
853 | } |
||
854 | |||
855 | $relativePath = $config->retrieveRelativeBasePath($file->getPathname()); |
||
856 | |||
857 | $mapped = $mapper($relativePath); |
||
858 | |||
859 | if (null !== $mapped) { |
||
860 | $relativePath = $mapped; |
||
861 | } |
||
862 | |||
863 | if (null !== $mapped) { |
||
864 | $logger->log( |
||
865 | BuildLogger::CHEVRON_PREFIX, |
||
866 | $relativePath, |
||
867 | OutputInterface::VERBOSITY_VERY_VERBOSE |
||
868 | ); |
||
869 | } else { |
||
870 | $logger->log( |
||
871 | BuildLogger::PLUS_PREFIX, |
||
872 | (string) $file, |
||
873 | OutputInterface::VERBOSITY_VERY_VERBOSE |
||
874 | ); |
||
875 | } |
||
876 | |||
877 | $box->addFile((string) $file, $relativePath); |
||
878 | } |
||
879 | } |
||
880 | |||
881 | private function createStub(Configuration $config, ?string $main, BuildLogger $logger): StubGenerator |
||
931 | } |
||
932 | } |
||
933 |