first commit

This commit is contained in:
grayTerminal-sh 2026-05-18 14:44:43 +02:00
commit 589116d516
5 changed files with 580 additions and 0 deletions

145
README.md Normal file
View file

@ -0,0 +1,145 @@
# aurtools
A small set of shell scripts to manage AUR packages on Arch Linux **without** `yay`, `paru`, or any other AUR helper.
This project follows the classic AUR workflow: clone the package repository, review the `PKGBUILD`, build with `makepkg`, and install with `pacman -U`. [web:22][web:303][web:305]
## Included scripts
- `aurinstall` — clone or update an AUR package repository, optionally review `PKGBUILD`, build the package, and install it with `pacman -U`. [web:22][web:305]
- `aurupdate` — iterate through local AUR package repositories, pull updates, rebuild selected packages, and reinstall them locally. [web:22][web:305]
- `aurremove` — remove installed AUR packages with `pacman -Rns` and optionally delete the local repository directory. [web:46][web:107]
- `_aurtools` — Zsh completion file for the scripts, including optional online package-name completion for `aurinstall` via the AUR RPC interface. [web:281]
## Why use this
This setup is intended for users who want full visibility into what gets built and installed from the AUR. Instead of relying on a full AUR helper, it keeps each package as a normal Git repository under `~/Aur`, making updates and audits easier to understand and review. [web:22][web:189]
## Requirements
Install the usual Arch build tools first:
```bash
sudo pacman -S --needed base-devel git
```
Some optional features require additional tools:
```bash
sudo pacman -S curl jq zsh
```
- `curl` and `jq` are used by the optional online completion for `aurinstall` through the AUR RPC API. [web:281]
- `zsh` is needed only for the provided completion script.
- An editor such as `nvim` is useful if `aurinstall` is run with review options like `-e`, `-E`, or `-d`.
## Installation
Copy the scripts somewhere in your `PATH`, for example `~/.local/bin`:
```bash
mkdir ~/Aur
install -Dm755 aurinstall ~/.local/bin/aurinstall
install -Dm755 aurupdate ~/.local/bin/aurupdate
install -Dm755 aurremove ~/.local/bin/aurremove
```
Install the Zsh completion file:
```bash
mkdir -p ~/.zsh/completions
install -Dm644 completions/_aurtools ~/.zsh/completions/_aurtools
```
Then ensure the completion directory is in `fpath` and initialize completion in `~/.zshrc`:
```zsh
fpath=("$HOME/.zsh/completions" $fpath)
autoload -Uz compinit
compinit
```
## Repository layout
The scripts assume that AUR repositories are stored under `~/Aur` by default:
```text
~/Aur/
├── package-one/
├── package-two/
└── package-three/
```
Each package is kept as its own Git repository cloned from `https://aur.archlinux.org/<pkgname>.git`, which matches the documented AUR workflow. [web:22][web:189]
## Usage
### Install a package
```bash
aurinstall proton-pass-bin
```
This clones the package if needed, builds it with `makepkg`, and installs the resulting package file with `pacman -U`. [web:22][web:305]
### Prompt before editing build files
```bash
aurinstall -e swayfx
```
### Always open `PKGBUILD` before building
```bash
aurinstall -E swayfx
```
Reviewing `PKGBUILD` before building is an important AUR safety habit because `makepkg` executes build instructions defined there. [web:303][web:305]
### Download and audit only
```bash
aurinstall -d swayfx
```
This mode updates or clones the repository and lets the user inspect package files without building or installing anything.
### Update local AUR repositories
```bash
aurupdate
```
This walks through the repositories stored in `~/Aur`, pulls upstream changes, and rebuilds selected packages.
### Remove a package
```bash
aurremove calcure
```
This removes the installed package with `pacman -Rns`, which removes the package, unneeded dependencies, and package-managed config files. [web:46][web:107][web:212]
## Zsh completion
The included completion script supports:
- local completion from existing repositories in `~/Aur` for `aurinstall`
- optional remote name completion for `aurinstall` through the AUR RPC interface [web:281]
- completion of installed foreign packages for `aurremove` via `pacman -Qm` [web:46]
If completion behaves strangely after changes, rebuild the completion cache:
```zsh
rm -f ~/.cache/zsh/zcompdump*
autoload -Uz compinit
compinit
```
## Security note
AUR packages are user-contributed build scripts, not official binary packages. The safest workflow is to inspect `PKGBUILD`, sources, checksums, and build steps before installation. [web:22][web:303][web:305]
## License
A permissive license such as MIT or ISC fits this kind of shell-script project well. GitHub recommends adding an explicit license if the repository is meant to be reused by others. [web:317][web:322]

