From 4d0db5add61a1108e266520c97c98ea7481be3f7 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 May 2015 17:25:55 +0200 Subject: [PATCH 01/15] 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()); From 65f69c4227f4525d2dee2bb7ab08fa84783843ff Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 May 2015 17:28:03 +0200 Subject: [PATCH 02/15] Remove debug output --- src/Composer/Repository/ComposerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index af2579e51..6c5984f3d 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -128,7 +128,7 @@ class ComposerRepository extends ArrayRepository } protected function loadName($pool, $name) - {echo "Loading $name\n"; + { // skip platform packages if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) { return array(); From 709943aca58cadfe6d373fee54484317df55d7a5 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 May 2015 17:30:53 +0200 Subject: [PATCH 03/15] ComposerRepository works differently now, so comment out test until replaced --- tests/Composer/Test/Repository/ComposerRepositoryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 5109ee41f..3066e2540 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -97,7 +97,7 @@ class ComposerRepositoryTest extends TestCase } public function testWhatProvides() - { + {/* $repo = $this->getMockBuilder('Composer\Repository\ComposerRepository') ->disableOriginalConstructor() ->setMethods(array('fetchFile')) @@ -163,6 +163,6 @@ class ComposerRepositoryTest extends TestCase $this->assertEquals(array('1', '1-alias', '2', '2-alias', '2-root', '3', '3-root'), array_keys($packages)); $this->assertInstanceOf('Composer\Package\AliasPackage', $packages['2-root']); $this->assertSame($packages['2'], $packages['2-root']->getAliasOf()); - $this->assertSame($packages['2'], $packages['2-alias']->getAliasOf()); + $this->assertSame($packages['2'], $packages['2-alias']->getAliasOf());*/ } } From 9b9ad9d0fe22d59feb4de9d9db41e3e63812547f Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 May 2015 17:34:41 +0200 Subject: [PATCH 04/15] Remove dead code paths and use exceptions instead of die --- .../Repository/ComposerRepository.php | 125 ++---------------- 1 file changed, 9 insertions(+), 116 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 6c5984f3d..0a98e62da 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -180,21 +180,11 @@ class ComposerRepository extends ArrayRepository } // 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']; - } - } + 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; @@ -415,108 +405,11 @@ class ComposerRepository extends ArrayRepository 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()); - } - - 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])) { - 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])) { - 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(); - foreach ($packages['packages'] as $versions) { - foreach ($versions as $version) { - // avoid loading the same objects twice - if (isset($this->providersByUid[$version['uid']])) { - // 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); - - if ($package instanceof AliasPackage) { - $aliased = $package->getAliasOf(); - $aliased->setRepository($this); - - $this->providers[$name][$version['uid']] = $aliased; - $this->providers[$name][$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 { - $this->providers[$name][$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); - - $this->providers[$name][$version['uid'].'-root'] = $alias; - $this->providersByUid[$version['uid'].'-root'] = $alias; - } - } - } - } - return $this->providers[$name]; + /** + * @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."); } /** From 090711b21cd2ec0550642f957e14dccf9442fa88 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 19:08:33 +0200 Subject: [PATCH 05/15] 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; - } - - // 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 (!$acceptableCallback(strtolower($version['name']), VersionParser::parseStability($version['version']))) { + continue; + } - 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()]; - } + // load acceptable packages in the providers + $package = $this->createPackage($version, 'Composer\Package\Package'); + $package->setRepository($this); - if (isset($rootAliasData)) { - $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']); - $alias->setRepository($this); + $loadedPackages[] = $package; - $loadedPackages[] = $alias; + if ($package instanceof AliasPackage) { + $aliased = $package->getAliasOf(); + $aliased->setRepository($this); - $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"); } /** From b99c03ea043c903961c0b1f9f7613e0c5ce81629 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 19:28:15 +0200 Subject: [PATCH 06/15] Entirely remove whatProvides from Composer repository --- src/Composer/DependencyResolver/Pool.php | 18 ++------------- .../Repository/ComposerRepository.php | 22 ++++++------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index aa4b86923..059cbfc0d 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -99,7 +99,6 @@ class Pool if ($repo instanceof ComposerRepository && $repo->hasProviders()) { $this->providerRepos[] = $repo; $repo->setRootAliases($rootAliases); - $repo->resetPackageIds(); } else { foreach ($repo->getPackages() as $package) { $this->loadPackage($package, $rootAliases, $exempt); @@ -222,26 +221,13 @@ 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; - if ($candidate->id < 1) { - $candidate->setId($this->id++); - $this->packages[$this->id - 2] = $candidate; - } - } - }*/ if ($mustMatchName) { - $candidates = array_filter($candidates, function ($candidate) use ($name) { - return $candidate->getName() == $name; - }); if (isset($this->packageByExactName[$name])) { - $candidates = array_merge($candidates, $this->packageByExactName[$name]); + $candidates = $this->packageByExactName[$name]; } } elseif (isset($this->packageByName[$name])) { - $candidates = array_merge($candidates, $this->packageByName[$name]); + $candidates = $this->packageByName[$name]; } $matches = $provideMatches = array(); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index c324a44bb..89c2b75b2 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -135,7 +135,7 @@ class ComposerRepository extends ArrayRepository return $loadedPackages; } - protected function loadName($name, $acceptableCallback) + protected function loadName($name, $acceptableCallback, $exactMatch = true) { // skip platform packages if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) { @@ -180,25 +180,22 @@ class ComposerRepository extends ArrayRepository $loadedPackages = array(); foreach ($packages['packages'] as $versions) { foreach ($versions as $version) { - if ($version['name'] !== $name) { + if ($exactMatch && $version['name'] !== $name) { continue; } - if (!$acceptableCallback(strtolower($version['name']), VersionParser::parseStability($version['version']))) { + if ($acceptableCallback && !$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); + $this->addPackage($package); $loadedPackages[] = $package; if ($package instanceof AliasPackage) { - $aliased = $package->getAliasOf(); - $aliased->setRepository($this); - - $loadedPackages[] = $aliased; + $loadedPackages[] = $package->getAliasOf(); } } } @@ -221,7 +218,7 @@ class ComposerRepository extends ArrayRepository foreach ($this->getProviderNames() as $providerName) { if ($name === $providerName) { - $packages = $this->whatProvides(new Pool('dev'), $providerName); + $packages = $this->loadName($providerName, null, false); foreach ($packages as $package) { if ($name == $package->getName() && $version === $package->getVersion()) { return $package; @@ -252,7 +249,7 @@ class ComposerRepository extends ArrayRepository foreach ($this->getProviderNames() as $providerName) { if ($name === $providerName) { - $packages = $this->whatProvides(new Pool('dev'), $providerName); + $packages = $this->loadName($providerName, null, false); foreach ($packages as $package) { if ($name == $package->getName() && (null === $version || $version === $package->getVersion())) { $packages[] = $package; @@ -350,11 +347,6 @@ class ComposerRepository extends ArrayRepository return $this->hasProviders; } - public function whatProvides(Pool $pool, $name) - { - throw new \RuntimeException("Runtime repository provider calculation no longer occurs"); - } - /** * {@inheritDoc} */ From da02c53540c6f7a13c162054203465aa0c7ebdee Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 19:44:07 +0200 Subject: [PATCH 07/15] Update the composer repository whatprovides test to a loadrecursively test --- src/Composer/DependencyResolver/Solver.php | 4 +-- .../Repository/ComposerRepositoryTest.php | 34 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 2ad1d2be2..7dd947acf 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -174,12 +174,12 @@ class Solver foreach ($this->jobs as $job) { switch ($job['cmd']) { case 'install': - $packageNames[] = $job['packageName']; + $packageNames[$job['packageName']] = true; break; } } - $this->pool->loadRecursively($packageNames, true); + $this->pool->loadRecursively(array_keys($packageNames), true); $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs); $this->checkForRootRequireProblems($ignorePlatformReqs); diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 3066e2540..4e4fc99bb 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -96,8 +96,8 @@ class ComposerRepositoryTest extends TestCase ); } - public function testWhatProvides() - {/* + public function testLoadRecursively() + { $repo = $this->getMockBuilder('Composer\Repository\ComposerRepository') ->disableOriginalConstructor() ->setMethods(array('fetchFile')) @@ -144,25 +144,19 @@ class ComposerRepositoryTest extends TestCase ) ))); - $pool = $this->getMock('Composer\DependencyResolver\Pool'); - $pool->expects($this->any()) - ->method('isPackageAcceptable') - ->will($this->returnValue(true)); - $versionParser = new VersionParser(); - $repo->setRootAliases(array( - 'a' => array( - $versionParser->normalize('0.6') => array('alias' => 'dev-feature', 'alias_normalized' => $versionParser->normalize('dev-feature')), - $versionParser->normalize('1.1.x-dev') => array('alias' => '1.0', 'alias_normalized' => $versionParser->normalize('1.0')), - ), - )); - - $packages = $repo->whatProvides($pool, 'a'); - $this->assertCount(7, $packages); - $this->assertEquals(array('1', '1-alias', '2', '2-alias', '2-root', '3', '3-root'), array_keys($packages)); - $this->assertInstanceOf('Composer\Package\AliasPackage', $packages['2-root']); - $this->assertSame($packages['2'], $packages['2-root']->getAliasOf()); - $this->assertSame($packages['2'], $packages['2-alias']->getAliasOf());*/ + $that = $this; + $packages = $repo->loadRecursively(array('a'), true, function ($name, $stability) use ($that) { + $this->assertEquals('a', $name); + return true; + }); + + $this->assertCount(5, $packages); + $this->assertEquals(array('1.0.x-dev', 'dev-master', '1.1.x-dev', 'dev-develop', '0.6'), array_map(function ($p) { + return $p->getPrettyVersion(); + }, $packages)); + $this->assertInstanceOf('Composer\Package\AliasPackage', $packages[2]); + $this->assertSame($packages[3], $packages[2]->getAliasOf()); } } From ec5416f03c763ed79f8af3801a7678114a763392 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 19:55:49 +0200 Subject: [PATCH 08/15] loadDev parameter is nonsense, properly load packages in create command --- src/Composer/Command/CreateProjectCommand.php | 1 + src/Composer/DependencyResolver/Pool.php | 3 +-- src/Composer/DependencyResolver/Solver.php | 2 +- src/Composer/Repository/ComposerRepository.php | 5 +---- tests/Composer/Test/Repository/ComposerRepositoryTest.php | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 65366dfe2..299758311 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -276,6 +276,7 @@ EOT $pool = new Pool($stability); $pool->addRepository($sourceRepo); + $pool->loadRecursively(array($name)); // find the latest version if there are multiple $versionSelector = new VersionSelector($pool); diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 059cbfc0d..566c6e262 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -167,7 +167,7 @@ class Pool return $this->packages[$id - 1]; } - public function loadRecursively(array $packageNames, $loadDev) + public function loadRecursively(array $packageNames) { $loadedMap = array(); do { @@ -177,7 +177,6 @@ class Pool foreach ($this->providerRepos as $repo) { $packages = $repo->loadRecursively( $packageNames, - $loadDev, array($this, 'isPackageAcceptable') ); diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 7dd947acf..bcfd08388 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -179,7 +179,7 @@ class Solver } } - $this->pool->loadRecursively(array_keys($packageNames), true); + $this->pool->loadRecursively(array_keys($packageNames)); $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 89c2b75b2..62b6847af 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -100,7 +100,7 @@ class ComposerRepository extends ArrayRepository return $this->rootAliases; } - public function loadRecursively(array $packageNames, $loadDev, $acceptableCallback) + public function loadRecursively(array $packageNames, $acceptableCallback) { $workQueue = new \SplQueue; @@ -123,9 +123,6 @@ class ComposerRepository extends ArrayRepository foreach ($packages as $package) { $loadedPackages[] = $package; $requires = $package->getRequires(); - if ($loadDev) { - $requires = array_merge($requires, $package->getDevRequires()); - } foreach ($requires as $link) { $workQueue->enqueue($link->getTarget()); } diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 4e4fc99bb..1c63feb1a 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -147,7 +147,7 @@ class ComposerRepositoryTest extends TestCase $versionParser = new VersionParser(); $that = $this; - $packages = $repo->loadRecursively(array('a'), true, function ($name, $stability) use ($that) { + $packages = $repo->loadRecursively(array('a'), function ($name, $stability) use ($that) { $this->assertEquals('a', $name); return true; }); From aa7d145dd08b3aaf2a38ab01e82ad73364d0549f Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 20:24:04 +0200 Subject: [PATCH 09/15] PHP 5.3 compatible function invokation --- src/Composer/Repository/ComposerRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 62b6847af..098ff8819 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -181,7 +181,9 @@ class ComposerRepository extends ArrayRepository continue; } - if ($acceptableCallback && !$acceptableCallback(strtolower($version['name']), VersionParser::parseStability($version['version']))) { + if ($acceptableCallback && !call_user_func( + $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version']) + )) { continue; } From cfd0e443126e695b787313d736a7d4945c08bdf1 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 20:28:22 +0200 Subject: [PATCH 10/15] Move private function further down in pool --- src/Composer/DependencyResolver/Pool.php | 81 +++++++++++++----------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 566c6e262..222c414cb 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -107,44 +107,6 @@ class Pool } } - 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); @@ -167,6 +129,11 @@ class Pool return $this->packages[$id - 1]; } + /** + * Ensures that all given names and their requirements are loaded. + * + * @param array $packageNames A list of names that need to be available + */ public function loadRecursively(array $packageNames) { $loadedMap = array(); @@ -214,6 +181,44 @@ class Pool return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName); } + 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; + } + } + } + /** * @see whatProvides */ From 63e96a41f89fbca4bc07d88cb47ffd784ffb0a40 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 20:30:57 +0200 Subject: [PATCH 11/15] Add proper docblocks in composer repo --- .../Repository/ComposerRepository.php | 150 ++++++++++-------- 1 file changed, 80 insertions(+), 70 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 098ff8819..23867ddef 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -132,76 +132,6 @@ class ComposerRepository extends ArrayRepository return $loadedPackages; } - protected function loadName($name, $acceptableCallback, $exactMatch = true) - { - // 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])) { - 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])) { - 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); - } - - $loadedPackages = array(); - foreach ($packages['packages'] as $versions) { - foreach ($versions as $version) { - if ($exactMatch && $version['name'] !== $name) { - continue; - } - - if ($acceptableCallback && !call_user_func( - $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version']) - )) { - continue; - } - - // load acceptable packages in the providers - $package = $this->createPackage($version, 'Composer\Package\Package'); - $this->addPackage($package); - - $loadedPackages[] = $package; - - if ($package instanceof AliasPackage) { - $loadedPackages[] = $package->getAliasOf(); - } - } - } - - return $loadedPackages; - } - /** * {@inheritDoc} */ @@ -328,6 +258,86 @@ class ComposerRepository extends ArrayRepository return $providers; } + /** + * Loads package data for a given package name or provider name + * + * @param string $name + * @param callable $acceptableCallback A callback to check if a package should be loaded + * @param bool $exactMatch Whether packages only providing the name should be ignored + * + * @return array All packages that were loaded + */ + protected function loadName($name, $acceptableCallback, $exactMatch = true) + { + // 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])) { + 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])) { + 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); + } + + $loadedPackages = array(); + foreach ($packages['packages'] as $versions) { + foreach ($versions as $version) { + if ($exactMatch && $version['name'] !== $name) { + continue; + } + + if ($acceptableCallback && !call_user_func( + $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version']) + )) { + continue; + } + + // load acceptable packages in the providers + $package = $this->createPackage($version, 'Composer\Package\Package'); + $this->addPackage($package); + + $loadedPackages[] = $package; + + if ($package instanceof AliasPackage) { + $loadedPackages[] = $package->getAliasOf(); + } + } + } + + return $loadedPackages; + } + + protected function configurePackageTransportOptions(PackageInterface $package) { foreach ($package->getDistUrls() as $url) { From 67f10c16019a8dcd11115a590496c8fa53b4fb47 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 May 2015 20:32:05 +0200 Subject: [PATCH 12/15] PHP 5.3 this/that compatibility --- tests/Composer/Test/Repository/ComposerRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 1c63feb1a..14dfb5e24 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -148,7 +148,7 @@ class ComposerRepositoryTest extends TestCase $that = $this; $packages = $repo->loadRecursively(array('a'), function ($name, $stability) use ($that) { - $this->assertEquals('a', $name); + $that->assertEquals('a', $name); return true; }); From 65243ca3922d0872fd3d24d882cba9a1a47058c0 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 8 Jun 2015 18:45:03 +0200 Subject: [PATCH 13/15] Move methods for PR readability and fix phpdoc --- .../Repository/ComposerRepository.php | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 23867ddef..b17e61515 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -100,6 +100,14 @@ class ComposerRepository extends ArrayRepository return $this->rootAliases; } + /** + * Load all packages with given names and dependencies + * + * @param array $packageNames + * @param callable|null $acceptableCallback Callback to filter packages + * + * @return array The loaded package objects + */ public function loadRecursively(array $packageNames, $acceptableCallback) { $workQueue = new \SplQueue; @@ -258,11 +266,29 @@ class ComposerRepository extends ArrayRepository return $providers; } + protected function configurePackageTransportOptions(PackageInterface $package) + { + foreach ($package->getDistUrls() as $url) { + if (strpos($url, $this->baseUrl) === 0) { + $package->setTransportOptions($this->options); + + return; + } + } + } + + public function hasProviders() + { + $this->loadRootServerFile(); + + return $this->hasProviders; + } + /** * Loads package data for a given package name or provider name * * @param string $name - * @param callable $acceptableCallback A callback to check if a package should be loaded + * @param callable|null $acceptableCallback A callback to check if a package should be loaded * @param bool $exactMatch Whether packages only providing the name should be ignored * * @return array All packages that were loaded @@ -337,25 +363,6 @@ class ComposerRepository extends ArrayRepository return $loadedPackages; } - - protected function configurePackageTransportOptions(PackageInterface $package) - { - foreach ($package->getDistUrls() as $url) { - if (strpos($url, $this->baseUrl) === 0) { - $package->setTransportOptions($this->options); - - return; - } - } - } - - public function hasProviders() - { - $this->loadRootServerFile(); - - return $this->hasProviders; - } - /** * {@inheritDoc} */ From 8b28d4bc82d8ac093747e05626771ce513a34ff4 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 8 Jun 2015 18:50:15 +0200 Subject: [PATCH 14/15] Optimisation: Composer repo version listings are index by package name --- src/Composer/Repository/ComposerRepository.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index b17e61515..80fd90a86 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -336,12 +336,12 @@ class ComposerRepository extends ArrayRepository } $loadedPackages = array(); - foreach ($packages['packages'] as $versions) { - foreach ($versions as $version) { - if ($exactMatch && $version['name'] !== $name) { - continue; - } + foreach ($packages['packages'] as $packageName => $versions) { + if ($exactMatch && $packageName !== $name) { + continue; + } + foreach ($versions as $version) { if ($acceptableCallback && !call_user_func( $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version']) )) { From e25b86c12918a1618ac5aab0f45b87221de0e1f6 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 8 Jun 2015 18:57:56 +0200 Subject: [PATCH 15/15] Fix composer repo test to match what composer repos send --- .../Repository/ComposerRepositoryTest.php | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 14dfb5e24..02d546068 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -124,23 +124,25 @@ class ComposerRepositoryTest extends TestCase ->method('fetchFile') ->will($this->returnValue(array( 'packages' => array( - array(array( - 'uid' => 1, - 'name' => 'a', - 'version' => 'dev-master', - 'extra' => array('branch-alias' => array('dev-master' => '1.0.x-dev')), - )), - array(array( - 'uid' => 2, - 'name' => 'a', - 'version' => 'dev-develop', - 'extra' => array('branch-alias' => array('dev-develop' => '1.1.x-dev')), - )), - array(array( - 'uid' => 3, - 'name' => 'a', - 'version' => '0.6', - )), + 'a' => array( + 'dev-master' => array( + 'uid' => 1, + 'name' => 'a', + 'version' => 'dev-master', + 'extra' => array('branch-alias' => array('dev-master' => '1.0.x-dev')), + ), + 'dev-develop' => array( + 'uid' => 2, + 'name' => 'a', + 'version' => 'dev-develop', + 'extra' => array('branch-alias' => array('dev-develop' => '1.1.x-dev')), + ), + '0.6' => array( + 'uid' => 3, + 'name' => 'a', + 'version' => '0.6', + ), + ), ) )));