From 4d0db5add61a1108e266520c97c98ea7481be3f7 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 May 2015 17:25:55 +0200 Subject: [PATCH] POC Implementation of loading only explicitly named package data --- src/Composer/DependencyResolver/Pool.php | 7 + src/Composer/DependencyResolver/Solver.php | 15 ++ .../Repository/ComposerRepository.php | 160 +++++++++++++++++- 3 files changed, 181 insertions(+), 1 deletion(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 000d63805..510b8f03d 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -160,6 +160,13 @@ class Pool return $this->packages[$id - 1]; } + public function ensureLoaded($constrainedNames) + { + foreach ($this->providerRepos as $repo) { + $repo->ensureLoaded($this, $constrainedNames); + } + } + /** * Searches all packages providing the given package name and match the constraint * diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 6975df2cd..402828cea 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -169,6 +169,21 @@ class Solver $this->jobs = $request->getJobs(); $this->setupInstalledMap(); + + $constrainedNames = array(); + foreach ($this->jobs as $job) { + switch ($job['cmd']) { + case 'install': + $constrainedNames[] = array( + 'name' => $job['packageName'], + 'constraint' => $job['constraint'], + ); + break; + } + } + + $this->pool->ensureLoaded($constrainedNames); + $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs); $this->checkForRootRequireProblems($ignorePlatformReqs); $this->decisions = new Decisions($this->pool); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index bd84ae187..af2579e51 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -96,6 +96,161 @@ class ComposerRepository extends ArrayRepository $this->rootAliases = $rootAliases; } + public function ensureLoaded($pool, array $constrainedNames) + { + $workQueue = new \SplQueue; + + foreach ($constrainedNames as $packageSpec) { + $workQueue->enqueue($packageSpec); + } + + $loadedMap = array(); + + while (!$workQueue->isEmpty()) { + $packageSpec = $workQueue->dequeue(); + if (isset($this->loadedMap[$packageSpec['name']])) { + continue; + } + + $this->loadedMap[$packageSpec['name']] = true; + + $packages = $this->loadName($pool, $packageSpec['name']); + + foreach ($packages as $package) { + foreach ($package->getRequires() as $link) { + $workQueue->enqueue(array( + 'name' => $link->getTarget(), + 'constraint' => $link->getConstraint() + )); + } + } + } + } + + protected function loadName($pool, $name) + {echo "Loading $name\n"; + // skip platform packages + if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) { + return array(); + } + + if (null === $this->providerListing) { + $this->loadProviderListings($this->loadRootServerFile()); + } + + if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) { + $hash = null; + $url = str_replace('%package%', $name, $this->lazyProvidersUrl); + $cacheKey = false; + } elseif ($this->providersUrl) { + // package does not exist in this repo + if (!isset($this->providerListing[$name])) { + $this->providers[$name] = array(); + return array(); + } + + $hash = $this->providerListing[$name]['sha256']; + $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl); + $cacheKey = 'provider-'.strtr($name, '/', '$').'.json'; + } else { + // BC handling for old providers-includes + $url = 'p/'.$name.'.json'; + + // package does not exist in this repo + if (!isset($this->providerListing[$url])) { + $this->providers[$name] = array(); + return array(); + } + $hash = $this->providerListing[$url]['sha256']; + $cacheKey = null; + } + + if ($cacheKey && $this->cache->sha256($cacheKey) === $hash) { + $packages = json_decode($this->cache->read($cacheKey), true); + } else { + $packages = $this->fetchFile($url, $cacheKey, $hash); + } + + $this->providers[$name] = array(); + $loadedPackages = array(); + foreach ($packages['packages'] as $versions) { + foreach ($versions as $version) { + if ($version['name'] !== $name) { + continue; + } + + // avoid loading the same objects twice + if (isset($this->providersByUid[$version['uid']])) {die("wtf?"); + // skip if already assigned + if (!isset($this->providers[$name][$version['uid']])) { + // expand alias in two packages + if ($this->providersByUid[$version['uid']] instanceof AliasPackage) { + $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']]->getAliasOf(); + $this->providers[$name][$version['uid'].'-alias'] = $this->providersByUid[$version['uid']]; + } else { + $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']]; + } + // check for root aliases + if (isset($this->providersByUid[$version['uid'].'-root'])) { + $this->providers[$name][$version['uid'].'-root'] = $this->providersByUid[$version['uid'].'-root']; + } + } + } else { + if (!$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) { + continue; + } + + // load acceptable packages in the providers + $package = $this->createPackage($version, 'Composer\Package\Package'); + $package->setRepository($this); + + $loadedPackages[] = $package; + + 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; + } + } + } + } + + return $loadedPackages; + } + /** * {@inheritDoc} */ @@ -257,9 +412,12 @@ class ComposerRepository extends ArrayRepository } // skip platform packages - if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) { + if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) { return array(); } + var_dump($name); + debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + die("should not reach\n"); if (null === $this->providerListing) { $this->loadProviderListings($this->loadRootServerFile());