#!/bin/bash
# my-universe: register every package repository of the universe for dnf / apt / pacman
# Generated by scripts/render.py from site/install.sh, see https://tsukini22.github.io/my-universe
set -euo pipefail

SITE="https://tsukini22.github.io/my-universe"
KEY_URL="$SITE/RPM-GPG-KEY-tsukini"
FINGERPRINT="69B8284D99B9A729C5BE935B067035C6A7DFA916"
SUDO="sudo"
DRY_RUN=0
ONLY=""

# name|base url|formats|pacman database
SOURCES=(
    "libutils|https://tsukini22.github.io/libutils|rpm deb arch|libutils"
    "brain|https://tsukini22.github.io/banana-brain|rpm deb arch|brain"
    "context-forge|https://tsukini22.github.io/context-forge|rpm deb|"
    "xstyle|https://tsukini22.github.io/xstyle|rpm deb arch|xstyle"
    "xdesk|https://tsukini22.github.io/xdesk|rpm deb arch|xdesk"
)

# =========================
# Parse arguments
# =========================
usage() {
    echo "Usage: $0 [--only NAME[,NAME...]] [--no-sudo] [--dry-run]"
    echo "  --only NAMES   Register only these packages (comma separated)"
    echo "  --no-sudo      Run without sudo (requires the script to be run as root already)"
    echo "  --dry-run      Print what would be done, change nothing"
    exit 1
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --only) ONLY="${2:-}"; [[ -n "$ONLY" ]] || usage; shift ;;
        --only=*) ONLY="${1#--only=}" ;;
        --no-sudo) SUDO="" ;;
        --dry-run) DRY_RUN=1 ;;
        -h|--help) usage ;;
        *) echo "Error: unknown argument '$1'" >&2; usage ;;
    esac
    shift
done

# =========================
# Tools
# =========================
run() { # Run a command, or print it with --dry-run
    if [[ "$DRY_RUN" == 1 ]]; then echo "+ $*"; else "$@"; fi
}

write_root() { # Write the standard input into a root file (append with -a)
    if [[ "$DRY_RUN" == 1 ]]; then echo "+ write $*:"; sed 's/^/    /'; else $SUDO tee "$@" > /dev/null; fi
}

selected() { # Is this source asked (--only)
    [[ -z "$ONLY" ]] || [[ ",$ONLY," == *",$1,"* ]]
}

configured() { # Is this url already set up in another file than the universe one: configured <url> <universe file> <files...>
    local url="$1" own="$2" file
    shift 2
    for file in "$@"; do
        [[ -f "$file" && "$file" != "$own" ]] && grep -qsF "$url" "$file" && { echo "$file"; return 0; }
    done
    return 1
}

# =========================
# Find the os
# =========================
if [[ -f /etc/os-release ]]; then
    . /etc/os-release
    OS_ID="${ID:-unknown}"
    OS_ID_LIKE="${ID_LIKE:-}"
else
    echo "Error: /etc/os-release not found, cannot detect OS." >&2
    exit 1
fi

is_rpm_based() { [[ "$OS_ID" =~ ^(fedora|rhel|centos|rocky|almalinux)$ ]] || [[ "$OS_ID_LIKE" =~ (fedora|rhel) ]]; }
is_deb_based() { [[ "$OS_ID" =~ ^(debian|ubuntu)$ ]] || [[ "$OS_ID_LIKE" =~ (debian|ubuntu) ]]; }
is_arch_based() { [[ "$OS_ID" =~ ^(arch|manjaro|endeavouros|cachyos)$ ]] || [[ "$OS_ID_LIKE" =~ arch ]]; }

# =========================
# RPM
# =========================
install_rpm_repo() {
    local file="/etc/yum.repos.d/universe.repo" content="" entry name base formats db other
    echo "Detected RPM-based system (ID=$OS_ID). Setting up the universe repositories..."
    for entry in "${SOURCES[@]}"; do
        IFS='|' read -r name base formats db <<< "$entry"
        selected "$name" && [[ " $formats " == *" rpm "* ]] || continue
        if other="$(configured "$base/fedora" "$file" /etc/yum.repos.d/*.repo)"; then
            echo "  - $name: already set up by $other, skipped"
            continue
        fi
        content+="[universe-$name]"$'\n'"name=my-universe - $name"$'\n'"baseurl=$base/fedora/\$releasever/\$basearch"$'\n'
        content+="enabled=1"$'\n'"gpgcheck=1"$'\n'"gpgkey=$KEY_URL"$'\n\n'
        echo "  + $name"
    done
    [[ -n "$content" ]] || { echo "Nothing to set up."; return 0; }
    printf '%s' "$content" | write_root "$file"
    run $SUDO rpm --import "$KEY_URL"
    echo "Universe repositories installed. You can now run: $SUDO dnf install <package>"
}

