From e085a72f6450a83d173f0eaa7399158a7f5fd686 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Thu, 31 Jan 2019 11:20:17 +0000 Subject: [PATCH 001/101] Fix mode bitmask when detecting a Windows junction --- src/Composer/Util/Filesystem.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index ebb7dfbd3..3a8f523fc 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -648,6 +648,10 @@ class Filesystem /** * Returns whether the target directory is a Windows NTFS Junction. * + * We test if the path is a directory and not an ordinary link, then check + * that the mode value returned from lstat (which gives the status of the + * link itself) is not a directory. + * * @param string $junction Path to check. * @return bool */ @@ -659,22 +663,14 @@ class Filesystem if (!is_dir($junction) || is_link($junction)) { return false; } - /** - * According to MSDN at https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx we can detect a junction now - * using the 'mode' value from stat: "The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit - * is set if path specifies an ordinary file or a device." We have just tested for a directory above, so if - * we have a directory that isn't one according to lstat(...) we must have a junction. - * - * #define _S_IFDIR 0x4000 - * #define _S_IFREG 0x8000 - * - * Stat cache should be cleared before to avoid accidentally reading wrong information from previous installs. - */ + + // Important to clear cache first clearstatcache(true, $junction); clearstatcache(false); $stat = lstat($junction); - return !($stat['mode'] & 0xC000); + // S_IFDIR is 0x4000, S_IFMT is the 0xF000 bitmask + return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false; } /** From da0dc74414fd8e6eca65619a6d9c1dd1a04facc6 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Sun, 10 Feb 2019 14:41:20 +0000 Subject: [PATCH 002/101] Update doc block, remove redundant clearstatcache --- src/Composer/Util/Filesystem.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 3a8f523fc..2ebc434b7 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -652,6 +652,11 @@ class Filesystem * that the mode value returned from lstat (which gives the status of the * link itself) is not a directory. * + * This relies on the fact that PHP does not set this value because there is + * no universal file type flag for a junction or a mount point. However a + * bug in PHP can cause a random value to be returned and this could result + * in a junction not being detected: https://bugs.php.net/bug.php?id=77552 + * * @param string $junction Path to check. * @return bool */ @@ -664,9 +669,8 @@ class Filesystem return false; } - // Important to clear cache first + // Important to clear all caches first clearstatcache(true, $junction); - clearstatcache(false); $stat = lstat($junction); // S_IFDIR is 0x4000, S_IFMT is the 0xF000 bitmask From a5cd912c02b94e8f5c97a0506eda456d47286a37 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 Feb 2019 10:51:32 +0100 Subject: [PATCH 003/101] Update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db9890bda..36ceddfc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### [1.8.4] 2019-02-11 + + * Fixed long standing solver bug leading to odd solving issues in edge cases, see #7946 + * Fixed HHVM support for upcoming releases + * Fixed unix proxy for binaries to be POSIX compatible instead of breaking some shells + * Fixed invalid deprecation warning for composer-plugin-api + * Fixed edge case issues with Windows junctions when working with path repositories + ### [1.8.3] 2019-01-30 * Fixed regression when executing partial updates @@ -729,6 +737,10 @@ * Initial release +[1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4 +[1.8.3]: https://github.com/composer/composer/compare/1.8.2...1.8.3 +[1.8.2]: https://github.com/composer/composer/compare/1.8.1...1.8.2 +[1.8.1]: https://github.com/composer/composer/compare/1.8.0...1.8.1 [1.8.0]: https://github.com/composer/composer/compare/1.7.3...1.8.0 [1.7.3]: https://github.com/composer/composer/compare/1.7.2...1.7.3 [1.7.2]: https://github.com/composer/composer/compare/1.7.1...1.7.2 From c903a63f100cd6a5afbbcbdca4bb8fceae2261fd Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Mon, 28 Jan 2019 21:18:26 +0000 Subject: [PATCH 004/101] Update appveyor to PHP 7.3 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e7c20c9e6..cb0f3d33c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ clone_depth: 5 environment: # This sets the PHP version (from Chocolatey) - PHPCI_CHOCO_VERSION: 7.2.9 + PHPCI_CHOCO_VERSION: 7.3.1 PHPCI_CACHE: C:\tools\phpci PHPCI_PHP: C:\tools\phpci\php PHPCI_COMPOSER: C:\tools\phpci\composer From d1cf69fa922d6a46cad283e9d347761175ee0b0a Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Sun, 10 Feb 2019 19:04:58 +0000 Subject: [PATCH 005/101] Remove junctions with PHP rather than system rmdir PHP will happily remove junctions using its `rmdir` function (tested on versions back to 5.2.17). This saves invoking system `rmdir` through cmd.exe. --- src/Composer/Util/Filesystem.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 2ebc434b7..8b0546f3a 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -692,9 +692,7 @@ class Filesystem if (!$this->isJunction($junction)) { throw new IOException(sprintf('%s is not a junction and thus cannot be removed as one', $junction)); } - $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape($junction)); - clearstatcache(true, $junction); - return ($this->getProcess()->execute($cmd, $output) === 0); + return $this->rmdir($junction); } } From 6212eadcb07349ed946fc8e9a7698f49d20084b7 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Mon, 11 Feb 2019 21:30:56 +0000 Subject: [PATCH 006/101] Only use junctions if they can be safely removed --- src/Composer/Downloader/PathDownloader.php | 30 ++++++++++++++++++++++ src/Composer/Util/Filesystem.php | 17 +++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php index e7084bd97..a63a3d82d 100644 --- a/src/Composer/Downloader/PathDownloader.php +++ b/src/Composer/Downloader/PathDownloader.php @@ -82,6 +82,12 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter $allowedStrategies = array(self::STRATEGY_MIRROR); } + // Check we can use junctions safely if we are on Windows + if (Platform::isWindows() && self::STRATEGY_SYMLINK === $currentStrategy && !$this->safeJunctions()) { + $currentStrategy = self::STRATEGY_MIRROR; + $allowedStrategies = array(self::STRATEGY_MIRROR); + } + $fileSystem = new Filesystem(); $this->filesystem->removeDirectory($path); @@ -172,4 +178,28 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter return $packageVersion['commit']; } } + + /** + * Returns true if junctions can be safely used on Windows + * + * A PHP bug makes junction detection fragile, leading to possible data loss + * when removing a package. See https://bugs.php.net/bug.php?id=77552 + * + * For safety we require a minimum version of Windows 7, so we can call the + * system rmdir which can detect junctions and not delete target content. + * + * @return bool + */ + private function safeJunctions() + { + // Bug fixed in 7.3.3 and 7.2.16 + if (PHP_VERSION_ID >= 70303 || (PHP_VERSION_ID >= 70216 && PHP_VERSION_ID < 70300)) { + return true; + } + + // Windows 7 is version 6.1 + return function_exists('proc_open') && + (PHP_WINDOWS_VERSION_MAJOR > 6 || + (PHP_WINDOWS_VERSION_MAJOR === 6 && PHP_WINDOWS_VERSION_MINOR >= 1)); + } } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 8b0546f3a..c4e1b1b12 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -650,12 +650,17 @@ class Filesystem * * We test if the path is a directory and not an ordinary link, then check * that the mode value returned from lstat (which gives the status of the - * link itself) is not a directory. + * link itself) is not a directory, by replicating the POSIX S_ISDIR test. * - * This relies on the fact that PHP does not set this value because there is - * no universal file type flag for a junction or a mount point. However a - * bug in PHP can cause a random value to be returned and this could result - * in a junction not being detected: https://bugs.php.net/bug.php?id=77552 + * This logic works because PHP does not set the mode value for a junction, + * since there is no universal file type flag for it. Unfortunately an + * uninitialized variable in PHP prior to 7.2.16 and 7.3.3 may cause a + * random value to be returned. See https://bugs.php.net/bug.php?id=77552 + * + * If this random value passes the S_ISDIR test, then a junction will not be + * detected and a recursive delete operation could lead to loss of data in + * the target directory. Note that Windows rmdir can handle this situation + * and will only delete the junction (from Windows 7 onwards). * * @param string $junction Path to check. * @return bool @@ -673,7 +678,7 @@ class Filesystem clearstatcache(true, $junction); $stat = lstat($junction); - // S_IFDIR is 0x4000, S_IFMT is the 0xF000 bitmask + // S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask) return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false; } From ae9ed20812a2f0d6b2959dc882fcee26746bd361 Mon Sep 17 00:00:00 2001 From: John Stevenson Date: Tue, 12 Feb 2019 12:09:25 +0000 Subject: [PATCH 007/101] Update 05-repositories.md --- doc/05-repositories.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 9cd1dbf28..ba5713aed 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -666,6 +666,10 @@ Instead of default fallback strategy you can force to use symlink with mirroring can be useful when deploying or generating package from a monolithic repository. +> **Note:** On Windows, directory symlinks are implemented using NTFS junctions +> because they can be created by non-admin users. Mirroring will always be used +> on versions below Windows 7 or if `proc_open` has been disabled. + ```json { "repositories": [ From fc2c445c063cc71eafc945e6a19125215b0acb00 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 12 Feb 2019 11:54:23 +0100 Subject: [PATCH 008/101] Make sure we properly usleep() on windows rmdir/unlink usleep() returns void, therefore the previous code didn't work --- src/Composer/Util/Filesystem.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index c4e1b1b12..7c342573b 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -199,9 +199,15 @@ class Filesystem */ public function unlink($path) { - if (!@$this->unlinkImplementation($path)) { + $unlinked = @$this->unlinkImplementation($path); + if (!$unlinked) { // retry after a bit on windows since it tends to be touchy with mass removals - if (!Platform::isWindows() || (usleep(350000) && !@$this->unlinkImplementation($path))) { + if (Platform::isWindows()) { + usleep(350000); + $unlinked = @$this->unlinkImplementation($path); + } + + if (!$unlinked) { $error = error_get_last(); $message = 'Could not delete '.$path.': ' . @$error['message']; if (Platform::isWindows()) { @@ -224,9 +230,15 @@ class Filesystem */ public function rmdir($path) { - if (!@rmdir($path)) { + $deleted = @rmdir($path); + if (!$deleted) { // retry after a bit on windows since it tends to be touchy with mass removals - if (!Platform::isWindows() || (usleep(350000) && !@rmdir($path))) { + if (Platform::isWindows()) { + usleep(350000); + $deleted = !@rmdir($path); + } + + if (!$deleted) { $error = error_get_last(); $message = 'Could not delete '.$path.': ' . @$error['message']; if (Platform::isWindows()) { From 4cf069535fca7ab64fdfeb6d281e2c98e6f8e259 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Tue, 12 Feb 2019 15:05:37 +0000 Subject: [PATCH 009/101] Improve safe junction logic --- src/Composer/Downloader/PathDownloader.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php index a63a3d82d..4c71fb4f4 100644 --- a/src/Composer/Downloader/PathDownloader.php +++ b/src/Composer/Downloader/PathDownloader.php @@ -180,24 +180,21 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter } /** - * Returns true if junctions can be safely used on Windows + * Returns true if junctions can be created and safely used on Windows * * A PHP bug makes junction detection fragile, leading to possible data loss * when removing a package. See https://bugs.php.net/bug.php?id=77552 * * For safety we require a minimum version of Windows 7, so we can call the - * system rmdir which can detect junctions and not delete target content. + * system rmdir which will preserve target content if given a junction. + * + * The PHP bug was fixed in 7.2.16 and 7.3.3 (requires at least Windows 7). * * @return bool */ private function safeJunctions() { - // Bug fixed in 7.3.3 and 7.2.16 - if (PHP_VERSION_ID >= 70303 || (PHP_VERSION_ID >= 70216 && PHP_VERSION_ID < 70300)) { - return true; - } - - // Windows 7 is version 6.1 + // We need to call mklink, and rmdir on Windows 7 (version 6.1) return function_exists('proc_open') && (PHP_WINDOWS_VERSION_MAJOR > 6 || (PHP_WINDOWS_VERSION_MAJOR === 6 && PHP_WINDOWS_VERSION_MINOR >= 1)); From 0aa030f09d3fb47b708e39cffeb7470099010f0c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 13 Feb 2019 07:26:14 +0100 Subject: [PATCH 010/101] Fixed typo introduced in recent fix --- src/Composer/Util/Filesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 7c342573b..1903f1c8d 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -235,7 +235,7 @@ class Filesystem // retry after a bit on windows since it tends to be touchy with mass removals if (Platform::isWindows()) { usleep(350000); - $deleted = !@rmdir($path); + $deleted = @rmdir($path); } if (!$deleted) { From d9f873d00e6670f6802441e21538e0e4704128a2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 16 Feb 2019 17:39:59 +0100 Subject: [PATCH 011/101] Abort when HHVM 4.0 is detected to output a clear user message, refs #7990 --- bin/composer | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/composer b/bin/composer index 5e142662c..3585787f2 100755 --- a/bin/composer +++ b/bin/composer @@ -18,6 +18,11 @@ $xdebug = new XdebugHandler('Composer', '--ansi'); $xdebug->check(); unset($xdebug); +if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '4.0', '>=')) { + echo 'HHVM 4.0 has dropped support for Composer, please use PHP instead. Aborting.'.PHP_EOL; + exit(1); +} + if (function_exists('ini_set')) { @ini_set('display_errors', 1); From 0fd74d1cc43ce7bedfc21e473ea4b44e9b3a2503 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 12:28:21 +0100 Subject: [PATCH 012/101] Fix PerforceDownloader, fixes #7979 --- src/Composer/Downloader/PerforceDownloader.php | 2 +- tests/Composer/Test/Downloader/PerforceDownloaderTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php index df270417f..a7dc013b3 100644 --- a/src/Composer/Downloader/PerforceDownloader.php +++ b/src/Composer/Downloader/PerforceDownloader.php @@ -78,7 +78,7 @@ class PerforceDownloader extends VcsDownloader */ public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url) { - $this->doDownload($target, $path, $url); + $this->doInstall($target, $path, $url); } /** diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index d2b8fb753..77a61f9cf 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -121,7 +121,7 @@ class PerforceDownloaderTest extends TestCase * @depends testInitPerforceInstantiatesANewPerforceObject * @depends testInitPerforceDoesNothingIfPerforceAlreadySet */ - public function testDoDownloadWithTag() + public function testDoInstallWithTag() { //I really don't like this test but the logic of each Perforce method is tested in the Perforce class. Really I am just enforcing workflow. $ref = 'SOURCE_REF@123'; @@ -145,7 +145,7 @@ class PerforceDownloaderTest extends TestCase * @depends testInitPerforceInstantiatesANewPerforceObject * @depends testInitPerforceDoesNothingIfPerforceAlreadySet */ - public function testDoDownloadWithNoTag() + public function testDoInstallWithNoTag() { $ref = 'SOURCE_REF'; $label = null; From fb3d0981c04570d283485da984f4d4d96a998b78 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 12:35:24 +0100 Subject: [PATCH 013/101] Fix test suite --- tests/Composer/Test/DependencyResolver/SolverTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index b80e7c61d..e50927fe2 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -899,6 +899,8 @@ class SolverTest extends TestCase $this->request->install('A'); + $this->createSolver(); + // check correct setup for assertion later $this->assertFalse($this->solver->testFlagLearnedPositiveLiteral); From a062cd1a31f05dd5b87f761f1784dec4775f7306 Mon Sep 17 00:00:00 2001 From: CZechBoY Date: Mon, 7 Jan 2019 16:22:41 +0100 Subject: [PATCH 014/101] added phpstan on level 0 --- .travis.yml | 12 +++++- phpstan/autoload.php | 5 +++ phpstan/config.neon | 38 +++++++++++++++++++ .../DependencyResolver/PoolBuilder.php | 6 +-- src/Composer/Downloader/GzipDownloader.php | 1 + src/Composer/Downloader/RarDownloader.php | 1 + src/Composer/Downloader/XzDownloader.php | 1 + src/Composer/Downloader/ZipDownloader.php | 2 + src/Composer/Package/Locker.php | 8 ++++ .../Package/Version/VersionGuesser.php | 1 + src/Composer/Util/Bitbucket.php | 6 +++ src/Composer/Util/Filesystem.php | 4 ++ src/Composer/Util/GitHub.php | 4 ++ src/Composer/Util/GitLab.php | 4 ++ src/Composer/Util/Loop.php | 2 +- src/Composer/Util/StreamContextFactory.php | 1 + .../Test/Downloader/FileDownloaderTest.php | 2 + .../Test/Downloader/ZipDownloaderTest.php | 2 +- 18 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 phpstan/autoload.php create mode 100644 phpstan/config.neon diff --git a/.travis.yml b/.travis.yml index f02fefcb1..1140053c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,15 @@ matrix: - php: 5.6 - php: 7.0 - php: 7.1 + env: PHPSTAN=1 - php: 7.2 + env: PHPSTAN=1 - php: 7.3 + env: PHPSTAN=1 - php: 7.3 - env: deps=high + env: + - deps=high + - PHPSTAN=1 - php: nightly fast_finish: true allow_failures: @@ -58,6 +63,11 @@ before_script: script: # run test suite directories in parallel using GNU parallel - ls -d tests/Composer/Test/* | grep -v TestCase.php | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml --colors=always {} || (echo -e "\e[41mFAILED\e[0m {}" && exit 1);' + # Run PHPStan + - if [[ $PHPSTAN == "1" ]]; then + composer require --dev phpstan/phpstan-shim:^0.11 --ignore-platform-reqs && + vendor/bin/phpstan.phar analyse src tests --configuration=phpstan/config.neon --autoload-file=phpstan/autoload.php; + fi before_deploy: - php -d phar.readonly=0 bin/compile diff --git a/phpstan/autoload.php b/phpstan/autoload.php new file mode 100644 index 000000000..7d1ed7671 --- /dev/null +++ b/phpstan/autoload.php @@ -0,0 +1,5 @@ +pool = new Pool($this->filterRequires); + $pool = new Pool($this->filterRequires); $this->rootAliases = $rootAliases; // TODO do we really want the request here? kind of want a root requirements thingy instead @@ -133,13 +133,13 @@ class PoolBuilder } } - $this->pool->setPackages($this->packages, $this->priorities); + $pool->setPackages($this->packages, $this->priorities); unset($this->aliasMap); unset($this->loadedNames); unset($this->nameConstraints); - return $this->pool; + return $pool; } private function loadPackage(PackageInterface $package, $repoIndex) diff --git a/src/Composer/Downloader/GzipDownloader.php b/src/Composer/Downloader/GzipDownloader.php index 9748b91ac..91be4593d 100644 --- a/src/Composer/Downloader/GzipDownloader.php +++ b/src/Composer/Downloader/GzipDownloader.php @@ -28,6 +28,7 @@ use Composer\IO\IOInterface; */ class GzipDownloader extends ArchiveDownloader { + /** @var ProcessExecutor */ protected $process; public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null) diff --git a/src/Composer/Downloader/RarDownloader.php b/src/Composer/Downloader/RarDownloader.php index 2ebc3bf18..d0fbadcc6 100644 --- a/src/Composer/Downloader/RarDownloader.php +++ b/src/Composer/Downloader/RarDownloader.php @@ -32,6 +32,7 @@ use RarArchive; */ class RarDownloader extends ArchiveDownloader { + /** @var ProcessExecutor */ protected $process; public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null) diff --git a/src/Composer/Downloader/XzDownloader.php b/src/Composer/Downloader/XzDownloader.php index 19e51c321..371ceda1b 100644 --- a/src/Composer/Downloader/XzDownloader.php +++ b/src/Composer/Downloader/XzDownloader.php @@ -28,6 +28,7 @@ use Composer\IO\IOInterface; */ class XzDownloader extends ArchiveDownloader { + /** @var ProcessExecutor */ protected $process; public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null) diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index efa9fc994..bd8d3b499 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -33,7 +33,9 @@ class ZipDownloader extends ArchiveDownloader private static $hasZipArchive; private static $isWindows; + /** @var ProcessExecutor */ protected $process; + /** @var ZipArchive|null */ private $zipArchiveObject; public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null) diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 405d43261..68540581c 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -31,13 +31,21 @@ use Seld\JsonLint\ParsingException; */ class Locker { + /** @var JsonFile */ private $lockFile; + /** @var RepositoryManager */ private $repositoryManager; + /** @var InstallationManager */ private $installationManager; + /** @var string */ private $hash; + /** @var string */ private $contentHash; + /** @var ArrayLoader */ private $loader; + /** @var ArrayDumper */ private $dumper; + /** @var ProcessExecutor */ private $process; private $lockDataCache; diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index 1c2fdf986..d655bc080 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -17,6 +17,7 @@ use Composer\Repository\Vcs\HgDriver; use Composer\IO\NullIO; use Composer\Semver\VersionParser as SemverVersionParser; use Composer\Util\Git as GitUtil; +use Composer\Util\HttpDownloader; use Composer\Util\ProcessExecutor; use Composer\Util\Svn as SvnUtil; diff --git a/src/Composer/Util/Bitbucket.php b/src/Composer/Util/Bitbucket.php index d9f569b1b..ea02dfa0b 100644 --- a/src/Composer/Util/Bitbucket.php +++ b/src/Composer/Util/Bitbucket.php @@ -22,11 +22,17 @@ use Composer\Downloader\TransportException; */ class Bitbucket { + /** @var IOInterface */ private $io; + /** @var Config */ private $config; + /** @var ProcessExecutor */ private $process; + /** @var HttpDownloader */ private $httpDownloader; + /** @var array */ private $token = array(); + /** @var int|null */ private $time; const OAUTH2_ACCESS_TOKEN_URL = 'https://bitbucket.org/site/oauth2/access_token'; diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 1903f1c8d..805eda14b 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -23,6 +23,7 @@ use Symfony\Component\Finder\Finder; */ class Filesystem { + /** @var ProcessExecutor */ private $processExecutor; public function __construct(ProcessExecutor $executor = null) @@ -537,6 +538,9 @@ class Filesystem return $size; } + /** + * @return ProcessExecutor + */ protected function getProcess() { return $this->processExecutor; diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php index c3046cb77..d6bfb62ca 100644 --- a/src/Composer/Util/GitHub.php +++ b/src/Composer/Util/GitHub.php @@ -22,9 +22,13 @@ use Composer\Downloader\TransportException; */ class GitHub { + /** @var IOInterface */ protected $io; + /** @var Config */ protected $config; + /** @var ProcessExecutor */ protected $process; + /** @var HttpDownloader */ protected $httpDownloader; /** diff --git a/src/Composer/Util/GitLab.php b/src/Composer/Util/GitLab.php index 2a4867954..b2dbf2836 100644 --- a/src/Composer/Util/GitLab.php +++ b/src/Composer/Util/GitLab.php @@ -23,9 +23,13 @@ use Composer\Json\JsonFile; */ class GitLab { + /** @var IOInterface */ protected $io; + /** @var Config */ protected $config; + /** @var ProcessExecutor */ protected $process; + /** @var HttpDownloader */ protected $httpDownloader; /** diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php index 1be7d478b..c50cf4b02 100644 --- a/src/Composer/Util/Loop.php +++ b/src/Composer/Util/Loop.php @@ -20,7 +20,7 @@ use React\Promise\Promise; */ class Loop { - private $io; + private $httpDownloader; public function __construct(HttpDownloader $httpDownloader) { diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index a87bc6d8b..f39c6dd38 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -14,6 +14,7 @@ namespace Composer\Util; use Composer\Composer; use Composer\CaBundle\CaBundle; +use Composer\Downloader\TransportException; use Psr\Log\LoggerInterface; /** diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php index 10ea401a8..89c538eab 100644 --- a/tests/Composer/Test/Downloader/FileDownloaderTest.php +++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php @@ -20,6 +20,8 @@ use Composer\Util\Loop; class FileDownloaderTest extends TestCase { + private $httpDownloader; + protected function getDownloader($io = null, $config = null, $eventDispatcher = null, $cache = null, $httpDownloader = null, $filesystem = null) { $io = $io ?: $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php index b754af607..e69149271 100644 --- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php @@ -25,7 +25,7 @@ class ZipDownloaderTest extends TestCase * @var string */ private $testDir; - private $prophet; + private $httpDownloader; private $io; private $config; private $package; From 799717f102ec64482d2aaaa5fef58bd86952e9ad Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 13:03:34 +0100 Subject: [PATCH 015/101] Tweak and fix some more phpstan reports --- phpstan/config.neon | 6 ++++-- .../Test/DependencyResolver/SolverTest.php | 2 +- .../Test/Downloader/PerforceDownloaderTest.php | 4 ++-- .../Test/Repository/Vcs/PerforceDriverTest.php | 2 +- .../Test/Repository/VcsRepositoryTest.php | 15 +++++++++------ 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/phpstan/config.neon b/phpstan/config.neon index 5f77d5cd1..7c0122f9a 100644 --- a/phpstan/config.neon +++ b/phpstan/config.neon @@ -29,9 +29,11 @@ parameters: - '~^Undefined variable: \$vendorDir$~' - '~^Undefined variable: \$baseDir$~' + # variable defined in eval + - '~^Undefined variable: \$res$~' + # always checked whether the class exists - - '~^Instantiated class Symfony\\Component\\Console\\Terminal not found\.$~' - - '~^Class Symfony\\Component\\Console\\Input\\StreamableInputInterface not found\.$~' + - '~^Call to an undefined static method Symfony\\Component\\Process\\Process::fromShellCommandline\(\).$~' # parent call in test mocks - '~^Composer\\Test\\Mock\\HttpDownloaderMock::__construct\(\) does not call parent constructor from Composer\\Util\\HttpDownloader\.$~' diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index e50927fe2..95696e610 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -40,7 +40,7 @@ class SolverTest extends TestCase $this->repo = new ArrayRepository; $this->repoInstalled = new InstalledArrayRepository; - $this->request = new Request($this->repoSet); + $this->request = new Request(); $this->policy = new DefaultPolicy; } diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index 77a61f9cf..b6347789b 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -129,7 +129,7 @@ class PerforceDownloaderTest extends TestCase $this->package->expects($this->once())->method('getSourceReference')->will($this->returnValue($ref)); $this->io->expects($this->once())->method('writeError')->with($this->stringContains('Cloning '.$ref)); $perforceMethods = array('setStream', 'p4Login', 'writeP4ClientSpec', 'connectClient', 'syncCodeBase', 'cleanupClientSpec'); - $perforce = $this->getMockBuilder('Composer\Util\Perforce', $perforceMethods)->disableOriginalConstructor()->getMock(); + $perforce = $this->getMockBuilder('Composer\Util\Perforce')->disableOriginalConstructor()->getMock(); $perforce->expects($this->at(0))->method('initializePath')->with($this->equalTo($this->testPath)); $perforce->expects($this->at(1))->method('setStream')->with($this->equalTo($ref)); $perforce->expects($this->at(2))->method('p4Login'); @@ -152,7 +152,7 @@ class PerforceDownloaderTest extends TestCase $this->package->expects($this->once())->method('getSourceReference')->will($this->returnValue($ref)); $this->io->expects($this->once())->method('writeError')->with($this->stringContains('Cloning '.$ref)); $perforceMethods = array('setStream', 'p4Login', 'writeP4ClientSpec', 'connectClient', 'syncCodeBase', 'cleanupClientSpec'); - $perforce = $this->getMockBuilder('Composer\Util\Perforce', $perforceMethods)->disableOriginalConstructor()->getMock(); + $perforce = $this->getMockBuilder('Composer\Util\Perforce')->disableOriginalConstructor()->getMock(); $perforce->expects($this->at(0))->method('initializePath')->with($this->equalTo($this->testPath)); $perforce->expects($this->at(1))->method('setStream')->with($this->equalTo($ref)); $perforce->expects($this->at(2))->method('p4Login'); diff --git a/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php b/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php index ff4e19121..1c44e82dd 100644 --- a/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php @@ -108,7 +108,7 @@ class PerforceDriverTest extends TestCase { $methods = array('p4login', 'checkStream', 'writeP4ClientSpec', 'connectClient', 'getComposerInformation', 'cleanupClientSpec'); - return $this->getMockBuilder('Composer\Util\Perforce', $methods)->disableOriginalConstructor()->getMock(); + return $this->getMockBuilder('Composer\Util\Perforce')->disableOriginalConstructor()->getMock(); } public function testInitializeCapturesVariablesFromRepoConfig() diff --git a/tests/Composer/Test/Repository/VcsRepositoryTest.php b/tests/Composer/Test/Repository/VcsRepositoryTest.php index 0cab2f8bb..65bf52409 100644 --- a/tests/Composer/Test/Repository/VcsRepositoryTest.php +++ b/tests/Composer/Test/Repository/VcsRepositoryTest.php @@ -32,17 +32,18 @@ class VcsRepositoryTest extends TestCase protected function initialize() { - $oldCwd = getcwd(); - self::$composerHome = $this->getUniqueTmpDirectory(); - self::$gitRepo = $this->getUniqueTmpDirectory(); - $locator = new ExecutableFinder(); if (!$locator->find('git')) { $this->skipped = 'This test needs a git binary in the PATH to be able to run'; return; } - if (!@mkdir(self::$gitRepo) || !@chdir(self::$gitRepo)) { + + $oldCwd = getcwd(); + self::$composerHome = $this->getUniqueTmpDirectory(); + self::$gitRepo = $this->getUniqueTmpDirectory(); + + if (!@chdir(self::$gitRepo)) { $this->skipped = 'Could not create and move into the temp git repo '.self::$gitRepo; return; @@ -60,6 +61,7 @@ class VcsRepositoryTest extends TestCase $exec('git init'); $exec('git config user.email composertest@example.org'); $exec('git config user.name ComposerTest'); + $exec('git config commit.gpgsign false'); touch('foo'); $exec('git add foo'); $exec('git commit -m init'); @@ -150,7 +152,8 @@ class VcsRepositoryTest extends TestCase 'home' => self::$composerHome, ), )); - $repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO, $config); + $httpDownloader = $this->getMockBuilder('Composer\Util\HttpDownloader')->disableOriginalConstructor()->getMock(); + $repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO, $config, $httpDownloader); $packages = $repo->getPackages(); $dumper = new ArrayDumper(); From 2c520bf93b985a33ab7c5f3ca281142ea00ca256 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 13:37:30 +0100 Subject: [PATCH 016/101] Fix build --- phpstan/config.neon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpstan/config.neon b/phpstan/config.neon index 7c0122f9a..9fd155963 100644 --- a/phpstan/config.neon +++ b/phpstan/config.neon @@ -33,6 +33,8 @@ parameters: - '~^Undefined variable: \$res$~' # always checked whether the class exists + - '~^Instantiated class Symfony\\Component\\Console\\Terminal not found\.$~' + - '~^Class Symfony\\Component\\Console\\Input\\StreamableInputInterface not found\.$~' - '~^Call to an undefined static method Symfony\\Component\\Process\\Process::fromShellCommandline\(\).$~' # parent call in test mocks From 9da40b3c2c000ce36ddb74b9afd80e8ab77333d4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 13:56:08 +0100 Subject: [PATCH 017/101] Only run phpstan once --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1140053c0..a06922904 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,15 +23,12 @@ matrix: - php: 5.6 - php: 7.0 - php: 7.1 - env: PHPSTAN=1 - php: 7.2 - env: PHPSTAN=1 - php: 7.3 env: PHPSTAN=1 - php: 7.3 env: - deps=high - - PHPSTAN=1 - php: nightly fast_finish: true allow_failures: From 0caa616e6c498e0ffb4a6363d0ee695698956068 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 14:03:23 +0100 Subject: [PATCH 018/101] Fix test warnings --- tests/Composer/Test/ApplicationTest.php | 2 +- tests/Composer/Test/CacheTest.php | 6 ++++-- .../Test/Downloader/FileDownloaderTest.php | 8 ++++---- .../Test/Downloader/GitDownloaderTest.php | 16 ++++++++-------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index 8739a5004..39d462544 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -47,7 +47,7 @@ class ApplicationTest extends TestCase $index = 0; $outputMock->expects($this->at($index++)) - ->method("writeError"); + ->method("write"); if (extension_loaded('xdebug')) { $outputMock->expects($this->at($index++)) diff --git a/tests/Composer/Test/CacheTest.php b/tests/Composer/Test/CacheTest.php index 50c767752..a8d3eae4a 100644 --- a/tests/Composer/Test/CacheTest.php +++ b/tests/Composer/Test/CacheTest.php @@ -20,6 +20,7 @@ class CacheTest extends TestCase private $files; private $root; private $finder; + private $filesystem; private $cache; public function setUp() @@ -34,11 +35,12 @@ class CacheTest extends TestCase } $this->finder = $this->getMockBuilder('Symfony\Component\Finder\Finder')->disableOriginalConstructor()->getMock(); + $this->filesystem = $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $this->cache = $this->getMockBuilder('Composer\Cache') ->setMethods(array('getFinder')) - ->setConstructorArgs(array($io, $this->root)) + ->setConstructorArgs(array($io, $this->root, 'a-z0-9.', $this->filesystem)) ->getMock(); $this->cache ->expects($this->any()) @@ -105,7 +107,7 @@ class CacheTest extends TestCase public function testClearCache() { - $this->finder + $this->filesystem ->method('removeDirectory') ->with($this->root) ->willReturn(true); diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php index 89c538eab..7c4259ca3 100644 --- a/tests/Composer/Test/Downloader/FileDownloaderTest.php +++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php @@ -223,7 +223,7 @@ class FileDownloaderTest extends TestCase public function testDowngradeShowsAppropriateMessage() { - $oldPackage = $this->getMock('Composer\Package\PackageInterface'); + $oldPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $oldPackage->expects($this->any()) ->method('getFullPrettyVersion') ->will($this->returnValue('1.2.0')); @@ -231,7 +231,7 @@ class FileDownloaderTest extends TestCase ->method('getVersion') ->will($this->returnValue('1.2.0.0')); - $newPackage = $this->getMock('Composer\Package\PackageInterface'); + $newPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $newPackage->expects($this->any()) ->method('getFullPrettyVersion') ->will($this->returnValue('1.0.0')); @@ -245,7 +245,7 @@ class FileDownloaderTest extends TestCase ->method('getDistUrls') ->will($this->returnValue(array($distUrl))); - $ioMock = $this->getMock('Composer\IO\IOInterface'); + $ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $ioMock->expects($this->at(0)) ->method('writeError') ->with($this->stringContains('Downloading')); @@ -256,7 +256,7 @@ class FileDownloaderTest extends TestCase $path = $this->getUniqueTmpDirectory(); touch($path.'_script.js'); - $filesystem = $this->getMock('Composer\Util\Filesystem'); + $filesystem = $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $filesystem->expects($this->once()) ->method('removeDirectory') ->will($this->returnValue(true)); diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index b5d0054de..b9a85a666 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -604,7 +604,7 @@ composer https://github.com/old/url (push) public function testDowngradeShowsAppropriateMessage() { - $oldPackage = $this->getMock('Composer\Package\PackageInterface'); + $oldPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $oldPackage->expects($this->any()) ->method('getVersion') ->will($this->returnValue('1.2.0.0')); @@ -618,7 +618,7 @@ composer https://github.com/old/url (push) ->method('getSourceUrls') ->will($this->returnValue(array('/foo/bar', 'https://github.com/composer/composer'))); - $newPackage = $this->getMock('Composer\Package\PackageInterface'); + $newPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $newPackage->expects($this->any()) ->method('getSourceReference') ->will($this->returnValue('ref')); @@ -632,12 +632,12 @@ composer https://github.com/old/url (push) ->method('getFullPrettyVersion') ->will($this->returnValue('1.0.0')); - $processExecutor = $this->getMock('Composer\Util\ProcessExecutor'); + $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor->expects($this->any()) ->method('execute') ->will($this->returnValue(0)); - $ioMock = $this->getMock('Composer\IO\IOInterface'); + $ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $ioMock->expects($this->at(0)) ->method('writeError') ->with($this->stringContains('Downgrading')); @@ -649,7 +649,7 @@ composer https://github.com/old/url (push) public function testNotUsingDowngradingWithReferences() { - $oldPackage = $this->getMock('Composer\Package\PackageInterface'); + $oldPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $oldPackage->expects($this->any()) ->method('getVersion') ->will($this->returnValue('dev-ref')); @@ -660,7 +660,7 @@ composer https://github.com/old/url (push) ->method('getSourceUrls') ->will($this->returnValue(array('/foo/bar', 'https://github.com/composer/composer'))); - $newPackage = $this->getMock('Composer\Package\PackageInterface'); + $newPackage = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $newPackage->expects($this->any()) ->method('getSourceReference') ->will($this->returnValue('ref')); @@ -671,12 +671,12 @@ composer https://github.com/old/url (push) ->method('getVersion') ->will($this->returnValue('dev-ref2')); - $processExecutor = $this->getMock('Composer\Util\ProcessExecutor'); + $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor->expects($this->any()) ->method('execute') ->will($this->returnValue(0)); - $ioMock = $this->getMock('Composer\IO\IOInterface'); + $ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $ioMock->expects($this->at(0)) ->method('writeError') ->with($this->stringContains('updating')); From 936933fa66e70795e8d4ddb0372e1720fdd9c90a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 14:12:01 +0100 Subject: [PATCH 019/101] Fix cache tests --- tests/Composer/Test/CacheTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Composer/Test/CacheTest.php b/tests/Composer/Test/CacheTest.php index a8d3eae4a..1c4c67c98 100644 --- a/tests/Composer/Test/CacheTest.php +++ b/tests/Composer/Test/CacheTest.php @@ -13,6 +13,7 @@ namespace Composer\Test; use Composer\Test\TestCase; +use Composer\Cache; use Composer\Util\Filesystem; class CacheTest extends TestCase @@ -40,7 +41,7 @@ class CacheTest extends TestCase $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $this->cache = $this->getMockBuilder('Composer\Cache') ->setMethods(array('getFinder')) - ->setConstructorArgs(array($io, $this->root, 'a-z0-9.', $this->filesystem)) + ->setConstructorArgs(array($io, $this->root)) ->getMock(); $this->cache ->expects($this->any()) @@ -109,13 +110,12 @@ class CacheTest extends TestCase { $this->filesystem ->method('removeDirectory') - ->with($this->root) + ->with($this->root.'/') ->willReturn(true); - $this->assertTrue($this->cache->clear()); + $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); + $this->cache = new Cache($io, $this->root, 'a-z0-9.', $this->filesystem); - for ($i = 0; $i < 3; $i++) { - $this->assertFileNotExists("{$this->root}/cached.file{$i}.zip"); - } + $this->assertTrue($this->cache->clear()); } } From d381b3a781b70e92152e752df3c704e700e6270e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 16:59:09 +0100 Subject: [PATCH 020/101] Fix variable name --- src/Composer/Repository/ComposerRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index bb613497f..d75d02bac 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -313,9 +313,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } } } + + // add aliases of matched packages even if they did not match the constraint foreach ($candidates as $candidate) { if ($candidate instanceof AliasPackage) { - if (isset($result[spl_object_hash($candidate->getAliasOf())])) { + if (isset($matches[spl_object_hash($candidate->getAliasOf())])) { $matches[spl_object_hash($candidate)] = $candidate; } } From 169fb2347ac63cf3a105bd65589fc982577d07e2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 17:00:57 +0100 Subject: [PATCH 021/101] Avoid issues with git signatures when running tests --- .../Test/Package/Archiver/ArchivableFilesFinderTest.php | 1 + tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php index f6afe10f1..cea4088b1 100644 --- a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php @@ -189,6 +189,7 @@ class ArchivableFilesFinderTest extends TestCase 'git init && '. 'git config user.email "you@example.com" && '. 'git config user.name "Your Name" && '. + 'git config commit.gpgsign false && '. 'git add .git* && '. 'git commit -m "ignore rules" && '. 'git add . && '. diff --git a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php index 714c9b923..45a635437 100644 --- a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php @@ -125,6 +125,12 @@ class ArchiveManagerTest extends ArchiverTest throw new \RuntimeException('Could not config: '.$this->process->getErrorOutput()); } + $result = $this->process->execute('git config commit.gpgsign false', $output, $this->testDir); + if ($result > 0) { + chdir($currentWorkDir); + throw new \RuntimeException('Could not config: '.$this->process->getErrorOutput()); + } + $result = $this->process->execute('git config user.name "Your Name"', $output, $this->testDir); if ($result > 0) { chdir($currentWorkDir); From 1b7e957cc1b62ad815dfdd4fab912bd8916e428f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Feb 2019 18:12:38 +0100 Subject: [PATCH 022/101] Add EventDispatcher::removeListener to allow deregistration of listeners --- .../EventDispatcher/EventDispatcher.php | 21 +++++++- .../EventDispatcher/EventDispatcherTest.php | 48 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index c37d7cf45..c24660659 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -46,7 +46,7 @@ class EventDispatcher protected $io; protected $loader; protected $process; - protected $listeners; + protected $listeners = array(); private $eventStack; /** @@ -172,6 +172,9 @@ class EventDispatcher throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public'); } + if (is_array($callable) && (is_string($callable[0]) || is_object($callable[0])) && is_string($callable[1])) { + $this->io->writeError(sprintf('> %s: %s', $event->getName(), (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1] ), true, IOInterface::VERBOSE); + } $event = $this->checkListenerExpectedEvent($callable, $event); $return = false === call_user_func($callable, $event) ? 1 : 0; } elseif ($this->isComposerScript($callable)) { @@ -364,6 +367,22 @@ class EventDispatcher $this->listeners[$eventName][$priority][] = $listener; } + /** + * @param callable|object $listener A callable or an object instance for which all listeners should be removed + */ + public function removeListener($listener) + { + foreach ($this->listeners as $eventName => $priorities) { + foreach ($priorities as $priority => $listeners) { + foreach ($listeners as $index => $candidate) { + if ($listener === $candidate || (is_array($candidate) && is_object($listener) && $candidate[0] === $listener)) { + unset($this->listeners[$eventName][$priority][$index]); + } + } + } + } + } + /** * Adds object methods as listeners for the events in getSubscribedEvents * diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php index 6d812e20a..a41d745ff 100644 --- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php +++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php @@ -171,6 +171,49 @@ class EventDispatcherTest extends TestCase return $rm; } + public function testDispatcherRemoveListener() + { + $composer = $this->createComposerInstance(); + + $composer->setRepositoryManager($this->getRepositoryManagerMockForDevModePassingTest()); + $composer->setInstallationManager($this->getMockBuilder('Composer\Installer\InstallationManager')->disableOriginalConstructor()->getMock()); + + $dispatcher = new EventDispatcher( + $composer, + $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE), + $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock() + ); + + $listener = array($this, 'someMethod'); + $listener2 = array($this, 'someMethod2'); + $listener3 = 'Composer\\Test\\EventDispatcher\\EventDispatcherTest::someMethod'; + + $dispatcher->addListener('ev1', $listener, 0); + $dispatcher->addListener('ev1', $listener, 1); + $dispatcher->addListener('ev1', $listener2, 1); + $dispatcher->addListener('ev1', $listener3); + $dispatcher->addListener('ev2', $listener3); + $dispatcher->addListener('ev2', $listener); + $dispatcher->dispatch('ev1'); + $dispatcher->dispatch('ev2'); + + $expected = '> ev1: Composer\Test\EventDispatcher\EventDispatcherTest->someMethod'.PHP_EOL + .'> ev1: Composer\Test\EventDispatcher\EventDispatcherTest->someMethod2'.PHP_EOL + .'> ev1: Composer\Test\EventDispatcher\EventDispatcherTest->someMethod'.PHP_EOL + .'> ev1: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL + .'> ev2: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL + .'> ev2: Composer\Test\EventDispatcher\EventDispatcherTest->someMethod'.PHP_EOL; + $this->assertEquals($expected, $io->getOutput()); + + $dispatcher->removeListener($this); + $dispatcher->dispatch('ev1'); + $dispatcher->dispatch('ev2'); + + $expected .= '> ev1: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL + .'> ev2: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL; + $this->assertEquals($expected, $io->getOutput()); + } + public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack() { $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); @@ -446,6 +489,11 @@ class EventDispatcherTest extends TestCase return true; } + public static function someMethod2() + { + return true; + } + private function createComposerInstance() { $composer = new Composer; From 6c782599f1e2e4a07a102aa28d5f70d39300bf95 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Feb 2019 10:54:42 +0100 Subject: [PATCH 023/101] Make IOInterface implement psr-4 LoggerInterface, fixes #5180 --- src/Composer/IO/BaseIO.php | 3 +-- src/Composer/IO/IOInterface.php | 3 ++- src/Composer/Util/Http/CurlDownloader.php | 1 - src/Composer/Util/HttpDownloader.php | 4 +--- src/Composer/Util/RemoteFilesystem.php | 4 +--- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Composer/IO/BaseIO.php b/src/Composer/IO/BaseIO.php index b327f1bbf..b63b59484 100644 --- a/src/Composer/IO/BaseIO.php +++ b/src/Composer/IO/BaseIO.php @@ -14,10 +14,9 @@ namespace Composer\IO; use Composer\Config; use Composer\Util\ProcessExecutor; -use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -abstract class BaseIO implements IOInterface, LoggerInterface +abstract class BaseIO implements IOInterface { protected $authentications = array(); diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php index 5766ba479..46302088f 100644 --- a/src/Composer/IO/IOInterface.php +++ b/src/Composer/IO/IOInterface.php @@ -13,13 +13,14 @@ namespace Composer\IO; use Composer\Config; +use Psr\Log\LoggerInterface; /** * The Input/Output helper interface. * * @author François Pluchino */ -interface IOInterface +interface IOInterface extends LoggerInterface { const QUIET = 1; const NORMAL = 2; diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index ff31bf695..ab0dae91e 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -20,7 +20,6 @@ use Composer\Util\RemoteFilesystem; use Composer\Util\StreamContextFactory; use Composer\Util\AuthHelper; use Composer\Util\Url; -use Psr\Log\LoggerInterface; use React\Promise\Promise; /** diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 172ea875a..68e11a4a4 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -17,7 +17,6 @@ use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; use Composer\Util\Http\Response; -use Psr\Log\LoggerInterface; use React\Promise\Promise; /** @@ -58,8 +57,7 @@ class HttpDownloader // Setup TLS options // The cafile option can be set via config.json if ($disableTls === false) { - $logger = $io instanceof LoggerInterface ? $io : null; - $this->options = StreamContextFactory::getTlsDefaults($options, $logger); + $this->options = StreamContextFactory::getTlsDefaults($options, $io); } else { $this->disableTls = true; } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 2709f7006..e2c50472c 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -16,7 +16,6 @@ use Composer\Config; use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; -use Psr\Log\LoggerInterface; /** * @author François Pluchino @@ -61,8 +60,7 @@ class RemoteFilesystem // Setup TLS options // The cafile option can be set via config.json if ($disableTls === false) { - $logger = $io instanceof LoggerInterface ? $io : null; - $this->options = StreamContextFactory::getTlsDefaults($options, $logger); + $this->options = StreamContextFactory::getTlsDefaults($options, $io); } else { $this->disableTls = true; } From ab945a6ec1899d5f5f5f844d39d5e921ddcebccd Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Feb 2019 11:11:35 +0100 Subject: [PATCH 024/101] Clean up RepositoryInterface, fixes #5464 --- src/Composer/Repository/RepositoryInterface.php | 3 ++- src/Composer/Repository/RepositoryManager.php | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index 567455163..e5f2c5159 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -78,8 +78,9 @@ interface RepositoryInterface extends \Countable * * @param string $query search query * @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only + * @param string $type The type of package to search for. Defaults to all types of packages * * @return array[] an array of array('name' => '...', 'description' => '...') */ - public function search($query, $mode = 0); + public function search($query, $mode = 0, $type = null); } diff --git a/src/Composer/Repository/RepositoryManager.php b/src/Composer/Repository/RepositoryManager.php index c3ce0c24a..2dca57099 100644 --- a/src/Composer/Repository/RepositoryManager.php +++ b/src/Composer/Repository/RepositoryManager.php @@ -125,13 +125,7 @@ class RepositoryManager $class = $this->repositoryClasses[$type]; - $reflMethod = new \ReflectionMethod($class, '__construct'); - $params = $reflMethod->getParameters(); - if (isset($params[3]) && $params[3]->getClass() && $params[3]->getClass()->getName() === 'Composer\Util\HttpDownloader') { - return new $class($config, $this->io, $this->config, $this->httpDownloader, $this->eventDispatcher); - } - - return new $class($config, $this->io, $this->config, $this->eventDispatcher); + return new $class($config, $this->io, $this->config, $this->httpDownloader, $this->eventDispatcher); } /** From 65903aacfdc19acb52c441dc5567d45052cfa169 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 19 Feb 2019 09:35:48 -0500 Subject: [PATCH 025/101] Fix type issues (#7996) * Fix type issues found by Psalm --- src/Composer/Command/BaseCommand.php | 6 ++++-- src/Composer/Command/ConfigCommand.php | 2 +- src/Composer/Command/DiagnoseCommand.php | 16 +--------------- src/Composer/Command/ShowCommand.php | 12 ++++++------ src/Composer/Command/SuggestsCommand.php | 5 ++++- src/Composer/Config/ConfigSourceInterface.php | 2 +- src/Composer/Config/JsonConfigSource.php | 2 +- src/Composer/Console/Application.php | 2 +- src/Composer/DependencyResolver/GenericRule.php | 8 ++++---- src/Composer/DependencyResolver/PoolBuilder.php | 6 +++--- src/Composer/DependencyResolver/Problem.php | 2 +- src/Composer/DependencyResolver/Solver.php | 5 +++-- src/Composer/Downloader/DownloadManager.php | 4 +--- src/Composer/Downloader/GitDownloader.php | 6 +++--- src/Composer/Downloader/PerforceDownloader.php | 2 +- src/Composer/EventDispatcher/EventDispatcher.php | 3 ++- src/Composer/Factory.php | 2 +- src/Composer/IO/IOInterface.php | 6 +++--- src/Composer/Installer.php | 2 +- src/Composer/Installer/InstallerInterface.php | 2 +- src/Composer/Installer/LibraryInstaller.php | 2 +- src/Composer/Package/BasePackage.php | 2 +- src/Composer/Package/PackageInterface.php | 2 +- src/Composer/Package/Version/VersionSelector.php | 2 +- .../Repository/Pear/BaseChannelReader.php | 2 +- .../Repository/Pear/ChannelRest10Reader.php | 2 +- src/Composer/Repository/PearRepository.php | 2 +- .../Repository/Vcs/VcsDriverInterface.php | 6 +++--- src/Composer/Util/AuthHelper.php | 2 +- src/Composer/Util/Filesystem.php | 1 + src/Composer/Util/HttpDownloader.php | 2 +- src/Composer/Util/Loop.php | 1 + src/Composer/Util/RemoteFilesystem.php | 2 +- src/Composer/Util/Svn.php | 2 +- 34 files changed, 59 insertions(+), 66 deletions(-) diff --git a/src/Composer/Command/BaseCommand.php b/src/Composer/Command/BaseCommand.php index 888b2a7f2..56ee9f7f4 100644 --- a/src/Composer/Command/BaseCommand.php +++ b/src/Composer/Command/BaseCommand.php @@ -27,6 +27,8 @@ use Symfony\Component\Console\Command\Command; /** * Base class for Composer commands * + * @method Application getApplication() + * * @author Ryan Weaver * @author Konstantin Kudryashov */ @@ -46,7 +48,7 @@ abstract class BaseCommand extends Command * @param bool $required * @param bool|null $disablePlugins * @throws \RuntimeException - * @return Composer + * @return Composer|null */ public function getComposer($required = true, $disablePlugins = null) { @@ -173,7 +175,7 @@ abstract class BaseCommand extends Command if ($input->getOption('prefer-source') || $input->getOption('prefer-dist') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'))) { $preferSource = $input->getOption('prefer-source') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs')); - $preferDist = $input->getOption('prefer-dist'); + $preferDist = (bool) $input->getOption('prefer-dist'); } return array($preferSource, $preferDist); diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 89ba495cf..3970d915d 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -226,7 +226,7 @@ EOT } $settingKey = $input->getArgument('setting-key'); - if (!$settingKey) { + if (!$settingKey || !is_string($settingKey)) { return 0; } diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 481d58060..c123e7003 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -602,20 +602,6 @@ EOT $text .= "Install either of them or recompile php without --disable-iconv"; break; - case 'unicode': - $text = PHP_EOL."The detect_unicode setting must be disabled.".PHP_EOL; - $text .= "Add the following to the end of your `php.ini`:".PHP_EOL; - $text .= " detect_unicode = Off"; - $displayIniMessage = true; - break; - - case 'suhosin': - $text = PHP_EOL."The suhosin.executor.include.whitelist setting is incorrect.".PHP_EOL; - $text .= "Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):".PHP_EOL; - $text .= " suhosin.executor.include.whitelist = phar ".$current; - $displayIniMessage = true; - break; - case 'php': $text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher."; break; @@ -713,7 +699,7 @@ EOT /** * Check if allow_url_fopen is ON * - * @return bool|string + * @return true|string */ private function checkConnectivity() { diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 5cb3fa860..a5a2cd780 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -823,10 +823,10 @@ EOT /** * Display a package tree * - * @param PackageInterface|string $package - * @param array $packagesInTree - * @param string $previousTreeBar - * @param int $level + * @param array|string $package + * @param array $packagesInTree + * @param string $previousTreeBar + * @param int $level */ protected function displayTree( $package, @@ -835,7 +835,7 @@ EOT $level = 1 ) { $previousTreeBar = str_replace('├', '│', $previousTreeBar); - if (isset($package['requires'])) { + if (is_array($package) && isset($package['requires'])) { $requires = $package['requires']; $treeBar = $previousTreeBar . ' ├'; $i = 0; @@ -968,7 +968,7 @@ EOT * @param string $phpVersion * @param bool $minorOnly * - * @return PackageInterface|null + * @return PackageInterface|false */ private function findLatestPackage(PackageInterface $package, Composer $composer, $phpVersion, $minorOnly = false) { diff --git a/src/Composer/Command/SuggestsCommand.php b/src/Composer/Command/SuggestsCommand.php index 225725e12..1c1f23f93 100644 --- a/src/Composer/Command/SuggestsCommand.php +++ b/src/Composer/Command/SuggestsCommand.php @@ -43,6 +43,9 @@ EOT ; } + /** + * {@inheritDoc} + */ protected function execute(InputInterface $input, OutputInterface $output) { $lock = $this->getComposer()->getLocker()->getLockData(); @@ -117,7 +120,7 @@ EOT $io->write(sprintf('%s', $suggestion)); } - return; + return null; } // Grouped by package diff --git a/src/Composer/Config/ConfigSourceInterface.php b/src/Composer/Config/ConfigSourceInterface.php index 0d56fc0ed..a00e989bb 100644 --- a/src/Composer/Config/ConfigSourceInterface.php +++ b/src/Composer/Config/ConfigSourceInterface.php @@ -39,7 +39,7 @@ interface ConfigSourceInterface * Add a config setting * * @param string $name Name - * @param string $value Value + * @param string|array $value Value */ public function addConfigSetting($name, $value); diff --git a/src/Composer/Config/JsonConfigSource.php b/src/Composer/Config/JsonConfigSource.php index 15d40d200..e22bbb1e5 100644 --- a/src/Composer/Config/JsonConfigSource.php +++ b/src/Composer/Config/JsonConfigSource.php @@ -259,7 +259,7 @@ class JsonConfigSource implements ConfigSourceInterface * * @param array $array * @param mixed $value - * @return array + * @return int */ private function arrayUnshiftRef(&$array, &$value) { diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 0bfee80f3..64a32b46f 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -284,7 +284,7 @@ class Application extends BaseApplication return $result; } catch (ScriptExecutionException $e) { - return $e->getCode(); + return (int) $e->getCode(); } catch (\Exception $e) { $this->hintCommonErrors($e); restore_error_handler(); diff --git a/src/Composer/DependencyResolver/GenericRule.php b/src/Composer/DependencyResolver/GenericRule.php index df8a2a003..eb753067e 100644 --- a/src/Composer/DependencyResolver/GenericRule.php +++ b/src/Composer/DependencyResolver/GenericRule.php @@ -23,10 +23,10 @@ class GenericRule extends Rule protected $literals; /** - * @param array $literals - * @param int $reason A RULE_* constant describing the reason for generating this rule - * @param Link|PackageInterface $reasonData - * @param array $job The job this rule was created from + * @param array $literals + * @param int|null $reason A RULE_* constant describing the reason for generating this rule + * @param Link|PackageInterface|int|null $reasonData + * @param array $job The job this rule was created from */ public function __construct(array $literals, $reason, $reasonData, $job = null) { diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 9eb3dc0d0..42444cc91 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -176,12 +176,12 @@ class PoolBuilder if (!isset($this->loadedNames[$require])) { $loadNames[$require] = null; } - if ($link->getConstraint()) { + if ($linkConstraint = $link->getConstraint()) { if (!array_key_exists($require, $this->nameConstraints)) { - $this->nameConstraints[$require] = new MultiConstraint(array($link->getConstraint()), false); + $this->nameConstraints[$require] = new MultiConstraint(array($linkConstraint), false); } elseif ($this->nameConstraints[$require]) { // TODO addConstraint function? - $this->nameConstraints[$require] = new MultiConstraint(array_merge(array($link->getConstraint()), $this->nameConstraints[$require]->getConstraints()), false); + $this->nameConstraints[$require] = new MultiConstraint(array_merge(array($linkConstraint), $this->nameConstraints[$require]->getConstraints()), false); } } else { $this->nameConstraints[$require] = null; diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 271c7261f..98b07405a 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -180,7 +180,7 @@ class Problem * Store a reason descriptor but ignore duplicates * * @param string $id A canonical identifier for the reason - * @param string $reason The reason descriptor + * @param string|array $reason The reason descriptor */ protected function addReason($id, $reason) { diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index 2188d99ce..821928382 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -13,6 +13,7 @@ namespace Composer\DependencyResolver; use Composer\IO\IOInterface; +use Composer\Package\PackageInterface; use Composer\Repository\RepositoryInterface; use Composer\Repository\PlatformRepository; use Composer\Repository\RepositorySet; @@ -44,7 +45,7 @@ class Solver protected $watchGraph; /** @var Decisions */ protected $decisions; - /** @var int[] */ + /** @var PackageInterface[] */ protected $installedMap; /** @var int */ @@ -691,7 +692,7 @@ class Solver /** * @todo this makes $disableRules always false; determine the rationale and possibly remove dead code? */ - $disableRules = array(); + $disableRules = false; $level = 1; $systemLevel = $level + 1; diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index 0b1ddb5a6..a23c167b5 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -294,9 +294,7 @@ class DownloadManager // if downloader type changed, or update failed and user asks for reinstall, // we wipe the dir and do a new install instead of updating it - if ($initialDownloader) { - $initialDownloader->remove($initial, $targetDir); - } + $initialDownloader->remove($initial, $targetDir); $this->install($target, $targetDir); } diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 96e47cb22..f698981fe 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -362,7 +362,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface ) { $command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference)); if (0 === $this->process->execute($command, $output, $path)) { - return; + return null; } } @@ -380,14 +380,14 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface ) { $command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference)); if (0 === $this->process->execute($command, $output, $path)) { - return; + return null; } } } $command = sprintf($template, ProcessExecutor::escape($gitRef)); if (0 === $this->process->execute($command, $output, $path)) { - return; + return null; } // reference was not found (prints "fatal: reference is not a tree: $ref") diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php index a7dc013b3..0427ec8c8 100644 --- a/src/Composer/Downloader/PerforceDownloader.php +++ b/src/Composer/Downloader/PerforceDownloader.php @@ -88,7 +88,7 @@ class PerforceDownloader extends VcsDownloader { $this->io->writeError('Perforce driver does not check for local changes before overriding', true); - return; + return null; } /** diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index c24660659..05e34dda1 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -199,6 +199,7 @@ class EventDispatcher } try { + /** @var InstallerEvent $event */ $return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags)); } catch (ScriptExecutionException $e) { $this->io->writeError(sprintf('Script %s was called via %s', $callable, $event->getName()), true, IOInterface::QUIET); @@ -499,7 +500,7 @@ class EventDispatcher * * @param Event $event * @throws \RuntimeException - * @return number + * @return int */ protected function pushEvent(Event $event) { diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index b2fd4efab..383337aa6 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -413,7 +413,7 @@ class Factory /** * @param IOInterface $io IO instance * @param bool $disablePlugins Whether plugins should not be loaded - * @return Composer + * @return Composer|null */ public static function createGlobal(IOInterface $io, $disablePlugins = false) { diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php index 46302088f..95f891c57 100644 --- a/src/Composer/IO/IOInterface.php +++ b/src/Composer/IO/IOInterface.php @@ -108,7 +108,7 @@ interface IOInterface extends LoggerInterface * @param string $default The default answer if none is given by the user * * @throws \RuntimeException If there is no data to read in the input stream - * @return string The user answer + * @return string|null The user answer */ public function ask($question, $default = null); @@ -146,7 +146,7 @@ interface IOInterface extends LoggerInterface * * @param string $question The question to ask * - * @return string The answer + * @return string|null The answer */ public function askAndHideAnswer($question); @@ -161,7 +161,7 @@ interface IOInterface extends LoggerInterface * @param bool $multiselect Select more than one value separated by comma * * @throws \InvalidArgumentException - * @return int|string|array The selected value or values (the key of the choices array) + * @return int|string|array|bool The selected value or values (the key of the choices array) */ public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false); diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 19c0015d6..fc877f18e 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -959,7 +959,7 @@ class Installer * @param RepositoryInterface $lockedRepository * @param string $task * @param array|null $operations - * @return array + * @return array|null */ private function processDevPackages($localRepo, Pool $pool, $policy, $repositories, $installedRepo, $lockedRepository, $task, array $operations = null) { diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index e00877ed9..310c5fcfc 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -48,7 +48,7 @@ interface InstallerInterface * * @param PackageInterface $package package instance * @param PackageInterface $prevPackage previous package instance in case of an update - * @return PromiseInterface + * @return PromiseInterface|null */ public function download(PackageInterface $package, PackageInterface $prevPackage = null); diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 4c2f45601..a89553b1b 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -43,7 +43,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface * * @param IOInterface $io * @param Composer $composer - * @param string $type + * @param string|null $type * @param Filesystem $filesystem * @param BinaryInstaller $binaryInstaller */ diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index f2f5be707..9630e7ef0 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -239,7 +239,7 @@ abstract class BasePackage implements PackageInterface * Build a regexp from a package name, expanding * globs as required * * @param string $whiteListedPattern - * @param bool $wrap Wrap the cleaned string by the given string + * @param string $wrap Wrap the cleaned string by the given string * @return string */ public static function packageNameToRegexp($whiteListedPattern, $wrap = '{^%s$}i') diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 73d2ade41..30488e89f 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -76,7 +76,7 @@ interface PackageInterface /** * Returns the package targetDir property * - * @return string The package targetDir + * @return string|null The package targetDir */ public function getTargetDir(); diff --git a/src/Composer/Package/Version/VersionSelector.php b/src/Composer/Package/Version/VersionSelector.php index d99780ab1..a8b4ae17b 100644 --- a/src/Composer/Package/Version/VersionSelector.php +++ b/src/Composer/Package/Version/VersionSelector.php @@ -45,7 +45,7 @@ class VersionSelector * @param string $targetPackageVersion * @param string $targetPhpVersion * @param string $preferredStability - * @return PackageInterface|bool + * @return PackageInterface|false */ public function findBestCandidate($packageName, $targetPackageVersion = null, $targetPhpVersion = null, $preferredStability = 'stable') { diff --git a/src/Composer/Repository/Pear/BaseChannelReader.php b/src/Composer/Repository/Pear/BaseChannelReader.php index b778bf08b..9b9acf2f2 100644 --- a/src/Composer/Repository/Pear/BaseChannelReader.php +++ b/src/Composer/Repository/Pear/BaseChannelReader.php @@ -47,7 +47,7 @@ abstract class BaseChannelReader * @param string $origin server * @param string $path relative path to content * @throws \UnexpectedValueException - * @return \SimpleXMLElement + * @return string */ protected function requestContent($origin, $path) { diff --git a/src/Composer/Repository/Pear/ChannelRest10Reader.php b/src/Composer/Repository/Pear/ChannelRest10Reader.php index 93969043a..9d14b71ea 100644 --- a/src/Composer/Repository/Pear/ChannelRest10Reader.php +++ b/src/Composer/Repository/Pear/ChannelRest10Reader.php @@ -150,7 +150,7 @@ class ChannelRest10Reader extends BaseChannelReader * @param string $baseUrl * @param string $packageName * @param string $version - * @return DependencyInfo[] + * @return DependencyInfo */ private function readPackageReleaseDependencies($baseUrl, $packageName, $version) { diff --git a/src/Composer/Repository/PearRepository.php b/src/Composer/Repository/PearRepository.php index 1bb22c0ed..5cffb6233 100644 --- a/src/Composer/Repository/PearRepository.php +++ b/src/Composer/Repository/PearRepository.php @@ -97,7 +97,7 @@ class PearRepository extends ArrayRepository implements ConfigurableRepositoryIn * * @param ChannelInfo $channelInfo * @param SemverVersionParser $versionParser - * @return CompletePackage + * @return CompletePackage[] */ private function buildComposerPackages(ChannelInfo $channelInfo, SemverVersionParser $versionParser) { diff --git a/src/Composer/Repository/Vcs/VcsDriverInterface.php b/src/Composer/Repository/Vcs/VcsDriverInterface.php index 5e3bcec68..e59bcf647 100644 --- a/src/Composer/Repository/Vcs/VcsDriverInterface.php +++ b/src/Composer/Repository/Vcs/VcsDriverInterface.php @@ -38,7 +38,7 @@ interface VcsDriverInterface * * @param string $file * @param string $identifier - * @return string + * @return string|null */ public function getFileContent($file, $identifier); @@ -46,7 +46,7 @@ interface VcsDriverInterface * Get the changedate for $identifier. * * @param string $identifier - * @return \DateTime + * @return \DateTime|null */ public function getChangeDate($identifier); @@ -73,7 +73,7 @@ interface VcsDriverInterface /** * @param string $identifier Any identifier to a specific branch/tag/commit - * @return array With type, url reference and shasum keys. + * @return array|null With type, url reference and shasum keys. */ public function getDist($identifier); diff --git a/src/Composer/Util/AuthHelper.php b/src/Composer/Util/AuthHelper.php index 3679b93da..2868d3346 100644 --- a/src/Composer/Util/AuthHelper.php +++ b/src/Composer/Util/AuthHelper.php @@ -73,7 +73,7 @@ class AuthHelper * @param string|null $reason a message/description explaining why this was called * @param string $warning an authentication warning returned by the server as {"warning": ".."}, if present * @param string[] $headers - * @return array containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be + * @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be * retried, if storeAuth is true then on a successful retry the authentication should be persisted to auth.json */ public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $warning = null, $headers = array()) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 805eda14b..2d73016c6 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -292,6 +292,7 @@ class Filesystem $this->ensureDirectoryExists($target); $result = true; + /** @var RecursiveDirectoryIterator $ri */ foreach ($ri as $file) { $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName(); if ($file->isDir()) { diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 68e11a4a4..5a5ec14b2 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -117,7 +117,7 @@ class HttpDownloader /** * Merges new options * - * @return array $options + * @return void */ public function setOptions(array $options) { diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php index c50cf4b02..dfaa2ac53 100644 --- a/src/Composer/Util/Loop.php +++ b/src/Composer/Util/Loop.php @@ -29,6 +29,7 @@ class Loop public function wait(array $promises) { + /** @var \Exception|null */ $uncaught = null; \React\Promise\all($promises)->then( diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index e2c50472c..07eccc791 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -398,7 +398,7 @@ class RemoteFilesystem // fail 4xx and 5xx responses and capture the response if ($statusCode && $statusCode >= 400 && $statusCode <= 599) { if (!$this->retry) { - if ($this->progress && !$this->retry && !$isRedirect) { + if ($this->progress && !$isRedirect) { $this->io->overwriteError("Downloading (failed)", false); } diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index 58114ac93..be1a81c91 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -304,7 +304,7 @@ class Svn $this->createAuthFromUrl(); } - return $this->hasAuth; + return (bool) $this->hasAuth; } /** From 61cd8664e56cfd71ed88537edabf616262518a9a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 08:43:33 +0100 Subject: [PATCH 026/101] Avoid creating empty bitbucket files if there was no composer.json present in the original branch/tag --- .../Repository/Vcs/BitbucketDriver.php | 76 ++++++++++--------- src/Composer/Repository/Vcs/GitHubDriver.php | 2 +- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/Composer/Repository/Vcs/BitbucketDriver.php b/src/Composer/Repository/Vcs/BitbucketDriver.php index 24a4af4dd..556ca5012 100644 --- a/src/Composer/Repository/Vcs/BitbucketDriver.php +++ b/src/Composer/Repository/Vcs/BitbucketDriver.php @@ -124,50 +124,52 @@ abstract class BitbucketDriver extends VcsDriver $composer = $this->getBaseComposerInformation($identifier); - // specials for bitbucket - if (!isset($composer['support']['source'])) { - $label = array_search( - $identifier, - $this->getTags() - ) ?: array_search( - $identifier, - $this->getBranches() - ) ?: $identifier; + if ($composer) { + // specials for bitbucket + if (!isset($composer['support']['source'])) { + $label = array_search( + $identifier, + $this->getTags() + ) ?: array_search( + $identifier, + $this->getBranches() + ) ?: $identifier; - if (array_key_exists($label, $tags = $this->getTags())) { - $hash = $tags[$label]; - } elseif (array_key_exists($label, $branches = $this->getBranches())) { - $hash = $branches[$label]; + if (array_key_exists($label, $tags = $this->getTags())) { + $hash = $tags[$label]; + } elseif (array_key_exists($label, $branches = $this->getBranches())) { + $hash = $branches[$label]; + } + + if (! isset($hash)) { + $composer['support']['source'] = sprintf( + 'https://%s/%s/%s/src', + $this->originUrl, + $this->owner, + $this->repository + ); + } else { + $composer['support']['source'] = sprintf( + 'https://%s/%s/%s/src/%s/?at=%s', + $this->originUrl, + $this->owner, + $this->repository, + $hash, + $label + ); + } } - - if (! isset($hash)) { - $composer['support']['source'] = sprintf( - 'https://%s/%s/%s/src', + if (!isset($composer['support']['issues']) && $this->hasIssues) { + $composer['support']['issues'] = sprintf( + 'https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository ); - } else { - $composer['support']['source'] = sprintf( - 'https://%s/%s/%s/src/%s/?at=%s', - $this->originUrl, - $this->owner, - $this->repository, - $hash, - $label - ); } - } - if (!isset($composer['support']['issues']) && $this->hasIssues) { - $composer['support']['issues'] = sprintf( - 'https://%s/%s/%s/issues', - $this->originUrl, - $this->owner, - $this->repository - ); - } - if (!isset($composer['homepage'])) { - $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website; + if (!isset($composer['homepage'])) { + $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website; + } } $this->infoCache[$identifier] = $composer; diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index d0b721af9..40a75b4dd 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -152,8 +152,8 @@ class GitHubDriver extends VcsDriver } $composer = $this->getBaseComposerInformation($identifier); - if ($composer) { + if ($composer) { // specials for github if (!isset($composer['support']['source'])) { $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier; From ff82334124633d35f23343db17017e0d5abab1c2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 08:42:49 +0100 Subject: [PATCH 027/101] Load ~dev files as well as main provider files for new v2 protocol, fixes #6415 --- src/Composer/Repository/ComposerRepository.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index d75d02bac..92d39adfd 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -581,6 +581,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito throw new \LogicException('loadAsyncPackages only supports v2 protocol composer repos with a metadata-url'); } + // load ~dev variants as well if present + // TODO ideally there should be a flag set from the repositoryset/poolbuilder to know which packages should have the dev packages loaded + // so we can optimize away some requests entirely + foreach ($packageNames as $name => $constraint) { + $packageNames[$name.'~dev'] = $constraint; + } + foreach ($packageNames as $name => $constraint) { $name = strtolower($name); From 177f21ec5c975df8771517d53192da7aa2b46651 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 10:51:07 +0100 Subject: [PATCH 028/101] Fix loading of dev providers, refs #6415 --- src/Composer/Repository/ComposerRepository.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 92d39adfd..8d0d8c3a4 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -591,8 +591,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito foreach ($packageNames as $name => $constraint) { $name = strtolower($name); + $realName = preg_replace('{~dev$}', '', $name); // skip platform packages, root package and composer-plugin-api - if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) { + if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $realName) || '__root__' === $realName || 'composer-plugin-api' === $realName) { continue; } @@ -606,16 +607,16 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified) - ->then(function ($response) use (&$packages, $contents, $name, $constraint, $repo, $isPackageAcceptableCallable) { + ->then(function ($response) use (&$packages, $contents, $realName, $constraint, $repo, $isPackageAcceptableCallable) { if (true === $response) { $response = $contents; } - if (!isset($response['packages'][$name])) { + if (!isset($response['packages'][$realName])) { return; } - $versions = $response['packages'][$name]; + $versions = $response['packages'][$realName]; if (isset($response['minified']) && $response['minified'] === 'composer/2.0') { // TODO extract in other method @@ -649,7 +650,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito foreach ($versions as $version) { if (isset($version['version_normalizeds'])) { foreach ($version['version_normalizeds'] as $index => $normalizedVersion) { - if (!$repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $normalizedVersion)) { + if (!$repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $normalizedVersion)) { foreach ($uniqKeys as $key) { unset($version[$key.'s'][$index]); } @@ -663,7 +664,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $version['version_normalized'] = $repo->versionParser->normalize($version['version']); } - if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $version['version_normalized'])) { + if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version['version_normalized'])) { $versionsToLoad[] = $version; } } From 2e204b016187c1ce4a50021fc127ff19ea5c650e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 11:10:44 +0100 Subject: [PATCH 029/101] Remove support for the first version of the compression algo (#7906) --- src/Composer/Package/Loader/ArrayLoader.php | 31 +++---------------- .../Repository/ComposerRepository.php | 24 +++----------- 2 files changed, 9 insertions(+), 46 deletions(-) diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php index c5edd0d68..511f6c7ca 100644 --- a/src/Composer/Package/Loader/ArrayLoader.php +++ b/src/Composer/Package/Loader/ArrayLoader.php @@ -62,39 +62,16 @@ class ArrayLoader implements LoaderInterface public function loadPackages(array $versions, $class) { - static $uniqKeys = array('version', 'version_normalized', 'source', 'dist', 'time'); - $packages = array(); $linkCache = array(); foreach ($versions as $version) { - if (isset($version['versions'])) { - $baseVersion = $version; - foreach ($uniqKeys as $key) { - unset($baseVersion[$key.'s']); - } + $package = $this->createObject($version, $class); - foreach ($version['versions'] as $index => $dummy) { - $unpackedVersion = $baseVersion; - foreach ($uniqKeys as $key) { - $unpackedVersion[$key] = $version[$key.'s'][$index]; - } + $this->configureCachedLinks($linkCache, $package, $version); + $package = $this->configureObject($package, $version); - $package = $this->createObject($unpackedVersion, $class); - - $this->configureCachedLinks($linkCache, $package, $unpackedVersion); - $package = $this->configureObject($package, $unpackedVersion); - - $packages[] = $package; - } - } else { - $package = $this->createObject($version, $class); - - $this->configureCachedLinks($linkCache, $package, $version); - $package = $this->configureObject($package, $version); - - $packages[] = $package; - } + $packages[] = $package; } return $packages; diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 8d0d8c3a4..ccb14f622 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -645,28 +645,14 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito unset($expanded, $expandedVersion, $versionData); } - static $uniqKeys = array('version', 'version_normalized', 'source', 'dist', 'time'); $versionsToLoad = array(); foreach ($versions as $version) { - if (isset($version['version_normalizeds'])) { - foreach ($version['version_normalizeds'] as $index => $normalizedVersion) { - if (!$repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $normalizedVersion)) { - foreach ($uniqKeys as $key) { - unset($version[$key.'s'][$index]); - } - } - } - if (count($version['version_normalizeds'])) { - $versionsToLoad[] = $version; - } - } else { - if (!isset($version['version_normalized'])) { - $version['version_normalized'] = $repo->versionParser->normalize($version['version']); - } + if (!isset($version['version_normalized'])) { + $version['version_normalized'] = $repo->versionParser->normalize($version['version']); + } - if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version['version_normalized'])) { - $versionsToLoad[] = $version; - } + if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version['version_normalized'])) { + $versionsToLoad[] = $version; } } From bdf1f7f82b6c7c876278fdcd2c85fa13b318a6e8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 13:24:44 +0100 Subject: [PATCH 030/101] Fix loading of aliased packages in ComposerRepository when filtering by callback --- src/Composer/Repository/BaseRepository.php | 8 ++- .../Repository/ComposerRepository.php | 55 ++++++++++++------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/Composer/Repository/BaseRepository.php b/src/Composer/Repository/BaseRepository.php index d835d55fd..fb10fb678 100644 --- a/src/Composer/Repository/BaseRepository.php +++ b/src/Composer/Repository/BaseRepository.php @@ -32,9 +32,11 @@ abstract class BaseRepository implements RepositoryInterface $result = array(); foreach ($packages as $package) { - if (array_key_exists($package->getName(), $packageMap) && - (!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion()))) && - call_user_func($isPackageAcceptableCallable, $package->getNames(), $package->getStability())) { + if ( + array_key_exists($package->getName(), $packageMap) + && (!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion()))) + && call_user_func($isPackageAcceptableCallable, $package->getNames(), $package->getStability()) + ) { $result[spl_object_hash($package)] = $package; if ($package instanceof AliasPackage && !isset($result[spl_object_hash($package->getAliasOf())])) { $result[spl_object_hash($package->getAliasOf())] = $package->getAliasOf(); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index ccb14f622..f12c85b85 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -103,7 +103,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/'); $this->io = $io; - $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$'); + $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$~'); $this->versionParser = new VersionParser(); $this->loader = new ArrayLoader($this->versionParser); $this->httpDownloader = $httpDownloader; @@ -139,9 +139,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return; } - $packages = $this->loadAsyncPackages(array($name => $constraint), function ($name, $stability) { - return true; - }); + $packages = $this->loadAsyncPackages(array($name => $constraint)); return reset($packages); } @@ -181,9 +179,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return array(); } - return $this->loadAsyncPackages(array($name => $constraint ?: new EmptyConstraint()), function ($name, $stability) { - return true; - }); + return $this->loadAsyncPackages(array($name => $constraint)); } if ($hasProviders) { @@ -241,7 +237,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $packageMap[$name] = new EmptyConstraint(); } - return array_values($this->loadAsyncPackages($packageMap, function ($name, $stability) { return true; })); + return array_values($this->loadAsyncPackages($packageMap)); } throw new \LogicException('Composer repositories that have lazy providers and no available-packages list can not load the complete list of packages, use getProviderNames instead.'); @@ -513,11 +509,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } if (!isset($versionsToLoad[$version['uid']])) { - if ($isPackageAcceptableCallable && !call_user_func($isPackageAcceptableCallable, $normalizedName, VersionParser::parseStability($version['version']))) { - continue; + if (!isset($version['version_normalized'])) { + $version['version_normalized'] = $this->versionParser->normalize($version['version']); } - $versionsToLoad[$version['uid']] = $version; + if ($this->isVersionAcceptable($isPackageAcceptableCallable, null, $normalizedName, $version)) { + $versionsToLoad[$version['uid']] = $version; + } } } } @@ -569,7 +567,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $this->configurePackageTransportOptions($package); } - private function loadAsyncPackages(array $packageNames, $isPackageAcceptableCallable) + /** + * @param array $packageNames array of package name => ConstraintInterface|null - if a constraint is provided, only packages matching it will be loaded + */ + private function loadAsyncPackages(array $packageNames, $isPackageAcceptableCallable = null) { $this->loadRootServerFile(); @@ -598,7 +599,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $url = str_replace('%package%', $name, $this->lazyProvidersUrl); - $cacheKey = 'provider-'.strtr($name, '/', '$').'.json'; + $cacheKey = 'provider-'.strtr($name, '/', '~').'.json'; $lastModified = null; if ($contents = $this->cache->read($cacheKey)) { @@ -651,7 +652,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $version['version_normalized'] = $repo->versionParser->normalize($version['version']); } - if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version['version_normalized'])) { + if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version)) { $versionsToLoad[] = $version; } } @@ -659,9 +660,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $loadedPackages = $repo->createPackages($versionsToLoad, 'Composer\Package\CompletePackage'); foreach ($loadedPackages as $package) { $package->setRepository($repo); - $packages[spl_object_hash($package)] = $package; + if ($package instanceof AliasPackage && !isset($packages[spl_object_hash($package->getAliasOf())])) { + $package->getAliasOf()->setRepository($repo); $packages[spl_object_hash($package->getAliasOf())] = $package->getAliasOf(); } } @@ -677,19 +679,30 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito /** * TODO v3 should make this private once we can drop PHP 5.3 support * + * @param string $name package name (must be lowercased already) * @private */ - public function isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $versionNormalized) + public function isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $versionData) { - if (!call_user_func($isPackageAcceptableCallable, strtolower($name), VersionParser::parseStability($versionNormalized))) { - return false; + $versions = array($versionData['version_normalized']); + + if ($alias = $this->loader->getBranchAlias($versionData)) { + $versions[] = $alias; } - if ($constraint && !$constraint->matches(new Constraint('==', $versionNormalized))) { - return false; + foreach ($versions as $version) { + if ($isPackageAcceptableCallable && !call_user_func($isPackageAcceptableCallable, $name, VersionParser::parseStability($version))) { + continue; + } + + if ($constraint && !$constraint->matches(new Constraint('==', $version))) { + continue; + } + + return true; } - return true; + return false; } protected function loadRootServerFile() From 8fe2b9ec69b8da2e4a0ca9629f20559c568bff6a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Feb 2019 13:41:43 +0100 Subject: [PATCH 031/101] Fix test --- tests/Composer/Test/Repository/ComposerRepositoryTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 55ca6bf09..c8af9418c 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -99,7 +99,13 @@ class ComposerRepositoryTest extends TestCase public function testWhatProvides() { $repo = $this->getMockBuilder('Composer\Repository\ComposerRepository') - ->disableOriginalConstructor() + ->setConstructorArgs(array( + array('url' => 'https://dummy.test.link'), + new NullIO, + FactoryMock::createConfig(), + $this->getMockBuilder('Composer\Util\HttpDownloader')->disableOriginalConstructor()->getMock(), + $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock() + )) ->setMethods(array('fetchFile')) ->getMock(); From ba346ef04d7cc6fdbf9423b06f51e48485d20b77 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 12:57:27 +0100 Subject: [PATCH 032/101] Add forward compatibility for upcoming v2 installed.json format, refs #7999 --- src/Composer/Repository/FilesystemRepository.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index bde55aad3..204aa095d 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -51,6 +51,11 @@ class FilesystemRepository extends WritableArrayRepository try { $packages = $this->file->read(); + // forward compatibility for composer v2 installed.json + if (isset($packages['packages'])) { + $packages = $packages['packages']; + } + if (!is_array($packages)) { throw new \UnexpectedValueException('Could not parse package list from the repository'); } From 427116749558f99e4c04ffa3fe358ebfd74d2fa5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 13:39:12 +0100 Subject: [PATCH 033/101] Improve version reporting --- src/Composer/Compiler.php | 1 + src/Composer/Composer.php | 37 ++++++++++++++++++++++ src/Composer/Console/Application.php | 6 ++-- src/Composer/Util/StreamContextFactory.php | 2 +- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index 27b1f4816..2c763d053 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -193,6 +193,7 @@ class Compiler $content = str_replace('@package_version@', $this->version, $content); $content = str_replace('@package_branch_alias_version@', $this->branchAliasVersion, $content); $content = str_replace('@release_date@', $this->versionDate->format('Y-m-d H:i:s'), $content); + $content = preg_replace('{SOURCE_VERSION = \'[^\']+\';}', 'SOURCE_VERSION = \'\';', $content); } $phar->addFromString($path, $content); diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index a3972f44f..7b60b28af 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -29,9 +29,46 @@ use Composer\Package\Archiver\ArchiveManager; */ class Composer { + /* + * Examples of the following constants in the various configurations they can be in + * + * releases (phar): + * const VERSION = '1.8.2'; + * const BRANCH_ALIAS_VERSION = ''; + * const RELEASE_DATE = '2019-01-29 15:00:53'; + * const SOURCE_VERSION = ''; + * + * snapshot builds (phar): + * const VERSION = 'd3873a05650e168251067d9648845c220c50e2d7'; + * const BRANCH_ALIAS_VERSION = '1.9-dev'; + * const RELEASE_DATE = '2019-02-20 07:43:56'; + * const SOURCE_VERSION = ''; + * + * source (git clone): + * const VERSION = '@package_version@'; + * const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; + * const RELEASE_DATE = '@release_date@'; + * const SOURCE_VERSION = '1.8-dev+source'; + */ const VERSION = '@package_version@'; const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; const RELEASE_DATE = '@release_date@'; + const SOURCE_VERSION = '1.8-dev+source'; + + public static function getVersion() + { + // no replacement done, this must be a source checkout + if (self::VERSION === '@package_version'.'@') { + return self::SOURCE_VERSION; + } + + // we have a branch alias and version is a commit id, this must be a snapshot build + if (self::BRANCH_ALIAS_VERSION !== '' && preg_match('{^[a-f0-9]{40}$}', self::VERSION)) { + return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION; + } + + return self::VERSION; + } /** * @var Package\RootPackageInterface diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index ccf83c943..a829ac38a 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -89,7 +89,7 @@ class Application extends BaseApplication $this->io = new NullIO(); - parent::__construct('Composer', Composer::VERSION); + parent::__construct('Composer', Composer::getVersion()); } /** @@ -181,7 +181,7 @@ class Application extends BaseApplication if (!$isProxyCommand) { $io->writeError(sprintf( 'Running %s (%s) with %s on %s', - Composer::VERSION, + Composer::getVersion(), Composer::RELEASE_DATE, defined('HHVM_VERSION') ? 'HHVM '.HHVM_VERSION : 'PHP '.PHP_VERSION, function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS' @@ -425,7 +425,7 @@ class Application extends BaseApplication */ public function getLongVersion() { - if (Composer::BRANCH_ALIAS_VERSION) { + if (Composer::BRANCH_ALIAS_VERSION && Composer::BRANCH_ALIAS_VERSION !== '@package_branch_alias_version'.'@') { return sprintf( '%s version %s (%s) %s', $this->getName(), diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 8dfd6624a..da3e578bd 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -142,7 +142,7 @@ final class StreamContextFactory if (!isset($options['http']['header']) || false === stripos(implode('', $options['http']['header']), 'user-agent')) { $options['http']['header'][] = sprintf( 'User-Agent: Composer/%s (%s; %s; %s%s)', - Composer::VERSION === '@package_version@' ? 'source' : Composer::VERSION, + Composer::getVersion(), function_exists('php_uname') ? php_uname('s') : 'Unknown', function_exists('php_uname') ? php_uname('r') : 'Unknown', $phpVersion, From 0f36a42d614deb4638f5e00cd3a86309df78db72 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 14:05:56 +0100 Subject: [PATCH 034/101] Allow filtering of warning/info msgs by composer version --- .../Repository/ComposerRepository.php | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 8a5da2b23..b9de0d7ea 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -20,6 +20,7 @@ use Composer\DependencyResolver\Pool; use Composer\Json\JsonFile; use Composer\Cache; use Composer\Config; +use Composer\Composer; use Composer\Factory; use Composer\IO\IOInterface; use Composer\Util\RemoteFilesystem; @@ -699,12 +700,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = JsonFile::parseJson($json, $filename); - if (!empty($data['warning'])) { - $this->io->writeError('Warning from '.$this->url.': '.$data['warning'].''); - } - if (!empty($data['info'])) { - $this->io->writeError('Info from '.$this->url.': '.$data['info'].''); - } + $this->outputWarnings($data); if ($cacheKey) { if ($storeLastModifiedTime) { @@ -769,12 +765,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = JsonFile::parseJson($json, $filename); - if (!empty($data['warning'])) { - $this->io->writeError('Warning from '.$this->url.': '.$data['warning'].''); - } - if (!empty($data['info'])) { - $this->io->writeError('Info from '.$this->url.': '.$data['info'].''); - } + $this->outputWarnings($data); $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified'); if ($lastModifiedDate) { @@ -835,4 +826,24 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito // wipe rootData as it is fully consumed at this point and this saves some memory $this->rootData = true; } + + private function outputWarnings($data) + { + foreach (array('warning', 'info') as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $this->io->writeError('<'.$type.'>'.ucfirst($type).' from '.$this->url.': '.$data[$type].''); + } + } } From 60f198c17d99728b0c1adb5b17e581fe274e34e8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 14:06:41 +0100 Subject: [PATCH 035/101] Update target version --- src/Composer/Composer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 7b60b28af..0d5faceb2 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -53,7 +53,7 @@ class Composer const VERSION = '@package_version@'; const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; const RELEASE_DATE = '@release_date@'; - const SOURCE_VERSION = '1.8-dev+source'; + const SOURCE_VERSION = '1.9-dev+source'; public static function getVersion() { From 3f5a986170867e1c06517f7cc82c6db9cf99f1d7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 14:49:06 +0100 Subject: [PATCH 036/101] Show warning in all 400/500 responses if available, fixes #7814 --- .../Repository/ComposerRepository.php | 26 +++---------------- src/Composer/Util/AuthHelper.php | 7 +---- src/Composer/Util/Http/CurlDownloader.php | 15 +++++------ src/Composer/Util/HttpDownloader.php | 22 ++++++++++++++++ src/Composer/Util/RemoteFilesystem.php | 18 ++++++------- 5 files changed, 40 insertions(+), 48 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index e835e221b..0cdb74bd6 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -962,7 +962,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($this->io, $this->url, $data); if ($cacheKey) { if ($storeLastModifiedTime) { @@ -1036,7 +1036,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($this->io, $this->url, $data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1101,7 +1101,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($io, $url, $data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1161,24 +1161,4 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito // wipe rootData as it is fully consumed at this point and this saves some memory $this->rootData = true; } - - private function outputWarnings($data) - { - foreach (array('warning', 'info') as $type) { - if (empty($data[$type])) { - continue; - } - - if (!empty($data[$type . '-versions'])) { - $versionParser = new VersionParser(); - $constraint = $versionParser->parseConstraints($data[$type . '-versions']); - $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); - if (!$constraint->matches($composer)) { - continue; - } - } - - $this->io->writeError('<'.$type.'>'.ucfirst($type).' from '.$this->url.': '.$data[$type].''); - } - } } diff --git a/src/Composer/Util/AuthHelper.php b/src/Composer/Util/AuthHelper.php index 2868d3346..7085f2561 100644 --- a/src/Composer/Util/AuthHelper.php +++ b/src/Composer/Util/AuthHelper.php @@ -71,12 +71,11 @@ class AuthHelper * @param string $origin * @param int $statusCode HTTP status code that triggered this call * @param string|null $reason a message/description explaining why this was called - * @param string $warning an authentication warning returned by the server as {"warning": ".."}, if present * @param string[] $headers * @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be * retried, if storeAuth is true then on a successful retry the authentication should be persisted to auth.json */ - public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $warning = null, $headers = array()) + public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array()) { $storeAuth = false; $retry = false; @@ -173,10 +172,6 @@ class AuthHelper throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode); } - $this->io->overwriteError(''); - if ($warning) { - $this->io->writeError(' '.$warning.''); - } $this->io->writeError(' Authentication required ('.parse_url($url, PHP_URL_HOST).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index ab0dae91e..1ebc64242 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -20,6 +20,7 @@ use Composer\Util\RemoteFilesystem; use Composer\Util\StreamContextFactory; use Composer\Util\AuthHelper; use Composer\Util\Url; +use Composer\Util\HttpDownloader; use React\Promise\Promise; /** @@ -261,6 +262,10 @@ class CurlDownloader $this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); } + if ($response->getStatusCode() >= 400 && $response->getHeader('content-type') === 'application/json') { + HttpDownloader::outputWarnings($this->io, $job['origin'], json_decode($response->getBody(), true)); + } + $result = $this->isAuthenticatedRetryNeeded($job, $response); if ($result['retry']) { if ($job['filename']) { @@ -371,15 +376,7 @@ class CurlDownloader private function isAuthenticatedRetryNeeded(array $job, Response $response) { if (in_array($response->getStatusCode(), array(401, 403)) && $job['attributes']['retryAuthFailure']) { - $warning = null; - if ($response->getHeader('content-type') === 'application/json') { - $data = json_decode($response->getBody(), true); - if (!empty($data['warning'])) { - $warning = $data['warning']; - } - } - - $result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $warning, $response->getHeaders()); + $result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders()); if ($result['retry']) { return $result; diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 5a5ec14b2..94e7ec0db 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -17,6 +17,8 @@ use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; use Composer\Util\Http\Response; +use Composer\Package\Version\VersionParser; +use Composer\Semver\Constraint\Constraint; use React\Promise\Promise; /** @@ -313,4 +315,24 @@ class HttpDownloader return $resp; } + + public static function outputWarnings(IOInterface $io, $url, $data) + { + foreach (array('warning', 'info') as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].''); + } + } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 07eccc791..c6ba4085c 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; +use Composer\Util\HttpDownloader; /** * @author François Pluchino @@ -291,15 +292,12 @@ class RemoteFilesystem if (!empty($http_response_header[0])) { $statusCode = $this->findStatusCode($http_response_header); + if ($statusCode >= 400 && $this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { + HttpDownloader::outputWarnings($this->io, $originUrl, json_decode($result, true)); + } + if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) { - $warning = null; - if ($this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { - $data = json_decode($result, true); - if (!empty($data['warning'])) { - $warning = $data['warning']; - } - } - $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning, $http_response_header); + $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $http_response_header); } } @@ -613,9 +611,9 @@ class RemoteFilesystem } } - protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null, $headers = array()) + protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array()) { - $result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $warning, $headers); + $result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers); $this->storeAuth = $result['storeAuth']; $this->retry = $result['retry']; From d37642d9f2719316e99ab186ab971e6ccf255bb8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 14:59:28 +0100 Subject: [PATCH 037/101] Add missing use --- src/Composer/Util/HttpDownloader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 94e7ec0db..93026ecbe 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -17,6 +17,7 @@ use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; use Composer\Util\Http\Response; +use Composer\Composer; use Composer\Package\Version\VersionParser; use Composer\Semver\Constraint\Constraint; use React\Promise\Promise; From f77285916a8c0481a57554ad8615a049660e6b9b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Feb 2019 15:28:50 +0100 Subject: [PATCH 038/101] Clean up temp file on curl request failure and make sure the response body is avaiable on 3xx/4xx/5xx responses --- src/Composer/Util/Http/CurlDownloader.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 1ebc64242..989e63d12 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -251,16 +251,20 @@ class CurlDownloader // prepare response object if ($job['filename']) { - fclose($job['bodyHandle']); - $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $job['filename'].'~'); + $contents = $job['filename'].'~'; + if ($statusCode >= 300) { + rewind($job['bodyHandle']); + $contents = stream_get_contents($job['bodyHandle']); + } + $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents); $this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); } else { rewind($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']); - fclose($job['bodyHandle']); $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents); $this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); } + fclose($job['bodyHandle']); if ($response->getStatusCode() >= 400 && $response->getHeader('content-type') === 'application/json') { HttpDownloader::outputWarnings($this->io, $job['origin'], json_decode($response->getBody(), true)); @@ -268,10 +272,6 @@ class CurlDownloader $result = $this->isAuthenticatedRetryNeeded($job, $response); if ($result['retry']) { - if ($job['filename']) { - @unlink($job['filename'].'~'); - } - $this->restartJob($job, $job['url'], array('storeAuth' => $result['storeAuth'])); continue; } @@ -422,6 +422,10 @@ class CurlDownloader private function restartJob(array $job, $url, array $attributes = array()) { + if ($job['filename']) { + @unlink($job['filename'].'~'); + } + $attributes = array_merge($job['attributes'], $attributes); $origin = Url::getOrigin($this->config, $url); @@ -430,6 +434,10 @@ class CurlDownloader private function failResponse(array $job, Response $response, $errorMessage) { + if ($job['filename']) { + @unlink($job['filename'].'~'); + } + return new TransportException('The "'.$job['url'].'" file could not be downloaded ('.$errorMessage.')', $response->getStatusCode()); } From 6473dd91850460b9825fa8300b71e7712618bafe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 27 Feb 2019 15:03:25 +0100 Subject: [PATCH 039/101] Minor improvements to VersionCacheInterface --- src/Composer/Repository/VcsRepository.php | 28 +++++++++++++++++++ .../Repository/VersionCacheInterface.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index d6fb1bbee..9a9ba5833 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -43,6 +43,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt private $driver; /** @var VersionCacheInterface */ private $versionCache; + private $emptyReferences = array(); public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, array $drivers = null, VersionCacheInterface $versionCache = null) { @@ -117,6 +118,11 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt return $this->branchErrorOccurred; } + public function getEmptyReferences() + { + return $this->emptyReferences; + } + protected function initialize() { parent::initialize(); @@ -159,6 +165,10 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($cachedPackage) { $this->addPackage($cachedPackage); + continue; + } elseif ($cachedPackage === false) { + $this->emptyReferences[] = $identifier; + continue; } @@ -174,6 +184,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($verbose) { $this->io->writeError('Skipped tag '.$tag.', no composer file'); } + $this->emptyReferences[] = $identifier; continue; } @@ -212,6 +223,9 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier))); } catch (\Exception $e) { + if ($e instanceof TransportException) { + $this->emptyReferences[] = $identifier; + } if ($verbose) { $this->io->writeError('Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).''); } @@ -258,6 +272,10 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($cachedPackage) { $this->addPackage($cachedPackage); + continue; + } elseif ($cachedPackage === false) { + $this->emptyReferences[] = $identifier; + continue; } @@ -266,6 +284,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($verbose) { $this->io->writeError('Skipped branch '.$branch.', no composer file'); } + $this->emptyReferences[] = $identifier; continue; } @@ -284,6 +303,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt } $this->addPackage($package); } catch (TransportException $e) { + $this->emptyReferences[] = $identifier; if ($verbose) { $this->io->writeError('Skipped branch '.$branch.', no composer file was found'); } @@ -352,6 +372,14 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt } $cachedPackage = $this->versionCache->getVersionPackage($version, $identifier); + if ($cachedPackage === false) { + if ($verbose) { + $this->io->writeError('Skipped '.$version.', no composer file (cached from ref '.$identifier.')'); + } + + return false; + } + if ($cachedPackage) { $msg = 'Found cached composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $version . ')'; if ($verbose) { diff --git a/src/Composer/Repository/VersionCacheInterface.php b/src/Composer/Repository/VersionCacheInterface.php index db5934b59..41d485c64 100644 --- a/src/Composer/Repository/VersionCacheInterface.php +++ b/src/Composer/Repository/VersionCacheInterface.php @@ -17,7 +17,7 @@ interface VersionCacheInterface /** * @param string $version * @param string $identifier - * @return array Package version data + * @return array|null|false Package version data if found, false to indicate the identifier is known but has no package, null for an unknown identifier */ public function getVersionPackage($version, $identifier); } From 627a832cc15f9321cbf97eb5692e515800b30f6f Mon Sep 17 00:00:00 2001 From: Patrick Reimers Date: Fri, 1 Mar 2019 19:39:07 +0100 Subject: [PATCH 040/101] Return non zero exit code on deprecation --- src/Composer/Package/Loader/ValidatingArrayLoader.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index 405e567f0..a8aa65331 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -195,7 +195,9 @@ class ValidatingArrayLoader implements LoaderInterface foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) { if ($this->validateArray($linkType) && isset($this->config[$linkType])) { foreach ($this->config[$linkType] as $package => $constraint) { - if (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) { + if ($err = self::hasPackageNamingError($package, true)) { + $this->warnings[] = 'Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.'; + } elseif (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) { $this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]'; } if (!is_string($constraint)) { From 5d14a95543d12436f3962b32357bafb6ae4bac8b Mon Sep 17 00:00:00 2001 From: Patrick Reimers Date: Fri, 1 Mar 2019 20:11:20 +0100 Subject: [PATCH 041/101] Add test for warning on deprecated naming --- .../Package/Loader/ValidatingArrayLoaderTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index ebe6871fe..6de6d45fa 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -337,6 +337,18 @@ class ValidatingArrayLoaderTest extends TestCase ), false, ), + array( + array( + 'name' => 'foo/bar', + 'require' => array( + 'Foo/Baz' => '^1.0', + ), + ), + array( + 'Deprecation warning: require.Foo/Baz is invalid, it should not contain uppercase characters. Please use foo/baz instead. Make sure you fix this as Composer 2.0 will error.', + ), + false, + ), array( array( 'name' => 'foo/bar', From 6bce9da8c87450c9a08c217e1a4e6142087b4cf5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 4 Mar 2019 08:53:18 +0100 Subject: [PATCH 042/101] Only keep track of empty references that returned a 404 --- src/Composer/Repository/VcsRepository.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index 9a9ba5833..edd0dabf8 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -223,7 +223,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier))); } catch (\Exception $e) { - if ($e instanceof TransportException) { + if ($e instanceof TransportException && $e->getCode() === 404) { $this->emptyReferences[] = $identifier; } if ($verbose) { @@ -303,7 +303,9 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt } $this->addPackage($package); } catch (TransportException $e) { - $this->emptyReferences[] = $identifier; + if ($e->getCode() === 404) { + $this->emptyReferences[] = $identifier; + } if ($verbose) { $this->io->writeError('Skipped branch '.$branch.', no composer file was found'); } From d96d046209646e93259d54ca9985004341c40fe2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 4 Mar 2019 11:38:58 +0100 Subject: [PATCH 043/101] Fix require of platform packages with --ignore-platform-reqs, fixes #8012 --- src/Composer/Command/InitCommand.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index abcea73b2..ecc3d3238 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -694,15 +694,22 @@ EOT { // find the latest version allowed in this pool $versionSelector = new VersionSelector($this->getPool($input, $minimumStability)); - $package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability); + $ignorePlatformReqs = $input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs'); - // retry without phpVersion if platform requirements are ignored in case nothing was found - if ($input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs')) { + // ignore phpVersion if platform requirements are ignored + if ($ignorePlatformReqs) { $phpVersion = null; - $package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability); } + $package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability); + if (!$package) { + // platform packages can not be found in the pool in versions other than the local platform's has + // so if platform reqs are ignored we just take the user's word for it + if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) { + return array($name, $requiredVersion ?: '*'); + } + // Check whether the PHP version was the problem if ($phpVersion && $versionSelector->findBestCandidate($name, $requiredVersion, null, $preferredStability)) { throw new \InvalidArgumentException(sprintf( From c876613d5c651d1aa0f0d6621d7955bfe09520e2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 4 Mar 2019 12:55:38 +0100 Subject: [PATCH 044/101] Added "Read more at" links to all commands (#8019) --- src/Composer/Command/ArchiveCommand.php | 1 + src/Composer/Command/ClearCacheCommand.php | 2 ++ src/Composer/Command/ConfigCommand.php | 2 ++ src/Composer/Command/CreateProjectCommand.php | 1 + src/Composer/Command/DependsCommand.php | 1 + src/Composer/Command/DiagnoseCommand.php | 1 + src/Composer/Command/DumpAutoloadCommand.php | 2 ++ src/Composer/Command/ExecCommand.php | 7 +++++++ src/Composer/Command/GlobalCommand.php | 1 + src/Composer/Command/HomeCommand.php | 2 ++ src/Composer/Command/InitCommand.php | 1 + src/Composer/Command/InstallCommand.php | 1 + src/Composer/Command/LicensesCommand.php | 1 + src/Composer/Command/OutdatedCommand.php | 2 +- src/Composer/Command/ProhibitsCommand.php | 1 + src/Composer/Command/RemoveCommand.php | 1 + src/Composer/Command/RequireCommand.php | 1 + src/Composer/Command/RunScriptCommand.php | 2 ++ src/Composer/Command/ScriptAliasCommand.php | 2 ++ src/Composer/Command/SearchCommand.php | 1 + src/Composer/Command/SelfUpdateCommand.php | 1 + src/Composer/Command/ShowCommand.php | 1 + src/Composer/Command/StatusCommand.php | 1 + src/Composer/Command/SuggestsCommand.php | 1 + src/Composer/Command/UpdateCommand.php | 1 + src/Composer/Command/ValidateCommand.php | 1 + 26 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php index 29858c6fc..d0d9542cb 100644 --- a/src/Composer/Command/ArchiveCommand.php +++ b/src/Composer/Command/ArchiveCommand.php @@ -56,6 +56,7 @@ package in the specified version and writes it to the specified directory. php composer.phar archive [--format=zip] [--dir=/foo] [package [version]] +Read more at https://getcomposer.org/doc/03-cli.md#archive EOT ) ; diff --git a/src/Composer/Command/ClearCacheCommand.php b/src/Composer/Command/ClearCacheCommand.php index 2514f6330..ec51c56d3 100644 --- a/src/Composer/Command/ClearCacheCommand.php +++ b/src/Composer/Command/ClearCacheCommand.php @@ -32,6 +32,8 @@ class ClearCacheCommand extends BaseCommand <<clear-cache deletes all cached packages from composer's cache directory. + +Read more at https://getcomposer.org/doc/03-cli.md#clear-cache-clearcache- EOT ) ; diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index c2347d306..b7e3b1f99 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -125,6 +125,8 @@ You can always pass more than one option. As an example, if you want to edit the global config.json file. %command.full_name% --editor --global + +Read more at https://getcomposer.org/doc/03-cli.md#config EOT ) ; diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index cca5f1871..3702c3595 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -104,6 +104,7 @@ controlled code by appending the '--prefer-source' flag. To install a package from another repository than the default one you can pass the '--repository=https://myrepository.org' flag. +Read more at https://getcomposer.org/doc/03-cli.md#create-project EOT ) ; diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php index acbc89a70..d6adec083 100644 --- a/src/Composer/Command/DependsCommand.php +++ b/src/Composer/Command/DependsCommand.php @@ -37,6 +37,7 @@ Displays detailed information about where a package is referenced. php composer.phar depends composer/composer +Read more at https://getcomposer.org/doc/03-cli.md#depends-why- EOT ) ; diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 3c4c3bb32..19ed81392 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -55,6 +55,7 @@ The diagnose command checks common errors to help debugging problem The process exit code will be 1 in case of warnings and 2 for errors. +Read more at https://getcomposer.org/doc/03-cli.md#diagnose EOT ) ; diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php index 55a2c5f16..3add15166 100644 --- a/src/Composer/Command/DumpAutoloadCommand.php +++ b/src/Composer/Command/DumpAutoloadCommand.php @@ -39,6 +39,8 @@ class DumpAutoloadCommand extends BaseCommand ->setHelp( <<php composer.phar dump-autoload + +Read more at https://getcomposer.org/doc/03-cli.md#dump-autoload-dumpautoload- EOT ) ; diff --git a/src/Composer/Command/ExecCommand.php b/src/Composer/Command/ExecCommand.php index f07bc9d28..c9184c707 100644 --- a/src/Composer/Command/ExecCommand.php +++ b/src/Composer/Command/ExecCommand.php @@ -36,6 +36,13 @@ class ExecCommand extends BaseCommand 'Arguments to pass to the binary. Use -- to separate from composer arguments' ), )) + ->setHelp( + <</.config/composer Note: This path may vary depending on customizations to bin-dir in composer.json or the environmental variable COMPOSER_BIN_DIR. +Read more at https://getcomposer.org/doc/03-cli.md#global EOT ) ; diff --git a/src/Composer/Command/HomeCommand.php b/src/Composer/Command/HomeCommand.php index a2f0756a1..b7d907066 100644 --- a/src/Composer/Command/HomeCommand.php +++ b/src/Composer/Command/HomeCommand.php @@ -49,6 +49,8 @@ homepage in your default browser. To open the homepage by default, use -H or --homepage. To show instead of open the repository or homepage URL, use -s or --show. + +Read more at https://getcomposer.org/doc/03-cli.md#browse-home EOT ); } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index ecc3d3238..66a56f978 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -72,6 +72,7 @@ in the current directory. php composer.phar init +Read more at https://getcomposer.org/doc/03-cli.md#init EOT ) ; diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index cc590d8c9..32fb1bdc6 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -61,6 +61,7 @@ exist it will look for composer.json and do the same. php composer.phar install +Read more at https://getcomposer.org/doc/03-cli.md#install-i EOT ) ; diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index 9dec45e1b..b3c30d63b 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -41,6 +41,7 @@ class LicensesCommand extends BaseCommand The license command displays detailed information about the licenses of the installed dependencies. +Read more at https://getcomposer.org/doc/03-cli.md#licenses EOT ) ; diff --git a/src/Composer/Command/OutdatedCommand.php b/src/Composer/Command/OutdatedCommand.php index 79409c58f..ae26a7487 100644 --- a/src/Composer/Command/OutdatedCommand.php +++ b/src/Composer/Command/OutdatedCommand.php @@ -50,7 +50,7 @@ The color coding (or signage if you have ANSI colors disabled) for dependency ve may involve work. - red (!): Dependency has a new version that is semver-compatible and you should upgrade it. - +Read more at https://getcomposer.org/doc/03-cli.md#outdated EOT ) ; diff --git a/src/Composer/Command/ProhibitsCommand.php b/src/Composer/Command/ProhibitsCommand.php index edf6729ab..9e5575c74 100644 --- a/src/Composer/Command/ProhibitsCommand.php +++ b/src/Composer/Command/ProhibitsCommand.php @@ -37,6 +37,7 @@ Displays detailed information about why a package cannot be installed. php composer.phar prohibits composer/composer +Read more at https://getcomposer.org/doc/03-cli.md#prohibits-why-not- EOT ) ; diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index 27be1a0ca..e4407d4cb 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -56,6 +56,7 @@ list of installed packages php composer.phar remove +Read more at https://getcomposer.org/doc/03-cli.md#remove EOT ) ; diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index b347de094..4cad91023 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -73,6 +73,7 @@ If you do not specify a version constraint, composer will choose a suitable one If you do not want to install the new dependencies immediately you can call it with --no-update +Read more at https://getcomposer.org/doc/03-cli.md#require EOT ) ; diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index ea3b5c892..6d39ce6da 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -62,6 +62,8 @@ class RunScriptCommand extends BaseCommand The run-script command runs scripts defined in composer.json: php composer.phar run-script post-update-cmd + +Read more at https://getcomposer.org/doc/03-cli.md#run-script EOT ) ; diff --git a/src/Composer/Command/ScriptAliasCommand.php b/src/Composer/Command/ScriptAliasCommand.php index 1aba0b074..455f7420c 100644 --- a/src/Composer/Command/ScriptAliasCommand.php +++ b/src/Composer/Command/ScriptAliasCommand.php @@ -48,6 +48,8 @@ class ScriptAliasCommand extends BaseCommand The run-script command runs scripts defined in composer.json: php composer.phar run-script post-update-cmd + +Read more at https://getcomposer.org/doc/03-cli.md#run-script EOT ) ; diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php index ed180e84c..54aa4dcea 100644 --- a/src/Composer/Command/SearchCommand.php +++ b/src/Composer/Command/SearchCommand.php @@ -49,6 +49,7 @@ class SearchCommand extends BaseCommand The search command searches for packages by its name php composer.phar search symfony composer +Read more at https://getcomposer.org/doc/03-cli.md#search EOT ) ; diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 243755963..78b27460e 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -60,6 +60,7 @@ versions of composer and if found, installs the latest. php composer.phar self-update +Read more at https://getcomposer.org/doc/03-cli.md#self-update-selfupdate- EOT ) ; diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index cc0fe0154..e9061743f 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -85,6 +85,7 @@ class ShowCommand extends BaseCommand The show command displays detailed information about a package, or lists all packages available. +Read more at https://getcomposer.org/doc/03-cli.md#show EOT ) ; diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index 3e46b7fa0..cd153fc58 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -52,6 +52,7 @@ class StatusCommand extends BaseCommand The status command displays a list of dependencies that have been modified locally. +Read more at https://getcomposer.org/doc/03-cli.md#status EOT ) ; diff --git a/src/Composer/Command/SuggestsCommand.php b/src/Composer/Command/SuggestsCommand.php index 225725e12..a200f8f69 100644 --- a/src/Composer/Command/SuggestsCommand.php +++ b/src/Composer/Command/SuggestsCommand.php @@ -38,6 +38,7 @@ The %command.name% command shows a sorted list of suggested package Enabling -v implies --by-package --by-suggestion, showing both lists. +Read more at https://getcomposer.org/doc/03-cli.md#suggests EOT ) ; diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 34420b747..e68c265c0 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -81,6 +81,7 @@ from a specific vendor: To select packages names interactively with auto-completion use -i. +Read more at https://getcomposer.org/doc/03-cli.md#update-u EOT ) ; diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php index 52023e528..5aba74adf 100644 --- a/src/Composer/Command/ValidateCommand.php +++ b/src/Composer/Command/ValidateCommand.php @@ -55,6 +55,7 @@ Exit codes in case of errors are: 2 validation error(s) 3 file unreadable or missing +Read more at https://getcomposer.org/doc/03-cli.md#validate EOT ); } From 8ae8d131d5c8635a6bd34063adfd340e29e3a158 Mon Sep 17 00:00:00 2001 From: Patrick Reimers Date: Tue, 5 Mar 2019 10:44:55 +0100 Subject: [PATCH 045/101] Add deprecation warning for name attribute --- src/Composer/Package/Loader/ValidatingArrayLoader.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index a8aa65331..43f23236b 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -49,6 +49,10 @@ class ValidatingArrayLoader implements LoaderInterface $this->warnings = array(); $this->config = $config; + if ($err = self::hasPackageNamingError($config['name'])) { + $this->warnings[] = 'Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.'; + } + if ($this->strictName) { $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true); } else { From dd1e80a38f7bb1ce759c127ec405a65f8d97c388 Mon Sep 17 00:00:00 2001 From: Patrick Reimers Date: Tue, 5 Mar 2019 10:53:43 +0100 Subject: [PATCH 046/101] Add tests for wrong package name. --- .../Loader/ValidatingArrayLoaderTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index 6de6d45fa..2fc059f3c 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -298,6 +298,30 @@ class ValidatingArrayLoaderTest extends TestCase 'homepage : invalid value (foo:bar), must be an http/https URL', ), ), + array( + array( + 'name' => 'foo/bar.json', + ), + array( + 'Deprecation warning: Your package name foo/bar.json is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead. Make sure you fix this as Composer 2.0 will error.', + ), + ), + array( + array( + 'name' => 'com1/foo', + ), + array( + 'Deprecation warning: Your package name com1/foo is reserved, package and vendor names can not match any of: nul, con, prn, aux, com1, com2, com3, com4, com5, com6, com7, com8, com9, lpt1, lpt2, lpt3, lpt4, lpt5, lpt6, lpt7, lpt8, lpt9. Make sure you fix this as Composer 2.0 will error.', + ), + ), + array( + array( + 'name' => 'Foo/Bar', + ), + array( + 'Deprecation warning: Your package name Foo/Bar is invalid, it should not contain uppercase characters. We suggest using foo/bar instead. Make sure you fix this as Composer 2.0 will error.', + ), + ), array( array( 'name' => 'foo/bar', From 20ff8b22f29ecb7422f756a86347d7562e17b935 Mon Sep 17 00:00:00 2001 From: Mike Hatch <4390485+mikeshatch@users.noreply.github.com> Date: Sat, 9 Mar 2019 00:27:34 -0600 Subject: [PATCH 047/101] Corrected a typo and two grammar errors. --- doc/00-intro.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/00-intro.md b/doc/00-intro.md index e4af54c2c..ed7a17c7c 100644 --- a/doc/00-intro.md +++ b/doc/00-intro.md @@ -10,7 +10,7 @@ Composer is **not** a package manager in the same sense as Yum or Apt are. Yes, it deals with "packages" or libraries, but it manages them on a per-project basis, installing them in a directory (e.g. `vendor`) inside your project. By default it does not install anything globally. Thus, it is a dependency -manager. It does however support a "global" project for convenience via the +manager. It does however support a "global" project for convenience via the [global](03-cli.md#global) command. This idea is not new and Composer is strongly inspired by node's @@ -47,7 +47,7 @@ Linux and macOS. ### Downloading the Composer Executable Composer offers a convenient installer that you can execute directly from the -commandline. Feel free to [download this file](https://getcomposer.org/installer) +command line. Feel free to [download this file](https://getcomposer.org/installer) or review it on [GitHub](https://github.com/composer/getcomposer.org/blob/master/web/installer) if you wish to know more about the inner workings of the installer. The source is plain PHP. @@ -82,7 +82,7 @@ Now run `php bin/composer` in order to run Composer. #### Globally You can place the Composer PHAR anywhere you wish. If you put it in a directory -that is part of your `PATH`, you can access it globally. On unixy systems you +that is part of your `PATH`, you can access it globally. On Unix systems you can even make it executable and invoke it without directly using the `php` interpreter. From 7c64300a1b4516fe8693ef17c690edafd25b716d Mon Sep 17 00:00:00 2001 From: Christian Ego Date: Mon, 11 Mar 2019 10:24:39 +0100 Subject: [PATCH 048/101] using emptyDirectory instead of remove for clearing the cache --- src/Composer/Cache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index 3f2861797..06c6a0996 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -189,7 +189,8 @@ class Cache public function clear() { if ($this->enabled) { - return $this->filesystem->removeDirectory($this->root); + $this->filesystem->emptyDirectory($this->root); + return true; } return false; From 486b25fd3015dc21df0524178d0ad279c91c8980 Mon Sep 17 00:00:00 2001 From: Novicaine Date: Fri, 15 Mar 2019 13:15:01 -0500 Subject: [PATCH 049/101] Fix for UNC Windows paths Made isAbsolutePath recognize Windows UNC-style absolute paths starting with \\ --- src/Composer/Util/Filesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 1903f1c8d..d9e83280b 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -440,7 +440,7 @@ class Filesystem */ public function isAbsolutePath($path) { - return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':'; + return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path,0,2) === '\\'; } /** From 077bbe33729f0a794052f1c7966e7f15211e3b41 Mon Sep 17 00:00:00 2001 From: Quynh Xuan Nguyen Date: Tue, 19 Mar 2019 11:20:21 +0700 Subject: [PATCH 050/101] Correct description grammar --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5ed969969..0878f5b65 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "composer/composer", "type": "library", - "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", "keywords": [ "package", "dependency", From 8944627245b66948111a33f467b7c865115c559b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Mar 2019 11:34:23 +0100 Subject: [PATCH 051/101] Fix syntax and backslash escaping --- src/Composer/Util/Filesystem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index d9e83280b..c025a6b8c 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -440,7 +440,7 @@ class Filesystem */ public function isAbsolutePath($path) { - return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path,0,2) === '\\'; + return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path, 0, 2) === '\\\\'; } /** From 4441be1a0536789b28bea20c3a86cbcac852a0d2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Mar 2019 18:31:12 +0100 Subject: [PATCH 052/101] Update deps --- composer.lock | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index d0f72d83c..44b30fa22 100644 --- a/composer.lock +++ b/composer.lock @@ -64,16 +64,16 @@ }, { "name": "composer/semver", - "version": "1.4.2", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e", + "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e", "shasum": "" }, "require": { @@ -122,7 +122,7 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2019-03-19T17:25:45+00:00" }, { "name": "composer/spdx-licenses", @@ -231,23 +231,23 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.7", + "version": "5.2.8", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "8560d4314577199ba51bf2032f02cd1315587c23" + "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8560d4314577199ba51bf2032f02cd1315587c23", - "reference": "8560d4314577199ba51bf2032f02cd1315587c23", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4", + "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.1", + "friendsofphp/php-cs-fixer": "~2.2.20", "json-schema/json-schema-test-suite": "1.2.0", "phpunit/phpunit": "^4.8.35" }, @@ -293,7 +293,7 @@ "json", "schema" ], - "time": "2018-02-14T22:26:30+00:00" + "time": "2019-01-14T23:55:14+00:00" }, { "name": "psr/log", @@ -437,7 +437,7 @@ }, { "name": "symfony/console", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/console.git", @@ -498,7 +498,7 @@ }, { "name": "symfony/debug", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -555,7 +555,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -605,7 +605,7 @@ }, { "name": "symfony/finder", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -771,7 +771,7 @@ }, { "name": "symfony/process", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -1360,6 +1360,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, { @@ -1736,7 +1737,7 @@ }, { "name": "symfony/yaml", - "version": "v2.8.48", + "version": "v2.8.49", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From fb8b06edef6fee799344aac0ef342e0846ef4974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 21 Mar 2019 19:44:49 +0100 Subject: [PATCH 053/101] Remove unused local variable --- src/Composer/DependencyResolver/Problem.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 073f64e2d..0dcc938fd 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -79,7 +79,6 @@ class Problem reset($reasons); $reason = current($reasons); - $rule = $reason['rule']; $job = $reason['job']; if (isset($job['constraint'])) { From 625bcee63a58e17cd6e2cc981e76541ea526040e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 1 Apr 2019 17:56:03 +0200 Subject: [PATCH 054/101] Fix handling of warnings to incl all 4xx responses --- .../Repository/ComposerRepository.php | 24 +---------- src/Composer/Util/RemoteFilesystem.php | 40 +++++++++++++------ 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index b9de0d7ea..38b865103 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -700,7 +700,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = JsonFile::parseJson($json, $filename); - $this->outputWarnings($data); + RemoteFilesystem::outputWarnings($this->io, $this->url, $data); if ($cacheKey) { if ($storeLastModifiedTime) { @@ -765,7 +765,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = JsonFile::parseJson($json, $filename); - $this->outputWarnings($data); + RemoteFilesystem::outputWarnings($this->io, $this->url, $data); $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified'); if ($lastModifiedDate) { @@ -826,24 +826,4 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito // wipe rootData as it is fully consumed at this point and this saves some memory $this->rootData = true; } - - private function outputWarnings($data) - { - foreach (array('warning', 'info') as $type) { - if (empty($data[$type])) { - continue; - } - - if (!empty($data[$type . '-versions'])) { - $versionParser = new VersionParser(); - $constraint = $versionParser->parseConstraints($data[$type . '-versions']); - $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); - if (!$constraint->matches($composer)) { - continue; - } - } - - $this->io->writeError('<'.$type.'>'.ucfirst($type).' from '.$this->url.': '.$data[$type].''); - } - } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index ea18a9e30..e1a93fcf9 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -13,6 +13,9 @@ namespace Composer\Util; use Composer\Config; +use Composer\Composer; +use Composer\Semver\Constraint\Constraint; +use Composer\Package\Version\VersionParser; use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; @@ -324,15 +327,12 @@ class RemoteFilesystem if (!empty($http_response_header[0])) { $statusCode = $this->findStatusCode($http_response_header); + if ($statusCode >= 400 && $this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { + self::outputWarnings($this->io, $originUrl, json_decode($result, true)); + } + if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) { - $warning = null; - if ($this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { - $data = json_decode($result, true); - if (!empty($data['warning'])) { - $warning = $data['warning']; - } - } - $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning, $http_response_header); + $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), null, $http_response_header); } } @@ -741,10 +741,6 @@ class RemoteFilesystem throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus); } - $this->io->overwriteError(''); - if ($warning) { - $this->io->writeError(' '.$warning.''); - } $this->io->writeError(' Authentication required ('.parse_url($this->fileUrl, PHP_URL_HOST).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); @@ -1090,4 +1086,24 @@ class RemoteFilesystem return count($pathParts) >= 4 && $pathParts[3] == 'downloads'; } + + public static function outputWarnings(IOInterface $io, $url, $data) + { + foreach (array('warning', 'info') as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].''); + } + } } From 88852fbf1adfc1ffeb91e2db7cbbe1aa7f0321f9 Mon Sep 17 00:00:00 2001 From: Jim Birch <5177009+thejimbirch@users.noreply.github.com> Date: Mon, 1 Apr 2019 09:04:32 -0400 Subject: [PATCH 055/101] Updates typo: nother-feature to another-feature --- doc/articles/versions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/articles/versions.md b/doc/articles/versions.md index c1fb25551..e3da6c8ec 100644 --- a/doc/articles/versions.md +++ b/doc/articles/versions.md @@ -32,7 +32,7 @@ repository:* v1 v2 my-feature -nother-feature +another-feature ~/my-library$ git tag v1.0 From 971528916b5c955066a7bc677d94032fd4c99298 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 3 Apr 2019 10:33:58 +0200 Subject: [PATCH 056/101] fix regex for heredoc/nowdoc * take into account relaxed changes introduced in php 7.3 * see: https://github.com/php/php-src/commit/4887357269107ed669463c4b95bd755fbbb52490 * allow " as well as ', which was introduced in php 5.3 closes #8080 --- src/Composer/Autoload/ClassMapGenerator.php | 2 +- .../Test/Autoload/Fixtures/classmap/StripNoise.php | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 5d937433b..f3245bca6 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -162,7 +162,7 @@ class ClassMapGenerator } // strip heredocs/nowdocs - $contents = preg_replace('{<<<\s*(\'?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\2(?=\r\n|\n|\r|;)}s', 'null', $contents); + $contents = preg_replace('{<<<\s*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r|\s*)\\2(?=\r\n|\n|\r|\s|;)}s', 'null', $contents); // strip strings $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); // strip leading non-php code if needed diff --git a/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php b/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php index 4c344089b..3806791e3 100644 --- a/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php +++ b/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php @@ -33,12 +33,18 @@ class Fail5 } ANOTHER -. <<< 'ONEMORE' +. <<< "ONEMORE" class Fail6 { } -ONEMORE; +ONEMORE +. << Date: Wed, 3 Apr 2019 11:38:06 +0200 Subject: [PATCH 057/101] expand regex and testcases --- src/Composer/Autoload/ClassMapGenerator.php | 2 +- .../Autoload/Fixtures/classmap/StripNoise.php | 91 +++++++++++++------ 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index f3245bca6..b7a3902df 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -162,7 +162,7 @@ class ClassMapGenerator } // strip heredocs/nowdocs - $contents = preg_replace('{<<<\s*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r|\s*)\\2(?=\r\n|\n|\r|\s|;)}s', 'null', $contents); + $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\s+)\\2(?=\s+|[;,.)])}s', 'null', $contents); // strip strings $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); // strip leading non-php code if needed diff --git a/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php b/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php index 3806791e3..8944360ee 100644 --- a/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php +++ b/tests/Composer/Test/Autoload/Fixtures/classmap/StripNoise.php @@ -7,48 +7,81 @@ namespace Foo; */ class StripNoise { - public function test() + public function test_heredoc() { - return <<'; + } + + public function test_simple_string() + { + return 'class FailSimpleString {}'; } } From 4ea8e48bf8830a83defcf31923cef95c89f66391 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Thu, 4 Apr 2019 08:45:08 +0200 Subject: [PATCH 058/101] leading whitespace is optional, but newline is not --- src/Composer/Autoload/ClassMapGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index b7a3902df..1ecf96bfe 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -162,7 +162,7 @@ class ClassMapGenerator } // strip heredocs/nowdocs - $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\s+)\\2(?=\s+|[;,.)])}s', 'null', $contents); + $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents); // strip strings $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); // strip leading non-php code if needed From 043b33ed382b6232f8451a85ff1ab415c5a4e5eb Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Sat, 6 Apr 2019 08:44:23 -0700 Subject: [PATCH 059/101] Fixes #8065: Sort plugins deterministically before loading. --- src/Composer/Autoload/AutoloadGenerator.php | 3 ++- src/Composer/Plugin/PluginManager.php | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 7ea1a3444..2d4c481b1 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -28,6 +28,7 @@ use Composer\Script\ScriptEvents; */ class AutoloadGenerator { + /** * @var EventDispatcher */ @@ -959,7 +960,7 @@ INITIALIZER; * @param array $packageMap * @return array */ - protected function sortPackageMap(array $packageMap) + public function sortPackageMap(array $packageMap) { $packages = array(); $paths = array(); diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index e8f4b58c3..da9fb5c20 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -15,10 +15,10 @@ namespace Composer\Plugin; use Composer\Composer; use Composer\EventDispatcher\EventSubscriberInterface; use Composer\IO\IOInterface; +use Composer\Package\CompletePackage; use Composer\Package\Package; use Composer\Package\Version\VersionParser; use Composer\Repository\RepositoryInterface; -use Composer\Package\AliasPackage; use Composer\Package\PackageInterface; use Composer\Package\Link; use Composer\Semver\Constraint\Constraint; @@ -253,8 +253,13 @@ class PluginManager */ private function loadRepository(RepositoryInterface $repo) { - foreach ($repo->getPackages() as $package) { /** @var PackageInterface $package */ - if ($package instanceof AliasPackage) { + $packages = $repo->getPackages(); + $generator = $this->composer->getAutoloadGenerator(); + $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $this->composer->getPackage(), $packages); + $sortedPackageMap = array_reverse($generator->sortPackageMap($packageMap)); + foreach ($sortedPackageMap as $fullPackage) { + $package = $fullPackage[0]; /** @var PackageInterface $package */ + if (!($package instanceof CompletePackage)) { continue; } if ('composer-plugin' === $package->getType()) { From 3e6300b5e810aada05581769f25c07f30f1f5a75 Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Sat, 6 Apr 2019 08:49:45 -0700 Subject: [PATCH 060/101] code style fix. --- src/Composer/Autoload/AutoloadGenerator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 2d4c481b1..272c6b920 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -28,7 +28,6 @@ use Composer\Script\ScriptEvents; */ class AutoloadGenerator { - /** * @var EventDispatcher */ From a908e22a91895fc63cfa173667ef395b3b6f5447 Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Sat, 6 Apr 2019 08:53:32 -0700 Subject: [PATCH 061/101] Fixed code style issues. --- src/Composer/Plugin/PluginManager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index da9fb5c20..cca4efe54 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -255,7 +255,8 @@ class PluginManager { $packages = $repo->getPackages(); $generator = $this->composer->getAutoloadGenerator(); - $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $this->composer->getPackage(), $packages); + $rootPackage = $this->composer->getPackage(); /** @var PackageInterface $rootPackage */ + $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $rootPackage, $packages); $sortedPackageMap = array_reverse($generator->sortPackageMap($packageMap)); foreach ($sortedPackageMap as $fullPackage) { $package = $fullPackage[0]; /** @var PackageInterface $package */ From 5633a68689a9653dc04a81bd06a37fa83e3a9c17 Mon Sep 17 00:00:00 2001 From: Kevin Boyd Date: Mon, 8 Apr 2019 22:44:08 -0700 Subject: [PATCH 062/101] Add a helper to disable process timeouts The helper can be included in custom script definitions by calling "Composer\\Config::disableProcessTimeout". Example: { "scripts": { "watch": [ "Composer\\Config::disableProcessTimeout", "vendor/bin/long-running-script --watch" ] } } --- src/Composer/Config.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 4d8199ccc..7abca7dfa 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -16,6 +16,7 @@ use Composer\Config\ConfigSourceInterface; use Composer\Downloader\TransportException; use Composer\IO\IOInterface; use Composer\Util\Platform; +use Composer\Util\ProcessExecutor; /** * @author Jordi Boggiano @@ -459,4 +460,20 @@ class Config } } } + + /** + * Used by long-running custom scripts in composer.json + * + * "scripts": { + * "watch": [ + * "Composer\\Config::disableProcessTimeout", + * "vendor/bin/long-running-script --watch" + * ] + * } + */ + public static function disableProcessTimeout() + { + // Override global timeout set earlier by environment or config + ProcessExecutor::setTimeout(0); + } } From 17810b2621cea5f09436a395ed630fb29a6928e7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 9 Apr 2019 12:47:24 +0200 Subject: [PATCH 063/101] Revert composer.json changes if update process throws, fixes #8062 --- src/Composer/Command/RequireCommand.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 4cad91023..508514eb4 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -25,6 +25,7 @@ use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; +use Composer\IO\IOInterface; /** * @author Jérémy Romey @@ -160,16 +161,27 @@ EOT if ($input->getOption('no-update')) { return 0; } - $updateDevMode = !$input->getOption('update-no-dev'); - $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader'); - $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative'); - $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); + try { + return $this->doUpdate($input, $output, $io, $requirements); + } catch (\Exception $e) { + $this->revertComposerFile(false); + throw $e; + } + } + + private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements) + { // Update packages $this->resetComposer(); $composer = $this->getComposer(true, $input->getOption('no-plugins')); $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress')); + $updateDevMode = !$input->getOption('update-no-dev'); + $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader'); + $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative'); + $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader'); + $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); From 12e683e2ee74ace0d3843307843762f4a8186d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 25 Mar 2019 12:12:32 +0200 Subject: [PATCH 064/101] ext-imagick: support version string from ImageMagick 6.x --- src/Composer/Repository/PlatformRepository.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php index 50cbb4649..3126f860a 100644 --- a/src/Composer/Repository/PlatformRepository.php +++ b/src/Composer/Repository/PlatformRepository.php @@ -166,8 +166,14 @@ class PlatformRepository extends ArrayRepository case 'imagick': $imagick = new \Imagick(); $imageMagickVersion = $imagick->getVersion(); - preg_match('/^ImageMagick ([\d.]+)-(\d+)/', $imageMagickVersion['versionString'], $matches); - $prettyVersion = "{$matches[1]}.{$matches[2]}"; + // 6.x: ImageMagick 6.2.9 08/24/06 Q16 http://www.imagemagick.org + // 7.x: ImageMagick 7.0.8-34 Q16 x86_64 2019-03-23 https://imagemagick.org + preg_match('/^ImageMagick ([\d.]+)(?:-(\d+))?/', $imageMagickVersion['versionString'], $matches); + if (isset($matches[2])) { + $prettyVersion = "{$matches[1]}.{$matches[2]}"; + } else { + $prettyVersion = $matches[1]; + } break; case 'libxml': From d2ab4f66fd79e9f3fe906a8c8b2c8c183819b27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 21 Mar 2019 19:17:55 +0100 Subject: [PATCH 065/101] Extract job packageName & constraint to variables --- src/Composer/DependencyResolver/Problem.php | 67 +++++++++++---------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 0dcc938fd..bb497b549 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -81,8 +81,11 @@ class Problem $job = $reason['job']; - if (isset($job['constraint'])) { - $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']); + $packageName = $job['packageName']; + $constraint = $job['constraint']; + + if (isset($constraint)) { + $packages = $this->pool->whatProvides($packageName, $constraint); } else { $packages = array(); } @@ -90,9 +93,9 @@ class Problem if ($job && $job['cmd'] === 'install' && empty($packages)) { // handle php/hhvm - if ($job['packageName'] === 'php' || $job['packageName'] === 'php-64bit' || $job['packageName'] === 'hhvm') { + if ($packageName === 'php' || $packageName === 'php-64bit' || $packageName === 'hhvm') { $version = phpversion(); - $available = $this->pool->whatProvides($job['packageName']); + $available = $this->pool->whatProvides($packageName); if (count($available)) { $firstAvailable = reset($available); @@ -103,13 +106,13 @@ class Problem } } - $msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but '; + $msg = "\n - This package requires ".$packageName.$this->constraintToText($constraint).' but '; if (defined('HHVM_VERSION') || count($available)) { return $msg . 'your HHVM version does not satisfy that requirement.'; } - if ($job['packageName'] === 'hhvm') { + if ($packageName === 'hhvm') { return $msg . 'you are running this with PHP and not HHVM.'; } @@ -117,43 +120,43 @@ class Problem } // handle php extensions - if (0 === stripos($job['packageName'], 'ext-')) { - if (false !== strpos($job['packageName'], ' ')) { - return "\n - The requested PHP extension ".$job['packageName'].' should be required as '.str_replace(' ', '-', $job['packageName']).'.'; + if (0 === stripos($packageName, 'ext-')) { + if (false !== strpos($packageName, ' ')) { + return "\n - The requested PHP extension ".$packageName.' should be required as '.str_replace(' ', '-', $packageName).'.'; } - $ext = substr($job['packageName'], 4); + $ext = substr($packageName, 4); $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system'; - return "\n - The requested PHP extension ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error.'. Install or enable PHP\'s '.$ext.' extension.'; + return "\n - The requested PHP extension ".$packageName.$this->constraintToText($constraint).' '.$error.'. Install or enable PHP\'s '.$ext.' extension.'; } // handle linked libs - if (0 === stripos($job['packageName'], 'lib-')) { - if (strtolower($job['packageName']) === 'lib-icu') { + if (0 === stripos($packageName, 'lib-')) { + if (strtolower($packageName) === 'lib-icu') { $error = extension_loaded('intl') ? 'has the wrong version installed, try upgrading the intl extension.' : 'is missing from your system, make sure the intl extension is loaded.'; - return "\n - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error; + return "\n - The requested linked library ".$packageName.$this->constraintToText($constraint).' '.$error; } - return "\n - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.'; + return "\n - The requested linked library ".$packageName.$this->constraintToText($constraint).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.'; } - if (!preg_match('{^[A-Za-z0-9_./-]+$}', $job['packageName'])) { - $illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $job['packageName']); + if (!preg_match('{^[A-Za-z0-9_./-]+$}', $packageName)) { + $illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $packageName); - return "\n - The requested package ".$job['packageName'].' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.'; + return "\n - The requested package ".$packageName.' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.'; } - if ($providers = $this->pool->whatProvides($job['packageName'], $job['constraint'], true, true)) { - return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' is satisfiable by '.$this->getPackageList($providers).' but these conflict with your requirements or minimum-stability.'; + if ($providers = $this->pool->whatProvides($packageName, $constraint, true, true)) { + return "\n - The requested package ".$packageName.$this->constraintToText($constraint).' is satisfiable by '.$this->getPackageList($providers).' but these conflict with your requirements or minimum-stability.'; } - if ($providers = $this->pool->whatProvides($job['packageName'], null, true, true)) { - return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' exists as '.$this->getPackageList($providers).' but these are rejected by your constraint.'; + if ($providers = $this->pool->whatProvides($packageName, null, true, true)) { + return "\n - The requested package ".$packageName.$this->constraintToText($constraint).' exists as '.$this->getPackageList($providers).' but these are rejected by your constraint.'; } - return "\n - The requested package ".$job['packageName'].' could not be found in any version, there may be a typo in the package name.'; + return "\n - The requested package ".$packageName.' could not be found in any version, there may be a typo in the package name.'; } } @@ -202,27 +205,29 @@ class Problem */ protected function jobToText($job) { + $packageName = $job['packageName']; + $constraint = $job['constraint']; switch ($job['cmd']) { case 'install': - $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']); + $packages = $this->pool->whatProvides($packageName, $constraint); if (!$packages) { - return 'No package found to satisfy install request for '.$job['packageName'].$this->constraintToText($job['constraint']); + return 'No package found to satisfy install request for '.$packageName.$this->constraintToText($constraint); } - return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).' -> satisfiable by '.$this->getPackageList($packages).'.'; + return 'Installation request for '.$packageName.$this->constraintToText($constraint).' -> satisfiable by '.$this->getPackageList($packages).'.'; case 'update': - return 'Update request for '.$job['packageName'].$this->constraintToText($job['constraint']).'.'; + return 'Update request for '.$packageName.$this->constraintToText($constraint).'.'; case 'remove': - return 'Removal request for '.$job['packageName'].$this->constraintToText($job['constraint']).''; + return 'Removal request for '.$packageName.$this->constraintToText($constraint).''; } - if (isset($job['constraint'])) { - $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']); + if (isset($constraint)) { + $packages = $this->pool->whatProvides($packageName, $constraint); } else { $packages = array(); } - return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])'; + return 'Job(cmd='.$job['cmd'].', target='.$packageName.', packages=['.$this->getPackageList($packages).'])'; } protected function getPackageList($packages) From 974a3305ae0f3703c81927dc650b66d823fbf538 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 9 Apr 2019 17:41:09 +0200 Subject: [PATCH 066/101] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36ceddfc9..c079b6922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### [1.8.5] 2019-04-09 + + * HHVM 4.0 is no longer compatible with Composer. Please use PHP instead going forward. + * Added forward compatibility with upcoming 2.0 changes + * Fixed support for PHP 7.3-style heredoc/nowdoc syntax changes in autoload generation + * Fixed require command usage when combined with --ignore-platform-reqs + * Fixed and cleaned up various Windows junctions handling issues + ### [1.8.4] 2019-02-11 * Fixed long standing solver bug leading to odd solving issues in edge cases, see #7946 @@ -737,6 +745,7 @@ * Initial release +[1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5 [1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4 [1.8.3]: https://github.com/composer/composer/compare/1.8.2...1.8.3 [1.8.2]: https://github.com/composer/composer/compare/1.8.1...1.8.2 From de0251953d6196a5931fc991d9e2a595d20ac46c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 9 Apr 2019 17:46:33 +0200 Subject: [PATCH 067/101] Update composer deps --- composer.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 05df052f8..849e32752 100644 --- a/composer.lock +++ b/composer.lock @@ -64,16 +64,16 @@ }, { "name": "composer/semver", - "version": "1.4.2", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e", + "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e", "shasum": "" }, "require": { @@ -122,28 +122,27 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2019-03-19T17:25:45+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2" + "reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d", + "reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" }, "type": "library", "extra": { @@ -183,7 +182,7 @@ "spdx", "validator" ], - "time": "2018-11-01T09:45:54+00:00" + "time": "2019-03-26T10:23:26+00:00" }, { "name": "composer/xdebug-handler", @@ -1360,6 +1359,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, { From 266a41e0464c8ccf23949e3794189dc4ccf3caba Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Tue, 9 Apr 2019 10:55:33 -0700 Subject: [PATCH 068/101] Refactor sortPackageMap to depend on separate sortPackage function. --- src/Composer/Autoload/AutoloadGenerator.php | 54 +++++++++++++++------ src/Composer/Plugin/PluginManager.php | 7 +-- src/Composer/Util/PackageSorter.php | 10 ++++ 3 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/Composer/Util/PackageSorter.php diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 272c6b920..6fc602429 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -17,6 +17,7 @@ use Composer\EventDispatcher\EventDispatcher; use Composer\Installer\InstallationManager; use Composer\IO\IOInterface; use Composer\Package\AliasPackage; +use Composer\Package\Link; use Composer\Package\PackageInterface; use Composer\Repository\InstalledRepositoryInterface; use Composer\Util\Filesystem; @@ -956,27 +957,18 @@ INITIALIZER; * * Packages of equal weight retain the original order * - * @param array $packageMap + * @param array $packages * @return array */ - public function sortPackageMap(array $packageMap) - { - $packages = array(); - $paths = array(); + public function sortPackages(array $packages) { $usageList = array(); - foreach ($packageMap as $item) { - list($package, $path) = $item; - $name = $package->getName(); - $packages[$name] = $package; - $paths[$name] = $path; - - foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { + foreach ($packages as $package) { /** @var PackageInterface $package */ + foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { /** @var Link $link */ $target = $link->getTarget(); - $usageList[$target][] = $name; + $usageList[$target][] = $package->getName(); } } - $computing = array(); $computed = array(); $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) { @@ -1034,9 +1026,41 @@ INITIALIZER; $stable_sort($weightList); - $sortedPackageMap = array(); + $sortedPackages = array(); foreach (array_keys($weightList) as $name) { + $sortedPackages[] = $packages[$name]; + } + return $sortedPackages; + } + + /** + * Sorts packages by dependency weight + * + * Packages of equal weight retain the original order + * + * @param array $packageMap + * @return array + */ + public function sortPackageMap(array $packageMap) + { + $packages = array(); + $paths = array(); + + foreach ($packageMap as $item) { + list($package, $path) = $item; + $name = $package->getName(); + $packages[$name] = $package; + $paths[$name] = $path; + } + + $sortedPackages = $this->sortPackages($packages); + + + $sortedPackageMap = array(); + + foreach ($sortedPackages as $package) { + $name = $package->getName(); $sortedPackageMap[] = array($packages[$name], $paths[$name]); } diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index cca4efe54..3810992d0 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -255,11 +255,8 @@ class PluginManager { $packages = $repo->getPackages(); $generator = $this->composer->getAutoloadGenerator(); - $rootPackage = $this->composer->getPackage(); /** @var PackageInterface $rootPackage */ - $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $rootPackage, $packages); - $sortedPackageMap = array_reverse($generator->sortPackageMap($packageMap)); - foreach ($sortedPackageMap as $fullPackage) { - $package = $fullPackage[0]; /** @var PackageInterface $package */ + $sortedPackages = array_reverse($generator->sortPackages($packages)); + foreach ($sortedPackages as $package) { if (!($package instanceof CompletePackage)) { continue; } diff --git a/src/Composer/Util/PackageSorter.php b/src/Composer/Util/PackageSorter.php new file mode 100644 index 000000000..2899fc959 --- /dev/null +++ b/src/Composer/Util/PackageSorter.php @@ -0,0 +1,10 @@ + Date: Tue, 9 Apr 2019 10:58:36 -0700 Subject: [PATCH 069/101] Move sortPackages to static helper class. --- src/Composer/Autoload/AutoloadGenerator.php | 86 +-------------------- src/Composer/Plugin/PluginManager.php | 4 +- src/Composer/Util/PackageSorter.php | 82 ++++++++++++++++++++ 3 files changed, 86 insertions(+), 86 deletions(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 6fc602429..5637157e1 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -17,11 +17,11 @@ use Composer\EventDispatcher\EventDispatcher; use Composer\Installer\InstallationManager; use Composer\IO\IOInterface; use Composer\Package\AliasPackage; -use Composer\Package\Link; use Composer\Package\PackageInterface; use Composer\Repository\InstalledRepositoryInterface; use Composer\Util\Filesystem; use Composer\Script\ScriptEvents; +use Composer\Util\PackageSorter; /** * @author Igor Wiedler @@ -952,88 +952,6 @@ INITIALIZER; ); } - /** - * Sorts packages by dependency weight - * - * Packages of equal weight retain the original order - * - * @param array $packages - * @return array - */ - public function sortPackages(array $packages) { - $usageList = array(); - - foreach ($packages as $package) { /** @var PackageInterface $package */ - foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { /** @var Link $link */ - $target = $link->getTarget(); - $usageList[$target][] = $package->getName(); - } - } - $computing = array(); - $computed = array(); - $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) { - // reusing computed importance - if (isset($computed[$name])) { - return $computed[$name]; - } - - // canceling circular dependency - if (isset($computing[$name])) { - return 0; - } - - $computing[$name] = true; - $weight = 0; - - if (isset($usageList[$name])) { - foreach ($usageList[$name] as $user) { - $weight -= 1 - $computeImportance($user); - } - } - - unset($computing[$name]); - $computed[$name] = $weight; - - return $weight; - }; - - $weightList = array(); - - foreach ($packages as $name => $package) { - $weight = $computeImportance($name); - $weightList[$name] = $weight; - } - - $stable_sort = function (&$array) { - static $transform, $restore; - - $i = 0; - - if (!$transform) { - $transform = function (&$v, $k) use (&$i) { - $v = array($v, ++$i, $k, $v); - }; - - $restore = function (&$v, $k) { - $v = $v[3]; - }; - } - - array_walk($array, $transform); - asort($array); - array_walk($array, $restore); - }; - - $stable_sort($weightList); - - $sortedPackages = array(); - - foreach (array_keys($weightList) as $name) { - $sortedPackages[] = $packages[$name]; - } - return $sortedPackages; - } - /** * Sorts packages by dependency weight * @@ -1054,7 +972,7 @@ INITIALIZER; $paths[$name] = $path; } - $sortedPackages = $this->sortPackages($packages); + $sortedPackages = PackageSorter::sortPackages($packages); $sortedPackageMap = array(); diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 3810992d0..bb9b66d83 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -24,6 +24,7 @@ use Composer\Package\Link; use Composer\Semver\Constraint\Constraint; use Composer\DependencyResolver\Pool; use Composer\Plugin\Capability\Capability; +use Composer\Util\PackageSorter; /** * Plugin manager @@ -254,8 +255,7 @@ class PluginManager private function loadRepository(RepositoryInterface $repo) { $packages = $repo->getPackages(); - $generator = $this->composer->getAutoloadGenerator(); - $sortedPackages = array_reverse($generator->sortPackages($packages)); + $sortedPackages = array_reverse(PackageSorter::sortPackages($packages)); foreach ($sortedPackages as $package) { if (!($package instanceof CompletePackage)) { continue; diff --git a/src/Composer/Util/PackageSorter.php b/src/Composer/Util/PackageSorter.php index 2899fc959..8d8c9a06c 100644 --- a/src/Composer/Util/PackageSorter.php +++ b/src/Composer/Util/PackageSorter.php @@ -3,8 +3,90 @@ namespace Composer\Util; +use Composer\Package\Link; +use Composer\Package\PackageInterface; class PackageSorter { + /** + * Sorts packages by dependency weight + * + * Packages of equal weight retain the original order + * + * @param array $packages + * @return array + */ + public static function sortPackages(array $packages) { + $usageList = array(); + foreach ($packages as $package) { /** @var PackageInterface $package */ + foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { /** @var Link $link */ + $target = $link->getTarget(); + $usageList[$target][] = $package->getName(); + } + } + $computing = array(); + $computed = array(); + $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) { + // reusing computed importance + if (isset($computed[$name])) { + return $computed[$name]; + } + + // canceling circular dependency + if (isset($computing[$name])) { + return 0; + } + + $computing[$name] = true; + $weight = 0; + + if (isset($usageList[$name])) { + foreach ($usageList[$name] as $user) { + $weight -= 1 - $computeImportance($user); + } + } + + unset($computing[$name]); + $computed[$name] = $weight; + + return $weight; + }; + + $weightList = array(); + + foreach ($packages as $name => $package) { + $weight = $computeImportance($name); + $weightList[$name] = $weight; + } + + $stable_sort = function (&$array) { + static $transform, $restore; + + $i = 0; + + if (!$transform) { + $transform = function (&$v, $k) use (&$i) { + $v = array($v, ++$i, $k, $v); + }; + + $restore = function (&$v) { + $v = $v[3]; + }; + } + + array_walk($array, $transform); + asort($array); + array_walk($array, $restore); + }; + + $stable_sort($weightList); + + $sortedPackages = array(); + + foreach (array_keys($weightList) as $name) { + $sortedPackages[] = $packages[$name]; + } + return $sortedPackages; + } } From 3501423eabe7348a6f0db9f547e7e211ff5a4210 Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Tue, 9 Apr 2019 11:15:19 -0700 Subject: [PATCH 070/101] Undo previous change. --- src/Composer/Autoload/AutoloadGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 5637157e1..325fb2c87 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -960,7 +960,7 @@ INITIALIZER; * @param array $packageMap * @return array */ - public function sortPackageMap(array $packageMap) + protected function sortPackageMap(array $packageMap) { $packages = array(); $paths = array(); From dd40d74bf6041ddcefa1ebe46fb9117d031b1ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Tue, 9 Apr 2019 18:28:45 +0200 Subject: [PATCH 071/101] Exclude more files from being exported --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitattributes b/.gitattributes index 32378b23e..51b431136 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,3 +10,8 @@ # Exclude non-essential files from dist /tests export-ignore +.github export-ignore +.php_cs export-ignore +.travis.yml export-ignore +appveyor.yml export-ignore +phpunit.xml.dist export-ignore From a2b647a99eb92e123b7e36ab135baeb7b219207a Mon Sep 17 00:00:00 2001 From: ShiraNai7 Date: Thu, 11 Apr 2019 20:23:31 +0200 Subject: [PATCH 072/101] Handle absolute phar:// paths in autoload_static.php --- src/Composer/Autoload/AutoloadGenerator.php | 18 +++- .../Test/Autoload/AutoloadGeneratorTest.php | 41 +++++++++ .../Test/Autoload/Fixtures/autoload_phar.php | 13 +++ .../Autoload/Fixtures/autoload_phar_psr4.php | 13 +++ .../Fixtures/autoload_phar_static.php | 87 +++++++++++++++++++ 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_phar.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_phar_psr4.php create mode 100644 tests/Composer/Test/Autoload/Fixtures/autoload_phar_static.php diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 7ea1a3444..4d04f7a2f 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -545,7 +545,7 @@ EOF; } } - if (preg_match('/\.phar.+$/', $path)) { + if (strpos($path, '.phar') !== false) { $baseDir = "'phar://' . " . $baseDir; } @@ -769,10 +769,14 @@ HEADER; $filesystem = new Filesystem(); $vendorPathCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/"; + $vendorPharPathCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/"; $appBaseDirCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/"; + $appBaseDirPharCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/"; $absoluteVendorPathCode = ' => ' . substr(var_export(rtrim($vendorDir, '\\/') . '/', true), 0, -1); + $absoluteVendorPharPathCode = ' => ' . substr(var_export(rtrim('phar://' . $vendorDir, '\\/') . '/', true), 0, -1); $absoluteAppBaseDirCode = ' => ' . substr(var_export(rtrim($baseDir, '\\/') . '/', true), 0, -1); + $absoluteAppBaseDirPharCode = ' => ' . substr(var_export(rtrim('phar://' . $baseDir, '\\/') . '/', true), 0, -1); $initializer = ''; $prefix = "\0Composer\Autoload\ClassLoader\0"; @@ -795,9 +799,15 @@ HEADER; // See https://bugs.php.net/68057 $staticPhpVersion = 70000; } - $value = var_export($value, true); - $value = str_replace($absoluteVendorPathCode, $vendorPathCode, $value); - $value = str_replace($absoluteAppBaseDirCode, $appBaseDirCode, $value); + $value = strtr( + var_export($value, true), + array( + $absoluteVendorPathCode => $vendorPathCode, + $absoluteVendorPharPathCode => $vendorPharPathCode, + $absoluteAppBaseDirCode => $appBaseDirCode, + $absoluteAppBaseDirPharCode => $appBaseDirPharCode, + ) + ); $value = ltrim(preg_replace('/^ */m', ' $0$0', $value)); $file .= sprintf(" public static $%s = %s;\n\n", $prop, $value); diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index c1605bf97..84ac16df7 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -486,6 +486,47 @@ class AutoloadGeneratorTest extends TestCase $this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty."); } + public function testPharAutoload() + { + $package = new Package('a', '1.0', '1.0'); + $package->setRequires(array( + new Link('a', 'a/a'), + )); + + $package->setAutoload(array( + 'psr-0' => array( + 'Foo' => 'foo.phar', + 'Bar' => 'dir/bar.phar/src', + ), + 'psr-4' => array( + 'Baz\\' => 'baz.phar', + 'Qux\\' => 'dir/qux.phar/src', + ), + )); + + $vendorPackage = new Package('a/a', '1.0', '1.0'); + $vendorPackage->setAutoload(array( + 'psr-0' => array( + 'Lorem' => 'lorem.phar', + 'Ipsum' => 'dir/ipsum.phar/src', + ), + 'psr-4' => array( + 'Dolor\\' => 'dolor.phar', + 'Sit\\' => 'dir/sit.phar/src', + ), + )); + + $this->repository->expects($this->once()) + ->method('getCanonicalPackages') + ->will($this->returnValue(array($vendorPackage))); + + $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, 'Phar'); + + $this->assertAutoloadFiles('phar', $this->vendorDir . '/composer'); + $this->assertAutoloadFiles('phar_psr4', $this->vendorDir . '/composer', 'psr4'); + $this->assertAutoloadFiles('phar_static', $this->vendorDir . '/composer', 'static'); + } + public function testPSRToClassMapIgnoresNonExistingDir() { $package = new Package('a', '1.0', '1.0'); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_phar.php b/tests/Composer/Test/Autoload/Fixtures/autoload_phar.php new file mode 100644 index 000000000..7654005f3 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_phar.php @@ -0,0 +1,13 @@ + array('phar://' . $vendorDir . '/a/a/lorem.phar'), + 'Ipsum' => array('phar://' . $vendorDir . '/a/a/dir/ipsum.phar/src'), + 'Foo' => array('phar://' . $baseDir . '/foo.phar'), + 'Bar' => array('phar://' . $baseDir . '/dir/bar.phar/src'), +); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_phar_psr4.php b/tests/Composer/Test/Autoload/Fixtures/autoload_phar_psr4.php new file mode 100644 index 000000000..f6142a001 --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_phar_psr4.php @@ -0,0 +1,13 @@ + array('phar://' . $vendorDir . '/a/a/dir/sit.phar/src'), + 'Qux\\' => array('phar://' . $baseDir . '/dir/qux.phar/src'), + 'Dolor\\' => array('phar://' . $vendorDir . '/a/a/dolor.phar'), + 'Baz\\' => array('phar://' . $baseDir . '/baz.phar'), +); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_phar_static.php b/tests/Composer/Test/Autoload/Fixtures/autoload_phar_static.php new file mode 100644 index 000000000..486a5c0dc --- /dev/null +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_phar_static.php @@ -0,0 +1,87 @@ + + array ( + 'Sit\\' => 4, + ), + 'Q' => + array ( + 'Qux\\' => 4, + ), + 'D' => + array ( + 'Dolor\\' => 6, + ), + 'B' => + array ( + 'Baz\\' => 4, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Sit\\' => + array ( + 0 => 'phar://' . __DIR__ . '/..' . '/a/a/dir/sit.phar/src', + ), + 'Qux\\' => + array ( + 0 => 'phar://' . __DIR__ . '/../..' . '/dir/qux.phar/src', + ), + 'Dolor\\' => + array ( + 0 => 'phar://' . __DIR__ . '/..' . '/a/a/dolor.phar', + ), + 'Baz\\' => + array ( + 0 => 'phar://' . __DIR__ . '/../..' . '/baz.phar', + ), + ); + + public static $prefixesPsr0 = array ( + 'L' => + array ( + 'Lorem' => + array ( + 0 => 'phar://' . __DIR__ . '/..' . '/a/a/lorem.phar', + ), + ), + 'I' => + array ( + 'Ipsum' => + array ( + 0 => 'phar://' . __DIR__ . '/..' . '/a/a/dir/ipsum.phar/src', + ), + ), + 'F' => + array ( + 'Foo' => + array ( + 0 => 'phar://' . __DIR__ . '/../..' . '/foo.phar', + ), + ), + 'B' => + array ( + 'Bar' => + array ( + 0 => 'phar://' . __DIR__ . '/../..' . '/dir/bar.phar/src', + ), + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitPhar::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitPhar::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInitPhar::$prefixesPsr0; + + }, null, ClassLoader::class); + } +} From 794234946c3b06e942e3d153ad08a9ba8d3a37df Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Apr 2019 16:23:38 +0200 Subject: [PATCH 073/101] Let curl handle proxy and cipher list itself --- src/Composer/Util/Http/CurlDownloader.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 989e63d12..f7ae28a24 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -51,11 +51,9 @@ class CurlDownloader 'http' => array( 'method' => CURLOPT_CUSTOMREQUEST, 'content' => CURLOPT_POSTFIELDS, - 'proxy' => CURLOPT_PROXY, 'header' => CURLOPT_HTTPHEADER, ), 'ssl' => array( - 'ciphers' => CURLOPT_SSL_CIPHER_LIST, 'cafile' => CURLOPT_CAINFO, 'capath' => CURLOPT_CAPATH, ), From 4e14ac7640eed7833b2aa780a84e5b068b465ecd Mon Sep 17 00:00:00 2001 From: Gregor Hyneck Date: Tue, 30 Apr 2019 13:46:17 +0200 Subject: [PATCH 074/101] Add documentation how to run plugins manually --- doc/articles/plugins.md | 5 +++++ doc/articles/scripts.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/articles/plugins.md b/doc/articles/plugins.md index 228cbac9e..86e24d87b 100644 --- a/doc/articles/plugins.md +++ b/doc/articles/plugins.md @@ -261,6 +261,11 @@ Now the `custom-plugin-command` is available alongside Composer commands. > _Composer commands are based on the [Symfony Console Component][10]._ +## Running plugins manually + +Plugins for an event can be run manually by the `run-script` command. This works the same way as +[running scripts manually](scripts.md#running-scripts-manually). + ## Using Plugins Plugin packages are automatically loaded as soon as they are installed and will diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index e0c27b10f..a3c3ab091 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -189,7 +189,7 @@ composer run-script [--dev] [--no-dev] script ``` For example `composer run-script post-install-cmd` will run any -**post-install-cmd** scripts that have been defined. +**post-install-cmd** scripts and [plugins](plugins.md) that have been defined. You can also give additional arguments to the script handler by appending `--` followed by the handler arguments. e.g. From e33560a33f4c137aed8923f254b581dcf61b5aa8 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 30 Apr 2019 14:07:46 +0200 Subject: [PATCH 075/101] Fixed 2.0 branch alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3a18fe45b..725f211e1 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "2.0-dev" } }, "autoload": { From e37ffb2a44df9cd8c7ab7c667a225a930db9698f Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Tue, 30 Apr 2019 16:38:03 +0100 Subject: [PATCH 076/101] Fix: Bitbucket getChangeDate throws exception for branches containing a slash --- src/Composer/Repository/Vcs/BitbucketDriver.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Composer/Repository/Vcs/BitbucketDriver.php b/src/Composer/Repository/Vcs/BitbucketDriver.php index 556ca5012..730edec3c 100644 --- a/src/Composer/Repository/Vcs/BitbucketDriver.php +++ b/src/Composer/Repository/Vcs/BitbucketDriver.php @@ -218,6 +218,13 @@ abstract class BitbucketDriver extends VcsDriver return $this->fallbackDriver->getChangeDate($identifier); } + if (strpos($identifier, '/') !== false) { + $branches = $this->getBranches(); + if (isset($branches[$identifier])) { + $identifier = $branches[$identifier]; + } + } + $resource = sprintf( 'https://api.bitbucket.org/2.0/repositories/%s/%s/commit/%s?fields=date', $this->owner, From c35a3c1c071be68fabfb4862dcb7f861d0f053ad Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 2 May 2019 09:35:13 +0200 Subject: [PATCH 077/101] update composer.lock --- composer.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.lock b/composer.lock index c678c96ea..eb15db515 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b078b12b2912d599e0c6904f64def484", + "content-hash": "280f5d5184039085b5f22236d267ae82", "packages": [ { "name": "composer/ca-bundle", @@ -1404,7 +1404,6 @@ "mock", "xunit" ], - "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, { From 5d615a16d175fcbdb67a536ef9d6fc4e8a1f6f2b Mon Sep 17 00:00:00 2001 From: Kevin Boyd Date: Wed, 10 Apr 2019 10:44:35 -0700 Subject: [PATCH 078/101] Add documentation for Composer\\Config::disableProcessTimeout --- doc/06-config.md | 14 ++++++++++++++ doc/articles/scripts.md | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/doc/06-config.md b/doc/06-config.md index 87d73f8a1..f3afc4eb1 100644 --- a/doc/06-config.md +++ b/doc/06-config.md @@ -9,6 +9,20 @@ Defaults to `300`. The duration processes like git clones can run before Composer assumes they died out. You may need to make this higher if you have a slow connection or huge vendors. +To disable the process timeout on a custom command under `scripts`, a static +helper is available: + +```json +{ + "scripts": { + "test": [ + "Composer\\Config::disableProcessTimeout", + "phpunit" + ] + } +} +``` + ## use-include-path Defaults to `false`. If `true`, the Composer autoloader will also look for classes diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index e0c27b10f..52ed86073 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -221,6 +221,26 @@ to the `phpunit` script. > are easily accessible. In this example no matter if the `phpunit` binary is > actually in `vendor/bin/phpunit` or `bin/phpunit` it will be found and executed. +Although Composer is not intended to manage long-running processes and other +such aspects of PHP projects, it can sometimes be handy to disable the process +timeout on custom commands. This timeout defaults to 300 seconds and can be +overridden for all commands using the config key `process-timeout`, or for +specific commands using an argument to the `run-script` command. + +A static helper also exists that can disable the process timeout for a specific +script directly in composer.json: + +```json +{ + "scripts": { + "test": [ + "Composer\\Config::disableProcessTimeout", + "phpunit" + ] + } +} +``` + ## Referencing scripts To enable script re-use and avoid duplicates, you can call a script from another From 51753bc08ce443e42ec9893a2836a58b476b0653 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 8 May 2019 14:58:46 +0200 Subject: [PATCH 079/101] fixes #8131 --- src/Composer/Json/JsonManipulator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index 40c0c09a2..8fe6a9f0a 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -22,7 +22,7 @@ class JsonManipulator private static $DEFINES = '(?(DEFINE) (? -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? ) (? true | false | null ) - (? " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ) + (? " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " ) (? \[ (?: (?&json) \s* (?: , (?&json) \s* )* )? \s* \] ) (? \s* (?&string) \s* : (?&json) \s* ) (? \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} ) From 080b0f27e9ac283345b6080ab0999ac49e3c24ac Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 8 May 2019 15:58:02 +0200 Subject: [PATCH 080/101] add missing testcase --- .../Test/Json/JsonManipulatorTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 05de454ca..d8bc7c200 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -2374,6 +2374,26 @@ class JsonManipulatorTest extends TestCase "package/a": "*" } } +', $manipulator->getContents()); + } + + public function testEscapedUnicodeDoesNotCauseBacktrackLimitErrorGithubIssue8131() + { + $manipulator = new JsonManipulator('{ + "description": "Some U\u00F1icode", + "require": { + "foo/bar": "^1.0" + } +}'); + + $this->assertTrue($manipulator->addLink('require', 'foo/baz', '^1.0')); + $this->assertEquals('{ + "description": "Some U\u00F1icode", + "require": { + "foo/bar": "^1.0", + "foo/baz": "^1.0" + } +} ', $manipulator->getContents()); } } From 8288d2c456287d4ec2d746db1d285d6bd82d52ec Mon Sep 17 00:00:00 2001 From: Sam L Date: Wed, 1 May 2019 11:25:26 -0400 Subject: [PATCH 081/101] Display branches and tags if verbose is specified --- src/Composer/Repository/VcsRepository.php | 61 ++++++++++++----------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index edd0dabf8..8d8bcbdca 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -30,7 +30,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt { protected $url; protected $packageName; - protected $verbose; + protected $isVerbose; + protected $isVeryVerbose; protected $io; protected $config; protected $versionParser; @@ -64,7 +65,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $this->url = $repoConfig['url']; $this->io = $io; $this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs'; - $this->verbose = $io->isVeryVerbose(); + $this->isVerbose = $io->isVerbose(); + $this->isVeryVerbose = $io->isVeryVerbose(); $this->config = $config; $this->repoConfig = $repoConfig; $this->versionCache = $versionCache; @@ -127,7 +129,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt { parent::initialize(); - $verbose = $this->verbose; + $isVerbose = $this->isVerbose; + $isVeryVerbose = $this->isVeryVerbose; $driver = $this->getDriver(); if (!$driver) { @@ -145,23 +148,23 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $this->packageName = !empty($data['name']) ? $data['name'] : null; } } catch (\Exception $e) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().''); } } foreach ($driver->getTags() as $tag => $identifier) { $msg = 'Reading composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $tag . ')'; - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError($msg); - } else { + } elseif ($isVerbose) { $this->io->overwriteError($msg, false); } // strip the release- prefix from tags if present $tag = str_replace('release-', '', $tag); - $cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $verbose); + $cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $isVerbose, $isVeryVerbose); if ($cachedPackage) { $this->addPackage($cachedPackage); @@ -173,7 +176,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt } if (!$parsedTag = $this->validateTag($tag)) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped tag '.$tag.', invalid tag name'); } continue; @@ -181,7 +184,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt try { if (!$data = $driver->getComposerInformation($identifier)) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped tag '.$tag.', no composer file'); } $this->emptyReferences[] = $identifier; @@ -203,7 +206,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt // broken package, version doesn't match tag if ($data['version_normalized'] !== $parsedTag) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json'); } continue; @@ -211,13 +214,13 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $tagPackageName = isset($data['name']) ? $data['name'] : $this->packageName; if ($existingPackage = $this->findPackage($tagPackageName, $data['version_normalized'])) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped tag '.$tag.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$data['version_normalized'].' internally'); } continue; } - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Importing tag '.$tag.' ('.$data['version_normalized'].')'); } @@ -226,35 +229,35 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($e instanceof TransportException && $e->getCode() === 404) { $this->emptyReferences[] = $identifier; } - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).''); } continue; } } - if (!$verbose) { + if (!$isVeryVerbose) { $this->io->overwriteError('', false); } $branches = $driver->getBranches(); foreach ($branches as $branch => $identifier) { $msg = 'Reading composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $branch . ')'; - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError($msg); - } else { + } elseif ($isVerbose) { $this->io->overwriteError($msg, false); } if ($branch === 'trunk' && isset($branches['master'])) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped branch '.$branch.', can not parse both master and trunk branches as they both resolve to 9999999-dev internally'); } continue; } if (!$parsedBranch = $this->validateBranch($branch)) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped branch '.$branch.', invalid name'); } continue; @@ -268,7 +271,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $version = $prefix . preg_replace('{(\.9{7})+}', '.x', $parsedBranch); } - $cachedPackage = $this->getCachedPackageVersion($version, $identifier, $verbose); + $cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose); if ($cachedPackage) { $this->addPackage($cachedPackage); @@ -281,7 +284,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt try { if (!$data = $driver->getComposerInformation($identifier)) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped branch '.$branch.', no composer file'); } $this->emptyReferences[] = $identifier; @@ -292,7 +295,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $data['version'] = $version; $data['version_normalized'] = $parsedBranch; - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Importing branch '.$branch.' ('.$data['version'].')'); } @@ -306,12 +309,12 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($e->getCode() === 404) { $this->emptyReferences[] = $identifier; } - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped branch '.$branch.', no composer file was found'); } continue; } catch (\Exception $e) { - if (!$verbose) { + if (!$isVeryVerbose) { $this->io->writeError(''); } $this->branchErrorOccurred = true; @@ -322,7 +325,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt } $driver->cleanup(); - if (!$verbose) { + if (!$isVeryVerbose) { $this->io->overwriteError('', false); } @@ -367,7 +370,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt return false; } - private function getCachedPackageVersion($version, $identifier, $verbose) + private function getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose) { if (!$this->versionCache) { return; @@ -375,7 +378,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt $cachedPackage = $this->versionCache->getVersionPackage($version, $identifier); if ($cachedPackage === false) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped '.$version.', no composer file (cached from ref '.$identifier.')'); } @@ -384,14 +387,14 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt if ($cachedPackage) { $msg = 'Found cached composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $version . ')'; - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError($msg); - } else { + } elseif ($isVerbose) { $this->io->overwriteError($msg, false); } if ($existingPackage = $this->findPackage($cachedPackage['name'], $cachedPackage['version_normalized'])) { - if ($verbose) { + if ($isVeryVerbose) { $this->io->writeError('Skipped cached version '.$version.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$cachedPackage['version_normalized'].' internally'); } $cachedPackage = null; From c7519144105bf319fd7ce437f9733b3cdc443ce7 Mon Sep 17 00:00:00 2001 From: pfofi <7479939+pfofi@users.noreply.github.com> Date: Fri, 10 May 2019 13:55:31 +0200 Subject: [PATCH 082/101] Fix URL resolution for Composer repositories Composer was unable canonicalize URLs in non-HTTP(S) Composer repositories. For example it was not possible to use a `providers-url` in a repository loaded via the `file://` scheme. See also: #8115 --- .../Repository/ComposerRepository.php | 6 +- .../Repository/ComposerRepositoryTest.php | 67 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 38b865103..1b03885fe 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -562,7 +562,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito protected function canonicalizeUrl($url) { if ('/' === $url[0]) { - return preg_replace('{(https?://[^/]+).*}i', '$1' . $url, $this->url); + if (preg_match('{[^:]+://[^/]*}', $this->url, $matches)) { + return $matches[0] . $url; + } + + return $this->url; } return $url; diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 3e29e8023..8e9216b35 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -204,4 +204,71 @@ class ComposerRepositoryTest extends TestCase $repository->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'library') ); } + + /** + * @dataProvider canonicalizeUrlProvider + * + * @param string $expected + * @param string $url + * @param string $repositoryUrl + */ + public function testCanonicalizeUrl($expected, $url, $repositoryUrl) + { + $repository = new ComposerRepository( + array('url' => $repositoryUrl), + new NullIO(), + FactoryMock::createConfig() + ); + + $object = new \ReflectionObject($repository); + + $method = $object->getMethod('canonicalizeUrl'); + $method->setAccessible(true); + + // ComposerRepository::__construct ensures that the repository URL has a + // protocol, so reset it here in order to test all cases. + $property = $object->getProperty('url'); + $property->setAccessible(true); + $property->setValue($repository, $repositoryUrl); + + $this->assertSame($expected, $method->invoke($repository, $url)); + } + + public function canonicalizeUrlProvider() + { + return array( + array( + 'https://example.org/path/to/file', + '/path/to/file', + 'https://example.org', + ), + array( + 'https://example.org/canonic_url', + 'https://example.org/canonic_url', + 'https://should-not-see-me.test', + ), + array( + 'file:///path/to/repository/file', + '/path/to/repository/file', + 'file:///path/to/repository', + ), + array( + // Assert that the repository URL is returned unchanged if it is + // not a URL. + // (Backward compatibility test) + 'invalid_repo_url', + '/path/to/file', + 'invalid_repo_url', + ), + array( + // Assert that URLs can contain sequences resembling pattern + // references as understood by preg_replace() without messing up + // the result. + // (Regression test) + 'https://example.org/path/to/unusual_$0_filename', + '/path/to/unusual_$0_filename', + 'https://example.org', + ), + ); + } } From e7f02be9ffec80384df5d49e463d9f127d6957bc Mon Sep 17 00:00:00 2001 From: pfofi <7479939+pfofi@users.noreply.github.com> Date: Sat, 11 May 2019 16:27:39 +0200 Subject: [PATCH 083/101] Anchor pattern --- src/Composer/Repository/ComposerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 1b03885fe..8fc40c812 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -562,7 +562,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito protected function canonicalizeUrl($url) { if ('/' === $url[0]) { - if (preg_match('{[^:]+://[^/]*}', $this->url, $matches)) { + if (preg_match('{^[^:]+://[^/]*}', $this->url, $matches)) { return $matches[0] . $url; } From ce8afe1c95c2594fa0a26c0b13d95df05f993754 Mon Sep 17 00:00:00 2001 From: Guilherme Rossato Date: Mon, 13 May 2019 10:26:27 -0300 Subject: [PATCH 084/101] Document the alternatives to disable the default script timeout Mentioning and giving an example of the usage of the 4 options to disable the default script timeout of 300 seconds: 1. Static helper (already exists and kept). 2. Config key "process-timeout". 3. Environment variable "COMPOSER_PROCESS_TIMEOUT". 4. The "--timeout" parameter. --- doc/articles/scripts.md | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 52ed86073..99ffd94dc 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -224,11 +224,13 @@ to the `phpunit` script. Although Composer is not intended to manage long-running processes and other such aspects of PHP projects, it can sometimes be handy to disable the process timeout on custom commands. This timeout defaults to 300 seconds and can be -overridden for all commands using the config key `process-timeout`, or for -specific commands using an argument to the `run-script` command. +overridden in a variety of ways depending on the desired effect: it's possible +to disable it for all command using the config key `process-timeout`, or for +a specific call using the `--timeout` parameter of the `run` (`run-scripts`) +command, or using a static helper for specific scripts. -A static helper also exists that can disable the process timeout for a specific -script directly in composer.json: +To disable the timeout for specific scripts with the static helper directly in +composer.json: ```json { @@ -241,6 +243,31 @@ script directly in composer.json: } ``` +To disable the timeout for every script on a given project, you can use the +composer.json configuration: + +```json +{ + "config": { + "process-timeout": 0 + } +} +``` + +It's also possible to set the global environment variable to disable the timeout +of all following scripts in the current terminal environment: + +``` +export COMPOSER_PROCESS_TIMEOUT=0 +``` + +To disable the timeout of a single script call, you must use the `run` composer +command and specify the `--timeout` parameter: + +``` +composer run test --timeout=0 +``` + ## Referencing scripts To enable script re-use and avoid duplicates, you can call a script from another From 1976da9ee951e1c7027b25b364d68b7b7aa10257 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 14 May 2019 10:18:13 +0200 Subject: [PATCH 085/101] modify text --- doc/articles/scripts.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 99ffd94dc..18417bfef 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -224,10 +224,13 @@ to the `phpunit` script. Although Composer is not intended to manage long-running processes and other such aspects of PHP projects, it can sometimes be handy to disable the process timeout on custom commands. This timeout defaults to 300 seconds and can be -overridden in a variety of ways depending on the desired effect: it's possible -to disable it for all command using the config key `process-timeout`, or for -a specific call using the `--timeout` parameter of the `run` (`run-scripts`) -command, or using a static helper for specific scripts. +overridden in a variety of ways depending on the desired effect: + +- disable it for all commands using the config key `process-timeout`, +- disable it for the current or future invocations of composer using the + environment variable `COMPOSER_PROCESS_TIMEOUT`, +- for a specific invocation using the `--timeout` flag of the `run-script` command, +- using a static helper for specific scripts. To disable the timeout for specific scripts with the static helper directly in composer.json: From 7f34189f91a06531bb8a8a3afcb9cf88f03fdbc7 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 14 May 2019 10:19:37 +0200 Subject: [PATCH 086/101] use full command name, not abbreviated/alias --- doc/articles/scripts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 18417bfef..771093610 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -264,11 +264,11 @@ of all following scripts in the current terminal environment: export COMPOSER_PROCESS_TIMEOUT=0 ``` -To disable the timeout of a single script call, you must use the `run` composer +To disable the timeout of a single script call, you must use the `run-script` composer command and specify the `--timeout` parameter: ``` -composer run test --timeout=0 +composer run-script test --timeout=0 ``` ## Referencing scripts From d63bf33848f396c58c5e0de834cf15f9d7094b95 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 14 May 2019 10:20:32 +0200 Subject: [PATCH 087/101] flag should come before script name --- doc/articles/scripts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 771093610..9516b82bc 100644 --- a/doc/articles/scripts.md +++ b/doc/articles/scripts.md @@ -268,7 +268,7 @@ To disable the timeout of a single script call, you must use the `run-script` co command and specify the `--timeout` parameter: ``` -composer run-script test --timeout=0 +composer run-script --timeout=0 test ``` ## Referencing scripts From faa7c5eea2de7e053f38c0726c01147531687361 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 19 May 2019 20:52:53 +0200 Subject: [PATCH 088/101] Allow overriding self-update target file with envvar COMPOSER_SELF_UPDATE_TARGET Useful if Composer is provided on a read-only filesystems, to allow self-update to work with a different destination --- src/Composer/Command/SelfUpdateCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 78b27460e..226aafeb5 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -351,6 +351,10 @@ TAGSPUBKEY @copy($localFilename, $backupTarget); } + if ($targetFilename = getenv('COMPOSER_SELF_UPDATE_TARGET')) { + $localFilename = realpath($targetFilename) ?: $targetFilename; + } + rename($newFilename, $localFilename); return null; From bd6b758a1be2ffd722690e27e83a0ab685a06d37 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 29 May 2019 08:45:05 +0200 Subject: [PATCH 089/101] fixes #8159 expand interface and add missing methods to aliaspackage --- src/Composer/Package/AliasPackage.php | 10 ++++++++ src/Composer/Package/PackageInterface.php | 28 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php index 09ed4fb9b..89f197856 100644 --- a/src/Composer/Package/AliasPackage.php +++ b/src/Composer/Package/AliasPackage.php @@ -401,4 +401,14 @@ class AliasPackage extends BasePackage implements CompletePackageInterface { return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')'; } + + public function setDistUrl($url) + { + return $this->aliasOf->setDistUrl($url); + } + + public function setDistType($type) + { + return $this->aliasOf->setDistType($type); + } } diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 73d2ade41..cb16efa7e 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -358,4 +358,32 @@ interface PackageInterface * @return array */ public function getTransportOptions(); + + /** + * @param string $reference + * + * @return void + */ + public function setSourceReference($reference); + + /** + * @param string $url + * + * @return void + */ + public function setDistUrl($url); + + /** + * @param string $type + * + * @return void + */ + public function setDistType($type); + + /** + * @param string $reference + * + * @return void + */ + public function setDistReference($reference); } From 9d79c69199b348789981e99ee3cf192f36337e1d Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Mon, 27 May 2019 19:54:30 +0100 Subject: [PATCH 090/101] Update xdebug-handler to 1.3.3 --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index 849e32752..08679183c 100644 --- a/composer.lock +++ b/composer.lock @@ -186,16 +186,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "d17708133b6c276d6e42ef887a877866b909d892" + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/d17708133b6c276d6e42ef887a877866b909d892", - "reference": "d17708133b6c276d6e42ef887a877866b909d892", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", "shasum": "" }, "require": { @@ -226,7 +226,7 @@ "Xdebug", "performance" ], - "time": "2019-01-28T20:25:53+00:00" + "time": "2019-05-27T17:52:04+00:00" }, { "name": "justinrainbow/json-schema", From 82825ccc74b977a86010dc78a80502e0dd5dc5dd Mon Sep 17 00:00:00 2001 From: pfofi <7479939+pfofi@users.noreply.github.com> Date: Fri, 7 Jun 2019 09:13:11 +0200 Subject: [PATCH 091/101] Use possessive quantifiers --- src/Composer/Repository/ComposerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 8fc40c812..9d5b727cc 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -562,7 +562,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito protected function canonicalizeUrl($url) { if ('/' === $url[0]) { - if (preg_match('{^[^:]+://[^/]*}', $this->url, $matches)) { + if (preg_match('{^[^:]++://[^/]*+}', $this->url, $matches)) { return $matches[0] . $url; } From 659c72f9c8db708ea6490b9daf8195e2ad7319ab Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 7 Jun 2019 13:11:53 +0200 Subject: [PATCH 092/101] Read classmap-authoritative and apcu-autoloader from project config when installing via create-project, fixes #8155 --- src/Composer/Command/CreateProjectCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 3702c3595..2985aa57a 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -184,7 +184,9 @@ EOT ->setRunScripts(!$noScripts) ->setIgnorePlatformRequirements($ignorePlatformReqs) ->setSuggestedPackagesReporter($this->suggestedPackagesReporter) - ->setOptimizeAutoloader($config->get('optimize-autoloader')); + ->setOptimizeAutoloader($config->get('optimize-autoloader')) + ->setClassMapAuthoritative($config->get('classmap-authoritative')) + ->setApcuAutoloader($config->get('apcu-autoloader')); if ($disablePlugins) { $installer->disablePlugins(); From 088fb56c3d6f1264760d495d40edf7569ee83068 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 7 Jun 2019 16:27:40 +0200 Subject: [PATCH 093/101] Fix display of HHVM warning appearing when HHVM is not in use, fixes #8138 --- src/Composer/DependencyResolver/Problem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 073f64e2d..c7e529889 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -106,7 +106,7 @@ class Problem $msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but '; - if (defined('HHVM_VERSION') || count($available)) { + if (defined('HHVM_VERSION') || (count($available) && $job['packageName'] === 'hhvm')) { return $msg . 'your HHVM version does not satisfy that requirement.'; } From e7eecc6901698ea352bff11ccabe5a1b6a6122c6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 7 Jun 2019 16:49:07 +0200 Subject: [PATCH 094/101] Add docs for COMPOSER_SELF_UPDATE_TARGET, refs #8151 --- doc/03-cli.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/03-cli.md b/doc/03-cli.md index 6460e9e1d..5fc527c49 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -917,6 +917,10 @@ if you use Composer as super user at all times like in docker containers. If set, the value is used as php's memory_limit. +### COMPOSER_SELF_UPDATE_TARGET + +If set, makes the self-update command write the new Composer phar file into that path instead of overwriting itself. Useful for updating Composer on read-only filesystem. + ### COMPOSER_MIRROR_PATH_REPOS If set to 1, this env changes the default path repository strategy to `mirror` instead From b4e5db1c7055ede2952cb8f77f03cc9aafe00f09 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 7 Jun 2019 17:24:34 +0200 Subject: [PATCH 095/101] Revert "Allow overriding self-update target file with envvar COMPOSER_SELF_UPDATE_TARGET" Revert "Add docs for COMPOSER_SELF_UPDATE_TARGET, refs #8151" This reverts commit e7eecc6901698ea352bff11ccabe5a1b6a6122c6. This reverts commit faa7c5eea2de7e053f38c0726c01147531687361. --- doc/03-cli.md | 4 ---- src/Composer/Command/SelfUpdateCommand.php | 4 ---- 2 files changed, 8 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 5fc527c49..6460e9e1d 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -917,10 +917,6 @@ if you use Composer as super user at all times like in docker containers. If set, the value is used as php's memory_limit. -### COMPOSER_SELF_UPDATE_TARGET - -If set, makes the self-update command write the new Composer phar file into that path instead of overwriting itself. Useful for updating Composer on read-only filesystem. - ### COMPOSER_MIRROR_PATH_REPOS If set to 1, this env changes the default path repository strategy to `mirror` instead diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 226aafeb5..78b27460e 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -351,10 +351,6 @@ TAGSPUBKEY @copy($localFilename, $backupTarget); } - if ($targetFilename = getenv('COMPOSER_SELF_UPDATE_TARGET')) { - $localFilename = realpath($targetFilename) ?: $targetFilename; - } - rename($newFilename, $localFilename); return null; From b73120cbbe16f758f3e9189d49970a8627211a9f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 11 Jun 2019 15:02:45 +0200 Subject: [PATCH 096/101] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c079b6922..a150aaad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### [1.8.6] 2019-06-11 + + * Fixed handling of backslash-escapes handling in compoesr.json when using the require command + * Fixed create-project not following classmap-authoritative and apcu-autoloader config values + * Fixed HHVM version warning showing up in some cases when it was not in use + ### [1.8.5] 2019-04-09 * HHVM 4.0 is no longer compatible with Composer. Please use PHP instead going forward. @@ -745,6 +751,7 @@ * Initial release +[1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6 [1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5 [1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4 [1.8.3]: https://github.com/composer/composer/compare/1.8.2...1.8.3 From 76da8d792eeae2e5e136c78454ed5bc9e8aee7d6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 11 Jun 2019 15:08:33 +0200 Subject: [PATCH 097/101] Update deps --- composer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index febcdbe86..8b7b3cb57 100644 --- a/composer.lock +++ b/composer.lock @@ -436,7 +436,7 @@ }, { "name": "symfony/console", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/console.git", @@ -497,7 +497,7 @@ }, { "name": "symfony/debug", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -554,7 +554,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -604,7 +604,7 @@ }, { "name": "symfony/finder", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -653,16 +653,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "reference": "82ebae02209c21113908c229e9883c419720738a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", + "reference": "82ebae02209c21113908c229e9883c419720738a", "shasum": "" }, "require": { @@ -674,7 +674,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.11-dev" } }, "autoload": { @@ -707,20 +707,20 @@ "polyfill", "portable" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2019-02-06T07:57:58+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", + "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", "shasum": "" }, "require": { @@ -732,7 +732,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.11-dev" } }, "autoload": { @@ -766,11 +766,11 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2019-02-06T07:57:58+00:00" }, { "name": "symfony/process", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -1736,7 +1736,7 @@ }, { "name": "symfony/yaml", - "version": "v2.8.49", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From 6c76310810ebdbdfd004441f42509fd2d6640907 Mon Sep 17 00:00:00 2001 From: "Theodore R. Smith" Date: Tue, 11 Jun 2019 09:35:51 -0500 Subject: [PATCH 098/101] [minor] Fixed a typo in the CHANGELOG.md. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a150aaad8..2e6075148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### [1.8.6] 2019-06-11 - * Fixed handling of backslash-escapes handling in compoesr.json when using the require command + * Fixed handling of backslash-escapes handling in composer.json when using the require command * Fixed create-project not following classmap-authoritative and apcu-autoloader config values * Fixed HHVM version warning showing up in some cases when it was not in use From 7399638e43fb7e7c361efe8ec38b0baf3fc49676 Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Tue, 11 Jun 2019 13:33:05 +0200 Subject: [PATCH 099/101] fixes #8179 --- src/Composer/Repository/Vcs/HgDriver.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 45f13d5fe..f943a8a0a 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -61,8 +61,9 @@ class HgDriver extends VcsDriver // clean up directory and do a fresh clone into it $fs->removeDirectory($this->repoDir); - $command = function ($url) { - return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($this->repoDir)); + $repoDir = $this->repoDir; + $command = function ($url) use ($repoDir) { + return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); }; $hgUtils->runCommand($command, $this->url, $this->repoDir); From 89d5d8f1824d66163ee04761567c11e81f814a61 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Jun 2019 18:34:16 +0200 Subject: [PATCH 100/101] Free $solver asap --- src/Composer/Installer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 8573f3695..9583c3eb1 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -473,6 +473,8 @@ class Installer $solver = new Solver($policy, $pool, $installedRepo, $this->io); try { $operations = $solver->solve($request, $this->ignorePlatformReqs); + $ruleSetSize = $solver->getRuleSetSize(); + $solver = null; } catch (SolverProblemsException $e) { $this->io->writeError('Your requirements could not be resolved to an installable set of packages.', true, IOInterface::QUIET); $this->io->writeError($e->getMessage()); @@ -489,7 +491,7 @@ class Installer $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations); $this->io->writeError("Analyzed ".count($pool)." packages to resolve dependencies", true, IOInterface::VERBOSE); - $this->io->writeError("Analyzed ".$solver->getRuleSetSize()." rules to resolve dependencies", true, IOInterface::VERBOSE); + $this->io->writeError("Analyzed ".$ruleSetSize." rules to resolve dependencies", true, IOInterface::VERBOSE); // execute operations if (!$operations) { From 8da046e4e982b7a8c01b038b19242dc339847cd8 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Sun, 23 Jun 2019 18:59:36 +0100 Subject: [PATCH 101/101] SVN: hide passwords for debug output --- src/Composer/Util/ProcessExecutor.php | 1 + .../Test/Util/ProcessExecutorTest.php | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index f5e1ef610..d72a02981 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -51,6 +51,7 @@ class ProcessExecutor return '://'.$m['user'].':***@'; }, $command); + $safeCommand = preg_replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand); $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand); } diff --git a/tests/Composer/Test/Util/ProcessExecutorTest.php b/tests/Composer/Test/Util/ProcessExecutorTest.php index e98898417..db16b8c02 100644 --- a/tests/Composer/Test/Util/ProcessExecutorTest.php +++ b/tests/Composer/Test/Util/ProcessExecutorTest.php @@ -61,11 +61,25 @@ class ProcessExecutorTest extends TestCase ProcessExecutor::setTimeout(60); } - public function testHidePasswords() + /** + * @dataProvider hidePasswordProvider + */ + public function testHidePasswords($command, $expectedCommandOutput) { $process = new ProcessExecutor($buffer = new BufferIO('', StreamOutput::VERBOSITY_DEBUG)); - $process->execute('echo https://foo:bar@example.org/ && echo http://foo@example.org && echo http://abcdef1234567890234578:x-oauth-token@github.com/', $output); - $this->assertEquals('Executing command (CWD): echo https://foo:***@example.org/ && echo http://foo@example.org && echo http://***:***@github.com/', trim($buffer->getOutput())); + $process->execute($command, $output); + $this->assertEquals('Executing command (CWD): ' . $expectedCommandOutput, trim($buffer->getOutput())); + } + + public function hidePasswordProvider() + { + return array( + array('echo https://foo:bar@example.org/', 'echo https://foo:***@example.org/'), + array('echo http://foo@example.org', 'echo http://foo@example.org'), + array('echo http://abcdef1234567890234578:x-oauth-token@github.com/', 'echo http://***:***@github.com/'), + array("svn ls --verbose --non-interactive --username 'foo' --password 'bar' 'https://foo.example.org/svn/'", "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'"), + array("svn ls --verbose --non-interactive --username 'foo' --password 'bar \'bar' 'https://foo.example.org/svn/'", "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'"), + ); } public function testDoesntHidePorts()