diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-31 00:07:36 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-31 00:07:36 +0900 |
| commit | dc1f030e3904677cd65eac0a90c1d850e0ad1bbf (patch) | |
| tree | 36f5177d90ae34f1b0b28cae5d1a3075acb2f8bd /crates/shirabe/tests/plugin/fixtures | |
| parent | a38ed045e9981664d90c05ab43ab4ab6026eb31b (diff) | |
| download | php-shirabe-dc1f030e3904677cd65eac0a90c1d850e0ad1bbf.tar.gz php-shirabe-dc1f030e3904677cd65eac0a90c1d850e0ad1bbf.tar.zst php-shirabe-dc1f030e3904677cd65eac0a90c1d850e0ad1bbf.zip | |
feat(plugin): serve HttpDownloader as a proxy stub
A downloader carries its own options, TLS defaults and request backends, and
what it shares with the graph is the IO it collects authentication into and
the config it reads. Plugin code writing `new HttpDownloader($io, $config)`
therefore allocates a Rust-side entity of its own rather than a second
downloader the graph knows nothing about, and the guard that shadowed the
class in the worker is gone.
The request surface is not served yet: get() and copy() have no wire
representation for the Response they return, and the async surface resolves
its promises with one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/plugin/fixtures')
3 files changed, 135 insertions, 0 deletions
diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/composer.json b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/composer.json new file mode 100644 index 00000000..08eec6ce --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/composer.json @@ -0,0 +1,17 @@ +{ + "name": "shirabe-test/http-downloader-probe", + "version": "1.0.0", + "type": "composer-plugin", + "description": "Fixture plugin driving an HttpDownloader it constructs itself.", + "autoload": { + "psr-4": { + "ShirabeTest\\HttpDownloader\\": "src/" + } + }, + "require": { + "composer-plugin-api": "^2.0" + }, + "extra": { + "class": "ShirabeTest\\HttpDownloader\\Plugin" + } +} diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/src/Plugin.php b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/src/Plugin.php new file mode 100644 index 00000000..504c2108 --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/plugin/src/Plugin.php @@ -0,0 +1,94 @@ +<?php + +namespace ShirabeTest\HttpDownloader; + +use Composer\Composer; +use Composer\Downloader\TransportException; +use Composer\EventDispatcher\EventSubscriberInterface; +use Composer\IO\IOInterface; +use Composer\Plugin\PluginInterface; +use Composer\Script\Event; +use Composer\Script\ScriptEvents; +use Composer\Util\HttpDownloader; + +/** + * Drives an HttpDownloader the plugin constructs itself and appends what every call reports to + * http-downloader-trace.txt, so the surface can be compared line by line between implementations: + * the identity of the object a plugin gets, the options it merges, and the static helpers. + * Nothing here reaches the network — the trace has to be reproducible offline. + */ +class Plugin implements PluginInterface, EventSubscriberInterface +{ + /** @var IOInterface */ + private $io; + + public function activate(Composer $composer, IOInterface $io): void + { + $this->io = $io; + } + + public function deactivate(Composer $composer, IOInterface $io): void + { + } + + public function uninstall(Composer $composer, IOInterface $io): void + { + } + + public static function getSubscribedEvents() + { + // Whether an install resolves or replays a lock file decides which of the two fires, so + // both are subscribed and the trace records the one that ran. + return [ + ScriptEvents::POST_INSTALL_CMD => 'onPostCommand', + ScriptEvents::POST_UPDATE_CMD => 'onPostCommand', + ]; + } + + public function onPostCommand(Event $event): void + { + $downloader = new HttpDownloader($this->io, $event->getComposer()->getConfig()); + $lines = ['event=' . $event->getName()]; + + $lines[] = 'class=' . json_encode(\get_class($downloader)) + . ' instanceof=' . json_encode($downloader instanceof HttpDownloader); + + // Only the key the plugin set is compared: the rest of the map is the TLS defaults, whose + // CA paths depend on the machine rather than on the implementation. + $downloader->setOptions(['http' => ['header' => ['X-Probe: 1']]]); + $options = $downloader->getOptions(); + $lines[] = 'options header=' . json_encode($options['http']['header'] ?? null); + $downloader->setOptions(['http' => ['header' => ['X-Probe: 2']]]); + $lines[] = 'options merged=' . json_encode($downloader->getOptions()['http']['header'] ?? null); + + $lines[] = 'isCurlEnabled=' . json_encode(HttpDownloader::isCurlEnabled()); + + // getExceptionHints() only inspects the exception it is handed; both arguments below stay + // clear of the branch that probes connectivity. + $lines[] = 'hints other=' . json_encode(HttpDownloader::getExceptionHints(new \RuntimeException('x'))) + . ' transport=' . json_encode(HttpDownloader::getExceptionHints(new TransportException('plain', 400))); + + // The version constraint cannot match, so this reaches Composer::getVersion() and the + // version parser without writing anything to the terminal. + $lines[] = 'outputWarnings=' . $this->describe(static function () use ($event): void { + HttpDownloader::outputWarnings( + $event->getIO(), + 'https://example.org/packages.json', + ['warning' => 'unreachable', 'warning-versions' => '^0.0.1'] + ); + }); + + file_put_contents('http-downloader-trace.txt', implode("\n", $lines) . "\n"); + } + + private function describe(callable $call): string + { + try { + $call(); + + return 'ok'; + } catch (\Throwable $e) { + return \get_class($e) . ': ' . $e->getMessage(); + } + } +} diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/project/composer.json b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/project/composer.json new file mode 100644 index 00000000..42318a10 --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-http-downloader/project/composer.json @@ -0,0 +1,24 @@ +{ + "name": "shirabe/e2e-http-downloader", + "description": "E2E fixture project: record what a plugin's own HttpDownloader reports.", + "repositories": [ + { + "type": "path", + "url": "../plugin", + "options": { + "symlink": false + } + }, + { + "packagist.org": false + } + ], + "require": { + "shirabe-test/http-downloader-probe": "1.0.0" + }, + "config": { + "allow-plugins": { + "shirabe-test/http-downloader-probe": true + } + } +} |
