Commit Graph
31 Commits
Author SHA1 Message Date
huntedbytheirs 9473b01a79 fix(info): handle missing deps field without unsigned indexOf wrap 2026-08-08 18:54:05 -04:00
huntedbytheirs fc979b650d test(e2e): add full smoketest covering install, search, upgrade, remove
Creates tests/e2e/smoketest.sh — a hermetic end-to-end test that:
- Sets up a mock ZUUR (python3 http.server serving local index/recipes)
- Creates fake zeta-makepkg and zeta scripts (no real Lua tools needed)
- Tests the full pipeline: search → install → upgrade → info → remove
- Verifies exit codes (0, 2 for not-found)
- Verifies installed.json state tracking
- Verifies binary installation/removal via ZETA_ROOT

BUG FOUND (documented in problems.md, not fixed):
- info.d scanDepsArray stores ptrdiff_t indexOf() result in size_t,
  causing ArrayIndexError when recipe lacks a deps field.
  Workaround: recipe includes deps = {}.

Evidence: .omo/evidence/task-27-tofu-core.log — 16/16 checks pass.
2026-08-08 18:52:19 -04:00
huntedbytheirs 70ab40abb9 fix(errors): create cache dir before writing lock file 2026-08-08 18:44:39 -04:00
huntedbytheirs bd26e7f428 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
2026-08-08 18:43:21 -04:00
huntedbytheirs 4d8af8f13d feat(install): add -S install with --dry-run and --noconfirm flags
Create full install pipeline (plan task 21):
- src/tofu/recipeparse.d: light .recipe Lua parser (parseRecipeFile)
- src/tofu/commands/install.d: installCommand with delegate seams
- 8 unit tests covering: happy path, not-found, dep cycle, build
  failure, install failure, --dry-run, --noconfirm, user abort
- All 21 modules pass dub test, dub build passes
- Evidence: .omo/evidence/task-21-tofu-core.log
2026-08-08 18:38:22 -04:00
huntedbytheirs 018640b27f feat(info): add -Si package info display 2026-08-08 18:30:36 -04:00
huntedbytheirs 7164cd7c04 feat(remove): add -R remove via zeta
- Add runRemove() to tofu.install (zeta subprocess module)
  - Same pipeProcess/tee/rolling-buffer pattern as runLocalProvide
  - Uses -Remove instead of -LocalProvide
  - Appends --force flag when force=true
- Create tofu.commands.remove with removeCommand()
  - Checks tofu-installed via state.d (warns if not, still proceeds)
  - Confirm prompt (Remove <name>? [y/N]) unless --noconfirm
  - Detects 'still required by' in zeta error → suggests --force
  - Cleans up install record on success
- Wire remove case in main.d dispatch
- 6 unittests with fake zeta scripts
2026-08-08 18:29:54 -04:00
huntedbytheirs 066700b540 feat(ui): add spinner, progress output, and summary table 2026-08-08 18:27:52 -04:00
huntedbytheirs de77fb1733 feat(search): add -Ss ZUUR index search
Implement tofu.commands.search module with searchCommand():
- Case-insensitive substring match on name, summary, version
- Sort results alphabetically by name
- Output format: zuur/<pool> <name> <ver>\n    <summary>
- Exit codes: 0 (success), 1 (no match), 6 (network error)
- Testable via injectable indexFetcher delegate (7 unit tests)
- Wire search dispatch in main.d (replaces stub)
2026-08-08 18:26:41 -04:00
huntedbytheirs 854e7155f9 fix(errors): add actionable error messages for all 16 failure paths 2026-08-08 18:21:17 -04:00
huntedbytheirs 47cfdee424 feat(cli): add yay/paru-style command parsing 2026-08-08 18:19:05 -04:00
huntedbytheirs 44024ca37d feat(state): track tofu-installed packages for upgrade checks 2026-08-08 18:17:24 -04:00
huntedbytheirs 88047eb4ca feat(install): orchestrate install via single root-package LocalProvide call 2026-08-08 18:12:42 -04:00
huntedbytheirs 8f9a3c85a4 feat(build): orchestrate sequential topological builds with fail-fast
Add buildAll() to src/tofu/build.d — sequential builder with:
- Empty plan → 'nothing to build' no-op
- Recipe existence pre-check → fail-fast on missing
- Skip-if-exists: don't rebuild when output present (unless --force)
- Separator line: U+2500 box chars '──── building <name> (i/n) ────'
- Fail-fast: halt immediately on first BuildException

6 unittests: all succeed, first fails, empty plan, skip existing,
force rebuild, missing recipe.
2026-08-08 18:09:06 -04:00
huntedbytheirs c43c1a78d9 feat(install): invoke zeta -LocalProvide with ZETA_LOCAL_PACKAGES and ZETA_REPO env 2026-08-08 18:05:27 -04:00
huntedbytheirs da19ac98b1 feat(build): invoke zeta-makepkg with conditional --force
- Add tofu.build module with runMakepkg() public API
- BuildException for missing binary, non-zero exit, missing output
- Real-time stdout/stderr streaming with last-20-lines stderr capture
- Conditional --force flag based on force parameter
- zetaToolchainPath resolution from Config
- 7 unittests using fake zeta-makepkg shell scripts
- pipeProcess + Redirect.stderr for tee approach
2026-08-08 18:05:07 -04:00
huntedbytheirs 7928b4d5f2 feat(resolve): generate build plan from constrained dep tree
Add generateBuildPlan() to tofu.resolve — filters constrained dep tree
to recipe-only packages, verifies cached recipes exist, and produces
an ordered BuildPlan ready for the build orchestrator (task 15).

