diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index d6fe2844f..49cb138d8 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -456,6 +456,10 @@ EOT ); if ($input->getOption('unset') && (isset($uniqueConfigValues[$settingKey]) || isset($multiConfigValues[$settingKey]))) { + if ($settingKey === 'disable-tls' && $this->config->get('disable-tls')) { + $this->getIO()->writeError('You are now running Composer with SSL/TLS protection enabled.'); + } + return $this->configSource->removeConfigSetting($settingKey); } if (isset($uniqueConfigValues[$settingKey])) { @@ -640,7 +644,17 @@ EOT )); } - return call_user_func(array($this->configSource, $method), $key, $normalizer($values[0])); + $normalizedValue = $normalizer($values[0]); + + if ($key === 'disable-tls') { + if (!$normalizedValue && $this->config->get('disable-tls')) { + $this->getIO()->writeError('You are now running Composer with SSL/TLS protection enabled.'); + } elseif ($normalizedValue && !$this->config->get('disable-tls')) { + $this->getIO()->writeError('You are now running Composer with SSL/TLS protection disabled.'); + } + } + + return call_user_func(array($this->configSource, $method), $key, $normalizedValue); } protected function handleMultiValue($key, array $callbacks, array $values, $method) diff --git a/src/Composer/DependencyResolver/Decisions.php b/src/Composer/DependencyResolver/Decisions.php index a9808e60e..86b62c3d3 100644 --- a/src/Composer/DependencyResolver/Decisions.php +++ b/src/Composer/DependencyResolver/Decisions.php @@ -196,4 +196,16 @@ class Decisions implements \Iterator, \Countable $this->decisionMap[$packageId] = -$level; } } + + public function __toString() + { + $decisionMap = $this->decisionMap; + ksort($decisionMap); + $str = '['; + foreach ($decisionMap as $packageId => $level) { + $str .= $packageId.':'.$level.','; + } + $str .= ']'; + return $str; + } } diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index c3128c6c4..66a43c37b 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -478,7 +478,7 @@ class Solver unset($seen[abs($literal)]); if ($num && 0 === --$num) { - $learnedLiterals[0] = -abs($literal); + $learnedLiterals[0] = -$literal; if (!$l1num) { break 2; diff --git a/src/Composer/Repository/RepositoryFactory.php b/src/Composer/Repository/RepositoryFactory.php index 9508f5886..261345930 100644 --- a/src/Composer/Repository/RepositoryFactory.php +++ b/src/Composer/Repository/RepositoryFactory.php @@ -94,6 +94,9 @@ class RepositoryFactory if (!$config) { $config = Factory::createConfig($io); } + if ($io) { + $io->loadConfiguration($config); + } if (!$rm) { if (!$io) { throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager'); diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index 7ad4f8f65..ccb1810de 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -846,6 +846,70 @@ class SolverTest extends TestCase )); } + /** + * Tests for a bug introduced in commit 451bab1c2cd58e05af6e21639b829408ad023463 Solver.php line 554/523 + * + * Every package and link in this test matters, only a combination this complex will run into the situation in which + * a negatively decided literal will need to be learned inverted as a positive assertion. + * + * In particular in this case the goal is to first have the solver decide X 2.0 should not be installed to later + * decide to learn that X 2.0 must be installed and revert decisions to retry solving with this new assumption. + */ + public function testLearnPositiveLiteral() + { + $this->repo->addPackage($packageA = $this->getPackage('A', '1.0')); + $this->repo->addPackage($packageB = $this->getPackage('B', '1.0')); + $this->repo->addPackage($packageC1 = $this->getPackage('C', '1.0')); + $this->repo->addPackage($packageC2 = $this->getPackage('C', '2.0')); + $this->repo->addPackage($packageD = $this->getPackage('D', '1.0')); + $this->repo->addPackage($packageE = $this->getPackage('E', '1.0')); + $this->repo->addPackage($packageF1 = $this->getPackage('F', '1.0')); + $this->repo->addPackage($packageF2 = $this->getPackage('F', '2.0')); + $this->repo->addPackage($packageG1 = $this->getPackage('G', '1.0')); + $this->repo->addPackage($packageG2 = $this->getPackage('G', '2.0')); + $this->repo->addPackage($packageG3 = $this->getPackage('G', '3.0')); + + $packageA->setRequires(array( + 'b' => new Link('A', 'B', $this->getVersionConstraint('==', '1.0'), 'requires'), + 'c' => new Link('A', 'C', $this->getVersionConstraint('>=', '1.0'), 'requires'), + 'd' => new Link('A', 'D', $this->getVersionConstraint('==', '1.0'), 'requires'), + )); + + $packageB->setRequires(array( + 'e' => new Link('B', 'E', $this->getVersionConstraint('==', '1.0'), 'requires'), + )); + + $packageC1->setRequires(array( + 'f' => new Link('C', 'F', $this->getVersionConstraint('==', '1.0'), 'requires'), + )); + $packageC2->setRequires(array( + 'f' => new Link('C', 'F', $this->getVersionConstraint('==', '1.0'), 'requires'), + 'g' => new Link('C', 'G', $this->getVersionConstraint('>=', '1.0'), 'requires'), + )); + + $packageD->setRequires(array( + 'f' => new Link('D', 'F', $this->getVersionConstraint('>=', '1.0'), 'requires'), + )); + + $packageE->setRequires(array( + 'g' => new Link('E', 'G', $this->getVersionConstraint('<=', '2.0'), 'requires'), + )); + + $this->reposComplete(); + + $this->request->install('A'); + + $this->checkSolverResult(array( + array('job' => 'install', 'package' => $packageF1), + array('job' => 'install', 'package' => $packageD), + array('job' => 'install', 'package' => $packageG2), + array('job' => 'install', 'package' => $packageC2), + array('job' => 'install', 'package' => $packageE), + array('job' => 'install', 'package' => $packageB), + array('job' => 'install', 'package' => $packageA), + )); + } + protected function reposComplete() { $this->repoSet->addRepository($this->repoInstalled); diff --git a/tests/Composer/Test/Fixtures/installer/update-requiring-decision-reverts-and-learning-positive-literals.test b/tests/Composer/Test/Fixtures/installer/update-requiring-decision-reverts-and-learning-positive-literals.test new file mode 100644 index 000000000..3f5667823 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-requiring-decision-reverts-and-learning-positive-literals.test @@ -0,0 +1,100 @@ +--TEST-- +Update a project which requires decision reverts and learning a positive literal to arrive at a correct solution. + +Tests for solver regression in commit 451bab1c2cd58e05af6e21639b829408ad023463. See also SolverTest testLearnPositiveLiteral +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { + "name": "spryker-feature/product", + "require": { + "spryker-feature/spryker-core": "1.0.0", + "spryker-shop/product-search-widget": ">=1.0.0", + "spryker/product-category-filter-gui": "1.0.0" + }, + "version": "1.0.0" + }, + { + "name": "spryker-feature/spryker-core", + "version": "1.0.0", + "require": { + "spryker/store": "1.0.0" + } + }, + { + "name": "spryker/store", + "version": "1.0.0", + "require": { + "spryker/kernel": "<=2.0.0" + } + }, + { + "name": "spryker-shop/product-search-widget", + "version": "1.0.0", + "require": { + "spryker/catalog": "1.0.0" + } + }, + { + "name": "spryker-shop/product-search-widget", + "version": "2.0.0", + "require": { + "spryker/catalog": "1.0.0", + "spryker/kernel": ">=1.0.0" + } + }, + { + "name": "spryker/product-category-filter-gui", + "version": "1.0.0", + "require": { + "spryker/catalog": ">=1.0.0" + } + }, + { + "name": "spryker/catalog", + "version": "1.0.0", + "require": { } + }, + { + "name": "spryker/catalog", + "version": "2.0.0", + "require": { } + }, + + { + "name": "spryker/kernel", + "version": "1.0.0", + "require": { } + }, + { + "name": "spryker/kernel", + "version": "2.0.0", + "require": { + } + }, + { + "name": "spryker/kernel", + "version": "3.0.0", + "require": { } + } + ] + } + ], + "require": { + "spryker-feature/product": "1.0.0" + } +} +--RUN-- +update +--EXPECT-- +Installing spryker/catalog (1.0.0) +Installing spryker/product-category-filter-gui (1.0.0) +Installing spryker/kernel (2.0.0) +Installing spryker-shop/product-search-widget (2.0.0) +Installing spryker/store (1.0.0) +Installing spryker-feature/spryker-core (1.0.0) +Installing spryker-feature/product (1.0.0) +