first upload
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 miaur contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,2 +1,49 @@
|
|||||||
# miaur
|
# miaur
|
||||||
|
|
||||||
A lightweight AUR helper written in pure Bash. No helper compilation required.
|
A lightweight AUR helper written in pure Bash. No helper compilation required.
|
||||||
|
|
||||||
|
Its everyday commands follow paru, including `-Syu`, `-S`, `-Ss`, `-Qua`, and `-G`.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/WHC2006/miaur.git
|
||||||
|
cd miaur
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
One command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <(curl -fsSL https://raw.githubusercontent.com/WHC2006/miaur/main/install.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
Install for the current user under `~/.local`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./install.sh --user
|
||||||
|
```
|
||||||
|
|
||||||
|
The installer adds the required packages automatically: `base-devel`, `git`, `curl`, and `jq`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
miaur # Upgrade everything (same as -Syu)
|
||||||
|
miaur foo # Search and select packages interactively
|
||||||
|
miaur -S <package> # Install a package
|
||||||
|
miaur -Ss <query> # Search packages
|
||||||
|
miaur -Qua # List available AUR upgrades
|
||||||
|
miaur -Sua # Upgrade AUR packages only
|
||||||
|
miaur -G <package> # Download a PKGBUILD
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `miaur -h` for more options.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The optional configuration file is `~/.config/miaur/miaur.conf`. See `config/miaur.conf.example`.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# bash completion for miaur
|
||||||
|
_miaur() {
|
||||||
|
local cur prev
|
||||||
|
COMPREPLY=()
|
||||||
|
cur=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
prev=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
local ops='-S -Syu -Sua -Ss -Si -Sc -Q -Qua -Qm -R -Rns -G -Gp -B -Bi -h -V'
|
||||||
|
local longs='--aur --repo --skipreview --cleanafter --removemake --noremovermake --bottomup --topdown --clonedir --mflags --sudoloop --nosudoloop --help --version'
|
||||||
|
|
||||||
|
case "$prev" in
|
||||||
|
-S | -Si | -Ss | -G | -Gp | -R | -Rns | -Qi)
|
||||||
|
COMPREPLY=($(compgen -W "$(pacman -Ssq "^${cur}" 2>/dev/null | head -50)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--clonedir)
|
||||||
|
COMPREPLY=($(compgen -d -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "$ops $longs" -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W "$(pacman -Ssq "^${cur}" 2>/dev/null | head -40)" -- "$cur"))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
complete -F _miaur miaur
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#compdef miaur
|
||||||
|
|
||||||
|
_miaur() {
|
||||||
|
local -a ops
|
||||||
|
ops=(
|
||||||
|
'-Syu:upgrade repository and AUR packages'
|
||||||
|
'-Sua:upgrade AUR packages only'
|
||||||
|
'-Ss:search packages'
|
||||||
|
'-Si:show package information'
|
||||||
|
'-S:install a package'
|
||||||
|
'-Qua:list AUR upgrades'
|
||||||
|
'-G:download a PKGBUILD'
|
||||||
|
'-Gp:print a PKGBUILD'
|
||||||
|
'-Bi:build and install'
|
||||||
|
'-Sc:clean caches'
|
||||||
|
'-Rns:remove a package'
|
||||||
|
'--aur:use the AUR only'
|
||||||
|
'--repo:use repositories only'
|
||||||
|
'--skipreview:skip PKGBUILD review'
|
||||||
|
'--bottomup:show AUR results first'
|
||||||
|
'--help:show help'
|
||||||
|
)
|
||||||
|
_arguments '*:package:_files' \
|
||||||
|
"${ops[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_miaur
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# miaur configuration example
|
||||||
|
# Copy this file to ~/.config/miaur/miaur.conf
|
||||||
|
|
||||||
|
# AurUrl = https://aur.archlinux.org
|
||||||
|
# AurRpcUrl = https://aur.archlinux.org/rpc/v5
|
||||||
|
# CloneDir = ~/.cache/miaur
|
||||||
|
|
||||||
|
SkipReview = false
|
||||||
|
CleanAfter = false
|
||||||
|
RemoveMake = true
|
||||||
|
BottomUp = false
|
||||||
|
SudoLoop = true
|
||||||
|
|
||||||
|
# MFlags = -si
|
||||||
|
# SortBy = votes
|
||||||
|
# SearchBy = name-desc
|
||||||
|
# Editor = nvim
|
||||||
|
# Bat = bat
|
||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# miaur one-click installer
|
||||||
|
# Usage:
|
||||||
|
# ./install.sh
|
||||||
|
# ./install.sh --user
|
||||||
|
# ./install.sh --uninstall
|
||||||
|
# bash <(curl -fsSL https://raw.githubusercontent.com/<user>/miaur/main/install.sh)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Override when forking: MIAUR_REPO=https://github.com/you/miaur.git ./install.sh
|
||||||
|
REPO_URL="${MIAUR_REPO:-https://github.com/WHC2006/miaur.git}"
|
||||||
|
BRANCH="${MIAUR_BRANCH:-main}"
|
||||||
|
|
||||||
|
USER_INSTALL=0
|
||||||
|
UNINSTALL=0
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--user) USER_INSTALL=1 ;;
|
||||||
|
--uninstall) UNINSTALL=1 ;;
|
||||||
|
-h | --help)
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: install.sh [--user] [--uninstall]
|
||||||
|
|
||||||
|
(default) Install system-wide to /usr/local (needs sudo)
|
||||||
|
--user Install to ~/.local (no sudo for the link)
|
||||||
|
--uninstall Remove installed miaur
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $arg" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $USER_INSTALL -eq 1 ]]; then
|
||||||
|
PREFIX="${HOME}/.local"
|
||||||
|
SUDO=
|
||||||
|
else
|
||||||
|
PREFIX=/usr/local
|
||||||
|
SUDO=sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
SHARE_DIR="${PREFIX}/share/miaur"
|
||||||
|
BIN_LINK="${PREFIX}/bin/miaur"
|
||||||
|
|
||||||
|
die() { echo "error: $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
need_root_ok() {
|
||||||
|
if [[ $USER_INSTALL -eq 0 && ${EUID:-$(id -u)} -ne 0 ]]; then
|
||||||
|
command -v sudo >/dev/null 2>&1 || die "sudo is required"
|
||||||
|
sudo -v || die "sudo authentication failed"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall() {
|
||||||
|
need_root_ok
|
||||||
|
echo "==> Uninstalling miaur"
|
||||||
|
$SUDO rm -f "$BIN_LINK"
|
||||||
|
$SUDO rm -rf "$SHARE_DIR"
|
||||||
|
echo "Done: removed $BIN_LINK and $SHARE_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_deps() {
|
||||||
|
command -v pacman >/dev/null 2>&1 || die "Arch Linux is required (pacman not found)"
|
||||||
|
echo "==> Installing dependencies"
|
||||||
|
if [[ ${EUID:-$(id -u)} -eq 0 ]]; then
|
||||||
|
pacman -S --needed --noconfirm base-devel git curl jq
|
||||||
|
else
|
||||||
|
sudo pacman -S --needed --noconfirm base-devel git curl jq
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve source tree: current repo, or clone to temp
|
||||||
|
resolve_src() {
|
||||||
|
local here
|
||||||
|
here=$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)
|
||||||
|
if [[ -f $here/miaur && -d $here/lib ]]; then
|
||||||
|
SRC=$here
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Cloning ${REPO_URL} (${BRANCH})"
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
trap 'rm -rf "${TMP:-}"' EXIT
|
||||||
|
git clone --depth 1 --branch "$BRANCH" "$REPO_URL" "$TMP/miaur" \
|
||||||
|
|| die "clone failed; set MIAUR_REPO to the repository URL"
|
||||||
|
SRC=$TMP/miaur
|
||||||
|
}
|
||||||
|
|
||||||
|
do_install() {
|
||||||
|
need_root_ok
|
||||||
|
install_deps
|
||||||
|
resolve_src
|
||||||
|
|
||||||
|
[[ -f $SRC/miaur && -d $SRC/lib ]] || die "incomplete source tree: $SRC"
|
||||||
|
|
||||||
|
echo "==> Installing to ${SHARE_DIR}"
|
||||||
|
$SUDO mkdir -p "$SHARE_DIR" "${PREFIX}/bin"
|
||||||
|
$SUDO rm -rf "$SHARE_DIR"
|
||||||
|
$SUDO mkdir -p "$SHARE_DIR"
|
||||||
|
$SUDO cp -a "$SRC/miaur" "$SRC/lib" "$SHARE_DIR/"
|
||||||
|
if [[ -d $SRC/completions ]]; then
|
||||||
|
$SUDO cp -a "$SRC/completions" "$SHARE_DIR/"
|
||||||
|
fi
|
||||||
|
if [[ -d $SRC/config ]]; then
|
||||||
|
$SUDO cp -a "$SRC/config" "$SHARE_DIR/"
|
||||||
|
fi
|
||||||
|
$SUDO chmod 755 "$SHARE_DIR/miaur"
|
||||||
|
$SUDO ln -sfn "$SHARE_DIR/miaur" "$BIN_LINK"
|
||||||
|
|
||||||
|
# Optional bash completion (system or user)
|
||||||
|
if [[ -d $SRC/completions ]]; then
|
||||||
|
if [[ $USER_INSTALL -eq 1 ]]; then
|
||||||
|
mkdir -p "${HOME}/.local/share/bash-completion/completions"
|
||||||
|
cp -f "$SRC/completions/miaur.bash" \
|
||||||
|
"${HOME}/.local/share/bash-completion/completions/miaur" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
if [[ -d /usr/share/bash-completion/completions ]]; then
|
||||||
|
$SUDO cp -f "$SRC/completions/miaur.bash" \
|
||||||
|
/usr/share/bash-completion/completions/miaur 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done: $(command -v miaur 2>/dev/null || echo "$BIN_LINK")"
|
||||||
|
"$BIN_LINK" -V
|
||||||
|
echo
|
||||||
|
echo "Try: miaur -Ss foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $UNINSTALL -eq 1 ]]; then
|
||||||
|
uninstall
|
||||||
|
else
|
||||||
|
do_install
|
||||||
|
fi
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUR RPC helpers (v5) using curl + jq
|
||||||
|
|
||||||
|
aur_rpc_get() {
|
||||||
|
local url=$1
|
||||||
|
local curl_bin
|
||||||
|
curl_bin=$(resolve_curl)
|
||||||
|
"$curl_bin" -fsSL --connect-timeout 15 --max-time 60 "$url"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Search AUR; prints: name|version|votes|popularity|desc (one per line)
|
||||||
|
aur_search() {
|
||||||
|
local query=$1
|
||||||
|
local by=${2:-$MIAUR_SEARCHBY}
|
||||||
|
local encoded
|
||||||
|
encoded=$(printf '%s' "$query" | jq -sRr @uri)
|
||||||
|
local json
|
||||||
|
json=$(aur_rpc_get "${MIAUR_AURRPC}/search/${encoded}?by=${by}") || return 1
|
||||||
|
local sort=${MIAUR_SORTBY:-votes}
|
||||||
|
local jq_sort
|
||||||
|
case "$sort" in
|
||||||
|
votes) jq_sort='sort_by(.NumVotes) | reverse' ;;
|
||||||
|
popularity) jq_sort='sort_by(.Popularity) | reverse' ;;
|
||||||
|
name) jq_sort='sort_by(.Name)' ;;
|
||||||
|
*) jq_sort='sort_by(.NumVotes) | reverse' ;;
|
||||||
|
esac
|
||||||
|
jq -r --argjson err 0 "
|
||||||
|
if .type == \"error\" then empty
|
||||||
|
else (.results // []) | ${jq_sort} | .[] |
|
||||||
|
[.Name, .Version, (.NumVotes|tostring), (.Popularity|tostring), (.Description // \"\")] | join(\"|\")
|
||||||
|
end
|
||||||
|
" <<<"$json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Info for one package; prints JSON object or empty
|
||||||
|
aur_info_json() {
|
||||||
|
local name=$1
|
||||||
|
local encoded
|
||||||
|
encoded=$(printf '%s' "$name" | jq -sRr @uri)
|
||||||
|
local json
|
||||||
|
json=$(aur_rpc_get "${MIAUR_AURRPC}/info?arg[]=${encoded}") || return 1
|
||||||
|
jq -c '.results[0] // empty' <<<"$json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Multi-info: args are package names. Prints JSON array of results.
|
||||||
|
aur_multiinfo_json() {
|
||||||
|
local args=()
|
||||||
|
local n
|
||||||
|
for n in "$@"; do
|
||||||
|
args+=(--data-urlencode "arg[]=${n}")
|
||||||
|
done
|
||||||
|
[[ ${#args[@]} -eq 0 ]] && { echo '[]'; return 0; }
|
||||||
|
local json
|
||||||
|
local curl_bin
|
||||||
|
curl_bin=$(resolve_curl)
|
||||||
|
json=$("$curl_bin" -fsSL --connect-timeout 15 --max-time 60 -G "${MIAUR_AURRPC}/info" "${args[@]}") || return 1
|
||||||
|
jq -c '.results // []' <<<"$json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if package exists on AUR (exit 0 if yes)
|
||||||
|
aur_exists() {
|
||||||
|
local j
|
||||||
|
j=$(aur_info_json "$1") || return 1
|
||||||
|
[[ -n $j && $j != null ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print human-readable info for a package (like pacman -Si for AUR)
|
||||||
|
aur_print_info() {
|
||||||
|
local name=$1
|
||||||
|
local j
|
||||||
|
j=$(aur_info_json "$name") || return 1
|
||||||
|
[[ -z $j || $j == null ]] && return 1
|
||||||
|
jq -r '
|
||||||
|
"Repository : aur",
|
||||||
|
"Name : \(.Name)",
|
||||||
|
"Version : \(.Version)",
|
||||||
|
"Description : \(.Description // "")",
|
||||||
|
"URL : \(.URL // "")",
|
||||||
|
"AUR URL : https://aur.archlinux.org/packages/\(.Name)",
|
||||||
|
"Groups : \((.Groups // []) | join(" "))",
|
||||||
|
"Depends On : \((.Depends // []) | join(" "))",
|
||||||
|
"Make Depends : \((.MakeDepends // []) | join(" "))",
|
||||||
|
"Check Depends : \((.CheckDepends // []) | join(" "))",
|
||||||
|
"Optional Deps : \((.OptDepends // []) | join(" "))",
|
||||||
|
"Provides : \((.Provides // []) | join(" "))",
|
||||||
|
"Conflicts With : \((.Conflicts // []) | join(" "))",
|
||||||
|
"Replaces : \((.Replaces // []) | join(" "))",
|
||||||
|
"Maintainer : \(.Maintainer // "(orphan)")",
|
||||||
|
"Votes : \(.NumVotes)",
|
||||||
|
"Popularity : \(.Popularity)",
|
||||||
|
"Last Modified : \(.LastModified)",
|
||||||
|
"Out Of Date : \(if .OutOfDate then (.OutOfDate|tostring) else "No" end)"
|
||||||
|
' <<<"$j"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print search line for AUR result: aur/name version (votes) desc
|
||||||
|
aur_format_search_line() {
|
||||||
|
local name=$1 ver=$2 votes=$3 pop=$4 desc=$5
|
||||||
|
local installed=
|
||||||
|
if is_pkg_installed "$name"; then
|
||||||
|
local localver
|
||||||
|
localver=$(pkg_local_version "$name")
|
||||||
|
if [[ $localver == "$ver" ]]; then
|
||||||
|
installed=" ${C_GREEN}[installed]${C_RESET}"
|
||||||
|
else
|
||||||
|
installed=" ${C_YELLOW}[installed: ${localver}]${C_RESET}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
printf '%saur/%s%s %s%s (%s)%s\n %s\n' \
|
||||||
|
"${C_BOLD}${C_CYAN}" "$name" "${C_RESET}" \
|
||||||
|
"${C_BOLD}${C_GREEN}${ver}${C_RESET}" \
|
||||||
|
"$installed" \
|
||||||
|
"$votes" \
|
||||||
|
"" \
|
||||||
|
"$desc"
|
||||||
|
}
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build and install AUR packages
|
||||||
|
|
||||||
|
# Build package in dir. install=1 to install after build.
|
||||||
|
# asdeps=1 to mark as dependency.
|
||||||
|
build_pkg() {
|
||||||
|
local dir=$1
|
||||||
|
local do_install=${2:-1}
|
||||||
|
local asdeps=${3:-0}
|
||||||
|
local name
|
||||||
|
name=$(basename "$dir")
|
||||||
|
|
||||||
|
msg "Building $name..."
|
||||||
|
(
|
||||||
|
cd "$dir" || exit 1
|
||||||
|
# Clear previous package files to avoid installing stale ones
|
||||||
|
rm -f ./*.pkg.tar.* 2>/dev/null || true
|
||||||
|
local -a mflags=()
|
||||||
|
# shellcheck disable=SC2206
|
||||||
|
mflags=(${MIAUR_MFLAGS})
|
||||||
|
# If MFLAGS contains -si we handle install ourselves more carefully
|
||||||
|
local -a clean_flags=()
|
||||||
|
local f
|
||||||
|
for f in "${mflags[@]}"; do
|
||||||
|
case "$f" in
|
||||||
|
-i | --install | -si | -is) ;;
|
||||||
|
*) clean_flags+=("$f") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
# Always sync deps for repo side via makepkg -s when needed
|
||||||
|
${MIAUR_MAKEPKG} -s --noconfirm "${clean_flags[@]}" || exit 1
|
||||||
|
) || die "build failed: $name"
|
||||||
|
|
||||||
|
if [[ $do_install -eq 1 ]]; then
|
||||||
|
local -a pkgs=()
|
||||||
|
mapfile -t pkgs < <(find "$dir" -maxdepth 1 -type f \( -name '*.pkg.tar.zst' -o -name '*.pkg.tar.xz' -o -name '*.pkg.tar.gz' \) ! -name '*-debug-*' | sort)
|
||||||
|
[[ ${#pkgs[@]} -eq 0 ]] && die "no build artifacts found: $name"
|
||||||
|
msg "Installing $name..."
|
||||||
|
local -a uflags=(-U --noconfirm)
|
||||||
|
[[ $asdeps -eq 1 ]] && uflags+=(--asdeps)
|
||||||
|
as_root ${MIAUR_PACMAN} "${uflags[@]}" "${pkgs[@]}" || die "installation failed: $name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${MIAUR_CLEANAFTER:-0} -eq 1 ]]; then
|
||||||
|
msg2 "Cleaning build directory: $dir"
|
||||||
|
rm -rf "$dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Full install pipeline for AUR package names (and their AUR deps)
|
||||||
|
# Targets are package names.
|
||||||
|
install_aur_packages() {
|
||||||
|
local -a targets=("$@")
|
||||||
|
[[ ${#targets[@]} -eq 0 ]] && return 0
|
||||||
|
|
||||||
|
need_cmd curl jq git makepkg pacman
|
||||||
|
|
||||||
|
sudoloop_start
|
||||||
|
|
||||||
|
msg "Resolving dependencies..."
|
||||||
|
local -a order=()
|
||||||
|
mapfile -t order < <(aur_resolve_order "${targets[@]}")
|
||||||
|
[[ ${#order[@]} -eq 0 ]] && die "no packages to install"
|
||||||
|
|
||||||
|
# Collect all repo deps across the graph
|
||||||
|
local -a repo_deps=()
|
||||||
|
local pkg dir line
|
||||||
|
declare -A repo_seen=()
|
||||||
|
for pkg in "${order[@]}"; do
|
||||||
|
dir=$(pkg_clone_dir "$pkg")
|
||||||
|
[[ -d $dir ]] || dir=$(aur_clone "$pkg")
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
repo\|*)
|
||||||
|
local rn=${line#repo|}
|
||||||
|
[[ -n ${repo_seen[$rn]+x} ]] && continue
|
||||||
|
repo_seen[$rn]=1
|
||||||
|
repo_deps+=("$rn")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <(collect_deps_for_dir "$dir" 1 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
install_repo_deps "${repo_deps[@]}"
|
||||||
|
|
||||||
|
# Review all packages first (like paru)
|
||||||
|
local -a build_list=()
|
||||||
|
for pkg in "${order[@]}"; do
|
||||||
|
dir=$(pkg_clone_dir "$pkg")
|
||||||
|
[[ -d $dir ]] || dir=$(aur_clone "$pkg")
|
||||||
|
local rc=0
|
||||||
|
review_pkgbuild "$dir" "$pkg" || rc=$?
|
||||||
|
if [[ $rc -eq 1 ]]; then
|
||||||
|
die "installation cancelled"
|
||||||
|
elif [[ $rc -eq 2 ]]; then
|
||||||
|
warn "Skipping $pkg"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
build_list+=("$pkg")
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ ${#build_list[@]} -eq 0 ]] && die "no packages to build"
|
||||||
|
|
||||||
|
# Explicit install targets (deps marked --asdeps)
|
||||||
|
declare -A is_target=()
|
||||||
|
for pkg in "${targets[@]}"; do
|
||||||
|
is_target[$pkg]=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Track make deps for optional removal (names from srcinfo)
|
||||||
|
local -a make_pkgs=()
|
||||||
|
declare -A make_seen=()
|
||||||
|
if [[ ${MIAUR_REMOVEMAKE:-0} -eq 1 ]]; then
|
||||||
|
for pkg in "${build_list[@]}"; do
|
||||||
|
dir=$(pkg_clone_dir "$pkg")
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
makedepend\|*)
|
||||||
|
local mn
|
||||||
|
mn=$(dep_name "${line#makedepend|}")
|
||||||
|
[[ -n ${is_target[$mn]+x} ]] && continue
|
||||||
|
[[ -n ${make_seen[$mn]+x} ]] && continue
|
||||||
|
make_seen[$mn]=1
|
||||||
|
make_pkgs+=("$mn")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <(srcinfo_dump "$dir")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
for pkg in "${build_list[@]}"; do
|
||||||
|
dir=$(pkg_clone_dir "$pkg")
|
||||||
|
local asdeps=0
|
||||||
|
[[ -z ${is_target[$pkg]+x} ]] && asdeps=1
|
||||||
|
# Skip if already up to date
|
||||||
|
if is_pkg_installed "$pkg"; then
|
||||||
|
local localver aurver
|
||||||
|
localver=$(pkg_local_version "$pkg")
|
||||||
|
aurver=$(jq -r '.Version // empty' <<<"$(aur_info_json "$pkg")" 2>/dev/null || true)
|
||||||
|
if [[ -n $aurver && $localver == "$aurver" && -z ${is_target[$pkg]+x} ]]; then
|
||||||
|
msg2 "$pkg is up to date ($localver)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
build_pkg "$dir" 1 "$asdeps"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove make depends that were installed as deps and not needed
|
||||||
|
if [[ ${MIAUR_REMOVEMAKE:-0} -eq 1 && ${#make_pkgs[@]} -gt 0 ]]; then
|
||||||
|
local -a to_rm=()
|
||||||
|
local m
|
||||||
|
for m in "${make_pkgs[@]}"; do
|
||||||
|
# Only remove if installed as dependency and not required
|
||||||
|
if pacman -Qdtq 2>/dev/null | grep -qx "$m"; then
|
||||||
|
to_rm+=("$m")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ ${#to_rm[@]} -gt 0 ]]; then
|
||||||
|
msg "Removing make dependencies: ${to_rm[*]}"
|
||||||
|
as_root ${MIAUR_PACMAN} -Rns --noconfirm "${to_rm[@]}" || warn "failed to remove make dependencies"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudoloop_stop
|
||||||
|
msg "Done"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build from local directories containing PKGBUILD
|
||||||
|
build_local_dirs() {
|
||||||
|
local do_install=${1:-0}
|
||||||
|
shift
|
||||||
|
local -a dirs=("$@")
|
||||||
|
local d
|
||||||
|
for d in "${dirs[@]}"; do
|
||||||
|
[[ -d $d ]] || die "directory does not exist: $d"
|
||||||
|
[[ -f $d/PKGBUILD ]] || die "PKGBUILD not found: $d"
|
||||||
|
# Resolve AUR deps of local pkgbuild
|
||||||
|
local -a aur_deps=()
|
||||||
|
local line
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
aur\|*) aur_deps+=("${line#aur|}") ;;
|
||||||
|
missing\|*) die "unable to resolve dependency: ${line#missing|}" ;;
|
||||||
|
repo\|*) ;;
|
||||||
|
esac
|
||||||
|
done < <(collect_deps_for_dir "$d" 1 1)
|
||||||
|
if [[ ${#aur_deps[@]} -gt 0 ]]; then
|
||||||
|
install_aur_packages "${aur_deps[@]}"
|
||||||
|
fi
|
||||||
|
# Install repo deps
|
||||||
|
local -a rd=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
repo\|*) rd+=("${line#repo|}") ;;
|
||||||
|
esac
|
||||||
|
done < <(collect_deps_for_dir "$d" 1 1)
|
||||||
|
install_repo_deps "${rd[@]}"
|
||||||
|
review_pkgbuild "$d" "$(basename "$d")" || die "cancelled"
|
||||||
|
build_pkg "$d" "$do_install" 0
|
||||||
|
done
|
||||||
|
}
|
||||||
+202
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# CLI parsing — paru-like short option clusters
|
||||||
|
|
||||||
|
# Globals set by parse_args
|
||||||
|
OP= # S Q R G B P D F T U none interactive
|
||||||
|
OP_REFRESH=0 # y
|
||||||
|
OP_UPGRADE=0 # u
|
||||||
|
OP_SEARCH=0 # s (count)
|
||||||
|
OP_INFO=0 # i
|
||||||
|
OP_CLEAN=0 # c
|
||||||
|
OP_AUR_ONLY=0 # a (with S/Q)
|
||||||
|
OP_PRINT=0 # -p for -G
|
||||||
|
OP_BUILD_INSTALL=0 # -i for -B
|
||||||
|
TARGETS=()
|
||||||
|
PACMAN_EXTRA=() # leftover short flags for pacman passthrough
|
||||||
|
DO_PASSTHRU=0
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
miaur
|
||||||
|
miaur <operation> [...]
|
||||||
|
miaur <search terms>
|
||||||
|
|
||||||
|
miaur is a pure-shell AUR helper with paru-like everyday commands.
|
||||||
|
|
||||||
|
Pacman operations extended with AUR support:
|
||||||
|
miaur {-h --help}
|
||||||
|
miaur {-V --version}
|
||||||
|
miaur {-Q --query} [options] [packages]
|
||||||
|
miaur {-R --remove} [options] <packages>
|
||||||
|
miaur {-S --sync} [options] [packages]
|
||||||
|
miaur {-U --upgrade} [options] <files>
|
||||||
|
|
||||||
|
Additional operations:
|
||||||
|
miaur {-G --getpkgbuild} [packages]
|
||||||
|
miaur {-B --build} [directories]
|
||||||
|
|
||||||
|
With no arguments, miaur runs 'miaur -Syu'.
|
||||||
|
|
||||||
|
Common commands:
|
||||||
|
miaur -Syu Upgrade repository and AUR packages
|
||||||
|
miaur -Sua Upgrade AUR packages only
|
||||||
|
miaur -S <package> Install from a repository or the AUR
|
||||||
|
miaur -Ss <query> Search packages
|
||||||
|
miaur -Si <package> Show package information
|
||||||
|
miaur -Qua List available AUR upgrades
|
||||||
|
miaur -G <package> Download a PKGBUILD
|
||||||
|
miaur -Gp <package> Print a PKGBUILD
|
||||||
|
miaur -Bi . Build and install a local PKGBUILD
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-a, --aur Assume targets are from the AUR
|
||||||
|
--repo Assume targets are from repositories
|
||||||
|
--skipreview Skip PKGBUILD review
|
||||||
|
--cleanafter Remove build sources after installation
|
||||||
|
--[no]removemake Remove make dependencies after installation
|
||||||
|
--bottomup Show AUR results first
|
||||||
|
--topdown Show repository results first (default)
|
||||||
|
--clonedir <path> Set the PKGBUILD clone directory
|
||||||
|
--mflags <flags> Pass additional flags to makepkg
|
||||||
|
--sudoloop Keep sudo credentials alive (default)
|
||||||
|
--nosudoloop Disable the sudo keep-alive loop
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_args() {
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
OP=S
|
||||||
|
OP_REFRESH=1
|
||||||
|
OP_UPGRADE=1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# No leading dash → interactive search
|
||||||
|
if [[ $1 != -* ]]; then
|
||||||
|
OP=interactive
|
||||||
|
TARGETS=("$@")
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local -a raw=("$@")
|
||||||
|
local i=0
|
||||||
|
while ((i < ${#raw[@]})); do
|
||||||
|
local arg=${raw[$i]}
|
||||||
|
case "$arg" in
|
||||||
|
-h | --help)
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-V | --version)
|
||||||
|
printf 'miaur v%s\n' "$MIAUR_VERSION"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--aur)
|
||||||
|
OP_AUR_ONLY=1
|
||||||
|
MIAUR_MODE=aur
|
||||||
|
;;
|
||||||
|
--repo)
|
||||||
|
MIAUR_MODE=repo
|
||||||
|
;;
|
||||||
|
--skipreview) MIAUR_SKIPREVIEW=1 ;;
|
||||||
|
--review) MIAUR_SKIPREVIEW=0 ;;
|
||||||
|
--cleanafter) MIAUR_CLEANAFTER=1 ;;
|
||||||
|
--nocleanafter) MIAUR_CLEANAFTER=0 ;;
|
||||||
|
--removemake) MIAUR_REMOVEMAKE=1 ;;
|
||||||
|
--noremovermake) MIAUR_REMOVEMAKE=0 ;;
|
||||||
|
--bottomup) MIAUR_BOTTOMUP=1 ;;
|
||||||
|
--topdown) MIAUR_BOTTOMUP=0 ;;
|
||||||
|
--sudoloop) MIAUR_SUDOLOOP=1 ;;
|
||||||
|
--nosudoloop) MIAUR_SUDOLOOP=0 ;;
|
||||||
|
--clonedir)
|
||||||
|
i=$((i + 1))
|
||||||
|
MIAUR_CLONEDIR=${raw[$i]:-}
|
||||||
|
[[ -n $MIAUR_CLONEDIR ]] || die "--clonedir requires a path"
|
||||||
|
;;
|
||||||
|
--clonedir=*) MIAUR_CLONEDIR=${arg#*=} ;;
|
||||||
|
--mflags)
|
||||||
|
i=$((i + 1))
|
||||||
|
MIAUR_MFLAGS=${raw[$i]:-}
|
||||||
|
;;
|
||||||
|
--mflags=*) MIAUR_MFLAGS=${arg#*=} ;;
|
||||||
|
--mode)
|
||||||
|
i=$((i + 1))
|
||||||
|
MIAUR_MODE=${raw[$i]:-}
|
||||||
|
;;
|
||||||
|
--mode=*) MIAUR_MODE=${arg#*=} ;;
|
||||||
|
--sync) OP=S ;;
|
||||||
|
--query) OP=Q ;;
|
||||||
|
--remove)
|
||||||
|
OP=R
|
||||||
|
DO_PASSTHRU=1
|
||||||
|
;;
|
||||||
|
--getpkgbuild) OP=G ;;
|
||||||
|
--build) OP=B ;;
|
||||||
|
--database | --files | --deptest | --upgrade)
|
||||||
|
DO_PASSTHRU=1
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
i=$((i + 1))
|
||||||
|
while ((i < ${#raw[@]})); do
|
||||||
|
TARGETS+=("${raw[$i]}")
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
local cluster=${arg:1}
|
||||||
|
local j c
|
||||||
|
for ((j = 0; j < ${#cluster}; j++)); do
|
||||||
|
c=${cluster:j:1}
|
||||||
|
case "$c" in
|
||||||
|
S) OP=S ;;
|
||||||
|
Q) OP=Q ;;
|
||||||
|
R)
|
||||||
|
OP=R
|
||||||
|
DO_PASSTHRU=1
|
||||||
|
;;
|
||||||
|
G) OP=G ;;
|
||||||
|
B) OP=B ;;
|
||||||
|
D | F | T | U) DO_PASSTHRU=1 ;;
|
||||||
|
y) OP_REFRESH=1 ;;
|
||||||
|
u) OP_UPGRADE=1 ;;
|
||||||
|
s) OP_SEARCH=$((OP_SEARCH + 1)) ;;
|
||||||
|
i)
|
||||||
|
if [[ $OP == B ]]; then
|
||||||
|
OP_BUILD_INSTALL=1
|
||||||
|
else
|
||||||
|
OP_INFO=1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
c) OP_CLEAN=1 ;;
|
||||||
|
a)
|
||||||
|
OP_AUR_ONLY=1
|
||||||
|
MIAUR_MODE=aur
|
||||||
|
;;
|
||||||
|
p)
|
||||||
|
if [[ $OP == G ]]; then
|
||||||
|
OP_PRINT=1
|
||||||
|
else
|
||||||
|
PACMAN_EXTRA+=("$c")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
V)
|
||||||
|
printf 'miaur v%s\n' "$MIAUR_VERSION"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*) PACMAN_EXTRA+=("$c") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
TARGETS+=("$arg")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Clone / update AUR package sources
|
||||||
|
|
||||||
|
pkg_clone_dir() {
|
||||||
|
local name=$1
|
||||||
|
printf '%s/%s' "${MIAUR_CLONEDIR}" "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clone or pull package; prints absolute path to clone dir
|
||||||
|
aur_clone() {
|
||||||
|
local name=$1
|
||||||
|
local dir
|
||||||
|
dir=$(pkg_clone_dir "$name")
|
||||||
|
mkdir -p "$MIAUR_CLONEDIR"
|
||||||
|
if [[ -d $dir/.git ]]; then
|
||||||
|
msg2 "Updating $name..."
|
||||||
|
if ! (cd "$dir" && ${MIAUR_GIT} pull --ff-only --quiet); then
|
||||||
|
warn "Cannot fast-forward $name; cloning it again"
|
||||||
|
rm -rf "$dir"
|
||||||
|
${MIAUR_GIT} clone --quiet "${MIAUR_AURURL}/${name}.git" "$dir" || die "clone failed: $name"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rm -rf "$dir"
|
||||||
|
msg2 "Cloning $name..."
|
||||||
|
${MIAUR_GIT} clone --quiet "${MIAUR_AURURL}/${name}.git" "$dir" || die "clone failed: $name"
|
||||||
|
fi
|
||||||
|
[[ -f $dir/PKGBUILD ]] || die "PKGBUILD not found after cloning: $name"
|
||||||
|
printf '%s\n' "$dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean clone cache for one package or all
|
||||||
|
aur_clean_cache() {
|
||||||
|
local target=${1:-}
|
||||||
|
if [[ -n $target ]]; then
|
||||||
|
local dir
|
||||||
|
dir=$(pkg_clone_dir "$target")
|
||||||
|
if [[ -d $dir ]]; then
|
||||||
|
msg "Cleaning cache: $dir"
|
||||||
|
rm -rf "$dir"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ -d $MIAUR_CLONEDIR ]]; then
|
||||||
|
msg "Cleaning AUR cache: $MIAUR_CLONEDIR"
|
||||||
|
# Keep VCS src dirs? Plan says clean clone cache — remove package dirs
|
||||||
|
find "$MIAUR_CLONEDIR" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} +
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
# Common utilities for miaur
|
||||||
|
|
||||||
|
MIAUR_VERSION="0.1.0"
|
||||||
|
|
||||||
|
# Colors (respect pacman Color / NO_COLOR / non-tty)
|
||||||
|
_miaur_color_enabled() {
|
||||||
|
[[ -n ${NO_COLOR:-} ]] && return 1
|
||||||
|
[[ ! -t 1 ]] && return 1
|
||||||
|
if [[ -f /etc/pacman.conf ]] && grep -Eq '^[[:space:]]*Color([[:space:]]|$)' /etc/pacman.conf 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
# Default: enable on tty even if pacman Color is commented
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if _miaur_color_enabled; then
|
||||||
|
C_RED=$'\033[31m'
|
||||||
|
C_GREEN=$'\033[32m'
|
||||||
|
C_YELLOW=$'\033[33m'
|
||||||
|
C_BLUE=$'\033[34m'
|
||||||
|
C_CYAN=$'\033[36m'
|
||||||
|
C_BOLD=$'\033[1m'
|
||||||
|
C_DIM=$'\033[2m'
|
||||||
|
C_RESET=$'\033[0m'
|
||||||
|
else
|
||||||
|
C_RED= C_GREEN= C_YELLOW= C_BLUE= C_CYAN= C_BOLD= C_DIM= C_RESET=
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg() { printf '%s::%s %s\n' "${C_BOLD}${C_BLUE}" "${C_RESET}" "$*" >&2; }
|
||||||
|
msg2() { printf '%s ->%s %s\n' "${C_BOLD}${C_BLUE}" "${C_RESET}" "$*" >&2; }
|
||||||
|
warn() { printf '%s==>%s WARNING: %s\n' "${C_BOLD}${C_YELLOW}" "${C_RESET}" "$*" >&2; }
|
||||||
|
error() { printf '%s==>%s ERROR: %s\n' "${C_BOLD}${C_RED}" "${C_RESET}" "$*" >&2; }
|
||||||
|
die() { error "$*"; exit 1; }
|
||||||
|
|
||||||
|
need_cmd() {
|
||||||
|
local c
|
||||||
|
for c in "$@"; do
|
||||||
|
command -v "$c" >/dev/null 2>&1 || die "required command not found: $c"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prefer system curl — some user PATH wrappers break AUR HTTPS
|
||||||
|
resolve_curl() {
|
||||||
|
if [[ -n ${MIAUR_CURL:-} ]]; then
|
||||||
|
printf '%s' "$MIAUR_CURL"
|
||||||
|
elif [[ -x /usr/bin/curl ]]; then
|
||||||
|
printf '%s' /usr/bin/curl
|
||||||
|
else
|
||||||
|
command -v curl
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Strip version constraints from a dep string: foo>=1.0 -> foo
|
||||||
|
dep_name() {
|
||||||
|
local d=$1
|
||||||
|
d=${d%%[><=]*}
|
||||||
|
d=${d%%:*}
|
||||||
|
printf '%s' "$d"
|
||||||
|
}
|
||||||
|
|
||||||
|
vercmp_safe() {
|
||||||
|
# pacman --print returns 0 if equal, 1 if first >, -1 if second >
|
||||||
|
/usr/bin/vercmp "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_pkg_installed() {
|
||||||
|
pacman -Q "$1" &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg_local_version() {
|
||||||
|
pacman -Q "$1" 2>/dev/null | awk '{print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run command as root via sudo
|
||||||
|
as_root() {
|
||||||
|
if [[ ${EUID:-$(id -u)} -eq 0 ]]; then
|
||||||
|
"$@"
|
||||||
|
else
|
||||||
|
${MIAUR_SUDO:-sudo} ${MIAUR_SUDOFLAGS:-} "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep sudo credentials alive in background
|
||||||
|
_sudo_loop_pid=
|
||||||
|
sudoloop_start() {
|
||||||
|
[[ ${MIAUR_SUDOLOOP:-0} -eq 1 ]] || return 0
|
||||||
|
[[ ${EUID:-$(id -u)} -eq 0 ]] && return 0
|
||||||
|
${MIAUR_SUDO:-sudo} -v || return 1
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
sleep 60
|
||||||
|
${MIAUR_SUDO:-sudo} -v || exit
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
_sudo_loop_pid=$!
|
||||||
|
}
|
||||||
|
|
||||||
|
sudoloop_stop() {
|
||||||
|
if [[ -n ${_sudo_loop_pid:-} ]]; then
|
||||||
|
kill "$_sudo_loop_pid" 2>/dev/null || true
|
||||||
|
wait "$_sudo_loop_pid" 2>/dev/null || true
|
||||||
|
_sudo_loop_pid=
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap sudoloop_stop EXIT
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Config defaults and loader for miaur
|
||||||
|
|
||||||
|
# Defaults
|
||||||
|
MIAUR_AURURL="${MIAUR_AURURL:-https://aur.archlinux.org}"
|
||||||
|
MIAUR_AURRPC="${MIAUR_AURRPC:-https://aur.archlinux.org/rpc/v5}"
|
||||||
|
MIAUR_CLONEDIR="${MIAUR_CLONEDIR:-${XDG_CACHE_HOME:-$HOME/.cache}/miaur}"
|
||||||
|
MIAUR_SKIPREVIEW="${MIAUR_SKIPREVIEW:-0}"
|
||||||
|
MIAUR_CLEANAFTER="${MIAUR_CLEANAFTER:-0}"
|
||||||
|
MIAUR_REMOVEMAKE="${MIAUR_REMOVEMAKE:-1}"
|
||||||
|
MIAUR_BOTTOMUP="${MIAUR_BOTTOMUP:-0}"
|
||||||
|
MIAUR_SUDOLOOP="${MIAUR_SUDOLOOP:-1}"
|
||||||
|
MIAUR_MFLAGS="${MIAUR_MFLAGS:--si}"
|
||||||
|
MIAUR_SORTBY="${MIAUR_SORTBY:-votes}"
|
||||||
|
MIAUR_SEARCHBY="${MIAUR_SEARCHBY:-name-desc}"
|
||||||
|
MIAUR_MODE="${MIAUR_MODE:-}" # aur|repo|empty=both
|
||||||
|
MIAUR_SUDO="${MIAUR_SUDO:-sudo}"
|
||||||
|
MIAUR_SUDOFLAGS="${MIAUR_SUDOFLAGS:-}"
|
||||||
|
MIAUR_GIT="${MIAUR_GIT:-git}"
|
||||||
|
MIAUR_MAKEPKG="${MIAUR_MAKEPKG:-makepkg}"
|
||||||
|
MIAUR_PACMAN="${MIAUR_PACMAN:-pacman}"
|
||||||
|
MIAUR_BAT="${MIAUR_BAT:-bat}"
|
||||||
|
MIAUR_EDITOR="${VISUAL:-${EDITOR:-nano}}"
|
||||||
|
|
||||||
|
_bool_val() {
|
||||||
|
case "${1,,}" in
|
||||||
|
1 | true | yes | on) printf '1' ;;
|
||||||
|
0 | false | no | off) printf '0' ;;
|
||||||
|
*) printf '%s' "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
miaur_load_config() {
|
||||||
|
local conf="${XDG_CONFIG_HOME:-$HOME/.config}/miaur/miaur.conf"
|
||||||
|
[[ -f $conf ]] || return 0
|
||||||
|
local line key val
|
||||||
|
while IFS= read -r line || [[ -n $line ]]; do
|
||||||
|
line=${line%%#*}
|
||||||
|
line=${line#"${line%%[![:space:]]*}"}
|
||||||
|
line=${line%"${line##*[![:space:]]}"}
|
||||||
|
[[ -z $line ]] && continue
|
||||||
|
key=${line%%=*}
|
||||||
|
val=${line#*=}
|
||||||
|
key=${key%"${key##*[![:space:]]}"}
|
||||||
|
key=${key#"${key%%[![:space:]]*}"}
|
||||||
|
val=${val#"${val%%[![:space:]]*}"}
|
||||||
|
val=${val%"${val##*[![:space:]]}"}
|
||||||
|
val=${val#\"}
|
||||||
|
val=${val%\"}
|
||||||
|
val=${val#\'}
|
||||||
|
val=${val%\'}
|
||||||
|
case "$key" in
|
||||||
|
AurUrl | AURURL) MIAUR_AURURL=$val ;;
|
||||||
|
AurRpcUrl | AURRPC) MIAUR_AURRPC=$val ;;
|
||||||
|
CloneDir)
|
||||||
|
MIAUR_CLONEDIR=$val
|
||||||
|
[[ $MIAUR_CLONEDIR == ~* ]] && MIAUR_CLONEDIR="${MIAUR_CLONEDIR/#\~/$HOME}"
|
||||||
|
;;
|
||||||
|
SkipReview) MIAUR_SKIPREVIEW=$(_bool_val "$val") ;;
|
||||||
|
CleanAfter) MIAUR_CLEANAFTER=$(_bool_val "$val") ;;
|
||||||
|
RemoveMake) MIAUR_REMOVEMAKE=$(_bool_val "$val") ;;
|
||||||
|
BottomUp) MIAUR_BOTTOMUP=$(_bool_val "$val") ;;
|
||||||
|
SudoLoop) MIAUR_SUDOLOOP=$(_bool_val "$val") ;;
|
||||||
|
MFlags) MIAUR_MFLAGS=$val ;;
|
||||||
|
SortBy) MIAUR_SORTBY=$val ;;
|
||||||
|
SearchBy) MIAUR_SEARCHBY=$val ;;
|
||||||
|
Sudo) MIAUR_SUDO=$val ;;
|
||||||
|
SudoFlags) MIAUR_SUDOFLAGS=$val ;;
|
||||||
|
Git) MIAUR_GIT=$val ;;
|
||||||
|
Makepkg) MIAUR_MAKEPKG=$val ;;
|
||||||
|
Pacman) MIAUR_PACMAN=$val ;;
|
||||||
|
Bat) MIAUR_BAT=$val ;;
|
||||||
|
Editor) MIAUR_EDITOR=$val ;;
|
||||||
|
esac
|
||||||
|
done <"$conf"
|
||||||
|
}
|
||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Dependency resolution from .SRCINFO / makepkg --printsrcinfo
|
||||||
|
|
||||||
|
# Parse srcinfo from directory into globals via stdout lines:
|
||||||
|
# pkgbase|NAME
|
||||||
|
# pkgname|NAME
|
||||||
|
# depend|DEP
|
||||||
|
# makedepend|DEP
|
||||||
|
# checkdepend|DEP
|
||||||
|
srcinfo_dump() {
|
||||||
|
local dir=$1
|
||||||
|
(
|
||||||
|
cd "$dir" || exit 1
|
||||||
|
${MIAUR_MAKEPKG} --printsrcinfo 2>/dev/null
|
||||||
|
) | awk '
|
||||||
|
/^pkgbase = / { print "pkgbase|" $3 }
|
||||||
|
/^[[:space:]]*pkgname = / { print "pkgname|" $3 }
|
||||||
|
/^[[:space:]]*depends = / { print "depend|" $3 }
|
||||||
|
/^[[:space:]]*makedepends = / { print "makedepend|" $3 }
|
||||||
|
/^[[:space:]]*checkdepends = / { print "checkdepend|" $3 }
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns 0 if dep is satisfied (installed or provided by installed pkg)
|
||||||
|
dep_satisfied() {
|
||||||
|
local dep name
|
||||||
|
name=$(dep_name "$1")
|
||||||
|
# pacman -T returns unsatisfied deps; empty means all ok
|
||||||
|
local out
|
||||||
|
out=$(pacman -T "$1" 2>/dev/null) || true
|
||||||
|
[[ -z $out ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Is package available in sync repos?
|
||||||
|
repo_has_pkg() {
|
||||||
|
pacman -Si "$1" &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve whether a dep name is in AUR (not in repos, or --aur mode)
|
||||||
|
# Sets: REPO_DEPS[] AUR_DEPS[] (caller-managed arrays passed by name)
|
||||||
|
# resolve_one_dep name -> echoes "repo:name" or "aur:name" or "ok" or "missing:name"
|
||||||
|
resolve_one_dep() {
|
||||||
|
local raw=$1
|
||||||
|
local name
|
||||||
|
name=$(dep_name "$raw")
|
||||||
|
if dep_satisfied "$raw"; then
|
||||||
|
echo "ok"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ ${MIAUR_MODE:-} != aur ]] && repo_has_pkg "$name"; then
|
||||||
|
echo "repo:$name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ ${MIAUR_MODE:-} != repo ]] && aur_exists "$name"; then
|
||||||
|
echo "aur:$name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
# Try provides via pacman -Ssq exact? fallback AUR search by name
|
||||||
|
if [[ ${MIAUR_MODE:-} != repo ]] && aur_exists "$name"; then
|
||||||
|
echo "aur:$name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "missing:$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Collect all deps for a cloned package dir into named arrays via stdout
|
||||||
|
# Format lines: repo|pkg / aur|pkg / missing|pkg
|
||||||
|
collect_deps_for_dir() {
|
||||||
|
local dir=$1
|
||||||
|
local include_make=${2:-1}
|
||||||
|
local include_check=${3:-1}
|
||||||
|
local line kind val
|
||||||
|
declare -A seen=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
kind=${line%%|*}
|
||||||
|
val=${line#*|}
|
||||||
|
case "$kind" in
|
||||||
|
depend) ;;
|
||||||
|
makedepend) [[ $include_make -eq 1 ]] || continue ;;
|
||||||
|
checkdepend) [[ $include_check -eq 1 ]] || continue ;;
|
||||||
|
*) continue ;;
|
||||||
|
esac
|
||||||
|
local name
|
||||||
|
name=$(dep_name "$val")
|
||||||
|
[[ -n ${seen[$name]+x} ]] && continue
|
||||||
|
seen[$name]=1
|
||||||
|
local r
|
||||||
|
r=$(resolve_one_dep "$val")
|
||||||
|
case "$r" in
|
||||||
|
ok) ;;
|
||||||
|
repo:*) echo "repo|${r#repo:}" ;;
|
||||||
|
aur:*) echo "aur|${r#aur:}" ;;
|
||||||
|
missing:*) echo "missing|${r#missing:}" ;;
|
||||||
|
esac
|
||||||
|
done < <(srcinfo_dump "$dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Recursively expand AUR deps for a list of package names.
|
||||||
|
# Prints ordered AUR package names (dependencies first).
|
||||||
|
# Uses DFS + topo-ish order.
|
||||||
|
aur_resolve_order() {
|
||||||
|
local -a roots=("$@")
|
||||||
|
declare -A visiting=() visited=()
|
||||||
|
local -a order=()
|
||||||
|
|
||||||
|
_visit() {
|
||||||
|
local pkg=$1
|
||||||
|
[[ -n ${visited[$pkg]+x} ]] && return 0
|
||||||
|
if [[ -n ${visiting[$pkg]+x} ]]; then
|
||||||
|
warn "Dependency cycle detected at: $pkg"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
visiting[$pkg]=1
|
||||||
|
local dir
|
||||||
|
dir=$(aur_clone "$pkg") || die "failed to fetch dependency: $pkg"
|
||||||
|
local line
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
aur\|*)
|
||||||
|
_visit "${line#aur|}"
|
||||||
|
;;
|
||||||
|
missing\|*)
|
||||||
|
die "unable to resolve dependency ${line#missing|} required by $pkg"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <(collect_deps_for_dir "$dir" 1 1)
|
||||||
|
unset 'visiting[$pkg]'
|
||||||
|
visited[$pkg]=1
|
||||||
|
order+=("$pkg")
|
||||||
|
}
|
||||||
|
|
||||||
|
local r
|
||||||
|
for r in "${roots[@]}"; do
|
||||||
|
_visit "$r"
|
||||||
|
done
|
||||||
|
printf '%s\n' "${order[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install repo packages as deps
|
||||||
|
install_repo_deps() {
|
||||||
|
local -a pkgs=("$@")
|
||||||
|
[[ ${#pkgs[@]} -eq 0 ]] && return 0
|
||||||
|
# Dedup
|
||||||
|
local -A u=()
|
||||||
|
local p
|
||||||
|
local -a list=()
|
||||||
|
for p in "${pkgs[@]}"; do
|
||||||
|
[[ -n ${u[$p]+x} ]] && continue
|
||||||
|
u[$p]=1
|
||||||
|
is_pkg_installed "$p" && continue
|
||||||
|
list+=("$p")
|
||||||
|
done
|
||||||
|
[[ ${#list[@]} -eq 0 ]] && return 0
|
||||||
|
msg "Installing repository dependencies: ${list[*]}"
|
||||||
|
as_root ${MIAUR_PACMAN} -S --needed --asdeps --noconfirm "${list[@]}"
|
||||||
|
}
|
||||||
+298
@@ -0,0 +1,298 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Dispatch handlers for miaur operations
|
||||||
|
|
||||||
|
# Reconstruct pacman argv from OP + PACMAN_EXTRA + targets for passthrough
|
||||||
|
pacman_passthru() {
|
||||||
|
local -a args=("$@")
|
||||||
|
as_root ${MIAUR_PACMAN} "${args[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Search repo + AUR
|
||||||
|
cmd_search() {
|
||||||
|
local -a terms=("$@")
|
||||||
|
[[ ${#terms[@]} -eq 0 ]] && die "specify a search query"
|
||||||
|
local query="${terms[*]}"
|
||||||
|
|
||||||
|
local -a repo_lines=() aur_lines=()
|
||||||
|
|
||||||
|
if [[ ${MIAUR_MODE:-} != aur ]]; then
|
||||||
|
mapfile -t repo_lines < <(${MIAUR_PACMAN} -Ss "$query" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${MIAUR_MODE:-} != repo ]]; then
|
||||||
|
local line name ver votes pop desc
|
||||||
|
while IFS='|' read -r name ver votes pop desc; do
|
||||||
|
[[ -z $name ]] && continue
|
||||||
|
aur_lines+=("$(aur_format_search_line "$name" "$ver" "$votes" "$pop" "$desc")")
|
||||||
|
done < <(aur_search "$query" || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${MIAUR_BOTTOMUP:-0} -eq 1 ]]; then
|
||||||
|
local l
|
||||||
|
for l in "${aur_lines[@]}"; do printf '%b\n' "$l"; done
|
||||||
|
[[ ${#repo_lines[@]} -gt 0 && ${#aur_lines[@]} -gt 0 ]] && echo
|
||||||
|
local r
|
||||||
|
for r in "${repo_lines[@]}"; do printf '%s\n' "$r"; done
|
||||||
|
else
|
||||||
|
local r
|
||||||
|
for r in "${repo_lines[@]}"; do printf '%s\n' "$r"; done
|
||||||
|
[[ ${#repo_lines[@]} -gt 0 && ${#aur_lines[@]} -gt 0 ]] && echo
|
||||||
|
local l
|
||||||
|
for l in "${aur_lines[@]}"; do printf '%b\n' "$l"; done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Interactive search + install (like `paru foo`)
|
||||||
|
cmd_interactive() {
|
||||||
|
local query="$*"
|
||||||
|
[[ -z $query ]] && die "specify a search query"
|
||||||
|
|
||||||
|
local -a entries=() # type|name
|
||||||
|
local -a display=()
|
||||||
|
|
||||||
|
# Repo results
|
||||||
|
if [[ ${MIAUR_MODE:-} != aur ]]; then
|
||||||
|
local line repo name rest
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ $line =~ ^([a-z0-9_-]+)/([^[:space:]]+) ]] || continue
|
||||||
|
repo=${BASH_REMATCH[1]}
|
||||||
|
name=${BASH_REMATCH[2]}
|
||||||
|
entries+=("repo|$name")
|
||||||
|
display+=("${C_BOLD}${C_BLUE}${repo}/${name}${C_RESET}")
|
||||||
|
done < <(${MIAUR_PACMAN} -Ss "$query" 2>/dev/null | grep -E '^[a-z0-9_-]+/' || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# AUR results
|
||||||
|
if [[ ${MIAUR_MODE:-} != repo ]]; then
|
||||||
|
local name ver votes pop desc
|
||||||
|
while IFS='|' read -r name ver votes pop desc; do
|
||||||
|
[[ -z $name ]] && continue
|
||||||
|
entries+=("aur|$name")
|
||||||
|
display+=("${C_BOLD}${C_CYAN}aur/${name}${C_RESET} ${ver} (${votes})")
|
||||||
|
done < <(aur_search "$query" || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ ${#entries[@]} -eq 0 ]] && die "no matches found: $query"
|
||||||
|
|
||||||
|
local i
|
||||||
|
if [[ ${MIAUR_BOTTOMUP:-0} -eq 1 ]]; then
|
||||||
|
for ((i = ${#display[@]} - 1; i >= 0; i--)); do
|
||||||
|
printf '%s%3d%s %b\n' "${C_DIM}" "$((i + 1))" "${C_RESET}" "${display[$i]}"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
for ((i = 0; i < ${#display[@]}; i++)); do
|
||||||
|
printf '%s%3d%s %b\n' "${C_DIM}" "$((i + 1))" "${C_RESET}" "${display[$i]}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s::%s Select packages (for example: 1 3; leave empty to cancel): ' \
|
||||||
|
"${C_BOLD}${C_BLUE}" "${C_RESET}"
|
||||||
|
local sel=
|
||||||
|
read -r sel || exit 1
|
||||||
|
[[ -z $sel ]] && { msg "Cancelled"; return 0; }
|
||||||
|
|
||||||
|
local -a repo_pkgs=() aur_pkgs=()
|
||||||
|
local tok
|
||||||
|
for tok in $sel; do
|
||||||
|
if [[ $tok =~ ^[0-9]+$ ]]; then
|
||||||
|
local idx=$((tok - 1))
|
||||||
|
((idx >= 0 && idx < ${#entries[@]})) || die "invalid number: $tok"
|
||||||
|
local e=${entries[$idx]}
|
||||||
|
case "$e" in
|
||||||
|
repo\|*) repo_pkgs+=("${e#repo|}") ;;
|
||||||
|
aur\|*) aur_pkgs+=("${e#aur|}") ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
die "invalid selection: $tok"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#repo_pkgs[@]} -gt 0 ]]; then
|
||||||
|
as_root ${MIAUR_PACMAN} -S --needed --noconfirm "${repo_pkgs[@]}"
|
||||||
|
fi
|
||||||
|
if [[ ${#aur_pkgs[@]} -gt 0 ]]; then
|
||||||
|
install_aur_packages "${aur_pkgs[@]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_info() {
|
||||||
|
local -a pkgs=("$@")
|
||||||
|
[[ ${#pkgs[@]} -eq 0 ]] && die "specify at least one package"
|
||||||
|
local p found
|
||||||
|
for p in "${pkgs[@]}"; do
|
||||||
|
found=0
|
||||||
|
if [[ ${MIAUR_MODE:-} != aur ]] && ${MIAUR_PACMAN} -Si "$p" 2>/dev/null; then
|
||||||
|
found=1
|
||||||
|
fi
|
||||||
|
if [[ ${MIAUR_MODE:-} != repo ]]; then
|
||||||
|
if aur_print_info "$p" 2>/dev/null; then
|
||||||
|
found=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[[ $found -eq 1 ]] || error "package not found: $p"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_sync_install() {
|
||||||
|
local -a pkgs=("$@")
|
||||||
|
[[ ${#pkgs[@]} -eq 0 ]] && die "specify at least one package"
|
||||||
|
|
||||||
|
local -a repo_pkgs=() aur_pkgs=()
|
||||||
|
local p
|
||||||
|
for p in "${pkgs[@]}"; do
|
||||||
|
if [[ ${MIAUR_MODE:-} == aur ]]; then
|
||||||
|
aur_pkgs+=("$p")
|
||||||
|
elif [[ ${MIAUR_MODE:-} == repo ]]; then
|
||||||
|
repo_pkgs+=("$p")
|
||||||
|
elif repo_has_pkg "$p"; then
|
||||||
|
repo_pkgs+=("$p")
|
||||||
|
elif aur_exists "$p"; then
|
||||||
|
aur_pkgs+=("$p")
|
||||||
|
else
|
||||||
|
die "package not found: $p"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#repo_pkgs[@]} -gt 0 ]]; then
|
||||||
|
as_root ${MIAUR_PACMAN} -S --needed --noconfirm "${repo_pkgs[@]}"
|
||||||
|
fi
|
||||||
|
if [[ ${#aur_pkgs[@]} -gt 0 ]]; then
|
||||||
|
install_aur_packages "${aur_pkgs[@]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_getpkgbuild() {
|
||||||
|
local -a pkgs=("$@")
|
||||||
|
[[ ${#pkgs[@]} -eq 0 ]] && die "specify at least one package"
|
||||||
|
local p dir
|
||||||
|
for p in "${pkgs[@]}"; do
|
||||||
|
if [[ $OP_PRINT -eq 1 ]]; then
|
||||||
|
dir=$(aur_clone "$p")
|
||||||
|
cat "$dir/PKGBUILD"
|
||||||
|
else
|
||||||
|
dir=$(aur_clone "$p")
|
||||||
|
# Copy to cwd like paru -G
|
||||||
|
if [[ -e ./$p ]]; then
|
||||||
|
warn "./$p already exists; replacing it"
|
||||||
|
rm -rf "./$p"
|
||||||
|
fi
|
||||||
|
cp -a "$dir" "./$p"
|
||||||
|
msg "Downloaded to ./$p"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_clean() {
|
||||||
|
# -Sc: clean pacman cache + AUR clone cache
|
||||||
|
if [[ ${MIAUR_MODE:-} != aur ]]; then
|
||||||
|
as_root ${MIAUR_PACMAN} -Sc --noconfirm || true
|
||||||
|
fi
|
||||||
|
aur_clean_cache
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch() {
|
||||||
|
# Full passthrough ops (R, D, F, T, U, or unknown)
|
||||||
|
if [[ $DO_PASSTHRU -eq 1 && $OP != S && $OP != Q ]]; then
|
||||||
|
# Rebuild approximate pacman command from original? Simpler: use saved extras
|
||||||
|
local -a args=()
|
||||||
|
case "$OP" in
|
||||||
|
R) args+=(-R) ;;
|
||||||
|
*)
|
||||||
|
# Fall back: user should use pacman; try to forward
|
||||||
|
args+=(-"${OP}")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
local c
|
||||||
|
for c in "${PACMAN_EXTRA[@]}"; do
|
||||||
|
args+=("-$c")
|
||||||
|
done
|
||||||
|
args+=("${TARGETS[@]}")
|
||||||
|
pacman_passthru "${args[@]}"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$OP" in
|
||||||
|
interactive)
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_interactive "${TARGETS[@]}"
|
||||||
|
;;
|
||||||
|
S)
|
||||||
|
if [[ $OP_CLEAN -eq 1 ]]; then
|
||||||
|
cmd_clean
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $OP_SEARCH -gt 0 ]]; then
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_search "${TARGETS[@]}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $OP_INFO -eq 1 ]]; then
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_info "${TARGETS[@]}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $OP_UPGRADE -eq 1 ]]; then
|
||||||
|
need_cmd curl jq
|
||||||
|
if [[ $OP_AUR_ONLY -eq 1 ]]; then
|
||||||
|
# -Sua or -Su --aur
|
||||||
|
[[ $OP_REFRESH -eq 1 ]] && as_root ${MIAUR_PACMAN} -Sy --noconfirm
|
||||||
|
cmd_upgrade_aur
|
||||||
|
else
|
||||||
|
cmd_upgrade_all "$OP_REFRESH"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $OP_REFRESH -eq 1 && ${#TARGETS[@]} -eq 0 ]]; then
|
||||||
|
as_root ${MIAUR_PACMAN} -Sy --noconfirm
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Install packages; optionally refresh first
|
||||||
|
[[ $OP_REFRESH -eq 1 ]] && as_root ${MIAUR_PACMAN} -Sy --noconfirm
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_sync_install "${TARGETS[@]}"
|
||||||
|
;;
|
||||||
|
Q)
|
||||||
|
if [[ $OP_UPGRADE -eq 1 && $OP_AUR_ONLY -eq 1 ]]; then
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_query_aur_upgrades
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $OP_UPGRADE -eq 1 ]]; then
|
||||||
|
# -Qu: repo + AUR
|
||||||
|
${MIAUR_PACMAN} -Qu || true
|
||||||
|
need_cmd curl jq
|
||||||
|
cmd_query_aur_upgrades || true
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Default query passthrough
|
||||||
|
local -a qargs=(-Q)
|
||||||
|
local c
|
||||||
|
for c in "${PACMAN_EXTRA[@]}"; do
|
||||||
|
qargs+=("-$c")
|
||||||
|
done
|
||||||
|
[[ $OP_AUR_ONLY -eq 1 ]] && qargs+=(-m)
|
||||||
|
[[ $OP_SEARCH -gt 0 ]] && qargs+=(-s)
|
||||||
|
[[ $OP_INFO -eq 1 ]] && qargs+=(-i)
|
||||||
|
qargs+=("${TARGETS[@]}")
|
||||||
|
${MIAUR_PACMAN} "${qargs[@]}"
|
||||||
|
;;
|
||||||
|
G)
|
||||||
|
need_cmd curl jq git
|
||||||
|
cmd_getpkgbuild "${TARGETS[@]}"
|
||||||
|
;;
|
||||||
|
B)
|
||||||
|
[[ ${#TARGETS[@]} -eq 0 ]] && TARGETS=(.)
|
||||||
|
need_cmd git makepkg
|
||||||
|
build_local_dirs "$OP_BUILD_INSTALL" "${TARGETS[@]}"
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
if [[ $DO_PASSTHRU -eq 1 ]]; then
|
||||||
|
die "unable to parse operation; use pacman directly or see --help"
|
||||||
|
fi
|
||||||
|
die "no operation specified"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "unsupported operation: $OP"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# PKGBUILD review
|
||||||
|
|
||||||
|
# Review PKGBUILD in dir. Returns 0 to continue, 1 to abort.
|
||||||
|
review_pkgbuild() {
|
||||||
|
local dir=$1
|
||||||
|
local name=${2:-$(basename "$dir")}
|
||||||
|
|
||||||
|
[[ ${MIAUR_SKIPREVIEW:-0} -eq 1 ]] && return 0
|
||||||
|
|
||||||
|
local pb="$dir/PKGBUILD"
|
||||||
|
[[ -f $pb ]] || die "PKGBUILD not found: $dir"
|
||||||
|
|
||||||
|
msg "Reviewing the PKGBUILD for $name"
|
||||||
|
if command -v "${MIAUR_BAT}" >/dev/null 2>&1; then
|
||||||
|
"${MIAUR_BAT}" --style=plain --paging=always --language=bash "$pb" || true
|
||||||
|
elif command -v less >/dev/null 2>&1; then
|
||||||
|
less -R "$pb" || true
|
||||||
|
else
|
||||||
|
cat "$pb"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also show install script / other files briefly
|
||||||
|
local f
|
||||||
|
for f in "$dir"/*.install "$dir"/PKGBUILD; do
|
||||||
|
[[ -f $f ]] || continue
|
||||||
|
done
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
printf '%s::%s View diff (d), edit (e), continue (y), skip (s), or quit (q)? [Y/d/e/s/q] ' \
|
||||||
|
"${C_BOLD}${C_BLUE}" "${C_RESET}"
|
||||||
|
local ans=
|
||||||
|
read -r ans || return 1
|
||||||
|
ans=${ans:-y}
|
||||||
|
case "${ans,,}" in
|
||||||
|
y | yes | '') return 0 ;;
|
||||||
|
q | quit | n | no)
|
||||||
|
warn "Cancelled by user"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
s | skip) return 2 ;;
|
||||||
|
e | edit)
|
||||||
|
"${MIAUR_EDITOR}" "$pb"
|
||||||
|
;;
|
||||||
|
d | diff)
|
||||||
|
if [[ -d $dir/.git ]]; then
|
||||||
|
(cd "$dir" && ${MIAUR_GIT} diff -- PKGBUILD) || true
|
||||||
|
else
|
||||||
|
warn "No Git history is available for comparison"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "Invalid input"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUR upgrade detection and application
|
||||||
|
|
||||||
|
# List foreign packages (AUR candidates): name version
|
||||||
|
foreign_packages() {
|
||||||
|
pacman -Qm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare installed foreign pkgs with AUR; print upgradable: name local -> remote
|
||||||
|
aur_outdated() {
|
||||||
|
local -a names=()
|
||||||
|
local -A localver=()
|
||||||
|
local name ver
|
||||||
|
while read -r name ver; do
|
||||||
|
[[ -z $name ]] && continue
|
||||||
|
names+=("$name")
|
||||||
|
localver[$name]=$ver
|
||||||
|
done < <(foreign_packages)
|
||||||
|
|
||||||
|
[[ ${#names[@]} -eq 0 ]] && return 0
|
||||||
|
|
||||||
|
# Batch in chunks of 100
|
||||||
|
local i chunk=100
|
||||||
|
local -a batch=()
|
||||||
|
for ((i = 0; i < ${#names[@]}; i++)); do
|
||||||
|
batch+=("${names[$i]}")
|
||||||
|
if ((${#batch[@]} == chunk || i == ${#names[@]} - 1)); then
|
||||||
|
local json
|
||||||
|
json=$(aur_multiinfo_json "${batch[@]}") || {
|
||||||
|
warn "Failed to query AUR updates"
|
||||||
|
batch=()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
local line rname rver
|
||||||
|
while IFS= read -r line; do
|
||||||
|
rname=${line%%|*}
|
||||||
|
rver=${line#*|}
|
||||||
|
[[ -z $rname ]] && continue
|
||||||
|
local lv=${localver[$rname]:-}
|
||||||
|
[[ -z $lv ]] && continue
|
||||||
|
if [[ $(vercmp_safe "$rver" "$lv") -gt 0 ]]; then
|
||||||
|
printf '%s %s -> %s\n' "$rname" "$lv" "$rver"
|
||||||
|
fi
|
||||||
|
done < <(jq -r '.[] | "\(.Name)|\(.Version)"' <<<"$json")
|
||||||
|
batch=()
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print outdated like pacman -Qu
|
||||||
|
cmd_query_aur_upgrades() {
|
||||||
|
local name old _arrow new
|
||||||
|
while read -r name old _arrow new; do
|
||||||
|
[[ -z $name ]] && continue
|
||||||
|
printf '%s %s -> %s\n' "$name" "$old" "$new"
|
||||||
|
done < <(aur_outdated)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Upgrade all outdated AUR packages
|
||||||
|
cmd_upgrade_aur() {
|
||||||
|
local -a pkgs=()
|
||||||
|
local name old arrow new
|
||||||
|
while read -r name old arrow new; do
|
||||||
|
[[ -z $name ]] && continue
|
||||||
|
pkgs+=("$name")
|
||||||
|
msg2 "$name ${old} -> ${new}"
|
||||||
|
done < <(aur_outdated)
|
||||||
|
|
||||||
|
if [[ ${#pkgs[@]} -eq 0 ]]; then
|
||||||
|
msg "No AUR package upgrades are available"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
msg "Upgrading ${#pkgs[@]} AUR package(s)"
|
||||||
|
install_aur_packages "${pkgs[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Full -Syu: refresh + repo upgrade + AUR upgrade
|
||||||
|
cmd_upgrade_all() {
|
||||||
|
local refresh=${1:-0}
|
||||||
|
sudoloop_start
|
||||||
|
local -a pac_args=()
|
||||||
|
[[ $refresh -eq 1 ]] && pac_args+=(-y)
|
||||||
|
pac_args+=(-Su)
|
||||||
|
|
||||||
|
msg "Synchronizing databases and upgrading repository packages..."
|
||||||
|
# Use -Syu style via pacman
|
||||||
|
if [[ $refresh -eq 1 ]]; then
|
||||||
|
as_root ${MIAUR_PACMAN} -Syu --noconfirm || die "repository upgrade failed"
|
||||||
|
else
|
||||||
|
as_root ${MIAUR_PACMAN} -Su --noconfirm || die "repository upgrade failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg "Checking for AUR updates..."
|
||||||
|
cmd_upgrade_aur
|
||||||
|
sudoloop_stop
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# miaur — pure-shell AUR helper (paru-like daily workflow)
|
||||||
|
|
||||||
|
MIAUR_HOME=$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)
|
||||||
|
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "$MIAUR_HOME/lib/common.sh"
|
||||||
|
# shellcheck source=lib/config.sh
|
||||||
|
source "$MIAUR_HOME/lib/config.sh"
|
||||||
|
# shellcheck source=lib/aur_rpc.sh
|
||||||
|
source "$MIAUR_HOME/lib/aur_rpc.sh"
|
||||||
|
# shellcheck source=lib/clone.sh
|
||||||
|
source "$MIAUR_HOME/lib/clone.sh"
|
||||||
|
# shellcheck source=lib/review.sh
|
||||||
|
source "$MIAUR_HOME/lib/review.sh"
|
||||||
|
# shellcheck source=lib/deps.sh
|
||||||
|
source "$MIAUR_HOME/lib/deps.sh"
|
||||||
|
# shellcheck source=lib/build.sh
|
||||||
|
source "$MIAUR_HOME/lib/build.sh"
|
||||||
|
# shellcheck source=lib/upgrade.sh
|
||||||
|
source "$MIAUR_HOME/lib/upgrade.sh"
|
||||||
|
# shellcheck source=lib/cli.sh
|
||||||
|
source "$MIAUR_HOME/lib/cli.sh"
|
||||||
|
# shellcheck source=lib/dispatch.sh
|
||||||
|
source "$MIAUR_HOME/lib/dispatch.sh"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
miaur_load_config
|
||||||
|
|
||||||
|
# Fast path: operations that are pure pacman wrappers with no AUR flags
|
||||||
|
# Keep original argv for -R/-D/-F/-T/-U when no miaur-specific long opts mixed in awkwardly.
|
||||||
|
# We still parse to detect them.
|
||||||
|
local -a orig=("$@")
|
||||||
|
parse_args "$@"
|
||||||
|
|
||||||
|
# Special: if DO_PASSTHRU and OP empty, forward entire original command
|
||||||
|
if [[ $DO_PASSTHRU -eq 1 && -z ${OP:-} ]]; then
|
||||||
|
# Replace program name conceptually — strip miaur-only long options already consumed
|
||||||
|
as_root ${MIAUR_PACMAN} "${orig[@]}"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For -R with extras like -Rns: OP=R DO_PASSTHRU=1
|
||||||
|
if [[ ${OP:-} == R ]]; then
|
||||||
|
local -a rargs=(-R)
|
||||||
|
local c
|
||||||
|
for c in "${PACMAN_EXTRA[@]}"; do
|
||||||
|
rargs+=("-$c")
|
||||||
|
done
|
||||||
|
rargs+=("${TARGETS[@]}")
|
||||||
|
as_root ${MIAUR_PACMAN} "${rargs[@]}"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
dispatch
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user