Skip to content

Commit

Permalink
Whitelist packages with names matching those specified before generat…
Browse files Browse the repository at this point in the history
…ing rules

Addresses composer#2690 doesn't do any performance optimisations yet which we
could do now
  • Loading branch information
naderman committed Feb 21, 2014
1 parent 0df9c80 commit 3148ffd
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 48 deletions.
4 changes: 2 additions & 2 deletions src/Composer/DependencyResolver/DefaultPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ public function versionCompare(PackageInterface $a, PackageInterface $b, $operat
return $constraint->matchSpecific($version, true);
}

public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package)
public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package, $mustMatchName = false)
{
$packages = array();

foreach ($pool->whatProvides($package->getName()) as $candidate) {
foreach ($pool->whatProvides($package->getName(), null, $mustMatchName) as $candidate) {
if ($candidate !== $package) {
$packages[] = $candidate;
}
Expand Down
24 changes: 18 additions & 6 deletions src/Composer/DependencyResolver/Pool.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Pool
protected $versionParser;
protected $providerCache = array();
protected $filterRequires;
protected $whitelist = null;
protected $id = 1;

public function __construct($minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
Expand All @@ -66,6 +67,11 @@ public function __construct($minimumStability = 'stable', array $stabilityFlags
$this->filterRequires = $filterRequires;
}

public function setWhitelist($whitelist)
{
$this->whitelist = $whitelist;
}

/**
* Adds a repository and its packages to this package pool
*
Expand Down Expand Up @@ -223,21 +229,24 @@ public function packageById($id)
* @param string $name The package name to be searched for
* @param LinkConstraintInterface $constraint A constraint that all returned
* packages must match or null to return all
* @param bool $mustMatchName Whether the name of returned packages
* must match the given name
* @return array A set of packages
*/
public function whatProvides($name, LinkConstraintInterface $constraint = null)
public function whatProvides($name, LinkConstraintInterface $constraint = null, $mustMatchName = false)
{
if (isset($this->providerCache[$name][(string) $constraint])) {
return $this->providerCache[$name][(string) $constraint];
$key = ((string) (int) $mustMatchName).((string) $constraint);
if (isset($this->providerCache[$name][$key])) {
return $this->providerCache[$name][$key];
}

return $this->providerCache[$name][(string) $constraint] = $this->computeWhatProvides($name, $constraint);
return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName);
}

/**
* @see whatProvides
*/
private function computeWhatProvides($name, $constraint)
private function computeWhatProvides($name, $constraint, $mustMatchName = false)
{
$candidates = array();

Expand All @@ -259,6 +268,9 @@ private function computeWhatProvides($name, $constraint)
$nameMatch = false;

foreach ($candidates as $candidate) {
if ($this->whitelist !== null && !isset($this->whitelist[$candidate->getId()])) {
continue;
}
switch ($this->match($candidate, $name, $constraint)) {
case self::MATCH_NONE:
break;
Expand Down Expand Up @@ -289,7 +301,7 @@ private function computeWhatProvides($name, $constraint)
}

// if a package with the required name exists, we ignore providers
if ($nameMatch) {
if ($nameMatch || $mustMatchName) {
return $matches;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Composer/DependencyResolver/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function remove($packageName, LinkConstraintInterface $constraint = null)
protected function addJob($packageName, $cmd, LinkConstraintInterface $constraint = null)
{
$packageName = strtolower($packageName);
$packages = $this->pool->whatProvides($packageName, $constraint);
$packages = $this->pool->whatProvides($packageName, $constraint, true);

$this->jobs[] = array(
'packages' => $packages,
Expand Down
71 changes: 71 additions & 0 deletions src/Composer/DependencyResolver/RuleSetGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class RuleSetGenerator
protected $rules;
protected $jobs;
protected $installedMap;
protected $whitelistedMap;
protected $addedMap;

public function __construct(PolicyInterface $policy, Pool $pool)
{
Expand Down Expand Up @@ -141,6 +143,41 @@ private function addRule($type, Rule $newRule = null)
$this->rules->add($newRule, $type);
}

protected function whitelistFromPackage(PackageInterface $package)
{
$workQueue = new \SplQueue;
$workQueue->enqueue($package);

while (!$workQueue->isEmpty()) {
$package = $workQueue->dequeue();
if (isset($this->whitelistedMap[$package->getId()])) {
continue;
}

$this->whitelistedMap[$package->getId()] = true;

foreach ($package->getRequires() as $link) {
$possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint(), true);

foreach ($possibleRequires as $require) {
$workQueue->enqueue($require);
}
}

$obsoleteProviders = $this->pool->whatProvides($package->getName(), null, true);

foreach ($obsoleteProviders as $provider) {
if ($provider === $package) {
continue;
}

if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
$workQueue->enqueue($provider);
}
}
}
}

protected function addRulesForPackage(PackageInterface $package)
{
$workQueue = new \SplQueue;
Expand Down Expand Up @@ -236,6 +273,30 @@ private function addRulesForUpdatePackages(PackageInterface $package)
}
}

private function whitelistFromUpdatePackages(PackageInterface $package)
{
$updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package, true);

foreach ($updates as $update) {
$this->whitelistFromPackage($update);
}
}

protected function whitelistFromJobs()
{
foreach ($this->jobs as $job) {
switch ($job['cmd']) {
case 'install':
if ($job['packages']) {
foreach ($job['packages'] as $package) {
$this->whitelistFromPackage($package);
}
}
break;
}
}
}

protected function addRulesForJobs()
{
foreach ($this->jobs as $job) {
Expand Down Expand Up @@ -270,6 +331,16 @@ public function getRulesFor($jobs, $installedMap)
$this->rules = new RuleSet;
$this->installedMap = $installedMap;

$this->whitelistedNames = array();
foreach ($this->installedMap as $package) {
$this->whitelistFromPackage($package);
$this->whitelistFromUpdatePackages($package);
}
$this->whitelistFromJobs();

$this->pool->setWhitelist($this->whitelistedMap);

$this->addedMap = array();
foreach ($this->installedMap as $package) {
$this->addRulesForPackage($package);
$this->addRulesForUpdatePackages($package);
Expand Down
10 changes: 5 additions & 5 deletions tests/Composer/Test/DependencyResolver/SolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,9 @@ public function testInstallProvider()

$this->request->install('A');

$this->checkSolverResult(array(
array('job' => 'install', 'package' => $packageQ),
array('job' => 'install', 'package' => $packageA),
));
// must explicitly pick the provider, so error in this case
$this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
$this->solver->solve($this->request);
}

public function testSkipReplacerOfExistingPackage()
Expand Down Expand Up @@ -574,11 +573,12 @@ public function testInstallAlternativeWithCircularRequire()
$this->reposComplete();

$this->request->install('A');
$this->request->install('C');

$this->checkSolverResult(array(
array('job' => 'install', 'package' => $packageB),
array('job' => 'install', 'package' => $packageA),
array('job' => 'install', 'package' => $packageC),
array('job' => 'install', 'package' => $packageB),
));
}

Expand Down
34 changes: 0 additions & 34 deletions tests/Composer/Test/Fixtures/installer/provide-priorities.test

This file was deleted.

0 comments on commit 3148ffd

Please sign in to comment.