Sfoglia il codice sorgente

Move construction of pool from repo set into a pool builder

Pool construction depends on the install request now, so only required
packages get loaded, add some structure for future asynchronously
loading composer repositories
Nils Adermann 6 anni fa
parent
commit
c0f19f6c57

+ 3 - 8
src/Composer/DependencyResolver/DefaultPolicy.php

@@ -57,11 +57,6 @@ class DefaultPolicy implements PolicyInterface
         return $packages;
     }
 
-    public function getPriority(Pool $pool, PackageInterface $package)
-    {
-        return $pool->getPriority($package->getRepository());
-    }
-
     public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
     {
         $packages = $this->groupLiteralsByNamePreferInstalled($pool, $installedMap, $literals);
@@ -168,7 +163,7 @@ class DefaultPolicy implements PolicyInterface
             return 1;
         }
 
-        return ($this->getPriority($pool, $a) > $this->getPriority($pool, $b)) ? -1 : 1;
+        return ($pool->getPriority($a->id) > $pool->getPriority($b->id)) ? -1 : 1;
     }
 
     /**
@@ -236,10 +231,10 @@ class DefaultPolicy implements PolicyInterface
             }
 
             if (null === $priority) {
-                $priority = $this->getPriority($pool, $package);
+                $priority = $pool->getPriority($package->id);
             }
 
-            if ($this->getPriority($pool, $package) != $priority) {
+            if ($pool->getPriority($package->id) != $priority) {
                 break;
             }
 

+ 16 - 103
src/Composer/DependencyResolver/Pool.php

@@ -27,7 +27,7 @@ use Composer\Repository\PlatformRepository;
 use Composer\Package\PackageInterface;
 
 /**
- * A package pool contains repositories that provide packages.
+ * A package pool contains all packages for dependency resolution
  *
  * @author Nils Adermann <naderman@naderman.de>
  * @author Jordi Boggiano <j.boggiano@seld.be>
@@ -41,23 +41,18 @@ class Pool implements \Countable
     const MATCH_REPLACE = 3;
     const MATCH_FILTERED = 4;
 
-    protected $repositories = array();
     protected $providerRepos = array();
     protected $packages = array();
     protected $packageByName = array();
     protected $packageByExactName = array();
-    protected $acceptableStabilities;
-    protected $stabilityFlags;
+    protected $priorities = array();
     protected $versionParser;
     protected $providerCache = array();
     protected $filterRequires;
     protected $whitelist = null;
-    protected $id = 1;
 
-    public function __construct(array $acceptableStabilities, array $stabilityFlags = array(), array $filterRequires = array())
+    public function __construct(array $filterRequires = array())
     {
-        $this->acceptableStabilities = $acceptableStabilities;
-        $this->stabilityFlags = $stabilityFlags;
         $this->filterRequires = $filterRequires;
         $this->versionParser = new VersionParser;
     }
@@ -68,76 +63,24 @@ class Pool implements \Countable
         $this->providerCache = array();
     }
 
-    /**
-     * Adds a repository and its packages to this package pool
-     *
-     * @param RepositoryInterface $repo        A package repository
-     * @param array               $rootAliases
-     */
-    public function addRepository(RepositoryInterface $repo, $rootAliases = array())
+    public function setPackages(array $packages, array $priorities = array())
     {
-        if ($repo instanceof CompositeRepository) {
-            $repos = $repo->getRepositories();
-        } else {
-            $repos = array($repo);
-        }
+        $this->priorities = $priorities;
+        $this->packages = $packages;
 
-        foreach ($repos as $repo) {
-            $this->repositories[] = $repo;
-
-            $exempt = $repo instanceof PlatformRepository || $repo instanceof InstalledRepositoryInterface;
-
-            if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
-                $this->providerRepos[] = $repo;
-                $repo->setRootAliases($rootAliases);
-                $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;
-                            }
-                        }
-                    }
-                }
+        foreach ($this->packages as $package) {
+            $names = $package->getNames();
+            $this->packageByExactName[$package->getName()][$package->id] = $package;
+
+            foreach ($names as $provided) {
+                $this->packageByName[$provided][] = $package;
             }
         }
     }
 
