From 079e501ac8676db4b793bff18da84388daeff55e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 27 Jan 2021 14:03:44 +0100 Subject: [PATCH 1/5] Revert "Merge pull request #9273 from nicolas-grekas/dev-version" This reverts commit d2d606ced201722dc56b759933bec4c688e7d994, reversing changes made to 4a8dbcd1451b7fd1e3537dee2302549587db8e2c. --- doc/05-repositories.md | 11 --------- .../Package/Loader/RootPackageLoader.php | 6 ++--- src/Composer/Repository/PathRepository.php | 5 ---- .../Package/Loader/RootPackageLoaderTest.php | 24 ------------------- .../path/with-branch-version/composer.json | 6 ----- .../Test/Repository/PathRepositoryTest.php | 24 ++----------------- 6 files changed, 4 insertions(+), 72 deletions(-) delete mode 100644 tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json diff --git a/doc/05-repositories.md b/doc/05-repositories.md index cd3266285..95881b078 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -658,17 +658,6 @@ the branch or tag that is currently checked out. Otherwise, the version should be explicitly defined in the package's `composer.json` file. If the version cannot be resolved by these means, it is assumed to be `dev-master`. -When the version cannot be inferred from the local VCS repository, you should use -the special `branch-version` entry under `extra` instead of `version`: - -```json -{ - "extra": { - "branch-version": "4.2-dev" - } -} -``` - The local package will be symlinked if possible, in which case the output in the console will read `Symlinking from ../../packages/my-package`. If symlinking is _not_ possible the package will be copied. In that case, the console will diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 5eceec97d..32118b113 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -81,10 +81,8 @@ class RootPackageLoader extends ArrayLoader if (!isset($config['version'])) { $commit = null; - if (isset($config['extra']['branch-version'])) { - $config['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $config['extra']['branch-version']).'.x-dev'; - } elseif (getenv('COMPOSER_ROOT_VERSION')) { - // override with env var if available + // override with env var if available + if (getenv('COMPOSER_ROOT_VERSION')) { $config['version'] = getenv('COMPOSER_ROOT_VERSION'); } else { $versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd()); diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index c3076e2e7..a0a6835b8 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -165,11 +165,6 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn ); $package['transport-options'] = $this->options; - // use the branch-version as the package version if available - if (!isset($package['version']) && isset($package['extra']['branch-version'])) { - $package['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $package['extra']['branch-version']).'.x-dev'; - } - // carry over the root package version if this path repo is in the same git repository as root package if (!isset($package['version']) && ($rootVersion = getenv('COMPOSER_ROOT_VERSION'))) { if ( diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php index c50cc77e0..858e95231 100644 --- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php @@ -201,28 +201,4 @@ class RootPackageLoaderTest extends TestCase $this->assertEquals("dev-latest-production", $package->getPrettyVersion()); } - - /** - * @dataProvider provideExtraBranchVersion - */ - public function testLoadExtraBranchVersion($branchVersion) - { - $package = $this->loadPackage(array( - 'extra' => array( - 'branch-version' => $branchVersion, - ), - )); - - $this->assertEquals('1.2.x-dev', $package->getPrettyVersion()); - } - - public function provideExtraBranchVersion() - { - return array( - array('1.2'), - array('1.2.x'), - array('1.2-dev'), - array('1.2.x-dev'), - ); - } } diff --git a/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json deleted file mode 100644 index 75545d5f9..000000000 --- a/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "test/path-branch-versioned", - "extra": { - "branch-version": "1.2" - } -} diff --git a/tests/Composer/Test/Repository/PathRepositoryTest.php b/tests/Composer/Test/Repository/PathRepositoryTest.php index 628c3320d..159d8cc97 100644 --- a/tests/Composer/Test/Repository/PathRepositoryTest.php +++ b/tests/Composer/Test/Repository/PathRepositoryTest.php @@ -72,23 +72,6 @@ class PathRepositoryTest extends TestCase $this->assertNotEmpty($packageVersion); } - public function testLoadPackageFromFileSystemWithExtraBranchVersion() - { - $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') - ->getMock(); - - $config = new \Composer\Config(); - $versionGuesser = null; - - $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-branch-version')); - $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config); - $packages = $repository->getPackages(); - - $this->assertEquals(1, $repository->count()); - - $this->assertTrue($repository->hasPackage($this->getPackage('test/path-branch-versioned', '1.2.x-dev'))); - } - public function testLoadPackageFromFileSystemWithWildcard() { $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') @@ -102,7 +85,7 @@ class PathRepositoryTest extends TestCase $packages = $repository->getPackages(); $names = array(); - $this->assertEquals(3, $repository->count()); + $this->assertEquals(2, $repository->count()); $package = $packages[0]; $names[] = $package->getName(); @@ -110,11 +93,8 @@ class PathRepositoryTest extends TestCase $package = $packages[1]; $names[] = $package->getName(); - $package = $packages[2]; - $names[] = $package->getName(); - sort($names); - $this->assertEquals(array('test/path-branch-versioned', 'test/path-unversioned', 'test/path-versioned'), $names); + $this->assertEquals(array('test/path-unversioned', 'test/path-versioned'), $names); } /** From 725b33ee5a8e72559a53d4ee7e6d8482bec28c66 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 21 Jan 2021 20:39:55 +0100 Subject: [PATCH 2/5] Handle "versions" option in PathRepository, remove support for "branch-version" --- doc/05-repositories.md | 20 ++++++++++++ src/Composer/Repository/PathRepository.php | 6 ++++ .../Test/Repository/PathRepositoryTest.php | 31 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 95881b078..4c1c7e000 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -658,6 +658,26 @@ the branch or tag that is currently checked out. Otherwise, the version should be explicitly defined in the package's `composer.json` file. If the version cannot be resolved by these means, it is assumed to be `dev-master`. +When the version cannot be inferred from the local VCS repository, or when you +want to override the version, you can use the `versions` option when declaring +the repository: + +```json +{ + "repositories": [ + { + "type": "path", + "url": "../../packages/my-package", + "options": { + "versions": { + "my/package": "4.2-dev" + } + } + } + ] +} +``` + The local package will be symlinked if possible, in which case the output in the console will read `Symlinking from ../../packages/my-package`. If symlinking is _not_ possible the package will be copied. In that case, the console will diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index a0a6835b8..b6601f883 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -164,6 +164,12 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn 'reference' => sha1($json . serialize($this->options)), ); $package['transport-options'] = $this->options; + unset($package['transport-options']['versions']); + + // use the version provided as option if available + if (isset($package['name'], $this->options['versions'][$package['name']])) { + $package['version'] = $this->options['versions'][$package['name']]; + } // carry over the root package version if this path repo is in the same git repository as root package if (!isset($package['version']) && ($rootVersion = getenv('COMPOSER_ROOT_VERSION'))) { diff --git a/tests/Composer/Test/Repository/PathRepositoryTest.php b/tests/Composer/Test/Repository/PathRepositoryTest.php index 159d8cc97..f2c8a9192 100644 --- a/tests/Composer/Test/Repository/PathRepositoryTest.php +++ b/tests/Composer/Test/Repository/PathRepositoryTest.php @@ -97,6 +97,37 @@ class PathRepositoryTest extends TestCase $this->assertEquals(array('test/path-unversioned', 'test/path-versioned'), $names); } + public function testLoadPackageWithExplicitVersions() + { + $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') + ->getMock(); + + $config = new \Composer\Config(); + $versionGuesser = null; + + $options = array( + 'versions' => array( + 'test/path-unversioned' => '4.3.2.1', + 'test/path-versioned' => '3.2.1.0', + ), + ); + $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*')); + $repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config); + $packages = $repository->getPackages(); + $versions = array(); + + $this->assertEquals(2, $repository->count()); + + $package = $packages[0]; + $versions[$package->getName()] = $package->getVersion(); + + $package = $packages[1]; + $versions[$package->getName()] = $package->getVersion(); + + ksort($versions); + $this->assertSame(array('test/path-unversioned' => '4.3.2.1', 'test/path-versioned' => '3.2.1.0'), $versions); + } + /** * Verify relative repository URLs remain relative, see #4439 */ From bab210777ec26619e56037615c8d4a68c5b601f2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 27 Jan 2021 15:01:26 +0100 Subject: [PATCH 3/5] Update deps --- composer.lock | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index e33b5471d..6dd6c3844 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.8", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8a7ecad675253e4654ea05505233285377405215" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", - "reference": "8a7ecad675253e4654ea05505233285377405215", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -26,14 +26,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -60,11 +61,6 @@ "ssl", "tls" ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.8" - }, "funding": [ { "url": "https://packagist.com", @@ -79,7 +75,7 @@ "type": "tidelift" } ], - "time": "2020-08-23T12:54:47+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/semver", From 92313447d6234af021a43643bb4ad00d19fe5b42 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 27 Jan 2021 15:02:19 +0100 Subject: [PATCH 4/5] Filter out exclude-from-classmap rules to avoid generating very long regexes, fixes #9487 --- src/Composer/Autoload/AutoloadGenerator.php | 27 +++++++++++++++++-- src/Composer/Autoload/ClassMapGenerator.php | 2 +- .../Test/Autoload/AutoloadGeneratorTest.php | 10 +++++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 863ceac43..88d7046c6 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -231,7 +231,7 @@ EOF; $excluded = null; if (!empty($autoloads['exclude-from-classmap'])) { - $excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}'; + $excluded = $autoloads['exclude-from-classmap']; } $classMap = array(); @@ -350,8 +350,31 @@ EOF; return $classMap; } + /** + * @param ?array $excluded + */ private function generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, $showAmbiguousWarning, array &$scannedFiles) { + if ($excluded) { + // filter excluded patterns here to only use those matching $dir + // exclude-from-classmap patterns are all realpath'd so we can only filter them if $dir exists so that realpath($dir) will work + // if $dir does not exist, it should anyway not find anything there so no trouble + if (file_exists($dir)) { + // transform $dir in the same way that exclude-from-classmap patterns are transformed so we can match them against each other + $dirMatch = preg_quote(strtr(realpath($dir), '\\', '/')); + foreach ($excluded as $index => $pattern) { + // extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character + $pattern = preg_replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern); + // if the pattern is not a subset or superset of $dir, it is unrelated and we skip it + if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) { + unset($excluded[$index]); + } + } + } + + $excluded = $excluded ? '{(' . implode('|', $excluded) . ')}' : null; + } + return ClassMapGenerator::createMap($dir, $excluded, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType, $scannedFiles); } @@ -458,7 +481,7 @@ EOF; if (isset($autoloads['classmap'])) { $excluded = null; if (!empty($autoloads['exclude-from-classmap'])) { - $excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}'; + $excluded = $autoloads['exclude-from-classmap']; } $scannedFiles = array(); diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 4adbcc8be..0724d5dd6 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -51,7 +51,7 @@ class ClassMapGenerator * Iterate over all files in the given directory searching for classes * * @param \Iterator|string $path The path to search in or an iterator - * @param string $excluded Regex that matches against the file path that exclude from the classmap. + * @param string $excluded Regex that matches file paths to be excluded from the classmap * @param IOInterface $io IO object * @param string $namespace Optional namespace prefix to filter by * @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 3cd8f7ff2..1811d06c0 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -1377,9 +1377,9 @@ EOF; $package->setAutoload(array( 'psr-0' => array('Foo' => '../path/../src'), 'psr-4' => array('Acme\Foo\\' => '../path/../src-psr4'), - 'classmap' => array('../classmap'), + 'classmap' => array('../classmap', '../classmap2/subdir', 'classmap3', 'classmap4'), 'files' => array('../test.php'), - 'exclude-from-classmap' => array('./../classmap/excluded'), + 'exclude-from-classmap' => array('./../classmap/excluded', '../classmap2', 'classmap3/classes.php', 'classmap4/*/classes.php'), )); $this->repository->expects($this->once()) @@ -1388,9 +1388,15 @@ EOF; $this->fs->ensureDirectoryExists($this->workingDir.'/src/Foo'); $this->fs->ensureDirectoryExists($this->workingDir.'/classmap/excluded'); + $this->fs->ensureDirectoryExists($this->workingDir.'/classmap2/subdir'); + $this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap3'); + $this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap4/foo/'); file_put_contents($this->workingDir.'/src/Foo/Bar.php', 'workingDir.'/classmap/classes.php', 'workingDir.'/classmap/excluded/classes.php', 'workingDir.'/classmap2/subdir/classes.php', 'workingDir.'/working-dir/classmap3/classes.php', 'workingDir.'/working-dir/classmap4/foo/classes.php', 'workingDir.'/test.php', 'generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_14'); From 4d2ae787032afb7adcfbba60298f5718039ec1fa Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 27 Jan 2021 15:40:59 +0100 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8caad32b6..96f476eec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### [1.10.20] 2021-01-27 + + * Fixed exclude-from-classmap causing regex issues when having too many paths + * Fixed compatibility issue with Symfony 4/5 + ### [1.10.19] 2020-12-04 * Fixed regression on PHP 8.0 @@ -924,6 +929,7 @@ * Initial release +[1.10.20]: https://github.com/composer/composer/compare/1.10.19...1.10.20 [1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19 [1.10.18]: https://github.com/composer/composer/compare/1.10.17...1.10.18 [1.10.17]: https://github.com/composer/composer/compare/1.10.16...1.10.17