Skip to content

Commit

Permalink
refactor: Refactor plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Apr 18, 2024
1 parent d0b7d6b commit 13e05d4
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 3 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}
],
"require": {
"composer-plugin-api": "^2.0",
"composer-plugin-api": "^2.1",
"php": "^8.1",
"leongrdic/smplang": "^1.0.2",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0",
Expand All @@ -42,6 +42,6 @@
}
},
"extra": {
"class": "LastCall\\DownloadsPlugin\\Plugin"
"class": "LastCall\\DownloadsPlugin\\Composer\\Plugin\\ExtraDownloadsPlugin"
}
}
58 changes: 58 additions & 0 deletions src/Composer/Installer/FileInstaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace LastCall\DownloadsPlugin\Composer\Installer;

use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Util\Filesystem;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;
use LastCall\DownloadsPlugin\Enum\PackageType;
use LastCall\DownloadsPlugin\Installer\ExecutableInstallerInterface;
use React\Promise\PromiseInterface;
use Symfony\Component\Finder\Finder;

class FileInstaller extends AbstractInstaller
{
public const TMP_PREFIX = '.composer-extra-tmp-';

protected Filesystem $filesystem;

public function __construct(
IOInterface $io,
Composer $composer,
?Filesystem $filesystem = null,
?ExecutableInstallerInterface $executableInstaller = null,
) {
parent::__construct($io, $composer, $executableInstaller);
$this->filesystem = $filesystem ?: new Filesystem();
}

public function supports(string $packageType): bool
{
return $packageType === PackageType::FILE->value;
}

public function install(InstalledRepositoryInterface $repo, PackageInterface $package): PromiseInterface
{
if (!$package instanceof ExtraDownloadInterface) {
return \React\Promise\resolve(null);
}

$expectedPath = $package->getInstallPath();
$tmpDir = \dirname($expectedPath).\DIRECTORY_SEPARATOR.uniqid(self::TMP_PREFIX, true);
$promise = $this->composer->getDownloadManager()->install($package, $tmpDir);

return $promise->then(function () use ($repo, $package, $expectedPath, $tmpDir) {
$finder = new Finder();
foreach ($finder->files()->in($tmpDir) as $file) {
$this->filesystem->rename($file, $expectedPath);
break;
}
$this->filesystem->remove($tmpDir);

return parent::install($repo, $package);
});
}
}
91 changes: 91 additions & 0 deletions src/Composer/Plugin/ExtraDownloadsPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace LastCall\DownloadsPlugin\Composer\Plugin;

use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Installer\PackageEvent;
use Composer\Installer\PackageEvents;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use LastCall\DownloadsPlugin\Composer\Installer\ArchiveInstaller;
use LastCall\DownloadsPlugin\Composer\Installer\FileInstaller;
use LastCall\DownloadsPlugin\Handler\PackageHandler;
use LastCall\DownloadsPlugin\Handler\PackageHandlerInterface;

class ExtraDownloadsPlugin implements PluginInterface, EventSubscriberInterface
{
private const EVENT_PRIORITY = 10;

public function __construct(private ?PackageHandlerInterface $handler = null)
{
}

public static function getSubscribedEvents(): array
{
return [
PackageEvents::POST_PACKAGE_INSTALL => ['handlePackageEvent', self::EVENT_PRIORITY],
PackageEvents::POST_PACKAGE_UPDATE => ['handlePackageEvent', self::EVENT_PRIORITY],
ScriptEvents::POST_INSTALL_CMD => ['handleScriptEvent', self::EVENT_PRIORITY],
ScriptEvents::POST_UPDATE_CMD => ['handleScriptEvent', self::EVENT_PRIORITY],
];
}

public function handleScriptEvent(Event $event): void
{
$rootPackage = $event->getComposer()->getPackage();
$this->getHandler($event->getComposer(), $event->getIO())->handle($rootPackage);

// Ensure that any other packages are properly reconciled.
$localRepo = $event->getComposer()->getRepositoryManager()->getLocalRepository();
foreach ($localRepo->getCanonicalPackages() as $package) {
$this->getHandler($event->getComposer(), $event->getIO())->handle($package);
}
}

public function handlePackageEvent(PackageEvent $event): void
{
$package = match (\get_class($event->getOperation())) {
InstallOperation::class => $event->getOperation()->getPackage(),
UpdateOperation::class => $event->getOperation()->getTargetPackage(),
default => throw new \Exception(sprintf('Operation %s not supported', $event->getOperation()->getOperationType()))
};
$this->getHandler($event->getComposer(), $event->getIO())->handle($package);
}

public function activate(Composer $composer, IOInterface $io): void
{
$this->addInstallers($composer, $io);
}

public function deactivate(Composer $composer, IOInterface $io): void
{
}

public function uninstall(Composer $composer, IOInterface $io): void
{
}

private function addInstallers(Composer $composer, IOInterface $io): void
{
$installers = [
new ArchiveInstaller($io, $composer),
new FileInstaller($io, $composer),
];
$installationManager = $composer->getInstallationManager();
foreach ($installers as $installer) {
$installationManager->addInstaller($installer);
}
}

private function getHandler(Composer $composer, IOInterface $io): PackageHandlerInterface
{
$this->handler ??= new PackageHandler($composer, $io);

return $this->handler;
}
}
7 changes: 7 additions & 0 deletions src/Exception/InvalidAttributeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace LastCall\DownloadsPlugin\Exception;

class InvalidAttributeException extends BaseException
{
}
2 changes: 1 addition & 1 deletion tests/Integration/Invalid/InvalidExecutableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ protected static function getExtraFile(): array

protected static function getErrorMessage(): string
{
return 'Skipped download extra files for package test/project: Attribute "executable" of extra file "invalid-executable" defined in package "test/project" are not valid paths.';
return 'Skipped download extra files for package test/project: Attribute "executable[*]" of extra file "invalid-executable" defined in package "test/project" must be relative path.';
}
}

0 comments on commit 13e05d4

Please sign in to comment.