From 685bc08c0a31bbfb2834adcd9a8d9095aef1c762 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 9 Nov 2017 13:04:07 +0100 Subject: [PATCH 1/9] Improve the error on init/require if a package could not be found --- src/Composer/Command/InitCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 94ac109fc..421f6b772 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -641,7 +641,7 @@ EOT )); } throw new \InvalidArgumentException(sprintf( - 'Could not find package %s at any version for your minimum-stability (%s). Check the package spelling or your minimum-stability', + 'Could not find a matching version of package %s. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (%s).', $name, $this->getMinimumStability($input) )); From f40f95b269386b20066b5bee3ea382b3439c23ab Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 16 Nov 2017 10:15:37 +0100 Subject: [PATCH 2/9] Add a note that a user could have forgotten to add a custom repo if package not found --- src/Composer/DependencyResolver/SolverProblemsException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/DependencyResolver/SolverProblemsException.php b/src/Composer/DependencyResolver/SolverProblemsException.php index 6014012a4..142895697 100644 --- a/src/Composer/DependencyResolver/SolverProblemsException.php +++ b/src/Composer/DependencyResolver/SolverProblemsException.php @@ -43,7 +43,7 @@ class SolverProblemsException extends \RuntimeException } if (strpos($text, 'could not be found') || strpos($text, 'no matching package found')) { - $text .= "\nPotential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see for more details.\n\nRead for further common problems."; + $text .= "\nPotential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see for more details.\n - It's a private package and you forgot to add a custom repository to find it\n\nRead for further common problems."; } if ($hasExtensionProblems) { From 7dffe79a0fc63437ee501d4ab02b607711efff96 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 16 Nov 2017 12:41:41 +0100 Subject: [PATCH 3/9] Update tests of solver problem message to match new message --- tests/Composer/Test/DependencyResolver/SolverTest.php | 3 ++- .../Test/Fixtures/installer/broken-deps-do-not-replace.test | 1 + tests/Composer/Test/Fixtures/installer/solver-problems.test | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index 9067c4abd..989c992f0 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -710,7 +710,8 @@ class SolverTest extends TestCase $msg .= "Potential causes:\n"; $msg .= " - A typo in the package name\n"; $msg .= " - The package is not available in a stable-enough version according to your minimum-stability setting\n"; - $msg .= " see for more details.\n\n"; + $msg .= " see for more details.\n"; + $msg .= " - It's a private package and you forgot to add a custom repository to find it\n\n"; $msg .= "Read for further common problems."; $this->assertEquals($msg, $e->getMessage()); } diff --git a/tests/Composer/Test/Fixtures/installer/broken-deps-do-not-replace.test b/tests/Composer/Test/Fixtures/installer/broken-deps-do-not-replace.test index fe6b00fff..db4ef23c0 100644 --- a/tests/Composer/Test/Fixtures/installer/broken-deps-do-not-replace.test +++ b/tests/Composer/Test/Fixtures/installer/broken-deps-do-not-replace.test @@ -34,6 +34,7 @@ Potential causes: - A typo in the package name - The package is not available in a stable-enough version according to your minimum-stability setting see for more details. + - It's a private package and you forgot to add a custom repository to find it Read for further common problems. diff --git a/tests/Composer/Test/Fixtures/installer/solver-problems.test b/tests/Composer/Test/Fixtures/installer/solver-problems.test index 605bd3cae..e0359a151 100644 --- a/tests/Composer/Test/Fixtures/installer/solver-problems.test +++ b/tests/Composer/Test/Fixtures/installer/solver-problems.test @@ -55,6 +55,7 @@ Potential causes: - A typo in the package name - The package is not available in a stable-enough version according to your minimum-stability setting see for more details. + - It's a private package and you forgot to add a custom repository to find it Read for further common problems. From 17ec4c17b0b56636d51abbae7a65e115581bb0fe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 28 Nov 2017 16:04:50 +0100 Subject: [PATCH 4/9] Set COMPOSER_DEV_MODE for all events and not just POST hooks --- src/Composer/Installer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 55ec51baf..576133164 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -194,6 +194,9 @@ class Installer } if ($this->runScripts) { + $devMode = (int) $this->devMode; + putenv("COMPOSER_DEV_MODE=$devMode"); + // dispatch pre event $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; $this->eventDispatcher->dispatchScript($eventName, $this->devMode); @@ -299,9 +302,6 @@ class Installer } if ($this->runScripts) { - $devMode = (int) $this->devMode; - putenv("COMPOSER_DEV_MODE=$devMode"); - // dispatch post event $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; $this->eventDispatcher->dispatchScript($eventName, $this->devMode); From 4c4f516ea255433a27a321106d06ed330d2bd04a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 28 Nov 2017 16:07:28 +0100 Subject: [PATCH 5/9] Make sure binaries are recreated before POST-hooks fire --- src/Composer/Installer.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 576133164..f86cfcf93 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -301,12 +301,6 @@ class Installer $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader); } - if ($this->runScripts) { - // dispatch post event - $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; - $this->eventDispatcher->dispatchScript($eventName, $this->devMode); - } - if ($this->executeOperations) { // force binaries re-generation in case they are missing foreach ($localRepo->getPackages() as $package) { @@ -321,6 +315,12 @@ class Installer } } + if ($this->runScripts) { + // dispatch post event + $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; + $this->eventDispatcher->dispatchScript($eventName, $this->devMode); + } + // re-enable GC except on HHVM which triggers a warning here if (!defined('HHVM_VERSION')) { gc_enable(); From b4df2c95173f08d887ad0c4066afbb3ca17a33f7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 28 Nov 2017 16:38:29 +0100 Subject: [PATCH 6/9] Avoid reverting the composer.json in case of a composer require/remove failure that is unrelated to the Solver Fixes #6821 and adds a different fix to #3464 which is getting reverted --- src/Composer/Command/InitCommand.php | 12 ++++++++++-- src/Composer/Command/RemoveCommand.php | 10 +--------- src/Composer/Command/RequireCommand.php | 10 +--------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index aa7213060..51c6d1c6e 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -374,6 +374,9 @@ EOT $requirement['version'], $requirement['name'] )); + } else { + // check that the specified version/constraint exists before we proceed + $this->findBestVersionForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $requirement['version']); } $result[] = $requirement['name'] . ' ' . $requirement['version']; @@ -631,13 +634,18 @@ EOT * @throws \InvalidArgumentException * @return string */ - private function findBestVersionForPackage(InputInterface $input, $name, $phpVersion, $preferredStability = 'stable') + private function findBestVersionForPackage(InputInterface $input, $name, $phpVersion, $preferredStability = 'stable', $requiredVersion = null) { // find the latest version allowed in this pool $versionSelector = new VersionSelector($this->getPool($input)); - $package = $versionSelector->findBestCandidate($name, null, $phpVersion, $preferredStability); + $package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability); if (!$package) { + if ($requiredVersion && $versionSelector->findBestCandidate($name, null, $phpVersion, $preferredStability)) { + throw new \InvalidArgumentException(sprintf( + 'Could not find package %s in a version matching %s', $name, $requiredVersion + )); + } // Check whether the PHP version was the problem if ($phpVersion && $versionSelector->findBestCandidate($name)) { throw new \InvalidArgumentException(sprintf( diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index 048baace0..236668455 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -136,19 +136,11 @@ EOT ->setRunScripts(!$input->getOption('no-scripts')) ; - $exception = null; - try { - $status = $install->run(); - } catch (\Exception $exception) { - $status = 1; - } + $status = $install->run(); if ($status !== 0) { $io->writeError("\n".'Removal failed, reverting '.$file.' to its original content.'); file_put_contents($jsonFile->getPath(), $composerBackup); } - if ($exception) { - throw $exception; - } return $status; } diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 354c661ad..16ca17332 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -175,12 +175,7 @@ EOT ->setPreferLowest($input->getOption('prefer-lowest')) ; - $exception = null; - try { - $status = $install->run(); - } catch (\Exception $exception) { - $status = 1; - } + $status = $install->run(); if ($status !== 0) { if ($newlyCreated) { $io->writeError("\n".'Installation failed, deleting '.$file.'.'); @@ -190,9 +185,6 @@ EOT file_put_contents($json->getPath(), $composerBackup); } } - if ($exception) { - throw $exception; - } return $status; } From 8a136d18e54c9dca834025569b4b2eaeda098c6d Mon Sep 17 00:00:00 2001 From: gregory Date: Wed, 11 Oct 2017 15:55:31 +0300 Subject: [PATCH 7/9] Correctly extract username/password from URL --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index f9cd89d98..bae3019a2 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -224,7 +224,7 @@ class RemoteFilesystem $this->redirects = 1; // The first request counts. // capture username/password from URL if there is one - if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) { + if (preg_match('{^https?://([^:]+):([^@]+)@([^/]+)}i', $fileUrl, $match)) { $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2])); } From 3c76e36e2c344718cae85466da4ae9fcc58c0298 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 28 Nov 2017 18:00:05 +0100 Subject: [PATCH 8/9] Fix regex, refs #6735 --- src/Composer/Util/RemoteFilesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index bae3019a2..cc6709b48 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -224,7 +224,7 @@ class RemoteFilesystem $this->redirects = 1; // The first request counts. // capture username/password from URL if there is one - if (preg_match('{^https?://([^:]+):([^@]+)@([^/]+)}i', $fileUrl, $match)) { + if (preg_match('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $fileUrl, $match)) { $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2])); } From b0922b95afc8ec029a90a616a7613286b73615be Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Thu, 2 Nov 2017 12:46:09 +0000 Subject: [PATCH 9/9] Report multiple inis in php.ini specific messages Where systems use multiple ini files it is perhaps more useful to suggest running `php --ini` to see their locations, rather than showing the loaded php.ini (if one exists). --- src/Composer/Util/IniHelper.php | 18 ++++++++++--- tests/Composer/Test/Util/IniHelperTest.php | 30 +++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/Composer/Util/IniHelper.php b/src/Composer/Util/IniHelper.php index 0dc0529a5..de1065320 100644 --- a/src/Composer/Util/IniHelper.php +++ b/src/Composer/Util/IniHelper.php @@ -33,7 +33,9 @@ class IniHelper */ public static function getAll() { - if ($env = strval(getenv(self::ENV_ORIGINAL))) { + $env = getenv(self::ENV_ORIGINAL); + + if (false !== $env) { return explode(PATH_SEPARATOR, $env); } @@ -47,7 +49,7 @@ class IniHelper } /** - * Describes the location of the loaded php.ini file + * Describes the location of the loaded php.ini file(s) * * @return string */ @@ -56,9 +58,19 @@ class IniHelper $paths = self::getAll(); if (empty($paths[0])) { + array_shift($paths); + } + + $ini = array_shift($paths); + + if (empty($ini)) { return 'A php.ini file does not exist. You will have to create one.'; } - return 'The php.ini used by your command-line PHP is: '.$paths[0]; + if (!empty($paths)) { + return 'Your command-line PHP is using multiple ini files. Run `php --ini` to show them.'; + } + + return 'The php.ini used by your command-line PHP is: '.$ini; } } diff --git a/tests/Composer/Test/Util/IniHelperTest.php b/tests/Composer/Test/Util/IniHelperTest.php index b3a69fd3c..8fa8660c4 100644 --- a/tests/Composer/Test/Util/IniHelperTest.php +++ b/tests/Composer/Test/Util/IniHelperTest.php @@ -21,7 +21,18 @@ class IniHelperTest extends \PHPUnit_Framework_TestCase { public static $envOriginal; - public function testWithLoadedIni() + public function testWithNoIni() + { + $paths = array( + '', + ); + + $this->setEnv($paths); + $this->assertContains('does not exist', IniHelper::getMessage()); + $this->assertEquals($paths, IniHelper::getAll()); + } + + public function testWithLoadedIniOnly() { $paths = array( 'loaded.ini', @@ -32,7 +43,20 @@ class IniHelperTest extends \PHPUnit_Framework_TestCase $this->assertEquals($paths, IniHelper::getAll()); } - public function testWithoutLoadedIni() + public function testWithLoadedIniAndAdditional() + { + $paths = array( + 'loaded.ini', + 'one.ini', + 'two.ini', + ); + + $this->setEnv($paths); + $this->assertContains('multiple ini files', IniHelper::getMessage()); + $this->assertEquals($paths, IniHelper::getAll()); + } + + public function testWithoutLoadedIniAndAdditional() { $paths = array( '', @@ -41,7 +65,7 @@ class IniHelperTest extends \PHPUnit_Framework_TestCase ); $this->setEnv($paths); - $this->assertContains('does not exist', IniHelper::getMessage()); + $this->assertContains('multiple ini files', IniHelper::getMessage()); $this->assertEquals($paths, IniHelper::getAll()); }