-    public function getPriority(RepositoryInterface $repo)
+    public function getPriority($id)
     {
-        $priority = array_search($repo, $this->repositories, true);
-
-        if (false === $priority) {
-            throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
-        }
-
-        return -$priority;
+        return $this->priorities[$id - 1];
     }
 
     /**
@@ -191,25 +134,12 @@ class Pool implements \Countable
     {
         $candidates = array();
 
-        foreach ($this->providerRepos as $repo) {
-            foreach ($repo->whatProvides($name, $bypassFilters, array($this, 'isPackageAcceptable')) 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();
@@ -287,23 +217,6 @@ class Pool implements \Countable
         return $prefix.' '.$package->getPrettyString();
     }
 
-    public function isPackageAcceptable($name, $stability)
-    {
-        foreach ((array) $name as $n) {
-            // allow if package matches the global stability requirement and has no exception
-            if (!isset($this->stabilityFlags[$n]) && isset($this->acceptableStabilities[$stability])) {
-                return true;
-            }
-
-            // allow if package matches the package-specific stability flag
-            if (isset($this->stabilityFlags[$n]) && BasePackage::$stabilities[$stability] <= $this->stabilityFlags[$n]) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     /**
      * Checks if the package matches the given constraint directly or through
      * provided or replaced packages

+ 147 - 0
src/Composer/DependencyResolver/PoolBuilder.php

@@ -0,0 +1,147 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\DependencyResolver;
+
+use Composer\Package\AliasPackage;
+use Composer\Package\BasePackage;
+use Composer\Package\PackageInterface;
+use Composer\Repository\AsyncRepositoryInterface;
+use Composer\Repository\InstalledRepositoryInterface;
+use Composer\Repository\LockArrayRepository;
+use Composer\Repository\PlatformRepository;
+
+/**
+ * @author Nils Adermann <naderman@naderman.de>
+ */
+class PoolBuilder
+{
+    private $isPackageAcceptableCallable;
+    private $filterRequires;
+    private $rootAliases;
+
+    private $loadedNames = array();
+
+    private $id = 1;
+    private $packages = array();
+    private $priorities = array();
+
+    public function __construct($isPackageAcceptableCallable, array $filterRequires = array())
+    {
+        $this->isPackageAcceptableCallable = $isPackageAcceptableCallable;
+        $this->filterRequires = $filterRequires;
+    }
+
+    public function buildPool(array $repositories, array $rootAliases, Request $request)
+    {
+        $this->pool = new Pool($this->filterRequires);
+        $this->rootAliases = $rootAliases;
+
+        // TODO do we really want the request here? kind of want a root requirements thingy instead
+        $loadNames = array();
+        foreach ($request->getJobs() as $job) {
+            switch ($job['cmd']) {
+                case 'install':
+                    $loadNames[$job['packageName']] = true;
+                    break;
+            }
+        }
+
+        foreach ($repositories as $repository) {
+            if ($repository instanceof ComposerRepository && $repository->hasProviders()) {
+                $this->providerRepos[] = $repository;
+                $repository->setRootAliases($this->rootAliases);
+                $repository->resetPackageIds();
+            }
+        }
+
+        while (!empty($loadNames)) {
+            $loadIds = array();
+            foreach ($repositories as $key => $repository) {
+                if ($repository instanceof AsyncRepositoryInterface) {
+                    $loadIds[$key] = $repository->requestPackages($loadNames);
+                }
+            }
+
+            foreach ($loadNames as $name => $void) {
+                $this->loadedNames[$name] = true;
+            }
+
+            $newLoadNames = array();
+            foreach ($repositories as $key => $repository) {
+                if ($repository instanceof PlatformRepository || $repository instanceof InstalledRepositoryInterface) {
+                    continue;
+                }
+
+                if ($repository instanceof AsyncRepositoryInterface) {
+                    $packages = $repository->returnPackages($loadIds[$key]);
+                } else {
+                    $packages = $repository->loadPackages($loadNames);
+                }
+
+                foreach ($packages as $package) {
+                    if (call_user_func($this->isPackageAcceptableCallable, $package->getNames(), $package->getStability())) {
+                        $newLoadNames += $this->loadPackage($package, $key);
+                    }
+                }
+            }
+
+            $loadNames = $newLoadNames;
+        }
+
+        foreach ($repositories as $key => $repository) {
+            if ($repository instanceof PlatformRepository ||
+                $repository instanceof InstalledRepositoryInterface) {
+                foreach ($repository->getPackages() as $package) {
+                    $this->loadPackage($package, $key);
+                }
+            }
+        }
+
+        $this->pool->setPackages($this->packages, $this->priorities);
+
+        return $this->pool;
+    }
+
+    private function loadPackage(PackageInterface $package, $repoIndex)
+    {
+        $package->setId($this->id++);
+        $this->packages[] = $package;
+        $this->priorities[$this->id - 2] = -$repoIndex;
+
+        // 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();
+            }
+            $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
+            $aliasPackage->setRootPackageAlias(true);
+            $aliasPackage->setId($this->id++);
+
+            $package->getRepository()->addPackage($aliasPackage); // TODO do we need this?
+            $this->packages[] = $aliasPackage;
+        }
+
+        $loadNames = array();
+        foreach ($package->getRequires() as $link) {
+            $require = $link->getTarget();
+            if (!isset($this->loadedNames[$require])) {
+                $loadNames[$require] = true;
+            }
+        }
+
+        return $loadNames;
+    }
+}
+

