Browse Source

Add InstalledRepository to clean up some concepts and usages, remove BaseRepository

Jordi Boggiano 5 years ago
parent
commit
2d8a8ed7e3

+ 9 - 14
src/Composer/Command/BaseDependencyCommand.php

@@ -14,8 +14,10 @@ namespace Composer\Command;
 
 use Composer\Package\Link;
 use Composer\Package\PackageInterface;
-use Composer\Repository\ArrayRepository;
+use Composer\Repository\InstalledArrayRepository;
 use Composer\Repository\CompositeRepository;
+use Composer\Repository\RootPackageRepository;
+use Composer\Repository\InstalledRepository;
 use Composer\Repository\PlatformRepository;
 use Composer\Repository\RepositoryFactory;
 use Composer\Plugin\CommandEvent;
@@ -70,10 +72,9 @@ class BaseDependencyCommand extends BaseCommand
         $commandEvent = new CommandEvent(PluginEvents::COMMAND, $this->getName(), $input, $output);
         $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
 
-        // Prepare repositories and set up a repo set
         $platformOverrides = $composer->getConfig()->get('platform') ?: array();
-        $repository = new CompositeRepository(array(
-            new ArrayRepository(array($composer->getPackage())),
+        $installedRepo = new InstalledRepository(array(
+            new RootPackageRepository($composer->getPackage()),
             $composer->getRepositoryManager()->getLocalRepository(),
             new PlatformRepository(array(), $platformOverrides),
         ));
@@ -84,25 +85,19 @@ class BaseDependencyCommand extends BaseCommand
             2,
             $input->getArgument(self::ARGUMENT_CONSTRAINT)
         );
-        $needle = strtolower($needle);
 
         // Find packages that are or provide the requested package first
-        $packages = array();
-        foreach ($repository->getPackages() as $package) {
-            if (in_array($needle, $package->getNames(), true)) {
-                $packages[] = $package;
-            }
-        }
+        $packages = $installedRepo->findPackagesWithReplacersAndProviders($needle);
         if (empty($packages)) {
             throw new \InvalidArgumentException(sprintf('Could not find package "%s" in your project', $needle));
         }
 
         // If the version we ask for is not installed then we need to locate it in remote repos and add it.
         // This is needed for why-not to resolve conflicts from an uninstalled version against installed packages.
-        if (!$repository->findPackage($needle, $textConstraint)) {
+        if (!$installedRepo->findPackage($needle, $textConstraint)) {
             $defaultRepos = new CompositeRepository(RepositoryFactory::defaultRepos($this->getIO()));
             if ($match = $defaultRepos->findPackage($needle, $textConstraint)) {
-                $repository->addRepository(new ArrayRepository(array(clone $match)));
+                $installedRepo->addRepository(new InstalledArrayRepository(array(clone $match)));
             }
         }
 
@@ -129,7 +124,7 @@ class BaseDependencyCommand extends BaseCommand
         $recursive = $renderTree || $input->getOption(self::OPTION_RECURSIVE);
 
         // Resolve dependencies
-        $results = $repository->getDependents($needles, $constraint, $inverted, $recursive);
+        $results = $installedRepo->getDependents($needles, $constraint, $inverted, $recursive);
         if (empty($results)) {
             $extra = (null !== $constraint) ? sprintf(' in versions %smatching %s', $inverted ? 'not ' : '', $textConstraint) : '';
             $this->getIO()->writeError(sprintf(

+ 2 - 2
src/Composer/Command/HomeCommand.php

@@ -14,7 +14,7 @@ namespace Composer\Command;
 
 use Composer\Package\CompletePackageInterface;
 use Composer\Repository\RepositoryInterface;
-use Composer\Repository\ArrayRepository;
+use Composer\Repository\RootPackageRepository;
 use Composer\Repository\RepositoryFactory;
 use Composer\Util\Platform;
 use Composer\Util\ProcessExecutor;
@@ -157,7 +157,7 @@ EOT
 
         if ($composer) {
             return array_merge(
-                array(new ArrayRepository(array($composer->getPackage()))), // root package
+                array(new RootPackageRepository($composer->getPackage())), // root package
                 array($composer->getRepositoryManager()->getLocalRepository()), // installed packages
                 $composer->getRepositoryManager()->getRepositories() // remotes
             );

+ 31 - 33
src/Composer/Command/ShowCommand.php

@@ -22,13 +22,14 @@ use Composer\Package\Version\VersionParser;
 use Composer\Package\Version\VersionSelector;
 use Composer\Plugin\CommandEvent;
 use Composer\Plugin\PluginEvents;
-use Composer\Repository\ArrayRepository;
 use Composer\Repository\ComposerRepository;
 use Composer\Repository\CompositeRepository;
 use Composer\Repository\PlatformRepository;
 use Composer\Repository\RepositoryFactory;
+use Composer\Repository\InstalledRepository;
 use Composer\Repository\RepositoryInterface;
 use Composer\Repository\RepositorySet;
+use Composer\Repository\RootPackageRepository;
 use Composer\Semver\Constraint\ConstraintInterface;
 use Composer\Semver\Semver;
 use Composer\Spdx\SpdxLicenses;
@@ -152,11 +153,11 @@ EOT
 
         if ($input->getOption('self')) {
             $package = $this->getComposer()->getPackage();
-            $repos = $installedRepo = new ArrayRepository(array($package));
+            $repos = $installedRepo = new InstalledRepository(array(new RootPackageRepository($package)));
         } elseif ($input->getOption('platform')) {
-            $repos = $installedRepo = $platformRepo;
+            $repos = $installedRepo = new InstalledRepository(array($platformRepo));
         } elseif ($input->getOption('available')) {
-            $installedRepo = $platformRepo;
+            $installedRepo = new InstalledRepository(array($platformRepo));
             if ($composer) {
                 $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
             } else {
@@ -166,15 +167,15 @@ EOT
             }
         } elseif ($input->getOption('all') && $composer) {
             $localRepo = $composer->getRepositoryManager()->getLocalRepository();
-            $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
+            $installedRepo = new InstalledRepository(array($localRepo, $platformRepo));
             $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
         } elseif ($input->getOption('all')) {
             $defaultRepos = RepositoryFactory::defaultRepos($io);
             $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
-            $installedRepo = $platformRepo;
+            $installedRepo = new InstalledRepository(array($platformRepo));
             $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
         } else {
-            $repos = $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
+            $repos = $installedRepo = new InstalledRepository(array($this->getComposer()->getRepositoryManager()->getLocalRepository()));
             $rootPkg = $this->getComposer()->getPackage();
             if (!$installedRepo->getPackages() && ($rootPkg->getRequires() || $rootPkg->getDevRequires())) {
                 $io->writeError('<warning>No dependencies installed. Try running composer install or update.</warning>');
@@ -313,10 +314,7 @@ EOT
         foreach ($repos as $repo) {
             if ($repo === $platformRepo) {
                 $type = 'platform';
-            } elseif (
-                $repo === $installedRepo
-                || ($installedRepo instanceof CompositeRepository && in_array($repo, $installedRepo->getRepositories(), true))
-            ) {
+            } elseif ($repo === $installedRepo || in_array($repo, $installedRepo->getRepositories(), true)) {
                 $type = 'installed';
             } else {
                 $type = 'available';
@@ -528,14 +526,14 @@ EOT
     /**
      * finds a package by name and version if provided
      *
-     * @param  RepositoryInterface        $installedRepo
+     * @param  InstalledRepository        $installedRepo
      * @param  RepositoryInterface        $repos
      * @param  string                     $name
      * @param  ConstraintInterface|string $version
      * @throws \InvalidArgumentException
      * @return array                      array(CompletePackageInterface, array of versions)
      */
-    protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null)
+    protected function getPackage(InstalledRepository $installedRepo, RepositoryInterface $repos, $name, $version = null)
     {
         $name = strtolower($name);
         $constraint = is_string($version) ? $this->versionParser->parseConstraints($version) : $version;
@@ -573,10 +571,10 @@ EOT
      *
      * @param CompletePackageInterface $package
      * @param array                    $versions
-     * @param RepositoryInterface      $installedRepo
+     * @param InstalledRepository      $installedRepo
      * @param PackageInterface|null    $latestPackage
      */
-    protected function printPackageInfo(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
+    protected function printPackageInfo(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo, PackageInterface $latestPackage = null)
     {
         $io = $this->getIO();
 
@@ -601,10 +599,10 @@ EOT
      *
      * @param CompletePackageInterface $package
      * @param array                    $versions
-     * @param RepositoryInterface      $installedRepo
+     * @param InstalledRepository      $installedRepo
      * @param PackageInterface|null    $latestPackage
      */
-    protected function printMeta(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
+    protected function printMeta(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo, PackageInterface $latestPackage = null)
     {
         $io = $this->getIO();
         $io->write('<info>name</info>     : ' . $package->getPrettyName());
@@ -673,9 +671,9 @@ EOT
      *
      * @param CompletePackageInterface $package
      * @param array                    $versions
-     * @param RepositoryInterface      $installedRepo
+     * @param InstalledRepository      $installedRepo
      */
-    protected function printVersions(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo)
+    protected function printVersions(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo)
     {
         uasort($versions, 'version_compare');
         $versions = array_keys(array_reverse($versions));
@@ -749,10 +747,10 @@ EOT
      *
      * @param CompletePackageInterface $package
      * @param array                    $versions
-     * @param RepositoryInterface      $installedRepo
+     * @param InstalledRepository      $installedRepo
      * @param PackageInterface|null    $latestPackage
      */
-    protected function printPackageInfoAsJson(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
+    protected function printPackageInfoAsJson(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo, PackageInterface $latestPackage = null)
     {
         $json = array(
             'name' => $package->getPrettyName(),
@@ -972,15 +970,15 @@ EOT
     /**
      * Generate the package tree
      *
-     * @param  PackageInterface $package
-     * @param  RepositoryInterface     $installedRepo
-     * @param  RepositoryInterface     $distantRepos
+     * @param  PackageInterface    $package
+     * @param  InstalledRepository $installedRepo
+     * @param  RepositoryInterface $remoteRepos
      * @return array
      */
     protected function generatePackageTree(
         PackageInterface $package,
-        RepositoryInterface $installedRepo,
-        RepositoryInterface $distantRepos
+        InstalledRepository $installedRepo,
+        RepositoryInterface $remoteRepos
     ) {
         $requires = $package->getRequires();
         ksort($requires);
@@ -993,7 +991,7 @@ EOT
                 'version' => $require->getPrettyConstraint(),
             );
 
-            $deepChildren = $this->addTree($requireName, $require, $installedRepo, $distantRepos, $packagesInTree);
+            $deepChildren = $this->addTree($requireName, $require, $installedRepo, $remoteRepos, $packagesInTree);
 
             if ($deepChildren) {
                 $treeChildDesc['requires'] = $deepChildren;
@@ -1072,22 +1070,22 @@ EOT
      *
      * @param  string                  $name
      * @param  PackageInterface|string $package
-     * @param  RepositoryInterface     $installedRepo
-     * @param  RepositoryInterface     $distantRepos
+     * @param  InstalledRepository     $installedRepo
+     * @param  RepositoryInterface     $remoteRepos
      * @param  array                   $packagesInTree
      * @return array
      */
     protected function addTree(
         $name,
         $package,
-        RepositoryInterface $installedRepo,
-        RepositoryInterface $distantRepos,
+        InstalledRepository $installedRepo,
+        RepositoryInterface $remoteRepos,
         array $packagesInTree
     ) {
         $children = array();
         list($package, $versions) = $this->getPackage(
             $installedRepo,
-            $distantRepos,
+            $remoteRepos,
             $name,
             $package->getPrettyConstraint() === 'self.version' ? $package->getConstraint() : $package->getPrettyConstraint()
         );
@@ -1104,7 +1102,7 @@ EOT
 
                 if (!in_array($requireName, $currentTree, true)) {
                     $currentTree[] = $requireName;
-                    $deepChildren = $this->addTree($requireName, $require, $installedRepo, $distantRepos, $currentTree);
+                    $deepChildren = $this->addTree($requireName, $require, $installedRepo, $remoteRepos, $currentTree);
                     if ($deepChildren) {
                         $treeChildDesc['requires'] = $deepChildren;
                     }

+ 8 - 8
src/Composer/Installer.php

@@ -51,6 +51,7 @@ use Composer\Package\PackageInterface;
 use Composer\Package\RootPackageInterface;
 use Composer\Repository\CompositeRepository;
 use Composer\Repository\InstalledArrayRepository;
+use Composer\Repository\InstalledRepository;
 use Composer\Repository\RootPackageRepository;
 use Composer\Repository\PlatformRepository;
 use Composer\Repository\RepositoryInterface;
@@ -257,12 +258,12 @@ class Installer
         }
 
         if ($this->update) {
-            $installedRepos = array(
+            $installedRepo = new InstalledRepository(array(
                 $this->locker->getLockedRepository($this->devMode),
                 $this->createPlatformRepo(false),
                 new RootPackageRepository(clone $this->package),
-            );
-            $this->suggestedPackagesReporter->outputMinimalistic(new CompositeRepository($installedRepos));
+            ));
+            $this->suggestedPackagesReporter->outputMinimalistic($installedRepo);
         }
 
         // Find abandoned packages and warn user
@@ -859,8 +860,7 @@ class Installer
             }
         }
 
-        $repositorySet = new RepositorySet('dev');
-        $repositorySet->addRepository($lockRepo);
+        $installedRepo = new InstalledRepository(array($lockRepo));
 
         $seen = array();
 
@@ -870,7 +870,7 @@ class Installer
             $packageQueue = new \SplQueue;
             $nameMatchesRequiredPackage = false;
 
-            $depPackages = $repositorySet->findPackages($packageName, null, RepositorySet::ALLOW_PROVIDERS_REPLACERS);
+            $depPackages = $installedRepo->findPackagesWithReplacersAndProviders($packageName);
             $matchesByPattern = array();
 
             // check if the name is a glob pattern that did not match directly
@@ -878,7 +878,7 @@ class Installer
                 // add any installed package matching the whitelisted name/pattern
                 $whitelistPatternSearchRegexp = BasePackage::packageNameToRegexp($packageName, '^%s$');
                 foreach ($lockRepo->search($whitelistPatternSearchRegexp) as $installedPackage) {
-                    $matchesByPattern[] = $repositorySet->findPackages($installedPackage['name'], null, RepositorySet::ALLOW_PROVIDERS_REPLACERS);
+                    $matchesByPattern[] = $installedRepo->findPackages($installedPackage['name']);
                 }
 
                 // add root requirements which match the whitelisted name/pattern
@@ -919,7 +919,7 @@ class Installer
                 $requires = $package->getRequires();
 
                 foreach ($requires as $require) {
-                    $requirePackages = $repositorySet->findPackages($require->getTarget(), null, RepositorySet::ALLOW_PROVIDERS_REPLACERS);
+                    $requirePackages = $installedRepo->findPackagesWithReplacersAndProviders($require->getTarget());
 
                     foreach ($requirePackages as $requirePackage) {
                         if (isset($this->updateWhitelist[$requirePackage->getName()])) {

+ 10 - 34
src/Composer/Plugin/PluginManager.php

@@ -19,7 +19,7 @@ use Composer\Package\CompletePackage;
 use Composer\Package\Package;
 use Composer\Package\Version\VersionParser;
 use Composer\Repository\RepositoryInterface;
-use Composer\Repository\CompositeRepository;
+use Composer\Repository\InstalledRepository;
 use Composer\Package\PackageInterface;
 use Composer\Package\Link;
 use Composer\Semver\Constraint\Constraint;
@@ -158,13 +158,13 @@ class PluginManager
         $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
         $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
 
-        $localRepos = $localRepo;
+        $installedRepo = new InstalledRepository(array($localRepo));
         if ($globalRepo) {
-            $localRepos = new CompositeRepository(array($localRepos, $globalRepo));
+            $installedRepo->addRepository($globalRepo);
         }
 
         $autoloadPackages = array($package->getName() => $package);
-        $autoloadPackages = $this->collectDependencies($localRepos, $autoloadPackages, $package);
+        $autoloadPackages = $this->collectDependencies($installedRepo, $autoloadPackages, $package);
 
         $generator = $this->composer->getAutoloadGenerator();
         $autoloads = array();
@@ -375,13 +375,13 @@ class PluginManager
     /**
      * Recursively generates a map of package names to packages for all deps
      *
-     * @param RepositoryInterface $localRepos Set of local repos
-     * @param array               $collected  Current state of the map for recursion
-     * @param PackageInterface    $package    The package to analyze
+     * @param InstalledRepository $installedRepo Set of local repos
+     * @param array               $collected     Current state of the map for recursion
+     * @param PackageInterface    $package       The package to analyze
      *
      * @return array Map of package names to packages
      */
-    private function collectDependencies(RepositoryInterface $localRepos, array $collected, PackageInterface $package)
+    private function collectDependencies(InstalledRepository $installedRepo, array $collected, PackageInterface $package)
     {
         $requires = array_merge(
             $package->getRequires(),
@@ -389,10 +389,10 @@ class PluginManager
         );
 
         foreach ($requires as $requireLink) {
-            foreach ($this->lookupInstalledPackages($localRepos, $requireLink) as $requiredPackage) {
+            foreach ($installedRepo->findPackagesWithReplacersAndProviders($requireLink->getTarget(), $requireLink->getConstraint()) as $requiredPackage) {
                 if (!isset($collected[$requiredPackage->getName()])) {
                     $collected[$requiredPackage->getName()] = $requiredPackage;
-                    $collected = $this->collectDependencies($localRepos, $collected, $requiredPackage);
+                    $collected = $this->collectDependencies($installedRepo, $collected, $requiredPackage);
                 }
             }
         }
@@ -400,30 +400,6 @@ class PluginManager
         return $collected;
     }
 
-    /**
-     * Resolves a package link to a package in the installed repo set
-     *
-     * Since dependencies are already installed this should always find one.
-     *
-     * @param RepositoryInterface $localRepos Set of local repos
-     * @param Link $link Package link to look up
-     *
-     * @return PackageInterface[] The found packages
-     */
-    private function lookupInstalledPackages(RepositoryInterface $localRepos, Link $link)
-    {
-        $matches = array();
-        foreach ($localRepos->getPackages() as $candidate) {
-            if (in_array($link->getTarget(), $candidate->getNames(), true)) {
-                if ($link->getConstraint() === null || $link->getConstraint()->matches(new Constraint('=', $candidate->getVersion()))) {
-                    $matches[] = $candidate;
-                }
-            }
-        }
-
-        return $matches;
-    }
-
     /**
      * Retrieves the path a package is installed to.
      *

+ 7 - 4
src/Composer/Repository/ArrayRepository.php

@@ -25,7 +25,7 @@ use Composer\Semver\Constraint\Constraint;
  *
  * @author Nils Adermann <naderman@naderman.de>
  */
-class ArrayRepository extends BaseRepository
+class ArrayRepository implements RepositoryInterface
 {
     /** @var PackageInterface[] */
     protected $packages;
@@ -44,7 +44,7 @@ class ArrayRepository extends BaseRepository
 
     public function getRepoName()
     {
-        return 'array repo (defining '.count($this->packages).' package'.(count($this->packages) > 1 ? 's' : '').')';
+        return 'array repo (defining '.$this->count().' package'.($this->count() > 1 ? 's' : '').')';
     }
 
     /**
@@ -126,8 +126,7 @@ class ArrayRepository extends BaseRepository
 
         foreach ($this->getPackages() as $package) {
             if ($name === $package->getName()) {
-                $pkgConstraint = new Constraint('==', $package->getVersion());
-                if (null === $constraint || $constraint->matches($pkgConstraint)) {
+                if (null === $constraint || $constraint->matches(new Constraint('==', $package->getVersion()))) {
                     $packages[] = $package;
                 }
             }
@@ -250,6 +249,10 @@ class ArrayRepository extends BaseRepository
      */
     public function count()
     {
+        if (null === $this->packages) {
+            $this->initialize();
+        }
+
         return count($this->packages);
     }
 

+ 1 - 1
src/Composer/Repository/CompositeRepository.php

@@ -19,7 +19,7 @@ use Composer\Package\PackageInterface;
  *
  * @author Beau Simensen <beau@dflydev.com>
  */
-class CompositeRepository extends BaseRepository
+class CompositeRepository implements RepositoryInterface
 {
     /**
      * List of repositories

+ 57 - 5
src/Composer/Repository/BaseRepository.php → src/Composer/Repository/InstalledRepository.php

@@ -12,19 +12,48 @@
 
 namespace Composer\Repository;
 
-use Composer\Package\AliasPackage;
-use Composer\Package\RootPackageInterface;
+use Composer\Package\Version\VersionParser;
 use Composer\Semver\Constraint\ConstraintInterface;
 use Composer\Semver\Constraint\Constraint;
+use Composer\Package\AliasPackage;
+use Composer\Package\RootPackageInterface;
 use Composer\Package\Link;
 
+
 /**
- * Common ancestor class for generic repository functionality.
+ * Installed repository is a composite of all installed repo types.
+ *
+ * The main use case is tagging a repo as an "installed" repository, and offering a way to get providers/replacers easily.
+ *
+ * Installed repos are LockArrayRepository, InstalledRepositoryInterface, RootPackageRepository and PlatformRepository
  *
- * @author Niels Keurentjes <niels.keurentjes@omines.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
  */
-abstract class BaseRepository implements RepositoryInterface
+class InstalledRepository extends CompositeRepository
 {
+    public function findPackagesWithReplacersAndProviders($name, $constraint = null)
+    {
+        $name = strtolower($name);
+
+        if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
+            $versionParser = new VersionParser();
+            $constraint = $versionParser->parseConstraints($constraint);
+        }
+
+        $matches = array();
+        foreach ($this->getRepositories() as $repo) {
+            foreach ($repo->getPackages() as $candidate) {
+                if (in_array($name, $candidate->getNames(), true)) {
+                    if (null === $constraint || $constraint->matches(new Constraint('==', $candidate->getVersion()))) {
+                        $matches[] = $candidate;
+                    }
+                }
+            }
+        }
+
+        return $matches;
+    }
+
     /**
      * 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
@@ -176,4 +205,27 @@ abstract class BaseRepository implements RepositoryInterface
 
         return $results;
     }
+
+    public function getRepoName()
+    {
+        return 'installed repo ('.implode(', ', array_map(function ($repo) { return $repo->getRepoName(); }, $this->repositories)).')';
+    }
+
+    /**
+     * Add a repository.
+     * @param RepositoryInterface $repository
+     */
+    public function addRepository(RepositoryInterface $repository)
+    {
+        if (
+            $repository instanceof LockArrayRepository
+            || $repository instanceof InstalledRepositoryInterface
+            || $repository instanceof RootPackageRepository
+            || $repository instanceof PlatformRepository
+        ) {
+            return parent::addRepository($repository);
+        }
+
+        throw new \LogicException('An InstalledRepository can not contain a repository of type '.get_class($repository).' ('.$repository->getRepoName().')');
+    }
 }

+ 8 - 12
src/Composer/Repository/RepositorySet.php

@@ -30,18 +30,14 @@ use Composer\Package\Version\StabilityFilter;
  */
 class RepositorySet
 {
-    /**
-     * Packages which replace/provide the given name might be returned as well even if they do not match the name exactly
-     */
-    const ALLOW_PROVIDERS_REPLACERS = 1;
     /**
      * Packages are returned even though their stability does not match the required stability
      */
-    const ALLOW_UNACCEPTABLE_STABILITIES = 2;
+    const ALLOW_UNACCEPTABLE_STABILITIES = 1;
     /**
      * Packages will be looked up in all repositories, even after they have been found in a higher prio one
      */
-    const ALLOW_SHADOWED_REPOSITORIES = 4;
+    const ALLOW_SHADOWED_REPOSITORIES = 2;
 
     /** @var array */
     private $rootAliases;
@@ -127,7 +123,6 @@ class RepositorySet
      */
     public function findPackages($name, ConstraintInterface $constraint = null, $flags = 0)
     {
-        $exactMatch = ($flags & self::ALLOW_PROVIDERS_REPLACERS) === 0;
         $ignoreStability = ($flags & self::ALLOW_UNACCEPTABLE_STABILITIES) !== 0;
         $loadFromAllRepos = ($flags & self::ALLOW_SHADOWED_REPOSITORIES) !== 0;
 
@@ -152,13 +147,14 @@ class RepositorySet
 
         $candidates = $packages ? call_user_func_array('array_merge', $packages) : array();
 
+        // when using loadPackages above (!$loadFromAllRepos) the repos already filter for stability so no need to do it again
+        if ($ignoreStability || !$loadFromAllRepos) {
+            return $candidates;
+        }
+
         $result = array();
         foreach ($candidates as $candidate) {
-            if ($exactMatch && $candidate->getName() !== $name) {
-                continue;
-            }
-
-            if (!$ignoreStability && $this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) {
+            if ($this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) {
                 $result[] = $candidate;
             }
         }

+ 51 - 0
tests/Composer/Test/Repository/InstalledRepositoryTest.php

@@ -0,0 +1,51 @@
+<?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\Test\Repository;
+
+use Composer\Repository\InstalledRepository;
+use Composer\Repository\ArrayRepository;
+use Composer\Repository\InstalledArrayRepository;
+use Composer\Package\Link;
+use Composer\Test\TestCase;
+
+class InstalledRepositoryTest extends TestCase
+{
+    public function testFindPackagesWithReplacersAndProviders()
+    {
+        $arrayRepoOne = new InstalledArrayRepository;
+        $arrayRepoOne->addPackage($foo = $this->getPackage('foo', '1'));
+        $arrayRepoOne->addPackage($foo2 = $this->getPackage('foo', '2'));
+
+        $arrayRepoTwo = new InstalledArrayRepository;
+        $arrayRepoTwo->addPackage($bar = $this->getPackage('bar', '1'));
+        $arrayRepoTwo->addPackage($bar2 = $this->getPackage('bar', '2'));
+
+        $foo->setReplaces(array(new Link('foo', 'provided')));
+        $bar2->setProvides(array(new Link('bar', 'provided')));
+
+        $repo = new InstalledRepository(array($arrayRepoOne, $arrayRepoTwo));
+
+        $this->assertEquals(array($foo2), $repo->findPackagesWithReplacersAndProviders('foo', '2'));
+        $this->assertEquals(array($bar), $repo->findPackagesWithReplacersAndProviders('bar', '1'));
+        $this->assertEquals(array($foo, $bar2), $repo->findPackagesWithReplacersAndProviders('provided'));
+    }
+
+    public function testAddRepository()
+    {
+        $arrayRepoOne = new ArrayRepository;
+
+        $this->setExpectedException('LogicException');
+
+        new InstalledRepository(array($arrayRepoOne));
+    }
+}