124
aurinstall Executable file
View file

@ -0,0 +1,124 @@
#!/bin/bash
set -euo pipefail
AUR_DIR="$HOME/Aur"
EDITOR_CMD="${EDITOR:-nvim}"
ASK_EDIT=0
FORCE_EDIT=0
DOWNLOAD_ONLY=0
while getopts ":eEd" opt; do
case "$opt" in
e) ASK_EDIT=1 ;;
E) FORCE_EDIT=1 ;;
d) DOWNLOAD_ONLY=1 ;;
*)
echo "Usage: aurinstall [-e|-E] [-d] <paquet1> [paquet2 ...]"
exit 1
;;
esac
done
shift $((OPTIND - 1))
RESET='\033[0m'
BOLD='\033[1m'
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[1;36m'
info() { printf "${BLUE}==>${RESET} %s\n" "$1"; }
ok() { printf "${GREEN}==>${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}==>${RESET} %s\n" "$1"; }
error() { printf "${RED}==>${RESET} %s\n" "$1"; }
section() { printf "\n${CYAN}${BOLD}>>> %s${RESET}\n" "$1"; }
if [[ $# -lt 1 ]]; then
error "Usage: aurinstall [-e|-E] [-d] <paquet1> [paquet2 ...]"
exit 1
fi
mkdir -p "$AUR_DIR"
if [[ "$DOWNLOAD_ONLY" -eq 0 ]]; then
sudo -v || exit 1
while true; do
sudo -n true || exit
sleep 30
done 2>/dev/null &
SUDO_LOOP_PID=$!
trap 'kill "$SUDO_LOOP_PID" 2>/dev/null' EXIT INT TERM
fi
for pkg in "$@" ; do
section "$pkg"
cd "$AUR_DIR" || exit 1
if [[ "$DOWNLOAD_ONLY" -eq 0 ]] && pacman -Q "$pkg" >/dev/null 2>&1; then
warn "$pkg est déjà installé, on passe."
continue
fi
if [[ -d "$pkg/.git" ]]; then
warn "$pkg déjà cloné, utilisation du dossier existant"
cd "$pkg" || { error "Impossible d'entrer dans $pkg"; continue; }
pull_output=$(git pull --ff-only 2>&1) || {
error "git pull failed pour $pkg"
cd "$AUR_DIR" || exit 1
continue
}
printf "%s\n" "$pull_output"
else
info "Clonage de $pkg"
if ! git clone "https://aur.archlinux.org/${pkg}.git"; then
error "Impossible de cloner $pkg"
continue
fi
cd "$pkg" || { error "Impossible d'entrer dans $pkg"; continue; }
fi
if [[ "$FORCE_EDIT" -eq 1 ]]; then
info "Ouverture de PKGBUILD et .SRCINFO dans $EDITOR_CMD"
"$EDITOR_CMD" PKGBUILD .SRCINFO
elif [[ "$ASK_EDIT" -eq 1 || "$DOWNLOAD_ONLY" -eq 1 ]]; then
printf "${YELLOW}Éditer PKGBUILD/.SRCINFO pour %s ? [y/N] ${RESET}" "$pkg"
read -r ans
if [[ "$ans" == "y" || "$ans" == "Y" ]]; then
"$EDITOR_CMD" PKGBUILD .SRCINFO
fi
fi
if [[ "$DOWNLOAD_ONLY" -eq 1 ]]; then
ok "$pkg prêt pour audit dans $AUR_DIR/$pkg"
continue
fi
info "Vérifie au minimum source=(), checksums, prepare()/build()/package() et validpgpkeys si présents"
rm -f ./*.pkg.tar ./*.pkg.tar.*
if ! makepkg -sf; then
error "Build failed pour $pkg"
cd "$AUR_DIR" || exit 1
continue
fi
pkgfile=$(find . -maxdepth 1 -type f \( -name '*.pkg.tar' -o -name '*.pkg.tar.*' \) ! -name '*.sig' | head -n1 || true)
echo "DEBUG: pkgfile='$pkgfile'"
if [[ -z "$pkgfile" ]]; then
error "Aucun paquet généré pour $pkg"
cd "$AUR_DIR" || exit 1
continue
fi
info "Installation de $pkgfile"
if ! sudo pacman -U --noconfirm "$pkgfile"; then
error "Install failed pour $pkg"
cd "$AUR_DIR" || exit 1
continue
fi
ok "$pkg installé avec succès"
done

59
aurremove Executable file
View file

@ -0,0 +1,59 @@
#!/bin/bash
set -euo pipefail
AUR_DIR="$HOME/Aur"
RESET='\033[0m'
BOLD='\033[1m'
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[1;36m'
info() { printf "${BLUE}==>${RESET} %s\n" "$1"; }
ok() { printf "${GREEN}==>${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}==>${RESET} %s\n" "$1"; }
error() { printf "${RED}==>${RESET} %s\n" "$1"; }
section() { printf "\n${CYAN}${BOLD}>>> %s${RESET}\n" "$1"; }
if [[ $# -lt 1 ]]; then
error "Usage: aurremove <paquet1> [paquet2 ...]"
exit 1
fi
sudo -v || exit 1
while true; do
sudo -n true || exit
sleep 30
done 2>/dev/null &
SUDO_LOOP_PID=$!
trap 'kill "$SUDO_LOOP_PID" 2>/dev/null' EXIT INT TERM
for pkg in "$@" ; do
section "$pkg"
if ! pacman -Q "$pkg" >/dev/null 2>&1; then
warn "$pkg n'est pas installé"
continue
fi
info "Désinstallation de $pkg"
if ! sudo pacman -Rns "$pkg"; then
error "Échec de suppression pour $pkg"
continue
fi
ok "$pkg supprimé du système"
if [[ -d "$AUR_DIR/$pkg" ]]; then
printf "${YELLOW}Supprimer aussi le dossier %s ? [y/N] ${RESET}" "$AUR_DIR/$pkg"
read -r ans
if [[ "$ans" == "y" || "$ans" == "Y" ]]; then
rm -rf "$AUR_DIR/$pkg"
ok "Dossier $AUR_DIR/$pkg supprimé"
else
warn "Dossier conservé : $AUR_DIR/$pkg"
fi
fi
done

194
aurupdate Executable file
View file

@ -0,0 +1,194 @@
#!/bin/bash
set -euo pipefail
AUR_DIR="${AUR_DIR:-$HOME/Aur}"
END_UPDATE="Mis à jour avec succès ;p."
SYSTEM_NAME="$(cat /etc/hostname 2>/dev/null || echo "unknown")"
RESET='\033[0m'
BOLD='\033[1m'
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[1;36m'
info() { printf "${BLUE}==>${RESET} %s\n" "$1"; }
ok() { printf "${GREEN}==>${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}==>${RESET} %s\n" "$1"; }
error() { printf "${RED}==>${RESET} %s\n" "$1"; }
section() { printf "\n${CYAN}${BOLD}>>> %s${RESET}\n" "$1"; }
[[ -d "$AUR_DIR" ]] || {
error "Répertoire AUR introuvable : $AUR_DIR"
exit 1
}
sudo -v || exit 1
while true; do
sudo -n true || exit
sleep 30
done 2>/dev/null &
SUDO_LOOP_PID=$!
trap 'kill "$SUDO_LOOP_PID" 2>/dev/null' EXIT INT TERM
cd "$AUR_DIR" || exit 1
shopt -s nullglob
repos=(*/)
shopt -u nullglob
if [[ ${#repos[@]} -eq 0 ]]; then
warn "Aucun dépôt AUR dans $AUR_DIR"
exit 0
fi
declare -a outdated_repos=()
audit_repo() {
local repo="$1"
local branch upstream local_rev remote_rev base_rev
cd "$AUR_DIR/$repo" || return 1
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
error "$repo n'est pas un dépôt git valide"
return 1
fi
branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null || true)
[[ -n "$branch" ]] || {
warn "$repo : HEAD détachée, ignoré"
return 1
}
if ! git remote update --prune >/dev/null 2>&1; then
error "Impossible de contacter le remote pour $repo"
return 1
fi
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true)
[[ -n "$upstream" ]] || upstream="origin/$branch"
local_rev=$(git rev-parse HEAD 2>/dev/null || true)
remote_rev=$(git rev-parse "$upstream" 2>/dev/null || true)
base_rev=$(git merge-base HEAD "$upstream" 2>/dev/null || true)
if [[ -z "$remote_rev" || -z "$local_rev" || -z "$base_rev" ]]; then
error "Impossible de comparer $repo avec $upstream"
return 1
fi
if [[ "$local_rev" == "$remote_rev" ]]; then
return 1
fi
if [[ "$local_rev" != "$base_rev" ]]; then
warn "$repo a des commits locaux non poussés, ignoré"
return 1
fi
outdated_repos+=("$repo")
return 0
}
ask_update() {
local repo="$1"
while true; do
printf "${YELLOW}Mettre à jour %s ? [y/N/q] ${RESET}" "$repo"
read -r ans
case "$ans" in
y|Y) return 0 ;;
n|N|"") return 1 ;;
q|Q) return 2 ;;
*) warn "Réponse invalide, utilise y, n ou q" ;;
esac
done
}
info "Scan des dépôts AUR..."
for d in "${repos[@]}"; do
repo="${d%/}"
audit_repo "$repo" || true
done
if [[ ${#outdated_repos[@]} -eq 0 ]]; then
ok "Aucune mise à jour AUR détectée"
exit 0
fi
section "Mises à jour détectées"
for repo in "${outdated_repos[@]}"; do
cd "$AUR_DIR/$repo" || continue
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo "origin/HEAD")
printf "${YELLOW}- %s${RESET}\n" "$repo"
git --no-pager log --oneline --decorate HEAD.."$upstream" | sed 's/^/ /'
done
declare -a selected_repos=()
section "Sélection"
for repo in "${outdated_repos[@]}"; do
if ask_update "$repo"; then
selected_repos+=("$repo")
else
rc=$?
if [[ $rc -eq 2 ]]; then
warn "Sélection interrompue"
break
fi
fi
done
if [[ ${#selected_repos[@]} -eq 0 ]]; then
warn "Aucun paquet sélectionné"
exit 0
fi
section "Paquets sélectionnés"
for repo in "${selected_repos[@]}"; do
printf "${GREEN}- %s${RESET}\n" "$repo"
done
for repo in "${selected_repos[@]}"; do
cd "$AUR_DIR/$repo" || continue
section "$repo"
info "Récupération des changements"
if ! git pull --ff-only; then
error "git pull failed for $repo"
continue
fi
info "Vérifie au minimum PKGBUILD, sources, checksums et fonctions de build"
rm -f ./*.pkg.tar.*
if ! makepkg -sf; then
error "Build failed for $repo"
continue
fi
pkgfile=$(find . -maxdepth 1 -type f -name '*.pkg.tar.*' ! -name '*.sig' | head -n1 || true)
if [[ -z "$pkgfile" ]]; then
error "Aucun paquet trouvé pour $repo"
continue
fi
info "Installation de $pkgfile"
if ! sudo pacman -U --noconfirm "$pkgfile"; then
error "Install failed for $repo"
continue
fi
ok "$repo installé avec succès"
done
printf "\n"
if command -v figlet >/dev/null 2>&1; then
figlet -f slant "$SYSTEM_NAME" | while IFS= read -r line; do
printf "${GREEN}%s${RESET}\n" "$line"
done
printf "${GREEN}%s${RESET}\n" "$END_UPDATE"
else
printf "${GREEN}%s : %s${RESET}\n" "$SYSTEM_NAME" "$END_UPDATE"
fi

58
completions/_aurtools Executable file
View file

@ -0,0 +1,58 @@
#compdef aurinstall aurupdate aurremove
_aurlist_dirs() {
local -a pkgs
local AUR_DIR=${AUR_DIR:-$HOME/Aur}
pkgs=()
if [[ -d $AUR_DIR ]]; then
local d
for d in "$AUR_DIR"/*; do
[[ -d $d ]] || continue
pkgs+=("${d:t}")
done
fi
compadd "$pkgs[@]"
}
_aurlist_installed() {
local -a pkgs
pkgs=(${(f)"$(pacman -Qm 2>/dev/null | awk '{print $1}')"})
compadd "$pkgs[@]"
}
_aursearch_online() {
local cur
cur="${words[CURRENT]}"
[[ -z "$cur" || ${#cur} -lt 2 ]] && return 0
command -v curl >/dev/null 2>&1 || return 0
command -v jq >/dev/null 2>&1 || return 0
local -a remote_pkgs
remote_pkgs=(${(f)"$(
curl -fsSL "https://aur.archlinux.org/rpc/v5/search/${cur}?by=name" 2>/dev/null \
| jq -r '.results[].Name' 2>/dev/null
)"})
(( ${#remote_pkgs[@]} )) && compadd "$remote_pkgs[@]"
}
_aurinstall() {
_aurlist_dirs
_aursearch_online
}
_aurupdate() {
_message 'aucun argument'
}
_aurremove() {
_aurlist_installed
}
compdef _aurinstall aurinstall
compdef _aurupdate aurupdate
compdef _aurremove aurremove