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
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ boot adminer — `api.php`, `Settings/Theme/screenshot.php` — each `require`
(`Env::DataDir->get()`, `Latte::engine()`, `Debug\Tracy::enable()`), so there are no function files
to special-case — PSR-4 covers everything.

**Build tooling in PHP goes to `app/cli/`, as `Desktop\Cli\` classes.** A static method with its
test in `tests/cli/`, added to `make qa`. It is dev-only autoload, and `package-app` removes the
**Build tooling in PHP goes to `app/cli/Command/`, as `Desktop\Cli\Command\` classes.** A static method listed in
`app/cli/run.php`, which the Makefile calls as `$(CLI) <command>`, with its test in `tests/cli/`, added to `make qa`. It is dev-only autoload, and `package-app` removes the
folder, so it never ships. `cli/` still holds the scripts not moved yet.

## The Adminer Desktop theme
Expand Down
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ COMPOSER_VERSION = 2.10.2
# at startup, before any argument parsing, so it lands whatever the SAPI does with argv.
WIN_INI = .cache/php-ini
COMPOSER = $(if $(EXE),PHP_INI_SCAN_DIR=$(WIN_INI)) ./bin/frankenphp$(EXE) php-cli .cache/composer.phar
# The build tooling under app/cli/: `$(CLI) <command>`, the commands listed in run.php.
CLI = ./bin/frankenphp$(EXE) php-cli app/cli/run.php

# Both paths are relative to the directory make runs in, which is the repo root; composer's
# --working-dir only chdirs later, long after PHP has loaded its extensions.
Expand Down Expand Up @@ -335,6 +337,7 @@ qa: fetch app/vendor i18n mcp-bridge-data ## Run every static check (php, go, j
./bin/frankenphp$(EXE) php-cli tests/version/AppVersionTest.php
./bin/frankenphp$(EXE) php-cli tests/shortcuts/ShortcutsTest.php
./bin/frankenphp$(EXE) php-cli tests/cli/WindowsIcoTest.php
./bin/frankenphp$(EXE) php-cli tests/cli/I18nTest.php
@sh tests/cli/kill-orphans-test.sh
@sh tests/cli/dresscode-test.sh
@sh tests/cli/dresscode-hook-test.sh
Expand Down Expand Up @@ -397,7 +400,7 @@ endif
# i18n dependency. The outputs are gitignored and rebuilt here before every build; the language
# files are the committed source. The PHP plugin UI localises itself, via AdminerDesktop::$translations.
i18n: bin/frankenphp$(EXE) app/vendor ## Generate the native-shell translations from app/src/I18n/Locale/*.php
./bin/frankenphp$(EXE) php-cli cli/i18n.php
$(CLI) i18n

# The MCP bridge's copy of what PHP owns — the tool catalogue for both settings, the offline
# sentences per locale — so the Go bridge describes tools from Server::catalogue() rather than a
Expand All @@ -413,7 +416,7 @@ bench: mcp-bridge-data ## Benchmark the MCP bridge's own cost per call

# Which strings each locale is still missing. Exits non-zero if any are, so CI can gate on it.
i18n-check: bin/frankenphp$(EXE) app/vendor ## Report native-shell translation coverage (missing strings per locale)
@./bin/frankenphp$(EXE) php-cli cli/i18n.php check
@$(CLI) i18n-check

# The exe's icon on Windows, from the same logo.png as the mac and linux ones. go build links any
# .syso beside the sources, and windres comes with the gcc cgo already needs.
Expand All @@ -422,9 +425,9 @@ WIN_ICON = $(if $(EXE),launcher/icon_windows_amd64.syso)
launcher/icon_windows_amd64.syso: launcher/icon.rc build.noindex/logo.ico
windres -O coff -i $< -o $@

build.noindex/logo.ico: assets/logo.png app/cli/WindowsIco.php app/vendor $(if $(EXE),$(WIN_INI)/gd.ini)
build.noindex/logo.ico: assets/logo.png app/cli/Command/WindowsIco.php app/vendor $(if $(EXE),$(WIN_INI)/gd.ini)
@mkdir -p $(dir $@)
$(if $(EXE),PHP_INI_SCAN_DIR=$(WIN_INI)) ./bin/frankenphp$(EXE) php-cli -r 'require "app/vendor/autoload.php"; Desktop\Cli\WindowsIco::run();'
$(if $(EXE),PHP_INI_SCAN_DIR=$(WIN_INI)) $(CLI) windows-ico

build: fetch i18n mcp-bridge-data $(WIN_ICON) ## Build the launcher binary
go build -ldflags "$(LDFLAGS)" -o build.noindex/adminer-desktop$(EXE) ./launcher
Expand Down
39 changes: 39 additions & 0 deletions app/cli/Command/I18n.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);

namespace Desktop\Cli\Command;

use Desktop\I18n\Catalog;
use Desktop\I18n\Domain;
use Desktop\I18n\Generator;

/** Regenerates the macOS .strings and the launcher's C table from the native language files, and
* gates every domain's coverage. Only the native domain is generated: the plugin domain is served
* at runtime by AdminerDesktop, so it is only checked.
*/
class I18n {
static function run(): void {
$catalog = Catalog::load(Domain::Native);
(new Generator($catalog))->generate(dirname(__DIR__, 3));
echo "i18n: wrote " . count($catalog->all()) . " .strings + launcher/i18n_gen.h\n";
}

/** Exits non-zero on a gap, for CI. */
static function check(): void {
$ok = true;
foreach (Domain::cases() as $domain) {
$ok = self::passes($domain->value, Catalog::load($domain)) && $ok;
}
exit($ok ? 0 : 1);
}

/** Prints the domain's report, and says whether it is complete with every ID well-formed. */
static function passes(string $label, Catalog $catalog): bool {
echo (new Generator($catalog))->report($label), "\n";
$malformed = $catalog->malformedIds();
if ($malformed !== []) {
echo "Malformed IDs in $label: '" . implode("', '", $malformed) . "'\n\n";
}
return $catalog->complete() && $malformed === [];
}
}
4 changes: 2 additions & 2 deletions app/cli/WindowsIco.php → app/cli/Command/WindowsIco.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types=1);

namespace Desktop\Cli;
namespace Desktop\Cli\Command;

use GdImage;
use RuntimeException;
Expand All @@ -11,7 +11,7 @@ class WindowsIco {
private const array SIZES = [16, 24, 32, 48, 64, 128, 256];

static function run(): void {
$root = dirname(__DIR__, 2);
$root = dirname(__DIR__, 3);
$logo = imagecreatefrompng("$root/assets/logo.png");
if (!$logo) {
throw new RuntimeException("ico: cannot read assets/logo.png");
Expand Down
22 changes: 22 additions & 0 deletions app/cli/run.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);

// The one entry the Makefile calls for build tooling: `$(CLI) <command>`.

use Desktop\Cli\Command\I18n;
use Desktop\Cli\Command\WindowsIco;

require dirname(__DIR__) . "/vendor/autoload.php";

$commands = [
"i18n" => I18n::run(...),
"i18n-check" => I18n::check(...),
"windows-ico" => WindowsIco::run(...),
];

$command = $commands[$argv[1] ?? ""] ?? null;
if (!$command) {
fwrite(STDERR, "usage: run.php " . implode("|", array_keys($commands)) . "\n");
exit(2);
}
$command();
2 changes: 1 addition & 1 deletion app/src/I18n/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* for the C side. English is the base and the fallback, so it gets no C rows of its own.
*/
final class Generator {
private const string BANNER = 'Generated from app/src/I18n/native/*.php by cli/i18n.php. Do not edit — edit the language files and run `make i18n`.';
private const string BANNER = 'Generated from app/src/I18n/native/*.php by app/cli/Command/I18n.php. Do not edit — edit the language files and run `make i18n`.';

public function __construct(private readonly Catalog $catalog) {
}
Expand Down
35 changes: 0 additions & 35 deletions cli/i18n.php

This file was deleted.

29 changes: 29 additions & 0 deletions tests/cli/I18nTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);

/** Does the coverage gate fail on what it exists to catch? A gate that passes everything looks
* exactly like one that found nothing, and CI runs it to decide.
*/

use Desktop\Cli\Command\I18n;
use Desktop\I18n\Catalog;
use Tester\Assert;

require dirname(__DIR__) . "/bootstrap.php";

$passes = function (array $byLocale): array {
ob_start();
$passed = I18n::passes("test", new Catalog($byLocale));
return [$passed, (string) ob_get_clean()];
};

[$passed] = $passes(['en' => ['menu.open' => 'Open'], 'cs' => ['menu.open' => 'Otevřít']]);
Assert::true($passed);

[$passed, $out] = $passes(['en' => ['menu.open' => 'Open'], 'cs' => []]);
Assert::false($passed);
Assert::contains('menu.open', $out);

[$passed, $out] = $passes(['en' => ['Bad Id' => 'Open'], 'cs' => ['Bad Id' => 'Otevřít']]);
Assert::false($passed);
Assert::contains("Malformed IDs in test: 'Bad Id'", $out);
2 changes: 1 addition & 1 deletion tests/cli/WindowsIcoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* wrong offset still builds, and shows up only as a blank icon on a machine nobody tests on.
*/

use Desktop\Cli\WindowsIco;
use Desktop\Cli\Command\WindowsIco;
use Tester\Assert;

require dirname(__DIR__) . "/bootstrap.php";
Expand Down
Loading