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:
|