RootPackageLoader.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Package\Loader;
  12. use Composer\Package\BasePackage;
  13. use Composer\Package\PackageInterface;
  14. use Composer\Package\AliasPackage;
  15. use Composer\Config;
  16. use Composer\Factory;
  17. use Composer\Package\Version\VersionGuesser;
  18. use Composer\Package\Version\VersionParser;
  19. use Composer\Repository\RepositoryManager;
  20. use Composer\Util\ProcessExecutor;
  21. /**
  22. * ArrayLoader built for the sole purpose of loading the root package
  23. *
  24. * Sets additional defaults and loads repositories
  25. *
  26. * @author Jordi Boggiano <j.boggiano@seld.be>
  27. */
  28. class RootPackageLoader extends ArrayLoader
  29. {
  30. /**
  31. * @var RepositoryManager
  32. */
  33. private $manager;
  34. /**
  35. * @var Config
  36. */
  37. private $config;
  38. /**
  39. * @var VersionGuesser
  40. */
  41. private $versionGuesser;
  42. public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null)
  43. {
  44. parent::__construct($parser);
  45. $this->manager = $manager;
  46. $this->config = $config;
  47. $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor(), $this->versionParser);
  48. }
  49. /**
  50. * @param array $config package data
  51. * @param string $class FQCN to be instantiated
  52. * @param string $cwd cwd of the root package to be used to guess the version if it is not provided
  53. * @return PackageInterface
  54. */
  55. public function load(array $config, $class = 'Composer\Package\RootPackage', $cwd = null)
  56. {
  57. if (!isset($config['name'])) {
  58. $config['name'] = '__root__';
  59. }
  60. $autoVersioned = false;
  61. if (!isset($config['version'])) {
  62. // override with env var if available
  63. if (getenv('COMPOSER_ROOT_VERSION')) {
  64. $version = getenv('COMPOSER_ROOT_VERSION');
  65. $commit = null;
  66. } else {
  67. $versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
  68. $version = $versionData['version'];
  69. $commit = $versionData['commit'];
  70. }
  71. if (!$version) {
  72. $version = '1.0.0';
  73. $autoVersioned = true;
  74. }
  75. $config['version'] = $version;
  76. if($commit){
  77. $config['source'] = array(
  78. 'type' => '',
  79. 'url' => '',
  80. 'reference' => $commit
  81. );
  82. }
  83. }
  84. $realPackage = $package = parent::load($config, $class);
  85. if ($realPackage instanceof AliasPackage) {
  86. $realPackage = $package->getAliasOf();
  87. }
  88. if ($autoVersioned) {
  89. $realPackage->replaceVersion($realPackage->getVersion(), 'No version set (parsed as 1.0.0)');
  90. }
  91. if (isset($config['minimum-stability'])) {
  92. $realPackage->setMinimumStability(VersionParser::normalizeStability($config['minimum-stability']));
  93. }
  94. $aliases = array();
  95. $stabilityFlags = array();
  96. $references = array();
  97. foreach (array('require', 'require-dev') as $linkType) {
  98. if (isset($config[$linkType])) {
  99. $linkInfo = BasePackage::$supportedLinkTypes[$linkType];
  100. $method = 'get'.ucfirst($linkInfo['method']);
  101. $links = array();
  102. foreach ($realPackage->$method() as $link) {
  103. $links[$link->getTarget()] = $link->getConstraint()->getPrettyString();
  104. }
  105. $aliases = $this->extractAliases($links, $aliases);
  106. $stabilityFlags = $this->extractStabilityFlags($links, $stabilityFlags, $realPackage->getMinimumStability());
  107. $references = $this->extractReferences($links, $references);
  108. }
  109. }
  110. if (isset($links[$config['name']])) {
  111. throw new \InvalidArgumentException(sprintf('Root package \'%s\' cannot require itself in its composer.json' . PHP_EOL .
  112. 'Did you accidentally name your root package after an external package?', $config['name']));
  113. }
  114. $realPackage->setAliases($aliases);
  115. $realPackage->setStabilityFlags($stabilityFlags);
  116. $realPackage->setReferences($references);
  117. if (isset($config['prefer-stable'])) {
  118. $realPackage->setPreferStable((bool) $config['prefer-stable']);
  119. }
  120. $repos = Factory::createDefaultRepositories(null, $this->config, $this->manager);
  121. foreach ($repos as $repo) {
  122. $this->manager->addRepository($repo);
  123. }
  124. $realPackage->setRepositories($this->config->getRepositories());
  125. return $package;
  126. }
  127. private function extractAliases(array $requires, array $aliases)
  128. {
  129. foreach ($requires as $reqName => $reqVersion) {
  130. if (preg_match('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) {
  131. $aliases[] = array(
  132. 'package' => strtolower($reqName),
  133. 'version' => $this->versionParser->normalize($match[1], $reqVersion),
  134. 'alias' => $match[2],
  135. 'alias_normalized' => $this->versionParser->normalize($match[2], $reqVersion),
  136. );
  137. }
  138. }
  139. return $aliases;
  140. }
  141. private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability)
  142. {
  143. $stabilities = BasePackage::$stabilities;
  144. $minimumStability = $stabilities[$minimumStability];
  145. foreach ($requires as $reqName => $reqVersion) {
  146. $constraints = array();
  147. // extract all sub-constraints in case it is an OR/AND multi-constraint
  148. $orSplit = preg_split('{\s*\|\|?\s*}', trim($reqVersion));
  149. foreach ($orSplit as $constraint) {
  150. $andSplit = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraint);
  151. foreach ($andSplit as $constraint) {
  152. $constraints[] = $constraint;
  153. }
  154. }
  155. // parse explicit stability flags to the most unstable
  156. $match = false;
  157. foreach ($constraints as $constraint) {
  158. if (preg_match('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) {
  159. $name = strtolower($reqName);
  160. $stability = $stabilities[VersionParser::normalizeStability($match[1])];
  161. if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) {
  162. continue;
  163. }
  164. $stabilityFlags[$name] = $stability;
  165. $match = true;
  166. }
  167. }
  168. if ($match) {
  169. continue;
  170. }
  171. // infer flags for requirements that have an explicit -dev or -beta version specified but only
  172. // for those that are more unstable than the minimumStability or existing flags
  173. $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
  174. if (preg_match('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) {
  175. $name = strtolower($reqName);
  176. $stability = $stabilities[$stabilityName];
  177. if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) {
  178. continue;
  179. }
  180. $stabilityFlags[$name] = $stability;
  181. }
  182. }
  183. return $stabilityFlags;
  184. }
  185. private function extractReferences(array $requires, array $references)
  186. {
  187. foreach ($requires as $reqName => $reqVersion) {
  188. $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
  189. if (preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === ($stabilityName = VersionParser::parseStability($reqVersion))) {
  190. $name = strtolower($reqName);
  191. $references[$name] = $match[1];
  192. }
  193. }
  194. return $references;
  195. }
  196. }