cli/manifest/inventory: tt package list and tt package uninstall - #1334
Open
bigbes wants to merge 3 commits into
Open
cli/manifest/inventory: tt package list and tt package uninstall#1334bigbes wants to merge 3 commits into
bigbes wants to merge 3 commits into
Conversation
Unpack a .tt package archive into a scope and bring the tree to a runnable state. A with-deps archive in the project scope is a plain offline extraction (tar xf, no network); a --without-deps archive additionally refetches its dependency closure from the registry by the lock's exact pins, reusing tt package fetch's install-with-DepsNone loop. user and system scopes accept only --without-deps archives — a with-deps archive there is refused from the archive header before anything touches disk. Joint resolution handles several packages sharing one project .rocks/ tree: a dependency they lock at different versions is reconciled to the highest locked version that satisfies every package's declared constraint, or the install fails with a breakdown of who pinned what. The choice is made only among versions already locked — no registry is consulted — over go-luarocks' version and constraint primitives. Per-package metadata (manifest, lock, VERSION) is recorded under .rocks/manifests/<pkg>/ for inventory and dependency refcounting. --locked refuses an archive whose lock diverges from its manifest, --upgrade installs only a strictly higher version, --force reinstalls over a collision, --yes skips the reconciliation prompt. A single archive surfaces its own failure code; a multi-archive run where some succeed and some fail exits 3. The archive reader is new: pack shipped a write-only tar+zstd writer, so install carries its own reader, with a tar-slip guard on every entry. Closes TNTP-8613
Install writes the per-package metadata under manifests/<pkg>/, and list/uninstall read it back. The three have to agree on the layout down to the directory name, so keeping the scope resolution, the metadata file names and the installed-package reader inside the install package would mean the inventory commands either duplicate them or import a package named after the one operation they do not perform. Move them into cli/manifest/state: Scope and ResolveLayout, the Package reader over manifests/ plus the primary package, WriteMetadata and its new inverse RemoveMetadata, and the rock path helpers install already used to drop a stale version. install keeps Scope as an alias so the CLI wiring is unchanged, and wraps the state errors so a bad --scope still exits 1. The ownership ledger uninstall will stand on is derived, not stored: a dependency is owned by every installed package whose lock pins it, so LockedDependencies over what is left under manifests/ is the whole count. Nothing has to be kept in sync by hand. Also read the primary package's VERSION file, which install had no use for but list does, and note in .golangci.yml that depguard matches the longest prefix — adding a sub-package to an allow list shadows the broader entry for its siblings. Part of TNTP-8614
Both commands work over what an install left on disk and nothing else: the source of truth is the metadata under .rocks/manifests/<pkg>/, so neither contacts a registry, runs a build, nor re-resolves anything. list reports the packages present in a scope — in project the project's own package plus every guest. -o picks the format, defaulting to a table on a terminal and YAML otherwise, so piped output is parseable without the caller remembering a flag. What it reports is what is on disk, deliberately not what a manifest declares. --tree renders the scope as one tree rooted at the project's own package. Guests hang off it because they are installed into its .rocks/ and share it, marked (guest) rather than presented as things the project requires. Each rock sits under whatever pulled it in: a lock stores the dependency closure flattened, with the parent discarded, but LuaRocks records every installed rock's own requirements in the tree manifest, so the edges survive there. Rocks the walk cannot root — a tree carrying no manifest, or incomplete edges — are still listed, under a group that says the parent is not recorded rather than implying the package asked for them. uninstall removes a guest and the shared dependencies it was the last to hold. Ownership is derived rather than counted: a dependency belongs to every installed package whose lock pins it, so setting the target aside and re-reading the remaining locks is the whole ledger, with no separate counter to drift out of sync. Two consequences are worth naming. Ownership covers the closure and not just declarations, so a rock no manifest ever named still goes with its last owner. And a guest that another package merely depends on is never swept away as a shared rock — it has its own metadata, so only an uninstall naming it removes it. Removal order is files first, metadata last, so an interrupted run can be repeated: the package still reads as installed until its files are gone. The package name is validated before anything is removed, since it becomes a path. Every rock in --tree is annotated with what an uninstall would do to it, and a test asserts that prediction against a real removal, so the annotation cannot drift from the refcounting it describes. The machine output keys the rock index as "rocks" rather than "dependencies": a package entry already carries a "dependencies" object, and one name must not stand for two shapes. Tested at both levels: Go tests over fixture trees for the ownership rules, the refusals, the graph walk and the rendering, and a pytest slice driving the real binary for the CLI surface. The system scope installs into /usr, so its slice runs in a container against a disposable tree. Closes TNTP-8614
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Install writes the per-package metadata under
manifests/<pkg>/, and list and uninstall read it back. The three have to agree on the layout down to the directory name, so keeping the scope resolution, the metadata file names and the installed-package reader inside the install package would mean the inventory commands either duplicate them or import a package named after the one operation they do not perform. They move intocli/manifest/state, and the two new commands are built on top of it.Closes TNTP-8614