From b336a13bc8c7893de179d58e0923ceb9fe29e178 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Mon, 25 Jul 2022 19:46:42 +0300 Subject: [PATCH 1/2] Add get-protoc-binary console command --- README.md | 2 + bin/rr | 2 + src/GetProtocBinaryCommand.php | 233 +++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 src/GetProtocBinaryCommand.php diff --git a/README.md b/README.md index 6dfdf21..3f83a7f 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ This repository contains commands to help you work with the RoadRunner, such as: Using the `preset` option can create an example configuration file with popular plugins for different typical tasks. For example, with web preset: `get-binary --preset web`. Available presets: `web` (contains plugins `http`, `jobs`). +- `get-protoc-binary` - allows to install the latest version of the `protoc-gen-php-grpc` file compatible with + your environment (operating system, processor architecture, runtime, etc...). - `versions` - displays a list of available RoadRunner binary versions. Testing: diff --git a/bin/rr b/bin/rr index c01b3c1..8d5ecdc 100644 --- a/bin/rr +++ b/bin/rr @@ -11,6 +11,7 @@ declare(strict_types=1); use Spiral\RoadRunner\Console\GetBinaryCommand; +use Spiral\RoadRunner\Console\GetProtocBinaryCommand; use Spiral\RoadRunner\Console\VersionsCommand; use Spiral\RoadRunner\Version; @@ -68,5 +69,6 @@ $app = new Symfony\Component\Console\Application('RoadRunner CLI', Version::curr $app->add(new GetBinaryCommand()); $app->add(new VersionsCommand()); +$app->add(new GetProtocBinaryCommand()); $app->run(); diff --git a/src/GetProtocBinaryCommand.php b/src/GetProtocBinaryCommand.php new file mode 100644 index 0000000..a2c6fbd --- /dev/null +++ b/src/GetProtocBinaryCommand.php @@ -0,0 +1,233 @@ +os = new OperatingSystemOption($this); + $this->arch = new ArchitectureOption($this); + $this->version = new VersionFilterOption($this); + $this->location = new InstallationLocationOption($this); + $this->stability = new StabilityOption($this); + } + + public function getDescription(): string + { + return 'Install or update protoc-gen-php-grpc binary'; + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + $io = $this->io($input, $output); + + $target = $this->location->get($input, $io); + $repository = $this->getRepository(); + + $output->writeln(''); + $output->writeln(' Environment:'); + $output->writeln(\sprintf(' - Version: %s', $this->version->get($input, $io))); + $output->writeln(\sprintf(' - Stability: %s', $this->stability->get($input, $io))); + $output->writeln(\sprintf(' - Operating System: %s', $this->os->get($input, $io))); + $output->writeln(\sprintf(' - Architecture: %s', $this->arch->get($input, $io))); + $output->writeln(''); + + // List of all available releases + $releases = $this->version->find($input, $io, $repository); + + /** + * @var AssetInterface $asset + * @var ReleaseInterface $release + */ + [$asset, $release] = $this->findAsset($repository, $releases, $input, $io); + + // Installation + $output->writeln( + \sprintf(" - %s", $release->getRepositoryName()) . + \sprintf(' (%s):', $release->getVersion()) . + ' Downloading...' + ); + + if ($output->isVerbose()) { + $output->writeln(\sprintf(" -- %s", $asset->getName())); + } + + // Install rr binary + $file = $this->installBinary($target, $release, $asset, $io, $output); + + // Success + if ($file === null) { + $io->warning('protoc-gen-php-grpc has not been installed'); + + return 1; + } + + return 0; + } + + private function installBinary( + string $target, + ReleaseInterface $release, + AssetInterface $asset, + StyleInterface $io, + OutputInterface $out + ): ?\SplFileInfo { + $extractor = $this->assetToArchive($asset, $out) + ->extract([ + 'protoc-gen-php-grpc.exe' => $target . '/protoc-gen-php-grpc.exe', + 'protoc-gen-php-grpc' => $target . '/protoc-gen-php-grpc', + ]); + + $file = null; + while ($extractor->valid()) { + $file = $extractor->current(); + + if (!$this->checkExisting($file, $io)) { + $extractor->send(false); + continue; + } + + // Success + $path = $file->getRealPath() ?: $file->getPathname(); + $message = 'protoc-gen-php-grpc (%s) has been installed into %s'; + $message = \sprintf($message, $release->getVersion(), $path); + $out->writeln($message); + + $extractor->next(); + + if (!$file->isExecutable()) { + @chmod($file->getRealPath(), 0755); + } + } + + return $file; + } + + private function checkExisting(\SplFileInfo $bin, StyleInterface $io): bool + { + if (\is_file($bin->getPathname())) { + $io->warning('protoc-gen-php-grpc binary file already exists!'); + + if (!$io->confirm('Do you want overwrite it?', false)) { + $io->note('Skipping protoc-gen-php-grpc installation...'); + + return false; + } + } + + return true; + } + + private function findAsset( + RepositoryInterface $repo, + ReleasesCollection $releases, + InputInterface $in, + StyleInterface $io + ): array { + $osOption = $this->os->get($in, $io); + $archOption = $this->arch->get($in, $io); + $stabilityOption = $this->stability->get($in, $io); + + /** @var ReleaseInterface[] $filtered */ + $filtered = $releases + ->minimumStability($stabilityOption) + ->withAssets(); + + foreach ($filtered as $release) { + $asset = $release->getAssets() + ->filter(static fn (AssetInterface $asset): bool => + 0 === \strncmp($asset->getName(), 'protoc-gen-php-grpc', \strlen('protoc-gen-php-grpc')) + ) + ->whereArchitecture($archOption) + ->whereOperatingSystem($osOption) + ->first(); + + if ($asset === null) { + $io->warning( + \vsprintf('%s %s does not contain available assembly (further search in progress)', [ + $repo->getName(), + $release->getVersion(), + ]) + ); + + continue; + } + + return [$asset, $release]; + } + + $message = \vsprintf(self::ERROR_ENVIRONMENT, [ + $this->os->getName(), + $osOption, + $this->arch->getName(), + $archOption, + $this->stability->getName(), + $stabilityOption, + $this->version->choices($releases), + ]); + + throw new \UnexpectedValueException($message); + } + + private function assetToArchive(AssetInterface $asset, OutputInterface $out, string $temp = null): ArchiveInterface + { + $factory = new Factory(); + + $progress = new ProgressBar($out); + $progress->setFormat(' [%bar%] %percent:3s%% (%size%Kb/%total%Kb)'); + $progress->setMessage('0.00', 'size'); + $progress->setMessage('?.??', 'total'); + $progress->display(); + + try { + return $factory->fromAsset($asset, function (int $size, int $total) use ($progress) { + if ($progress->getMaxSteps() !== $total) { + $progress->setMaxSteps($total); + } + + if ($progress->getStartTime() === 0) { + $progress->start(); + } + + $progress->setMessage(\number_format($size / 1000, 2), 'size'); + $progress->setMessage(\number_format($total / 1000, 2), 'total'); + + $progress->setProgress($size); + }, $temp); + } finally { + $progress->clear(); + } + } +} From cde83209ae99f92d3442f882c7b4ca0c6192efbf Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Tue, 26 Jul 2022 10:56:12 +0300 Subject: [PATCH 2/2] Change command name --- README.md | 2 +- bin/rr | 4 ++-- ...rotocBinaryCommand.php => DownloadProtocBinaryCommand.php} | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/{GetProtocBinaryCommand.php => DownloadProtocBinaryCommand.php} (98%) diff --git a/README.md b/README.md index 3f83a7f..7a2a01d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ This repository contains commands to help you work with the RoadRunner, such as: Using the `preset` option can create an example configuration file with popular plugins for different typical tasks. For example, with web preset: `get-binary --preset web`. Available presets: `web` (contains plugins `http`, `jobs`). -- `get-protoc-binary` - allows to install the latest version of the `protoc-gen-php-grpc` file compatible with +- `download-protoc-binary` - allows to install the latest version of the `protoc-gen-php-grpc` file compatible with your environment (operating system, processor architecture, runtime, etc...). - `versions` - displays a list of available RoadRunner binary versions. diff --git a/bin/rr b/bin/rr index 8d5ecdc..6156730 100644 --- a/bin/rr +++ b/bin/rr @@ -10,8 +10,8 @@ declare(strict_types=1); +use Spiral\RoadRunner\Console\DownloadProtocBinaryCommand; use Spiral\RoadRunner\Console\GetBinaryCommand; -use Spiral\RoadRunner\Console\GetProtocBinaryCommand; use Spiral\RoadRunner\Console\VersionsCommand; use Spiral\RoadRunner\Version; @@ -69,6 +69,6 @@ $app = new Symfony\Component\Console\Application('RoadRunner CLI', Version::curr $app->add(new GetBinaryCommand()); $app->add(new VersionsCommand()); -$app->add(new GetProtocBinaryCommand()); +$app->add(new DownloadProtocBinaryCommand()); $app->run(); diff --git a/src/GetProtocBinaryCommand.php b/src/DownloadProtocBinaryCommand.php similarity index 98% rename from src/GetProtocBinaryCommand.php rename to src/DownloadProtocBinaryCommand.php index a2c6fbd..6c89569 100644 --- a/src/GetProtocBinaryCommand.php +++ b/src/DownloadProtocBinaryCommand.php @@ -23,7 +23,7 @@ /** * protoc-gen-php-grpc file download command. */ -final class GetProtocBinaryCommand extends Command +final class DownloadProtocBinaryCommand extends Command { private const ERROR_ENVIRONMENT = 'Could not find any available protoc-gen-php-grpc binary version which meets criterion (--%s=%s --%s=%s --%s=%s). Available: %s'; @@ -35,7 +35,7 @@ final class GetProtocBinaryCommand extends Command public function __construct(string $name = null) { - parent::__construct($name ?? 'get-protoc-binary'); + parent::__construct($name ?? 'download-protoc-binary'); $this->os = new OperatingSystemOption($this); $this->arch = new ArchitectureOption($this);