Compare commits
7
Commits
0.1.0
..
a059e37564
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a059e37564 | ||
|
|
6da4312f5c | ||
|
|
57a3dc97d6 | ||
|
|
2aa0a21056 | ||
|
|
5f90c24b8d | ||
|
|
33ebf89748 | ||
|
|
3af159e09a |
No files matched your search
@@ -59,7 +59,7 @@ options:
|
|||||||
none (default: paru, else yay, when installed; other backends ignore it)
|
none (default: paru, else yay, when installed; other backends ignore it)
|
||||||
--no-aur same as --aur-helper=none
|
--no-aur same as --aur-helper=none
|
||||||
-h, --help this help
|
-h, --help this help
|
||||||
-V, --version print the version
|
-v, --version print the version
|
||||||
```
|
```
|
||||||
|
|
||||||
Exit status: `0` ok, `1` usage or backend error, `2` aborted (end of input),
|
Exit status: `0` ok, `1` usage or backend error, `2` aborted (end of input),
|
||||||
@@ -130,43 +130,64 @@ package (pacman backend with paru or yay, see below) and a space on every other
|
|||||||
|
|
||||||
One line, whitespace-separated tokens; `N` is the number in brackets. Numbers are
|
One line, whitespace-separated tokens; `N` is the number in brackets. Numbers are
|
||||||
stable for the whole session (rows that leave the list leave a gap). Every token
|
stable for the whole session (rows that leave the list leave a gap). Every token
|
||||||
of a line is validated first: a line with an unknown token or a number that is not
|
of a line is checked for syntax first: an unknown token rejects the line. A number
|
||||||
listed prints an error, runs nothing, and the prompt comes back.
|
or package name that is not listed prints an error and the remaining commands still run.
|
||||||
|
For `?` and `??`, a listed package name can replace the number, for example
|
||||||
|
`su-dummy-a?` or `su-dummy-a??`. A digits-only reference is interpreted as a number.
|
||||||
|
Names are restricted to these information commands to avoid unnecessary parsing
|
||||||
|
complexity: package names may contain `-` or end in `x`, which conflicts with the
|
||||||
|
other command suffixes.
|
||||||
|
|
||||||
| token | action |
|
| token | action |
|
||||||
|-------|--------|
|
|-------|--------|
|
||||||
| empty line | proceed: run the native upgrade with the current exclusions |
|
| empty line | proceed: run the native upgrade with the current exclusions |
|
||||||
| `N?` | what is it: the one-line description, `reason:` how it got installed (`explicitly installed`, `installed as a dependency`, `unknown` when the package manager cannot tell, `not installed` for a new dependency) and `required by:` the packages that depend on it, or `nothing`. That list covers installed packages only |
|
| `N?` | what is it: the one-line description, `reason:` how it got installed (`explicitly installed`, `installed as a dependency`, `unknown` when the package manager cannot tell, `not installed` for a new dependency) and `required by:` the packages that depend on it, or `nothing`. That list covers installed packages only |
|
||||||
| `N??` | full native info: the installed record, with the upstream candidate merged in as lines starting with `>` (see below). zypper shows `zypper info --requires` as it is |
|
| `N??` | full native info: the installed record, with the upstream candidate merged in as lines starting with `*` (see below); every line has a two-character gutter (` ` installed, `* ` upstream). zypper shows `zypper info --requires` as it is |
|
||||||
| `N-` | exclude from this run (toggle; `N-` again re-includes); shown with a `-` marker |
|
| `N-` | exclude from this run (toggle; `N-` again re-includes); shown with a `-` marker |
|
||||||
| `Nx` | purge now, with its now-unneeded dependencies: the purge is simulated first and the prompt lists everything it removes (`Purge su-dummy-a now? This also removes: su-dummy-b [y/N]`); the answer is read from the same stdin; the rows of every removed package leave the list. `x` refuses when other installed packages depend on the target, like `pacman -Rns`; purge the dependents first (`not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first`). Rows with old version `-` (new dependencies, not installed) cannot be purged |
|
| `Nx` | purge now, with its now-unneeded dependencies: the purge is simulated first and the prompt lists everything it removes (`Purge su-dummy-a now? This also removes: su-dummy-b [y/N]`); the answer is read from the same stdin; the rows of every removed package leave the list. `x` refuses when other installed packages depend on the target, like `pacman -Rns`; purge the dependents first (`not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first`). Rows with old version `-` (new dependencies, not installed) cannot be purged |
|
||||||
| `N+` | trust forever: write it and its installed dependency closure to the statefile; the row leaves the list. Rows this hides are re-included if they were excluded (a trusted package is upgraded) |
|
| `N+` | trust forever: write it and its installed dependency closure to the statefile; the row leaves the list. Rows this hides are re-included if they were excluded (a trusted package is upgraded) |
|
||||||
|
| `N++` | follow installed dependents recursively and trust each topmost package and its installed dependencies, even when a topmost package is not in the update list |
|
||||||
| `*+` / `*-` | `+` / `-` for every listed package (`*-` is an all-or-nothing toggle: when all are excluded it re-includes them) |
|
| `*+` / `*-` | `+` / `-` for every listed package (`*-` is an all-or-nothing toggle: when all are excluded it re-includes them) |
|
||||||
|
| `a` | show packages trusted during this session again, marked with `=`; packages already trusted before the session remain hidden |
|
||||||
| `l` | redraw the list |
|
| `l` | redraw the list |
|
||||||
| `q` | quit without upgrading (exit 0) |
|
| `q` | quit without upgrading (exit 0) |
|
||||||
| `h`, `?` | help |
|
| `h`, `?` | help |
|
||||||
| end of input | abort without upgrading (exit 2) |
|
| end of input | abort without upgrading (exit 2) |
|
||||||
|
|
||||||
Several tokens may share a line (`1? 3- 4+`); they run left to right. With `--all`
|
Several tokens may share a line (`1? 3- 4+`); they run left to right. Consecutive
|
||||||
|
`Nx` commands such as `5x 30x 41x` are simulated and confirmed together. Another
|
||||||
|
command ends the group; a dependent can be included with its dependency. Consecutive
|
||||||
|
`N+` commands are processed together: selected packages required by another selected
|
||||||
|
package are recorded as dependencies, regardless of their order. `*+` works the same
|
||||||
|
way. With `--all`
|
||||||
trusted packages are listed too, marked with `=`. When purges leave nothing to upgrade the
|
trusted packages are listed too, marked with `=`. When purges leave nothing to upgrade the
|
||||||
session ends by itself (exit 0).
|
session ends by itself (exit 0).
|
||||||
|
|
||||||
`N??` (and `show PKG`) prints the installed record in the package manager's own layout
|
`N??` (and `show PKG`) prints the installed record in the package manager's own layout
|
||||||
(`dpkg-query -s`, `pacman -Qi`, `dnf info --installed`), preceded by one `#` line saying how to read
|
(`dpkg-query -s`, `pacman -Qi`, `dnf info --installed`), preceded by one `#` line saying how to read
|
||||||
it. Right after each field whose value differs in the upstream candidate (`apt-cache show`,
|
it. Every other line starts with a two-character gutter, so keys and colons line up: two spaces
|
||||||
`pacman -Si` from the repository pacman would use, `dnf info --upgrades`) comes the candidate's line,
|
for the installed record, `* ` for the upstream candidate. Right after each field whose value
|
||||||
prefixed with `>`; fields only the candidate has (download size, checksums, repository) follow at the
|
differs in the upstream candidate (`apt-cache show`, `pacman -Si` from the repository pacman would
|
||||||
end the same way, and fields only the installed record has (install reason, conffiles,
|
use, `dnf info --upgrades`) comes the candidate's line, marked `* `; fields only the installed record
|
||||||
`Required By`) stay as they are. Identical fields are printed once; multi-line values (descriptions, pacman
|
has (install reason, conffiles, `Required By`) stay as they are, and identical fields are printed
|
||||||
`Optional Deps`, apt continuation lines) are compared as blocks and, when they differ, every line of
|
once. Fields only the candidate has (download size, checksums, repository) follow at the end the same
|
||||||
the candidate's block gets the `>`. A package that is not installed shows the candidate alone. When
|
way - on pacman next to their installed counterpart instead (`Repository` after `Version`,
|
||||||
the two records cannot be paired (zypper, whose `rpm -qi` and `zypper info` share almost no keys; no
|
`Download Size` after `Installed Size`; for the AUR `AUR URL` after `URL`, `Make Deps`/`Check Deps`
|
||||||
candidate; several installed architectures) the plain native output is shown. On Debian 12, with
|
after `Optional Deps`, `Maintainer` after `Packager`, `Last Modified` and `First Submitted` after
|
||||||
`su-dummy-b` 1.0 installed and 2.0 available:
|
`Build Date`, the rest at the end). Multi-line values (descriptions, apt continuation lines) are
|
||||||
|
compared as blocks and, when they differ, every line of the candidate's block gets the `* `. On pacman
|
||||||
|
values are compared unwrapped (the AUR helpers wrap long lists at the terminal width), lists such as
|
||||||
|
`Depends On` as sets of tokens in any order, `Optional Deps` by package names only (the installed
|
||||||
|
record says `name: description [installed]`, the AUR bare names); a differing value is printed on one
|
||||||
|
line like `pacman -Qi` does, `Optional Deps` one entry per line. A package that is not installed shows
|
||||||
|
the candidate alone, every line marked `* `. When the two records cannot be paired (zypper, whose
|
||||||
|
`rpm -qi` and `zypper info` share almost no keys; no candidate; several installed architectures) the
|
||||||
|
plain native output is shown, in the same gutter. On Debian 12, with `su-dummy-b` 1.0 installed and
|
||||||
|
2.0 available:
|
||||||
|
|
||||||
```
|
```
|
||||||
> 2??
|
> 2??
|
||||||
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
|
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
|
||||||
Package: su-dummy-b
|
Package: su-dummy-b
|
||||||
Status: install ok installed
|
Status: install ok installed
|
||||||
Priority: optional
|
Priority: optional
|
||||||
@@ -174,22 +195,22 @@ Section: misc
|
|||||||
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
|
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Version: 1.0
|
Version: 1.0
|
||||||
> Version: 2.0
|
* Version: 2.0
|
||||||
Conffiles:
|
Conffiles:
|
||||||
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
|
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
|
||||||
Description: dummy package su-dummy-b for skeptical-updater tests
|
Description: dummy package su-dummy-b for skeptical-updater tests
|
||||||
This package only exists to exercise the package manager.
|
This package only exists to exercise the package manager.
|
||||||
.
|
.
|
||||||
It ships one data file and one conffile (version 1.0).
|
It ships one data file and one conffile (version 1.0).
|
||||||
> Description: dummy package su-dummy-b for skeptical-updater tests
|
* Description: dummy package su-dummy-b for skeptical-updater tests
|
||||||
> This package only exists to exercise the package manager.
|
* This package only exists to exercise the package manager.
|
||||||
> .
|
* .
|
||||||
> It ships one data file and one conffile (version 2.0).
|
* It ships one data file and one conffile (version 2.0).
|
||||||
> Description-md5: 27e6732d8f16131f7512e1d4f1855cc3
|
* Description-md5: 27e6732d8f16131f7512e1d4f1855cc3
|
||||||
> Filename: ./su-dummy-b_2.0_all.deb
|
* Filename: ./su-dummy-b_2.0_all.deb
|
||||||
> Size: 824
|
* Size: 824
|
||||||
> MD5sum: 62274690c5324af5419515e9f430226b
|
* MD5sum: 62274690c5324af5419515e9f430226b
|
||||||
> SHA256: e1c87480693d98770356f1dc55616dc416f7e3c3f71dc3967e94dec77bb36c16
|
* SHA256: e1c87480693d98770356f1dc55616dc416f7e3c3f71dc3967e94dec77bb36c16
|
||||||
```
|
```
|
||||||
|
|
||||||
Under the rows, `Note:` lines report pending work that is not a row: new dependencies or
|
Under the rows, `Note:` lines report pending work that is not a row: new dependencies or
|
||||||
@@ -241,8 +262,9 @@ Upgrade finished.
|
|||||||
AUR row (a package that moved from the AUR into a repository).
|
AUR row (a package that moved from the AUR into a repository).
|
||||||
- **`N?`, `N+`, `Nx`** work as for any installed package, through pacman (`pacman -Qi`,
|
- **`N?`, `N+`, `Nx`** work as for any installed package, through pacman (`pacman -Qi`,
|
||||||
the statefile with backend `pacman`, `pacman -Rns`). **`N??`** merges `pacman -Qi` with the
|
the statefile with backend `pacman`, `pacman -Rns`). **`N??`** merges `pacman -Qi` with the
|
||||||
AUR record (`paru -Sia` / `yay -Sia`), `>` lines as usual: `> Version`, `> Repository : aur`,
|
AUR record (`paru -Sia` / `yay -Sia`), `*` lines as usual: `* Version` followed by
|
||||||
`> Maintainer`, `> Votes`, ... (`show PKG` does the same for a package in no repository).
|
`* Repository : aur`, `* AUR URL` under `URL`, `* Maintainer` under `Packager`, `* Votes`, ...
|
||||||
|
(`show PKG` does the same for a package in no repository).
|
||||||
- **`N-`** excludes an AUR row through the helper's `--ignore`.
|
- **`N-`** excludes an AUR row through the helper's `--ignore`.
|
||||||
- **`<enter>`** upgrades the repository packages first, exactly as without the AUR (pre-check,
|
- **`<enter>`** upgrades the repository packages first, exactly as without the AUR (pre-check,
|
||||||
the reviewed databases, `pacman -Su`), then, if AUR rows are left to upgrade, runs
|
the reviewed databases, `pacman -Su`), then, if AUR rows are left to upgrade, runs
|
||||||
@@ -398,7 +420,9 @@ database install / `-Su` sequence and stale throwaway databases, statefile locki
|
|||||||
the `mkdir` lock fallback (EPERM owner alive, no busy loop), an inaccessible state directory, the
|
the `mkdir` lock fallback (EPERM owner alive, no busy loop), an inaccessible state directory, the
|
||||||
sudo re-exec of the file itself and its loop guard), the `N??` merge on recorded pacman, apt, dnf4
|
sudo re-exec of the file itself and its loop guard), the `N??` merge on recorded pacman, apt, dnf4
|
||||||
and dnf5 records (changed, identical, installed-only, candidate-only and multi-line fields, apt's
|
and dnf5 records (changed, identical, installed-only, candidate-only and multi-line fields, apt's
|
||||||
short candidate descriptions, dnf5's padding, the fallbacks), the prompt on a real pty (`script`):
|
short candidate descriptions, dnf5's padding, the fallbacks, the two-character gutter; on pacman the
|
||||||
|
unwrapped comparison, token sets, `Optional Deps` name sets and the placement of candidate-only
|
||||||
|
fields, on the recorded `claude-desktop` records of paru and of yay, which wraps), the prompt on a real pty (`script`):
|
||||||
cursor editing, Up/Down history recall, the stashed line, the bell at both ends, no history file,
|
cursor editing, Up/Down history recall, the stashed line, the bell at both ends, no history file,
|
||||||
and the AUR (`tests/unit/aur.bats`, on recorded paru 2.1.0 and yay 13.0.1 output): helper detection
|
and the AUR (`tests/unit/aur.bats`, on recorded paru 2.1.0 and yay 13.0.1 output): helper detection
|
||||||
and overrides, the user the helper runs as (`runuser -u` / `sudo -u` with `SUDO_USER`, unprivileged,
|
and overrides, the user the helper runs as (`runuser -u` / `sudo -u` with `SUDO_USER`, unprivileged,
|
||||||
@@ -422,8 +446,9 @@ mirror state. `su-dummy-b` is recorded as installed as a dependency on every bac
|
|||||||
`--asdeps`, `apt-mark auto`, `dnf mark remove`, zypper's `AutoInstalled`) and `su-dummy-a` as
|
`--asdeps`, `apt-mark auto`, `dnf mark remove`, zypper's `AutoInstalled`) and `su-dummy-a` as
|
||||||
explicitly installed (dnf needs `dnf mark install`: it records plain `rpm` installs as
|
explicitly installed (dnf needs `dnf mark install`: it records plain `rpm` installs as
|
||||||
`unknown`). Then `tests/e2e/*.bats` exercise the real package manager: banner, list, `N?` (the
|
`unknown`). Then `tests/e2e/*.bats` exercise the real package manager: banner, list, `N?` (the
|
||||||
reason and `required by:` of both), `N??` (su-dummy-b's installed 1.0 record with `> Version`, and
|
reason and `required by:` of both), `N??` (su-dummy-b's installed 1.0 record with `* Version`, and
|
||||||
`> Repository` on pacman and dnf; zypper's plain `zypper info`), `N+` and the statefile,
|
`* Repository` on pacman and dnf, every line in the gutter; zypper's plain `zypper info`), `N+` and
|
||||||
|
the statefile,
|
||||||
`trust`/`untrust`/`refresh`,
|
`trust`/`untrust`/`refresh`,
|
||||||
excluding `su-dummy-b` (with and without a pre-existing hold/lock/IgnorePkg/exclude on
|
excluding `su-dummy-b` (with and without a pre-existing hold/lock/IgnorePkg/exclude on
|
||||||
`su-dummy-c`, which must survive byte for byte), trusting re-including an excluded
|
`su-dummy-c`, which must survive byte for byte), trusting re-including an excluded
|
||||||
|
|||||||
+29
-1
@@ -713,6 +713,33 @@ Out Of Date : No
|
|||||||
Submitted`, `Last Modified`, `Out Of Date` (yay: `Out-of-date`, plus `Keywords`).
|
Submitted`, `Last Modified`, `Out Of Date` (yay: `Out-of-date`, plus `Keywords`).
|
||||||
* Not in the AUR: paru `error: package 'no-such-package-zzz' was not found`, yay ` -> No AUR package found for
|
* Not in the AUR: paru `error: package 'no-such-package-zzz' was not found`, yay ` -> No AUR package found for
|
||||||
no-such-package-zzz`, exit 1. AUR unreachable: the `-Qua` errors above, exit 1.
|
no-such-package-zzz`, exit 1. AUR unreachable: the `-Qua` errors above, exit 1.
|
||||||
|
* Optional dependencies are **bare names** in both (`Optional Deps : pipewire kdialog gnome-keyring kwallet`
|
||||||
|
for `google-chrome`, whose AUR entries carry descriptions such as `pipewire: WebRTC desktop sharing under
|
||||||
|
Wayland`): the descriptions are dropped. `-Qi` prints one `name: description [installed]` per line.
|
||||||
|
* **yay wraps** long values at 80 columns - `Depends On`, `Optional Deps`, continuation lines indented to the value
|
||||||
|
column (31) - whenever `COLUMNS` is unset or 80, also without any terminal (stdout and stdin not a tty);
|
||||||
|
`COLUMNS=0` turns it off. paru 2.1.0 printed one line per field in every case tried (no terminal; an 80-column
|
||||||
|
pty with stdout piped, `COLUMNS` unset, 0 or 80; stdout the pty itself with `COLUMNS=0`). Verified 2026-10-10
|
||||||
|
with `claude-desktop` 2.31226.1-1 (39 dependencies), `yay -Sia claude-desktop` without `COLUMNS=0`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Depends On : alsa-lib at-spi2-core bubblewrap cairo dbus
|
||||||
|
expat gcc-libs glib2 glibc gtk3
|
||||||
|
...
|
||||||
|
xdg-desktop-portal xdg-utils qemu-system-x86
|
||||||
|
edk2-ovmf
|
||||||
|
Optional Deps : gnome-keyring kwallet libayatana-appindicator
|
||||||
|
xdg-desktop-portal-gtk xdg-desktop-portal-kde
|
||||||
|
qemu-system-aarch64 edk2-aarch64
|
||||||
|
```
|
||||||
|
|
||||||
|
(paru: `Depends On : alsa-lib at-spi2-core bubblewrap ... edk2-ovmf` on one line.) The installed side for
|
||||||
|
that comparison, `pacman -Qi claude-desktop` of 2.9939.4-1 (a stand-in package built from the AUR's own
|
||||||
|
`.SRCINFO` of that version, commit b7d5715, plus a dummy `kwallet` for `[installed]`): `Depends On` one line
|
||||||
|
without `bubblewrap`, `libpipewire`, `qemu-system-x86`, `edk2-ovmf`; `Optional Deps : gnome-keyring:
|
||||||
|
credential storage via Secret Service (GNOME)` / `kwallet: credential storage (KDE Plasma) [installed]` / ...
|
||||||
|
one per line. These records are the unit fixtures (`tests/unit/data/pacman/Qi.txt`,
|
||||||
|
`tests/unit/data/aur/Sia-{paru,yay}-claude-desktop.txt`).
|
||||||
|
|
||||||
### 15.3 `-Sua`: the AUR upgrade
|
### 15.3 `-Sua`: the AUR upgrade
|
||||||
|
|
||||||
@@ -739,5 +766,6 @@ Out Of Date : No
|
|||||||
|------|---------|
|
|------|---------|
|
||||||
| helper | `--aur-helper=paru\|yay\|none` / `--no-aur`, else `paru`, else `yay` |
|
| helper | `--aur-helper=paru\|yay\|none` / `--no-aur`, else `paru`, else `yay` |
|
||||||
| list | `<helper> -Qua`: rows `name old new aur` (flag `aur`, `[ignored]` -> held); a name `pacman -Qu` lists wins; exit 1 + empty stderr = none, other failures: warn, no AUR rows |
|
| list | `<helper> -Qua`: rows `name old new aur` (flag `aur`, `[ignored]` -> held); a name `pacman -Qu` lists wins; exit 1 + empty stderr = none, other failures: warn, no AUR rows |
|
||||||
| `N??` | `pacman -Qi` merged with `<helper> -Sia PKG` (section 14's merge) |
|
| `N??` | `pacman -Qi` merged with `<helper> -Sia PKG` (section 14's merge; pacman mode: values unwrapped, lists as token sets, `Optional Deps` as name sets, AUR-only fields next to their counterparts) |
|
||||||
|
| `COLUMNS` | `COLUMNS=0` for `-Qua` and `-Sia` (yay's wrapping); the upgrade keeps the terminal's |
|
||||||
| upgrade | after the repository step: `<helper> -Sua [--noconfirm when stdin is not a terminal] [--ignore <excluded rows>]` |
|
| upgrade | after the repository step: `<helper> -Sua [--noconfirm when stdin is not a terminal] [--ignore <excluded rows>]` |
|
||||||
+54
-15
@@ -125,6 +125,14 @@ Refreshing package lists... done.
|
|||||||
```
|
```
|
||||||
|
|
||||||
Command grammar (one line, whitespace-separated tokens, each `N` is the number in brackets):
|
Command grammar (one line, whitespace-separated tokens, each `N` is the number in brackets):
|
||||||
|
Unknown tokens reject the line; nonexistent numbers report an error and are skipped.
|
||||||
|
For `?` and `??`, the exact name of a listed package may replace `N`; a digits-only
|
||||||
|
reference is treated as a number. Missing or no longer listed names are reported and
|
||||||
|
skipped. Other commands accept only numbers: package names can contain `-` or end in
|
||||||
|
`x`, and limiting name references to information commands avoids unnecessary parsing
|
||||||
|
complexity.
|
||||||
|
Consecutive `N+` commands and `*+` trust the selected dependency roots, recording
|
||||||
|
other selected packages in their closures as dependencies regardless of input order.
|
||||||
|
|
||||||
| token | action |
|
| token | action |
|
||||||
|--------|---------------------------------------------------------------------------|
|
|--------|---------------------------------------------------------------------------|
|
||||||
@@ -153,8 +161,8 @@ On AUR rows `N?`, `N+` and `Nx` act through pacman like on any installed package
|
|||||||
`pacman -Qi` with `<helper> -Sia PKG`; `N-` excludes the row through the helper's `--ignore`.
|
`pacman -Qi` with `<helper> -Sia PKG`; `N-` excludes the row through the helper's `--ignore`.
|
||||||
|
|
||||||
Numbers are stable for the whole session (removed rows leave a gap, never renumber).
|
Numbers are stable for the whole session (removed rows leave a gap, never renumber).
|
||||||
All tokens of a line are validated first: an unknown token or a number that is not listed
|
Syntax is validated first; an unknown token rejects the line. Numbers that are not listed
|
||||||
prints an error, runs nothing of that line and re-prompts. EOF on stdin aborts without
|
print an error and are skipped while the remaining commands run. EOF on stdin aborts without
|
||||||
upgrading (exit 2) so a piped run can never upgrade by accident unless it sends an empty
|
upgrading (exit 2) so a piped run can never upgrade by accident unless it sends an empty
|
||||||
line. When purges leave no row at all, the session ends ("Nothing left to upgrade.", exit 0).
|
line. When purges leave no row at all, the session ends ("Nothing left to upgrade.", exit 0).
|
||||||
|
|
||||||
@@ -170,31 +178,62 @@ 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
|
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.
|
piped runs and their logs are unchanged.
|
||||||
|
|
||||||
Full info (`N??`, `show PKG`). The first line is `# lines starting with > come from the upstream
|
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
|
candidate: a differing value, or a field the installed record lacks` (no gutter); every other line
|
||||||
its native key/value layout, as the base. After each field whose candidate value differs, the
|
starts with a two-character gutter, ` ` for the installed record and its continuation lines, `* `
|
||||||
candidate's line follows, prefixed with `> ` (same key formatting); fields only the candidate has
|
for the candidate's lines and theirs, so keys and colons line up. Then the installed record in its
|
||||||
are appended at the end the same way; fields only the installed record has stay; identical fields
|
native key/value layout, as the base. After each field whose candidate value differs, the
|
||||||
print once. A field starts on a line that begins with a non-blank character and holds a `:` (the
|
candidate's line follows, marked `* ` (same key formatting); fields only the candidate has are
|
||||||
key is the text before it); lines beginning with a blank continue it, so multi-line values (pacman
|
appended at the end the same way (pacman: placed next to their counterpart, below); fields only the
|
||||||
`Optional Deps`, dnf `Description`, RFC-822 continuation lines) are compared as blocks, every line
|
installed record has stay; identical fields print once. A field starts on a line that begins with a
|
||||||
trimmed, and a differing candidate block gets `> ` on every line. `Description-xx` (apt Translation
|
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
|
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
|
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
|
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.
|
ones (dnf5: 16 installed, 15 available; yay's AUR records: 30), the candidate lines are re-padded to
|
||||||
|
the installed one's.
|
||||||
|
|
||||||
|
pacman (`-Qi` with `-Si REPO/PKG` or `<helper> -Sia PKG`, `discovery/pacman.md` sections 14-15):
|
||||||
|
|
||||||
|
- values are compared unwrapped - continuation lines joined to their key on both sides, runs of
|
||||||
|
blanks as one blank - because the AUR helpers wrap long lists at the terminal width;
|
||||||
|
- `Groups`, `Provides`, `Depends On`, `Required By`, `Optional For`, `Conflicts With`, `Replaces`,
|
||||||
|
`Make Deps`, `Check Deps`, `Licenses`, `Keywords`: as sets of exact tokens, in any order (a version
|
||||||
|
constraint is part of its token, so a changed constraint is a difference);
|
||||||
|
- `Optional Deps`: as sets of package names - `: description` and ` [installed]` stripped (`-Qi`
|
||||||
|
prints `name: description [installed]` per line, the AUR records bare names separated by blanks);
|
||||||
|
- a differing candidate value is printed on one line, as `-Qi` prints every field (an unwrapped
|
||||||
|
helper value is joined with two blanks for the lists above, one otherwise; a one-line value stays
|
||||||
|
as it is); `Optional Deps`, one entry per line in `-Qi`, gets one entry per line under the value
|
||||||
|
column;
|
||||||
|
- candidate-only fields go next to their installed counterpart, in this order, the others at the end
|
||||||
|
in the candidate's order:
|
||||||
|
|
||||||
|
| candidate field | right after |
|
||||||
|
|-----------------|-------------|
|
||||||
|
| `Repository` | `Version` |
|
||||||
|
| `AUR URL` | `URL` |
|
||||||
|
| `Keywords` | `Groups` |
|
||||||
|
| `Make Deps`, `Check Deps` | `Optional Deps` |
|
||||||
|
| `Maintainer` | `Packager` |
|
||||||
|
| `Last Modified`, `First Submitted` | `Build Date` |
|
||||||
|
| `Download Size` | `Installed Size` |
|
||||||
|
|
||||||
| backend | installed record | upstream candidate |
|
| 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); a package in no repository: the AUR record, `<helper> -Sia PKG`, when a helper is in use (should it not merge, `pacman -Qi` is followed by the AUR record with every line marked `> `) |
|
| pacman | `pacman -Qi PKG` | `pacman -Si REPO/PKG`, REPO = the first repository `pacman -Sl` lists PKG in (as for the review list); a package in no repository: the AUR record, `<helper> -Sia PKG`, when a helper is in use (should it not merge, `pacman -Qi` is followed by the AUR record with every line marked `* `) |
|
||||||
| 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` |
|
| 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` |
|
| 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) |
|
| 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
|
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
|
alone, every line marked `* `, under `# not installed: lines starting with * come from the upstream
|
||||||
|
candidate (all of them)`. Anything else - no candidate (an
|
||||||
up-to-date dnf package, a local-only pacman package), not exactly one record on each side (two
|
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 architectures), zypper - prints `<be>_full_info` as it is (in the " " gutter). `dnf info` headings
|
||||||
("Installed Packages", ...) are dropped. Verified formats: `discovery/{pacman,apt,rpm}.md`.
|
("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
|
Flags shown after a row: `[held]` = the package manager will not upgrade it on its own: on apt
|
||||||
|
|||||||
+354
-107
@@ -6,7 +6,7 @@
|
|||||||
# and zypper: list what would be upgraded, interrogate every package, remember the
|
# and zypper: list what would be upgraded, interrogate every package, remember the
|
||||||
# ones you trust, then run the native upgrade (with per-run exclusions).
|
# ones you trust, then run the native upgrade (with per-run exclusions).
|
||||||
#
|
#
|
||||||
# Version: 0.1.0
|
# Version: 0.6.0
|
||||||
#
|
#
|
||||||
# Specification: docs/DESIGN.md. Single file, bash >= 4.3, no runtime dependency
|
# Specification: docs/DESIGN.md. Single file, bash >= 4.3, no runtime dependency
|
||||||
# beyond the distro's package manager and coreutils/sed/grep (awk only on the apt
|
# beyond the distro's package manager and coreutils/sed/grep (awk only on the apt
|
||||||
@@ -23,7 +23,7 @@ export LC_ALL=C DEBIAN_FRONTEND=noninteractive
|
|||||||
# never read from or written to a file (no HISTFILE; `history -r`/`-w`/`-a` are never used).
|
# never read from or written to a file (no HISTFILE; `history -r`/`-w`/`-a` are never used).
|
||||||
unset HISTFILE
|
unset HISTFILE
|
||||||
|
|
||||||
readonly SU_VERSION=0.1.0
|
readonly SU_VERSION=0.6.0
|
||||||
readonly SU_PROG=skeptical-updater
|
readonly SU_PROG=skeptical-updater
|
||||||
readonly SU_STATE_HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
|
readonly SU_STATE_HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
|
||||||
readonly SU_PROMPT_HELP='<enter> upgrade | N? what is it | N?? full info | N- exclude this run | Nx purge now | N+ trust forever'
|
readonly SU_PROMPT_HELP='<enter> upgrade | N? what is it | N?? full info | N- exclude this run | Nx purge now | N+ trust forever'
|
||||||
@@ -105,20 +105,24 @@ options:
|
|||||||
none (default: paru, else yay, when installed; other backends ignore it)
|
none (default: paru, else yay, when installed; other backends ignore it)
|
||||||
--no-aur same as --aur-helper=none
|
--no-aur same as --aur-helper=none
|
||||||
-h, --help this help
|
-h, --help this help
|
||||||
-V, --version print the version
|
-v, --version print the version
|
||||||
|
|
||||||
interactive commands (one line, whitespace-separated tokens, N = number in brackets):
|
interactive commands (one line, whitespace-separated tokens, N = number in brackets):
|
||||||
<empty line> proceed: run the native upgrade with the current exclusions
|
<empty line> proceed: run the native upgrade with the current exclusions
|
||||||
N? what is it: the description, 'reason:' (explicitly installed, installed as
|
N? what is it: the description, 'reason:' (explicitly installed, installed as
|
||||||
a dependency, unknown or not installed) and 'required by:', the packages
|
a dependency, unknown or not installed) and 'required by:', the packages
|
||||||
that depend on it - installed packages only
|
that depend on it - installed packages only
|
||||||
N?? full native info: the installed record; lines starting with '>' come
|
N?? full native info: the installed record; lines starting with '*' come
|
||||||
from the upstream candidate (differing values, fields it adds)
|
from the upstream candidate (differing values, fields it adds)
|
||||||
|
For N? and N??, a listed package name may be used instead of N.
|
||||||
N- exclude from this run (toggle); shown with a '-' marker
|
N- exclude from this run (toggle); shown with a '-' marker
|
||||||
Nx purge it now with its now-unneeded dependencies (shown, asks y/N); refused
|
Nx purge it now with its now-unneeded dependencies (shown, asks y/N); refused
|
||||||
when other installed packages depend on it, like pacman -Rns
|
when other installed packages depend on it, like pacman -Rns
|
||||||
|
consecutive Nx commands are purged together after one confirmation
|
||||||
N+ trust it forever (with its installed dependency closure)
|
N+ trust it forever (with its installed dependency closure)
|
||||||
|
N++ trust the topmost installed dependents and their dependency closures
|
||||||
*+ / *- apply + / - to every listed package
|
*+ / *- apply + / - to every listed package
|
||||||
|
a show packages trusted during this session again
|
||||||
l redraw the list
|
l redraw the list
|
||||||
q quit without upgrading (exit 0)
|
q quit without upgrading (exit 0)
|
||||||
h, ? this help
|
h, ? this help
|
||||||
@@ -137,13 +141,17 @@ session_help() {
|
|||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
<enter> upgrade now, skipping the rows marked '-'
|
<enter> upgrade now, skipping the rows marked '-'
|
||||||
N? what is it: description, install reason + installed packages that need it
|
N? what is it: description, install reason + installed packages that need it
|
||||||
N?? full native info: installed record, '>' lines from the upstream candidate
|
N?? full native info: installed record, '*' lines from the upstream candidate
|
||||||
|
A listed package name may replace N for ? and ?? (e.g. okular?).
|
||||||
N- exclude N from this run (toggle)
|
N- exclude N from this run (toggle)
|
||||||
Nx purge N now: lists every package the purge removes, then asks y/N.
|
Nx purge N now: lists every package the purge removes, then asks y/N.
|
||||||
x refuses when other installed packages depend on the target, like
|
x refuses when other installed packages depend on the target, like
|
||||||
pacman -Rns; purge the dependents first
|
pacman -Rns; purge the dependents first
|
||||||
|
consecutive Nx commands are purged together after one confirmation
|
||||||
N+ trust N (and its installed dependencies) forever
|
N+ trust N (and its installed dependencies) forever
|
||||||
|
N++ trust the topmost installed dependents of N and their dependencies
|
||||||
*+ *- trust / exclude every listed package (*- again re-includes them)
|
*+ *- trust / exclude every listed package (*- again re-includes them)
|
||||||
|
a show packages trusted during this session again
|
||||||
l redraw the list (a '*' after the number marks an AUR package)
|
l redraw the list (a '*' after the number marks an AUR package)
|
||||||
q quit without upgrading
|
q quit without upgrading
|
||||||
h ? this help
|
h ? this help
|
||||||
@@ -197,7 +205,7 @@ parse_args() {
|
|||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
-V | --version)
|
-v | --version)
|
||||||
printf '%s %s\n' "$SU_PROG" "$SU_VERSION"
|
printf '%s %s\n' "$SU_PROG" "$SU_VERSION"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
@@ -908,7 +916,7 @@ apt_describe() {
|
|||||||
[[ -n $out ]] || out='(no description available)'
|
[[ -n $out ]] || out='(no description available)'
|
||||||
printf '%s\n' "$out"
|
printf '%s\n' "$out"
|
||||||
}
|
}
|
||||||
apt_full_info() { apt-cache show --no-all-versions "$1" </dev/null; }
|
apt_full_info() { apt-cache show --no-all-versions "$1" </dev/null | gutter; }
|
||||||
# apt_installed_record PKG: dpkg's own record (`dpkg-query -s`: richer than `apt-cache show
|
# apt_installed_record PKG: dpkg's own record (`dpkg-query -s`: richer than `apt-cache show
|
||||||
# PKG=<installed version>`, which gives the archive's record when that version is still listed:
|
# PKG=<installed version>`, which gives the archive's record when that version is still listed:
|
||||||
# no Status, no Conffiles, often only the short description); a package dpkg merely remembers
|
# no Status, no Conffiles, often only the short description); a package dpkg merely remembers
|
||||||
@@ -970,20 +978,21 @@ apt_closure() {
|
|||||||
# is system-wide (it also takes pre-existing orphans, e.g. old kernels: verified), so the
|
# is system-wide (it also takes pre-existing orphans, e.g. old kernels: verified), so the
|
||||||
# orphans that were already autoremovable before are subtracted and the rest named explicitly.
|
# orphans that were already autoremovable before are subtracted and the rest named explicitly.
|
||||||
apt_purge_plan() {
|
apt_purge_plan() {
|
||||||
local pkg=$1 pre sim w name rest
|
local pre sim w name rest
|
||||||
local -A before=()
|
local -A before=() requested=()
|
||||||
local -a args=("$pkg")
|
local -a args=("$@")
|
||||||
|
for name in "$@"; do requested[$name]=1; done
|
||||||
pre=$(apt-get -s autoremove </dev/null 2>/dev/null) || pre=''
|
pre=$(apt-get -s autoremove </dev/null 2>/dev/null) || pre=''
|
||||||
while read -r w name rest; do
|
while read -r w name rest; do
|
||||||
[[ $w == Remv || $w == Purg ]] && before[$name]=1
|
[[ $w == Remv || $w == Purg ]] && before[$name]=1
|
||||||
done <<<"$pre"
|
done <<<"$pre"
|
||||||
sim=$(apt-get -s purge --auto-remove "$pkg" </dev/null 2>&1) || {
|
sim=$(apt-get -s purge --auto-remove "$@" </dev/null 2>&1) || {
|
||||||
printf '%s\n' "$sim" >&2
|
printf '%s\n' "$sim" >&2
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
while read -r w name rest; do
|
while read -r w name rest; do
|
||||||
[[ $w == Remv || $w == Purg ]] || continue
|
[[ $w == Remv || $w == Purg ]] || continue
|
||||||
[[ -z ${before[$name]+x} && $name != "$pkg" ]] && args+=("$name")
|
[[ -z ${before[$name]+x} && -z ${requested[$name]+x} ]] && args+=("$name")
|
||||||
done <<<"$sim"
|
done <<<"$sim"
|
||||||
sim=$(apt-get -s purge "${args[@]}" </dev/null 2>&1) || {
|
sim=$(apt-get -s purge "${args[@]}" </dev/null 2>&1) || {
|
||||||
printf '%s\n' "$sim" >&2
|
printf '%s\n' "$sim" >&2
|
||||||
@@ -1292,9 +1301,11 @@ aur_warn_pending() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# aur_exec ARGS...: run the helper (as the invoking user when we are root), stdin from /dev/null,
|
# aur_exec ARGS...: run the helper (as the invoking user when we are root), stdin from /dev/null,
|
||||||
# our lock descriptors closed, from that user's home
|
# our lock descriptors closed, from that user's home; COLUMNS=0: yay wraps -Sia lists at 80 columns
|
||||||
|
# otherwise, even without a terminal (discovery/pacman.md 15.2; the merge unwraps anyway)
|
||||||
aur_exec() {
|
aur_exec() {
|
||||||
(
|
(
|
||||||
|
export COLUMNS=0
|
||||||
if [[ -n $AUR_HOME ]]; then cd -- "$AUR_HOME" 2>/dev/null || cd /; fi
|
if [[ -n $AUR_HOME ]]; then cd -- "$AUR_HOME" 2>/dev/null || cd /; fi
|
||||||
run_child ${AUR_RUN[@]+"${AUR_RUN[@]}"} "$AUR_HELPER" "$@"
|
run_child ${AUR_RUN[@]+"${AUR_RUN[@]}"} "$AUR_HELPER" "$@"
|
||||||
)
|
)
|
||||||
@@ -1415,19 +1426,19 @@ pacman_describe() {
|
|||||||
[[ -n $out ]] || return 1
|
[[ -n $out ]] || return 1
|
||||||
printf '%s\n' "$out"
|
printf '%s\n' "$out"
|
||||||
}
|
}
|
||||||
# pacman_full_info PKG: -Qi and -Si as pacman prints them (each record ends with a blank line). A
|
# pacman_full_info PKG: -Qi and -Si as pacman prints them (each record ends with a blank line), with
|
||||||
# package in no repository: the AUR record when a helper is in use, every line marked with "> "
|
# the " " gutter. A package in no repository: the AUR record when a helper is in use, every line
|
||||||
# (reached only when it does not merge with -Qi - paru's and yay's records do)
|
# marked "* " (reached only when it does not merge with -Qi - paru's and yay's records do)
|
||||||
pacman_full_info() {
|
pacman_full_info() {
|
||||||
local ok=1 qi si aur='' l
|
local ok=1 qi si aur=''
|
||||||
qi=$(_pm -Qi -- "$1" 2>/dev/null) && ok=0
|
qi=$(_pm -Qi -- "$1" 2>/dev/null) && ok=0
|
||||||
si=$(_pm -Si -- "$1" 2>/dev/null) && ok=0
|
si=$(_pm -Si -- "$1" 2>/dev/null) && ok=0
|
||||||
if [[ -z $si ]] && aur_prepare; then aur=$(aur_info "$1") || aur=''; fi
|
if [[ -z $si ]] && aur_prepare; then aur=$(aur_info "$1") || aur=''; fi
|
||||||
[[ -z $aur ]] || say "# lines starting with > are the AUR record ($AUR_HELPER -Sia) as it prints it"
|
[[ -z $aur ]] || say "# lines starting with * are the AUR record ($AUR_HELPER -Sia) as it prints it"
|
||||||
[[ -z $qi ]] || printf '%s\n\n' "$qi"
|
[[ -z $qi ]] || printf '%s\n\n' "$qi" | gutter
|
||||||
[[ -z $si ]] || printf '%s\n\n' "$si"
|
[[ -z $si ]] || printf '%s\n\n' "$si" | gutter
|
||||||
if [[ -n $aur ]]; then
|
if [[ -n $aur ]]; then
|
||||||
while IFS= read -r l; do printf '> %s\n' "$l"; done <<<"$aur"
|
printf '%s\n' "$aur" | sed '/./s/^/* /'
|
||||||
ok=0
|
ok=0
|
||||||
fi
|
fi
|
||||||
return "$ok"
|
return "$ok"
|
||||||
@@ -1503,7 +1514,7 @@ pacman_closure() {
|
|||||||
# On refusal pacman explains on stdout (":: removing X breaks dependency ..."): show all of it.
|
# On refusal pacman explains on stdout (":: removing X breaks dependency ..."): show all of it.
|
||||||
pacman_purge_plan() {
|
pacman_purge_plan() {
|
||||||
local out rc=0 l
|
local out rc=0 l
|
||||||
out=$(COLUMNS=0 pacman -Rs --print --print-format '%n' -- "$1" </dev/null 2>&1) || rc=$?
|
out=$(COLUMNS=0 pacman -Rs --print --print-format '%n' -- "$@" </dev/null 2>&1) || rc=$?
|
||||||
if ((rc)); then
|
if ((rc)); then
|
||||||
printf '%s\n' "$out" >&2
|
printf '%s\n' "$out" >&2
|
||||||
return "$rc"
|
return "$rc"
|
||||||
@@ -1866,7 +1877,7 @@ dnf_describe() {
|
|||||||
done <<<"$out"
|
done <<<"$out"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
dnf_full_info() { "$DNF" -q info "$1" </dev/null; }
|
dnf_full_info() { "$DNF" -q info "$1" </dev/null | gutter; }
|
||||||
# dnf_installed_record PKG / dnf_candidate_record PKG installed|not-installed: `dnf info` blocks
|
# dnf_installed_record PKG / dnf_candidate_record PKG installed|not-installed: `dnf info` blocks
|
||||||
# without their heading line ("Installed Packages", dnf5 "Available upgrades", ...). The candidate
|
# without their heading line ("Installed Packages", dnf5 "Available upgrades", ...). The candidate
|
||||||
# of an installed package is its upgrade (--upgrades: the installed architecture only, nothing for
|
# of an installed package is its upgrade (--upgrades: the installed architecture only, nothing for
|
||||||
@@ -1904,7 +1915,7 @@ dnf_purge_plan() {
|
|||||||
local out line in=0 wrapped=0
|
local out line in=0 wrapped=0
|
||||||
local -a f=()
|
local -a f=()
|
||||||
local arch_re='^(noarch|x86_64|x86_64_v[0-9]|aarch64|i[3-6]86|ppc64le|ppc64|s390x|armv7hl|armv7l|riscv64|loongarch64|src)$'
|
local arch_re='^(noarch|x86_64|x86_64_v[0-9]|aarch64|i[3-6]86|ppc64le|ppc64|s390x|armv7hl|armv7l|riscv64|loongarch64|src)$'
|
||||||
out=$("$DNF" --assumeno remove "$1" </dev/null 2>&1) || true
|
out=$("$DNF" --assumeno remove "$@" </dev/null 2>&1) || true
|
||||||
if [[ $out != *'Transaction Summary'* ]]; then
|
if [[ $out != *'Transaction Summary'* ]]; then
|
||||||
if [[ $out == *'Nothing to do'* ]]; then return 0; fi
|
if [[ $out == *'Nothing to do'* ]]; then return 0; fi
|
||||||
printf '%s\n' "$out" >&2
|
printf '%s\n' "$out" >&2
|
||||||
@@ -2053,7 +2064,7 @@ zypper_describe() {
|
|||||||
out=$(rpm -q --qf '%{SUMMARY}\n' "$1" </dev/null 2>/dev/null) || return 1
|
out=$(rpm -q --qf '%{SUMMARY}\n' "$1" </dev/null 2>/dev/null) || return 1
|
||||||
printf '%s\n' "$out"
|
printf '%s\n' "$out"
|
||||||
}
|
}
|
||||||
zypper_full_info() { zypper --non-interactive --quiet info --requires "$1" </dev/null; }
|
zypper_full_info() { zypper --non-interactive --quiet info --requires "$1" </dev/null | gutter; }
|
||||||
zypper_rdepends() { rpm_rdeps "$1"; }
|
zypper_rdepends() { rpm_rdeps "$1"; }
|
||||||
zypper_closure() { rpm_closure "$1"; }
|
zypper_closure() { rpm_closure "$1"; }
|
||||||
# zypper_reason PKG: the "Installed" line of `zypper info` - "Yes (automatically)", "Yes" or "No"
|
# zypper_reason PKG: the "Installed" line of `zypper info` - "Yes (automatically)", "Yes" or "No"
|
||||||
@@ -2087,7 +2098,7 @@ zypper_reason() {
|
|||||||
}
|
}
|
||||||
zypper_purge_plan() {
|
zypper_purge_plan() {
|
||||||
local xml rc=0 sec name rest
|
local xml rc=0 sec name rest
|
||||||
xml=$(zypper --non-interactive --no-refresh --xmlout remove --dry-run --clean-deps "$1" </dev/null 2>&1) || rc=$?
|
xml=$(zypper --non-interactive --no-refresh --xmlout remove --dry-run --clean-deps "$@" </dev/null 2>&1) || rc=$?
|
||||||
if ((rc)); then
|
if ((rc)); then
|
||||||
[[ $rc != 104 ]] || say "zypper: no installed package provides '$1' (exit 104)" >&2
|
[[ $rc != 104 ]] || say "zypper: no installed package provides '$1' (exit 104)" >&2
|
||||||
((rc == 104)) || printf '%s\n' "$xml" >&2
|
((rc == 104)) || printf '%s\n' "$xml" >&2
|
||||||
@@ -2225,6 +2236,8 @@ maybe_refresh() { if ((opt_refresh)); then be refresh || true; fi; }
|
|||||||
R_NAME=() R_OLD=() R_NEW=() R_REPO=() R_FLAGS=() R_AUR=() R_NUM=() R_GONE=() R_EXCL=() R_NOTES=()
|
R_NAME=() R_OLD=() R_NEW=() R_REPO=() R_FLAGS=() R_AUR=() R_NUM=() R_GONE=() R_EXCL=() R_NOTES=()
|
||||||
N_IDX=() # number -> row index
|
N_IDX=() # number -> row index
|
||||||
N_MAX=0
|
N_MAX=0
|
||||||
|
SESSION_SHOW_TRUSTED=0
|
||||||
|
declare -A SESSION_TRUSTED=()
|
||||||
|
|
||||||
load_rows() {
|
load_rows() {
|
||||||
local out rc=0 line name old new repo flags i n=0 w aur shown
|
local out rc=0 line name old new repo flags i n=0 w aur shown
|
||||||
@@ -2272,7 +2285,7 @@ rows_left() { # number of rows not purged
|
|||||||
row_visible() { # row_visible IDX
|
row_visible() { # row_visible IDX
|
||||||
local i=$1
|
local i=$1
|
||||||
((R_GONE[i] == 0 && R_NUM[i] > 0)) || return 1
|
((R_GONE[i] == 0 && R_NUM[i] > 0)) || return 1
|
||||||
((opt_all)) || ! is_trusted "${R_NAME[i]}"
|
((opt_all)) || ! is_trusted "${R_NAME[i]}" || { ((SESSION_SHOW_TRUSTED)) && [[ -n ${SESSION_TRUSTED[${R_NAME[i]}]+x} ]]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
print_list() {
|
print_list() {
|
||||||
@@ -2289,6 +2302,8 @@ print_list() {
|
|||||||
done
|
done
|
||||||
if ((opt_all)); then
|
if ((opt_all)); then
|
||||||
say "$total upgradable, $trusted trusted (marked with =), $review to review:"
|
say "$total upgradable, $trusted trusted (marked with =), $review to review:"
|
||||||
|
elif ((SESSION_SHOW_TRUSTED)); then
|
||||||
|
say "$total upgradable, $trusted trusted (session trusted marked with =), $review to review:"
|
||||||
else
|
else
|
||||||
say "$total upgradable, $trusted trusted (hidden, use --all to show), $review to review:"
|
say "$total upgradable, $trusted trusted (hidden, use --all to show), $review to review:"
|
||||||
fi
|
fi
|
||||||
@@ -2356,20 +2371,32 @@ print_info() {
|
|||||||
# pacman, apt, dnf. zypper does not (rpm -qi and zypper info share almost no keys, and zypper cannot
|
# pacman, apt, dnf. zypper does not (rpm -qi and zypper info share almost no keys, and zypper cannot
|
||||||
# print the installed record by itself) and keeps <be>_full_info, as does any package for which
|
# print the installed record by itself) and keeps <be>_full_info, as does any package for which
|
||||||
# either side is missing or is not exactly one record.
|
# either side is missing or is not exactly one record.
|
||||||
readonly SU_MERGE_NOTE='# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
readonly SU_MERGE_NOTE='# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks'
|
||||||
readonly SU_CANDIDATE_NOTE='# not installed: this is the upstream candidate'
|
readonly SU_CANDIDATE_NOTE='# not installed: lines starting with * come from the upstream candidate (all of them)'
|
||||||
# merge: each base field is printed as it is; when the candidate's value differs, the candidate's
|
# gutter: the two-character gutter of N?? / show for native output shown as it is (" " before every
|
||||||
# line(s) follow, prefixed with "> "; fields only the candidate has are appended the same way. A
|
# non-empty line; the merge itself uses " " for installed lines and "* " for the candidate's)
|
||||||
# field starts on a line beginning with a non-blank character that holds a ":" (key = the text
|
gutter() { sed '/./s/^/ /'; }
|
||||||
# before it, trailing blanks dropped; a heading without ":" before the record is skipped); lines
|
# merge: every line gets a two-character gutter: " " for the installed record, "* " for the
|
||||||
# beginning with a blank continue it (pacman Optional Deps, dnf Description, RFC-822 continuation
|
# candidate. Each installed field is printed as it is; when the candidate's value differs, the
|
||||||
# lines), so multi-line values are compared - and prefixed - as blocks, every line trimmed. A blank
|
# candidate's line(s) follow; fields only the candidate has are appended. A field starts on a line
|
||||||
# line ends a record: exit 3 unless each side holds exactly one. Description-xx (apt Translation
|
# beginning with a non-blank character that holds a ":" (key = the text before it, trailing blanks
|
||||||
# files) pairs with Description. apt=1: the archives carry only the short description of the
|
# dropped; a heading without ":" before the record is skipped); lines beginning with a blank continue
|
||||||
# candidate (the long text is in the Translation files), so a one-line candidate Description equal
|
# it (pacman Optional Deps, dnf Description, RFC-822 continuation lines), so multi-line values are
|
||||||
# to the first installed line is the same description. When both records align every ":" in one
|
# compared - and marked - as blocks, every line trimmed. A blank line ends a record: exit 3 unless
|
||||||
# column (pacman, dnf) but in different ones (dnf5 pads installed and available keys differently),
|
# each side holds exactly one. Description-xx (apt Translation files) pairs with Description.
|
||||||
# the candidate lines are re-padded to the installed record's column.
|
# apt=1: the archives carry only the short description of the candidate (the long text is in the
|
||||||
|
# Translation files), so a one-line candidate Description equal to the first installed line is the
|
||||||
|
# same description. When both records align every ":" in one column (pacman, dnf) but in different
|
||||||
|
# ones (dnf5 pads installed and available keys differently, yay -Sia pads to 30), the candidate lines
|
||||||
|
# are re-padded to the installed record's column.
|
||||||
|
# pm=1 (pacman: -Qi with -Si or an AUR helper's -Sia; discovery/pacman.md sections 14-15): values are
|
||||||
|
# compared unwrapped (continuation lines joined: the AUR helpers wrap long lists at the terminal
|
||||||
|
# width), runs of blanks as one; list fields (Depends On, Provides, ...) as token sets, in any order
|
||||||
|
# (a version constraint is part of its token); Optional Deps by package names only (-Qi prints
|
||||||
|
# "name: description [installed]" per line, the AUR prints bare names). A differing candidate value
|
||||||
|
# is one line, as -Qi prints it - but Optional Deps, one entry per line under the value column - and
|
||||||
|
# candidate-only fields go next to their installed counterpart (the anchor table below: Repository
|
||||||
|
# after Version, AUR URL after URL, ...), the others at the end in the candidate's order.
|
||||||
# shellcheck disable=SC2016 # awk program, not shell
|
# shellcheck disable=SC2016 # awk program, not shell
|
||||||
readonly AWK_MERGE_RECORDS='
|
readonly AWK_MERGE_RECORDS='
|
||||||
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t\r]+$/, "", s); return s }
|
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t\r]+$/, "", s); return s }
|
||||||
@@ -2379,7 +2406,52 @@ function repad(l, i, k) {
|
|||||||
if (shift > 0) return sprintf("%" shift "s", "") l
|
if (shift > 0) return sprintf("%" shift "s", "") l
|
||||||
return substr(l, 1 - shift)
|
return substr(l, 1 - shift)
|
||||||
}
|
}
|
||||||
function pfx(s, n, a, m) { n = split(s, a, "\n"); for (m = 1; m <= n; m++) print "> " repad(a[m]) }
|
function mine(s, n, a, m) { n = split(s, a, "\n"); for (m = 1; m <= n; m++) print " " a[m] }
|
||||||
|
function theirs(s, n, a, m) { n = split(s, a, "\n"); for (m = 1; m <= n; m++) print "* " repad(a[m]) }
|
||||||
|
# kv K V: a "Key : value" line in the layout of the installed record
|
||||||
|
function kv(k, v) { return (col[1] > 0) ? sprintf("%-" (col[1] - 1) "s: %s", k, v) : k " : " v }
|
||||||
|
function isort(a, n, i, j, t) { for (i = 2; i <= n; i++) { t = a[i]; for (j = i - 1; j > 0 && a[j] > t; j--) a[j + 1] = a[j]; a[j + 1] = t } }
|
||||||
|
function joined(a, n, i, r) { r = ""; for (i = 1; i <= n; i++) r = r (i > 1 ? " " : "") a[i]; return r }
|
||||||
|
function flat(s) { gsub(/[ \t\n]+/, " ", s); return trim(s) }
|
||||||
|
# tokens S: the sorted tokens of a list value
|
||||||
|
function tokens(s, t, n, i, u, m) { n = split(flat(s), t, " "); m = 0; for (i = 1; i <= n; i++) if (t[i] != "") u[++m] = t[i]; isort(u, m); return joined(u, m) }
|
||||||
|
# entries S E: the entries of an Optional Deps value: one per line, or separated by 2+ blanks
|
||||||
|
function entries(s, e, n, a, m, c, b, x, ne) {
|
||||||
|
ne = 0; n = split(s, a, "\n")
|
||||||
|
for (m = 1; m <= n; m++) { c = split(a[m], b, /[ \t][ \t]+/); for (x = 1; x <= c; x++) { b[x] = trim(b[x]); if (b[x] != "") e[++ne] = b[x] } }
|
||||||
|
return ne
|
||||||
|
}
|
||||||
|
# names S: the sorted package names of an Optional Deps value ("None": none)
|
||||||
|
function names(s, e, n, i, x, u, m) {
|
||||||
|
n = entries(s, e); m = 0
|
||||||
|
for (i = 1; i <= n; i++) { x = e[i]; sub(/[ \t]*\[installed\]$/, "", x); sub(/:( .*)?$/, "", x); x = trim(x); if (x != "" && x != "None") u[++m] = x }
|
||||||
|
isort(u, m); return joined(u, m)
|
||||||
|
}
|
||||||
|
function same(k) {
|
||||||
|
if (!pm) return val[1, k] == val[2, k]
|
||||||
|
if (k == "Optional Deps") return names(val[1, k]) == names(val[2, k])
|
||||||
|
if (k in LIST) return tokens(val[1, k]) == tokens(val[2, k])
|
||||||
|
return flat(val[1, k]) == flat(val[2, k])
|
||||||
|
}
|
||||||
|
function up(k, e, n, i, ind, v) {
|
||||||
|
done[k] = 1
|
||||||
|
if (!pm) { theirs(raw[2, k]); return }
|
||||||
|
if (k == "Optional Deps") {
|
||||||
|
n = entries(val[2, k], e); ind = (col[1] > 0) ? col[1] + 1 : length(k) + 3
|
||||||
|
print "* " kv(k, e[1])
|
||||||
|
for (i = 2; i <= n; i++) print "* " sprintf("%" ind "s", "") e[i]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (nl[2, k] == 1) { theirs(raw[2, k]); return }
|
||||||
|
v = val[2, k]; gsub(/\n/, (k in LIST) ? " " : " ", v)
|
||||||
|
print "* " kv(k, v)
|
||||||
|
}
|
||||||
|
BEGIN {
|
||||||
|
n = split("Groups|Provides|Depends On|Required By|Optional For|Conflicts With|Replaces|Make Deps|Check Deps|Licenses|Keywords", t, "|")
|
||||||
|
for (i = 1; i <= n; i++) LIST[t[i]] = 1
|
||||||
|
na = split("Repository>Version|AUR URL>URL|Keywords>Groups|Make Deps>Optional Deps|Check Deps>Optional Deps|Maintainer>Packager|Last Modified>Build Date|First Submitted>Build Date|Download Size>Installed Size", t, "|")
|
||||||
|
for (i = 1; i <= na; i++) { split(t[i], p, ">"); AK[i] = p[1]; AA[i] = p[2] }
|
||||||
|
}
|
||||||
FNR == 1 { side = (FILENAME == ARGV[1]) ? 1 : 2; cur = "" }
|
FNR == 1 { side = (FILENAME == ARGV[1]) ? 1 : 2; cur = "" }
|
||||||
/^[ \t]*$/ { if (nk[side]) ended[side] = 1; next }
|
/^[ \t]*$/ { if (nk[side]) ended[side] = 1; next }
|
||||||
/^[^ \t]/ {
|
/^[^ \t]/ {
|
||||||
@@ -2405,23 +2477,23 @@ END {
|
|||||||
shift = (col[1] > 0 && col[2] > 0) ? col[1] - col[2] : 0
|
shift = (col[1] > 0 && col[2] > 0) ? col[1] - col[2] : 0
|
||||||
for (j = 1; j <= nk[1]; j++) {
|
for (j = 1; j <= nk[1]; j++) {
|
||||||
k = key[1, j]
|
k = key[1, j]
|
||||||
print raw[1, k]
|
mine(raw[1, k])
|
||||||
if (!((2, k) in raw) || val[1, k] == val[2, k]) continue
|
if (((2, k) in raw) && !same(k) && !(apt && k == "Description" && nl[2, k] == 1 && val[2, k] == first[1, k])) up(k)
|
||||||
if (apt && k == "Description" && nl[2, k] == 1 && val[2, k] == first[1, k]) continue
|
if (pm) for (a = 1; a <= na; a++) if (AA[a] == k && ((2, AK[a]) in raw) && !((1, AK[a]) in raw) && !(AK[a] in done)) up(AK[a])
|
||||||
pfx(raw[2, k])
|
|
||||||
}
|
}
|
||||||
for (j = 1; j <= nk[2]; j++) { k = key[2, j]; if (!((1, k) in raw)) pfx(raw[2, k]) }
|
for (j = 1; j <= nk[2]; j++) { k = key[2, j]; if (!((1, k) in raw) && !(k in done)) up(k) }
|
||||||
}'
|
}'
|
||||||
|
|
||||||
print_full_info() { # print_full_info PKG [OLD] (N?? / show); 1 if the package manager knows nothing
|
print_full_info() { # print_full_info PKG [OLD] (N?? / show); 1 if the package manager knows nothing
|
||||||
local rc=0 inst='' cand='' out apt=0
|
local rc=0 inst='' cand='' out apt=0 pm=0
|
||||||
if declare -F "${BACKEND}_installed_record" >/dev/null; then
|
if declare -F "${BACKEND}_installed_record" >/dev/null; then
|
||||||
[[ $BACKEND != apt ]] || apt=1
|
[[ $BACKEND != apt ]] || apt=1
|
||||||
|
[[ $BACKEND != pacman ]] || pm=1
|
||||||
# a row whose old version is "-" is a new dependency: not installed, nothing to ask
|
# a row whose old version is "-" is a new dependency: not installed, nothing to ask
|
||||||
[[ ${2:-} == - ]] || inst=$(be installed_record "$1") || inst=''
|
[[ ${2:-} == - ]] || inst=$(be installed_record "$1") || inst=''
|
||||||
if [[ -n $inst ]]; then
|
if [[ -n $inst ]]; then
|
||||||
cand=$(be candidate_record "$1" installed) || cand=''
|
cand=$(be candidate_record "$1" installed) || cand=''
|
||||||
if [[ -n $cand ]] && out=$(awk -v apt="$apt" "$AWK_MERGE_RECORDS" <(printf '%s\n' "$inst") <(printf '%s\n' "$cand")); then
|
if [[ -n $cand ]] && out=$(awk -v apt="$apt" -v pm="$pm" "$AWK_MERGE_RECORDS" <(printf '%s\n' "$inst") <(printf '%s\n' "$cand")); then
|
||||||
say "$SU_MERGE_NOTE"
|
say "$SU_MERGE_NOTE"
|
||||||
say "$out"
|
say "$out"
|
||||||
return 0
|
return 0
|
||||||
@@ -2430,11 +2502,12 @@ print_full_info() { # print_full_info PKG [OLD] (N?? / show); 1 if the package m
|
|||||||
cand=$(be candidate_record "$1" not-installed) || cand=''
|
cand=$(be candidate_record "$1" not-installed) || cand=''
|
||||||
if [[ -n $cand ]]; then
|
if [[ -n $cand ]]; then
|
||||||
say "$SU_CANDIDATE_NOTE"
|
say "$SU_CANDIDATE_NOTE"
|
||||||
say "$cand"
|
printf '%s\n' "$cand" | sed '/./s/^/* /'
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
# the native output as it is (<be>_full_info prints it with the gutter)
|
||||||
be full_info "$1" || rc=$?
|
be full_info "$1" || rc=$?
|
||||||
((rc == 0)) && return 0
|
((rc == 0)) && return 0
|
||||||
err "no package information for '$1' ($(be label) exited $rc)"
|
err "no package information for '$1' ($(be label) exited $rc)"
|
||||||
@@ -2569,66 +2642,103 @@ num_row() { # num_row N -> $REPLY = row index of a listed row, rc 1 if N is not
|
|||||||
REPLY=${N_IDX[n]}
|
REPLY=${N_IDX[n]}
|
||||||
}
|
}
|
||||||
|
|
||||||
# session_purge IDX: pacman's -Rns principle on every backend - a package that other installed
|
# session_purge IDX...: pacman's -Rns principle on every backend - a package that other installed
|
||||||
# packages still depend on is never purged (they are listed, as N? does; nothing cascades);
|
# packages still depend on is never purged (they are listed, as N? does; nothing cascades);
|
||||||
# otherwise the package goes with the dependencies it alone needed, as the y/N prompt lists.
|
# otherwise the package goes with the dependencies it alone needed, as the y/N prompt lists.
|
||||||
session_purge() {
|
session_purge() {
|
||||||
local i=$1 name=${R_NAME[$1]} rc=0 out line p prompt rd d
|
local i name rd out rc=0 p prompt idx dep changed
|
||||||
local -a plan=() others=() extra=()
|
local -a targets=() target_names=() total_plan=() total_others=() extra=() rdeps=()
|
||||||
local -A still=() gone=() mine=()
|
local -A purge_selected=() rejected=() reverse=() gone=() allowed=() still=()
|
||||||
|
local line
|
||||||
|
|
||||||
|
for idx in "$@"; do purge_selected[${R_NAME[idx]}]=$idx; done
|
||||||
|
mapfile -t targets < <(printf '%s\n' "${purge_selected[@]}" | sort -n)
|
||||||
|
for i in "${targets[@]}"; do
|
||||||
|
name=${R_NAME[i]}
|
||||||
if [[ ${R_OLD[i]} == - ]]; then
|
if [[ ${R_OLD[i]} == - ]]; then
|
||||||
say "$name is not installed (the upgrade would install it as a new dependency): nothing to purge; use $((R_NUM[i]))- to exclude it from this run."
|
say "$name is not installed (the upgrade would install it as a new dependency): nothing to purge; use $((R_NUM[i]))- to exclude it from this run."
|
||||||
return 0
|
rejected[$name]=1
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
rd=$(be rdepends "$name") || rd=''
|
rd=$(be rdepends "$name") || rd=''
|
||||||
rd=$(printf '%s\n' "$rd" | sed '/^$/d' | tr '\n' ' ')
|
reverse[$name]=$(printf '%s\n' "$rd" | sed '/^$/d' | tr '\n' ' ')
|
||||||
rd=${rd% }
|
done
|
||||||
if [[ -n $rd ]]; then
|
# A refused dependent also blocks its dependencies, including through a chain.
|
||||||
|
changed=1
|
||||||
|
while ((changed)); do
|
||||||
|
changed=0
|
||||||
|
for i in "${targets[@]}"; do
|
||||||
|
name=${R_NAME[i]}
|
||||||
|
[[ -z ${rejected[$name]+x} ]] || continue
|
||||||
|
read -r -a rdeps <<<"${reverse[$name]}"
|
||||||
|
for dep in "${rdeps[@]}"; do
|
||||||
|
if [[ -z ${purge_selected[$dep]+x} || -n ${rejected[$dep]+x} ]]; then
|
||||||
|
rd=${reverse[$name]% }
|
||||||
say "not purged: $name is required by: ${rd// /, } - purge the dependents first"
|
say "not purged: $name is required by: ${rd// /, } - purge the dependents first"
|
||||||
return 0
|
rejected[$name]=1
|
||||||
|
changed=1
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
out=$(be purge_plan "$name" | sort -u) || rc=$?
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for i in "${targets[@]}"; do
|
||||||
|
name=${R_NAME[i]}
|
||||||
|
[[ -z ${rejected[$name]+x} ]] || continue
|
||||||
|
target_names+=("$name")
|
||||||
|
allowed[$name]=1
|
||||||
|
closure_of "$name"
|
||||||
|
for dep in ${CLOSURE[@]+"${CLOSURE[@]}"}; do allowed[$dep]=1; done
|
||||||
|
done
|
||||||
|
((${#target_names[@]})) || return 0
|
||||||
|
out=$(be purge_plan "${target_names[@]}" | sort -u) || rc=$?
|
||||||
if ((rc)); then
|
if ((rc)); then
|
||||||
err "cannot purge $name: $(be label) refuses (see above); nothing was removed"
|
err "cannot purge ${target_names[*]}: $(be label) refuses (see above); nothing was removed"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
while IFS= read -r p; do
|
while IFS= read -r p; do
|
||||||
[[ -n $p && -z ${gone[$p]+x} ]] || continue
|
[[ -n $p ]] || continue
|
||||||
|
total_plan+=("$p")
|
||||||
gone[$p]=1
|
gone[$p]=1
|
||||||
plan+=("$p")
|
[[ -n ${purge_selected[$p]+x} && -z ${rejected[$p]+x} ]] || total_others+=("$p")
|
||||||
[[ $p == "$name" ]] || others+=("$p")
|
[[ -n ${allowed[$p]+x} && -z ${rejected[$p]+x} ]] || extra+=("$p")
|
||||||
done <<<"$out"
|
done <<<"$out"
|
||||||
if ((${#plan[@]} == 0)); then
|
if ((${#total_plan[@]} == 0)); then
|
||||||
say "$name is not installed: nothing to purge."
|
say "${target_names[*]} is not installed: nothing to purge."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
# belt and braces: the plan may only hold the target and its own (installed) dependencies;
|
for name in "${target_names[@]}"; do
|
||||||
# anything else means a dependent the reverse-dependency query missed (e.g. through a virtual)
|
if [[ -z ${gone[$name]+x} ]]; then
|
||||||
if ((${#others[@]})); then
|
err "cannot purge $name: $(be label) did not include it in the plan; nothing was removed"
|
||||||
closure_of "$name"
|
return 0
|
||||||
for d in ${CLOSURE[@]+"${CLOSURE[@]}"}; do mine[$d]=1; done
|
fi
|
||||||
for p in "${others[@]}"; do [[ -n ${mine[$p]+x} ]] || extra+=("$p"); done
|
done
|
||||||
|
# belt and braces: no package outside the targets and their dependencies may be removed.
|
||||||
if ((${#extra[@]})); then
|
if ((${#extra[@]})); then
|
||||||
err "cannot purge $name: $(be label) would also remove $(join_by ', ' "${extra[@]}"), which $name does not depend on (dependents of it?); nothing was removed"
|
err "cannot purge ${target_names[*]}: $(be label) would also remove $(join_by ', ' "${extra[@]}"), which ${target_names[*]} does not depend on (dependents of it?); nothing was removed"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
prompt="Purge ${target_names[*]} now?"
|
||||||
prompt="Purge $name now?"
|
((${#total_others[@]} == 0)) || prompt+=" This also removes: $(join_by ', ' "${total_others[@]}")"
|
||||||
((${#others[@]} == 0)) || prompt+=" This also removes: $(join_by ', ' "${others[@]}")"
|
|
||||||
read_line "$prompt [y/N] "
|
read_line "$prompt [y/N] "
|
||||||
case $REPLY in
|
case $REPLY in
|
||||||
y | Y | yes | YES | Yes) ;;
|
y | Y | yes | YES | Yes) ;;
|
||||||
*)
|
*)
|
||||||
say "not purged: $name"
|
say "not purged: ${target_names[*]}"
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
be purge "${plan[@]}" || rc=$?
|
rc=0
|
||||||
|
be purge "${total_plan[@]}" || rc=$?
|
||||||
if ((rc)); then
|
if ((rc)); then
|
||||||
err "purge of $name failed ($(be label) exited $rc); the row stays in the list"
|
if ((${#target_names[@]} == 1)); then
|
||||||
|
err "purge of ${target_names[0]} failed ($(be label) exited $rc); the row stays in the list"
|
||||||
|
else
|
||||||
|
err "purge of ${target_names[*]} failed ($(be label) exited $rc); the rows stay in the list"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
say "purged: ${plan[*]}"
|
say "purged: ${total_plan[*]}"
|
||||||
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
if [[ -n ${gone[${R_NAME[i]}]+x} ]]; then
|
if [[ -n ${gone[${R_NAME[i]}]+x} ]]; then
|
||||||
R_GONE[i]=1
|
R_GONE[i]=1
|
||||||
@@ -2652,15 +2762,42 @@ session_purge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
session_trust() { # session_trust IDX...
|
session_trust() { # session_trust IDX...
|
||||||
local i now
|
local i j d now covered
|
||||||
now=$(now_utc)
|
local -a selected=() roots=()
|
||||||
|
local -A seen=() reach=()
|
||||||
for i in "$@"; do
|
for i in "$@"; do
|
||||||
|
[[ -z ${seen[$i]+x} ]] || continue
|
||||||
|
seen[$i]=1
|
||||||
|
selected+=("$i")
|
||||||
|
done
|
||||||
|
for i in "${selected[@]}"; do
|
||||||
|
closure_of "${R_NAME[i]}"
|
||||||
|
for d in ${CLOSURE[@]+"${CLOSURE[@]}"}; do reach["$i,$d"]=1; done
|
||||||
|
done
|
||||||
|
for i in "${selected[@]}"; do
|
||||||
|
covered=0
|
||||||
|
for j in "${selected[@]}"; do
|
||||||
|
[[ $i != "$j" && -n ${reach[$j,${R_NAME[i]}]+x} ]] || continue
|
||||||
|
if [[ -z ${reach[$i,${R_NAME[j]}]+x} ]] || ((j < i)); then covered=1; break; fi
|
||||||
|
done
|
||||||
|
((covered)) || roots+=("$i")
|
||||||
|
done
|
||||||
|
now=$(now_utc)
|
||||||
|
for i in "${roots[@]}"; do
|
||||||
trust_pkg "${R_NAME[i]}" "$now"
|
trust_pkg "${R_NAME[i]}" "$now"
|
||||||
R_EXCL[i]=0
|
R_EXCL[i]=0
|
||||||
done
|
done
|
||||||
|
session_finish_trust
|
||||||
|
}
|
||||||
|
|
||||||
|
session_finish_trust() {
|
||||||
|
local i
|
||||||
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
|
if ((R_NUM[i] > 0 && !R_GONE[i])) && is_trusted "${R_NAME[i]}"; then SESSION_TRUSTED[${R_NAME[i]}]=1; fi
|
||||||
|
done
|
||||||
# a row this trust hides must not stay excluded behind the user's back
|
# a row this trust hides must not stay excluded behind the user's back
|
||||||
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
if ((R_EXCL[i] && !R_GONE[i] && !opt_all)) && is_trusted "${R_NAME[i]}"; then
|
if ((R_EXCL[i] && !R_GONE[i])) && is_trusted "${R_NAME[i]}" && ! row_visible "$i"; then
|
||||||
R_EXCL[i]=0
|
R_EXCL[i]=0
|
||||||
say " (${R_NAME[i]} is trusted now: no longer excluded from this run)"
|
say " (${R_NAME[i]} is trusted now: no longer excluded from this run)"
|
||||||
fi
|
fi
|
||||||
@@ -2668,6 +2805,62 @@ session_trust() { # session_trust IDX...
|
|||||||
state_save
|
state_save
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_trust_dependents() {
|
||||||
|
local i=$1 node dep out root other candidate now head blocked
|
||||||
|
local -a queue=() nodes=() roots=() walk=() deps=()
|
||||||
|
local -A seen=() edges=() reach=() visited=()
|
||||||
|
if [[ ${R_OLD[i]} == - ]]; then
|
||||||
|
say "${R_NAME[i]} is not installed: cannot find installed dependents."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
queue=("${R_NAME[i]}")
|
||||||
|
seen[${R_NAME[i]}]=1
|
||||||
|
for ((head = 0; head < ${#queue[@]}; head++)); do
|
||||||
|
node=${queue[head]}
|
||||||
|
nodes+=("$node")
|
||||||
|
if ! out=$(be rdepends "$node"); then
|
||||||
|
err "cannot find installed dependents of $node; nothing was trusted"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
while IFS= read -r dep; do
|
||||||
|
[[ -n $dep ]] || continue
|
||||||
|
edges[$node]+=" $dep"
|
||||||
|
if [[ -z ${seen[$dep]+x} ]]; then seen[$dep]=1; queue+=("$dep"); fi
|
||||||
|
done <<<"$out"
|
||||||
|
done
|
||||||
|
for root in "${nodes[@]}"; do
|
||||||
|
walk=("$root")
|
||||||
|
visited=(["$root"]=1)
|
||||||
|
for ((head = 0; head < ${#walk[@]}; head++)); do
|
||||||
|
node=${walk[head]}
|
||||||
|
read -r -a deps <<<"${edges[$node]-}"
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
[[ -z ${visited[$dep]+x} ]] || continue
|
||||||
|
visited[$dep]=1
|
||||||
|
walk+=("$dep")
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for node in "${walk[@]}"; do reach["$root,$node"]=1; done
|
||||||
|
done
|
||||||
|
mapfile -t nodes < <(printf '%s\n' "${nodes[@]}" | sort -u)
|
||||||
|
for root in "${nodes[@]}"; do
|
||||||
|
blocked=0
|
||||||
|
for other in "${nodes[@]}"; do
|
||||||
|
[[ $root != "$other" && -n ${reach[$root,$other]+x} ]] || continue
|
||||||
|
if [[ -z ${reach[$other,$root]+x} || $other < $root ]]; then blocked=1; break; fi
|
||||||
|
done
|
||||||
|
((blocked)) || roots+=("$root")
|
||||||
|
done
|
||||||
|
now=$(now_utc)
|
||||||
|
for candidate in "${roots[@]}"; do
|
||||||
|
trust_pkg "$candidate" "$now"
|
||||||
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
|
[[ ${R_NAME[i]} != "$candidate" ]] || R_EXCL[i]=0
|
||||||
|
done
|
||||||
|
done
|
||||||
|
session_finish_trust
|
||||||
|
}
|
||||||
|
|
||||||
session_toggle_all() {
|
session_toggle_all() {
|
||||||
local i all=1
|
local i all=1
|
||||||
local -a idx=()
|
local -a idx=()
|
||||||
@@ -2687,26 +2880,33 @@ session_toggle_all() {
|
|||||||
SESSION_PROCEED=0
|
SESSION_PROCEED=0
|
||||||
UPGRADE_FAILED_MSG= # set by <be>_upgrade when the failing step is not the package manager's own
|
UPGRADE_FAILED_MSG= # set by <be>_upgrade when the failing step is not the package manager's own
|
||||||
|
|
||||||
# session_line LINE: validate every token first (a typo never executes half a line), then run them
|
session_flush_purges() {
|
||||||
|
local -n pb=$1
|
||||||
|
if ((${#pb[@]})); then
|
||||||
|
session_purge "${pb[@]}"
|
||||||
|
pb=()
|
||||||
|
if (($(rows_left) == 0 && ${#R_NOTES[@]} == 0)); then
|
||||||
|
say "Nothing left to upgrade."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
session_line() {
|
session_line() {
|
||||||
local tok n op i
|
local tok n op i name
|
||||||
local -a toks=()
|
local -a toks=() batch=() purge_batch=()
|
||||||
local re='^([0-9]{1,6})(\?\?|\?|-|x|\+)$'
|
local -A initial=() named=()
|
||||||
|
local re='^([0-9]{1,6})(\?\?|\?|-|x|\+\+|\+)$'
|
||||||
|
local name_re='^([A-Za-z0-9_+@][A-Za-z0-9_+.@:~-]*)(\?\?|\?)$'
|
||||||
read -r -a toks <<<"$1" || true
|
read -r -a toks <<<"$1" || true
|
||||||
if ((${#toks[@]} == 0)); then
|
if ((${#toks[@]} == 0)); then
|
||||||
SESSION_PROCEED=1
|
SESSION_PROCEED=1
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
for tok in "${toks[@]}"; do
|
for tok in "${toks[@]}"; do
|
||||||
if [[ $tok =~ $re ]]; then
|
if [[ ! $tok =~ $re && ! $tok =~ $name_re ]]; then
|
||||||
n=$((10#${BASH_REMATCH[1]}))
|
|
||||||
if ! num_row "$n"; then
|
|
||||||
err "no package [$n] in the list (l to redraw)"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
case $tok in
|
case $tok in
|
||||||
'*+' | '*-' | l | q | h | '?') ;;
|
'*+' | '*-' | a | l | q | h | '?') ;;
|
||||||
*)
|
*)
|
||||||
err "unknown command '$tok' (h for help)"
|
err "unknown command '$tok' (h for help)"
|
||||||
return 0
|
return 0
|
||||||
@@ -2714,16 +2914,49 @@ session_line() {
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
for ((n = 1; n <= N_MAX; n++)); do
|
||||||
|
if num_row "$n"; then
|
||||||
|
initial[$n]=$REPLY
|
||||||
|
named[${R_NAME[REPLY]}]=$REPLY
|
||||||
|
fi
|
||||||
|
done
|
||||||
for tok in "${toks[@]}"; do
|
for tok in "${toks[@]}"; do
|
||||||
|
if [[ $tok =~ $re ]]; then
|
||||||
|
op=${BASH_REMATCH[2]}
|
||||||
|
if [[ $op == x ]]; then
|
||||||
|
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
|
||||||
|
elif [[ $op == + ]]; then
|
||||||
|
session_flush_purges purge_batch
|
||||||
|
else
|
||||||
|
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
|
||||||
|
session_flush_purges purge_batch
|
||||||
|
fi
|
||||||
|
elif [[ $tok =~ $name_re ]]; then
|
||||||
|
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
|
||||||
|
session_flush_purges purge_batch
|
||||||
|
else
|
||||||
|
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
|
||||||
|
session_flush_purges purge_batch
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $tok =~ $re ]]; then
|
if [[ $tok =~ $re ]]; then
|
||||||
n=$((10#${BASH_REMATCH[1]}))
|
n=$((10#${BASH_REMATCH[1]}))
|
||||||
op=${BASH_REMATCH[2]}
|
op=${BASH_REMATCH[2]}
|
||||||
if ! num_row "$n"; then
|
if [[ -z ${initial[$n]+x} ]] || ((R_GONE[${initial[$n]:-0}])); then
|
||||||
err "package [$n] has left the list; ignoring the rest of the line"
|
err "no package [$n] in the list (l to redraw)"
|
||||||
return 0
|
continue
|
||||||
|
fi
|
||||||
|
i=${initial[$n]}
|
||||||
|
if [[ $op == + ]]; then
|
||||||
|
batch+=("$i")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ $op == x ]]; then
|
||||||
|
purge_batch+=("$i")
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
i=$REPLY
|
|
||||||
case $op in
|
case $op in
|
||||||
|
'++') session_trust_dependents "$i" ;;
|
||||||
'?') print_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
'?') print_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
||||||
'??') print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
'??') print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
||||||
-)
|
-)
|
||||||
@@ -2735,15 +2968,20 @@ session_line() {
|
|||||||
say "excluded from this run: ${R_NAME[i]}"
|
say "excluded from this run: ${R_NAME[i]}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
x)
|
|
||||||
session_purge "$i"
|
|
||||||
if (($(rows_left) == 0 && ${#R_NOTES[@]} == 0)); then
|
|
||||||
say "Nothing left to upgrade."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
+) session_trust "$i" ;;
|
|
||||||
esac
|
esac
|
||||||
|
elif [[ $tok =~ $name_re ]]; then
|
||||||
|
name=${BASH_REMATCH[1]}
|
||||||
|
op=${BASH_REMATCH[2]}
|
||||||
|
if [[ -z ${named[$name]+x} ]] || ((R_GONE[${named[$name]:-0}])); then
|
||||||
|
err "no package '$name' in the list (l to redraw)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
i=${named[$name]}
|
||||||
|
if [[ $op == '?' ]]; then
|
||||||
|
print_info "${R_NAME[i]}" "${R_OLD[i]}" || true
|
||||||
|
else
|
||||||
|
print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
case $tok in
|
case $tok in
|
||||||
'*+')
|
'*+')
|
||||||
@@ -2754,6 +2992,13 @@ session_line() {
|
|||||||
if ((${#idx[@]})); then session_trust "${idx[@]}"; else say "nothing to trust"; fi
|
if ((${#idx[@]})); then session_trust "${idx[@]}"; else say "nothing to trust"; fi
|
||||||
;;
|
;;
|
||||||
'*-') session_toggle_all ;;
|
'*-') session_toggle_all ;;
|
||||||
|
a)
|
||||||
|
SESSION_SHOW_TRUSTED=1
|
||||||
|
for ((n = 1; n <= N_MAX; n++)); do
|
||||||
|
if num_row "$n"; then initial[$n]=$REPLY; named[${R_NAME[REPLY]}]=$REPLY; fi
|
||||||
|
done
|
||||||
|
print_list
|
||||||
|
;;
|
||||||
l) print_list ;;
|
l) print_list ;;
|
||||||
q)
|
q)
|
||||||
say "Quit: nothing was upgraded."
|
say "Quit: nothing was upgraded."
|
||||||
@@ -2763,6 +3008,8 @@ session_line() {
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
if ((${#batch[@]})); then session_trust "${batch[@]}"; fi
|
||||||
|
session_flush_purges purge_batch
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_interactive() {
|
cmd_interactive() {
|
||||||
|
|||||||
+5
-5
@@ -67,12 +67,12 @@ pacman_only() { [[ $BE == pacman ]] || skip "pacman backend only"; }
|
|||||||
'su-dummy-aur: Skeptical-updater dummy package AUR (foreign: in no repository)' \
|
'su-dummy-aur: Skeptical-updater dummy package AUR (foreign: in no repository)' \
|
||||||
'reason: explicitly installed' \
|
'reason: explicitly installed' \
|
||||||
'required by: nothing')"
|
'required by: nothing')"
|
||||||
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
assert_line '# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks'
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.0-1' '* Version : 2.0-1' '* Repository : aur')"
|
||||||
assert_line ' Install Reason : Explicitly installed'
|
assert_line ' Install Reason : Explicitly installed'
|
||||||
assert_line '> Repository : aur'
|
assert_output --partial "$(printf '%s\n' ' URL : https://example.invalid/su-dummy' '* AUR URL : https://aur.archlinux.org/packages/su-dummy-aur')"
|
||||||
assert_line '> Maintainer : su-fixture'
|
assert_output --partial "$(printf '%s\n' ' Packager : su-fixture <su-fixture@example.invalid>' '* Maintainer : su-fixture')"
|
||||||
assert_line '> AUR URL : https://aur.archlinux.org/packages/su-dummy-aur'
|
assert_output --partial "$(printf '%s\n' ' Validated By : None' '* Votes : 7' '* Popularity : 0.01' '* Out Of Date : No')"
|
||||||
run grep -c 'su-tester HOME=/home/su-tester PWD=/home/su-tester -Sia su-dummy-aur' "$PARU_LOG"
|
run grep -c 'su-tester HOME=/home/su-tester PWD=/home/su-tester -Sia su-dummy-aur' "$PARU_LOG"
|
||||||
assert_output 1
|
assert_output 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,28 +61,29 @@ zypper_verb() { case $(. /etc/os-release && printf '%s' "$ID") in opensuse-tumbl
|
|||||||
assert_success
|
assert_success
|
||||||
if [[ $BE == zypper ]]; then # no comparable records: the plain zypper info --requires
|
if [[ $BE == zypper ]]; then # no comparable records: the plain zypper info --requires
|
||||||
assert_line ' Information for package su-dummy-b:'
|
assert_line ' Information for package su-dummy-b:'
|
||||||
refute_line --partial '# lines starting with >'
|
refute_line --partial '# lines starting with *'
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
assert_line '# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks'
|
||||||
case $BE in
|
case $BE in
|
||||||
apt)
|
apt)
|
||||||
assert_line ' Package: su-dummy-b'
|
assert_line ' Package: su-dummy-b'
|
||||||
assert_line ' Status: install ok installed'
|
assert_line ' Status: install ok installed'
|
||||||
assert_output --partial "$(printf '%s\n' 'Version: 1.0' '> Version: 2.0')"
|
assert_output --partial "$(printf '%s\n' ' Version: 1.0' '* Version: 2.0')"
|
||||||
assert_line --regexp '^> Filename: .*su-dummy-b_2\.0_all\.deb$'
|
assert_line --regexp '^\* Filename: .*su-dummy-b_2\.0_all\.deb$'
|
||||||
;;
|
;;
|
||||||
pacman)
|
pacman)
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.0-1' '* Version : 2.0-1' '* Repository : su-dummy')"
|
||||||
assert_line ' Install Reason : Installed as a dependency for another package'
|
assert_line ' Install Reason : Installed as a dependency for another package'
|
||||||
assert_line '> Repository : su-dummy'
|
|
||||||
;;
|
;;
|
||||||
dnf)
|
dnf)
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.0' '> Version : 2.0')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.0' '* Version : 2.0')"
|
||||||
assert_output --partial "$(printf '%s\n' 'Repository : @System' '> Repository : su-dummy')"
|
assert_output --partial "$(printf '%s\n' ' Repository : @System' '* Repository : su-dummy')"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
[[ $(grep -c '^> ' <<<"$output") -ge 2 ]]
|
[[ $(grep -c '^\* ' <<<"$output") -ge 2 ]]
|
||||||
|
# every line has the two-character gutter, except the note
|
||||||
|
[[ $(grep -cvE '^(# lines starting with| |\* |$)' <<<"$(sed -n '/^# lines starting with/,/^> q$/p' <<<"$output" | sed '$d')") -eq 0 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "N+ writes the user row and the dep row; list hides both and counts them" {
|
@test "N+ writes the user row and the dep row; list hides both and counts them" {
|
||||||
|
|||||||
+140
-28
@@ -314,22 +314,30 @@ upgrade_steps() {
|
|||||||
run skup --no-refresh <<<$'1??\nq'
|
run skup --no-refresh <<<$'1??\nq'
|
||||||
assert_success
|
assert_success
|
||||||
log_has "$AS_ALICE paru -Sia pfetch"
|
log_has "$AS_ALICE paru -Sia pfetch"
|
||||||
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
assert_line '# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks'
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.10.0-1' '> Version : 1.11.0-1')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.10.0-1' '* Version : 1.11.0-1' '* Repository : aur')"
|
||||||
assert_line ' Install Reason : Explicitly installed'
|
assert_line ' Install Reason : Explicitly installed'
|
||||||
assert_line ' Description : A pretty system information tool written in POSIX sh.'
|
assert_line ' Description : A pretty system information tool written in POSIX sh.'
|
||||||
[[ $(count_lines 'Description : A pretty system information tool written in POSIX sh.') -eq 1 ]]
|
[[ $(grep -c 'Description : A pretty system' <<<"$output") -eq 1 ]]
|
||||||
|
# the AUR-only fields next to their installed counterparts, the rest at the end
|
||||||
assert_output --partial "$(printf '%s\n' \
|
assert_output --partial "$(printf '%s\n' \
|
||||||
'> Repository : aur' \
|
' URL : https://github.com/Un1q32/pfetch' \
|
||||||
'> AUR URL : https://aur.archlinux.org/packages/pfetch' \
|
'* AUR URL : https://aur.archlinux.org/packages/pfetch')"
|
||||||
'> Make Deps : None' \
|
assert_output --partial "$(printf '%s\n' \
|
||||||
'> Check Deps : None' \
|
' Optional Deps : None' \
|
||||||
'> Maintainer : yigits' \
|
'* Make Deps : None' \
|
||||||
'> Votes : 48' \
|
'* Check Deps : None')"
|
||||||
'> Popularity : 0.10344' \
|
assert_output --partial "$(printf '%s\n' \
|
||||||
'> First Submitted : Sat, 16 Jan 2021 09:13:08' \
|
' Packager : Unknown Packager' \
|
||||||
'> Last Modified : Tue, 9 Jun 2026 22:43:50' \
|
'* Maintainer : yigits' \
|
||||||
'> Out Of Date : No')"
|
' Build Date : Sat Oct 10 12:42:02 2026' \
|
||||||
|
'* Last Modified : Tue, 9 Jun 2026 22:43:50' \
|
||||||
|
'* First Submitted : Sat, 16 Jan 2021 09:13:08')"
|
||||||
|
assert_output --partial "$(printf '%s\n' \
|
||||||
|
' Validated By : None' \
|
||||||
|
'* Votes : 48' \
|
||||||
|
'* Popularity : 0.10344' \
|
||||||
|
'* Out Of Date : No')"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "N?? with yay: its wider key column is re-padded to pacman's" {
|
@test "N?? with yay: its wider key column is re-padded to pacman's" {
|
||||||
@@ -337,11 +345,10 @@ upgrade_steps() {
|
|||||||
run skup --no-refresh <<<$'1??\nq'
|
run skup --no-refresh <<<$'1??\nq'
|
||||||
assert_success
|
assert_success
|
||||||
log_has "$AS_ALICE yay -Sia pfetch"
|
log_has "$AS_ALICE yay -Sia pfetch"
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.10.0-1' '> Version : 1.11.0-1')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.10.0-1' '* Version : 1.11.0-1' '* Repository : aur')"
|
||||||
assert_line '> Repository : aur'
|
assert_output --partial "$(printf '%s\n' ' Groups : None' '* Keywords : fetch')"
|
||||||
assert_line '> Keywords : fetch'
|
assert_line '* First Submitted : Sat 16 Jan 2021 09:13:08 AM UTC'
|
||||||
assert_line '> First Submitted : Sat 16 Jan 2021 09:13:08 AM UTC'
|
assert_output --partial "$(printf '%s\n' ' Validated By : None' '* Popularity : 0.103440' '* Votes : 48' '* Out-of-date : No')"
|
||||||
assert_line '> Out-of-date : No'
|
|
||||||
refute_output --regexp 'Repository {10,}:'
|
refute_output --regexp 'Repository {10,}:'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,32 +357,137 @@ upgrade_steps() {
|
|||||||
assert_success
|
assert_success
|
||||||
assert_line ' Name : su-dummy-aur'
|
assert_line ' Name : su-dummy-aur'
|
||||||
assert_line ' Install Reason : Explicitly installed'
|
assert_line ' Install Reason : Explicitly installed'
|
||||||
refute_line --regexp '^> [A-Z#]'
|
refute_line --regexp '^\* '
|
||||||
log_has "$AS_ALICE paru -Sia su-dummy-aur"
|
log_has "$AS_ALICE paru -Sia su-dummy-aur"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "N?? when the AUR record does not merge: -Qi, then the AUR record with every line marked >" {
|
@test "N?? claude-desktop (recorded): yay's wrapped record unwrapped, one-line lists, Optional Deps per entry, AUR fields in place" {
|
||||||
|
# real records: the installed 2.9939.4-1 (pacman -Qi of a stand-in built from the AUR's own
|
||||||
|
# .SRCINFO of that version) and yay 13.0.1's -Sia of 2.31226.1-1, wrapped at 80 columns as yay
|
||||||
|
# prints it without COLUMNS=0 (discovery/pacman.md section 15.2)
|
||||||
|
use_fakes yay pacman runuser getent
|
||||||
|
run skup show claude-desktop
|
||||||
|
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 : claude-desktop
|
||||||
|
Version : 2.9939.4-1
|
||||||
|
* Version : 2.31226.1-1
|
||||||
|
* Repository : aur
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
Architecture : x86_64
|
||||||
|
URL : https://claude.com/download
|
||||||
|
* AUR URL : https://aur.archlinux.org/packages/claude-desktop
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Groups : None
|
||||||
|
* Keywords : None
|
||||||
|
Provides : None
|
||||||
|
Depends On : alsa-lib at-spi2-core cairo dbus expat gcc-libs glib2 glibc gtk3 hicolor-icon-theme libcap-ng libcups libdrm libnotify libseccomp libsecret libx11 libxcb libxcomposite libxdamage libxext libxfixes libxkbcommon libxrandr libxtst mesa nspr nss pango socat systemd-libs util-linux-libs virtiofsd xdg-desktop-portal xdg-utils
|
||||||
|
* Depends On : alsa-lib at-spi2-core bubblewrap cairo dbus expat gcc-libs glib2 glibc gtk3 hicolor-icon-theme libcap-ng libcups libdrm libnotify libpipewire libseccomp libsecret libx11 libxcb libxcomposite libxdamage libxext libxfixes libxkbcommon libxrandr libxtst mesa nspr nss pango socat systemd-libs util-linux-libs virtiofsd xdg-desktop-portal xdg-utils qemu-system-x86 edk2-ovmf
|
||||||
|
Optional Deps : gnome-keyring: credential storage via Secret Service (GNOME)
|
||||||
|
kwallet: credential storage (KDE Plasma) [installed]
|
||||||
|
libayatana-appindicator: system tray icon
|
||||||
|
xdg-desktop-portal-gtk: portal backend for GTK desktops
|
||||||
|
xdg-desktop-portal-kde: portal backend for KDE Plasma
|
||||||
|
* Optional Deps : gnome-keyring
|
||||||
|
* kwallet
|
||||||
|
* libayatana-appindicator
|
||||||
|
* xdg-desktop-portal-gtk
|
||||||
|
* xdg-desktop-portal-kde
|
||||||
|
* qemu-system-aarch64
|
||||||
|
* edk2-aarch64
|
||||||
|
* Make Deps : None
|
||||||
|
* Check Deps : None
|
||||||
|
Required By : None
|
||||||
|
Optional For : None
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Replaces : None
|
||||||
|
Installed Size : 117.74 MiB
|
||||||
|
Packager : Unknown Packager
|
||||||
|
* Maintainer : diazkev314
|
||||||
|
Build Date : Sat Oct 3 04:00:00 2026
|
||||||
|
* Last Modified : Fri 09 Oct 2026 11:31:19 PM UTC
|
||||||
|
* First Submitted : Sun 05 Jul 2026 01:58:02 AM UTC
|
||||||
|
Install Date : Sat Oct 10 13:49:52 2026
|
||||||
|
Install Reason : Explicitly installed
|
||||||
|
Install Script : No
|
||||||
|
Validated By : None
|
||||||
|
* Popularity : 6.458490
|
||||||
|
* Votes : 21
|
||||||
|
* Out-of-date : No
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
log_has "$AS_ALICE yay -Sia claude-desktop"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N?? claude-desktop: paru's unwrapped record merges to the same Depends On and Optional Deps lines" {
|
||||||
|
use_fakes yay pacman runuser getent
|
||||||
|
run skup show claude-desktop
|
||||||
|
yay_out=$output
|
||||||
|
use_fakes paru pacman runuser getent
|
||||||
|
run skup show claude-desktop
|
||||||
|
assert_success
|
||||||
|
[[ $(grep -A8 '^ Depends On' <<<"$output") == "$(grep -A8 '^ Depends On' <<<"$yay_out")" ]] ||
|
||||||
|
fail "paru and yay merge Depends On / Optional Deps differently"
|
||||||
|
assert_line '* Out Of Date : No'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N?? pacman lists: a wrapped, reordered Depends On and bare Optional Deps names equal to the installed sets print once" {
|
||||||
|
use_fakes yay pacman runuser getent
|
||||||
|
FAKE_AUR_SIA=same run skup show claude-desktop
|
||||||
|
assert_success
|
||||||
|
[[ $(count_lines ' Depends On : alsa-lib at-spi2-core cairo dbus expat gcc-libs glib2 glibc gtk3 hicolor-icon-theme libcap-ng libcups libdrm libnotify libseccomp libsecret libx11 libxcb libxcomposite libxdamage libxext libxfixes libxkbcommon libxrandr libxtst mesa nspr nss pango socat systemd-libs util-linux-libs virtiofsd xdg-desktop-portal xdg-utils') -eq 1 ]]
|
||||||
|
refute_line --regexp '^\* +(Depends On|Optional Deps|Conflicts With) *:'
|
||||||
|
refute_line --regexp '^\* {18,}'
|
||||||
|
assert_output --partial "$(printf '%s\n' \
|
||||||
|
' kwallet: credential storage (KDE Plasma) [installed]' \
|
||||||
|
' libayatana-appindicator: system tray icon' \
|
||||||
|
' xdg-desktop-portal-gtk: portal backend for GTK desktops' \
|
||||||
|
' xdg-desktop-portal-kde: portal backend for KDE Plasma' \
|
||||||
|
'* Make Deps : None')"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N?? pacman lists: an added token or a changed version constraint is a difference (one * line, as -Qi prints it)" {
|
||||||
|
use_fakes yay pacman runuser getent
|
||||||
|
FAKE_AUR_SIA=constraint run skup show claude-desktop
|
||||||
|
assert_success
|
||||||
|
assert_line --regexp '^\* Depends On : xdg-utils xdg-desktop-portal virtiofsd .* pango nss>=3\.100 nspr .* at-spi2-core alsa-lib$'
|
||||||
|
[[ $(grep -c '^\* Depends On' <<<"$output") -eq 1 ]]
|
||||||
|
refute_line --regexp '^\* +(Optional Deps|Conflicts With) *:'
|
||||||
|
run skup show claude-desktop
|
||||||
|
assert_line --regexp '^\* Depends On : alsa-lib at-spi2-core bubblewrap cairo .* libnotify libpipewire libseccomp .* xdg-utils qemu-system-x86 edk2-ovmf$'
|
||||||
|
# an extra upstream name in Optional Deps: the upstream block, one entry per line
|
||||||
|
assert_output --partial "$(printf '%s\n' \
|
||||||
|
'* Optional Deps : gnome-keyring' \
|
||||||
|
'* kwallet' \
|
||||||
|
'* libayatana-appindicator' \
|
||||||
|
'* xdg-desktop-portal-gtk' \
|
||||||
|
'* xdg-desktop-portal-kde' \
|
||||||
|
'* qemu-system-aarch64' \
|
||||||
|
'* edk2-aarch64')"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N?? when the AUR record does not merge: -Qi, then the AUR record with every line marked *" {
|
||||||
FAKE_AUR_SIA=twice run skup --no-refresh <<<$'1??\nq'
|
FAKE_AUR_SIA=twice run skup --no-refresh <<<$'1??\nq'
|
||||||
assert_success
|
assert_success
|
||||||
assert_line '# lines starting with > are the AUR record (paru -Sia) as it prints it'
|
assert_line '# lines starting with * are the AUR record (paru -Sia) as it prints it'
|
||||||
refute_line --partial '# lines starting with > come from the upstream candidate'
|
refute_line --partial '# lines starting with * come from the upstream candidate'
|
||||||
assert_line ' Version : 1.10.0-1'
|
assert_line ' Version : 1.10.0-1'
|
||||||
[[ $(count_lines '> Version : 1.11.0-1') -eq 2 ]]
|
[[ $(count_lines '* Version : 1.11.0-1') -eq 2 ]]
|
||||||
[[ $(count_lines '> Repository : aur') -eq 2 ]]
|
[[ $(count_lines '* Repository : aur') -eq 2 ]]
|
||||||
assert_line ' Install Reason : Explicitly installed'
|
assert_line ' Install Reason : Explicitly installed'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "show PKG for an AUR package: the same merge, the helper decided on the spot" {
|
@test "show PKG for an AUR package: the same merge, the helper decided on the spot" {
|
||||||
run skup show pfetch
|
run skup show pfetch
|
||||||
assert_success
|
assert_success
|
||||||
assert_line '> Repository : aur'
|
assert_output --partial "$(printf '%s\n' ' Version : 1.10.0-1' '* Version : 1.11.0-1' '* Repository : aur')"
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.10.0-1' '> Version : 1.11.0-1')"
|
|
||||||
export SKEPTICAL_UPDATER_EUID=1000
|
export SKEPTICAL_UPDATER_EUID=1000
|
||||||
unset SUDO_USER
|
unset SUDO_USER
|
||||||
: >"$FAKE_LOG"
|
: >"$FAKE_LOG"
|
||||||
run skup show pfetch
|
run skup show pfetch
|
||||||
assert_success
|
assert_success
|
||||||
assert_line '> Maintainer : yigits'
|
assert_line '* Maintainer : yigits'
|
||||||
log_has 'paru -Sia pfetch'
|
log_has 'paru -Sia pfetch'
|
||||||
log_lacks '^runuser'
|
log_lacks '^runuser'
|
||||||
}
|
}
|
||||||
@@ -385,7 +497,7 @@ upgrade_steps() {
|
|||||||
run skup show pfetch
|
run skup show pfetch
|
||||||
assert_success
|
assert_success
|
||||||
assert_line ' Name : pfetch'
|
assert_line ' Name : pfetch'
|
||||||
refute_line --regexp '^> '
|
refute_line --regexp '^\* '
|
||||||
[[ $(grep -c 'warning: aur:' <<<"$output") -eq 1 ]]
|
[[ $(grep -c 'warning: aur:' <<<"$output") -eq 1 ]]
|
||||||
log_lacks '^paru'
|
log_lacks '^paru'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -785,3 +785,13 @@ zypp_conf() { # a "real" zypp.conf + locks file with one user lock, in the test
|
|||||||
refute_output --partial 'skeptical-updater.'
|
refute_output --partial 'skeptical-updater.'
|
||||||
[[ ! -e $STATE/zypper-private ]]
|
[[ ! -e $STATE/zypper-private ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "pacman: dependent and dependency are simulated and purged together" {
|
||||||
|
use_fakes pacman
|
||||||
|
run skup --no-refresh <<<$'2x 1x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'Purge su-dummy-a su-dummy-b now? [y/N] y'
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b'
|
||||||
|
log_has 'pacman -Rs --print --print-format %n -- su-dummy-a su-dummy-b'
|
||||||
|
log_has 'pacman -Rns --noconfirm -- su-dummy-a su-dummy-b'
|
||||||
|
}
|
||||||
+6
-4
@@ -24,12 +24,14 @@ setup() { common_setup; }
|
|||||||
assert_line 'usage: skeptical-updater [options] [command]'
|
assert_line 'usage: skeptical-updater [options] [command]'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "--version and -V print the version" {
|
@test "--version and -v print the version" {
|
||||||
run skup --version
|
run skup --version
|
||||||
assert_success
|
assert_success
|
||||||
assert_output 'skeptical-updater 0.1.0'
|
assert_output --regexp '^skeptical-updater [0-9]+\.[0-9]+\.[0-9]+(\+(alpha|beta|rc)[.-]?[0-9]+)?$'
|
||||||
run skup -V
|
local version=$output
|
||||||
assert_output 'skeptical-updater 0.1.0'
|
run skup -v
|
||||||
|
assert_success
|
||||||
|
assert_output "$version"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "an unknown option is a usage error (exit 1)" {
|
@test "an unknown option is a usage error (exit 1)" {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Repository : aur
|
||||||
|
Name : claude-desktop
|
||||||
|
Version : 2.31226.1-1
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
URL : https://claude.com/download
|
||||||
|
AUR URL : https://aur.archlinux.org/packages/claude-desktop
|
||||||
|
Groups : None
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Provides : None
|
||||||
|
Depends On : alsa-lib at-spi2-core bubblewrap cairo dbus expat gcc-libs glib2 glibc gtk3 hicolor-icon-theme libcap-ng libcups libdrm libnotify libpipewire libseccomp libsecret libx11 libxcb libxcomposite libxdamage libxext libxfixes libxkbcommon libxrandr libxtst mesa nspr nss pango socat systemd-libs util-linux-libs virtiofsd xdg-desktop-portal xdg-utils qemu-system-x86 edk2-ovmf
|
||||||
|
Make Deps : None
|
||||||
|
Check Deps : None
|
||||||
|
Optional Deps : gnome-keyring kwallet libayatana-appindicator xdg-desktop-portal-gtk xdg-desktop-portal-kde qemu-system-aarch64 edk2-aarch64
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Maintainer : diazkev314
|
||||||
|
Votes : 21
|
||||||
|
Popularity : 6.45849
|
||||||
|
First Submitted : Sun, 5 Jul 2026 01:58:02
|
||||||
|
Last Modified : Fri, 9 Oct 2026 23:31:19
|
||||||
|
Out Of Date : No
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
Repository : aur
|
||||||
|
Name : claude-desktop
|
||||||
|
Version : 2.31226.1-1
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
URL : https://claude.com/download
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Groups : None
|
||||||
|
Provides : None
|
||||||
|
Depends On : xdg-utils xdg-desktop-portal virtiofsd
|
||||||
|
util-linux-libs systemd-libs socat pango nss>=3.100
|
||||||
|
nspr mesa libxtst libxrandr libxkbcommon
|
||||||
|
libxfixes libxext libxdamage libxcomposite
|
||||||
|
libxcb libx11 libsecret libseccomp libnotify
|
||||||
|
libdrm libcups libcap-ng hicolor-icon-theme gtk3
|
||||||
|
glibc glib2 gcc-libs expat dbus cairo
|
||||||
|
at-spi2-core alsa-lib
|
||||||
|
Optional Deps : xdg-desktop-portal-kde xdg-desktop-portal-gtk
|
||||||
|
libayatana-appindicator kwallet gnome-keyring
|
||||||
|
Make Deps : None
|
||||||
|
Check Deps : None
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Replaces : None
|
||||||
|
AUR URL : https://aur.archlinux.org/packages/claude-desktop
|
||||||
|
First Submitted : Sun 05 Jul 2026 01:58:02 AM UTC
|
||||||
|
Keywords : None
|
||||||
|
Last Modified : Fri 09 Oct 2026 11:31:19 PM UTC
|
||||||
|
Maintainer : diazkev314
|
||||||
|
Popularity : 6.458490
|
||||||
|
Votes : 21
|
||||||
|
Out-of-date : No
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
Repository : aur
|
||||||
|
Name : claude-desktop
|
||||||
|
Version : 2.31226.1-1
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
URL : https://claude.com/download
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Groups : None
|
||||||
|
Provides : None
|
||||||
|
Depends On : xdg-utils xdg-desktop-portal virtiofsd
|
||||||
|
util-linux-libs systemd-libs socat pango nss
|
||||||
|
nspr mesa libxtst libxrandr libxkbcommon
|
||||||
|
libxfixes libxext libxdamage libxcomposite
|
||||||
|
libxcb libx11 libsecret libseccomp libnotify
|
||||||
|
libdrm libcups libcap-ng hicolor-icon-theme gtk3
|
||||||
|
glibc glib2 gcc-libs expat dbus cairo
|
||||||
|
at-spi2-core alsa-lib
|
||||||
|
Optional Deps : xdg-desktop-portal-kde xdg-desktop-portal-gtk
|
||||||
|
libayatana-appindicator kwallet gnome-keyring
|
||||||
|
Make Deps : None
|
||||||
|
Check Deps : None
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Replaces : None
|
||||||
|
AUR URL : https://aur.archlinux.org/packages/claude-desktop
|
||||||
|
First Submitted : Sun 05 Jul 2026 01:58:02 AM UTC
|
||||||
|
Keywords : None
|
||||||
|
Last Modified : Fri 09 Oct 2026 11:31:19 PM UTC
|
||||||
|
Maintainer : diazkev314
|
||||||
|
Popularity : 6.458490
|
||||||
|
Votes : 21
|
||||||
|
Out-of-date : No
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
Repository : aur
|
||||||
|
Name : claude-desktop
|
||||||
|
Version : 2.31226.1-1
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
URL : https://claude.com/download
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Groups : None
|
||||||
|
Provides : None
|
||||||
|
Depends On : alsa-lib at-spi2-core bubblewrap cairo dbus
|
||||||
|
expat gcc-libs glib2 glibc gtk3
|
||||||
|
hicolor-icon-theme libcap-ng libcups libdrm
|
||||||
|
libnotify libpipewire libseccomp libsecret
|
||||||
|
libx11 libxcb libxcomposite libxdamage
|
||||||
|
libxext libxfixes libxkbcommon libxrandr
|
||||||
|
libxtst mesa nspr nss pango socat
|
||||||
|
systemd-libs util-linux-libs virtiofsd
|
||||||
|
xdg-desktop-portal xdg-utils qemu-system-x86
|
||||||
|
edk2-ovmf
|
||||||
|
Optional Deps : gnome-keyring kwallet libayatana-appindicator
|
||||||
|
xdg-desktop-portal-gtk xdg-desktop-portal-kde
|
||||||
|
qemu-system-aarch64 edk2-aarch64
|
||||||
|
Make Deps : None
|
||||||
|
Check Deps : None
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Replaces : None
|
||||||
|
AUR URL : https://aur.archlinux.org/packages/claude-desktop
|
||||||
|
First Submitted : Sun 05 Jul 2026 01:58:02 AM UTC
|
||||||
|
Keywords : None
|
||||||
|
Last Modified : Fri 09 Oct 2026 11:31:19 PM UTC
|
||||||
|
Maintainer : diazkev314
|
||||||
|
Popularity : 6.458490
|
||||||
|
Votes : 21
|
||||||
|
Out-of-date : No
|
||||||
|
|
||||||
@@ -332,3 +332,29 @@ Install Date : Fri Oct 9 08:00:00 2026
|
|||||||
Install Reason : Explicitly installed
|
Install Reason : Explicitly installed
|
||||||
Install Script : No
|
Install Script : No
|
||||||
Validated By : None
|
Validated By : None
|
||||||
|
|
||||||
|
Name : claude-desktop
|
||||||
|
Version : 2.9939.4-1
|
||||||
|
Description : Official Claude AI desktop app from Anthropic — Chat, Cowork, and Claude Code
|
||||||
|
Architecture : x86_64
|
||||||
|
URL : https://claude.com/download
|
||||||
|
Licenses : LicenseRef-Proprietary
|
||||||
|
Groups : None
|
||||||
|
Provides : None
|
||||||
|
Depends On : alsa-lib at-spi2-core cairo dbus expat gcc-libs glib2 glibc gtk3 hicolor-icon-theme libcap-ng libcups libdrm libnotify libseccomp libsecret libx11 libxcb libxcomposite libxdamage libxext libxfixes libxkbcommon libxrandr libxtst mesa nspr nss pango socat systemd-libs util-linux-libs virtiofsd xdg-desktop-portal xdg-utils
|
||||||
|
Optional Deps : gnome-keyring: credential storage via Secret Service (GNOME)
|
||||||
|
kwallet: credential storage (KDE Plasma) [installed]
|
||||||
|
libayatana-appindicator: system tray icon
|
||||||
|
xdg-desktop-portal-gtk: portal backend for GTK desktops
|
||||||
|
xdg-desktop-portal-kde: portal backend for KDE Plasma
|
||||||
|
Required By : None
|
||||||
|
Optional For : None
|
||||||
|
Conflicts With : claude claude-desktop-bin
|
||||||
|
Replaces : None
|
||||||
|
Installed Size : 117.74 MiB
|
||||||
|
Packager : Unknown Packager
|
||||||
|
Build Date : Sat Oct 3 04:00:00 2026
|
||||||
|
Install Date : Sat Oct 10 13:49:52 2026
|
||||||
|
Install Reason : Explicitly installed
|
||||||
|
Install Script : No
|
||||||
|
Validated By : None
|
||||||
@@ -137,21 +137,20 @@ case $op in
|
|||||||
-Rs)
|
-Rs)
|
||||||
((print)) || exit 98
|
((print)) || exit 98
|
||||||
tg=${targets[0]}
|
tg=${targets[0]}
|
||||||
if [[ -n ${FAKE_PACMAN_RS_REFUSE:-} || $tg == su-dummy-b ]]; then
|
if [[ -n ${FAKE_PACMAN_RS_REFUSE:-} || " ${targets[*]} " == *' su-dummy-b '* && " ${targets[*]} " != *' su-dummy-a '* ]]; then
|
||||||
echo "checking dependencies..."
|
echo "checking dependencies..."
|
||||||
echo ":: removing $tg breaks dependency '$tg' required by su-dummy-a"
|
echo ":: removing $tg breaks dependency '$tg' required by su-dummy-a"
|
||||||
echo "error: failed to prepare transaction (could not satisfy dependencies)" >&2
|
echo "error: failed to prepare transaction (could not satisfy dependencies)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
for tg in "${targets[@]}"; do
|
||||||
case $tg in
|
case $tg in
|
||||||
su-dummy-a) printf '%s\n' su-dummy-a su-dummy-b ;; # b was installed as a dependency of a
|
su-dummy-a) printf '%s\n' su-dummy-a su-dummy-b ;;
|
||||||
su-dummy-c | glib2 | expat | ca-certificates-mozilla | pfetch | su-dummy-aur) echo "$tg" ;; # (the last two: foreign, AUR)
|
su-dummy-b | su-dummy-c | glib2 | expat | ca-certificates-mozilla | pfetch | su-dummy-aur) echo "$tg" ;;
|
||||||
*)
|
*) echo "error: target not found: $tg" >&2; exit 1 ;;
|
||||||
echo "error: target not found: $tg" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
for r in ${FAKE_PACMAN_RS_EXTRA:-}; do [[ ${r%%:*} == "$tg" ]] && echo "${r#*:}"; done
|
for r in ${FAKE_PACMAN_RS_EXTRA:-}; do [[ ${r%%:*} == "$tg" ]] && echo "${r#*:}"; done
|
||||||
|
done
|
||||||
;;
|
;;
|
||||||
-Rns)
|
-Rns)
|
||||||
rc=$(fake_rc FAKE_PACMAN_RNS_RC 0)
|
rc=$(fake_rc FAKE_PACMAN_RNS_RC 0)
|
||||||
|
|||||||
@@ -11,8 +11,9 @@
|
|||||||
# noise (yay's colored root warning on stdout), none (nothing to upgrade: exit 1, no output) or
|
# noise (yay's colored root warning on stdout), none (nothing to upgrade: exit 1, no output) or
|
||||||
# fail (the AUR is unreachable: exit 1 with the recorded error). Packages purged by the fake pacman
|
# fail (the AUR is unreachable: exit 1 with the recorded error). Packages purged by the fake pacman
|
||||||
# are not listed. -Sia PKG prints data/aur/Sia-<helper>-PKG.txt (else the helper's not-found
|
# are not listed. -Sia PKG prints data/aur/Sia-<helper>-PKG.txt (else the helper's not-found
|
||||||
# error, exit 1), twice with FAKE_AUR_SIA=twice (a record that cannot be merged); -Sua exits
|
# error, exit 1), twice with FAKE_AUR_SIA=twice (a record that cannot be merged), or the variant
|
||||||
# FAKE_AUR_SUA_RC (default 0).
|
# Sia-<helper>-PKG-<FAKE_AUR_SIA>.txt when it exists; -Sua exits FAKE_AUR_SUA_RC (default 0).
|
||||||
|
# claude-desktop: yay's record is the wrapped one yay prints without COLUMNS=0, recorded verbatim.
|
||||||
# shellcheck source=../fakelib.bash
|
# shellcheck source=../fakelib.bash
|
||||||
. "${BASH_SOURCE[0]%/*}/../fakelib.bash"
|
. "${BASH_SOURCE[0]%/*}/../fakelib.bash"
|
||||||
fake_log "$@"
|
fake_log "$@"
|
||||||
@@ -38,6 +39,10 @@ case ${1:-} in
|
|||||||
printf '%s\n' "$out"
|
printf '%s\n' "$out"
|
||||||
;;
|
;;
|
||||||
-Sia)
|
-Sia)
|
||||||
|
if [[ -n ${FAKE_AUR_SIA:-} && -f $D/Sia-$FAKE_NAME-${2:-}-$FAKE_AUR_SIA.txt ]]; then
|
||||||
|
cat "$D/Sia-$FAKE_NAME-$2-$FAKE_AUR_SIA.txt"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
if [[ -f $D/Sia-$FAKE_NAME-${2:-}.txt ]]; then
|
if [[ -f $D/Sia-$FAKE_NAME-${2:-}.txt ]]; then
|
||||||
cat "$D/Sia-$FAKE_NAME-$2.txt"
|
cat "$D/Sia-$FAKE_NAME-$2.txt"
|
||||||
[[ ${FAKE_AUR_SIA:-} != twice ]] || cat "$D/Sia-$FAKE_NAME-$2.txt"
|
[[ ${FAKE_AUR_SIA:-} != twice ]] || cat "$D/Sia-$FAKE_NAME-$2.txt"
|
||||||
|
|||||||
+233
-6
@@ -93,15 +93,62 @@ UPGRADE='apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--forc
|
|||||||
@test "N?? prints the installed record merged with the candidate" {
|
@test "N?? prints the installed record merged with the candidate" {
|
||||||
run skup --no-refresh <<<$'1??\nq'
|
run skup --no-refresh <<<$'1??\nq'
|
||||||
assert_success
|
assert_success
|
||||||
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
assert_line '# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks'
|
||||||
assert_line ' Package: su-dummy-a'
|
assert_line ' Package: su-dummy-a'
|
||||||
assert_line 'Version: 1.0'
|
assert_output --partial "$(printf '%s\n' ' Version: 1.0' '* Version: 2.0')"
|
||||||
assert_line '> Version: 2.0'
|
assert_line '* Depends: su-dummy-b (>= 2.0)'
|
||||||
assert_line '> Depends: su-dummy-b (>= 2.0)'
|
|
||||||
log_has 'dpkg-query -s -- su-dummy-a'
|
log_has 'dpkg-query -s -- su-dummy-a'
|
||||||
log_has 'apt-cache show --no-all-versions su-dummy-a'
|
log_has 'apt-cache show --no-all-versions su-dummy-a'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "listed package names support both information commands alongside numeric commands" {
|
||||||
|
run skup --no-refresh <<<$'su-dummy-a? 2? su-dummy-b?? 3-\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'su-dummy-a: dummy package su-dummy-a for skeptical-updater tests'
|
||||||
|
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
||||||
|
assert_line ' Package: su-dummy-b'
|
||||||
|
assert_line 'excluded from this run: su-dummy-c'
|
||||||
|
log_has 'dpkg-query -s -- su-dummy-b'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "unknown or hidden package names report an error and do not stop later commands" {
|
||||||
|
write_state "$HEADER" "apt${T}su-dummy-a${T}user${T}2026-01-01T00:00:00Z"
|
||||||
|
run skup --no-refresh <<<$'missing? su-dummy-a?? 2?\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "no package 'missing' in the list"
|
||||||
|
assert_output --partial "no package 'su-dummy-a' in the list"
|
||||||
|
assert_line 'su-dummy-c: dummy package su-dummy-c for skeptical-updater tests'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "names work for trusted rows shown with --all and new dependencies" {
|
||||||
|
write_state "$HEADER" "apt${T}su-dummy-a${T}user${T}2026-01-01T00:00:00Z"
|
||||||
|
run skup --no-refresh --all <<<$'su-dummy-a?\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'su-dummy-a: dummy package su-dummy-a for skeptical-updater tests'
|
||||||
|
FAKE_APT_SIM=real run skup --no-refresh <<<$'su-dummy-newdep? su-dummy-newdep??\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'reason: not installed'
|
||||||
|
log_lacks '^dpkg-query -s -- su-dummy-newdep'
|
||||||
|
log_has 'apt-cache show --no-all-versions su-dummy-newdep'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "a package removed during a line cannot be queried by name" {
|
||||||
|
run skup --no-refresh <<<$'3x su-dummy-c? 2?\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "no package 'su-dummy-c' in the list"
|
||||||
|
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "package names are not accepted for trust, exclude or purge" {
|
||||||
|
for token in su-dummy-a+ su-dummy-a- su-dummy-ax; do
|
||||||
|
run skup --no-refresh <<<"$token"$'\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "unknown command '$token'"
|
||||||
|
[[ ! -e $STATE_FILE ]]
|
||||||
|
log_lacks '^apt-get -y purge'
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
@test "N?? on a new dependency (old version -) never looks for an installed record" {
|
@test "N?? on a new dependency (old version -) never looks for an installed record" {
|
||||||
FAKE_APT_SIM=real run skup --no-refresh <<<$'9??\nq'
|
FAKE_APT_SIM=real run skup --no-refresh <<<$'9??\nq'
|
||||||
assert_success
|
assert_success
|
||||||
@@ -293,11 +340,49 @@ UPGRADE='apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--forc
|
|||||||
run skup --no-refresh <<<$'*+\nl\nq'
|
run skup --no-refresh <<<$'*+\nl\nq'
|
||||||
assert_success
|
assert_success
|
||||||
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
||||||
assert_line 'trusted su-dummy-b'
|
|
||||||
assert_line 'trusted su-dummy-c'
|
assert_line 'trusted su-dummy-c'
|
||||||
assert_line '3 upgradable, 3 trusted (hidden, use --all to show), 0 to review:'
|
assert_line '3 upgradable, 3 trusted (hidden, use --all to show), 0 to review:'
|
||||||
run cut -f2,3 "$STATE_FILE"
|
run cut -f2,3 "$STATE_FILE"
|
||||||
assert_line "su-dummy-b${T}user"
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "consecutive trust commands keep dependencies under their selected root in either order" {
|
||||||
|
for line in '1+ 2+ 3+' '2+ 3+ 1+'; do
|
||||||
|
rm -rf "$STATE"
|
||||||
|
run skup --no-refresh <<<"$line"$'\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
||||||
|
assert_line 'trusted su-dummy-c'
|
||||||
|
refute_output --partial 'no package ['
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
assert_line "su-dummy-c${T}user"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "invalid numbers do not stop other commands on the line" {
|
||||||
|
run skup --no-refresh <<<$'9+ 2- 0? 3+\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'no package [9] in the list'
|
||||||
|
assert_output --partial 'no package [0] in the list'
|
||||||
|
assert_line 'excluded from this run: su-dummy-b'
|
||||||
|
assert_line 'trusted su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "a package removed by a purge does not stop later commands" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'1x 2? 3-\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'no package [2] in the list'
|
||||||
|
assert_line 'excluded from this run: su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "trusting a dependency and its root with --all keeps the dependency implicit" {
|
||||||
|
run skup --no-refresh --all <<<$'2+ 1+\nq'
|
||||||
|
assert_success
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "*- excludes every listed package; *- again re-includes them" {
|
@test "*- excludes every listed package; *- again re-includes them" {
|
||||||
@@ -372,3 +457,145 @@ UPGRADE='apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--forc
|
|||||||
assert_line ' [3] su-dummy-c 1.0 -> 2.0 file:/srv/su-repo ./ [held]'
|
assert_line ' [3] su-dummy-c 1.0 -> 2.0 file:/srv/su-repo ./ [held]'
|
||||||
assert_line 'su-dummy-c: dummy package su-dummy-c for skeptical-updater tests'
|
assert_line 'su-dummy-c: dummy package su-dummy-c for skeptical-updater tests'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "Nx: consecutive purges use one transaction including orphans" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'1x 3x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'Purge su-dummy-a su-dummy-c now? This also removes: su-dummy-b [y/N] y'
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b su-dummy-c'
|
||||||
|
assert_line 'Nothing left to upgrade.'
|
||||||
|
log_has 'apt-get -y purge su-dummy-a su-dummy-b su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: other commands flush the batch before resolving removed rows" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'1x 2? 3x\ny\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b'
|
||||||
|
assert_output --partial 'no package [2] in the list'
|
||||||
|
assert_line 'Purge su-dummy-c now? [y/N] y'
|
||||||
|
assert_line 'purged: su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: a trust command cannot act on a removed row" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'1x 2+\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'no package [2] in the list'
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: duplicate targets are purged once" {
|
||||||
|
run skup --no-refresh <<<$'3x 3x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'Purge su-dummy-c now? [y/N] y'
|
||||||
|
assert_line 'purged: su-dummy-c'
|
||||||
|
log_has 'apt-get -y purge su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: a refused target does not prevent other purges" {
|
||||||
|
run skup --no-refresh <<<$'2x 3x\ny\nl\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first'
|
||||||
|
assert_line 'purged: su-dummy-c'
|
||||||
|
log_has 'apt-get -y purge su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: invalid numbers do not interrupt a batch" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'1x 9x 3x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'no package [9] in the list'
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b su-dummy-c'
|
||||||
|
log_has 'apt-get -y purge su-dummy-a su-dummy-b su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: rejecting the prompt purges nothing" {
|
||||||
|
run skup --no-refresh <<<$'1x 3x\nn\nl\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'not purged: su-dummy-a su-dummy-c'
|
||||||
|
assert_line '3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:'
|
||||||
|
log_lacks '^apt-get -y purge'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: failed transaction keeps all rows" {
|
||||||
|
FAKE_APT_PURGE_RC=100 run skup --no-refresh <<<$'1x 3x\nyes\nl\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'purge of su-dummy-a su-dummy-c failed (apt exited 100); the rows stay in the list'
|
||||||
|
assert_line '3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: a dependent and dependency are planned together" {
|
||||||
|
FAKE_APT_AUTO_ORPHANS=su-dummy-a:su-dummy-b run skup --no-refresh <<<$'2x 1x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'Purge su-dummy-a su-dummy-b now? [y/N] y'
|
||||||
|
assert_line 'purged: su-dummy-a su-dummy-b'
|
||||||
|
log_has 'apt-get -y purge su-dummy-a su-dummy-b'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Nx: unexpected removals never leak into another target's purge" {
|
||||||
|
FAKE_APT_SIM_EXTRA=su-dummy-a:su-dummy-c run skup --no-refresh <<<$'1x 2x\ny\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'would also remove su-dummy-c'
|
||||||
|
log_lacks '^apt-get -y purge'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "a shows session trusted rows without exposing previously trusted rows" {
|
||||||
|
write_state "$HEADER" "apt${T}su-dummy-c${T}user${T}2026-01-01T00:00:00Z"
|
||||||
|
run skup --no-refresh <<<$'1+\na\n2?\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line '=[1] su-dummy-a 1.0 -> 2.0 su-fixture:su-repo'
|
||||||
|
assert_line '=[2] su-dummy-b 1.0 -> 2.0 su-fixture:su-repo'
|
||||||
|
refute_output --partial '=[3] su-dummy-c'
|
||||||
|
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "a works on the same line as trust and keeps removed rows hidden" {
|
||||||
|
run skup --no-refresh <<<$'3x\ny\n1+ a 2?\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'purged: su-dummy-c'
|
||||||
|
assert_line '=[1] su-dummy-a 1.0 -> 2.0 su-fixture:su-repo'
|
||||||
|
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
||||||
|
refute_output --partial '=[3] su-dummy-c'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts the topmost installed dependent and its dependencies" {
|
||||||
|
run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts all topmost branches including packages outside the list" {
|
||||||
|
local fixture_data="$BATS_TEST_TMPDIR/data"
|
||||||
|
cp -R "$FAKE_DATA" "$fixture_data"
|
||||||
|
printf 'su-dummy-b\nReverse Depends:\n su-dummy-a\n su-dummy-c\n' >"$fixture_data/apt/rdepends/su-dummy-b"
|
||||||
|
printf 'su-dummy-a\nReverse Depends:\n su-dummy-w\n' >"$fixture_data/apt/rdepends/su-dummy-a"
|
||||||
|
sed -i 's/su-virtual | su-dummy-alt/su-dummy-a/; s/^ii \(.*su-dummy-c\)\t\t\t\t/ii \1\t\tsu-dummy-b\t/' "$fixture_data/apt/dpkg-status.tsv"
|
||||||
|
FAKE_DATA="$fixture_data" run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'trusted su-dummy-c'
|
||||||
|
assert_output --partial 'trusted su-dummy-w'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-c${T}user"
|
||||||
|
assert_line "su-dummy-w${T}user"
|
||||||
|
assert_line "su-dummy-a${T}dep:su-dummy-w"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ terminates on a dependency cycle and chooses one root" {
|
||||||
|
local fixture_data="$BATS_TEST_TMPDIR/data"
|
||||||
|
cp -R "$FAKE_DATA" "$fixture_data"
|
||||||
|
printf 'su-dummy-a\nReverse Depends:\n su-dummy-b\n' >"$fixture_data/apt/rdepends/su-dummy-a"
|
||||||
|
sed -i 's/^ii \(.*su-dummy-b\)\t\t\t\t/ii \1\t\tsu-dummy-a\t/' "$fixture_data/apt/dpkg-status.tsv"
|
||||||
|
FAKE_DATA="$fixture_data" run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'trusted su-dummy-a'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts the package itself when it has no installed dependents" {
|
||||||
|
run skup --no-refresh <<<$'3++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'trusted su-dummy-c'
|
||||||
|
}
|
||||||
+63
-63
@@ -117,7 +117,7 @@ setup() { common_setup; }
|
|||||||
run skup show su-dummy-b
|
run skup show su-dummy-b
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$(cat <<'EOF'
|
assert_output "$(cat <<'EOF'
|
||||||
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
|
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
|
||||||
Package: su-dummy-b
|
Package: su-dummy-b
|
||||||
Status: install ok installed
|
Status: install ok installed
|
||||||
Priority: optional
|
Priority: optional
|
||||||
@@ -125,28 +125,27 @@ Section: misc
|
|||||||
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
|
Maintainer: Skeptical Updater Fixture <su-fixture@example.invalid>
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Version: 1.0
|
Version: 1.0
|
||||||
> Version: 2.0
|
* Version: 2.0
|
||||||
Conffiles:
|
Conffiles:
|
||||||
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
|
/etc/su-dummy/su-dummy-b.conf 607e2d3a119dfe832d937ce579ef1079
|
||||||
Description: dummy package su-dummy-b for skeptical-updater tests
|
Description: dummy package su-dummy-b for skeptical-updater tests
|
||||||
This package only exists to exercise the package manager.
|
This package only exists to exercise the package manager.
|
||||||
.
|
.
|
||||||
It ships one data file and one conffile (version 1.0).
|
It ships one data file and one conffile (version 1.0).
|
||||||
> Description: dummy package su-dummy-b for skeptical-updater tests
|
* Description: dummy package su-dummy-b for skeptical-updater tests
|
||||||
> This package only exists to exercise the package manager.
|
* This package only exists to exercise the package manager.
|
||||||
> .
|
* .
|
||||||
> It ships one data file and one conffile (version 2.0).
|
* It ships one data file and one conffile (version 2.0).
|
||||||
> Description-md5: 36da7dcdaf4ec207be2937d1f5dfa408
|
* Description-md5: 36da7dcdaf4ec207be2937d1f5dfa408
|
||||||
> Filename: ./su-dummy-b_2.0_all.deb
|
* Filename: ./su-dummy-b_2.0_all.deb
|
||||||
> Size: 840
|
* Size: 840
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
log_has 'dpkg-query -s -- su-dummy-b'
|
log_has 'dpkg-query -s -- su-dummy-b'
|
||||||
log_has 'apt-cache show --no-all-versions su-dummy-b'
|
log_has 'apt-cache show --no-all-versions su-dummy-b'
|
||||||
run skup show su-dummy-a
|
run skup show su-dummy-a
|
||||||
assert_success
|
assert_success
|
||||||
assert_line 'Depends: su-dummy-b'
|
assert_output --partial "$(printf '%s\n' ' Depends: su-dummy-b' '* Depends: su-dummy-b (>= 2.0)')"
|
||||||
assert_line '> Depends: su-dummy-b (>= 2.0)'
|
|
||||||
run skup show no-such-pkg-xyz
|
run skup show no-such-pkg-xyz
|
||||||
assert_failure 1
|
assert_failure 1
|
||||||
assert_output --partial "no package information for 'no-such-pkg-xyz' (apt exited 100)"
|
assert_output --partial "no package information for 'no-such-pkg-xyz' (apt exited 100)"
|
||||||
@@ -157,21 +156,21 @@ EOF
|
|||||||
run skup show perl-base
|
run skup show perl-base
|
||||||
assert_success
|
assert_success
|
||||||
[[ $(grep -c '^ Description: minimal Perl system$' <<<"$output") -eq 1 ]]
|
[[ $(grep -c '^ Description: minimal Perl system$' <<<"$output") -eq 1 ]]
|
||||||
refute_line --partial '> Description:'
|
refute_line --partial '* Description:'
|
||||||
assert_output --partial "$(printf '%s\n' 'Installed-Size: 7639' '> Installed-Size: 7643')"
|
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')"
|
assert_output --partial "$(printf '%s\n' ' Version: 5.36.0-7+deb12u3' '* Version: 5.36.0-7+deb12u4')"
|
||||||
[[ $(grep -c '^ Breaks: ' <<<"$output") -eq 1 ]]
|
[[ $(grep -c '^ Breaks: ' <<<"$output") -eq 1 ]]
|
||||||
refute_line --regexp '^> (Breaks|Pre-Depends|Essential|Source):'
|
refute_line --regexp '^\* (Breaks|Pre-Depends|Essential|Source):'
|
||||||
assert_line --index -1 '> SHA256: d7d1943aec9597629bf73075efcc5ef6dc9bda96d78e80d843156ecd448478b8'
|
assert_line --index -1 '* SHA256: d7d1943aec9597629bf73075efcc5ef6dc9bda96d78e80d843156ecd448478b8'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "apt: show of a package that is not installed prints the candidate alone, with a note" {
|
@test "apt: show of a package that is not installed prints the candidate alone, with a note" {
|
||||||
run skup show zsh
|
run skup show zsh
|
||||||
assert_success
|
assert_success
|
||||||
assert_line --index 0 '# not installed: this is the upstream candidate'
|
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 1 '* Package: zsh'
|
||||||
assert_line --index 3 'Version: 5.9-4+b15'
|
assert_line --index 3 '* Version: 5.9-4+b15'
|
||||||
refute_line --partial '> '
|
refute_line --regexp '^ '
|
||||||
log_has 'dpkg-query -s -- zsh'
|
log_has 'dpkg-query -s -- zsh'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,18 +271,20 @@ EOF
|
|||||||
assert_output 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
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
|
# 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
|
# 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
|
use_fakes pacman
|
||||||
run skup show glib2
|
run skup show glib2
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$(cat <<'EOF'
|
assert_output "$(cat <<'EOF'
|
||||||
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
|
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
|
||||||
Name : glib2
|
Name : glib2
|
||||||
Version : 2.88.3-1
|
Version : 2.88.3-1
|
||||||
> Version : 2.90.1-1
|
* Version : 2.90.1-1
|
||||||
|
* Repository : core
|
||||||
Description : Low level core library
|
Description : Low level core library
|
||||||
Architecture : x86_64
|
Architecture : x86_64
|
||||||
URL : https://gitlab.gnome.org/GNOME/glib
|
URL : https://gitlab.gnome.org/GNOME/glib
|
||||||
@@ -294,26 +295,25 @@ Depends On : bash glibc libffi libsysprof-capture pcre2 util-linux-lib
|
|||||||
Optional Deps : dconf: GSettings storage backend
|
Optional Deps : dconf: GSettings storage backend
|
||||||
glib2-devel: development tools
|
glib2-devel: development tools
|
||||||
gvfs: most gio functionality
|
gvfs: most gio functionality
|
||||||
> Optional Deps : dconf: GSettings storage backend
|
* Optional Deps : dconf: GSettings storage backend
|
||||||
> glib2-devel: development tools
|
* glib2-devel: development tools
|
||||||
> gvfs: most gio functionality
|
* gvfs: most gio functionality
|
||||||
> python: gdbus-codegen
|
* python: gdbus-codegen
|
||||||
Required By : libsecret pinentry
|
Required By : libsecret pinentry
|
||||||
Optional For : None
|
Optional For : None
|
||||||
Conflicts With : None
|
Conflicts With : None
|
||||||
Replaces : None
|
Replaces : None
|
||||||
Installed Size : 37.89 MiB
|
Installed Size : 37.89 MiB
|
||||||
> Installed Size : 38.39 MiB
|
* Installed Size : 38.39 MiB
|
||||||
|
* Download Size : 5.12 MiB
|
||||||
Packager : Jan Alexander Steffens (heftig) <heftig@archlinux.org>
|
Packager : Jan Alexander Steffens (heftig) <heftig@archlinux.org>
|
||||||
Build Date : Wed Jul 29 14:57:16 2026
|
Build Date : Wed Jul 29 14:57:16 2026
|
||||||
> Build Date : Tue Oct 6 16:19:12 2026
|
* Build Date : Tue Oct 6 16:19:12 2026
|
||||||
Install Date : Sun Oct 4 00:00:00 2026
|
Install Date : Sun Oct 4 00:00:00 2026
|
||||||
Install Reason : Installed as a dependency for another package
|
Install Reason : Installed as a dependency for another package
|
||||||
Install Script : No
|
Install Script : No
|
||||||
Validated By : Signature
|
Validated By : Signature
|
||||||
> Validated By : SHA-256 Sum Signature
|
* Validated By : SHA-256 Sum Signature
|
||||||
> Repository : core
|
|
||||||
> Download Size : 5.12 MiB
|
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
log_has 'pacman -Qi -- glib2'
|
log_has 'pacman -Qi -- glib2'
|
||||||
@@ -324,7 +324,7 @@ EOF
|
|||||||
use_fakes pacman
|
use_fakes pacman
|
||||||
run skup show su-dummy-b
|
run skup show su-dummy-b
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
|
assert_output --partial "$(printf '%s\n' ' Version : 1.0-1' '* Version : 2.0-1')"
|
||||||
assert_line ' Required By : su-dummy-a'
|
assert_line ' Required By : su-dummy-a'
|
||||||
refute_output --partial '3.0-1'
|
refute_output --partial '3.0-1'
|
||||||
log_has 'pacman -Si -- su-dummy/su-dummy-b'
|
log_has 'pacman -Si -- su-dummy/su-dummy-b'
|
||||||
@@ -332,13 +332,13 @@ EOF
|
|||||||
run skup show bash
|
run skup show bash
|
||||||
assert_success
|
assert_success
|
||||||
assert_line --index 0 ' Name : bash'
|
assert_line --index 0 ' Name : bash'
|
||||||
refute_line --partial '# lines starting with >'
|
refute_line --partial '# lines starting with *'
|
||||||
# not installed: the candidate alone
|
# not installed: the candidate alone
|
||||||
run skup show su-dummy-new
|
run skup show su-dummy-new
|
||||||
assert_success
|
assert_success
|
||||||
assert_line --index 0 '# not installed: this is the upstream candidate'
|
assert_line --index 0 '# not installed: lines starting with * come from the upstream candidate (all of them)'
|
||||||
assert_line --index 1 'Repository : su-dummy'
|
assert_line --index 1 '* Repository : su-dummy'
|
||||||
refute_line --partial '> '
|
refute_line --regexp '^ '
|
||||||
run skup show nope
|
run skup show nope
|
||||||
assert_failure 1
|
assert_failure 1
|
||||||
}
|
}
|
||||||
@@ -508,27 +508,27 @@ EOF
|
|||||||
run skup show su-dummy-b
|
run skup show su-dummy-b
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$(cat <<'EOF'
|
assert_output "$(cat <<'EOF'
|
||||||
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
|
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
|
||||||
Name : su-dummy-b
|
Name : su-dummy-b
|
||||||
Version : 1.0
|
Version : 1.0
|
||||||
> Version : 2.0
|
* Version : 2.0
|
||||||
Release : 1
|
Release : 1
|
||||||
Architecture : noarch
|
Architecture : noarch
|
||||||
Size : 15
|
Size : 15
|
||||||
> Size : 6.5 k
|
* Size : 6.5 k
|
||||||
Source : su-dummy-b-1.0-1.src.rpm
|
Source : su-dummy-b-1.0-1.src.rpm
|
||||||
> Source : su-dummy-b-2.0-1.src.rpm
|
* Source : su-dummy-b-2.0-1.src.rpm
|
||||||
Repository : @System
|
Repository : @System
|
||||||
> Repository : su-dummy
|
* Repository : su-dummy
|
||||||
Summary : skeptical-updater dummy su-dummy-b (v1.0)
|
Summary : skeptical-updater dummy su-dummy-b (v1.0)
|
||||||
> Summary : skeptical-updater dummy su-dummy-b (v2.0)
|
* Summary : skeptical-updater dummy su-dummy-b (v2.0)
|
||||||
License : MIT
|
License : MIT
|
||||||
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
|
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).
|
: 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.
|
* 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).
|
* : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
log_has 'dnf -q info --installed su-dummy-b'
|
log_has 'dnf -q info --installed su-dummy-b'
|
||||||
@@ -536,7 +536,7 @@ EOF
|
|||||||
# real almalinux:9 records: an identical multi-line Description once, "From repo" (installed only) kept
|
# real almalinux:9 records: an identical multi-line Description once, "From repo" (installed only) kept
|
||||||
run skup show glibc
|
run skup show glibc
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --partial "$(printf '%s\n' 'Release : 275.el9_8' '> Release : 283.el9_8')"
|
assert_output --partial "$(printf '%s\n' ' Release : 275.el9_8' '* Release : 283.el9_8')"
|
||||||
assert_line ' From repo : baseos'
|
assert_line ' From repo : baseos'
|
||||||
[[ $(grep -c '^ Description : The glibc package contains' <<<"$output") -eq 1 ]]
|
[[ $(grep -c '^ Description : The glibc package contains' <<<"$output") -eq 1 ]]
|
||||||
[[ $(grep -c 'Linux system will not function\.$' <<<"$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
|
FAKE_DNF_MAJOR=5 run skup show su-dummy-b
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$(cat <<'EOF'
|
assert_output "$(cat <<'EOF'
|
||||||
# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks
|
# lines starting with * come from the upstream candidate: a differing value, or a field the installed record lacks
|
||||||
Name : su-dummy-b
|
Name : su-dummy-b
|
||||||
Epoch : 0
|
Epoch : 0
|
||||||
Version : 1.0
|
Version : 1.0
|
||||||
> Version : 2.0
|
* Version : 2.0
|
||||||
Release : 1
|
Release : 1
|
||||||
Architecture : noarch
|
Architecture : noarch
|
||||||
Installed size : 15.0 B
|
Installed size : 15.0 B
|
||||||
Source : su-dummy-b-1.0-1.src.rpm
|
Source : su-dummy-b-1.0-1.src.rpm
|
||||||
> Source : su-dummy-b-2.0-1.src.rpm
|
* Source : su-dummy-b-2.0-1.src.rpm
|
||||||
From repository : <unknown>
|
From repository : <unknown>
|
||||||
Summary : skeptical-updater dummy su-dummy-b (v1.0)
|
Summary : skeptical-updater dummy su-dummy-b (v1.0)
|
||||||
> Summary : skeptical-updater dummy su-dummy-b (v2.0)
|
* Summary : skeptical-updater dummy su-dummy-b (v2.0)
|
||||||
URL :
|
URL :
|
||||||
License : MIT
|
License : MIT
|
||||||
Description : Dummy package su-dummy-b version 1.0 for skeptical-updater tests.
|
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).
|
: 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.
|
* 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).
|
* : Second paragraph of su-dummy-b 2.0 (blank line above on purpose).
|
||||||
Vendor : <NULL>
|
Vendor : <NULL>
|
||||||
> Vendor :
|
* Vendor :
|
||||||
> Download size : 6.6 KiB
|
* Download size : 6.6 KiB
|
||||||
> Repository : su-dummy
|
* Repository : su-dummy
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
@@ -580,14 +580,14 @@ EOF
|
|||||||
use_fakes dnf rpm
|
use_fakes dnf rpm
|
||||||
run skup show zsh
|
run skup show zsh
|
||||||
assert_success
|
assert_success
|
||||||
assert_line --index 0 '# not installed: this is the upstream candidate'
|
assert_line --index 0 '# not installed: lines starting with * come from the upstream candidate (all of them)'
|
||||||
assert_line --index 1 'Name : zsh'
|
assert_line --index 1 '* Name : zsh'
|
||||||
refute_line 'Available Packages'
|
refute_line --partial 'Available Packages'
|
||||||
log_has 'dnf -q info --available zsh'
|
log_has 'dnf -q info --available zsh'
|
||||||
# two installed records (e.g. two architectures): nothing to pair, the output stays dnf -q info
|
# 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
|
FAKE_DNF_INFO_TWICE=installed run skup show su-dummy-a
|
||||||
assert_success
|
assert_success
|
||||||
refute_line --partial '# lines starting with >'
|
refute_line --partial '# lines starting with *'
|
||||||
assert_line ' Installed Packages'
|
assert_line ' Installed Packages'
|
||||||
assert_line ' Available Upgrades'
|
assert_line ' Available Upgrades'
|
||||||
log_has 'dnf -q info su-dummy-a'
|
log_has 'dnf -q info su-dummy-a'
|
||||||
@@ -674,7 +674,7 @@ EOF
|
|||||||
run skup show su-dummy-a
|
run skup show su-dummy-a
|
||||||
assert_success
|
assert_success
|
||||||
assert_line ' Information for package su-dummy-a:'
|
assert_line ' Information for package su-dummy-a:'
|
||||||
refute_line --partial '# lines starting with >'
|
refute_line --partial '# lines starting with *'
|
||||||
log_has 'zypper --non-interactive --quiet info --requires su-dummy-a'
|
log_has 'zypper --non-interactive --quiet info --requires su-dummy-a'
|
||||||
run skup show nothing-like-this
|
run skup show nothing-like-this
|
||||||
assert_failure 1
|
assert_failure 1
|
||||||
|
|||||||
Reference in new issue
Block a user