feat(upgrade): add -Syu upgrade for tofu-installed recipe packages
- src/tofu/commands/upgrade.d: full 7-step upgrade pipeline
- Fetches index, lists installed state, compares versions
- Shows upgrade plan with confirmation prompt
- REUSES installCommand per outdated package (force=true, noconfirm=true)
- Continue-on-failure for multi-package upgrades
- Binary-only packages excluded (pool=binary → skip)
- 6 unittests: no-installed, all-uptodate, outdated-upgraded,
removed-from-index, multi-with-failure, confirmation-denied
- src/main.d: wire upgrade stub → upgradeCommand(pa, cfg)
- Evidence: dub test (23/23 pass) + dub build clean
This commit is contained in:
@@ -86,3 +86,39 @@ Rather than adding build/install delegate seams to `installCommand`, the tests r
|
||||
**Rationale**: Keeps `installCommand`'s API surface minimal (only index/binary seams). The fake scripts exercise the full production code path through `buildAll` and `installAll`, providing higher-fidelity integration tests.
|
||||
|
||||
---
|
||||
|
||||
### Task 22: Upgrade REUSES installCommand — no duplication
|
||||
|
||||
The upgrade command calls `installCommand(pkgName, flags, cfg, ...)` for each outdated package rather than replicating the install pipeline (fetch → resolve → build → install → record). This avoids code duplication and ensures upgrades benefit from all fixes/enhancements to the install path.
|
||||
|
||||
**Rationale**: DRY principle. The install pipeline is the single source of truth for package installation. Upgrade is "install with a newer version" — same semantics, same code path.
|
||||
|
||||
### Task 22: force=true override for upgrade builds
|
||||
|
||||
When upgrade calls `installCommand`, it passes a copy of `ParsedArgs` with `force=true`. This ensures stale build output from the previous version is overwritten — ZETA's `-ReProvide` handles the overwrite at install time, but the build step must also rebuild even if `package.lua` already exists in the built cache.
|
||||
|
||||
**Rationale**: Without force, `buildAll`'s skip-if-exists optimization would see the old version's `package.lua` and skip the rebuild. Upgrades MUST rebuild.
|
||||
|
||||
### Task 22: noconfirm=true on per-package flags in upgrade
|
||||
|
||||
Each `installCommand` call within upgrade receives `noconfirm=true`. The upgrade plan already showed the overall list and obtained user confirmation; individual package installs should not re-prompt.
|
||||
|
||||
**Rationale**: Double-confirmation is poor UX. The upgrade's "Proceed? [y/N]" covers all packages. If the user wants per-package confirms, they can upgrade individually with `tofu -S <pkg>`.
|
||||
|
||||
### Task 22: Continue-on-failure for multi-package upgrades
|
||||
|
||||
Unlike `installCommand` which returns immediately on failure, `upgradeCommand` collects failures and continues with remaining packages. This ensures one broken package doesn't block updates to all others.
|
||||
|
||||
**Rationale**: Arch/pacman convention (`-Syu` continues on errors). Users expect upgrades to be best-effort. Failed packages are reported in the summary with a non-zero exit code.
|
||||
|
||||
### Task 22: Binary-only packages excluded from upgrade
|
||||
|
||||
Packages with `pool == Pool.binary` in the ZUUR index are skipped by upgrade with `logDetail`. Binary packages are managed by ZETA directly; tofu only tracks and upgrades recipe-built packages.
|
||||
|
||||
**Rationale**: Tofu's `installed.json` state only tracks recipe packages. Upgrading binary packages would require a different mechanism (e.g. querying ZETA's local database), which is outside tofu's scope.
|
||||
|
||||
### Task 22: Closure adapter for delegate type mismatch
|
||||
|
||||
`upgradeCommand`'s indexFetcher is `PackageIndex[] delegate(Config)` (with Config param), but `installCommand` expects `PackageIndex[] delegate()` (no-arg closure). The adapter is a zero-arg closure `delegate PackageIndex[]() @safe { return index; }` that captures the already-fetched index array.
|
||||
|
||||
**Rationale**: Avoids fetching the index once per package during upgrade. The single fetch at upgrade level is reused for all installCommand calls.
|
||||
|
||||
Reference in New Issue
Block a user