From 83efeaec5cda2f2fd75e7521cfd66bd511c4d019 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 14 Sep 2018 14:40:34 +0200 Subject: [PATCH 1/2] Attempt to prune versions which are impossible to install during pool building --- src/Composer/DependencyResolver/Pool.php | 8 ++-- .../DependencyResolver/PoolBuilder.php | 39 ++++++++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 35feafde8..355ba25d4 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -58,12 +58,12 @@ class Pool implements \Countable public function setPackages(array $packages, array $priorities = array()) { - $this->priorities = $priorities; - $this->packages = $packages; - $id = 1; - foreach ($this->packages as $package) { + foreach ($packages as $i => $package) { + $this->packages[] = $package; + $this->priorities[] = isset($priorities[$i]) ? $priorities[$i] : 0; + $package->id = $id++; $names = $package->getNames(); $this->packageByExactName[$package->getName()][$package->id] = $package; diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 2fd3c8230..9c5e48efa 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -20,6 +20,8 @@ use Composer\Repository\ComposerRepository; use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\LockArrayRepository; use Composer\Repository\PlatformRepository; +use Composer\Semver\Constraint\Constraint; +use Composer\Semver\Constraint\MultiConstraint; /** * @author Nils Adermann @@ -30,6 +32,9 @@ class PoolBuilder private $filterRequires; private $rootAliases; + private $aliasMap = array(); + private $nameConstraints = array(); + private $loadedNames = array(); private $packages = array(); @@ -52,6 +57,7 @@ class PoolBuilder switch ($job['cmd']) { case 'install': $loadNames[$job['packageName']] = $job['constraint']; + $this->nameConstraints[$job['packageName']] = $job['constraint'] ? new MultiConstraint(array($job['constraint']), false) : null; break; } } @@ -92,6 +98,17 @@ class PoolBuilder $loadNames = $newLoadNames; } + foreach ($this->packages as $i => $package) { + if (!$package instanceof AliasPackage && !isset($this->aliasMap[spl_object_hash($package)]) && isset($this->nameConstraints[$package->getName()])) { + $constraint = $this->nameConstraints[$package->getName()]; + + if ($constraint && !$constraint->matches(new Constraint('==', $package->getVersion()))) { + unset($this->packages[$i]); + unset($this->priorities[$i]); + } + } + } + foreach ($repositories as $key => $repository) { if ($repository instanceof PlatformRepository || $repository instanceof InstalledRepositoryInterface) { @@ -111,18 +128,26 @@ class PoolBuilder $this->packages[] = $package; $this->priorities[] = -$repoIndex; + if ($package instanceof AliasPackage) { + $this->aliasMap[spl_object_hash($package->getAliasOf())][] = $package; + } + // handle root package aliases $name = $package->getName(); if (isset($this->rootAliases[$name][$package->getVersion()])) { $alias = $this->rootAliases[$name][$package->getVersion()]; if ($package instanceof AliasPackage) { - $package = $package->getAliasOf(); + $basePackage = $package->getAliasOf(); + } else { + $basePackage = $package; } - $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); + $aliasPackage = new AliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']); $aliasPackage->setRootPackageAlias(true); $package->getRepository()->addPackage($aliasPackage); // TODO do we need this? $this->packages[] = $aliasPackage; + $this->priorities[] = -$repoIndex; + $this->aliasMap[spl_object_hash($aliasPackage->getAliasOf())][] = $aliasPackage; } $loadNames = array(); @@ -131,6 +156,16 @@ class PoolBuilder if (!isset($this->loadedNames[$require])) { $loadNames[$require] = null; } + if ($link->getConstraint()) { + if (!array_key_exists($require, $this->nameConstraints)) { + $this->nameConstraints[$require] = new MultiConstraint(array($link->getConstraint()), false); + } elseif ($this->nameConstraints[$require]) { + // TODO addConstraint function? + $this->nameConstraints[$require] = new MultiConstraint(array_merge(array($link->getConstraint()), $this->nameConstraints[$require]->getConstraints()), false); + } + } else { + $this->nameConstraints[$require] = null; + } } return $loadNames; From 537f4fbc3b487029b45c277744a34bc30890d2aa Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 14 Sep 2018 15:03:38 +0200 Subject: [PATCH 2/2] Prune unreachable required versions correctly for aliased packages In trials this seems pointless, so maybe better to skip aliases and reduce memory and cpu wasted on looking these things up --- .../DependencyResolver/PoolBuilder.php | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 9c5e48efa..8ab6e5244 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -99,12 +99,27 @@ class PoolBuilder } foreach ($this->packages as $i => $package) { - if (!$package instanceof AliasPackage && !isset($this->aliasMap[spl_object_hash($package)]) && isset($this->nameConstraints[$package->getName()])) { + // we check all alias related packages at once, so no need ot check individual aliases + // isset also checks non-null value + if (!$package instanceof AliasPackage && isset($this->nameConstraints[$package->getName()])) { $constraint = $this->nameConstraints[$package->getName()]; - if ($constraint && !$constraint->matches(new Constraint('==', $package->getVersion()))) { - unset($this->packages[$i]); - unset($this->priorities[$i]); + $aliasedPackages = array($i => $package); + if (isset($this->aliasMap[spl_object_hash($package)])) { + $aliasedPackages += $this->aliasMap[spl_object_hash($package)]; + } + + $found = false; + foreach ($aliasedPackages as $packageOrAlias) { + if ($constraint->matches(new Constraint('==', $packageOrAlias->getVersion()))) { + $found = true; + } + } + if (!$found) { + foreach ($aliasedPackages as $index => $packageOrAlias) { + unset($this->packages[$index]); + unset($this->priorities[$index]); + } } } } @@ -120,16 +135,21 @@ class PoolBuilder $this->pool->setPackages($this->packages, $this->priorities); + unset($this->aliasMap); + unset($this->loadedNames); + unset($this->nameConstraints); + return $this->pool; } private function loadPackage(PackageInterface $package, $repoIndex) { + $index = count($this->packages); $this->packages[] = $package; $this->priorities[] = -$repoIndex; if ($package instanceof AliasPackage) { - $this->aliasMap[spl_object_hash($package->getAliasOf())][] = $package; + $this->aliasMap[spl_object_hash($package->getAliasOf())][$index] = $package; } // handle root package aliases @@ -147,7 +167,7 @@ class PoolBuilder $package->getRepository()->addPackage($aliasPackage); // TODO do we need this? $this->packages[] = $aliasPackage; $this->priorities[] = -$repoIndex; - $this->aliasMap[spl_object_hash($aliasPackage->getAliasOf())][] = $aliasPackage; + $this->aliasMap[spl_object_hash($aliasPackage->getAliasOf())][$index+1] = $aliasPackage; } $loadNames = array();