fix(show): star marker, aligned gutter and smarter AUR merge

N?? / show marks the upstream candidate with "*" instead of ">" (the
prompt, which read as a command in logs), and every line but the note
gets a two-character gutter: "  " for the installed record, "* " for the
candidate, so keys and colons line up. The plain native fallback (zypper,
unmergeable records) and the not-installed candidate use the same gutter.

pacman records (-Qi with -Si or the AUR helper's -Sia) are now compared
the way they are meant:
- values unwrapped (continuation lines joined, runs of blanks as one):
  yay wraps Depends On / Optional Deps at 80 columns even without a
  terminal unless COLUMNS=0, which the helper now gets for -Qua and -Sia
- Depends On, Provides, Conflicts With, Make/Check Deps and the other
  lists as sets of exact tokens in any order (a constraint is a change)
- Optional Deps by package names ("name: description [installed]" in
  -Qi, bare names from the AUR)
- a differing value is one line like -Qi, Optional Deps one entry per
  line; candidate-only fields sit next to their counterpart (Repository
  after Version, AUR URL after URL, Maintainer after Packager, ...)

Verified on recorded claude-desktop records (paru 2.1.0, yay 13.0.1, the
installed 2.9939.4-1 from the AUR's own .SRCINFO); discovery/pacman.md
section 15.2.
This commit is contained in:
bryanpedini committed 2026-10-10 16:01:51 +02:00
1 parent def537af58
commit 3af159e09a
16 files changed
+680 -288

No files matched your search

+135 -135
View File
@@ -117,36 +117,35 @@ setup() { common_setup; }
run skup show su-dummy-b
assert_success
assert_output "$(cat <<'EOF'
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
Package: su-dummy-b
Status: install ok installed
Priority: optional
Section: misc
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
Architecture: all
Version: 1.0
> Version: 2.0
Conffiles:
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
Description: dummy package su-dummy-b for skeptical-updater tests
This package only exists to exercise the package manager.
.
It ships one data file and one conffile (version 1.0).
> Description: dummy package su-dummy-b for skeptical-updater tests
> This package only exists to exercise the package manager.
> .
> It ships one data file and one conffile (version 2.0).
> Description-md5: 36da7dcdaf4ec207be2937d1f5dfa408
> Filename: ./su-dummy-b_2.0_all.deb
> Size: 840
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
Package: su-dummy-b
Status: install ok installed
Priority: optional
Section: misc
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
Architecture: all
Version: 1.0
* Version: 2.0
Conffiles:
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
Description: dummy package su-dummy-b for skeptical-updater tests
This package only exists to exercise the package manager.
.
It ships one data file and one conffile (version 1.0).
* Description: dummy package su-dummy-b for skeptical-updater tests
* This package only exists to exercise the package manager.
* .
* It ships one data file and one conffile (version 2.0).
* Description-md5: 36da7dcdaf4ec207be2937d1f5dfa408
* Filename: ./su-dummy-b_2.0_all.deb
* Size: 840
EOF
)"
log_has 'dpkg-query -s -- su-dummy-b'
log_has 'apt-cache show --no-all-versions su-dummy-b'
run skup show su-dummy-a
assert_success
assert_line 'Depends: su-dummy-b'
assert_line '> Depends: su-dummy-b (>= 2.0)'
assert_output --partial "$(printf '%s\n' ' Depends: su-dummy-b' '* Depends: su-dummy-b (>= 2.0)')"
run skup show no-such-pkg-xyz
assert_failure 1
assert_output --partial "no package information for 'no-such-pkg-xyz' (apt exited 100)"
@@ -156,22 +155,22 @@ EOF
# real debian:12 records: perl-base 5.36.0-7+deb12u3 installed, +deb12u4 from bookworm-security
run skup show perl-base
assert_success
[[ $(grep -c '^Description: minimal Perl system$' <<<"$output") -eq 1 ]]
refute_line --partial '> Description:'
assert_output --partial "$(printf '%s\n' 'Installed-Size: 7639' '> Installed-Size: 7643')"
assert_output --partial "$(printf '%s\n' 'Version: 5.36.0-7+deb12u3' '> Version: 5.36.0-7+deb12u4')"
[[ $(grep -c '^Breaks: ' <<<"$output") -eq 1 ]]
refute_line --regexp '^> (Breaks|Pre-Depends|Essential|Source):'
assert_line --index -1 '> SHA256: d7d1943aec9597629bf73075efcc5ef6dc9bda96d78e80d843156ecd448478b8'
[[ $(grep -c '^ Description: minimal Perl system$' <<<"$output") -eq 1 ]]
refute_line --partial '* Description:'
assert_output --partial "$(printf '%s\n' ' Installed-Size: 7639' '* Installed-Size: 7643')"
assert_output --partial "$(printf '%s\n' ' Version: 5.36.0-7+deb12u3' '* Version: 5.36.0-7+deb12u4')"
[[ $(grep -c '^ Breaks: ' <<<"$output") -eq 1 ]]
refute_line --regexp '^\* (Breaks|Pre-Depends|Essential|Source):'
assert_line --index -1 '* SHA256: d7d1943aec9597629bf73075efcc5ef6dc9bda96d78e80d843156ecd448478b8'
}
@test "apt: show of a package that is not installed prints the candidate alone, with a note" {
run skup show zsh
assert_success
assert_line --index 0 '# not installed: this is the upstream candidate'
assert_line --index 1 'Package: zsh'
assert_line --index 3 'Version: 5.9-4+b15'
refute_line --partial '> '
assert_line --index 0 '# not installed: lines starting with * come from the upstream candidate (all of them)'
assert_line --index 1 '* Package: zsh'
assert_line --index 3 '* Version: 5.9-4+b15'
refute_line --regexp '^ '
log_has 'dpkg-query -s -- zsh'
}
@@ -272,48 +271,49 @@ EOF
assert_output 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
}
@test "pacman: show merges -Qi with -Si of the candidate's repository: '>' lines for what differs" {
@test "pacman: show merges -Qi with -Si of the candidate's repository: '*' lines for what differs, in place" {
# real archlinux records (glib2 2.88.3-1 installed, core 2.90.1-1), one Optional Deps entry
# added to the candidate: changed fields, identical ones once, -Qi-only fields kept, a differing
# multi-line block, -Si-only fields appended
# Optional Deps block (one entry per line), -Si-only fields next to their counterparts
# (Repository after Version, Download Size after Installed Size); every line in the gutter
use_fakes pacman
run skup show glib2
assert_success
assert_output "$(cat <<'EOF'
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
Name : glib2
Version : 2.88.3-1
> Version : 2.90.1-1
Description : Low level core library
Architecture : x86_64
URL : https://gitlab.gnome.org/GNOME/glib
Licenses : LGPL-2.1-or-later
Groups : None
Provides : libglib-2.0.so=0-64 libgio-2.0.so=0-64 libgirepository-2.0.so=0-64 libgmodule-2.0.so=0-64 libgobject-2.0.so=0-64 libgthread-2.0.so=0-64
Depends On : bash glibc libffi libsysprof-capture pcre2 util-linux-libs zlib libffi.so=8-64 libmount.so=1-64
Optional Deps : dconf: GSettings storage backend
glib2-devel: development tools
gvfs: most gio functionality
> Optional Deps : dconf: GSettings storage backend
> glib2-devel: development tools
> gvfs: most gio functionality
> python: gdbus-codegen
Required By : libsecret pinentry
Optional For : None
Conflicts With : None
Replaces : None
Installed Size : 37.89 MiB
> Installed Size : 38.39 MiB
Packager : Jan Alexander Steffens (heftig) <heftig@archlinux.org>
Build Date : Wed Jul 29 14:57:16 2026
> Build Date : Tue Oct 6 16:19:12 2026
Install Date : Sun Oct 4 00:00:00 2026
Install Reason : Installed as a dependency for another package
Install Script : No
Validated By : Signature
> Validated By : SHA-256 Sum Signature
> Repository : core
> Download Size : 5.12 MiB
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
Name : glib2
Version : 2.88.3-1
* Version : 2.90.1-1
* Repository : core
Description : Low level core library
Architecture : x86_64
URL : https://gitlab.gnome.org/GNOME/glib
Licenses : LGPL-2.1-or-later
Groups : None
Provides : libglib-2.0.so=0-64 libgio-2.0.so=0-64 libgirepository-2.0.so=0-64 libgmodule-2.0.so=0-64 libgobject-2.0.so=0-64 libgthread-2.0.so=0-64
Depends On : bash glibc libffi libsysprof-capture pcre2 util-linux-libs zlib libffi.so=8-64 libmount.so=1-64
Optional Deps : dconf: GSettings storage backend
glib2-devel: development tools
gvfs: most gio functionality
* Optional Deps : dconf: GSettings storage backend
* glib2-devel: development tools
* gvfs: most gio functionality
* python: gdbus-codegen
Required By : libsecret pinentry
Optional For : None
Conflicts With : None
Replaces : None
Installed Size : 37.89 MiB
* Installed Size : 38.39 MiB
* Download Size : 5.12 MiB
Packager : Jan Alexander Steffens (heftig) <heftig@archlinux.org>
Build Date : Wed Jul 29 14:57:16 2026
* Build Date : Tue Oct 6 16:19:12 2026
Install Date : Sun Oct 4 00:00:00 2026
Install Reason : Installed as a dependency for another package
Install Script : No
Validated By : Signature
* Validated By : SHA-256 Sum Signature
EOF
)"
log_has 'pacman -Qi -- glib2'
@@ -324,21 +324,21 @@ EOF
use_fakes pacman
run skup show su-dummy-b
assert_success
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
assert_line 'Required By : su-dummy-a'
assert_output --partial "$(printf '%s\n' ' Version : 1.0-1' '* Version : 2.0-1')"
assert_line ' Required By : su-dummy-a'
refute_output --partial '3.0-1'
log_has 'pacman -Si -- su-dummy/su-dummy-b'
# bash: in the sync list, but no -Si record - the output stays what it was (-Qi, then -Si)
run skup show bash
assert_success
assert_line --index 0 'Name : bash'
refute_line --partial '# lines starting with >'
assert_line --index 0 ' Name : bash'
refute_line --partial '# lines starting with *'
# not installed: the candidate alone
run skup show su-dummy-new
assert_success
assert_line --index 0 '# not installed: this is the upstream candidate'
assert_line --index 1 'Repository : su-dummy'
refute_line --partial '> '
assert_line --index 0 '# not installed: lines starting with * come from the upstream candidate (all of them)'
assert_line --index 1 '* Repository : su-dummy'
refute_line --regexp '^ '
run skup show nope
assert_failure 1
}
@@ -508,27 +508,27 @@ EOF
run skup show su-dummy-b
assert_success
assert_output "$(cat <<'EOF'
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
Name : su-dummy-b
Version : 1.0
> Version : 2.0
Release : 1
Architecture : noarch
Size : 15
> Size : 6.5 k
Source : su-dummy-b-1.0-1.src.rpm
> Source : su-dummy-b-2.0-1.src.rpm
Repository : @System
> Repository : su-dummy
Summary : skeptical-updater dummy su-dummy-b (v1.0)
> Summary : skeptical-updater dummy su-dummy-b (v2.0)
License : MIT
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
:
: Second paragraph of su-dummy-b 1.0 (blank line above on purpose).
> Description : Dummy package su-dummy-b version 2.0 for skeptical-updater tests.
> :
> : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
Name : su-dummy-b
Version : 1.0
* Version : 2.0
Release : 1
Architecture : noarch
Size : 15
* Size : 6.5 k
Source : su-dummy-b-1.0-1.src.rpm
* Source : su-dummy-b-2.0-1.src.rpm
Repository : @System
* Repository : su-dummy
Summary : skeptical-updater dummy su-dummy-b (v1.0)
* Summary : skeptical-updater dummy su-dummy-b (v2.0)
License : MIT
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
:
: Second paragraph of su-dummy-b 1.0 (blank line above on purpose).
* Description : Dummy package su-dummy-b version 2.0 for skeptical-updater tests.
* :
* : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
EOF
)"
log_has 'dnf -q info --installed su-dummy-b'
@@ -536,9 +536,9 @@ EOF
# real almalinux:9 records: an identical multi-line Description once, "From repo" (installed only) kept
run skup show glibc
assert_success
assert_output --partial "$(printf '%s\n' 'Release : 275.el9_8' '> Release : 283.el9_8')"
assert_line 'From repo : baseos'
[[ $(grep -c '^Description : The glibc package contains' <<<"$output") -eq 1 ]]
assert_output --partial "$(printf '%s\n' ' Release : 275.el9_8' '* Release : 283.el9_8')"
assert_line ' From repo : baseos'
[[ $(grep -c '^ Description : The glibc package contains' <<<"$output") -eq 1 ]]
[[ $(grep -c 'Linux system will not function\.$' <<<"$output") -eq 1 ]]
}
@@ -547,31 +547,31 @@ EOF
FAKE_DNF_MAJOR=5 run skup show su-dummy-b
assert_success
assert_output "$(cat <<'EOF'
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
Name : su-dummy-b
Epoch : 0
Version : 1.0
> Version : 2.0
Release : 1
Architecture : noarch
Installed size : 15.0 B
Source : su-dummy-b-1.0-1.src.rpm
> Source : su-dummy-b-2.0-1.src.rpm
From repository : <unknown>
Summary : skeptical-updater dummy su-dummy-b (v1.0)
> Summary : skeptical-updater dummy su-dummy-b (v2.0)
URL :
License : MIT
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
:
: Second paragraph of su-dummy-b 1.0 (blank line above on purpose).
> Description : Dummy package su-dummy-b version 2.0 for skeptical-updater tests.
> :
> : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
Vendor : <NULL>
> Vendor :
> Download size : 6.6 KiB
> Repository : su-dummy
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
Name : su-dummy-b
Epoch : 0
Version : 1.0
* Version : 2.0
Release : 1
Architecture : noarch
Installed size : 15.0 B
Source : su-dummy-b-1.0-1.src.rpm
* Source : su-dummy-b-2.0-1.src.rpm
From repository : <unknown>
Summary : skeptical-updater dummy su-dummy-b (v1.0)
* Summary : skeptical-updater dummy su-dummy-b (v2.0)
URL :
License : MIT
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
:
: Second paragraph of su-dummy-b 1.0 (blank line above on purpose).
* Description : Dummy package su-dummy-b version 2.0 for skeptical-updater tests.
* :
* : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
Vendor : <NULL>
* Vendor :
* Download size : 6.6 KiB
* Repository : su-dummy
EOF
)"
}
@@ -580,16 +580,16 @@ EOF
use_fakes dnf rpm
run skup show zsh
assert_success
assert_line --index 0 '# not installed: this is the upstream candidate'
assert_line --index 1 'Name : zsh'
refute_line 'Available Packages'
assert_line --index 0 '# not installed: lines starting with * come from the upstream candidate (all of them)'
assert_line --index 1 '* Name : zsh'
refute_line --partial 'Available Packages'
log_has 'dnf -q info --available zsh'
# two installed records (e.g. two architectures): nothing to pair, the output stays dnf -q info
FAKE_DNF_INFO_TWICE=installed run skup show su-dummy-a
assert_success
refute_line --partial '# lines starting with >'
assert_line 'Installed Packages'
assert_line 'Available Upgrades'
refute_line --partial '# lines starting with *'
assert_line ' Installed Packages'
assert_line ' Available Upgrades'
log_has 'dnf -q info su-dummy-a'
}
@@ -673,8 +673,8 @@ EOF
use_fakes zypper rpm
run skup show su-dummy-a
assert_success
assert_line 'Information for package su-dummy-a:'
refute_line --partial '# lines starting with >'
assert_line ' Information for package su-dummy-a:'
refute_line --partial '# lines starting with *'
log_has 'zypper --non-interactive --quiet info --requires su-dummy-a'
run skup show nothing-like-this
assert_failure 1