- Skips binary-satisfied deps (Zeta handles those)
- Preserves topological order from constrained nodes (deps-first)
- Missing recipe files: re-fetch via injectable delegate seam
  (production wires tofu.fetch.fetchRecipe; tests inject mocks)
- Empty plan (all binary) → returns empty BuildPlan + log info
- Root always recipe — always included in plan
- 6 unittests: filter binary, fetch seam, missing no-seam,
  all-binary empty, root with binary dep, cache hit no-fetch
- dub test + dub build pass with warningsAsErrors
2026-08-08 17:58:25 -04:00
huntedbytheirs ba411e9fc4 feat(resolve): add version-constraint-aware dep resolution with binary fallback 2026-08-08 17:53:45 -04:00
huntedbytheirs 406a87ca41 chore: gitignore test runner artifacts 2026-08-08 17:47:29 -04:00
huntedbytheirs 6a153ef1ac feat(deps): add dep tree builder with version constraint parsing
Port of ZETA lib/deps.lua depth-first resolution algorithm:
- DepNode/DepTree structs for topologically-ordered dependency trees
- resolveDepTree() with function-pointer seam for testability
- Cycle detection with full chain message (e.g. 'A -> B -> A')
- Memoization to skip already-resolved nodes
- Parses recipe.deps string[] into DepConstraint[] via DepConstraint.parse

7 unittests: constraint parsing, linear chain, self-cycle, mutual
cycle, missing dep propagation, diamond shared dep, leaf node.
2026-08-08 17:46:27 -04:00
huntedbytheirs b3cdde4d7c feat(cache): add recipe cache with index-version-based staleness check 2026-08-08 17:45:14 -04:00
huntedbytheirs d7d0d2ec6d feat(fetch): download ZUUR recipe directories to cache
Implements tofu.fetch module with fetchRecipe() that downloads
ZUUR recipe directories using a known-file strategy (no directory
listing assumed). Downloads .recipe (required), package.lua (optional),
build.sh (optional), and custom build_script references.

Key features:
- Light recipe scanning for build_system/build_script discovery
- 404 on .recipe → 'package not found' user-friendly error
- 404 on optional files → logged and skipped
- 404 on referenced build_script → real error
- Partial file cleanup on failure
- 5 unittests using python3 http.server for multi-file scenarios

8/8 modules pass, dub build succeeds with warnings-as-errors.
2026-08-08 17:38:41 -04:00
huntedbytheirs b367f21d29 feat(binary): check zuur/binary package.lua version against constraints 2026-08-08 17:38:21 -04:00
huntedbytheirs c876821cda feat(index): fetch and sandbox-parse ZUUR index.lua
- Module tofu.index: download index via tofu.http.get, sandbox parse via Lua subprocess
- Whitelist sandbox (ported from ZETA lib/sandbox.lua): index code has zero I/O/exec access
- Lua 5.1/5.2+ compatible: setfenv detection with fallback to load() env param
- JSON escaping: handles quotes, backslashes, control characters in string values
- Defensive parsing: skips entries with empty names or invalid pool values
- 10 unittest blocks: happy path, malicious os.execute/io.open blocked, lua not found, bad JSON, empty index, missing name skip, invalid pool skip, syntax error, string escaping
- Evidence: 7 modules pass unittests, dub build passes with warnings-as-errors
2026-08-08 17:37:59 -04:00
huntedbytheirs 777de734f8 feat(http): add synchronous HTTP client with std.net.curl 2026-08-08 17:30:34 -04:00
huntedbytheirs c545879115 feat(version): port rpm-style version comparison from ZETA 2026-08-08 17:22:06 -04:00
huntedbytheirs 348f0e3bac feat(types): add core data structures
PackageIndex, Recipe, DepConstraint, BuildPlan, BuildResult, CacheManifest, BinaryCheckResult structs. Pool/BuildSystem/DepOp/Source enums. DepConstraint.parse() ported from ZETA vercmp.lua. TypesException for parsing errors. All @safe, all strings default to empty string.
2026-08-08 17:17:20 -04:00
huntedbytheirs 3fb03b23d7 feat(config): add env var and XDG TOML config loading
- Config struct with zuurUrl, cacheDir, zetaToolchainPath, zetaPath, defaultJobs
- Priority: env vars > TOML config file > hardcoded defaults
- Env vars: TOFU_ZUUR_URL, TOFU_CACHE_DIR, TOFU_ZETA_TOOLCHAIN_PATH,
  TOFU_ZETA_PATH, TOFU_DEFAULT_JOBS, TOFU_CONFIG
- TOML [core] section parsing via toml package v1.0.0
- URL helpers: recipesUrl, binaryManifestUrl, indexUrl
- Cache path helpers: recipesCacheDir, builtDir, builtPackagesDir
- Malformed TOML → stderr warning + fallback to defaults
- 14 unittest blocks covering all config scenarios
- All tests pass: dub test → 3 modules passed unittests
2026-08-08 17:17:04 -04:00
huntedbytheirs c331416623 feat(log): add colored NO_COLOR-aware logging 2026-08-08 17:16:50 -04:00
huntedbytheirs b2d1df72f9 chore: scaffold dub project with TOML dep 2026-08-08 17:10:04 -04:00
huntedbytheirs 709bb310e1 Initial commit 2026-08-08 16:11:02 -04:00