diff --git a/src/Handler/PackageHandler.php b/src/Handler/PackageHandler.php new file mode 100644 index 0000000..e61b047 --- /dev/null +++ b/src/Handler/PackageHandler.php @@ -0,0 +1,51 @@ +parser = $parser ?? new Parser($this->io); + $vendorDir = $this->composer->getConfig()->get('vendor-dir'); + $this->repository = $repository ?? new ExtraDownloadsRepository(new JsonFile($vendorDir.'/composer/installed-extra-downloads.json', null, $this->io)); + } + + public function handle(PackageInterface $package): void + { + $installationManager = $this->composer->getInstallationManager(); + $extraDownloads = array_filter( + $this->parser->parse($package), + fn (PackageInterface $extraDownload) => !$installationManager->isPackageInstalled($this->repository, $extraDownload) + ); + if (empty($extraDownloads)) { + return; + } + $operations = array_map( + fn (PackageInterface $extraDownload) => new InstallOperation($extraDownload), + array_values($extraDownloads) + ); + $installationManager->execute($this->repository, $operations, false, false); + if (!$package instanceof RootPackageInterface) { + $installationManager->ensureBinariesPresence($package); + } + } +} diff --git a/src/Handler/PackageHandlerInterface.php b/src/Handler/PackageHandlerInterface.php new file mode 100644 index 0000000..4331fcb --- /dev/null +++ b/src/Handler/PackageHandlerInterface.php @@ -0,0 +1,10 @@ +composer = $this->createMock(Composer::class); + $this->io = $this->createMock(IOInterface::class); + $this->parser = $this->createMock(ParserInterface::class); + $this->repository = $this->createMock(InstalledRepositoryInterface::class); + $this->installationManager = $this->createMock(InstallationManager::class); + $this->handler = new PackageHandler( + $this->composer, + $this->io, + $this->parser, + $this->repository + ); + } + + public function testHandleEmptyExtraDownloads(): void + { + $package = $this->createMock(PackageInterface::class); + $this->composer + ->expects($this->once()) + ->method('getInstallationManager') + ->willReturn($this->installationManager); + $this->parser + ->expects($this->once()) + ->method('parse') + ->with($package) + ->willReturn([]); + $this->installationManager + ->expects($this->never()) + ->method('isPackageInstalled'); + $this->installationManager + ->expects($this->never()) + ->method('execute'); + $this->installationManager + ->expects($this->never()) + ->method('ensureBinariesPresence'); + $this->handler->handle($package); + } + + public function testHandleAllExtraDownloadsInstalled(): void + { + $package = $this->createMock(PackageInterface::class); + $this->composer + ->expects($this->once()) + ->method('getInstallationManager') + ->willReturn($this->installationManager); + $this->parser + ->expects($this->once()) + ->method('parse') + ->with($package) + ->willReturn([ + $extraDownload1 = $this->createMock(ExtraDownloadInterface::class), + $extraDownload2 = $this->createMock(ExtraDownloadInterface::class), + $extraDownload3 = $this->createMock(ExtraDownloadInterface::class), + ]); + $this->installationManager + ->expects($this->exactly(3)) + ->method('isPackageInstalled') + ->withConsecutive( + [$this->repository, $extraDownload1], + [$this->repository, $extraDownload2], + [$this->repository, $extraDownload3] + ) + ->willReturn(true); + $this->installationManager + ->expects($this->never()) + ->method('execute'); + $this->installationManager + ->expects($this->never()) + ->method('ensureBinariesPresence'); + $this->handler->handle($package); + } + + public function getHandleTests(): array + { + return [ + [new Package('vendor/library-name', '1.0.0', 'v1.0.0'), true], + [new RootPackage('my-organization/my-project', '1.2.3', 'v1.2.3'), false], + ]; + } + + /** + * @dataProvider getHandleTests + */ + public function testHandle(PackageInterface $package, bool $ensureBinariesPresence): void + { + $this->composer + ->expects($this->once()) + ->method('getInstallationManager') + ->willReturn($this->installationManager); + $this->parser + ->expects($this->once()) + ->method('parse') + ->with($package) + ->willReturn([ + $extraDownload1 = $this->createMock(ExtraDownloadInterface::class), + $extraDownload2 = $this->createMock(ExtraDownloadInterface::class), + $extraDownload3 = $this->createMock(ExtraDownloadInterface::class), + ]); + $this->installationManager + ->expects($this->exactly(3)) + ->method('isPackageInstalled') + ->withConsecutive( + [$this->repository, $extraDownload1], + [$this->repository, $extraDownload2], + [$this->repository, $extraDownload3] + ) + ->willReturnOnConsecutiveCalls(false, true, false); + $this->installationManager + ->expects($this->once()) + ->method('execute') + ->with( + $this->repository, + $this->callback(function (array $operations) use ($extraDownload1, $extraDownload3) { + $this->assertCount(2, $operations); + $this->assertInstanceOf(InstallOperation::class, $operations[0]); + $this->assertSame($extraDownload1, $operations[0]->getPackage()); + $this->assertInstanceOf(InstallOperation::class, $operations[1]); + $this->assertSame($extraDownload3, $operations[1]->getPackage()); + + return true; + }), + false, + false, + ); + $this->installationManager + ->expects($this->exactly($ensureBinariesPresence)) + ->method('ensureBinariesPresence') + ->with($package); + $this->handler->handle($package); + } +}