#!/bin/bash
#***** LAVA Config Copyright 2026 LAVA Controls - Stephen Loeckle *****
# Sets which LAVA apt ring (stable or testing) this box follows.
#   lava-ring                       show the current ring
#   lava-ring stable                everything from stable
#   lava-ring testing               everything from testing
#   lava-ring testing lavaplayer    only the named package(s) from testing, the rest from stable
#   lava-ring --apply               make apt match the config (run by postinst)
# The setting lives in /etc/default/lavaconfig:
#   LAVA_RING=stable|testing
#   LAVA_TESTING_PACKAGES="lavaplayer lavaboxagent"   (optional, limits testing to these packages)
# None of the files written here are packaged files, so package upgrades keep the box on its ring.

CONF=${LAVA_RING_CONF:-/etc/default/lavaconfig}
LIST=${LAVA_RING_LIST:-/etc/apt/sources.list.d/lavacontrols.list}
TLIST=${LAVA_RING_TLIST:-/etc/apt/sources.list.d/lavacontrols-testing.list}
PREFS=${LAVA_RING_PREFS:-/etc/apt/preferences.d/lavacontrols-testing}
SAVED=${LAVA_RING_SAVED:-/var/lib/lavaconfig/lavacontrols.list.saved}
DEFAULT_SOURCE='deb http://apt.lucidnetworks.net/debian stable lava'
LAVA_HOSTS='apt\.(lucidnetworks\.net|lavacontrols\.com)'
LAVA_ORIGIN='LAVA Controls LLC'

valid() { [ "$1" = "stable" ] || [ "$1" = "testing" ]; }

conf_value() {
    [ -f "$CONF" ] && sed -n "s/^$1=//p" "$CONF" | tail -1 | tr -d "\"'"
}

ring_from_conf() { conf_value LAVA_RING | tr -d '[:space:]'; }

# Only well-formed package names are ever written into the apt preferences
packages_from_conf() {
    for p in $(conf_value LAVA_TESTING_PACKAGES | tr ',' ' '); do
        if [[ "$p" =~ ^[a-z0-9][a-z0-9+.-]+$ ]]; then echo -n "$p "; fi
    done
}

# Boxes set up before LAVA_RING existed: take the ring from the apt source they already use
ring_from_list() {
    for f in "$LIST" "$SAVED"; do
        if grep -q '^deb ' "$f" 2>/dev/null; then
            if grep -Eq '^deb .*[[:space:]]testing[[:space:]]' "$f"; then echo testing; else echo stable; fi
            return
        fi
    done
    echo stable
}

set_conf() {
    if [ ! -f "$CONF" ]; then
        mkdir -p "$(dirname "$CONF")"
        echo "# LAVA apt ring for this box (change with: lava-ring stable | testing [package ...])" > "$CONF"
    fi
    if grep -q "^$1=" "$CONF"; then
        sed -i "s/^$1=.*/$1=$2/" "$CONF"
    else
        echo "$1=$2" >> "$CONF"
    fi
    chown root:root "$CONF" &>/dev/null
    chmod 644 "$CONF"
}

# $1 = ring, $2 = packages limited to testing (may be empty)
write_apt() {
    local ring=$1 pkgs=$2 suite=$1
    [ "$ring" = "testing" ] && [ -n "$pkgs" ] && suite=stable

    if [ ! -s "$LIST" ]; then
        mkdir -p "$(dirname "$LIST")"
        if [ -s "$SAVED" ]; then
            cp -p "$SAVED" "$LIST"
        else
            echo "$DEFAULT_SOURCE" > "$LIST"
        fi
    fi
    # A file that is there but has its deb line commented out was disabled on purpose: leave it
    if ! grep -Eq "^deb .*$LAVA_HOSTS" "$LIST"; then
        echo "lava-ring: $LIST has no active LAVA deb line, leaving it disabled" >&2
        rm -f "$TLIST" "$PREFS"
        return
    fi
    # Only LAVA repo lines follow the ring
    sed -i -E "/^deb .*$LAVA_HOSTS/s/[[:space:]](stable|testing)[[:space:]]/ $suite /" "$LIST"
    chown root:root "$LIST" &>/dev/null
    chmod 644 "$LIST"

    if [ "$ring" = "testing" ] && [ -n "$pkgs" ]; then
        # Stable stays the main source; testing is added but held back for everything except $pkgs.
        # The named packages get the normal priority, so the newest of stable/testing wins for them.
        mkdir -p "$(dirname "$TLIST")" "$(dirname "$PREFS")"
        {
            echo "# Written by lava-ring - do not edit, change LAVA_TESTING_PACKAGES in $CONF"
            grep -E "^deb .*$LAVA_HOSTS" "$LIST" | sed -E 's/[[:space:]]stable[[:space:]]/ testing /'
        } > "$TLIST"
        {
            echo "# Written by lava-ring - do not edit, change LAVA_TESTING_PACKAGES in $CONF"
            echo "Package: *"
            echo "Pin: release o=$LAVA_ORIGIN,n=testing"
            echo "Pin-Priority: 100"
            echo
            echo "Package: $pkgs" | sed 's/ *$//'
            echo "Pin: release o=$LAVA_ORIGIN,n=testing"
            echo "Pin-Priority: 500"
        } > "$PREFS"
        chown root:root "$TLIST" "$PREFS" &>/dev/null
        chmod 644 "$TLIST" "$PREFS"
    else
        rm -f "$TLIST" "$PREFS"
    fi
}

describe() {
    if [ "$1" = "testing" ] && [ -n "$2" ]; then
        echo "stable, with testing for: ${2% }"
    else
        echo "$1"
    fi
}

if [ $# -gt 0 ] && [ "$(id -u)" != "0" ] && [ -z "$LAVA_RING_CONF" ]; then
    echo "lava-ring: must be run as root" >&2
    exit 1
fi

case "$1" in
    "")
        ring=$(ring_from_conf)
        if valid "$ring"; then
            describe "$ring" "$(packages_from_conf)"
        else
            echo "$(ring_from_list) (not set in $CONF yet)"
        fi
        ;;
    --apply)
        ring=$(ring_from_conf)
        if ! valid "$ring"; then
            ring=$(ring_from_list)
            set_conf LAVA_RING "$ring"
        fi
        write_apt "$ring" "$(packages_from_conf)"
        ;;
    stable|testing)
        ring=$1; shift
        pkgs=""
        for p in "$@"; do
            if [[ ! "$p" =~ ^[a-z0-9][a-z0-9+.-]+$ ]]; then
                echo "lava-ring: '$p' is not a package name" >&2
                exit 1
            fi
            pkgs="$pkgs$p "
        done
        if [ "$ring" = "stable" ] && [ -n "$pkgs" ]; then
            echo "lava-ring: packages can only be named with testing" >&2
            exit 1
        fi
        set_conf LAVA_RING "$ring"
        set_conf LAVA_TESTING_PACKAGES "\"${pkgs% }\""
        write_apt "$ring" "$pkgs"
        echo "Ring set to $(describe "$ring" "$pkgs"). Run apt-get update to pick it up."
        ;;
    *)
        echo "usage: lava-ring [stable | testing [package ...] | --apply]" >&2
        exit 1
        ;;
esac
