Files
miaur/lib/build.sh
T
Cursor AgentandFrank Vitrano bba71040d6 Improve safety and CLI fidelity for everyday use
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>
2026-07-23 14:39:03 +00:00

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
}