feat(show): merge the installed record with the upstream candidate
N?? and `show PKG` now print the installed record in the package
manager's own key/value layout, after one line explaining the format:
# lines starting with > come from the upstream candidate: a differing
value, or a field the installed record lacks
After each field whose candidate value differs comes the candidate's
line prefixed with "> "; fields only the candidate has are appended the
same way; installed-only fields stay; identical fields print once.
Multi-line values (pacman Optional Deps, dnf Description, RFC-822
continuation lines) are compared as blocks and a differing candidate
block gets "> " on every line. A package that is not installed shows the
candidate alone ("# not installed: this is the upstream candidate").
Merged where the backend gives comparable records for both sides:
- pacman: -Qi vs -Si REPO/PKG, REPO = the first repository -Sl lists
- apt: dpkg-query -s (Status, Conffiles, the long description; richer
than apt-cache show PKG=<installed>, which gives the archive record
when that version is still listed) vs apt-cache show --no-all-versions;
Description-xx pairs with Description and a one-line candidate
Description equal to the installed first line counts as identical
(the archives ship the long text in Translation files)
- dnf: info --installed vs info --upgrades (--available lists other
architectures first and nothing for an up-to-date package); not
installed: --available; dnf5's differently padded keys are re-padded
zypper keeps `zypper info --requires`: rpm -qi and zypper info share
almost no keys and zypper cannot print the installed record itself.
No candidate, or not exactly one record per side, keeps the old output.
Formats verified in containers and recorded in discovery/*.md. Unit
tests replay recorded pacman, apt, dnf4 and dnf5 records; the E2E suite
checks 2?? on su-dummy-b on all 12 distros.
This commit is contained in:
1 parent
296c77e319
commit
875c8294bf
30 files changed
+857
-45
No files matched your search
+30
-1
@@ -99,7 +99,7 @@ Command grammar (one line, whitespace-separated tokens, each `N` is the number i
|
||||
|--------|---------------------------------------------------------------------------|
|
||||
| empty line | proceed: run the native upgrade with the current exclusions |
|
||||
| `N?` | print three lines, none indented: `PKG: <one-line description>`, `reason: <r>` with `<r>` = `explicitly installed`, `installed as a dependency`, `unknown` (the backend cannot tell) or `not installed` (also, without asking the backend, for a row whose old version is `-`), and `required by: <a, b, ...>` - the reverse dependencies, installed packages only - or `required by: nothing` |
|
||||
| `N??` | print the full native info dump (`apt-cache show` / `pacman -Qi` / `dnf info` / `zypper info --requires`) |
|
||||
| `N??` | print the full native info: the installed record merged with the upstream candidate (see "Full info" below); zypper: `zypper info --requires` as it is |
|
||||
| `N-` | exclude from this run (toggle; `N-` again re-includes); shown with `-` marker |
|
||||
| `Nx` | purge it now, following pacman's `-Rns` principle on every backend: if any installed package still depends on it, refuse and print who (the reverse dependencies `N?` shows) - never cascade; otherwise simulate the native purge of it together with its now-unneeded dependencies, show that removal set ("This also removes: ...") and ask `y/N`. As a safety check, a simulated set containing anything that is neither the target nor in its installed dependency closure is refused too. Only a purge that ran removes rows (of every package it removed). A row whose old version is `-` (a new dependency, not installed) cannot be purged |
|
||||
| `N+` | trust it: write it and its installed dependency closure to the statefile; the row leaves the list (with `--all` it stays, marked `=`). Rows that this trust hides are re-included if they were excluded |
|
||||
@@ -126,6 +126,33 @@ history by itself). readline draws the prompt and the line on stderr, as bash do
|
||||
stdin keeps the plain `IFS= read -r` with the prompt on stdout and each line echoed after it, so
|
||||
piped runs and their logs are unchanged.
|
||||
|
||||
Full info (`N??`, `show PKG`). The first line is `# lines starting with > come from the upstream
|
||||
candidate: a differing value, or a field the installed record lacks`; then the installed record in
|
||||
its native key/value layout, as the base. After each field whose candidate value differs, the
|
||||
candidate's line follows, prefixed with `> ` (same key formatting); fields only the candidate has
|
||||
are appended at the end the same way; fields only the installed record has stay; identical fields
|
||||
print once. A field starts on a line that begins with a non-blank character and holds a `:` (the
|
||||
key is the text before it); lines beginning with a blank continue it, so multi-line values (pacman
|
||||
`Optional Deps`, dnf `Description`, RFC-822 continuation lines) are compared as blocks, every line
|
||||
trimmed, and a differing candidate block gets `> ` on every line. `Description-xx` (apt Translation
|
||||
files) pairs with `Description`; on apt a one-line candidate `Description` equal to the first
|
||||
installed line counts as identical (the archives carry only the short description, the long text
|
||||
is in the Translation files). When both records align their `:` in one column but in different
|
||||
ones (dnf5: 16 installed, 15 available), the candidate lines are re-padded to the installed one's.
|
||||
|
||||
| backend | installed record | upstream candidate |
|
||||
|---------|------------------|--------------------|
|
||||
| pacman | `pacman -Qi PKG` | `pacman -Si REPO/PKG`, REPO = the first repository `pacman -Sl` lists PKG in (as for the review list) |
|
||||
| apt | `dpkg-query -s PKG` (Status, Conffiles, always the long description; `apt-cache show PKG=<installed>` gives the archive's record when that version is still listed: no Status/Conffiles, short description only); a `Status` of `not-installed`/`config-files` = not installed | `apt-cache show --no-all-versions PKG` |
|
||||
| dnf | `dnf -q info --installed PKG` | `dnf -q info --upgrades PKG` (installed architecture only; `--available` also lists other architectures and, for an up-to-date package, other builds); not installed: `--available` |
|
||||
| zypper | - | - (`rpm -qi` and `zypper info` share almost no keys - Version vs version-release, Arch, byte sizes, source names, description layout - and zypper cannot print the installed record by itself: `zypper info -r @System` is refused) |
|
||||
|
||||
A package that is not installed (a row whose old version is `-` is not asked) shows the candidate
|
||||
alone under `# not installed: this is the upstream candidate`. Anything else - no candidate (an
|
||||
up-to-date dnf package, a local-only pacman package), not exactly one record on each side (two
|
||||
installed architectures), zypper - prints `<be>_full_info` unchanged. `dnf info` headings
|
||||
("Installed Packages", ...) are dropped. Verified formats: `discovery/{pacman,apt,rpm}.md`.
|
||||
|
||||
Flags shown after a row: `[held]` = the package manager will not upgrade it on its own: on apt
|
||||
a hold (`apt-mark hold`) or a package apt keeps back (the "kept back" block of
|
||||
`apt-get -s --with-new-pkgs upgrade`), on pacman an `IgnorePkg` (`[ignored]` in `pacman -Qu`).
|
||||
@@ -213,6 +240,8 @@ Every backend is a set of bash functions with a common prefix. All output is
|
||||
# plus "#<note>" lines for pending work that is not a row
|
||||
<be>_describe PKG # stdout: one-line summary
|
||||
<be>_full_info PKG # stdout: native full dump (candidate version if available)
|
||||
<be>_installed_record PKG # optional (pacman, apt, dnf): stdout: ONE native record of the installed package
|
||||
<be>_candidate_record PKG installed|not-installed # optional, with the above: ONE native record of the candidate
|
||||
<be>_rdepends PKG # stdout: installed packages requiring PKG, one per line
|
||||
<be>_reason PKG # stdout: explicit | dependency | unknown | not-installed (how PKG got installed)
|
||||
<be>_closure PKG # stdout: installed recursive dependency closure of PKG (excluding PKG), one per line
|
||||
|
||||
Reference in new issue
Block a user