From 33d65d401724b47780c7f41897dc39178a6bbf3f Mon Sep 17 00:00:00 2001 From: James Titcumb Date: Fri, 8 Mar 2024 20:45:47 +0000 Subject: [PATCH] Introduce Illuminate Container for service location --- .php.stub | 19 +++ bin/pie | 17 +- composer.json | 1 + composer.lock | 152 +++++++++++++++++- psalm.xml.dist | 10 ++ src/Container.php | 74 +++++++++ .../ResolveDependencyWithComposer.php | 14 -- src/Downloading/DownloadAndExtract.php | 1 + src/Downloading/DownloadZip.php | 1 + src/Downloading/ExtractZip.php | 1 + src/Downloading/UnixDownloadAndExtract.php | 20 +-- .../Command/DownloadCommandTest.php | 10 +- 12 files changed, 269 insertions(+), 51 deletions(-) create mode 100644 .php.stub create mode 100644 src/Container.php diff --git a/.php.stub b/.php.stub new file mode 100644 index 0000000..be1e3f0 --- /dev/null +++ b/.php.stub @@ -0,0 +1,19 @@ + $name + * @psalm-return ($name is class-string ? T : mixed) + */ + public function get(string $name): object; + } +} diff --git a/bin/pie b/bin/pie index b68dbb1..4928bff 100755 --- a/bin/pie +++ b/bin/pie @@ -5,21 +5,20 @@ declare(strict_types=1); namespace Php\Pie; +use Php\Pie\Command\DownloadCommand; use Php\Pie\DependencyResolver\ResolveDependencyWithComposer; use Php\Pie\Downloading\UnixDownloadAndExtract; use Symfony\Component\Console\Application; +use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; /** @psalm-suppress UnresolvableInclude */ include $_composer_autoload_path ?? __DIR__ . '/../vendor/autoload.php'; $application = new Application('pie', 'dev-main'); -// @todo make these lazy eventually https://symfony.com/doc/current/console/lazy_commands.html -$application->addCommands([ - // @todo we may want to use some kind of service locator eventually - new Command\DownloadCommand( - ResolveDependencyWithComposer::factory(), - // @todo detect platform - UnixDownloadAndExtract::factory(), - ), -]); +$application->setCommandLoader(new ContainerCommandLoader( + Container::factory(), + [ + 'download' => DownloadCommand::class, + ] +)); $application->run(); diff --git a/composer.json b/composer.json index 978cc53..8de5973 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "composer/composer": "^2.7", "guzzlehttp/guzzle": "^7.8", "guzzlehttp/psr7": "^2.6", + "illuminate/container": "^10.47", "psr/http-message": "^2.0", "symfony/console": "^6.4", "webmozart/assert": "^1.11" diff --git a/composer.lock b/composer.lock index 6d966f0..b4e1178 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "37d41a51728ec587b1d61db4f11eb903", + "content-hash": "e06f8eec17d3884eb9d1bec39a8991bf", "packages": [ { "name": "composer/ca-bundle", @@ -961,6 +961,105 @@ ], "time": "2023-12-03T20:05:35+00:00" }, + { + "name": "illuminate/container", + "version": "v10.47.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/container.git", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/container/zipball/ddc26273085fad3c471b2602ad820e0097ff7939", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0", + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1" + }, + "provide": { + "psr/container-implementation": "1.1|2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Container\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Container package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-06-18T09:12:03+00:00" + }, + { + "name": "illuminate/contracts", + "version": "v10.47.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "shasum": "" + }, + "require": { + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1", + "psr/simple-cache": "^1.0|^2.0|^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2024-01-15T18:52:32+00:00" + }, { "name": "justinrainbow/json-schema", "version": "v5.2.13", @@ -1294,6 +1393,57 @@ }, "time": "2021-07-14T16:46:02+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "ralouphie/getallheaders", "version": "3.0.3", diff --git a/psalm.xml.dist b/psalm.xml.dist index d78d0a9..f8fc9cf 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -20,4 +20,14 @@ + + + + + + + + + + diff --git a/src/Container.php b/src/Container.php new file mode 100644 index 0000000..8ce2af0 --- /dev/null +++ b/src/Container.php @@ -0,0 +1,74 @@ +singleton(DownloadCommand::class); + $container->singleton( + DependencyResolver::class, + static function (): DependencyResolver { + $repositorySet = new RepositorySet(); + $repositorySet->addRepository(new CompositeRepository(RepositoryFactory::defaultReposWithDefaultManager(new NullIO()))); + + return new ResolveDependencyWithComposer( + new PlatformRepository(), + $repositorySet, + ); + }, + ); + $container->singleton( + UnixDownloadAndExtract::class, + static function (): UnixDownloadAndExtract { + $config = Factory::createConfig(); + $io = new NullIO(); + $io->loadConfiguration($config); + + return new UnixDownloadAndExtract( + new DownloadZip( + new Client(), + new AuthHelper($io, $config), + ), + new ExtractZip(), + ); + }, + ); + $container->singleton( + DownloadAndExtract::class, + static function (ContainerInterface $container): DownloadAndExtract { + if (Platform::isWindows()) { + // @todo add windows downloader + throw new RuntimeException('Windows support not yet'); + } + + return $container->get(UnixDownloadAndExtract::class); + }, + ); + + return $container; + } +} diff --git a/src/DependencyResolver/ResolveDependencyWithComposer.php b/src/DependencyResolver/ResolveDependencyWithComposer.php index 4e5b5ed..995b67e 100644 --- a/src/DependencyResolver/ResolveDependencyWithComposer.php +++ b/src/DependencyResolver/ResolveDependencyWithComposer.php @@ -4,12 +4,9 @@ declare(strict_types=1); namespace Php\Pie\DependencyResolver; -use Composer\IO\NullIO; use Composer\Package\CompletePackageInterface; use Composer\Package\Version\VersionSelector; -use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; -use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositorySet; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ @@ -21,17 +18,6 @@ final class ResolveDependencyWithComposer implements DependencyResolver ) { } - public static function factory(): self - { - $repositorySet = new RepositorySet(); - $repositorySet->addRepository(new CompositeRepository(RepositoryFactory::defaultReposWithDefaultManager(new NullIO()))); - - return new self( - new PlatformRepository(), - $repositorySet, - ); - } - public function __invoke(string $packageName, string|null $requestedVersion): Package { $package = (new VersionSelector($this->repositorySet, $this->platformRepository)) diff --git a/src/Downloading/DownloadAndExtract.php b/src/Downloading/DownloadAndExtract.php index b210221..413a246 100644 --- a/src/Downloading/DownloadAndExtract.php +++ b/src/Downloading/DownloadAndExtract.php @@ -6,6 +6,7 @@ namespace Php\Pie\Downloading; use Php\Pie\DependencyResolver\Package; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ interface DownloadAndExtract { public function __invoke(Package $package): DownloadedPackage; diff --git a/src/Downloading/DownloadZip.php b/src/Downloading/DownloadZip.php index 77eea86..756a35c 100644 --- a/src/Downloading/DownloadZip.php +++ b/src/Downloading/DownloadZip.php @@ -19,6 +19,7 @@ use function explode; use function file_put_contents; use function trim; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class DownloadZip { public function __construct( diff --git a/src/Downloading/ExtractZip.php b/src/Downloading/ExtractZip.php index bc326c3..e5f0cec 100644 --- a/src/Downloading/ExtractZip.php +++ b/src/Downloading/ExtractZip.php @@ -10,6 +10,7 @@ use ZipArchive; use function explode; use function sprintf; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ class ExtractZip { public function to(string $zipFile, string $destination): string diff --git a/src/Downloading/UnixDownloadAndExtract.php b/src/Downloading/UnixDownloadAndExtract.php index 7f1920f..60d702d 100644 --- a/src/Downloading/UnixDownloadAndExtract.php +++ b/src/Downloading/UnixDownloadAndExtract.php @@ -4,10 +4,6 @@ declare(strict_types=1); namespace Php\Pie\Downloading; -use Composer\Factory; -use Composer\IO\NullIO; -use Composer\Util\AuthHelper; -use GuzzleHttp\Client; use Php\Pie\DependencyResolver\Package; use function file_exists; @@ -15,6 +11,7 @@ use function mkdir; use function sys_get_temp_dir; use function uniqid; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class UnixDownloadAndExtract implements DownloadAndExtract { public function __construct( @@ -23,21 +20,6 @@ final class UnixDownloadAndExtract implements DownloadAndExtract ) { } - public static function factory(): self - { - $config = Factory::createConfig(); - $io = new NullIO(); - $io->loadConfiguration($config); - - return new self( - new DownloadZip( - new Client(), - new AuthHelper($io, $config), - ), - new ExtractZip(), - ); - } - public function __invoke(Package $package): DownloadedPackage { $localTempPath = sys_get_temp_dir() . '/' . uniqid('pie_downloader_', true); diff --git a/test/integration/Command/DownloadCommandTest.php b/test/integration/Command/DownloadCommandTest.php index e50c238..1261236 100644 --- a/test/integration/Command/DownloadCommandTest.php +++ b/test/integration/Command/DownloadCommandTest.php @@ -5,9 +5,8 @@ declare(strict_types=1); namespace Php\PieIntegrationTest\Command; use Php\Pie\Command\DownloadCommand; -use Php\Pie\DependencyResolver\ResolveDependencyWithComposer; +use Php\Pie\Container; use Php\Pie\DependencyResolver\UnableToResolveRequirement; -use Php\Pie\Downloading\UnixDownloadAndExtract; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Tester\CommandTester; @@ -22,12 +21,7 @@ class DownloadCommandTest extends TestCase public function setUp(): void { - $this->commandTester = new CommandTester( - new DownloadCommand( - ResolveDependencyWithComposer::factory(), - UnixDownloadAndExtract::factory(), - ), - ); + $this->commandTester = new CommandTester(Container::factory()->get(DownloadCommand::class)); } public function testDownloadCommand(): void