8000 Whitelist packages with names matching those specified before generating rules by naderman · Pull Request #2733 · composer/composer · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Whitelist packages with names matching those specified before generating rules #2733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 21, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
28 changes: 23 additions & 5 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to cast to string explicitly. the concatenation operator already does it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in eb5c785

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 @@ -288,6 +300,12 @@ private function computeWhatProvides($name, $constraint)
}
}

if ($mustMatchName) {
return array_filter($matches, function ($match) use ($name) {
return $match->getName() == $name;
});
}

// if a package with the required name exists, we ignore providers
if ($nameMatch) {
return $matches;
Expand Down
21 changes: 17 additions & 4 deletions src/Composer/DependencyResolver/Problem.php
8000
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,13 @@ public function getPrettyString(array $installedMap = array())
$rule = $reason['rule'];
$job = $reason['job'];

if ($job && $job['cmd'] === 'install' && empty($job['packages'])) {
if (isset($job['constraint'])) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
} else {
$packages = array();
}

if ($job && $job['cmd'] === 'install' && empty($packages)) {
// handle php extensions
if (0 === stripos($job['packageName'], 'ext-')) {
$ext = substr($job['packageName'], 4);
Expand Down Expand Up @@ -161,18 +167,25 @@ protected function jobToText($job)
{
switch ($job['cmd']) {
case 'install':
if (!$job['packages']) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
if (!$packages) {
return 'No package found to satisfy install request for '.$job['packageName'].$this->constraintToText($job['constraint']);
}

return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).' -> satisfiable by '.$this->getPackageList($job['packages']).'.';
return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).' -> satisfiable by '.$this->getPackageList($packages).'.';
case 'update':
return 'Update request for '.$job['packageName'].$this->constraintToText($job['constraint']).'.';
case 'remove':
return 'Removal request for '.$job['packageName'].$this->constraintToText($job['constraint']).'';
}

return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($job['packages']).'])';
if (isset($job['constraint'])) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
} else {
$packages = array();
}

return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])';
}

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

$this->jobs[] = array(
'packages' => $packages,
'cmd' => $cmd,
'packageName' => $packageName,
'constraint' => $constraint,
Expand All @@ -58,7 +56,7 @@ protected function addJob($packageName, $cmd, LinkConstraintInterface $constrain

public function updateAll()
{
$this->jobs[] = array('cmd' => 'update-all', 'packages' => array());
$this->jobs[] = array('cmd' => 'update-all');
}

public function getJobs()
Expand Down
80 changes: 76 additions & 4 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,26 +273,51 @@ 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':
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint'], true);
foreach ($packages as $package) {
$this->whitelistFromPackage($package);
}
break;
}
}
}

protected function addRulesForJobs()
{
foreach ($this->jobs as $job) {
switch ($job['cmd']) {
case 'install':
if ($job['packages']) {
foreach ($job['packages'] as $package) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
if ($packages) {
foreach ($packages as $package) {
if (!isset($this->installedMap[$package->getId()])) {
$this->addRulesForPackage($package);
}
}

$rule = $this->createInstallOneOfRule($job['packages'], Rule::RULE_JOB_INSTALL, $job);
$rule = $this->createInstallOneOfRule($packages, Rule::RULE_JOB_INSTALL, $job);
$this->addRule(RuleSet::TYPE_JOB, $rule);
}
break;
case 'remove':
// remove all packages with this name including uninstalled
// ones to make sure none of them are picked as replacements
foreach ($job['packages'] as $package) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
foreach ($packages as $package) {
$rule = $this->createRemoveRule($package, Rule::RULE_JOB_REMOVE, $job);
$this->addRule(RuleSet::TYPE_JOB, $rule);
}
Expand All @@ -270,6 +332,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
5 changes: 3 additions & 2 deletions src/Composer/DependencyResolver/Solver.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ protected function setupInstalledMap()
foreach ($this->jobs as $job) {
switch ($job['cmd']) {
case 'update':
foreach ($job['packages'] as $package) {
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
foreach ($packages as $package) {
if (isset($this->installedMap[$package->getId()])) {
$this->updateMap[$package->getId()] = true;
}
Expand All @@ -145,7 +146,7 @@ protected function setupInstalledMap()
break;

case 'install':
if (!$job['packages']) {
if (!$this->pool->whatProvides($job['packageName'], $job['constraint'])) {
$problem = new Problem($this->pool);
$problem->addRule(new Rule($this->pool, array(), null, null, $job));
$this->problems[] = $problem;
Expand Down
10 changes: 5 additions & 5 deletions tests/Composer/Test/DependencyResolver/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public function testRequestInstallAndRemove()

$this->assertEquals(
array(
array('packages' => array($foo), 'cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
array('packages' => array($bar), 'cmd' => 'install', 'packageName' => 'bar', 'constraint' => null),
array('packages' => array($foobar), 'cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null),
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
array('cmd' => 'install', 'packageName' => 'bar', 'constraint' => null),
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null),
),
$request->getJobs());
}
Expand All @@ -66,7 +66,7 @@ public function testRequestInstallSamePackageFromDifferentRepositories()

$this->assertEquals(
array(
array('packages' => array($foo1, $foo2), 'cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint),
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint),
),
$request->getJobs()
);
Expand All @@ -80,7 +80,7 @@ public function testUpdateAll()
$request->updateA 10000 ll();

$this->assertEquals(
array(array('cmd' => 'update-all', 'packages' => array())),
array(array('cmd' => 'update-all')),
$request->getJobs());
}
}
19 changes: 9 additions & 10 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 All @@ -465,7 +464,7 @@ public function testSkipReplacerOfExistingPackage()
));
}

public function testInstallReplacerOfMissingPackage()
public function testNoInstallReplacerOfMissingPackage()
{
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
Expand All @@ -476,10 +475,8 @@ public function testInstallReplacerOfMissingPackage()

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

$this->checkSolverResult(array(
array('job' => 'install', 'package' => $packageQ),
array('job' => 'install', 'package' => $packageA),
));
$this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
$this->solver->solve($this->request);
}

public function testSkipReplacedPackageIfReplacerIsSelected()
Expand Down Expand Up @@ -574,11 +571,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 Expand Up @@ -611,6 +609,7 @@ public function testUseReplacerIfNecessary()
$this->reposComplete();

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

$this->checkSolverResult(array(
array('job' => 'install', 'package' => $packageD2),
Expand Down
Loading
0