#!/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[@]}" }