112 lines
3.6 KiB
Bash
112 lines
3.6 KiB
Bash
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
# See LICENSE.md for license information.
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# Host package handling: maps the logical names in distroPackages.txt to
|
|
# apt or dnf packages, reports which are missing, and installs them.
|
|
# Sourced after lib/common.sh.
|
|
|
|
JOEY_PACKAGE_MAP="$JOEY_INSTALLER/distroPackages.txt"
|
|
|
|
|
|
# distroFamily -- print apt, dnf or unknown.
|
|
distroFamily() {
|
|
local id=""
|
|
local like=""
|
|
if [ -r /etc/os-release ]; then
|
|
id="$(. /etc/os-release && printf '%s' "${ID:-}")"
|
|
like="$(. /etc/os-release && printf '%s' "${ID_LIKE:-}")"
|
|
fi
|
|
case " $id $like " in
|
|
*" debian "*|*" ubuntu "*) printf 'apt\n' ;;
|
|
*" fedora "*|*" rhel "*|*" centos "*|*" rocky "*) printf 'dnf\n' ;;
|
|
*) printf 'unknown\n' ;;
|
|
esac
|
|
}
|
|
|
|
|
|
# distroPackageNames LOGICAL... -- print the real package names, one per line.
|
|
distroPackageNames() {
|
|
local family
|
|
local column
|
|
local name
|
|
local row
|
|
family="$(distroFamily)"
|
|
case "$family" in
|
|
apt) column=2 ;;
|
|
dnf) column=3 ;;
|
|
*) die "unsupported Linux distribution (need apt or dnf); install host packages by hand: $*" ;;
|
|
esac
|
|
for name in "$@"; do
|
|
row="$(awk -v n="$name" -v c="$column" '$1 == n { print $c }' "$JOEY_PACKAGE_MAP")"
|
|
[ -n "$row" ] || die "no entry for host dependency '$name' in distroPackages.txt"
|
|
[ "$row" != "-" ] || die "host dependency '$name' has no $family package"
|
|
printf '%s\n' "${row//,/$'\n'}"
|
|
done
|
|
}
|
|
|
|
|
|
# distroMissing PACKAGE... -- print the packages that are not installed.
|
|
distroMissing() {
|
|
local family
|
|
local pkg
|
|
local native=""
|
|
family="$(distroFamily)"
|
|
[ "$family" = "apt" ] && native="$(dpkg --print-architecture)"
|
|
for pkg in "$@"; do
|
|
case "$family" in
|
|
apt)
|
|
aptInstalled "$pkg" "$native" || printf '%s\n' "$pkg"
|
|
;;
|
|
dnf)
|
|
rpm -q "$pkg" >/dev/null 2>&1 || printf '%s\n' "$pkg"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
|
|
# aptInstalled PACKAGE NATIVE-ARCH -- PACKAGE is installed for this machine.
|
|
# dpkg-query prints one line per architecture present (libc6 on a system
|
|
# with i386 multiarch has two), so look for a native or arch-all line; a
|
|
# PACKAGE that names its architecture (libc6:i386) needs that one.
|
|
aptInstalled() {
|
|
local arch
|
|
local status
|
|
local want="$2"
|
|
if [[ "$1" == *:* ]]; then
|
|
want="${1##*:}"
|
|
fi
|
|
while read -r arch status; do
|
|
if [ "$status" = "installed" ] && { [ "$arch" = "$want" ] || [ "$arch" = "all" ]; }; then
|
|
return 0
|
|
fi
|
|
done <<< "$(dpkg-query -W -f='${Architecture} ${db:Status-Status}\n' "$1" 2>/dev/null || true)"
|
|
return 1
|
|
}
|
|
|
|
|
|
# distroInstall PACKAGE... -- install with one sudo call (none when already
|
|
# root, as in containers and CI, which often have no sudo at all).
|
|
distroInstall() {
|
|
local family
|
|
local yes=()
|
|
local asRoot=()
|
|
[ $# -gt 0 ] || return 0
|
|
family="$(distroFamily)"
|
|
[ "$JOEY_ASSUME_YES" = "1" ] && yes=(-y)
|
|
[ "$(id -u)" = "0" ] || asRoot=(sudo)
|
|
info "installing host packages: $*"
|
|
case "$family" in
|
|
apt)
|
|
"${asRoot[@]}" apt-get update
|
|
"${asRoot[@]}" env DEBIAN_FRONTEND=noninteractive apt-get install "${yes[@]}" --no-install-recommends "$@"
|
|
;;
|
|
dnf)
|
|
"${asRoot[@]}" dnf install "${yes[@]}" "$@"
|
|
;;
|
|
*)
|
|
die "unsupported Linux distribution; install by hand: $*"
|
|
;;
|
|
esac
|
|
}
|