# =========================
# DEB
# =========================
install_deb_repo() {
    local file="/etc/apt/sources.list.d/universe.list" keyring="/etc/apt/keyrings/universe.gpg" content="" entry name base formats db other
    echo "Detected DEB-based system (ID=$OS_ID). Setting up the universe repositories..."
    for entry in "${SOURCES[@]}"; do
        IFS='|' read -r name base formats db <<< "$entry"
        selected "$name" && [[ " $formats " == *" deb "* ]] || continue
        # The same url with another signed-by is an apt error: a repository set up on its own is kept
        if other="$(configured "$base/debian" "$file" /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources)"; then
            echo "  - $name: already set up by $other, skipped"
            continue
        fi
        content+="deb [arch=$(dpkg --print-architecture) signed-by=$keyring] $base/debian stable main"$'\n'
        echo "  + $name"
    done
    [[ -n "$content" ]] || { echo "Nothing to set up."; return 0; }
    run $SUDO install -m 0755 -d /etc/apt/keyrings
    if [[ "$DRY_RUN" == 1 ]]; then
        echo "+ curl $KEY_URL | gpg --dearmor > $keyring"
    else
        curl -fsSL "$KEY_URL" | gpg --dearmor | $SUDO tee "$keyring" > /dev/null
        $SUDO chmod a+r "$keyring"
    fi
    printf '%s' "$content" | write_root "$file"
    run $SUDO apt-get update
    echo "Universe repositories installed. You can now run: $SUDO apt install <package>"
}

# =========================
# Arch (pacman)
# =========================
PACMAN_CONF="${PACMAN_CONF:-/etc/pacman.conf}"

install_arch_repo() {
    local content="" entry name base formats db key_file
    echo "Detected Arch-based system (ID=$OS_ID). Setting up the universe repositories..."
    for entry in "${SOURCES[@]}"; do
        IFS='|' read -r name base formats db <<< "$entry"
        selected "$name" && [[ " $formats " == *" arch "* ]] || continue
        # The name of a pacman repository is the name of its database: one section per database
        if grep -q "^\[$db\]" "$PACMAN_CONF"; then
            echo "  - $name: [$db] already in $PACMAN_CONF, skipped"
            continue
        fi
        content+=$'\n'"[$db]"$'\n'"SigLevel = Required"$'\n'"Server = $base/arch/\$arch"$'\n'
        echo "  + $name"
    done
    [[ -n "$content" ]] || { echo "Nothing to set up."; return 0; }
    if [[ "$DRY_RUN" == 1 ]]; then
        echo "+ pacman-key --add <$KEY_URL> && pacman-key --lsign-key $FINGERPRINT"
    else
        key_file="$(mktemp)"
        curl -fsSL -o "$key_file" "$KEY_URL"
        $SUDO pacman-key --add "$key_file"
        $SUDO pacman-key --lsign-key "$FINGERPRINT"
        rm -f "$key_file"
    fi
    printf '%s' "$content" | write_root -a "$PACMAN_CONF"
    run $SUDO pacman -Sy
    echo "Universe repositories installed. You can now run: $SUDO pacman -S <package>"
}

# =========================
# Dispatch
# =========================
if is_rpm_based; then
    install_rpm_repo
elif is_deb_based; then
    install_deb_repo
elif is_arch_based; then
    install_arch_repo
else
    echo "Error: unsupported distribution (ID=$OS_ID, ID_LIKE=$OS_ID_LIKE)." >&2
    echo "Supported: Fedora/RHEL-based (rpm), Debian/Ubuntu-based (deb) and Arch-based (pacman)." >&2
    exit 1
fi
