From 090711b21cd2ec0550642f957e14dccf9442fa88 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 19:08:33 +0200 Subject: [PATCH] Completely move loading of packages from composer repo to pool --- src/Composer/DependencyResolver/Pool.php | 103 +++++++++----- src/Composer/DependencyResolver/Solver.php | 9 +- .../Repository/ComposerRepository.php | 129 +++++------------- 3 files changed, 105 insertions(+), 136 deletions(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 510b8f03d..aa4b86923 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -102,42 +102,50 @@ class Pool $repo->resetPackageIds(); } else { foreach ($repo->getPackages() as $package) { - $names = $package->getNames(); - $stability = $package->getStability(); - if ($exempt || $this->isPackageAcceptable($names, $stability)) { - $package->setId($this->id++); - $this->packages[] = $package; - $this->packageByExactName[$package->getName()][$package->id] = $package; - - foreach ($names as $provided) { - $this->packageByName[$provided][] = $package; - } - - // handle root package aliases - $name = $package->getName(); - if (isset($rootAliases[$name][$package->getVersion()])) { - $alias = $rootAliases[$name][$package->getVersion()]; - if ($package instanceof AliasPackage) { - $package = $package->getAliasOf(); - } - $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); - $aliasPackage->setRootPackageAlias(true); - $aliasPackage->setId($this->id++); - - $package->getRepository()->addPackage($aliasPackage); - $this->packages[] = $aliasPackage; - $this->packageByExactName[$aliasPackage->getName()][$aliasPackage->id] = $aliasPackage; - - foreach ($aliasPackage->getNames() as $name) { - $this->packageByName[$name][] = $aliasPackage; - } - } - } + $this->loadPackage($package, $rootAliases, $exempt); } } } } + private function loadPackage(PackageInterface $package, array $rootAliases, $acceptableExemption = false) + { + $names = $package->getNames(); + $stability = $package->getStability(); + + if (!$acceptableExemption && !$this->isPackageAcceptable($names, $stability)) { + return; + } + + $package->setId($this->id++); + $this->packages[] = $package; + $this->packageByExactName[$package->getName()][$package->id] = $package; + + foreach ($names as $provided) { + $this->packageByName[$provided][] = $package; + } + + // handle root package aliases + $name = $package->getName(); + if (isset($rootAliases[$name][$package->getVersion()])) { + $alias = $rootAliases[$name][$package->getVersion()]; + if ($package instanceof AliasPackage) { + $package = $package->getAliasOf(); + } + $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); + $aliasPackage->setRootPackageAlias(true); + $aliasPackage->setId($this->id++); + + $package->getRepository()->addPackage($aliasPackage); + $this->packages[] = $aliasPackage; + $this->packageByExactName[$aliasPackage->getName()][$aliasPackage->id] = $aliasPackage; + + foreach ($aliasPackage->getNames() as $name) { + $this->packageByName[$name][] = $aliasPackage; + } + } + } + public function getPriority(RepositoryInterface $repo) { $priority = array_search($repo, $this->repositories, true); @@ -160,11 +168,32 @@ class Pool return $this->packages[$id - 1]; } - public function ensureLoaded($constrainedNames) + public function loadRecursively(array $packageNames, $loadDev) { - foreach ($this->providerRepos as $repo) { - $repo->ensureLoaded($this, $constrainedNames); - } + $loadedMap = array(); + do { + $newPackageNames = array(); + $loadedCount = count($loadedMap); + + foreach ($this->providerRepos as $repo) { + $packages = $repo->loadRecursively( + $packageNames, + $loadDev, + array($this, 'isPackageAcceptable') + ); + + foreach ($packages as $package) { + $name = $package->getName(); + if (!isset($loadedMap[$name])) { + $loadedMap[$name] = true; + $newPackageNames[] = $name; + } + $this->loadPackage($package, $repo->getRootAliases()); + } + } + + $packageNames = $newPackageNames; + } while (count($loadedMap) > $loadedCount); } /** @@ -193,7 +222,7 @@ class Pool private function computeWhatProvides($name, $constraint, $mustMatchName = false) { $candidates = array(); - +/* foreach ($this->providerRepos as $repo) { foreach ($repo->whatProvides($this, $name) as $candidate) { $candidates[] = $candidate; @@ -202,7 +231,7 @@ class Pool $this->packages[$this->id - 2] = $candidate; } } - } + }*/ if ($mustMatchName) { $candidates = array_filter($candidates, function ($candidate) use ($name) { diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 402828cea..2ad1d2be2 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -170,19 +170,16 @@ class Solver $this->setupInstalledMap(); - $constrainedNames = array(); + $packageNames = array(); foreach ($this->jobs as $job) { switch ($job['cmd']) { case 'install': - $constrainedNames[] = array( - 'name' => $job['packageName'], - 'constraint' => $job['constraint'], - ); + $packageNames[] = $job['packageName']; break; } } - $this->pool->ensureLoaded($constrainedNames); + $this->pool->loadRecursively($packageNames, true); $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs); $this->checkForRootRequireProblems($ignorePlatformReqs); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 0a98e62da..c324a44bb 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -43,10 +43,9 @@ class ComposerRepository extends ArrayRepository protected $searchUrl; protected $hasProviders = false; protected $providersUrl; + protected $loadedMap = array(); protected $lazyProvidersUrl; protected $providerListing; - protected $providers = array(); - protected $providersByUid = array(); protected $loader; protected $rootAliases; protected $allowSslDowngrade = false; @@ -96,38 +95,47 @@ class ComposerRepository extends ArrayRepository $this->rootAliases = $rootAliases; } - public function ensureLoaded($pool, array $constrainedNames) + public function getRootAliases() + { + return $this->rootAliases; + } + + public function loadRecursively(array $packageNames, $loadDev, $acceptableCallback) { $workQueue = new \SplQueue; - foreach ($constrainedNames as $packageSpec) { - $workQueue->enqueue($packageSpec); + foreach ($packageNames as $packageName) { + $workQueue->enqueue($packageName); } - $loadedMap = array(); + $loadedPackages = array(); while (!$workQueue->isEmpty()) { - $packageSpec = $workQueue->dequeue(); - if (isset($this->loadedMap[$packageSpec['name']])) { + $packageName = $workQueue->dequeue(); + if (isset($this->loadedMap[$packageName])) { continue; } - $this->loadedMap[$packageSpec['name']] = true; + $this->loadedMap[$packageName] = true; - $packages = $this->loadName($pool, $packageSpec['name']); + $packages = $this->loadName($packageName, $acceptableCallback); foreach ($packages as $package) { - foreach ($package->getRequires() as $link) { - $workQueue->enqueue(array( - 'name' => $link->getTarget(), - 'constraint' => $link->getConstraint() - )); + $loadedPackages[] = $package; + $requires = $package->getRequires(); + if ($loadDev) { + $requires = array_merge($requires, $package->getDevRequires()); + } + foreach ($requires as $link) { + $workQueue->enqueue($link->getTarget()); } } } + + return $loadedPackages; } - protected function loadName($pool, $name) + protected function loadName($name, $acceptableCallback) { // skip platform packages if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) { @@ -145,7 +153,6 @@ class ComposerRepository extends ArrayRepository } elseif ($this->providersUrl) { // package does not exist in this repo if (!isset($this->providerListing[$name])) { - $this->providers[$name] = array(); return array(); } @@ -158,7 +165,6 @@ class ComposerRepository extends ArrayRepository // package does not exist in this repo if (!isset($this->providerListing[$url])) { - $this->providers[$name] = array(); return array(); } $hash = $this->providerListing[$url]['sha256']; @@ -171,7 +177,6 @@ class ComposerRepository extends ArrayRepository $packages = $this->fetchFile($url, $cacheKey, $hash); } - $this->providers[$name] = array(); $loadedPackages = array(); foreach ($packages['packages'] as $versions) { foreach ($versions as $version) { @@ -179,61 +184,21 @@ class ComposerRepository extends ArrayRepository continue; } - // avoid loading the same objects twice - if (isset($this->providersByUid[$version['uid']])) { - /** - * @todo verify and remove - */ - throw new \RuntimeException("Should not happen anymore"); - } else { - if (!$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) { - continue; - } + if (!$acceptableCallback(strtolower($version['name']), VersionParser::parseStability($version['version']))) { + continue; + } - // load acceptable packages in the providers - $package = $this->createPackage($version, 'Composer\Package\Package'); - $package->setRepository($this); + // load acceptable packages in the providers + $package = $this->createPackage($version, 'Composer\Package\Package'); + $package->setRepository($this); - $loadedPackages[] = $package; + $loadedPackages[] = $package; - if ($package instanceof AliasPackage) { - $aliased = $package->getAliasOf(); - $aliased->setRepository($this); + if ($package instanceof AliasPackage) { + $aliased = $package->getAliasOf(); + $aliased->setRepository($this); - $loadedPackages[] = $aliased; - - foreach ($aliased->getNames() as $providedName) { - $this->providers[$providedName][$version['uid']] = $aliased; - $this->providers[$providedName][$version['uid'].'-alias'] = $package; - } - - // override provider with its alias so it can be expanded in the if block above - $this->providersByUid[$version['uid']] = $package; - } else { - foreach ($package->getNames() as $providedName) { - $this->providers[$providedName][$version['uid']] = $package; - } - $this->providersByUid[$version['uid']] = $package; - } - - // handle root package aliases - unset($rootAliasData); - - if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) { - $rootAliasData = $this->rootAliases[$package->getName()][$package->getVersion()]; - } elseif ($package instanceof AliasPackage && isset($this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()])) { - $rootAliasData = $this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()]; - } - - if (isset($rootAliasData)) { - $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']); - $alias->setRepository($this); - - $loadedPackages[] = $alias; - - $this->providers[$name][$version['uid'].'-root'] = $alias; - $this->providersByUid[$version['uid'].'-root'] = $alias; - } + $loadedPackages[] = $aliased; } } } @@ -385,31 +350,9 @@ class ComposerRepository extends ArrayRepository return $this->hasProviders; } - public function resetPackageIds() - { - foreach ($this->providersByUid as $package) { - if ($package instanceof AliasPackage) { - $package->getAliasOf()->setId(-1); - } - $package->setId(-1); - } - } - public function whatProvides(Pool $pool, $name) { - if (isset($this->providers[$name])) { - return $this->providers[$name]; - } - - // skip platform packages - if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) { - return array(); - } - - /** - * @todo verify this is no longer possible and change code to remove this - */ - throw new \RuntimeException("Could not find package that should have been loaded."); + throw new \RuntimeException("Runtime repository provider calculation no longer occurs"); } /**