Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 234 |
|
0.00% |
0 / 25 |
CRAP | |
0.00% |
0 / 1 |
installer | |
0.00% |
0 / 234 |
|
0.00% |
0 / 25 |
4830 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
install | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
do_install | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
20 | |||
get_installed_packages | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
get_composer | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
do_get_installed_packages | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
get_available_packages | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
do_get_available_packages | |
0.00% |
0 / 58 |
|
0.00% |
0 / 1 |
210 | |||
check_requirements | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
get_compatible_versions | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
110 | |||
generate_ext_json_file | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
6 | |||
restore_ext_json_file | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
get_core_packages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
get_core_php_requirement | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_composer_repositories | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 | |||
get_composer_ext_json_filename | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_extra_dependencies | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
set_repositories | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
set_packagist | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
set_composer_filename | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
set_packages_vendor_dir | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
set_root_path | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
move_to_root | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
restore_cwd | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
wrap | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\composer; |
15 | |
16 | use Composer\Composer; |
17 | use Composer\DependencyResolver\Request as composer_request; |
18 | use Composer\Factory; |
19 | use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; |
20 | use Composer\IO\IOInterface; |
21 | use Composer\IO\NullIO; |
22 | use Composer\Json\JsonFile; |
23 | use Composer\Json\JsonValidationException; |
24 | use Composer\Package\BasePackage; |
25 | use Composer\Package\CompleteAliasPackage; |
26 | use Composer\Package\CompletePackage; |
27 | use Composer\Package\PackageInterface; |
28 | use Composer\PartialComposer; |
29 | use Composer\Repository\ComposerRepository; |
30 | use Composer\Semver\Constraint\ConstraintInterface; |
31 | use Composer\Semver\VersionParser; |
32 | use Composer\Util\HttpDownloader; |
33 | use phpbb\composer\io\null_io; |
34 | use phpbb\config\config; |
35 | use phpbb\exception\runtime_exception; |
36 | use phpbb\filesystem\filesystem; |
37 | use phpbb\request\request; |
38 | use Seld\JsonLint\ParsingException; |
39 | use phpbb\filesystem\helper as filesystem_helper; |
40 | |
41 | /** |
42 | * Class to install packages through composer while freezing core dependencies. |
43 | */ |
44 | class installer |
45 | { |
46 | const PHPBB_TYPES = 'phpbb-extension,phpbb-style,phpbb-language'; |
47 | |
48 | /** |
49 | * @var array Repositories to look packages from |
50 | */ |
51 | protected $repositories = []; |
52 | |
53 | /** |
54 | * @var bool Indicates whether packagist usage is allowed or not |
55 | */ |
56 | protected $packagist = false; |
57 | |
58 | /** |
59 | * @var string Composer filename used to manage the packages |
60 | */ |
61 | protected $composer_filename = 'composer-ext.json'; |
62 | |
63 | /** |
64 | * @var string Directory where to install packages vendors |
65 | */ |
66 | protected $packages_vendor_dir = 'vendor-ext/'; |
67 | |
68 | /** |
69 | * @var string Minimum stability |
70 | */ |
71 | protected $minimum_stability = 'stable'; |
72 | |
73 | /** |
74 | * @var string phpBB root path |
75 | */ |
76 | protected $root_path; |
77 | |
78 | /** |
79 | * @var string|null Stores the original working directory in case it has been changed through move_to_root() |
80 | */ |
81 | private $original_cwd; |
82 | |
83 | /** |
84 | * @var array|null Stores the content of the ext json file before generate_ext_json_file() overrides it |
85 | */ |
86 | private $ext_json_file_backup; |
87 | |
88 | /** |
89 | * @var request phpBB request object |
90 | */ |
91 | private $request; |
92 | |
93 | /** |
94 | * @var filesystem phpBB filesystem |
95 | */ |
96 | private $filesystem; |
97 | |
98 | /** |
99 | * @param string $root_path phpBB root path |
100 | * @param filesystem $filesystem Filesystem object |
101 | * @param request $request phpBB request object |
102 | * @param config|null $config Config object |
103 | */ |
104 | public function __construct($root_path, filesystem $filesystem, request $request, config $config = null) |
105 | { |
106 | if ($config) |
107 | { |
108 | $repositories = json_decode($config['exts_composer_repositories'], true); |
109 | |
110 | if (is_array($repositories) && !empty($repositories)) |
111 | { |
112 | $this->repositories = (array) $repositories; |
113 | } |
114 | |
115 | $this->packagist = (bool) $config['exts_composer_packagist']; |
116 | $this->composer_filename = $config['exts_composer_json_file']; |
117 | $this->packages_vendor_dir = $config['exts_composer_vendor_dir']; |
118 | $this->minimum_stability = $config['exts_composer_minimum_stability']; |
119 | } |
120 | |
121 | $this->root_path = $root_path; |
122 | $this->request = $request; |
123 | $this->filesystem = $filesystem; |
124 | |
125 | putenv('COMPOSER_HOME=' . filesystem_helper::realpath($root_path) . '/store/composer'); |
126 | } |
127 | |
128 | /** |
129 | * Update the current installed set of packages |
130 | * |
131 | * @param array $packages Packages to install. |
132 | * Each entry may be a name or an array associating a version constraint to a name |
133 | * @param array $whitelist White-listed packages (packages that can be installed/updated/removed) |
134 | * @param IOInterface|null $io IO object used for the output |
135 | * |
136 | * @throws runtime_exception |
137 | */ |
138 | public function install(array $packages, $whitelist, IOInterface $io = null) |
139 | { |
140 | $this->wrap(function() use ($packages, $whitelist, $io) { |
141 | $this->do_install($packages, $whitelist, $io); |
142 | }); |
143 | } |
144 | |
145 | /** |
146 | * Update the current installed set of packages |
147 | * |
148 | * /!\ Doesn't change the current working directory |
149 | * |
150 | * @param array $packages Packages to install. |
151 | * Each entry may be a name or an array associating a version constraint to a name |
152 | * @param array $whitelist White-listed packages (packages that can be installed/updated/removed) |
153 | * @param io\io_interface|null $io IO object used for the output |
154 | * |
155 | * @throws runtime_exception |
156 | * @throws JsonValidationException |
157 | */ |
158 | protected function do_install(array $packages, $whitelist, io\io_interface $io = null) |
159 | { |
160 | if (!$io) |
161 | { |
162 | $this->restore_cwd(); |
163 | $io = new null_io(); |
164 | $this->move_to_root(); |
165 | } |
166 | |
167 | $this->generate_ext_json_file($packages); |
168 | |
169 | $composer = $this->get_composer($this->get_composer_ext_json_filename()); |
170 | |
171 | $install = \Composer\Installer::create($io, $composer); |
172 | |
173 | $composer->getInstallationManager()->setOutputProgress(false); |
174 | |
175 | $install |
176 | ->setVerbose(true) |
177 | ->setPreferSource(false) |
178 | ->setPreferDist(true) |
179 | ->setDevMode(false) |
180 | ->setUpdate(true) |
181 | ->setUpdateAllowList($whitelist) |
182 | ->setUpdateAllowTransitiveDependencies(composer_request::UPDATE_ONLY_LISTED) |
183 | ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList(false)) |
184 | ->setOptimizeAutoloader(true) |
185 | ->setDumpAutoloader(true) |
186 | ->setPreferStable(true) |
187 | ->setRunScripts(false) |
188 | ->setDryRun(false); |
189 | |
190 | try |
191 | { |
192 | $result = $install->run(); |
193 | } |
194 | catch (\Exception $e) |
195 | { |
196 | $this->restore_ext_json_file(); |
197 | $this->restore_cwd(); |
198 | |
199 | throw new runtime_exception('COMPOSER_CANNOT_INSTALL', [], $e); |
200 | } |
201 | |
202 | if ($result !== 0) |
203 | { |
204 | $this->restore_ext_json_file(); |
205 | $this->restore_cwd(); |
206 | |
207 | throw new runtime_exception($io->get_composer_error(), []); |
208 | } |
209 | } |
210 | |
211 | /** |
212 | * Returns the list of currently installed packages |
213 | * |
214 | * @param string|array $types Returns only the packages with the given type(s) |
215 | * |
216 | * @return array The installed packages associated to their version. |
217 | * |
218 | * @throws runtime_exception |
219 | */ |
220 | public function get_installed_packages($types) |
221 | { |
222 | return $this->wrap(function() use ($types) { |
223 | return $this->do_get_installed_packages($types); |
224 | }); |
225 | } |
226 | |
227 | /** |
228 | * Create instance of composer for supplied config file |
229 | * |
230 | * @param string|null $config_file Path to config file relative to phpBB root dir or null |
231 | * |
232 | * @return Composer|PartialComposer |
233 | * @throws JsonValidationException |
234 | */ |
235 | protected function get_composer(?string $config_file): PartialComposer |
236 | { |
237 | static $composer_factory; |
238 | if (!$composer_factory) |
239 | { |
240 | $composer_factory = new Factory(); |
241 | } |
242 | |
243 | $io = new NullIO(); |
244 | |
245 | return $composer_factory->createComposer( |
246 | $io, |
247 | $config_file, |
248 | false, |
249 | filesystem_helper::realpath('') |
250 | ); |
251 | } |
252 | |
253 | /** |
254 | * Returns the list of currently installed packages |
255 | * |
256 | * /!\ Doesn't change the current working directory |
257 | * |
258 | * @param string|array $types Returns only the packages with the given type(s) |
259 | * |
260 | * @return array The installed packages associated to their version. |
261 | */ |
262 | protected function do_get_installed_packages($types) |
263 | { |
264 | $types = (array) $types; |
265 | |
266 | try |
267 | { |
268 | $composer = $this->get_composer($this->get_composer_ext_json_filename()); |
269 | |
270 | $installed = []; |
271 | |
272 | /** @var \Composer\Package\Link[] $required_links */ |
273 | $required_links = $composer->getPackage()->getRequires(); |
274 | $installed_packages = $composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages(); |
275 | |
276 | foreach ($installed_packages as $package) |
277 | { |
278 | if (in_array($package->getType(), $types, true)) |
279 | { |
280 | $version = array_key_exists($package->getName(), $required_links) ? |
281 | $required_links[$package->getName()]->getPrettyConstraint() : '*'; |
282 | $installed[$package->getName()] = $version; |
283 | } |
284 | } |
285 | |
286 | return $installed; |
287 | } |
288 | catch (\Exception $e) |
289 | { |
290 | return []; |
291 | } |
292 | } |
293 | |
294 | /** |
295 | * Gets the list of the available packages of the configured type in the configured repositories |
296 | * |
297 | * /!\ Doesn't change the current working directory |
298 | * |
299 | * @param string $type Returns only the packages with the given type |
300 | * |
301 | * @return array The name of the available packages, associated to their definition. Ordered by name. |
302 | * |
303 | * @throws runtime_exception |
304 | */ |
305 | public function get_available_packages($type) |
306 | { |
307 | return $this->wrap(function() use ($type) { |
308 | return $this->do_get_available_packages($type); |
309 | }); |
310 | } |
311 | |
312 | /** |
313 | * Gets the list of the available packages of the configured type in the configured repositories |
314 | * |
315 | * @param string $type Returns only the packages with the given type |
316 | * |
317 | * @return array The name of the available packages, associated to their definition. Ordered by name. |
318 | */ |
319 | protected function do_get_available_packages($type) |
320 | { |
321 | try |
322 | { |
323 | $this->generate_ext_json_file($this->do_get_installed_packages(explode(',', self::PHPBB_TYPES))); |
324 | |
325 | $io = new NullIO(); |
326 | $composer = $this->get_composer($this->get_composer_ext_json_filename()); |
327 | |
328 | /** @var ConstraintInterface $core_constraint */ |
329 | $core_constraint = $composer->getPackage()->getRequires()['phpbb/phpbb']->getConstraint(); |
330 | $core_stability = $composer->getPackage()->getMinimumStability(); |
331 | |
332 | $available = []; |
333 | |
334 | $compatible_packages = []; |
335 | $repositories = $composer->getRepositoryManager()->getRepositories(); |
336 | |
337 | /** @var \Composer\Repository\RepositoryInterface $repository */ |
338 | foreach ($repositories as $repository) |
339 | { |
340 | try |
341 | { |
342 | if ($repository instanceof ComposerRepository) |
343 | { |
344 | // Special case for packagist which exposes an api to retrieve all packages of a given type. |
345 | // For the others composer repositories with providers we can't do anything. It would be too slow. |
346 | |
347 | $repositoryReflection = new \ReflectionObject($repository); |
348 | $repo_url = $repositoryReflection->getProperty('url'); |
349 | $repo_url->setAccessible(true); |
350 | |
351 | if ($repo_url->getValue($repository) === 'https://repo.packagist.org') |
352 | { |
353 | $url = 'https://packagist.org/packages/list.json?type=' . $type; |
354 | $composer_config = new \Composer\Config(); |
355 | $downloader = new HttpDownloader($io, $composer_config); |
356 | $json = $downloader->get($url)->getBody(); |
357 | |
358 | /** @var PackageInterface $package */ |
359 | foreach (JsonFile::parseJson($json, $url)['packageNames'] as $package) |
360 | { |
361 | $versions = $repository->findPackages($package); |
362 | $compatible_packages = $this->get_compatible_versions($compatible_packages, $core_constraint, $core_stability, $package, $versions); |
363 | } |
364 | } |
365 | } |
366 | else |
367 | { |
368 | // Pre-filter repo packages by their type |
369 | $packages = []; |
370 | /** @var PackageInterface $package */ |
371 | foreach ($repository->getPackages() as $package) |
372 | { |
373 | if ($package->getType() === $type) |
374 | { |
375 | $packages[$package->getName()][] = $package; |
376 | } |
377 | } |
378 | |
379 | // Filter the compatibles versions |
380 | foreach ($packages as $package => $versions) |
381 | { |
382 | $compatible_packages = $this->get_compatible_versions($compatible_packages, $core_constraint, $core_stability, $package, $versions); |
383 | } |
384 | } |
385 | } |
386 | catch (\Exception $e) |
387 | { |
388 | // If a repo fails, just skip it. |
389 | continue; |
390 | } |
391 | } |
392 | |
393 | foreach ($compatible_packages as $name => $versions) |
394 | { |
395 | // Determine the highest version of the package |
396 | /** @var CompletePackage|CompleteAliasPackage $highest_version */ |
397 | $highest_version = null; |
398 | |
399 | // Sort the versions array in descending order |
400 | usort($versions, function ($a, $b) |
401 | { |
402 | return version_compare($b->getVersion(), $a->getVersion()); |
403 | }); |
404 | |
405 | // The first element in the sorted array is the highest version |
406 | if (!empty($versions)) |
407 | { |
408 | $highest_version = $versions[0]; |
409 | |
410 | // If highest version is a non-numeric dev branch, it's an instance of CompleteAliasPackage, |
411 | // so we need to get the package being aliased in order to show the true non-numeric version. |
412 | if ($highest_version instanceof CompleteAliasPackage) |
413 | { |
414 | $highest_version = $highest_version->getAliasOf(); |
415 | } |
416 | } |
417 | |
418 | // Generates the entry |
419 | $available[$name] = []; |
420 | $available[$name]['name'] = $highest_version->getPrettyName(); |
421 | $available[$name]['display_name'] = $highest_version->getExtra()['display-name']; |
422 | $available[$name]['composer_name'] = $highest_version->getName(); |
423 | $available[$name]['version'] = $highest_version->getPrettyVersion(); |
424 | |
425 | if ($highest_version instanceof CompletePackage) |
426 | { |
427 | $available[$name]['description'] = $highest_version->getDescription(); |
428 | $available[$name]['url'] = $highest_version->getHomepage(); |
429 | $available[$name]['authors'] = $highest_version->getAuthors(); |
430 | } |
431 | else |
432 | { |
433 | $available[$name]['description'] = ''; |
434 | $available[$name]['url'] = ''; |
435 | $available[$name]['authors'] = []; |
436 | } |
437 | } |
438 | |
439 | usort($available, function($a, $b) |
440 | { |
441 | return strcasecmp($a['display_name'], $b['display_name']); |
442 | }); |
443 | |
444 | return $available; |
445 | } |
446 | catch (\Exception $e) |
447 | { |
448 | return []; |
449 | } |
450 | } |
451 | |
452 | /** |
453 | * Checks the requirements of the manager and returns true if it can be used. |
454 | * |
455 | * @return bool |
456 | */ |
457 | public function check_requirements() |
458 | { |
459 | return $this->filesystem->is_writable([ |
460 | $this->root_path . $this->composer_filename, |
461 | $this->root_path . $this->packages_vendor_dir, |
462 | $this->root_path . substr($this->composer_filename, 0, -5) . '.lock', |
463 | ]); |
464 | } |
465 | |
466 | /** |
467 | * Updates $compatible_packages with the versions of $versions compatibles with the $core_constraint |
468 | * |
469 | * @param array $compatible_packages List of compatibles versions |
470 | * @param ConstraintInterface $core_constraint Constraint against the phpBB version |
471 | * @param string $core_stability Core stability |
472 | * @param string $package_name Considered package |
473 | * @param array $versions List of available versions |
474 | * |
475 | * @return array |
476 | */ |
477 | private function get_compatible_versions(array $compatible_packages, ConstraintInterface $core_constraint, $core_stability, $package_name, array $versions) |
478 | { |
479 | $version_parser = new VersionParser(); |
480 | |
481 | $core_stability_value = BasePackage::$stabilities[$core_stability]; |
482 | |
483 | /** @var PackageInterface $version */ |
484 | foreach ($versions as $version) |
485 | { |
486 | try |
487 | { |
488 | // Check stability first to avoid unnecessary operations |
489 | if (BasePackage::$stabilities[$version->getStability()] > $core_stability_value) |
490 | { |
491 | continue; |
492 | } |
493 | |
494 | $requires = $version->getRequires(); |
495 | $extra = $version->getExtra(); |
496 | |
497 | // Check for compatibility with phpBB if 'phpbb/phpbb' exists in 'requires' |
498 | if (isset($requires['phpbb/phpbb'])) |
499 | { |
500 | $package_constraint = $requires['phpbb/phpbb']->getConstraint(); |
501 | if (!$package_constraint->matches($core_constraint)) |
502 | { |
503 | continue; |
504 | } |
505 | } |
506 | |
507 | // Check for compatibility with phpBB if 'phpbb/phpbb' exists in 'soft-require' |
508 | if (isset($extra['soft-require']['phpbb/phpbb'])) |
509 | { |
510 | $package_constraint = $version_parser->parseConstraints($extra['soft-require']['phpbb/phpbb']); |
511 | if (!$package_constraint->matches($core_constraint)) |
512 | { |
513 | continue; |
514 | } |
515 | } |
516 | |
517 | // Check for compatibility with php if 'php' exists in 'requires' |
518 | if (isset($requires['php'])) |
519 | { |
520 | $php_constraint = $version_parser->parseConstraints(PHP_VERSION); |
521 | $package_constraint = $requires['php']->getConstraint(); |
522 | if (!$package_constraint->matches($php_constraint)) |
523 | { |
524 | continue; |
525 | } |
526 | } |
527 | |
528 | $compatible_packages[$package_name][] = $version; |
529 | } |
530 | catch (\Exception $e) |
531 | { |
532 | // Do nothing (to log when a true debug logger is available) |
533 | } |
534 | } |
535 | |
536 | return $compatible_packages; |
537 | } |
538 | |
539 | /** |
540 | * Generates and write the json file used to install the set of packages |
541 | * |
542 | * @param array $packages Packages to update. |
543 | * Each entry may be a name or an array associating a version constraint to a name |
544 | * @throws JsonValidationException |
545 | */ |
546 | protected function generate_ext_json_file(array $packages) |
547 | { |
548 | $io = new NullIO(); |
549 | |
550 | $composer = $this->get_composer(null); |
551 | |
552 | $core_packages = $this->get_core_packages($composer); |
553 | |
554 | // The composer/installers package must be installed on his own and not provided by the existing autoloader |
555 | $core_replace = $core_packages; |
556 | unset($core_replace['composer/installers']); |
557 | |
558 | $ext_json_data = [ |
559 | 'require' => array_merge( |
560 | ['php' => $this->get_core_php_requirement($composer)], |
561 | $core_packages, |
562 | $this->get_extra_dependencies(), |
563 | $packages), |
564 | 'replace' => $core_replace, |
565 | 'repositories' => $this->get_composer_repositories(), |
566 | 'config' => [ |
567 | 'vendor-dir' => $this->packages_vendor_dir, |
568 | 'allow-plugins' => [ |
569 | 'composer/installers' => true, |
570 | ] |
571 | ], |
572 | 'minimum-stability' => $this->minimum_stability, |
573 | ]; |
574 | |
575 | $this->ext_json_file_backup = null; |
576 | $json_file = new JsonFile($this->get_composer_ext_json_filename()); |
577 | |
578 | try |
579 | { |
580 | $ext_json_file_backup = $json_file->read(); |
581 | } |
582 | catch (ParsingException $e) |
583 | { |
584 | $ext_json_file_backup = '{}'; |
585 | |
586 | $lockFile = new JsonFile(substr($this->get_composer_ext_json_filename(), 0, -5) . '.lock'); |
587 | $lockFile->write([]); |
588 | } |
589 | |
590 | $json_file->write($ext_json_data); |
591 | $this->ext_json_file_backup = $ext_json_file_backup; |
592 | } |
593 | |
594 | /** |
595 | * Restore the json file overridden by generate_ext_json_file() |
596 | */ |
597 | protected function restore_ext_json_file() |
598 | { |
599 | if ($this->ext_json_file_backup) |
600 | { |
601 | try |
602 | { |
603 | $json_file = new JsonFile($this->get_composer_ext_json_filename()); |
604 | $json_file->write($this->ext_json_file_backup); |
605 | } |
606 | catch (\Exception $e) |
607 | { |
608 | } |
609 | |
610 | $this->ext_json_file_backup = null; |
611 | } |
612 | } |
613 | |
614 | /** |
615 | * Get the core installed packages |
616 | * |
617 | * @param Composer $composer Composer object to load the dependencies |
618 | * @return array The core packages with their version |
619 | */ |
620 | protected function get_core_packages(Composer $composer) |
621 | { |
622 | $core_deps = []; |
623 | $packages = $composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages(); |
624 | |
625 | foreach ($packages as $package) |
626 | { |
627 | $core_deps[$package->getName()] = $package->getPrettyVersion(); |
628 | } |
629 | |
630 | $core_deps['phpbb/phpbb'] = PHPBB_VERSION; |
631 | |
632 | return $core_deps; |
633 | } |
634 | |
635 | /** |
636 | * Get the PHP version required by the core |
637 | * |
638 | * @param Composer $composer Composer object to load the dependencies |
639 | * @return string The PHP version required by the core |
640 | */ |
641 | protected function get_core_php_requirement(Composer $composer) |
642 | { |
643 | return $composer->getLocker()->getLockData()['platform']['php']; |
644 | } |
645 | |
646 | /** |
647 | * Generate the repositories entry of the packages json file |
648 | * |
649 | * @return array repositories entry |
650 | */ |
651 | protected function get_composer_repositories() |
652 | { |
653 | $repositories = []; |
654 | |
655 | if (!$this->packagist) |
656 | { |
657 | $repositories[]['packagist'] = false; |
658 | } |
659 | |
660 | foreach ($this->repositories as $repository) |
661 | { |
662 | if (preg_match('#^' . get_preg_expression('url') . '$#iu', $repository)) |
663 | { |
664 | $repositories[] = [ |
665 | 'type' => 'composer', |
666 | 'url' => $repository, |
667 | 'canonical' => $this->packagist ? false : true, |
668 | ]; |
669 | } |
670 | } |
671 | |
672 | return $repositories; |
673 | } |
674 | |
675 | /** |
676 | * Get the name of the json file used for the packages. |
677 | * |
678 | * @return string The json filename |
679 | */ |
680 | protected function get_composer_ext_json_filename() |
681 | { |
682 | return $this->composer_filename; |
683 | } |
684 | |
685 | /** |
686 | * Get extra dependencies required to install the packages |
687 | * |
688 | * @return array Array of composer dependencies |
689 | */ |
690 | protected function get_extra_dependencies() |
691 | { |
692 | return []; |
693 | } |
694 | |
695 | /** |
696 | * Sets the customs repositories |
697 | * |
698 | * @param array $repositories An array of composer repositories to use |
699 | */ |
700 | public function set_repositories(array $repositories) |
701 | { |
702 | $this->repositories = $repositories; |
703 | } |
704 | |
705 | /** |
706 | * Allow or disallow packagist |
707 | * |
708 | * @param boolean $packagist |
709 | */ |
710 | public function set_packagist($packagist) |
711 | { |
712 | $this->packagist = $packagist; |
713 | } |
714 | |
715 | /** |
716 | * Sets the name of the managed packages' json file |
717 | * |
718 | * @param string $composer_filename |
719 | */ |
720 | public function set_composer_filename($composer_filename) |
721 | { |
722 | $this->composer_filename = $composer_filename; |
723 | } |
724 | |
725 | /** |
726 | * Sets the location of the managed packages' vendors |
727 | * |
728 | * @param string $packages_vendor_dir |
729 | */ |
730 | public function set_packages_vendor_dir($packages_vendor_dir) |
731 | { |
732 | $this->packages_vendor_dir = $packages_vendor_dir; |
733 | } |
734 | |
735 | /** |
736 | * Sets the phpBB root path |
737 | * |
738 | * @param string $root_path |
739 | */ |
740 | public function set_root_path($root_path) |
741 | { |
742 | $this->root_path = $root_path; |
743 | } |
744 | |
745 | /** |
746 | * Change the current directory to phpBB root |
747 | */ |
748 | protected function move_to_root() |
749 | { |
750 | if ($this->original_cwd === null) |
751 | { |
752 | $this->original_cwd = getcwd(); |
753 | chdir($this->root_path); |
754 | } |
755 | } |
756 | |
757 | /** |
758 | * Restore the current working directory if move_to_root() have been called |
759 | */ |
760 | protected function restore_cwd() |
761 | { |
762 | if ($this->original_cwd) |
763 | { |
764 | chdir($this->original_cwd); |
765 | $this->original_cwd = null; |
766 | } |
767 | } |
768 | |
769 | /** |
770 | * Wraps a callable in order to adjust the context needed by composer |
771 | * |
772 | * @param callable $callable |
773 | * |
774 | * @return mixed |
775 | */ |
776 | protected function wrap(callable $callable) |
777 | { |
778 | // The composer installers works with a path relative to the current directory |
779 | $this->move_to_root(); |
780 | |
781 | // The composer installers uses some super globals |
782 | $super_globals = $this->request->super_globals_disabled(); |
783 | $this->request->enable_super_globals(); |
784 | |
785 | try |
786 | { |
787 | return $callable(); |
788 | } |
789 | finally |
790 | { |
791 | $this->restore_cwd(); |
792 | |
793 | if ($super_globals) |
794 | { |
795 | $this->request->disable_super_globals(); |
796 | } |
797 | } |
798 | } |
799 | } |