From 6504a6e6f8402b8bc686af198acffd5b6c6fc8c3 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 11:13:01 +0400 Subject: [PATCH 1/6] fix: Consider stability, OS, and architecture flags in `get` command --- src/Command/Get.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Command/Get.php b/src/Command/Get.php index f97dedf..3ef02b4 100644 --- a/src/Command/Get.php +++ b/src/Command/Get.php @@ -88,6 +88,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int parent::execute($input, $output); $container = $this->container; + $input->hasOption('stability') and + $container->set(Stability::fromString((string) $input->getOption('stability'))); + $input->hasOption('os') and + $container->set(OperatingSystem::tryFromString((string) $input->getOption('os'))); + $input->hasOption('arch') and + $container->set(Architecture::tryFromString((string) $input->getOption('arch'))); + /** @var Actions $actionsConfig */ $actionsConfig = $container->get(Actions::class); $actions = $this->getDownloadActions($input, $actionsConfig); From 7ec999c81b1a5effbf0d7009c352e0dba9cc4780 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 11:13:22 +0400 Subject: [PATCH 2/6] chore: add `mago` binary into registry --- resources/software.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/resources/software.json b/resources/software.json index a95149c..c87ea98 100644 --- a/resources/software.json +++ b/resources/software.json @@ -138,7 +138,7 @@ { "name": "Trap", "alias": "trap", - "description": "A minimized version of the Buggregator Server that does not require Docker and is intended solely for local use.\n", + "description": "A minimized version of the Buggregator Server that does not require Docker and is intended solely for local use.", "homepage": "https://buggregator.dev/", "repositories": [ { @@ -151,6 +151,23 @@ "name": "trap", "version-command": "--version" } + }, + { + "name": "Mago", + "alias": "mago", + "description": "Mago is a toolchain for PHP that aims to provide a set of tools to help developers write better code.", + "homepage": "https://mago.carthage.software/", + "repositories": [ + { + "type": "github", + "uri": "carthage-software/mago", + "asset-pattern": "/^mago.*/" + } + ], + "binary": { + "name": "mago", + "version-command": "--version" + } } ] } From fa59327803e57636d4b7534f0c7587aa97404c25 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 11:27:14 +0400 Subject: [PATCH 3/6] fix: Better validation of flags for `get` command --- src/Command/Get.php | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/Command/Get.php b/src/Command/Get.php index 3ef02b4..443821e 100644 --- a/src/Command/Get.php +++ b/src/Command/Get.php @@ -10,8 +10,10 @@ use Internal\DLoad\Module\Common\Stability; use Internal\DLoad\Module\Config\Schema\Action\Download as DownloadConfig; use Internal\DLoad\Module\Config\Schema\Actions; +use Internal\DLoad\Service\Container; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -66,7 +68,7 @@ public function configure(): void $this->addOption('path', null, InputOption::VALUE_OPTIONAL, 'Path to store the binary, e.g. "./bin"', "."); $this->addOption('arch', null, InputOption::VALUE_OPTIONAL, 'Architecture, e.g. "amd64", "arm64" etc.'); $this->addOption('os', null, InputOption::VALUE_OPTIONAL, 'Operating system, e.g. "linux", "darwin" etc.'); - $this->addOption('stability', null, InputOption::VALUE_OPTIONAL, 'Stability, e.g. "stable", "beta" etc.'); + $this->addOption('stability', null, InputOption::VALUE_OPTIONAL, 'Minimum stability, e.g. "rc", "beta" etc.'); $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force download even if binary exists'); } @@ -88,12 +90,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int parent::execute($input, $output); $container = $this->container; - $input->hasOption('stability') and - $container->set(Stability::fromString((string) $input->getOption('stability'))); - $input->hasOption('os') and - $container->set(OperatingSystem::tryFromString((string) $input->getOption('os'))); - $input->hasOption('arch') and - $container->set(Architecture::tryFromString((string) $input->getOption('arch'))); + $this->applyFlags($input, $container); /** @var Actions $actionsConfig */ $actionsConfig = $container->get(Actions::class); @@ -147,4 +144,35 @@ private function getDownloadActions(InputInterface $input, Actions $actionsConfi $input->getArgument(self::ARG_SOFTWARE), ); } + + /** + * Applies command-line flags to override container settings. + * + * Sets architecture, operating system, and stability in the container + * based on provided CLI options. + * + * @param InputInterface $input Command input + * @param Container $container Dependency injection container + * + * @throws InvalidArgumentException When an unknown value is provided + */ + private function applyFlags(InputInterface $input, Container $container): void + { + $stability = (string) $input->getOption('stability'); + $stability === '' or $container->set( + Stability::fromString((string) $input->getOption('stability')) ?? throw new InvalidArgumentException( + "Unknown stability level: {$stability}", + ), + ); + + $os = (string) $input->getOption('os'); + $os === '' or $container->set(OperatingSystem::tryFromString($os) ?? throw new InvalidArgumentException( + "Unknown operating system: {$os}", + )); + + $arch = (string) $input->getOption('arch'); + $arch === '' or $container->set(Architecture::tryFromString($arch) ?? throw new InvalidArgumentException( + "Unknown architecture: {$arch}", + )); + } } From 7cadae6afb5ac05e13f2ca22105482f0855b5da6 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 14:21:46 +0400 Subject: [PATCH 4/6] feat: add version syntax support for software packages in `get` command --- src/Command/Get.php | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/Command/Get.php b/src/Command/Get.php index 443821e..7471c90 100644 --- a/src/Command/Get.php +++ b/src/Command/Get.php @@ -33,8 +33,8 @@ * # Download specific version of software * ./vendor/bin/dload get rr --stability=beta * - * # Download multiple software packages - * ./vendor/bin/dload get rr dolt temporal + * # Download multiple software packages with versions and stability + * ./vendor/bin/dload get rr dolt:1.44.1 temporal:1.*@alpha * * # Download software defined in config file * ./vendor/bin/dload get --config=./dload.xml @@ -90,11 +90,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int parent::execute($input, $output); $container = $this->container; - $this->applyFlags($input, $container); + self::applyFlags($input, $container); /** @var Actions $actionsConfig */ $actionsConfig = $container->get(Actions::class); - $actions = $this->getDownloadActions($input, $actionsConfig); + $actions = self::getDownloadActions($input, $actionsConfig); $output->writeln('Architecture: ' . $container->get(Architecture::class)->name); $output->writeln(' Op. system: ' . $container->get(OperatingSystem::class)->name); @@ -125,7 +125,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int * * @return list List of download configurations to process */ - private function getDownloadActions(InputInterface $input, Actions $actionsConfig): array + private static function getDownloadActions(InputInterface $input, Actions $actionsConfig): array { $argument = $input->getArgument(self::ARG_SOFTWARE); if ($argument === []) { @@ -139,12 +139,31 @@ private function getDownloadActions(InputInterface $input, Actions $actionsConfi } return \array_map( - static fn(mixed $software): DownloadConfig => $toDownload[$software] - ?? DownloadConfig::fromSoftwareId((string) $software), - $input->getArgument(self::ARG_SOFTWARE), + static fn(string $software): DownloadConfig => $toDownload[$software] ?? self::parseSoftware($software), + (array) $input->getArgument(self::ARG_SOFTWARE), ); } + /** + * Parses a software identifier into a download configuration. + * + * Supports "name:version" format to specify exact versions. + * E.g. "rr:2.10.0", "dolt:1.2.3@beta", "temporal:1.3.1-priority", etc. + * + * @param string $software Software identifier, e.g. "rr" or "dolt:1.2.3" + * @return DownloadConfig Parsed download configuration + */ + private static function parseSoftware(string $software): DownloadConfig + { + [$name, $version] = \explode(':', $software, 2) + [1 => '']; + $name === '' and throw new InvalidArgumentException("Software name cannot be empty, given: {$software}."); + + $action = DownloadConfig::fromSoftwareId($name); + $version === '' or $action->version = $version; + + return $action; + } + /** * Applies command-line flags to override container settings. * @@ -156,23 +175,23 @@ private function getDownloadActions(InputInterface $input, Actions $actionsConfi * * @throws InvalidArgumentException When an unknown value is provided */ - private function applyFlags(InputInterface $input, Container $container): void + private static function applyFlags(InputInterface $input, Container $container): void { $stability = (string) $input->getOption('stability'); $stability === '' or $container->set( Stability::fromString((string) $input->getOption('stability')) ?? throw new InvalidArgumentException( - "Unknown stability level: {$stability}", + "Unknown stability level: {$stability}.", ), ); $os = (string) $input->getOption('os'); $os === '' or $container->set(OperatingSystem::tryFromString($os) ?? throw new InvalidArgumentException( - "Unknown operating system: {$os}", + "Unknown operating system: {$os}.", )); $arch = (string) $input->getOption('arch'); $arch === '' or $container->set(Architecture::tryFromString($arch) ?? throw new InvalidArgumentException( - "Unknown architecture: {$arch}", + "Unknown architecture: {$arch}.", )); } } From 5bc33780ebca5b3538339de8282afb817634bf7b Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 14:22:44 +0400 Subject: [PATCH 5/6] docs(readme): describe the new version syntax in `get` command --- README-es.md | 3 +++ README-ru.md | 3 +++ README-zh.md | 3 +++ README.md | 3 +++ 4 files changed, 12 insertions(+) diff --git a/README-es.md b/README-es.md index bae131a..1ebccc6 100644 --- a/README-es.md +++ b/README-es.md @@ -153,6 +153,9 @@ También puedes descargar la versión más reciente desde [GitHub releases](http # Descargar paquetes específicos ./vendor/bin/dload get rr temporal +# Descargar con versiones específicas +./vendor/bin/dload get rr:2025.1.0 dolt:1.44.1 temporal:1.*@alpha + # Descargar con opciones adicionales ./vendor/bin/dload get rr --stability=beta --force ``` diff --git a/README-ru.md b/README-ru.md index 85f4f9a..a301ed7 100644 --- a/README-ru.md +++ b/README-ru.md @@ -154,6 +154,9 @@ composer require internal/dload -W # Загрузить конкретные пакеты ./vendor/bin/dload get rr temporal +# Загрузить с указанием конкретных версий +./vendor/bin/dload get rr:2025.1.0 dolt:1.44.1 temporal:1.*@alpha + # Загрузить с дополнительными опциями ./vendor/bin/dload get rr --stability=beta --force ``` diff --git a/README-zh.md b/README-zh.md index 668279b..c3a3d22 100644 --- a/README-zh.md +++ b/README-zh.md @@ -153,6 +153,9 @@ composer require internal/dload -W # 下载指定软件包 ./vendor/bin/dload get rr temporal +# 下载指定版本的软件包 +./vendor/bin/dload get rr:2025.1.0 dolt:1.44.1 temporal:1.*@alpha + # 带选项下载 ./vendor/bin/dload get rr --stability=beta --force ``` diff --git a/README.md b/README.md index f3ae368..12b410c 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,9 @@ Alternatively, you can download the latest release from [GitHub releases](https: # Download specific packages ./vendor/bin/dload get rr temporal +# Download with specific versions and minimum stability +./vendor/bin/dload get rr:2025.* dolt:1.44.1 mago:1.*@alpha + # Download with options ./vendor/bin/dload get rr --stability=beta --force ``` From d7af815d0f20bec3652608ef15a6e4404f4b0775 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 29 Aug 2025 14:26:38 +0400 Subject: [PATCH 6/6] chore: add guidelines for Claude Code context --- CLAUDE.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9dd4261 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,50 @@ +- Always use guidelines from the `docs/guidelines` folder + +## Guidelines Index + +### 📖 Documentation Guidelines +**Path:** `docs/guidelines/how-to-translate-readme-docs.md` +**Value:** Standardizes documentation translation process and multilingual content management +**Key Areas:** +- Translation workflow using LLMs for documentation +- Multilanguage README pattern using ISO 639-1 codes (`README-{lang_code}.md`) +- Quality standards: preserve technical content, ensure natural language flow +- Review process for translated content +- MAPS framework for complex translations + +### 🖥️ Console Command Development +**Path:** `docs/guidelines/how-to-write-console-command.md` +**Value:** Ensures consistent CLI interface design and proper Symfony console integration +**Key Areas:** +- Command structure: extend `Base` class, use `#[AsCommand]` attribute +- Required methods: `configure()` and `execute()` +- Type system: always use `Path` value object instead of strings for file paths +- Interactive patterns: use `$input->isInteractive()` for detection +- Error handling: proper return codes (`Command::SUCCESS`, `Command::FAILURE`, `Command::INVALID`) +- Best practices: method extraction, confirmation dialogs, file operation patterns +- Available services through DI container (Logger, StyleInterface, etc.) + +### 📝 PHP Code Standards +**Path:** `docs/guidelines/how-to-write-php-code-best-practices.md` +**Value:** Maintains modern PHP code quality and leverages latest language features for better performance and maintainability +**Key Areas:** +- Modern PHP 8.1+ features: constructor promotion, union types, match expressions, throw expressions +- Code structure: PER-2 standards, single responsibility, final classes by default +- Enumerations: use enums for fixed value sets, CamelCase naming, backed enums for primitives +- Immutability: readonly properties, `with` prefix for immutable updates +- Type system: precise PHPDoc annotations, generics, non-empty-string types +- Comparison patterns: strict equality (`===`), null coalescing (`??`), avoid `empty()` +- Dependency injection and IoC container patterns + +### 🧪 Testing Guidelines +**Path:** `docs/guidelines/how-to-write-tests.md` +**Value:** Ensures comprehensive test coverage with modern PHPUnit practices and proper test isolation +**Key Areas:** +- Test structure: mirror source structure, `final` test classes, Arrange-Act-Assert pattern +- Module testing: independent test areas with dedicated `Stub` directories +- Naming: `{ClassUnderTest}Test`, descriptive method names +- Modern PHPUnit: PHP 8.1+ attributes (`#[CoversClass]`, `#[DataProvider]`), data providers with generators +- Isolation: mock dependencies, use test doubles, reset state between tests +- **Critical restrictions**: DO NOT mock enums or final classes - use real instances +- Error testing: expectException before Act phase +- Test traits for shared functionality \ No newline at end of file