diff options
Diffstat (limited to 'crates/shirabe-php-rpc')
3 files changed, 220 insertions, 86 deletions
diff --git a/crates/shirabe-php-rpc/php/guards/Composer/Util/HttpDownloader.php b/crates/shirabe-php-rpc/php/guards/Composer/Util/HttpDownloader.php deleted file mode 100644 index a2fad123..00000000 --- a/crates/shirabe-php-rpc/php/guards/Composer/Util/HttpDownloader.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php - -// Generated by scripts/plugin-stub-generator; do not edit by hand. -// Guard for Composer\Util\HttpDownloader. -// The Rust side owns this class and the worker has no proxy for it, so this -// declaration shadows the real one: the constants and the hierarchy stay, while -// constructing it or calling anything on it raises an explicit error. - -namespace Composer\Util; - -use Composer\Config; -use Composer\IO\IOInterface; - -class HttpDownloader -{ - private const STATUS_QUEUED = 1; - private const STATUS_STARTED = 2; - private const STATUS_COMPLETED = 3; - private const STATUS_FAILED = 4; - private const STATUS_ABORTED = 5; - - public function __construct(IOInterface $io, Config $config, array $options = [], bool $disableTls = false) - { - \ShirabeUnsupportedClass::fail(self::class, '__construct'); - } - - public function get(string $url, array $options = []) - { - \ShirabeUnsupportedClass::fail(self::class, 'get'); - } - - public function add(string $url, array $options = []) - { - \ShirabeUnsupportedClass::fail(self::class, 'add'); - } - - public function copy(string $url, string $to, array $options = []) - { - \ShirabeUnsupportedClass::fail(self::class, 'copy'); - } - - public function addCopy(string $url, string $to, array $options = []) - { - \ShirabeUnsupportedClass::fail(self::class, 'addCopy'); - } - - public function getOptions() - { - \ShirabeUnsupportedClass::fail(self::class, 'getOptions'); - } - - public function setOptions(array $options) - { - \ShirabeUnsupportedClass::fail(self::class, 'setOptions'); - } - - public function wait(?int $index = null) - { - \ShirabeUnsupportedClass::fail(self::class, 'wait'); - } - - public function enableAsync(): void - { - \ShirabeUnsupportedClass::fail(self::class, 'enableAsync'); - } - - public function countActiveJobs(?int $index = null): int - { - \ShirabeUnsupportedClass::fail(self::class, 'countActiveJobs'); - } - - public static function outputWarnings(IOInterface $io, string $url, $data): void - { - \ShirabeUnsupportedClass::fail(self::class, 'outputWarnings'); - } - - public static function getExceptionHints(\Throwable $e): ?array - { - \ShirabeUnsupportedClass::fail(self::class, 'getExceptionHints'); - } - - public static function isCurlEnabled(): bool - { - \ShirabeUnsupportedClass::fail(self::class, 'isCurlEnabled'); - } -} diff --git a/crates/shirabe-php-rpc/php/stubs/Composer/Util/HttpDownloader.php b/crates/shirabe-php-rpc/php/stubs/Composer/Util/HttpDownloader.php new file mode 100644 index 00000000..c29b1abb --- /dev/null +++ b/crates/shirabe-php-rpc/php/stubs/Composer/Util/HttpDownloader.php @@ -0,0 +1,216 @@ +<?php + +// Generated by scripts/plugin-stub-generator; do not edit by hand. +// Proxy stub for Composer\Util\HttpDownloader: the public surface forwards to the Rust-side entity over RPC. + +namespace Composer\Util; + +use Composer\Config; +use Composer\IO\IOInterface; +use Composer\Downloader\TransportException; +use Composer\Pcre\Preg; +use Composer\Composer; +use Composer\Package\Version\VersionParser; +use Composer\Semver\Constraint\Constraint; + +class HttpDownloader implements \ShirabeRustStub +{ + /** @var int */ + protected $__rhandle; + /** @var int */ + protected $__epoch; + + /** + * Binds a stub the registry built for an existing entity. Proxy instantiation bypasses + * the constructor, which belongs to plugin code building a new entity instead. + */ + public function __shirabeBind(int $rhandle, int $epoch): void + { + $this->__rhandle = $rhandle; + $this->__epoch = $epoch; + } + + public function __destruct() + { + \ShirabeRustObjectRegistry::release($this->__rhandle); + } + + public function __shirabeRustHandleDescriptor(): array + { + return [ + '__rhandle' => $this->__rhandle, + '__class' => static::class, + '__epoch' => $this->__epoch, + ]; + } + + public function __clone() + { + // PHP has already shallow-copied this stub, so both copies would point at one + // entity and release it twice. The Rust side clones the entity instead, applying + // whatever __clone semantics the real class defines, and this copy rebinds to the + // fresh handle. Entities without clone semantics answer with an explicit error. + [$this->__rhandle, $this->__epoch] = \ShirabeRpcRuntime::callRust($this->__rhandle, '__shirabeClone', []); + \ShirabeRustObjectRegistry::adopt($this->__rhandle, $this); + } + + public function __get($name) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, '__get', [$name]); + } + + public function __set($name, $value): void + { + \ShirabeRpcRuntime::callRust($this->__rhandle, '__set', [$name, $value]); + } + + public function __isset($name): bool + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, '__isset', [$name]); + } + + public function __unset($name): void + { + \ShirabeRpcRuntime::callRust($this->__rhandle, '__unset', [$name]); + } + + public function __construct(IOInterface $io, Config $config, array $options = [], bool $disableTls = false) + { + [$this->__rhandle, $this->__epoch] = \ShirabeRpcRuntime::callRust(0, '__shirabeConstruct', [static::class, [$io, $config, $options, $disableTls]]); + \ShirabeRustObjectRegistry::adopt($this->__rhandle, $this); + } + + private const STATUS_QUEUED = 1; + private const STATUS_STARTED = 2; + private const STATUS_COMPLETED = 3; + private const STATUS_FAILED = 4; + private const STATUS_ABORTED = 5; + + public static function outputWarnings(IOInterface $io, string $url, $data): void + { + $cleanMessage = static function ($msg) use ($io) { + if (!$io->isDecorated()) { + $msg = Preg::replace('{'.chr(27).'\\[[;\d]*m}u', '', $msg); + } + + return $msg; + }; + + // legacy warning/info keys + foreach (['warning', 'info'] as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$cleanMessage($data[$type]).'</'.$type.'>'); + } + + // modern Composer 2.2+ format with support for multiple warning/info messages + foreach (['warnings', 'infos'] as $key) { + if (empty($data[$key])) { + continue; + } + + $versionParser = new VersionParser(); + foreach ($data[$key] as $spec) { + $type = substr($key, 0, -1); + $constraint = $versionParser->parseConstraints($spec['versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$cleanMessage($spec['message']).'</'.$type.'>'); + } + } + } + + public static function getExceptionHints(\Throwable $e): ?array + { + if (!$e instanceof TransportException) { + return null; + } + + if ( + false !== strpos($e->getMessage(), 'Resolving timed out') + || false !== strpos($e->getMessage(), 'Could not resolve host') + ) { + Silencer::suppress(); + $testConnectivity = file_get_contents('https://8.8.8.8', false, stream_context_create([ + 'ssl' => ['verify_peer' => false], + 'http' => ['follow_location' => false, 'ignore_errors' => true], + ])); + Silencer::restore(); + if (false !== $testConnectivity) { + return [ + '<error>The following exception probably indicates you have misconfigured DNS resolver(s)</error>', + ]; + } + + return [ + '<error>The following exception probably indicates you are offline or have misconfigured DNS resolver(s)</error>', + ]; + } + + return null; + } + + public static function isCurlEnabled(): bool + { + return \extension_loaded('curl') && \function_exists('curl_multi_exec') && \function_exists('curl_multi_init'); + } + + public function get(string $url, array $options = []) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'get', [$url, $options]); + } + + public function add(string $url, array $options = []) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'add', [$url, $options]); + } + + public function copy(string $url, string $to, array $options = []) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'copy', [$url, $to, $options]); + } + + public function addCopy(string $url, string $to, array $options = []) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'addCopy', [$url, $to, $options]); + } + + public function getOptions() + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'getOptions', []); + } + + public function setOptions(array $options) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'setOptions', [$options]); + } + + public function wait(?int $index = null) + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'wait', [$index]); + } + + public function enableAsync(): void + { + \ShirabeRpcRuntime::callRust($this->__rhandle, 'enableAsync', []); + } + + public function countActiveJobs(?int $index = null): int + { + return \ShirabeRpcRuntime::callRust($this->__rhandle, 'countActiveJobs', [$index]); + } +} diff --git a/crates/shirabe-php-rpc/src/lib.rs b/crates/shirabe-php-rpc/src/lib.rs index c898fb82..3731c691 100644 --- a/crates/shirabe-php-rpc/src/lib.rs +++ b/crates/shirabe-php-rpc/src/lib.rs @@ -1040,6 +1040,10 @@ const STUB_FILES: &[(&str, &str)] = &[ "Composer/Util/ProcessExecutor.php", include_str!("../php/stubs/Composer/Util/ProcessExecutor.php"), ), + ( + "Composer/Util/HttpDownloader.php", + include_str!("../php/stubs/Composer/Util/HttpDownloader.php"), + ), ]; /// Hand-written worker-side classes (two-world implementations with behavior of their own, not |
