#!/bin/bash
# Ingest a ChimeraX RPM and (re)build the thin per-ChimeraX build image.
#
#   refresh-chimerax /path/to/ucsf-chimerax[-daily]-<ver>-<rel>.el9.x86_64.rpm
#   refresh-chimerax /path/to/chimerax-daily.rpm   # daily ships bare-named
#
# Detects daily-vs-release and the el version from the RPM itself (queried
# inside the toolchain container, in case the host has no `rpm`), asserts the
# el9 / GCC 11 LCD contract, then rebuilds ONLY the thin ChimeraX layer on top
# of the prebuilt toolchain image.
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
: "${CHIMERAX_BUILDENV:=${XDG_CACHE_HOME:-$HOME/.cache}/chimerax-buildenv}"
TOOLCHAIN_SIF="$CHIMERAX_BUILDENV/toolchain-el9.sif"

die() { echo "refresh-chimerax: $*" >&2; exit 1; }

[[ $# -eq 1 ]] || die "usage: refresh-chimerax /path/to/[ucsf-]chimerax[-daily]*.rpm"
RPM="$(readlink -f "$1")"
[[ -f "$RPM" ]] || die "RPM not found: $1"

# The toolchain is the prerequisite; it provides `rpm` for the metadata query.
if [[ ! -e "$TOOLCHAIN_SIF" ]]; then
    echo "Toolchain image missing; building it first ..."
    "$HERE/build-toolchain"
fi

# Query the RPM from inside the container (host may have no rpm). Bind its dir.
RPM_DIR="$(dirname "$RPM")"
META="$(singularity exec --bind "$RPM_DIR" "$TOOLCHAIN_SIF" \
        rpm -qp --nosignature --qf '%{NAME}|%{VERSION}|%{RELEASE}|%{ARCH}\n' "$RPM")"
NAME="${META%%|*}"; rest="${META#*|}"
CXVERSION="${rest%%|*}"; rest="${rest#*|}"
RELEASE="${rest%%|*}"; ARCH="${rest##*|}"

# The `ucsf-` prefix is optional: release RPMs ship as ucsf-chimerax, while the
# daily channel is distributed as a bare chimerax-daily package.
case "$NAME" in
    ucsf-chimerax-daily|chimerax-daily) CHANNEL=daily ;;
    ucsf-chimerax|chimerax)             CHANNEL=release ;;
    *) die "unexpected package name '$NAME' (expected [ucsf-]chimerax[-daily])" ;;
esac

# LCD contract guards.
[[ "$RELEASE" == *el9* ]] || die "RPM dist tag is '$RELEASE', not el9 -- this toolchain targets the RHEL9/glibc-2.34 LCD. Refusing to mix dist tags."
GCCVER="$(singularity exec "$TOOLCHAIN_SIF" gcc -dumpversion | cut -d. -f1)"
if [[ "$GCCVER" != "11" ]]; then
    echo "WARNING: toolchain gcc is $GCCVER, expected 11. Bundles may demand a" >&2
    echo "         newer libstdc++ (GLIBCXX) than RHEL9 ships and fail to load." >&2
fi

echo "ChimeraX: $NAME $CXVERSION-$RELEASE ($ARCH)  ->  channel=$CHANNEL"

# Single combined image: release (`chimerax`) and daily (`chimerax-daily`) are
# layered into the SAME .sif so they coexist on PATH. Base this build on the
# existing combined image if present (preserving the other channel), else on
# the toolchain for the first layer.
OUT="$CHIMERAX_BUILDENV/chimerax.sif"
if [[ -e "$OUT" ]]; then
    BASE_SIF="$OUT"
    echo "Layering $CHANNEL onto existing $OUT (other channel preserved)."
else
    BASE_SIF="$TOOLCHAIN_SIF"
    echo "Creating $OUT from toolchain (first channel: $CHANNEL)."
fi

DEF="$(mktemp --suffix=.def)"
# Build to a temp .sif first: BASE_SIF may BE $OUT, and a build cannot read its
# base while --force-overwriting the same path. Swap in atomically on success.
TMP_OUT="$(mktemp --tmpdir="$CHIMERAX_BUILDENV" chimerax.XXXXXX.sif)"
trap 'rm -f "$DEF" "$TMP_OUT"' EXIT
sed -e "s#@BASE_SIF@#$BASE_SIF#g" \
    -e "s#@CHIMERAX_RPM@#$RPM#g" \
    -e "s#@CHANNEL@#$CHANNEL#g" \
    -e "s#@CXVERSION@#$CXVERSION-$RELEASE#g" \
    "$HERE/chimerax.def.in" > "$DEF"

echo "Building $OUT ..."
singularity build --fakeroot --force "$TMP_OUT" "$DEF"
mv -f "$TMP_OUT" "$OUT"
echo "Done: $OUT"
echo "Build a bundle with:  cd <bundle-source> && cxmake $CHANNEL app-install"
