feat(cli): GUI 二进制内建 CLI 子命令分发,ull 纳入发布资产(M82)
一个二进制两种用法:两个 GUI 的 main.rs 在进 UI 之前分发子命令,命中就把控制权交给 unlucky_cli::run —— 不建窗口、不探后端、不扫字体、不 dlopen 图形库。 分发判据只有一条,子命令表不重复:crates/cli 的解析器是唯一真相源。 - 首个 token 是裸词 → 子命令位置,交 CLI(未知子命令由 CLI 报错 + 提示 --help,退出 1, 不静默开窗) - 首个 token 是 flag → 只有 CLI 解析出真命令才算 CLI 调用;--data-dir X 解析成 Welcome、 --screenshot / --renderer / --diff 等 GUI 参数解析失败,一律仍走 GUI(CI 脚本零改动) 顺带:unlucky-launcher --version 以前会直接开窗,现在走 CLI 分发报版本。 packaging:ull 作为独立裸资产随每个槽位发布(make_artifacts.py + release.yml 的 assets 数组与 SHA256SUMS glob),矩阵完整性检查改成 GUI/CLI 各查一次。 app-iced 的 x11 / wayland / linux-theme-detection 收进 target 专属的 cfg(target_os) 段。 门禁实跑:cargo fmt --all --check 通过;cargo clippy --workspace --all-targets -D warnings 通过(exit 0);cargo test --workspace 通过(51 个测试二进制 / 1369 个用例,含本次新增的 5 + 5 条分发判据用例)。
This commit is contained in:
1 parent
ef3212021a
commit
1c7285cea9
11 files changed
+457
-53
No files matched your search
@@ -9,6 +9,7 @@ Release matrix (see `packaging/README.md` for the full contract):
|
||||
Linux arm64 unlucky-launcher-<ver>-linux-arm64.tar.gz
|
||||
macOS arm64 unlucky-launcher-<ver>-macos-arm64.tar.gz
|
||||
macOS x64 unlucky-launcher-<ver>-macos-x64.tar.gz
|
||||
every slot ull-<ver>-<slot>[.exe] (bare CLI binary, no archive)
|
||||
all SHA256SUMS.txt
|
||||
|
||||
`--version` is taken from the cargo workspace so a tag can never drift away from
|
||||
@@ -17,6 +18,15 @@ The archives carry the launcher binary plus LICENSE / NOTICE / README.md, which
|
||||
what the license obligations ask for; Windows ships the bare `.exe` (the single-file
|
||||
selling point) and the same three documents are attached to the Release next to it.
|
||||
|
||||
The CLI ships as its **own bare asset** on every platform rather than inside the tar.gz:
|
||||
the point of `ull` is a small single file you download and run on a machine with no
|
||||
display, and an archive it has to be extracted from adds a step for that user. The
|
||||
launcher is the archive because it needs the license texts beside it; the Release
|
||||
carries LICENSE / NOTICE / README.md anyway, so a bare `ull` loses nothing.
|
||||
|
||||
The launcher binary also answers every CLI subcommand, so `ull` is not a second
|
||||
interface — it is the version of it that links no graphics stack at all.
|
||||
|
||||
Slot and build directory are overridable because a cross build's binaries live in
|
||||
`target/<triple>/release` and the build host (x64) is not the artifact (arm64): CI
|
||||
passes both from its matrix, and the executable header is read back so a binary can
|
||||
@@ -189,6 +199,16 @@ def write_sums(out_dir: Path, assets: list[Path]) -> Path:
|
||||
return sums
|
||||
|
||||
|
||||
def stage_cli(out_dir: Path, version: str, slot: str, cli: Path) -> Path:
|
||||
"""Copy the CLI out as its own bare asset (`ull-<ver>-<slot>[.exe]`)."""
|
||||
name = f"{CLI_BIN}-{version}-{slot}" + (".exe" if cli.suffix == ".exe" else "")
|
||||
asset = out_dir / name
|
||||
shutil.copy2(cli, asset)
|
||||
# 裸文件下载即可运行:Windows 宿主机上源文件没有 x 位,这里补上(UNIX 侧才有意义)。
|
||||
asset.chmod(0o755)
|
||||
return asset
|
||||
|
||||
|
||||
def stage_archive(out_dir: Path, tag: str, version: str, launcher: Path) -> Path:
|
||||
"""tar.gz with one top-level dir holding the binary + compliance docs."""
|
||||
stem = f"unlucky-launcher-{version}-{tag}"
|
||||
@@ -259,10 +279,15 @@ def main() -> int:
|
||||
shutil.copy2(launcher, asset)
|
||||
else:
|
||||
asset = stage_archive(out_dir, slot, version, launcher)
|
||||
# CLI 与 GUI 同一矩阵槽位、各自独立资产:架构同样回读文件头校验,不给 arm64 槽位混进 x64 的 ull。
|
||||
cli = binary(CLI_BIN, build_dir, family)
|
||||
verify_arch(cli, slot)
|
||||
cli_asset = stage_cli(out_dir, version, slot, cli)
|
||||
|
||||
sums = write_sums(out_dir, [asset])
|
||||
size_mb = asset.stat().st_size / (1024 * 1024)
|
||||
print(f"artifact: {asset.name} {size_mb:.2f} MiB sha256={sha256(asset)}")
|
||||
sums = write_sums(out_dir, [asset, cli_asset])
|
||||
for item in (asset, cli_asset):
|
||||
size_mb = item.stat().st_size / (1024 * 1024)
|
||||
print(f"artifact: {item.name} {size_mb:.2f} MiB sha256={sha256(item)}")
|
||||
print(f"sums: {sums.name}")
|
||||
return 0
|
||||
|
||||
|
||||
Reference in new issue
Block a user