Skip to content

Commit

Permalink
Merge pull request #12269 from Seldaek/fix_installed_regr
Browse files Browse the repository at this point in the history
Fix regression from #12233 in InstalledVersions when reload is used
  • Loading branch information
Seldaek authored Jan 21, 2025
2 parents f12d2f5 + d2cd6de commit 0626efa
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
20 changes: 18 additions & 2 deletions src/Composer/InstalledVersions.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class InstalledVersions
*/
private static $installed;

/**
* @var bool
*/
private static $installedIsLocalDir;

/**
* @var bool|null
*/
Expand Down Expand Up @@ -309,6 +314,12 @@ public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();

// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}

/**
Expand All @@ -325,19 +336,24 @@ private static function getInstalled()
$copiedLocalDir = false;

if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
$copiedLocalDir = true;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions tests/Composer/Test/InstalledVersionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,31 @@ public function testGetInstallPath(): void
self::assertSame('/foo/bar/vendor/c/c', \Composer\InstalledVersions::getInstallPath('c/c'));
self::assertNull(\Composer\InstalledVersions::getInstallPath('foo/impl'));
}

public function testWithClassLoaderLoaded(): void
{
// disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no
// class loaders are registered
$prop = new \ReflectionProperty(ClassLoader::class, 'registeredLoaders');
$prop->setAccessible(true);
$prop->setValue(null, array_slice(self::$previousRegisteredLoaders, 0, 1, true));

$prop2 = new \ReflectionProperty(InstalledVersions::class, 'installedIsLocalDir');
$prop2->setAccessible(true);
$prop2->setValue(null, true);

self::assertFalse(InstalledVersions::isInstalled('foo/bar'));
InstalledVersions::reload([
'root' => InstalledVersions::getRootPackage(),
'versions' => [
'foo/bar' => [
'version' => '1.0.0',
'dev_requirement' => false,
],
],
]);
self::assertTrue(InstalledVersions::isInstalled('foo/bar'));

$prop->setValue(null, []);
}
}
9 changes: 4 additions & 5 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* file that was distributed with this source code.
*/

use Composer\InstalledVersions;
use Composer\Util\Platform;

error_reporting(E_ALL);
Expand All @@ -20,10 +19,10 @@
}

require __DIR__.'/../src/bootstrap.php';

if (!class_exists(InstalledVersions::class, false)) {
require __DIR__.'/../src/Composer/InstalledVersions.php';
}
// ensure we always use the latest InstalledVersions.php even if an older composer ran the install, but we need
// to have it included from vendor dir and not from src/ otherwise some gated check in the code will not work
copy(__DIR__.'/../src/Composer/InstalledVersions.php', __DIR__.'/../vendor/composer/InstalledVersions.php');
require __DIR__.'/../vendor/composer/InstalledVersions.php';

Platform::putEnv('COMPOSER_TESTS_ARE_RUNNING', '1');

Expand Down

0 comments on commit 0626efa

Please sign in to comment.