feat(install): orchestrate install via single root-package LocalProvide call

This commit is contained in:
2026-08-08 18:12:42 -04:00
parent 8f9a3c85a4
commit 88047eb4ca
3 changed files with 456 additions and 0 deletions
+51
View File
@@ -684,3 +684,54 @@ The sandbox test (test 2) creates a sentinel file, serves an index containing `o
- `dub test` passes — all 13 modules, including 6 new buildAll unittests.
- `dub build` passes with `warningsAsErrors`.
- Evidence logged to `.omo/evidence/task-15-tofu-core.log`.
---
## Task 17 — `tofu.install.installAll` (install orchestrator)
### Architecture
- `installAll(BuildPlan plan, Config cfg)` added to `tofu.install` — single root-package `-LocalProvide` call.
- Imports added: `tofu.types` (selective: `BuildPlan`, `BuildPlanEntry`, `Source`), `std.conv : to`, `std.file : exists`.
- Reuses `runLocalProvide` — no new process-spawning logic.
### Algorithm
1. **Empty plan** → `logInfo("nothing to install")`, return early.
2. **Verify built cache**: for each `Source.recipe` entry, check `cfg.builtPackagesDir()/name/package.lua` exists. Missing → `InstallException("built package missing from cache: <name> (was the build skipped?)")`.
3. **Root = last entry** in `plan.order()` — matches `deps.resolve`/`generateBuildPlan` convention (topological order, root last).
4. **Single call**: `runLocalProvide(rootName, cfg)` — ZETA's `deps.resolve` walks the full tree from `ZETA_LOCAL_PACKAGES` + `ZETA_REPO`.
5. **Success**: `logOk("installed <root> with N dependencies")` where N = `order.length - 1`.
6. **InstallException from `runLocalProvide`**: propagates to caller (no catch needed — install command records state).
### "already installed" handling
- Handled internally by `runLocalProvide` — exit 0 + "already installed" substring in output → `logInfo("already installed — skipping")`, no throw.
- `installAll` continues to `logOk` after.
### Dependencies counted
- All entries in `BuildPlan` are recipe-sourced (binary excluded by `generateBuildPlan`). Root is last entry. Dep count = `order.length - 1`.
### `@safe` / `@trusted` architecture
- `installAll` is `@safe` public.
- Only `std.file.exists` requires `@trusted` wrapper — inline lambda `() @trusted { pkgExists = exists(pkgPath); }()`.
### Imports strategy
- Top-level selective import: `import tofu.types : BuildPlan, BuildPlanEntry, Source;` — avoids pulling in the full types module.
- `import std.conv : to;` for `to!string(size_t)`.
- `import std.file : exists;` at module level for the built-cache verification check.
### Unittests — 5 new test blocks (test 1–5 for installAll)
- Reused existing test infrastructure: `makeTempDir`, `removeDir`, `writeFakeScript`, `testConfig`.
- Test (1): plan [B, C, A] with all package.lua + fake zeta captures `$2` → "A" only, no "B"/"C".
- Test (2): plan missing B's package.lua → `InstallException` "built package missing from cache: B".
- Test (3): empty plan → no-op, no throw.
- Test (4): fake zeta exits 1 → `InstallException` "install failed for A".
- Test (5): fake zeta prints "already installed" + exits 0 → no throw, `logOk` succeeds.
### Arg capture pattern
- Fake zeta script: `echo "$2" >> <path>` — `$2` = package name (args: `fake-zeta -LocalProvide <pkgName> --pass`).
- Previous learnings used `$3` incorrectly — in bash, `$0`=script name, `$1`=-LocalProvide, `$2`=pkgName, `$3`=--pass.
### Build verified
- `dub test` passes — all 13 modules, including 5 new installAll unittests (plus 5 pre-existing runLocalProvide tests = 10 total in install.d).
- `dub build` passes with `warningsAsErrors`.
- No D LSP server configured for `.d` — diagnostics verified via compiler.
- Evidence logged to `.omo/evidence/task-17-tofu-core.log`.