+ 2 - 2
src/Composer/DependencyResolver/Problem.php

@@ -71,7 +71,7 @@ class Problem
      * @param  array  $installedMap A map of all installed packages
      * @return string
      */
-    public function getPrettyString(array $installedMap = array())
+    public function getPrettyString(array $installedMap = array(), array $learnedPool = array())
     {
         $reasons = call_user_func_array('array_merge', array_reverse($this->reasons));
 
@@ -168,7 +168,7 @@ class Problem
                 $messages[] = $this->jobToText($job);
             } elseif ($rule) {
                 if ($rule instanceof Rule) {
-                    $messages[] = $rule->getPrettyString($this->pool, $installedMap);
+                    $messages[] = $rule->getPrettyString($this->pool, $installedMap, $learnedPool);
                 }
             }
         }

+ 13 - 2
src/Composer/DependencyResolver/Rule.php

@@ -126,7 +126,7 @@ abstract class Rule
 
     abstract public function isAssertion();
 
-    public function getPrettyString(Pool $pool, array $installedMap = array())
+    public function getPrettyString(Pool $pool, array $installedMap = array(), array $learnedPool = array())
     {
         $literals = $this->getLiterals();
 
@@ -230,7 +230,18 @@ abstract class Rule
             case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
                 return $ruleText;
             case self::RULE_LEARNED:
-                return 'Conclusion: '.$ruleText;
+                // TODO not sure this is a good idea, most of these rules should be listed in the problem anyway
+                $learnedString = '(learned rule, ';
+                if (isset($learnedPool[$this->reasonData])) {
+                    foreach ($learnedPool[$this->reasonData] as $learnedRule) {
+                        $learnedString .= $learnedRule->getPrettyString($pool, $installedMap, $learnedPool);
+                    }
+                } else {
+                    $learnedString .= 'reasoning unavailable';
+                }
+                $learnedString .= ')';
+
+                return 'Conclusion: '.$ruleText.' '.$learnedString;
             case self::RULE_PACKAGE_ALIAS:
                 return $ruleText;
             default:

+ 1 - 1
src/Composer/DependencyResolver/Solver.php

@@ -244,7 +244,7 @@ class Solver
         }
 
         if ($this->problems) {
-            throw new SolverProblemsException($this->problems, $this->installedMap);
+            throw new SolverProblemsException($this->problems, $this->installedMap, $this->learnedPool);
         }
 
         $transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisions);

+ 4 - 2
src/Composer/DependencyResolver/SolverProblemsException.php

@@ -21,11 +21,13 @@ class SolverProblemsException extends \RuntimeException
 {
     protected $problems;
     protected $installedMap;
+    protected $learnedPool;
 
-    public function __construct(array $problems, array $installedMap)
+    public function __construct(array $problems, array $installedMap, array $learnedPool)
     {
         $this->problems = $problems;
         $this->installedMap = $installedMap;
+        $this->learnedPool = $learnedPool;
 
         parent::__construct($this->createMessage(), 2);
     }
@@ -35,7 +37,7 @@ class SolverProblemsException extends \RuntimeException
         $text = "\n";
         $hasExtensionProblems = false;
         foreach ($this->problems as $i => $problem) {
-            $text .= "  Problem ".($i + 1).$problem->getPrettyString($this->installedMap)."\n";
+            $text .= "  Problem ".($i + 1).$problem->getPrettyString($this->installedMap, $this->learnedPool)."\n";
 
             if (!$hasExtensionProblems && $this->hasExtensionProblems($problem->getReasons())) {
                 $hasExtensionProblems = true;

+ 2 - 2
src/Composer/Installer.php

@@ -467,7 +467,7 @@ class Installer
 
         $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $installedRepo, $request);
 
-        $pool = $repositorySet->createPool();
+        $pool = $repositorySet->createPool($request);
 
         // force dev packages to have the latest links if we update or install from a (potentially new) lock
         $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, 'force-links');
@@ -701,7 +701,7 @@ class Installer
 
         // solve deps to see which get removed
         $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $repositorySet, $installedRepo, $request);
