diff --git a/src/ComposerIntegration/ComposerIntegrationHandler.php b/src/ComposerIntegration/ComposerIntegrationHandler.php index 64a5561..d5e33ca 100644 --- a/src/ComposerIntegration/ComposerIntegrationHandler.php +++ b/src/ComposerIntegration/ComposerIntegrationHandler.php @@ -55,6 +55,7 @@ public function __invoke(Package $package, Composer $composer, TargetPlatform $t $composerInstaller = PieComposerInstaller::createWithPhpBinary( $targetPlatform->phpBinaryPath, + $package->extensionName, $this->arrayCollectionIo, $composer, ); diff --git a/src/ComposerIntegration/PhpBinaryPathBasedPlatformRepository.php b/src/ComposerIntegration/PhpBinaryPathBasedPlatformRepository.php index 72e75de..fae9d17 100644 --- a/src/ComposerIntegration/PhpBinaryPathBasedPlatformRepository.php +++ b/src/ComposerIntegration/PhpBinaryPathBasedPlatformRepository.php @@ -8,6 +8,7 @@ use Composer\Pcre\Preg; use Composer\Repository\PlatformRepository; use Composer\Semver\VersionParser; +use Php\Pie\ExtensionName; use Php\Pie\Platform\TargetPhp\PhpBinaryPath; use UnexpectedValueException; @@ -19,7 +20,7 @@ class PhpBinaryPathBasedPlatformRepository extends PlatformRepository { private VersionParser $versionParser; - public function __construct(PhpBinaryPath $phpBinaryPath) + public function __construct(PhpBinaryPath $phpBinaryPath, ExtensionName|null $extensionBeingInstalled) { $this->versionParser = new VersionParser(); $this->packages = []; @@ -32,6 +33,16 @@ public function __construct(PhpBinaryPath $phpBinaryPath) $extVersions = $phpBinaryPath->extensions(); foreach ($extVersions as $extension => $extensionVersion) { + /** + * If the extension we're trying to exclude is not excluded from this list if it is already installed + * and enabled, it conflicts when running {@see ComposerIntegrationHandler}. + * + * @link https://github.com/php/pie/issues/150 + */ + if ($extensionBeingInstalled !== null && $extension === $extensionBeingInstalled->name()) { + continue; + } + $this->addPackage($this->packageForExtension($extension, $extensionVersion)); } diff --git a/src/ComposerIntegration/PieComposerInstaller.php b/src/ComposerIntegration/PieComposerInstaller.php index 524d504..57febc0 100644 --- a/src/ComposerIntegration/PieComposerInstaller.php +++ b/src/ComposerIntegration/PieComposerInstaller.php @@ -8,6 +8,7 @@ use Composer\Installer; use Composer\IO\IOInterface; use Composer\Repository\PlatformRepository; +use Php\Pie\ExtensionName; use Php\Pie\Platform\TargetPhp\PhpBinaryPath; use Webmozart\Assert\Assert; @@ -18,17 +19,23 @@ */ class PieComposerInstaller extends Installer { - private PhpBinaryPath|null $phpBinaryPath = null; + private PhpBinaryPath|null $phpBinaryPath = null; + private ExtensionName|null $extensionBeingInstalled = null; protected function createPlatformRepo(bool $forUpdate): PlatformRepository { - Assert::notNull($this->phpBinaryPath, 'PHP Binary path was not set, maybe createWithPhpBinary was not used?'); + Assert::notNull($this->phpBinaryPath, '$phpBinaryPath was not set, maybe createWithPhpBinary was not used?'); + Assert::notNull($this->extensionBeingInstalled, '$extensionBeingInstalled was not set, maybe createWithPhpBinary was not used?'); - return new PhpBinaryPathBasedPlatformRepository($this->phpBinaryPath); + return new PhpBinaryPathBasedPlatformRepository($this->phpBinaryPath, $this->extensionBeingInstalled); } - public static function createWithPhpBinary(PhpBinaryPath $php, IOInterface $io, Composer $composer): self - { + public static function createWithPhpBinary( + PhpBinaryPath $php, + ExtensionName $extensionBeingInstalled, + IOInterface $io, + Composer $composer, + ): self { /** @psalm-suppress InvalidArgument some kind of unrelated type mismatch, defined in parent */ $composerInstaller = new self( $io, @@ -42,7 +49,8 @@ public static function createWithPhpBinary(PhpBinaryPath $php, IOInterface $io, $composer->getAutoloadGenerator(), ); - $composerInstaller->phpBinaryPath = $php; + $composerInstaller->phpBinaryPath = $php; + $composerInstaller->extensionBeingInstalled = $extensionBeingInstalled; return $composerInstaller; } diff --git a/src/ComposerIntegration/VersionSelectorFactory.php b/src/ComposerIntegration/VersionSelectorFactory.php index 60a6954..ef81ef6 100644 --- a/src/ComposerIntegration/VersionSelectorFactory.php +++ b/src/ComposerIntegration/VersionSelectorFactory.php @@ -35,7 +35,7 @@ public static function make( ): VersionSelector { return new VersionSelector( self::factoryRepositorySet($composer, $requestedPackageAndVersion->version), - new PhpBinaryPathBasedPlatformRepository($targetPlatform->phpBinaryPath), + new PhpBinaryPathBasedPlatformRepository($targetPlatform->phpBinaryPath, null), ); } } diff --git a/test/unit/ComposerIntegration/PhpBinaryPathBasedPlatformRepositoryTest.php b/test/unit/ComposerIntegration/PhpBinaryPathBasedPlatformRepositoryTest.php index 72213d8..1fc7c65 100644 --- a/test/unit/ComposerIntegration/PhpBinaryPathBasedPlatformRepositoryTest.php +++ b/test/unit/ComposerIntegration/PhpBinaryPathBasedPlatformRepositoryTest.php @@ -6,6 +6,7 @@ use Composer\Package\PackageInterface; use Php\Pie\ComposerIntegration\PhpBinaryPathBasedPlatformRepository; +use Php\Pie\ExtensionName; use Php\Pie\Platform\TargetPhp\PhpBinaryPath; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -30,7 +31,7 @@ public function testPlatformRepositoryContainsExpectedPacakges(): void 'another' => '1.2.3-alpha.34', ]); - $platformRepository = new PhpBinaryPathBasedPlatformRepository($phpBinaryPath); + $platformRepository = new PhpBinaryPathBasedPlatformRepository($phpBinaryPath, null); self::assertSame( [ @@ -46,4 +47,33 @@ public function testPlatformRepositoryContainsExpectedPacakges(): void ), ); } + + public function testPlatformRepositoryExcludesExtensionBeingInstalled(): void + { + $extensionBeingInstalled = ExtensionName::normaliseFromString('extension_being_installed'); + + $phpBinaryPath = $this->createMock(PhpBinaryPath::class); + $phpBinaryPath->expects(self::once()) + ->method('version') + ->willReturn('8.1.0'); + $phpBinaryPath->expects(self::once()) + ->method('extensions') + ->willReturn([ + 'foo' => '8.1.0', + 'extension_being_installed' => '1.2.3', + ]); + + $platformRepository = new PhpBinaryPathBasedPlatformRepository($phpBinaryPath, $extensionBeingInstalled); + + self::assertSame( + [ + 'php:8.1.0', + 'ext-foo:8.1.0', + ], + array_map( + static fn (PackageInterface $package): string => $package->getName() . ':' . $package->getPrettyVersion(), + $platformRepository->getPackages(), + ), + ); + } }