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
@@ -622,3 +622,15 @@ $ apt-mark showmanual su-dummy-a su-dummy-b su-dummy-c -> su-dummy-a (only t
|
||||
* A removed package with its configuration files kept (`rc`) is in neither list: not installed. A package installed with `dpkg -i` is manual (also `su-dummy-c` reinstalled with `dpkg -i` after `dpkg -r`).
|
||||
* apt-mark prints a native package without its architecture qualifier (`apt-mark showauto libc6:amd64` -> `libc6`) and nothing for an arch that is not installed (`libc6:i386` -> empty); a name that is not a package is treated as a pattern (`apt-mark showmanual 'su-dummy-?'` and `'su-dummy-.'` -> `su-dummy-a`), exact names win (`libapt-pkg6.0`, `libbz2-1.0`, `libdb5.3` answered for themselves). Hence the tool matches the output line by line against `PKG` (or `PKG` without `:arch`).
|
||||
* Fixture: `su-dummy-a`/`-c` are manual (`dpkg -i`), `su-dummy-b` is auto with `SU_FIXTURE_B_AUTO=1` (`apt-mark auto su-dummy-b`); no change needed.
|
||||
|
||||
## 14. Item 14 - full info (`N??` / `show`): `dpkg-query -s` merged with `apt-cache show --no-all-versions`
|
||||
|
||||
Verified 2026-10-10 on debian:12 (apt 2.6.1, dpkg 1.21.23), `LC_ALL=C`: the fixture (`SU_FIXTURE_OFFLINE=1 SU_FIXTURE_ORPHAN=1 SU_FIXTURE_B_AUTO=1`) and the real archive after `apt-get update` (`perl-base` 5.36.0-7+deb12u3 installed, +deb12u4 in bookworm-security; `bash`, up to date).
|
||||
|
||||
* Installed record, two candidates compared:
|
||||
* `dpkg-query -s PKG`: Package, Essential, Status, Priority, Section, Installed-Size, Maintainer, Architecture, Multi-Arch, Source, Version, Replaces, Provides, (Pre-)Depends, Recommends, Suggests, Breaks, Conflicts, Conffiles (multi-line), Description (short + long, always: dpkg keeps it), Homepage. rc 1 and `package 'x' is not installed and no information is available` for an unknown name; a removed package with config files left still answers (`Status: deinstall ok config-files`).
|
||||
* `apt-cache show PKG=<installed version>`: when that version is only in dpkg's status (the fixture's 1.0, installed with `dpkg -i`) it is the same record plus a computed `Description-md5`; when the version is still in the lists (bash) it is the **archive's** record instead: no Status, no Conffiles, only the short description (Debian ships the long text in Translation files), plus Tag, Filename, Size, MD5sum, SHA256.
|
||||
* Chosen: `dpkg-query -s` - the record of what is installed, with its local fields, independent of the lists. `Status` third word `not-installed`/`config-files` = not installed.
|
||||
* Candidate: `apt-cache show --no-all-versions PKG` (as before). Same RFC-822 layout (`Key: value`, continuation lines start with a space, ` .` = empty line), keys in another order. Against the installed record: Version, Installed-Size and changed relations differ; Status, Conffiles, Multi-Arch (sometimes) only installed; Description-md5, Tag, Filename, Size, MD5sum, SHA256 only in the candidate.
|
||||
* Description: on the real archive the candidate's `Description` is one line (perl-base: `Description: minimal Perl system`) while dpkg has the long text; with Translation files downloaded it is `Description-en:` with the long text (see item 3). So `Description-xx` pairs with `Description`, and a one-line candidate equal to the installed first line counts as the same description. The fixture's local repository carries the long text in `Packages`, so there the two blocks really differ (`(version 1.0)` vs `(version 2.0)`).
|
||||
* Several installed architectures of one name (M-A: same) give several `dpkg-query -s` records: not paired, the plain candidate is shown.
|
||||
Reference in new issue
Block a user