-        $solver = new Solver($policy, $repositorySet->createPool(), $installedRepo, $this->io);
+        $solver = new Solver($policy, $repositorySet->createPool($request), $installedRepo, $this->io);
         $ops = $solver->solve($request, $this->ignorePlatformReqs);
         $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $repositorySet, $installedRepo, $request, $ops);
 

+ 2 - 2
src/Composer/Package/Locker.php

@@ -14,9 +14,9 @@ namespace Composer\Package;
 
 use Composer\Json\JsonFile;
 use Composer\Installer\InstallationManager;
+use Composer\Repository\LockArrayRepository;
 use Composer\Repository\RepositoryManager;
 use Composer\Util\ProcessExecutor;
-use Composer\Repository\ArrayRepository;
 use Composer\Package\Dumper\ArrayDumper;
 use Composer\Package\Loader\ArrayLoader;
 use Composer\Util\Git as GitUtil;
@@ -150,7 +150,7 @@ class Locker
     public function getLockedRepository($withDevReqs = false)
     {
         $lockData = $this->getLockData();
-        $packages = new ArrayRepository();
+        $packages = new LockArrayRepository();
 
         $lockedPackages = $lockData['packages'];
         if ($withDevReqs) {

+ 38 - 0
src/Composer/Repository/AsyncRepositoryInterface.php

@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+use Composer\Package\PackageInterface;
+
+/**
+ * Repository interface.
+ *
+ * @author Nils Adermann <naderman@naderman.de>
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface AsyncRepositoryInterface
+{
+    /**
+     * @param array $names Names of packages to retrieve data for
+     * @return scalar Id to be passed to later loadPackages call
+     */
+    public function requestPackages(array $names);
+
+    /**
+     * @param array $names
+     * @return scalar id for load call
+     */
+    public function returnPackages($loadId);
+}
+

+ 15 - 0
src/Composer/Repository/BaseRepository.php

@@ -24,6 +24,21 @@ use Composer\Package\Link;
  */
 abstract class BaseRepository implements RepositoryInterface
 {
+    // TODO should this stay here? some repos need a better implementation
+    public function loadPackages(array $packageNameMap)
+    {
+        $packages = $this->getPackages();
+
+        $result = array();
+        foreach ($packages as $package) {
+            if (isset($packageNameMap[$package->getName()])) {
+                $result[] = $package;
+            }
+        }
+
+        return $result;
+    }
+
     /**
      * Returns a list of links causing the requested needle packages to be installed, as an associative array with the
      * dependent's name as key, and an array containing in order the PackageInterface and Link describing the relationship

+ 25 - 0
src/Composer/Repository/LockArrayRepository.php

@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+/**
+ * Lock array repository.
+ *
+ * Regular array repository, only uses a different type to identify the lock file as the source of info
+ *
+ * @author Nils Adermann <naderman@naderman.de>
+ */
+class LockArrayRepository extends ArrayRepository implements RepositoryInterface
+{
+}
+

+ 9 - 0
src/Composer/Repository/RepositoryInterface.php

@@ -55,6 +55,7 @@ interface RepositoryInterface extends \Countable
      */
     public function findPackages($name, $constraint = null);
 
+    // TODO this should really not be in this generic interface anymore
     /**
      * Returns list of registered packages.
      *
@@ -62,6 +63,14 @@ interface RepositoryInterface extends \Countable
      */
     public function getPackages();
 
+    /**
+     * Returns list of registered packages with the supplied name
+     *
+     * @param bool[] $packageNameMap
+     * @return PackageInterface[]
+     */
+    public function loadPackages(array $packageNameMap);
+
     /**
      * Searches the repository for packages containing the query
      *

+ 30 - 11
src/Composer/Repository/RepositorySet.php

@@ -13,6 +13,8 @@
 namespace Composer\Repository;
 
 use Composer\DependencyResolver\Pool;
+use Composer\DependencyResolver\PoolBuilder;
+use Composer\DependencyResolver\Request;
 use Composer\Package\BasePackage;
 use Composer\Package\Version\VersionParser;
 use Composer\Repository\CompositeRepository;
@@ -31,9 +33,6 @@ class RepositorySet
     /** @var RepositoryInterface[] */
     private $repositories = array();
 
-    /** @var ComposerRepository[] */
-    private $providerRepos = array();
-
     private $acceptableStabilities;
     private $stabilityFlags;
     protected $filterRequires;
@@ -79,9 +78,6 @@ class RepositorySet
 
         foreach ($repos as $repo) {
             $this->repositories[] = $repo;
-            if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
-                $this->providerRepos[] = $repo;
-            }
         }
     }
 
