Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
- Always use guidelines from the `docs/guidelines` folder

## Guidelines Index

### 📖 Documentation Guidelines

Check failure on line 5 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Headings should be surrounded by blank lines

CLAUDE.md:5 MD022/blanks-around-headings Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "### 📖 Documentation Guidelines"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
**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

Check failure on line 9 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Lists should be surrounded by blank lines

CLAUDE.md:9 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- Translation workflow using L..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md
- 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

Check failure on line 15 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Headings should be surrounded by blank lines

CLAUDE.md:15 MD022/blanks-around-headings Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "### 🖥️ Console Command Development"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
**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

Check failure on line 19 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Lists should be surrounded by blank lines

CLAUDE.md:19 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- Command structure: extend `B..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md
- 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

Check failure on line 27 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Headings should be surrounded by blank lines

CLAUDE.md:27 MD022/blanks-around-headings Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "### 📝 PHP Code Standards"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
**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

Check failure on line 31 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Lists should be surrounded by blank lines

CLAUDE.md:31 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- Modern PHP 8.1+ features: co..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md
- 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

Check failure on line 39 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Headings should be surrounded by blank lines

CLAUDE.md:39 MD022/blanks-around-headings Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "### 🧪 Testing Guidelines"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
**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

Check failure on line 43 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Lists should be surrounded by blank lines

CLAUDE.md:43 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- Test structure: mirror sourc..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md
- 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

Check failure on line 50 in CLAUDE.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Files should end with a single newline character

CLAUDE.md:50:38 MD047/single-trailing-newline Files should end with a single newline character https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md047.md
3 changes: 3 additions & 0 deletions README-es.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
- [Instalación](#instalación)
- [Inicio Rápido](#inicio-rápido)
- [Uso desde Línea de Comandos](#uso-desde-línea-de-comandos)
- [Inicializar Configuración](#inicializar-configuración)

Check failure on line 40 in README-es.md

View workflow job for this annotation

GitHub Actions / markdown-linting

Unordered list indentation

README-es.md:40:1 MD007/ul-indent Unordered list indentation [Expected: 2; Actual: 4] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md007.md
- [Descargar Software](#descargar-software)
- [Ver Software](#ver-software)
- [Construir Software Personalizado](#construir-software-personalizado)
Expand Down Expand Up @@ -153,6 +153,9 @@
# 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
```
Expand Down
3 changes: 3 additions & 0 deletions README-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
3 changes: 3 additions & 0 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
19 changes: 18 additions & 1 deletion resources/software.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
{
Expand All @@ -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"
}
}
]
}
70 changes: 62 additions & 8 deletions src/Command/Get.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,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
Expand Down Expand Up @@ -66,7 +68,7 @@
$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');
}

Expand All @@ -88,9 +90,11 @@
parent::execute($input, $output);
$container = $this->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);
Expand Down Expand Up @@ -121,7 +125,7 @@
*
* @return list<DownloadConfig> 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 === []) {
Expand All @@ -134,10 +138,60 @@
$toDownload[$action->software] = $action;
}

return \array_map(

Check failure on line 141 in src/Command/Get.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

LessSpecificReturnStatement

src/Command/Get.php:141:16: LessSpecificReturnStatement: The type 'array<array-key, Internal\DLoad\Module\Config\Schema\Action\Download>' is more general than the declared return type 'list<Internal\DLoad\Module\Config\Schema\Action\Download>' for Internal\DLoad\Command\Get::getDownloadActions (see https://psalm.dev/129)
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.
*
* 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 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}.",
),
);

$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}.",
));
}
}
Loading