feat(aur): list and upgrade AUR packages through paru or yay on Arch
On the pacman backend, an installed AUR helper (paru, else yay;
--aur-helper=paru|yay|none, --no-aur) adds the AUR updates to the review
list. The helper never runs as root: when the tool is root through sudo it
runs as SUDO_USER (runuser -u, else sudo -u, with that user's HOME, from
that home); unprivileged it runs as is; a root login gets no AUR, with a
warning. The banner names the helper ("+ AUR via paru").
- listing: <helper> -Qua (also with --no-refresh), rows with repository
"aur"; [ignored] is shown [held]; a failing -Qua warns and the session
goes on with the repository rows
- every row has a marker column after the number: "*" for AUR rows, a
space otherwise (on every backend)
- N?? merges pacman -Qi with <helper> -Sia; N?, N+, Nx stay with pacman;
N- excludes through the helper's --ignore
- <enter>: the repository step exactly as before, then <helper> -Sua
--ignore <excluded> as the invoking user (--noconfirm only when stdin is
not a terminal); pacman is skipped when only AUR rows are left; a helper
failure is reported and its status returned; --dry-run prints it
- other backends never run a helper; --aur-helper is ignored with a warning
paru 2.1.0 and yay 13.0.1 formats verified in discovery/pacman.md section
15 (proof: discovery/pacman/aur.sh). Unit tests replay the recorded output
(fake paru, yay, runuser, getent); the archlinux E2E run installs the
foreign su-dummy-aur and drives a fake paru through a fake sudo built on
passwordless su for wheel.
This commit is contained in:
1 parent
875c8294bf
commit
def537af58
39 files changed
+1903
-115
No files matched your search
@@ -9,6 +9,7 @@ Companion files (all in `discovery/pacman/`):
|
||||
| `fixture.sh` | E2E fixture: dummy packages `su-dummy-{a,b,c}` 1.0 installed, 2.0 offered by a local repo |
|
||||
| `lib.sh` | proven bash helpers (`pm_upgradable`, `pm_field`, `pm_closure`, `pm_plan`, ...) |
|
||||
| `checks.sh` | executable proof of this document (`ALL CHECKS PASSED` on `archlinux:latest` and `archlinux:base-devel`) |
|
||||
| `aur.sh` | proof of section 15 (paru and yay output formats; **needs network**: Arch mirrors, the AUR, GitHub) |
|
||||
|
||||
Re-run the proof:
|
||||
|
||||
@@ -30,6 +31,7 @@ docker run --rm -i -v "$PWD/discovery/pacman:/d:ro" archlinux:latest bash /d/che
|
||||
| per-run exclusion | `pacman -Su --noconfirm --ignore a,b` (or repeated `--ignore`); globs work |
|
||||
| upgrade | `pacman -Su --noconfirm` (`-Syu` if you did not refresh before) |
|
||||
| purge | `pacman -Rns --noconfirm -- pkg...` |
|
||||
| AUR (paru / yay, section 15) | list `<helper> -Qua`, record `<helper> -Sia PKG`, upgrade `<helper> -Sua [--noconfirm] [--ignore a,b]`, never as root |
|
||||
|
||||
Top gotchas (details below):
|
||||
|
||||
@@ -615,3 +617,127 @@ Validated By : None
|
||||
* Multi-line: only `Optional Deps` (continuation lines indented to the value column, one entry each - glib2: `dconf: ...` / `glib2-devel: ...` / `gvfs: ...`); with `COLUMNS=0` nothing else wraps (`Provides` of glib2, 6 entries, stays one line).
|
||||
* The candidate is `-Si REPO/PKG` with REPO = the first repository `-Sl` lists PKG in (pacman's choice, the join `pacman_upgradable` uses); plain `-Si PKG` prints one record per repository that has PKG.
|
||||
* Missing sides: `-Qi` of a package only in a sync database fails (not installed: the candidate alone); a local-only package has no `-Si` record (the plain `-Qi` stays).
|
||||
|
||||
## 15. AUR helpers: paru and yay (`-Qua`, `-Sia`, `-Sua`)
|
||||
|
||||
Verified 2026-10-10 on archlinux:latest (pacman 7.1.0 / libalpm 16.0.1) with **paru 2.1.0** and **yay 13.0.1**,
|
||||
both built from the AUR, run as the unprivileged user `bob` (wheel, NOPASSWD sudo) with stdin from `/dev/null`,
|
||||
stdout piped, `LC_ALL=C`. `paru-bin` 2.1.0 does not start on this pacman (`paru: error while loading shared
|
||||
libraries: libalpm.so.15: cannot open shared object file`, exit 127: it links libalpm 15), so paru was built from
|
||||
the `paru` package (cargo); yay is `yay-bin`. Outdated AUR package: `pfetch` 1.10.0-1 (built from an older commit
|
||||
of its AUR git), 1.11.0-1 in the AUR; devel package: `pfetch-git`; foreign package that is not in the AUR:
|
||||
`su-local-only` (hand-built). Proof: `discovery/pacman/aur.sh` (needs network):
|
||||
|
||||
```
|
||||
docker run --rm -i -v "$PWD/discovery/pacman:/d:ro" archlinux:latest bash /d/aur.sh
|
||||
```
|
||||
|
||||
### 15.1 `-Qua`: the AUR upgrades
|
||||
|
||||
```
|
||||
$ paru -Qua $ yay -Qua
|
||||
pfetch 1.10.0-1 -> 1.11.0-1 pfetch 1.10.0-1 -> 1.11.0-1 [122d13h]
|
||||
[exit 0] [exit 0]
|
||||
```
|
||||
|
||||
* Format `name SP old SP "->" SP new [SP extra]`, like `pacman -Qu`; no colour when piped (both). yay 13 appends the
|
||||
time since the package's `Last Modified` in the AUR (`[122d13h]`: 9 Jun 2026 to 10 Oct 2026); paru nothing.
|
||||
`paru -Qu` / `yay -Qu` print the same line here (repository and AUR upgrades together).
|
||||
* `IgnorePkg = pfetch`: paru prints `pfetch 1.10.0-1 -> 1.11.0-1 [ignored]` (exit 0); **yay leaves the package
|
||||
out** (no output, exit 1).
|
||||
* Nothing to upgrade: **exit 1, nothing on stdout or stderr** (both, with and without `--devel`).
|
||||
* The AUR unreachable (`127.0.0.1 aur.archlinux.org` in `/etc/hosts`): **exit 1 with the error on stderr**:
|
||||
|
||||
```
|
||||
paru: error: error sending request for url (https://aur.archlinux.org/rpc): error trying to connect: tcp connect
|
||||
error: Connection refused (os error 111): ... Connection refused (os error 111) (one line)
|
||||
yay: -> 1 error occurred:
|
||||
* request failed: Get "https://aur.archlinux.org/rpc?arg%5B%5D=paru&...&type=info&v=5": dial tcp
|
||||
127.0.0.1:443: connect: connection refused (then 2 blank lines)
|
||||
```
|
||||
|
||||
So exit 1 with an empty stderr = nothing to upgrade; anything else = failure.
|
||||
* A foreign package that is not in the AUR is not mentioned by `-Qua` (only `-Sua` says `:: packages not in the
|
||||
AUR: su-local-only` / ` -> Packages not in AUR: su-local-only`). Foreign = in no sync database: with the
|
||||
repositories of the E2E fixture commented out, every base package is foreign to the helper.
|
||||
* Devel (VCS) packages, after `paru -S pfetch-git`, `paru --gendb`, `yay -Y --gendb` and replacing the commit ids
|
||||
recorded in `~/.local/state/paru/devel.toml` / `~/.cache/yay/vcs.json` by older ones: paru checks them **by
|
||||
default** (`paru -Qua`, with or without `--devel`; `-Sua` prints `:: Looking for devel upgrades...`), yay only
|
||||
with `--devel` (or `yay -Y --devel --save`). The new version is the literal `latest-commit`:
|
||||
|
||||
```
|
||||
$ paru -Qua $ yay -Qua --devel ($ yay -Qua: exit 1, nothing)
|
||||
pfetch-git r432.a906ff8-1 -> latest-commit pfetch-git r432.a906ff8-1 -> latest-commit [2299d6h]
|
||||
```
|
||||
|
||||
* As root: `paru -Qua` works (same output); `yay -Qua` works but prints `^[[1m^[[33m -> ^[[0m^[[0mAvoid running
|
||||
yay as root/sudo.` on **stdout**. `paru -Sua` as root: `error: can't install AUR package as root` (exit 1);
|
||||
`yay -Sua` as root fails as well (exit 1). The helpers must run as a normal user.
|
||||
|
||||
### 15.2 `-Sia PKG`: the AUR record
|
||||
|
||||
`paru -Si pfetch`, `paru -Sia pfetch` and `paru -Si --aur pfetch` print the same record; `yay -Si pfetch` asks the
|
||||
repositories only (`error: package 'pfetch' was not found` / ` -> exit status 1`, exit 1), `yay -Sia pfetch` gives
|
||||
the AUR record. Both are pacman-style, one record followed by a blank line:
|
||||
|
||||
```
|
||||
$ paru -Sia pfetch $ yay -Sia pfetch (keys padded to 30)
|
||||
Repository : aur Repository : aur
|
||||
Name : pfetch Name / Version / Description / URL / Licenses /
|
||||
Version : 1.11.0-1 Groups / Provides / Depends On / Optional Deps /
|
||||
Description : A pretty system information tool ... Make Deps / Check Deps / Conflicts With /
|
||||
URL : https://github.com/Un1q32/pfetch Replaces : None
|
||||
AUR URL : https://aur.archlinux.org/packages/pfetch AUR URL : https://aur...
|
||||
Groups : None First Submitted : Sat 16 Jan 2021 09:13:08 AM UTC
|
||||
Licenses : MIT Keywords : fetch
|
||||
Provides : pfetch Last Modified : Tue 09 Jun 2026 10:43:50 PM UTC
|
||||
Depends On : None Maintainer : yigits
|
||||
Make Deps : None Popularity : 0.103440
|
||||
Check Deps : None Votes : 48
|
||||
Optional Deps : None Out-of-date : No
|
||||
Conflicts With : pfetch-git
|
||||
Maintainer : yigits
|
||||
Votes : 48
|
||||
Popularity : 0.10344
|
||||
First Submitted : Sat, 16 Jan 2021 09:13:08
|
||||
Last Modified : Tue, 9 Jun 2026 22:43:50
|
||||
Out Of Date : No
|
||||
```
|
||||
|
||||
* Comparable with `pacman -Qi pfetch` (section 14): one record per side, every `:` in one column per side (paru: 17,
|
||||
like pacman; yay: 31, re-padded by the merge), keys spelled like pacman's. Both, here identical: `Name`,
|
||||
`Description`, `URL`, `Licenses`, `Groups`, `Provides`, `Depends On`, `Optional Deps`, `Conflicts With` (yay also
|
||||
`Replaces`); different: `Version`. `-Qi` only: `Architecture`, `Required By`, `Optional For`, `Installed Size`,
|
||||
`Packager`, `Build Date`, `Install Date`, `Install Reason`, `Install Script`, `Validated By`. AUR only:
|
||||
`Repository` (`aur`), `AUR URL`, `Make Deps`, `Check Deps`, `Maintainer`, `Votes`, `Popularity`, `First
|
||||
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
|
||||
no-such-package-zzz`, exit 1. AUR unreachable: the `-Qua` errors above, exit 1.
|
||||
|
||||
### 15.3 `-Sua`: the AUR upgrade
|
||||
|
||||
* `--ignore` covers AUR packages (both): `paru -Sua --noconfirm --ignore pfetch` -> ` there is nothing to do`, stderr
|
||||
`warning: pfetch: ignoring package upgrade (1.10.0-1 => 1.11.0-1)`, exit 0; `yay -Sua --noconfirm --ignore pfetch`
|
||||
-> ` -> pfetch: ignoring package upgrade (1.10.0-1 => 1.11.0-1)` and ` there is nothing to do` (stdout), exit 0.
|
||||
Names that are not installed (`--ignore su-dummy-x,su-dummy-y`) are accepted and pfetch is upgraded.
|
||||
* `--noconfirm`, stdin `/dev/null`: both upgrade without asking (exit 0). paru still prints `:: Proceed to review?
|
||||
[Y/n]:` and answers it; yay's menus (`Packages to exclude`, `Packages to cleanBuild?`, `Diffs to show?`) take
|
||||
their default (none). The helper installs with `sudo pacman -U` itself (here NOPASSWD; otherwise sudo asks for
|
||||
the user's password on the terminal).
|
||||
* **Without `--noconfirm`, stdin `/dev/null`**: paru takes the defaults at end of input and upgrades (printing the
|
||||
PKGBUILD as its review); **yay exits 1** at its first menu (`:: 1 package to upgrade/install.` ... `Excluding
|
||||
packages may cause partial upgrades`), nothing upgraded. So `--noconfirm` whenever stdin is not a terminal; on a
|
||||
terminal the helper keeps its prompts (paru's PKGBUILD review, yay's diff menu).
|
||||
* Devel: `paru -Sua --noconfirm` rebuilt `pfetch-git` for the `latest-commit` row (`warning: pfetch-git-r432.a906ff8-1
|
||||
is up to date -- reinstalling`, since only the recorded commit was faked).
|
||||
* `runuser -u bob -- env` (as root) sets `HOME=/home/bob`, `USER`, `LOGNAME` and `MAIL` (PAM) and keeps `PATH` and
|
||||
the working directory; `runuser` is in util-linux (the base image has it, `sudo` it has not).
|
||||
|
||||
### 15.4 Chosen
|
||||
|
||||
| need | command (as the invoking user: `runuser -u "$SUDO_USER" -- env HOME=<home>`, else `sudo -u ...`; unprivileged runs as they are; a root login without `SUDO_USER`: no AUR) |
|
||||
|------|---------|
|
||||
| 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 |
|
||||
| `N??` | `pacman -Qi` merged with `<helper> -Sia PKG` (section 14's merge) |
|
||||
| upgrade | after the repository step: `<helper> -Sua [--noconfirm when stdin is not a terminal] [--ignore <excluded rows>]` |
|
||||
Reference in new issue
Block a user