1
0
mirror of https://github.com/php/pie.git synced 2026-03-23 23:12:17 +01:00

Introduce Illuminate Container for service location

This commit is contained in:
James Titcumb
2024-03-08 20:45:47 +00:00
parent 2c35b2c973
commit 33d65d4017
12 changed files with 269 additions and 51 deletions

19
.php.stub Normal file
View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Psr\Container {
interface ContainerInterface
{
/** @param string|class-string $name */
public function has(string $name): bool;
/**
* @template T of object
* @psalm-param string|class-string<T> $name
* @psalm-return ($name is class-string ? T : mixed)
*/
public function get(string $name): object;
}
}

17
bin/pie
View File

@@ -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();

View File

@@ -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"

152
composer.lock generated
View File

@@ -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",

View File

@@ -20,4 +20,14 @@
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
</plugins>
<stubs>
<file name=".php.stub"/>
</stubs>
<issueHandlers>
<PossiblyUnusedMethod>
<errorLevel type="suppress">
<directory name="src/Command" />
</errorLevel>
</PossiblyUnusedMethod>
</issueHandlers>
</psalm>

74
src/Container.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace Php\Pie;
use Composer\Factory;
use Composer\IO\NullIO;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory;
use Composer\Repository\RepositorySet;
use Composer\Util\AuthHelper;
use Composer\Util\Platform;
use GuzzleHttp\Client;
use Php\Pie\Command\DownloadCommand;
use Php\Pie\DependencyResolver\DependencyResolver;
use Php\Pie\DependencyResolver\ResolveDependencyWithComposer;
use Php\Pie\Downloading\DownloadAndExtract;
use Php\Pie\Downloading\DownloadZip;
use Php\Pie\Downloading\ExtractZip;
use Php\Pie\Downloading\UnixDownloadAndExtract;
use Psr\Container\ContainerInterface;
use RuntimeException;
final class Container
{
public static function factory(): ContainerInterface
{
$container = new \Illuminate\Container\Container();
$container->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;
}
}

View File

@@ -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))

View File

@@ -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;

View File

@@ -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(

View File

@@ -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

View File

@@ -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);

View File

@@ -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