119 lines
3.3 KiB
Bash
119 lines
3.3 KiB
Bash
#!/bin/bash
|
|
# Shared helpers for the Pop!_OS / Ubuntu installer.
|
|
|
|
DOTFILES_DIR="${DOTFILES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
|
KEYRINGS_DIR="/etc/apt/keyrings"
|
|
APT_LISTS_DIR="/etc/apt/sources.list.d"
|
|
|
|
info() { printf '\033[0;32m==>\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[1;33mWARNING:\033[0m %s\n' "$*" >&2; }
|
|
error() { printf '\033[0;31mERROR:\033[0m %s\n' "$*" >&2; }
|
|
die() {
|
|
error "$*"
|
|
exit 1
|
|
}
|
|
|
|
require_cmd() {
|
|
command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
|
|
}
|
|
|
|
download_verified() {
|
|
local url="$1" sha256="$2" destination="$3"
|
|
|
|
if ! curl -fsSL --retry 3 "$url" -o "$destination"; then
|
|
rm -f "$destination"
|
|
die "Failed to download $url"
|
|
fi
|
|
if ! printf '%s %s\n' "$sha256" "$destination" | sha256sum --check --status -; then
|
|
rm -f "$destination"
|
|
die "SHA-256 verification failed for $url"
|
|
fi
|
|
}
|
|
|
|
key_fingerprints_match() {
|
|
local key="$1" expected_fingerprints="$2"
|
|
local actual_fingerprints normalized_expected
|
|
|
|
actual_fingerprints="$(
|
|
gpg --show-keys --with-colons "$key" 2>/dev/null |
|
|
awk -F: '$1 == "fpr" { print $10 }' |
|
|
sort -u |
|
|
tr '\n' ' '
|
|
)"
|
|
normalized_expected="$(
|
|
for fingerprint in $expected_fingerprints; do
|
|
printf '%s\n' "$fingerprint"
|
|
done |
|
|
sort -u |
|
|
tr '\n' ' '
|
|
)"
|
|
|
|
[[ -n $actual_fingerprints && $actual_fingerprints == "$normalized_expected" ]]
|
|
}
|
|
|
|
apt_install() {
|
|
sudo apt-get install -y --no-install-recommends "$@"
|
|
}
|
|
|
|
apt_update_once() {
|
|
if [[ -z ${_APT_UPDATED:-} ]]; then
|
|
info "Refreshing apt indexes..."
|
|
sudo apt-get update -y
|
|
_APT_UPDATED=1
|
|
fi
|
|
}
|
|
|
|
# Symlink $1 -> $2, backing up any pre-existing real target first. Idempotent.
|
|
backup_and_link() {
|
|
local src="$1" dest="$2"
|
|
if [[ ! -e $src ]]; then
|
|
warn "Source missing, skipping link: $src"
|
|
return 0
|
|
fi
|
|
mkdir -p "$(dirname "$dest")"
|
|
if [[ -L $dest ]]; then
|
|
[[ "$(readlink "$dest")" == "$src" ]] && return 0
|
|
rm -f "$dest"
|
|
elif [[ -e $dest ]]; then
|
|
mv "$dest" "$dest.pre-install.$(date +%s)"
|
|
info "Backed up existing $dest"
|
|
fi
|
|
ln -sfn "$src" "$dest"
|
|
info "Linked $dest -> $src"
|
|
}
|
|
|
|
# Add a signed apt repo. Args: name keyring_url repo_line expected_fingerprints
|
|
add_apt_repo() {
|
|
local name="$1" keyring_url="$2" repo_line="$3" expected_fingerprints="$4"
|
|
local keyring="$KEYRINGS_DIR/$name.gpg"
|
|
local list="$APT_LISTS_DIR/$name.list"
|
|
|
|
if [[ -f $list && -s $keyring ]] &&
|
|
key_fingerprints_match "$keyring" "$expected_fingerprints"; then
|
|
return 0
|
|
fi
|
|
info "Adding apt repo: $name"
|
|
|
|
local tmp_key tmp_gpg
|
|
tmp_key="$(mktemp)"
|
|
tmp_gpg="$(mktemp)"
|
|
trap 'rm -f "$tmp_key" "$tmp_gpg"' RETURN
|
|
|
|
if ! curl -fsSL "$keyring_url" -o "$tmp_key"; then
|
|
die "Failed to download key for $name from $keyring_url"
|
|
fi
|
|
[[ -s $tmp_key ]] || die "Downloaded key for $name is empty"
|
|
|
|
key_fingerprints_match "$tmp_key" "$expected_fingerprints" ||
|
|
die "Signing-key fingerprint verification failed for $name"
|
|
|
|
if ! gpg --yes --dearmor -o "$tmp_gpg" <"$tmp_key" 2>/dev/null; then
|
|
# Already binary (.gpg) keys can't be dearmored; use the raw bytes instead.
|
|
cp "$tmp_key" "$tmp_gpg"
|
|
fi
|
|
|
|
sudo install -d -m 0755 "$KEYRINGS_DIR"
|
|
sudo install -m 0644 "$tmp_gpg" "$keyring"
|
|
echo "$repo_line" | sudo tee "$list" >/dev/null
|
|
unset _APT_UPDATED # force re-update so the new repo is seen
|
|
}
|