feat(state): track tofu-installed packages for upgrade checks
This commit is contained in:
@@ -735,3 +735,60 @@ The sandbox test (test 2) creates a sentinel file, serves an index containing `o
|
||||
- `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`.
|
||||
|
||||
---
|
||||
|
||||
## Task 18 — `tofu.state` (post-install state tracking for -Syu upgrades)
|
||||
|
||||
### Architecture
|
||||
- Module `tofu.state` depends on: `tofu.config` (Config, cacheDir), `tofu.log` (logWarn), `std.json` (parseJSON, JSONValue, JSONType), `std.file` (readText, write, rename, exists, remove), `std.datetime` (Clock).
|
||||
- State file: `cfg.cacheDir ~ "/installed.json"` — JSON array of `{"name":"...","ver":"...","installedAt":<unix-ts>,"source":"recipe"}` objects.
|
||||
- Five public APIs: `recordInstall`, `listInstalled`, `isInstalledByTofu`, `removeInstallRecord`, `installedVersion`.
|
||||
- Atomic writes: write to `.tmp` file then `rename()` — ensures the state file is never half-written.
|
||||
|
||||
### `@safe` / `@trusted` architecture
|
||||
- All public functions are `@safe`.
|
||||
- JSON operations (`parseJSON`, `JSONValue.array` property) are `@system` in Phobos — isolated behind `@trusted` wrappers (`fParseJSON`, `fArray`).
|
||||
- `JSONValue.array` returns `ref inout(JSONValue[])` — must use `ref JSONValue` parameter in the wrapper (not by-value copy) to avoid dangling reference.
|
||||
- Filesystem operations (`readText`, `write`, `rename`, `exists`, `remove`) isolated in `@trusted` wrappers — same pattern as all other modules.
|
||||
|
||||
### State file structure
|
||||
- Single JSON array at `~/.cache/tofu/installed.json` — SEPARATE from ZETA's per-package `var/db/zeta/<name>/` database.
|
||||
- `recordInstall` handles reinstall: if an entry for `name` already exists, it's replaced (new ver + timestamp); otherwise appended.
|
||||
- `removeInstallRecord` for missing entries is a no-op.
|
||||
- `installedVersion` returns `""` for unknown packages — convenience for upgrade command comparison.
|
||||
- Source is always `"recipe"` — this module only tracks recipe-built packages.
|
||||
|
||||
### Corrupted/missing state handling
|
||||
- Missing file → empty list (normal for fresh install).
|
||||
- Corrupted JSON → `logWarn` + return empty list (never throws).
|
||||
- Individual corrupted entries within a valid JSON array → skipped silently.
|
||||
- After corruption, `recordInstall` writes fresh state successfully (recovery).
|
||||
|
||||
### Test strategy (7 unittests)
|
||||
- Used temp directory pattern from `config.d`: `tempDir ~ "/tofu-test-state-" ~ suffix ~ "-" ~ thisProcessID.to!string`.
|
||||
- `scope(exit)` with `rmdirRecurse` for cleanup — same as `cache.d`/`build.d`/`install.d`.
|
||||
- `makeTestConfig(suffix)` creates isolated `Config` with unique cache dir per test.
|
||||
- Test (1): recordInstall → listInstalled contains it with correct ver ✓
|
||||
- Test (2): recordInstall twice same name → single entry, latest ver ✓
|
||||
- Test (3): isInstalledByTofu → true with filled pkg; unknown → false ✓
|
||||
- Test (4): removeInstallRecord → gone; removing missing → no-op ✓
|
||||
- Test (5): corrupted JSON file → empty list + no throw ✓
|
||||
- Test (6): missing file → empty list ✓
|
||||
- Test (7): file is valid JSON after writes (parse back externally) ✓
|
||||
- Extra: installedVersion convenience ✓
|
||||
|
||||
### `@safe` + `@trusted` attribute conflict on test helpers
|
||||
- `makeTestConfig` calls `tempDir` and `thisProcessID` which are `@safe` in DMD 2.112 (not `@system`). Marking it both `@safe` and `@trusted` causes "conflicting attribute" error. Fix: `@safe` only (no `@trusted` suffix needed).
|
||||
|
||||
### `JSONType` enum in Phobos
|
||||
- Members: `JSONType.array`, `JSONType.object`, `JSONType.string_` (underscore because `string` is a D keyword), `JSONType.integer`, `JSONType.float_`, etc.
|
||||
- `JSONValue.str` returns `string`, `.integer` returns `long`.
|
||||
|
||||
### Build verification
|
||||
- `dub test` (excluding pre-existing broken `cli.d` and `errors.d`) — 14 modules pass unittests including state.d's 7 test blocks.
|
||||
- `dub build` fails due to pre-existing `cli.d` import error (`indexOf` on string) — NOT caused by state.d. state.d compiles clean standalone (`dmd -c -o-`).
|
||||
- Evidence logged to `.omo/evidence/task-18-tofu-core.log`.
|
||||
|
||||
### Pre-existing breakage note
|
||||
- `src/tofu/cli.d` and `src/tofu/errors.d` are pre-existing broken modules from parallel agent tasks (after task 17). They block `dub build` and `dub test` (without `.skip` rename). These are outside the scope of task 18.
|
||||
|
||||
Reference in New Issue
Block a user