@@ -133,20 +129,43 @@ class RepositorySet
         return $candidates;
     }
 
+    public function getPriority(RepositoryInterface $repo)
+    {
+        $priority = array_search($repo, $this->repositories, true);
+
+        if (false === $priority) {
+            throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
+        }
+
+        return -$priority;
+    }
+
     /**
      * Create a pool for dependency resolution from the packages in this repository set.
      *
      * @return Pool
      */
-    public function createPool()
+    public function createPool(Request $request)
     {
-        $this->pool = new Pool($this->acceptableStabilities, $this->stabilityFlags, $this->filterRequires);
+        $poolBuilder = new PoolBuilder(array($this, 'isPackageAcceptable'), $this->filterRequires);
 
-        foreach ($this->repositories as $repository) {
-            $this->pool->addRepository($repository, $this->rootAliases);
+        return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $request);
+    }
+
+    // TODO unify this with above in some simpler version without "request"?
+    public function createPoolForPackage($packageName)
+    {
+        return $this->createPoolForPackages(array($packageName));
+    }
+
+    public function createPoolForPackages($packageNames)
+    {
+        $request = new Request();
+        foreach ($packageNames as $packageName) {
+            $request->install($packageName);
         }
 
-        return $this->pool;
+        return $this->createPool($request);
     }
 
     /**

+ 16 - 15
tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php

@@ -21,6 +21,7 @@ use Composer\Package\AliasPackage;
 use Composer\Repository\RepositorySet;
 use Composer\Semver\Constraint\Constraint;
 use Composer\TestCase;
+use http\Env\Request;
 
 class DefaultPolicyTest extends TestCase
 {
@@ -47,7 +48,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA->getId());
         $expected = array($packageA->getId());
@@ -63,7 +64,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA1->getId(), $packageA2->getId());
         $expected = array($packageA2->getId());
@@ -79,7 +80,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA2 = $this->getPackage('A', '1.0.1-alpha'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA1->getId(), $packageA2->getId());
         $expected = array($packageA2->getId());
@@ -95,7 +96,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA2 = $this->getPackage('A', '1.0.1-alpha'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA1->getId(), $packageA2->getId());
         $expected = array($packageA1->getId());
@@ -112,7 +113,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA2 = $this->getPackage('A', '1.0.0'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA1->getId(), $packageA2->getId());
         $expected = array($packageA2->getId());
@@ -129,7 +130,7 @@ class DefaultPolicyTest extends TestCase
         $this->repositorySet->addRepository($this->repoInstalled);
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA->getId(), $packageAInstalled->getId());
         $expected = array($packageA->getId());
@@ -150,7 +151,7 @@ class DefaultPolicyTest extends TestCase
         $this->repositorySet->addRepository($otherRepository);
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA->getId(), $packageAImportant->getId());
         $expected = array($packageAImportant->getId());
@@ -173,7 +174,7 @@ class DefaultPolicyTest extends TestCase
         $this->repositorySet->addRepository($repo1);
         $this->repositorySet->addRepository($repo2);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($package1->getId(), $package2->getId(), $package3->getId(), $package4->getId());
         $expected = array($package2->getId());
@@ -185,7 +186,7 @@ class DefaultPolicyTest extends TestCase
         $this->repositorySet->addRepository($repo2);
         $this->repositorySet->addRepository($repo1);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $expected = array($package4->getId());
         $selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
@@ -209,7 +210,7 @@ class DefaultPolicyTest extends TestCase
         $this->repositorySet->addRepository($repoImportant);
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $packages = $pool->whatProvides('a', new Constraint('=', '2.1.9999999.9999999-dev'));
         $literals = array();
@@ -234,7 +235,7 @@ class DefaultPolicyTest extends TestCase
 
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackages(array('A', 'B'));
 
         $literals = array($packageA->getId(), $packageB->getId());
         $expected = $literals;
@@ -253,7 +254,7 @@ class DefaultPolicyTest extends TestCase
 
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackages(array('A', 'B'));
 
         $literals = array($packageA->getId(), $packageB->getId());
         $expected = $literals;
@@ -274,7 +275,7 @@ class DefaultPolicyTest extends TestCase
 
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackages(array('vendor-a/replacer', 'vendor-b/replacer'));
 
         $literals = array($packageA->getId(), $packageB->getId());
         $expected = $literals;
@@ -290,7 +291,7 @@ class DefaultPolicyTest extends TestCase
         $repositorySet = new RepositorySet(array(), 'dev');
         $repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackages(array('vendor-a/replacer', 'vendor-b/replacer'));
 
         $literals = array($packageA->getId(), $packageB->getId());
         $expected = $literals;
@@ -317,7 +318,7 @@ class DefaultPolicyTest extends TestCase
         $this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0'));
         $this->repositorySet->addRepository($this->repo);
 
-        $pool = $this->repositorySet->createPool();
+        $pool = $this->repositorySet->createPoolForPackage('A');
 
         $literals = array($packageA1->getId(), $packageA2->getId());
         $expected = array($packageA1->getId());

+ 6 - 73
tests/Composer/Test/DependencyResolver/PoolTest.php

@@ -22,90 +22,25 @@ class PoolTest extends TestCase
     public function testPool()
     {
         $pool = $this->createPool();
-        $repo = new ArrayRepository;
         $package = $this->getPackage('foo', '1');
 
-        $repo->addPackage($package);
-        $pool->addRepository($repo);
+        $pool->setPackages(array($package));
 
         $this->assertEquals(array($package), $pool->whatProvides('foo'));
         $this->assertEquals(array($package), $pool->whatProvides('foo'));
     }
 
-    public function testPoolIgnoresIrrelevantPackages()
-    {
-        $pool = new Pool(array('stable' => BasePackage::STABILITY_STABLE), array('bar' => BasePackage::STABILITY_BETA));
-        $repo = new ArrayRepository;
-        $repo->addPackage($package = $this->getPackage('bar', '1'));
-        $repo->addPackage($betaPackage = $this->getPackage('bar', '1-beta'));
-        $repo->addPackage($alphaPackage = $this->getPackage('bar', '1-alpha'));
-        $repo->addPackage($package2 = $this->getPackage('foo', '1'));
-        $repo->addPackage($rcPackage2 = $this->getPackage('foo', '1rc'));
-
-        $pool->addRepository($repo);
-
-        $this->assertEquals(array($package, $betaPackage), $pool->whatProvides('bar'));
-        $this->assertEquals(array($package2), $pool->whatProvides('foo'));
-    }
-
-    /**
-     * @expectedException \RuntimeException
-     */
-    public function testGetPriorityForNotRegisteredRepository()
-    {
-        $pool = $this->createPool();
-        $repository = new ArrayRepository;
-
-        $pool->getPriority($repository);
-    }
-
-    public function testGetPriorityWhenRepositoryIsRegistered()
-    {
-        $pool = $this->createPool();
-        $firstRepository = new ArrayRepository;
-        $pool->addRepository($firstRepository);
-        $secondRepository = new ArrayRepository;
-        $pool->addRepository($secondRepository);
-
-        $firstPriority = $pool->getPriority($firstRepository);
-        $secondPriority = $pool->getPriority($secondRepository);
-
-        $this->assertEquals(0, $firstPriority);
-        $this->assertEquals(-1, $secondPriority);
-    }
-
-    public function testWhatProvidesSamePackageForDifferentRepositories()
-    {
-        $pool = $this->createPool();
-        $firstRepository = new ArrayRepository;
-        $secondRepository = new ArrayRepository;
-
-        $firstPackage = $this->getPackage('foo', '1');
-        $secondPackage = $this->getPackage('foo', '1');
-        $thirdPackage = $this->getPackage('foo', '2');
-
-        $firstRepository->addPackage($firstPackage);
-        $secondRepository->addPackage($secondPackage);
-        $secondRepository->addPackage($thirdPackage);
-
-        $pool->addRepository($firstRepository);
-        $pool->addRepository($secondRepository);
-
-        $this->assertEquals(array($firstPackage, $secondPackage, $thirdPackage), $pool->whatProvides('foo'));
-    }
-
     public function testWhatProvidesPackageWithConstraint()
     {
         $pool = $this->createPool();
-        $repository = new ArrayRepository;
 
         $firstPackage = $this->getPackage('foo', '1');
         $secondPackage = $this->getPackage('foo', '2');
 
-        $repository->addPackage($firstPackage);
-        $repository->addPackage($secondPackage);
-
-        $pool->addRepository($repository);
+        $pool->setPackages(array(
+            $firstPackage,
+            $secondPackage,
+        ));
 
         $this->assertEquals(array($firstPackage, $secondPackage), $pool->whatProvides('foo'));
         $this->assertEquals(array($secondPackage), $pool->whatProvides('foo', $this->getVersionConstraint('==', '2')));
@@ -114,11 +49,9 @@ class PoolTest extends TestCase
     public function testPackageById()
     {
         $pool = $this->createPool();
-        $repository = new ArrayRepository;
         $package = $this->getPackage('foo', '1');
 
-        $repository->addPackage($package);
-        $pool->addRepository($repository);
+        $pool->setPackages(array($package));
 
         $this->assertSame($package, $pool->packageById(1));
     }

+ 6 - 11
tests/Composer/Test/DependencyResolver/RuleSetTest.php

@@ -22,13 +22,6 @@ use Composer\TestCase;
 
 class RuleSetTest extends TestCase
 {
-    protected $pool;
-
-    public function setUp()
-    {
-        $this->pool = new Pool(array('stable' => BasePackage::STABILITY_STABLE));
-    }
-
     public function testAdd()
     {
         $rules = array(
@@ -146,9 +139,11 @@ class RuleSetTest extends TestCase
 
     public function testPrettyString()
     {
-        $repo = new ArrayRepository;
-        $repo->addPackage($p = $this->getPackage('foo', '2.1'));
-        $this->pool->addRepository($repo);
+        $pool = new Pool(array('stable' => BasePackage::STABILITY_STABLE));
+        $pool->setPackages(array(
+            $p = $this->getPackage('foo', '2.1'),
+        ));
+        $p->setId(1);
 
         $ruleSet = new RuleSet;
         $literal = $p->getId();
@@ -156,7 +151,7 @@ class RuleSetTest extends TestCase
 
         $ruleSet->add($rule, RuleSet::TYPE_JOB);
 
-        $this->assertContains('JOB     : Install command rule (install foo 2.1)', $ruleSet->getPrettyString($this->pool));
+        $this->assertContains('JOB     : Install command rule (install foo 2.1)', $ruleSet->getPrettyString($pool));
     }
 
     private function getRuleMock()

+ 8 - 12
tests/Composer/Test/DependencyResolver/RuleTest.php

@@ -22,13 +22,6 @@ use Composer\TestCase;
 
 class RuleTest extends TestCase
 {
-    protected $pool;
-
-    public function setUp()
-    {
-        $this->pool = new Pool(array('stable' => BasePackage::STABILITY_STABLE));
-    }
-
     public function testGetHash()
     {
         $rule = new GenericRule(array(123), Rule::RULE_JOB_INSTALL, null);
@@ -100,13 +93,16 @@ class RuleTest extends TestCase
 
     public function testPrettyString()
     {
-        $repo = new ArrayRepository;
-        $repo->addPackage($p1 = $this->getPackage('foo', '2.1'));
-        $repo->addPackage($p2 = $this->getPackage('baz', '1.1'));
-        $this->pool->addRepository($repo);
+        $pool = new Pool(array('stable' => BasePackage::STABILITY_STABLE));
+        $pool->setPackages(array(
+            $p1 = $this->getPackage('foo', '2.1'),
+            $p2 = $this->getPackage('baz', '1.1'),
+        ));
+        $p1->setId(1);
+        $p2->setId(2);
 
         $rule = new GenericRule(array($p1->getId(), -$p2->getId()), Rule::RULE_JOB_INSTALL, null);
 
-        $this->assertEquals('Install command rule (don\'t install baz 1.1|install foo 2.1)', $rule->getPrettyString($this->pool));
+        $this->assertEquals('Install command rule (don\'t install baz 1.1|install foo 2.1)', $rule->getPrettyString($pool));
     }
 }

+ 15 - 4
tests/Composer/Test/DependencyResolver/SolverTest.php

@@ -20,6 +20,7 @@ use Composer\DependencyResolver\Request;
 use Composer\DependencyResolver\Solver;
 use Composer\DependencyResolver\SolverProblemsException;
 use Composer\Package\Link;
+use Composer\Repository\InstalledArrayRepository;
 use Composer\Repository\RepositorySet;
 use Composer\TestCase;
 use Composer\Semver\Constraint\MultiConstraint;
@@ -31,12 +32,13 @@ class SolverTest extends TestCase
     protected $repoInstalled;
     protected $request;
     protected $policy;
+    protected $solver;
 
     public function setUp()
     {
         $this->repoSet = new RepositorySet(array());
         $this->repo = new ArrayRepository;
-        $this->repoInstalled = new ArrayRepository;
+        $this->repoInstalled = new InstalledArrayRepository;
 
         $this->request = new Request($this->repoSet);
         $this->policy = new DefaultPolicy;
@@ -71,6 +73,7 @@ class SolverTest extends TestCase
 
         $this->request->install('B', $this->getVersionConstraint('==', '1'));
 
+        $this->createSolver();
         try {
             $transaction = $this->solver->solve($this->request);
             $this->fail('Unsolvable conflict did not result in exception.');
@@ -94,8 +97,6 @@ class SolverTest extends TestCase
         $this->repoSet->addRepository($repo1);
         $this->repoSet->addRepository($repo2);
 
-        $this->solver = new Solver($this->policy, $this->repoSet->createPool(), $this->repoInstalled, new NullIO());
-
         $this->request->install('foo');
 
         $this->checkSolverResult(array(
@@ -447,6 +448,7 @@ class SolverTest extends TestCase
 
         // must explicitly pick the provider, so error in this case
         $this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
+        $this->createSolver();
         $this->solver->solve($this->request);
     }
 
@@ -480,6 +482,7 @@ class SolverTest extends TestCase
         $this->request->install('A');
 
         $this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
+        $this->createSolver();
         $this->solver->solve($this->request);
     }
 
@@ -652,6 +655,7 @@ class SolverTest extends TestCase
 
         $this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
 
+        $this->createSolver();
         $this->solver->solve($this->request);
     }
 
@@ -668,6 +672,7 @@ class SolverTest extends TestCase
         $this->request->install('A');
         $this->request->install('B');
 
+        $this->createSolver();
         try {
             $transaction = $this->solver->solve($this->request);
             $this->fail('Unsolvable conflict did not result in exception.');
@@ -697,6 +702,7 @@ class SolverTest extends TestCase
 
         $this->request->install('A');
 
+        $this->createSolver();
         try {
             $transaction = $this->solver->solve($this->request);
             $this->fail('Unsolvable conflict did not result in exception.');
@@ -744,6 +750,7 @@ class SolverTest extends TestCase
 
         $this->request->install('A');
 
+        $this->createSolver();
         try {
             $transaction = $this->solver->solve($this->request);
             $this->fail('Unsolvable conflict did not result in exception.');
@@ -843,12 +850,16 @@ class SolverTest extends TestCase
     {
         $this->repoSet->addRepository($this->repoInstalled);
         $this->repoSet->addRepository($this->repo);
+    }
 
-        $this->solver = new Solver($this->policy, $this->repoSet->createPool(), $this->repoInstalled, new NullIO());
+    protected function createSolver()
+    {
+        $this->solver = new Solver($this->policy, $this->repoSet->createPool($this->request), $this->repoInstalled, new NullIO());
     }
 
     protected function checkSolverResult(array $expected)
     {
+        $this->createSolver();
         $transaction = $this->solver->solve($this->request);
 
         $result = array();

+ 0 - 1
tests/Composer/Test/InstallerTest.php

@@ -30,7 +30,6 @@ use Symfony\Component\Console\Output\StreamOutput;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Formatter\OutputFormatter;
 use Composer\TestCase;
-use Composer\IO\BufferIO;
 
 class InstallerTest extends TestCase
 {