Drop default --noconfirm (opt-in via --noconfirm), fix --noremovemake, forward pacman argv intact for -R/-D/-F/-T/-U, deepen PKGBUILD review, show an install plan before building, and add shellcheck CI plus unit tests. Co-authored-by: Frank Vitrano <WHC2006@users.noreply.github.com>
237 lines
6.3 KiB
Bash
237 lines
6.3 KiB
Bash
#!/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
|
|
local -a mk_extra=()
|
|
mapfile -t mk_extra < <(pac_noconfirm_args)
|
|
# Always sync deps for repo side via makepkg -s when needed
|
|
${MIAUR_MAKEPKG} -s "${mk_extra[@]}" "${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)
|
|
local -a conf=()
|
|
mapfile -t conf < <(pac_noconfirm_args)
|
|
uflags+=("${conf[@]}")
|
|
[[ $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[@]}")
|
|
# Drop empty line if order was empty print
|
|
local -a order_clean=()
|
|
local _o
|
|
for _o in "${order[@]}"; do
|
|
[[ -n $_o ]] && order_clean+=("$_o")
|
|
done
|
|
order=("${order_clean[@]}")
|
|
[[ ${#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
|
|
|
|
msg "Packages to build (${#order[@]}):"
|
|
declare -A is_target_preview=()
|
|
for pkg in "${targets[@]}"; do
|
|
is_target_preview[$pkg]=1
|
|
done
|
|
for pkg in "${order[@]}"; do
|
|
if [[ -n ${is_target_preview[$pkg]+x} ]]; then
|
|
msg2 "aur/$pkg (target)"
|
|
else
|
|
msg2 "aur/$pkg"
|
|
fi
|
|
done
|
|
if [[ ${#repo_deps[@]} -gt 0 ]]; then
|
|
msg "Repository dependencies (${#repo_deps[@]}):"
|
|
msg2 "${repo_deps[*]}"
|
|
fi
|
|
confirm_ask "Proceed with installation?" || {
|
|
warn "Cancelled by user"
|
|
sudoloop_stop
|
|
return 1
|
|
}
|
|
|
|
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[*]}"
|
|
# Cleanup after an already-confirmed install: avoid a second prompt by default
|
|
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
|
|
}
|