annotate vendor/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * This file is part of the Composer Merge plugin.
Chris@0 4 *
Chris@0 5 * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
Chris@0 6 *
Chris@0 7 * This software may be modified and distributed under the terms of the MIT
Chris@0 8 * license. See the LICENSE file for details.
Chris@0 9 */
Chris@0 10
Chris@0 11 namespace Wikimedia\Composer\Merge;
Chris@0 12
Chris@0 13 use Wikimedia\Composer\Logger;
Chris@0 14
Chris@0 15 use Composer\Composer;
Chris@0 16 use Composer\Json\JsonFile;
Chris@0 17 use Composer\Package\BasePackage;
Chris@0 18 use Composer\Package\CompletePackage;
Chris@0 19 use Composer\Package\Link;
Chris@0 20 use Composer\Package\Loader\ArrayLoader;
Chris@0 21 use Composer\Package\RootAliasPackage;
Chris@0 22 use Composer\Package\RootPackage;
Chris@0 23 use Composer\Package\RootPackageInterface;
Chris@0 24 use Composer\Package\Version\VersionParser;
Chris@0 25 use UnexpectedValueException;
Chris@0 26
Chris@0 27 /**
Chris@0 28 * Processing for a composer.json file that will be merged into
Chris@0 29 * a RootPackageInterface
Chris@0 30 *
Chris@0 31 * @author Bryan Davis <bd808@bd808.com>
Chris@0 32 */
Chris@0 33 class ExtraPackage
Chris@0 34 {
Chris@0 35
Chris@0 36 /**
Chris@0 37 * @var Composer $composer
Chris@0 38 */
Chris@0 39 protected $composer;
Chris@0 40
Chris@0 41 /**
Chris@0 42 * @var Logger $logger
Chris@0 43 */
Chris@0 44 protected $logger;
Chris@0 45
Chris@0 46 /**
Chris@0 47 * @var string $path
Chris@0 48 */
Chris@0 49 protected $path;
Chris@0 50
Chris@0 51 /**
Chris@0 52 * @var array $json
Chris@0 53 */
Chris@0 54 protected $json;
Chris@0 55
Chris@0 56 /**
Chris@0 57 * @var CompletePackage $package
Chris@0 58 */
Chris@0 59 protected $package;
Chris@0 60
Chris@0 61 /**
Chris@0 62 * @var VersionParser $versionParser
Chris@0 63 */
Chris@0 64 protected $versionParser;
Chris@0 65
Chris@0 66 /**
Chris@0 67 * @param string $path Path to composer.json file
Chris@0 68 * @param Composer $composer
Chris@0 69 * @param Logger $logger
Chris@0 70 */
Chris@0 71 public function __construct($path, Composer $composer, Logger $logger)
Chris@0 72 {
Chris@0 73 $this->path = $path;
Chris@0 74 $this->composer = $composer;
Chris@0 75 $this->logger = $logger;
Chris@0 76 $this->json = $this->readPackageJson($path);
Chris@0 77 $this->package = $this->loadPackage($this->json);
Chris@0 78 $this->versionParser = new VersionParser();
Chris@0 79 }
Chris@0 80
Chris@0 81 /**
Chris@0 82 * Get list of additional packages to include if precessing recursively.
Chris@0 83 *
Chris@0 84 * @return array
Chris@0 85 */
Chris@0 86 public function getIncludes()
Chris@0 87 {
Chris@0 88 return isset($this->json['extra']['merge-plugin']['include']) ?
Chris@0 89 $this->json['extra']['merge-plugin']['include'] : array();
Chris@0 90 }
Chris@0 91
Chris@0 92 /**
Chris@0 93 * Get list of additional packages to require if precessing recursively.
Chris@0 94 *
Chris@0 95 * @return array
Chris@0 96 */
Chris@0 97 public function getRequires()
Chris@0 98 {
Chris@0 99 return isset($this->json['extra']['merge-plugin']['require']) ?
Chris@0 100 $this->json['extra']['merge-plugin']['require'] : array();
Chris@0 101 }
Chris@0 102
Chris@0 103 /**
Chris@0 104 * Read the contents of a composer.json style file into an array.
Chris@0 105 *
Chris@0 106 * The package contents are fixed up to be usable to create a Package
Chris@0 107 * object by providing dummy "name" and "version" values if they have not
Chris@0 108 * been provided in the file. This is consistent with the default root
Chris@0 109 * package loading behavior of Composer.
Chris@0 110 *
Chris@0 111 * @param string $path
Chris@0 112 * @return array
Chris@0 113 */
Chris@0 114 protected function readPackageJson($path)
Chris@0 115 {
Chris@0 116 $file = new JsonFile($path);
Chris@0 117 $json = $file->read();
Chris@0 118 if (!isset($json['name'])) {
Chris@0 119 $json['name'] = 'merge-plugin/' .
Chris@0 120 strtr($path, DIRECTORY_SEPARATOR, '-');
Chris@0 121 }
Chris@0 122 if (!isset($json['version'])) {
Chris@0 123 $json['version'] = '1.0.0';
Chris@0 124 }
Chris@0 125 return $json;
Chris@0 126 }
Chris@0 127
Chris@0 128 /**
Chris@0 129 * @param array $json
Chris@0 130 * @return CompletePackage
Chris@0 131 */
Chris@0 132 protected function loadPackage(array $json)
Chris@0 133 {
Chris@0 134 $loader = new ArrayLoader();
Chris@0 135 $package = $loader->load($json);
Chris@0 136 // @codeCoverageIgnoreStart
Chris@0 137 if (!$package instanceof CompletePackage) {
Chris@0 138 throw new UnexpectedValueException(
Chris@0 139 'Expected instance of CompletePackage, got ' .
Chris@0 140 get_class($package)
Chris@0 141 );
Chris@0 142 }
Chris@0 143 // @codeCoverageIgnoreEnd
Chris@0 144 return $package;
Chris@0 145 }
Chris@0 146
Chris@0 147 /**
Chris@0 148 * Merge this package into a RootPackageInterface
Chris@0 149 *
Chris@0 150 * @param RootPackageInterface $root
Chris@0 151 * @param PluginState $state
Chris@0 152 */
Chris@0 153 public function mergeInto(RootPackageInterface $root, PluginState $state)
Chris@0 154 {
Chris@0 155 $this->prependRepositories($root);
Chris@0 156
Chris@0 157 $this->mergeRequires('require', $root, $state);
Chris@0 158
Chris@0 159 $this->mergePackageLinks('conflict', $root);
Chris@0 160 $this->mergePackageLinks('replace', $root);
Chris@0 161 $this->mergePackageLinks('provide', $root);
Chris@0 162
Chris@0 163 $this->mergeSuggests($root);
Chris@0 164
Chris@0 165 $this->mergeAutoload('autoload', $root);
Chris@0 166
Chris@0 167 $this->mergeExtra($root, $state);
Chris@0 168
Chris@0 169 $this->mergeScripts($root, $state);
Chris@0 170
Chris@0 171 if ($state->isDevMode()) {
Chris@0 172 $this->mergeDevInto($root, $state);
Chris@0 173 } else {
Chris@0 174 $this->mergeReferences($root);
Chris@0 175 }
Chris@0 176 }
Chris@0 177
Chris@0 178 /**
Chris@0 179 * Merge just the dev portion into a RootPackageInterface
Chris@0 180 *
Chris@0 181 * @param RootPackageInterface $root
Chris@0 182 * @param PluginState $state
Chris@0 183 */
Chris@0 184 public function mergeDevInto(RootPackageInterface $root, PluginState $state)
Chris@0 185 {
Chris@0 186 $this->mergeRequires('require-dev', $root, $state);
Chris@0 187 $this->mergeAutoload('devAutoload', $root);
Chris@0 188 $this->mergeReferences($root);
Chris@0 189 }
Chris@0 190
Chris@0 191 /**
Chris@0 192 * Add a collection of repositories described by the given configuration
Chris@0 193 * to the given package and the global repository manager.
Chris@0 194 *
Chris@0 195 * @param RootPackageInterface $root
Chris@0 196 */
Chris@0 197 protected function prependRepositories(RootPackageInterface $root)
Chris@0 198 {
Chris@0 199 if (!isset($this->json['repositories'])) {
Chris@0 200 return;
Chris@0 201 }
Chris@0 202 $repoManager = $this->composer->getRepositoryManager();
Chris@0 203 $newRepos = array();
Chris@0 204
Chris@0 205 foreach ($this->json['repositories'] as $repoJson) {
Chris@0 206 if (!isset($repoJson['type'])) {
Chris@0 207 continue;
Chris@0 208 }
Chris@0 209 $this->logger->info("Prepending {$repoJson['type']} repository");
Chris@0 210 $repo = $repoManager->createRepository(
Chris@0 211 $repoJson['type'],
Chris@0 212 $repoJson
Chris@0 213 );
Chris@0 214 $repoManager->prependRepository($repo);
Chris@0 215 $newRepos[] = $repo;
Chris@0 216 }
Chris@0 217
Chris@0 218 $unwrapped = self::unwrapIfNeeded($root, 'setRepositories');
Chris@0 219 $unwrapped->setRepositories(array_merge(
Chris@0 220 $newRepos,
Chris@0 221 $root->getRepositories()
Chris@0 222 ));
Chris@0 223 }
Chris@0 224
Chris@0 225 /**
Chris@0 226 * Merge require or require-dev into a RootPackageInterface
Chris@0 227 *
Chris@0 228 * @param string $type 'require' or 'require-dev'
Chris@0 229 * @param RootPackageInterface $root
Chris@0 230 * @param PluginState $state
Chris@0 231 */
Chris@0 232 protected function mergeRequires(
Chris@0 233 $type,
Chris@0 234 RootPackageInterface $root,
Chris@0 235 PluginState $state
Chris@0 236 ) {
Chris@0 237 $linkType = BasePackage::$supportedLinkTypes[$type];
Chris@0 238 $getter = 'get' . ucfirst($linkType['method']);
Chris@0 239 $setter = 'set' . ucfirst($linkType['method']);
Chris@0 240
Chris@0 241 $requires = $this->package->{$getter}();
Chris@0 242 if (empty($requires)) {
Chris@0 243 return;
Chris@0 244 }
Chris@0 245
Chris@0 246 $this->mergeStabilityFlags($root, $requires);
Chris@0 247
Chris@0 248 $requires = $this->replaceSelfVersionDependencies(
Chris@0 249 $type,
Chris@0 250 $requires,
Chris@0 251 $root
Chris@0 252 );
Chris@0 253
Chris@0 254 $root->{$setter}($this->mergeOrDefer(
Chris@0 255 $type,
Chris@0 256 $root->{$getter}(),
Chris@0 257 $requires,
Chris@0 258 $state
Chris@0 259 ));
Chris@0 260 }
Chris@0 261
Chris@0 262 /**
Chris@0 263 * Merge two collections of package links and collect duplicates for
Chris@0 264 * subsequent processing.
Chris@0 265 *
Chris@0 266 * @param string $type 'require' or 'require-dev'
Chris@0 267 * @param array $origin Primary collection
Chris@0 268 * @param array $merge Additional collection
Chris@0 269 * @param PluginState $state
Chris@0 270 * @return array Merged collection
Chris@0 271 */
Chris@0 272 protected function mergeOrDefer(
Chris@0 273 $type,
Chris@0 274 array $origin,
Chris@0 275 array $merge,
Chris@0 276 $state
Chris@0 277 ) {
Chris@0 278 if ($state->ignoreDuplicateLinks() && $state->replaceDuplicateLinks()) {
Chris@0 279 $this->logger->warning("Both replace and ignore-duplicates are true. These are mutually exclusive.");
Chris@0 280 $this->logger->warning("Duplicate packages will be ignored.");
Chris@0 281 }
Chris@0 282
Chris@0 283 $dups = array();
Chris@0 284 foreach ($merge as $name => $link) {
Chris@0 285 if (isset($origin[$name]) && $state->ignoreDuplicateLinks()) {
Chris@0 286 $this->logger->info("Ignoring duplicate <comment>{$name}</comment>");
Chris@0 287 continue;
Chris@0 288 } elseif (!isset($origin[$name]) || $state->replaceDuplicateLinks()) {
Chris@0 289 $this->logger->info("Merging <comment>{$name}</comment>");
Chris@0 290 $origin[$name] = $link;
Chris@0 291 } else {
Chris@0 292 // Defer to solver.
Chris@0 293 $this->logger->info(
Chris@0 294 "Deferring duplicate <comment>{$name}</comment>"
Chris@0 295 );
Chris@0 296 $dups[] = $link;
Chris@0 297 }
Chris@0 298 }
Chris@0 299 $state->addDuplicateLinks($type, $dups);
Chris@0 300 return $origin;
Chris@0 301 }
Chris@0 302
Chris@0 303 /**
Chris@0 304 * Merge autoload or autoload-dev into a RootPackageInterface
Chris@0 305 *
Chris@0 306 * @param string $type 'autoload' or 'devAutoload'
Chris@0 307 * @param RootPackageInterface $root
Chris@0 308 */
Chris@0 309 protected function mergeAutoload($type, RootPackageInterface $root)
Chris@0 310 {
Chris@0 311 $getter = 'get' . ucfirst($type);
Chris@0 312 $setter = 'set' . ucfirst($type);
Chris@0 313
Chris@0 314 $autoload = $this->package->{$getter}();
Chris@0 315 if (empty($autoload)) {
Chris@0 316 return;
Chris@0 317 }
Chris@0 318
Chris@0 319 $unwrapped = self::unwrapIfNeeded($root, $setter);
Chris@0 320 $unwrapped->{$setter}(array_merge_recursive(
Chris@0 321 $root->{$getter}(),
Chris@0 322 $this->fixRelativePaths($autoload)
Chris@0 323 ));
Chris@0 324 }
Chris@0 325
Chris@0 326 /**
Chris@0 327 * Fix a collection of paths that are relative to this package to be
Chris@0 328 * relative to the base package.
Chris@0 329 *
Chris@0 330 * @param array $paths
Chris@0 331 * @return array
Chris@0 332 */
Chris@0 333 protected function fixRelativePaths(array $paths)
Chris@0 334 {
Chris@0 335 $base = dirname($this->path);
Chris@0 336 $base = ($base === '.') ? '' : "{$base}/";
Chris@0 337
Chris@0 338 array_walk_recursive(
Chris@0 339 $paths,
Chris@0 340 function (&$path) use ($base) {
Chris@0 341 $path = "{$base}{$path}";
Chris@0 342 }
Chris@0 343 );
Chris@0 344 return $paths;
Chris@0 345 }
Chris@0 346
Chris@0 347 /**
Chris@0 348 * Extract and merge stability flags from the given collection of
Chris@0 349 * requires and merge them into a RootPackageInterface
Chris@0 350 *
Chris@0 351 * @param RootPackageInterface $root
Chris@0 352 * @param array $requires
Chris@0 353 */
Chris@0 354 protected function mergeStabilityFlags(
Chris@0 355 RootPackageInterface $root,
Chris@0 356 array $requires
Chris@0 357 ) {
Chris@0 358 $flags = $root->getStabilityFlags();
Chris@0 359 $sf = new StabilityFlags($flags, $root->getMinimumStability());
Chris@0 360
Chris@0 361 $unwrapped = self::unwrapIfNeeded($root, 'setStabilityFlags');
Chris@0 362 $unwrapped->setStabilityFlags(array_merge(
Chris@0 363 $flags,
Chris@0 364 $sf->extractAll($requires)
Chris@0 365 ));
Chris@0 366 }
Chris@0 367
Chris@0 368 /**
Chris@0 369 * Merge package links of the given type into a RootPackageInterface
Chris@0 370 *
Chris@0 371 * @param string $type 'conflict', 'replace' or 'provide'
Chris@0 372 * @param RootPackageInterface $root
Chris@0 373 */
Chris@0 374 protected function mergePackageLinks($type, RootPackageInterface $root)
Chris@0 375 {
Chris@0 376 $linkType = BasePackage::$supportedLinkTypes[$type];
Chris@0 377 $getter = 'get' . ucfirst($linkType['method']);
Chris@0 378 $setter = 'set' . ucfirst($linkType['method']);
Chris@0 379
Chris@0 380 $links = $this->package->{$getter}();
Chris@0 381 if (!empty($links)) {
Chris@0 382 $unwrapped = self::unwrapIfNeeded($root, $setter);
Chris@0 383 // @codeCoverageIgnoreStart
Chris@0 384 if ($root !== $unwrapped) {
Chris@0 385 $this->logger->warning(
Chris@0 386 'This Composer version does not support ' .
Chris@0 387 "'{$type}' merging for aliased packages."
Chris@0 388 );
Chris@0 389 }
Chris@0 390 // @codeCoverageIgnoreEnd
Chris@0 391 $unwrapped->{$setter}(array_merge(
Chris@0 392 $root->{$getter}(),
Chris@0 393 $this->replaceSelfVersionDependencies($type, $links, $root)
Chris@0 394 ));
Chris@0 395 }
Chris@0 396 }
Chris@0 397
Chris@0 398 /**
Chris@0 399 * Merge suggested packages into a RootPackageInterface
Chris@0 400 *
Chris@0 401 * @param RootPackageInterface $root
Chris@0 402 */
Chris@0 403 protected function mergeSuggests(RootPackageInterface $root)
Chris@0 404 {
Chris@0 405 $suggests = $this->package->getSuggests();
Chris@0 406 if (!empty($suggests)) {
Chris@0 407 $unwrapped = self::unwrapIfNeeded($root, 'setSuggests');
Chris@0 408 $unwrapped->setSuggests(array_merge(
Chris@0 409 $root->getSuggests(),
Chris@0 410 $suggests
Chris@0 411 ));
Chris@0 412 }
Chris@0 413 }
Chris@0 414
Chris@0 415 /**
Chris@0 416 * Merge extra config into a RootPackageInterface
Chris@0 417 *
Chris@0 418 * @param RootPackageInterface $root
Chris@0 419 * @param PluginState $state
Chris@0 420 */
Chris@0 421 public function mergeExtra(RootPackageInterface $root, PluginState $state)
Chris@0 422 {
Chris@0 423 $extra = $this->package->getExtra();
Chris@0 424 unset($extra['merge-plugin']);
Chris@0 425 if (!$state->shouldMergeExtra() || empty($extra)) {
Chris@0 426 return;
Chris@0 427 }
Chris@0 428
Chris@0 429 $rootExtra = $root->getExtra();
Chris@0 430 $unwrapped = self::unwrapIfNeeded($root, 'setExtra');
Chris@0 431
Chris@0 432 if ($state->replaceDuplicateLinks()) {
Chris@0 433 $unwrapped->setExtra(
Chris@0 434 self::mergeExtraArray($state->shouldMergeExtraDeep(), $rootExtra, $extra)
Chris@0 435 );
Chris@0 436 } else {
Chris@0 437 if (!$state->shouldMergeExtraDeep()) {
Chris@0 438 foreach (array_intersect(
Chris@0 439 array_keys($extra),
Chris@0 440 array_keys($rootExtra)
Chris@0 441 ) as $key) {
Chris@0 442 $this->logger->info(
Chris@0 443 "Ignoring duplicate <comment>{$key}</comment> in ".
Chris@0 444 "<comment>{$this->path}</comment> extra config."
Chris@0 445 );
Chris@0 446 }
Chris@0 447 }
Chris@0 448 $unwrapped->setExtra(
Chris@0 449 self::mergeExtraArray($state->shouldMergeExtraDeep(), $extra, $rootExtra)
Chris@0 450 );
Chris@0 451 }
Chris@0 452 }
Chris@0 453
Chris@0 454 /**
Chris@0 455 * Merge scripts config into a RootPackageInterface
Chris@0 456 *
Chris@0 457 * @param RootPackageInterface $root
Chris@0 458 * @param PluginState $state
Chris@0 459 */
Chris@0 460 public function mergeScripts(RootPackageInterface $root, PluginState $state)
Chris@0 461 {
Chris@0 462 $scripts = $this->package->getScripts();
Chris@0 463 if (!$state->shouldMergeScripts() || empty($scripts)) {
Chris@0 464 return;
Chris@0 465 }
Chris@0 466
Chris@0 467 $rootScripts = $root->getScripts();
Chris@0 468 $unwrapped = self::unwrapIfNeeded($root, 'setScripts');
Chris@0 469
Chris@0 470 if ($state->replaceDuplicateLinks()) {
Chris@0 471 $unwrapped->setScripts(
Chris@0 472 array_merge($rootScripts, $scripts)
Chris@0 473 );
Chris@0 474 } else {
Chris@0 475 $unwrapped->setScripts(
Chris@0 476 array_merge($scripts, $rootScripts)
Chris@0 477 );
Chris@0 478 }
Chris@0 479 }
Chris@0 480
Chris@0 481 /**
Chris@0 482 * Merges two arrays either via arrayMergeDeep or via array_merge.
Chris@0 483 *
Chris@0 484 * @param bool $mergeDeep
Chris@0 485 * @param array $array1
Chris@0 486 * @param array $array2
Chris@0 487 * @return array
Chris@0 488 */
Chris@0 489 public static function mergeExtraArray($mergeDeep, $array1, $array2)
Chris@0 490 {
Chris@0 491 if ($mergeDeep) {
Chris@0 492 return NestedArray::mergeDeep($array1, $array2);
Chris@0 493 }
Chris@0 494
Chris@0 495 return array_merge($array1, $array2);
Chris@0 496 }
Chris@0 497
Chris@0 498 /**
Chris@0 499 * Update Links with a 'self.version' constraint with the root package's
Chris@0 500 * version.
Chris@0 501 *
Chris@0 502 * @param string $type Link type
Chris@0 503 * @param array $links
Chris@0 504 * @param RootPackageInterface $root
Chris@0 505 * @return array
Chris@0 506 */
Chris@0 507 protected function replaceSelfVersionDependencies(
Chris@0 508 $type,
Chris@0 509 array $links,
Chris@0 510 RootPackageInterface $root
Chris@0 511 ) {
Chris@0 512 $linkType = BasePackage::$supportedLinkTypes[$type];
Chris@0 513 $version = $root->getVersion();
Chris@0 514 $prettyVersion = $root->getPrettyVersion();
Chris@0 515 $vp = $this->versionParser;
Chris@0 516
Chris@0 517 $method = 'get' . ucfirst($linkType['method']);
Chris@0 518 $packages = $root->$method();
Chris@0 519
Chris@0 520 return array_map(
Chris@0 521 function ($link) use ($linkType, $version, $prettyVersion, $vp, $packages) {
Chris@0 522 if ('self.version' === $link->getPrettyConstraint()) {
Chris@0 523 if (isset($packages[$link->getSource()])) {
Chris@0 524 /** @var Link $package */
Chris@0 525 $package = $packages[$link->getSource()];
Chris@0 526 return new Link(
Chris@0 527 $link->getSource(),
Chris@0 528 $link->getTarget(),
Chris@0 529 $vp->parseConstraints($package->getConstraint()->getPrettyString()),
Chris@0 530 $linkType['description'],
Chris@0 531 $package->getPrettyConstraint()
Chris@0 532 );
Chris@0 533 }
Chris@0 534
Chris@0 535 return new Link(
Chris@0 536 $link->getSource(),
Chris@0 537 $link->getTarget(),
Chris@0 538 $vp->parseConstraints($version),
Chris@0 539 $linkType['description'],
Chris@0 540 $prettyVersion
Chris@0 541 );
Chris@0 542 }
Chris@0 543 return $link;
Chris@0 544 },
Chris@0 545 $links
Chris@0 546 );
Chris@0 547 }
Chris@0 548
Chris@0 549 /**
Chris@0 550 * Get a full featured Package from a RootPackageInterface.
Chris@0 551 *
Chris@0 552 * In Composer versions before 599ad77 the RootPackageInterface only
Chris@0 553 * defines a sub-set of operations needed by composer-merge-plugin and
Chris@0 554 * RootAliasPackage only implemented those methods defined by the
Chris@0 555 * interface. Most of the unimplemented methods in RootAliasPackage can be
Chris@0 556 * worked around because the getter methods that are implemented proxy to
Chris@0 557 * the aliased package which we can modify by unwrapping. The exception
Chris@0 558 * being modifying the 'conflicts', 'provides' and 'replaces' collections.
Chris@0 559 * We have no way to actually modify those collections unfortunately in
Chris@0 560 * older versions of Composer.
Chris@0 561 *
Chris@0 562 * @param RootPackageInterface $root
Chris@0 563 * @param string $method Method needed
Chris@0 564 * @return RootPackageInterface|RootPackage
Chris@0 565 */
Chris@0 566 public static function unwrapIfNeeded(
Chris@0 567 RootPackageInterface $root,
Chris@0 568 $method = 'setExtra'
Chris@0 569 ) {
Chris@0 570 // @codeCoverageIgnoreStart
Chris@0 571 if ($root instanceof RootAliasPackage &&
Chris@0 572 !method_exists($root, $method)
Chris@0 573 ) {
Chris@0 574 // Unwrap and return the aliased RootPackage.
Chris@0 575 $root = $root->getAliasOf();
Chris@0 576 }
Chris@0 577 // @codeCoverageIgnoreEnd
Chris@0 578 return $root;
Chris@0 579 }
Chris@0 580
Chris@0 581 /**
Chris@0 582 * Update the root packages reference information.
Chris@0 583 *
Chris@0 584 * @param RootPackageInterface $root
Chris@0 585 */
Chris@0 586 protected function mergeReferences(RootPackageInterface $root)
Chris@0 587 {
Chris@0 588 // Merge source reference information for merged packages.
Chris@0 589 // @see RootPackageLoader::load
Chris@0 590 $references = array();
Chris@0 591 $unwrapped = $this->unwrapIfNeeded($root, 'setReferences');
Chris@0 592 foreach (array('require', 'require-dev') as $linkType) {
Chris@0 593 $linkInfo = BasePackage::$supportedLinkTypes[$linkType];
Chris@0 594 $method = 'get'.ucfirst($linkInfo['method']);
Chris@0 595 $links = array();
Chris@0 596 foreach ($unwrapped->$method() as $link) {
Chris@0 597 $links[$link->getTarget()] = $link->getConstraint()->getPrettyString();
Chris@0 598 }
Chris@0 599 $references = $this->extractReferences($links, $references);
Chris@0 600 }
Chris@0 601 $unwrapped->setReferences($references);
Chris@0 602 }
Chris@0 603
Chris@0 604 /**
Chris@0 605 * Extract vcs revision from version constraint (dev-master#abc123.
Chris@0 606 *
Chris@0 607 * @param array $requires
Chris@0 608 * @param array $references
Chris@0 609 * @return array
Chris@0 610 * @see RootPackageLoader::extractReferences()
Chris@0 611 */
Chris@0 612 protected function extractReferences(array $requires, array $references)
Chris@0 613 {
Chris@0 614 foreach ($requires as $reqName => $reqVersion) {
Chris@0 615 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
Chris@0 616 $stabilityName = VersionParser::parseStability($reqVersion);
Chris@0 617 if (
Chris@0 618 preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) &&
Chris@0 619 $stabilityName === 'dev'
Chris@0 620 ) {
Chris@0 621 $name = strtolower($reqName);
Chris@0 622 $references[$name] = $match[1];
Chris@0 623 }
Chris@0 624 }
Chris@0 625
Chris@0 626 return $references;
Chris@0 627 }
Chris@0 628 }
Chris@0 629 // vim:sw=4:ts=4:sts=4:et: