diff --git a/src/Composer/DependencyResolver/DefaultPolicy.php b/src/Composer/DependencyResolver/DefaultPolicy.php index 3659b0a51..ac3d38995 100644 --- a/src/Composer/DependencyResolver/DefaultPolicy.php +++ b/src/Composer/DependencyResolver/DefaultPolicy.php @@ -69,6 +69,8 @@ class DefaultPolicy implements PolicyInterface $literals = $this->pruneToBestVersion($literals); $literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals); + + $literals = $this->pruneRemoteAliases($literals); } $selected = call_user_func_array('array_merge', $packages); @@ -210,8 +212,8 @@ class DefaultPolicy implements PolicyInterface } /** - * Assumes that installed packages come first and then all highest priority packages - */ + * Assumes that installed packages come first and then all highest priority packages + */ protected function pruneToHighestPriorityOrInstalled(Pool $pool, array $installedMap, array $literals) { $selected = array(); @@ -239,4 +241,38 @@ class DefaultPolicy implements PolicyInterface return $selected; } + + /** + * Assumes that locally aliased (in root package requires) packages take priority over branch-alias ones + * + * If no package is a local alias, nothing happens + */ + protected function pruneRemoteAliases(array $literals) + { + $hasLocalAlias = false; + + foreach ($literals as $literal) { + $package = $literal->getPackage(); + + if ($package instanceof AliasPackage && $package->isRootPackageAlias()) { + $hasLocalAlias = true; + break; + } + } + + if (!$hasLocalAlias) { + return $literals; + } + + $selected = array(); + foreach ($literals as $literal) { + $package = $literal->getPackage(); + + if ($package instanceof AliasPackage && $package->isRootPackageAlias()) { + $selected[] = $literal; + } + } + + return $selected; + } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 583d27498..4ef8ea848 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -383,14 +383,16 @@ class Installer foreach ($this->repositoryManager->findPackages($alias['package'], $alias['version']) as $package) { $package->setAlias($alias['alias_normalized']); $package->setPrettyAlias($alias['alias']); - $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); + $package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); + $aliasPackage->setRootPackageAlias(true); } foreach ($this->repositoryManager->getLocalRepositories() as $repo) { foreach ($repo->findPackages($alias['package'], $alias['version']) as $package) { $package->setAlias($alias['alias_normalized']); $package->setPrettyAlias($alias['alias']); - $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); + $package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); $package->getRepository()->removePackage($package); + $aliasPackage->setRootPackageAlias(true); } } } diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php index af5887c9e..aee9a65ed 100644 --- a/src/Composer/Package/AliasPackage.php +++ b/src/Composer/Package/AliasPackage.php @@ -27,6 +27,7 @@ class AliasPackage extends BasePackage protected $prettyVersion; protected $dev; protected $aliasOf; + protected $rootPackageAlias = false; protected $requires; protected $conflicts; @@ -146,6 +147,27 @@ class AliasPackage extends BasePackage return $this->devRequires; } + /** + * Stores whether this is an alias created by an aliasing in the requirements of the root package or not + * + * Use by the policy for sorting manually aliased packages first, see #576 + * + * @param Boolean $value + */ + public function setRootPackageAlias($value) + { + return $this->rootPackageAlias = $value; + } + + /** + * @see setRootPackageAlias + * @return Boolean + */ + public function isRootPackageAlias() + { + return $this->rootPackageAlias; + } + /** * {@inheritDoc} */ diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php index 4bb7c9e33..8a6c64922 100644 --- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -18,6 +18,7 @@ use Composer\DependencyResolver\DefaultPolicy; use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\Literal; use Composer\Package\Link; +use Composer\Package\AliasPackage; use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Test\TestCase; @@ -99,6 +100,35 @@ class DefaultPolicyTest extends TestCase $this->assertEquals($expected, $selected); } + public function testSelectLocalReposFirst() + { + $this->repoImportant = new ArrayRepository; + + $this->repo->addPackage($packageA = $this->getPackage('A', 'dev-master')); + $this->repo->addPackage($packageAAlias = new AliasPackage($packageA, '2.1.9999999.9999999-dev', '2.1.x-dev')); + $this->repoImportant->addPackage($packageAImportant = $this->getPackage('A', 'dev-feature-a')); + $this->repoImportant->addPackage($packageAAliasImportant = new AliasPackage($packageAImportant, '2.1.9999999.9999999-dev', '2.1.x-dev')); + $this->repoImportant->addPackage($packageA2Important = $this->getPackage('A', 'dev-master')); + $this->repoImportant->addPackage($packageA2AliasImportant = new AliasPackage($packageA2Important, '2.1.9999999.9999999-dev', '2.1.x-dev')); + $packageAAliasImportant->setRootPackageAlias(true); + + $this->pool->addRepository($this->repoInstalled); + $this->pool->addRepository($this->repoImportant); + $this->pool->addRepository($this->repo); + + $packages = $this->pool->whatProvides('a', new VersionConstraint('=', '2.1.9999999.9999999-dev')); + $literals = array(); + foreach ($packages as $package) { + $literals[] = new Literal($package, true); + } + + $expected = array(new Literal($packageAAliasImportant, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, array(), $literals); + + $this->assertEquals($expected, $selected); + } + public function testSelectAllProviders() { $this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));