1
0
Fork 0

Fix autoload regression with metapackage dependencies (#11481)

fixes #11480

introduced by #11455
pull/11494/head
Jordi Boggiano 2023-05-24 14:58:11 +02:00 committed by GitHub
parent 4893b67efa
commit 33c293aec3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 18 deletions

View File

@ -473,7 +473,7 @@ EOF;
/** /**
* @param PackageInterface[] $packages * @param PackageInterface[] $packages
* @return array<int, array{0: PackageInterface, 1: string}> * @return non-empty-array<int, array{0: PackageInterface, 1: string|null}>
*/ */
public function buildPackageMap(InstallationManager $installationManager, PackageInterface $rootPackage, array $packages) public function buildPackageMap(InstallationManager $installationManager, PackageInterface $rootPackage, array $packages)
{ {
@ -485,14 +485,9 @@ EOF;
continue; continue;
} }
$this->validatePackage($package); $this->validatePackage($package);
$installPath = $installationManager->getInstallPath($package);
if ($installPath === null) {
continue;
}
$packageMap[] = [ $packageMap[] = [
$package, $package,
$installPath, $installationManager->getInstallPath($package),
]; ];
} }
@ -523,7 +518,7 @@ EOF;
/** /**
* Compiles an ordered list of namespace => path mappings * Compiles an ordered list of namespace => path mappings
* *
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap array of array(package, installDir-relative-to-composer.json) * @param non-empty-array<int, array{0: PackageInterface, 1: string|null}> $packageMap array of array(package, installDir-relative-to-composer.json or null for metapackages)
* @param RootPackageInterface $rootPackage root package instance * @param RootPackageInterface $rootPackage root package instance
* @param bool|string[] $filteredDevPackages If an array, the list of packages that must be removed. If bool, whether to filter out require-dev packages * @param bool|string[] $filteredDevPackages If an array, the list of packages that must be removed. If bool, whether to filter out require-dev packages
* @return array * @return array
@ -613,7 +608,7 @@ EOF;
} }
/** /**
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string|null}> $packageMap
* @return ?string * @return ?string
*/ */
protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, string $basePath, string $vendorPath, string $vendorPathCode, string $appBaseDirCode) protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, string $basePath, string $vendorPath, string $vendorPathCode, string $appBaseDirCode)
@ -623,6 +618,11 @@ EOF;
foreach ($packageMap as $item) { foreach ($packageMap as $item) {
[$package, $installPath] = $item; [$package, $installPath] = $item;
// packages that are not installed cannot autoload anything
if (null === $installPath) {
continue;
}
if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) { if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) {
$installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir())); $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
} }
@ -716,7 +716,7 @@ EOF;
} }
/** /**
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string|null}> $packageMap
* @param bool|'php-only' $checkPlatform * @param bool|'php-only' $checkPlatform
* @param string[] $devPackageNames * @param string[] $devPackageNames
* @return ?string * @return ?string
@ -1149,7 +1149,7 @@ INITIALIZER;
} }
/** /**
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string|null}> $packageMap
* @param string $type one of: 'psr-0'|'psr-4'|'classmap'|'files' * @param string $type one of: 'psr-0'|'psr-4'|'classmap'|'files'
* @return array<int, string>|array<string, array<string>>|array<string, string> * @return array<int, string>|array<string, array<string>>|array<string, string>
*/ */
@ -1160,6 +1160,11 @@ INITIALIZER;
foreach ($packageMap as $item) { foreach ($packageMap as $item) {
[$package, $installPath] = $item; [$package, $installPath] = $item;
// packages that are not installed cannot autoload anything
if (null === $installPath) {
continue;
}
$autoload = $package->getAutoload(); $autoload = $package->getAutoload();
if ($this->devMode && $package === $rootPackage) { if ($this->devMode && $package === $rootPackage) {
$autoload = array_merge_recursive($autoload, $package->getDevAutoload()); $autoload = array_merge_recursive($autoload, $package->getDevAutoload());
@ -1249,10 +1254,8 @@ INITIALIZER;
/** /**
* Filters out dev-dependencies * Filters out dev-dependencies
* *
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string|null}> $packageMap
* @return array<int, array{0: PackageInterface, 1: string}> * @return array<int, array{0: PackageInterface, 1: string|null}>
*
* @phpstan-param array<int, array{0: PackageInterface, 1: string}> $packageMap
*/ */
protected function filterPackageMap(array $packageMap, RootPackageInterface $rootPackage) protected function filterPackageMap(array $packageMap, RootPackageInterface $rootPackage)
{ {
@ -1305,8 +1308,8 @@ INITIALIZER;
* *
* Packages of equal weight are sorted alphabetically * Packages of equal weight are sorted alphabetically
* *
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string|null}> $packageMap
* @return array<int, array{0: PackageInterface, 1: string}> * @return array<int, array{0: PackageInterface, 1: string|null}>
*/ */
protected function sortPackageMap(array $packageMap) protected function sortPackageMap(array $packageMap)
{ {

View File

@ -131,7 +131,11 @@ class AutoloadGeneratorTest extends TestCase
->getMock(); ->getMock();
$this->im->expects($this->any()) $this->im->expects($this->any())
->method('getInstallPath') ->method('getInstallPath')
->will($this->returnCallback(function ($package): string { ->will($this->returnCallback(function ($package): ?string {
if ($package->getType() === 'metapackage') {
return null;
}
$targetDir = $package->getTargetDir(); $targetDir = $package->getTargetDir();
return $this->vendorDir.'/'.$package->getName() . ($targetDir ? '/'.$targetDir : ''); return $this->vendorDir.'/'.$package->getName() . ($targetDir ? '/'.$targetDir : '');
@ -398,6 +402,40 @@ class AutoloadGeneratorTest extends TestCase
$this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty."); $this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty.");
} }
public function testVendorsAutoloadingWithMetapackages(): void
{
$package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires([
'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
]);
$packages = [];
$packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0');
$packages[] = $c = new AliasPackage($b, '1.2', '1.2');
$a->setAutoload(['psr-0' => ['A' => 'src/', 'A\\B' => 'lib/']]);
$b->setAutoload(['psr-0' => ['B\\Sub\\Name' => 'src/']]);
$a->setType('metapackage');
$a->setRequires([
'b/b' => new Link('a/a', 'b/b', new MatchAllConstraint()),
]);
$this->repository->expects($this->once())
->method('getCanonicalPackages')
->will($this->returnValue($packages));
$this->fs->ensureDirectoryExists($this->vendorDir.'/composer');
$this->fs->ensureDirectoryExists($this->vendorDir.'/b/b/src');
// creating a/a files to make sure they would be found by autoloader even tho they are technically not
// needed as the package is a metapackage, but if it fails to be excluded it would find these
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src');
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/lib');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_5');
$this->assertAutoloadFiles('vendors_meta', $this->vendorDir.'/composer');
$this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty.");
}
public function testNonDevAutoloadExclusionWithRecursion(): void public function testNonDevAutoloadExclusionWithRecursion(): void
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');

View File

@ -0,0 +1,10 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'B\\Sub\\Name' => array($vendorDir . '/b/b/src'),
);