#!/usr/bin/env bash # Build taler-merchant-webui SPA *inside* this container and install it. # # Usage (as root in taler-hacktivism): # selfbuild-webui.sh [REF] # selfbuild-webui.sh v1.6.11 # selfbuild-webui.sh 0e4807845fc06f7c705711974650d67ef30e7919 # WEBUI_REF=master selfbuild-webui.sh # # Env: # WEBUI_REF tag / branch / commit (default: first arg or v1.6.11) # TTC_GIT default https://git.taler.net/taler-typescript-core.git # TTC_DIR default /var/taler-src/taler-typescript-core # SPA_DEST default /usr/share/taler-merchant-webui # PNPM_VERSION default 10.33.4 # SKIP_NODE_INSTALL 1 = do not apt/npm install node/pnpm # SKIP_DEPLOY 1 = build only, leave dist/prod in tree # EXPECT_VERSION if set, die unless dist version.txt matches # set -euo pipefail export DEBIAN_FRONTEND=noninteractive export PATH="/usr/local/bin:/usr/bin:/bin:${HOME}/.local/bin:${PATH:-}" WEBUI_REF="${WEBUI_REF:-${1:-v1.6.11}}" TTC_GIT="${TTC_GIT:-https://git.taler.net/taler-typescript-core.git}" TTC_DIR="${TTC_DIR:-/var/taler-src/taler-typescript-core}" SPA_DEST="${SPA_DEST:-/usr/share/taler-merchant-webui}" PNPM_VERSION="${PNPM_VERSION:-10.33.4}" SKIP_NODE_INSTALL="${SKIP_NODE_INSTALL:-0}" SKIP_DEPLOY="${SKIP_DEPLOY:-0}" EXPECT_VERSION="${EXPECT_VERSION:-}" log() { printf '+ %s\n' "$*"; } die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; } [ "$(id -u)" -eq 0 ] || die "run as root in the merchant container" # --------------------------------------------------------------------------- # Toolchain: node + pnpm # --------------------------------------------------------------------------- ensure_node() { if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1; then log "node $(node -v) npm $(npm -v)" return 0 fi [ "${SKIP_NODE_INSTALL}" = "1" ] && die "node/npm missing and SKIP_NODE_INSTALL=1" log "install nodejs + npm via apt" apt-get update -qq apt-get install -y --no-install-recommends nodejs npm ca-certificates git \ python3 curl ca-certificates 2>&1 | tail -20 command -v node >/dev/null 2>&1 || die "node still missing after apt" log "node $(node -v) npm $(npm -v)" } ensure_pnpm() { if command -v pnpm >/dev/null 2>&1; then log "pnpm $(pnpm -v)" return 0 fi [ "${SKIP_NODE_INSTALL}" = "1" ] && die "pnpm missing and SKIP_NODE_INSTALL=1" log "install pnpm@${PNPM_VERSION} globally" npm install -g "pnpm@${PNPM_VERSION}" 2>&1 | tail -15 # npm global bin may be /usr/local/bin or under /usr/lib hash -r 2>/dev/null || true export PATH="$(npm prefix -g)/bin:${PATH}" command -v pnpm >/dev/null 2>&1 || die "pnpm still missing after npm install -g" log "pnpm $(pnpm -v)" } # --------------------------------------------------------------------------- # Source tree at REF # --------------------------------------------------------------------------- checkout_ttc() { mkdir -p /var/taler-src if [ -d "${TTC_DIR}/.git" ]; then log "update existing ${TTC_DIR}" cd "${TTC_DIR}" git remote set-url origin "${TTC_GIT}" 2>/dev/null \ || git remote add origin "${TTC_GIT}" || true git fetch --tags --force origin else log "clone ${TTC_GIT} → ${TTC_DIR}" rm -rf "${TTC_DIR}" git clone "${TTC_GIT}" "${TTC_DIR}" cd "${TTC_DIR}" fi log "checkout ${WEBUI_REF}" # Accept tag, branch, or raw commit if git rev-parse --verify --quiet "refs/tags/${WEBUI_REF}" >/dev/null; then git checkout -f "refs/tags/${WEBUI_REF}" elif git rev-parse --verify --quiet "origin/${WEBUI_REF}" >/dev/null; then git checkout -f -B "${WEBUI_REF}" "origin/${WEBUI_REF}" elif git rev-parse --verify --quiet "${WEBUI_REF}" >/dev/null; then git checkout -f "${WEBUI_REF}" else # maybe short hash only available after fetch git fetch origin "${WEBUI_REF}" 2>/dev/null || true git checkout -f "${WEBUI_REF}" || die "cannot checkout WEBUI_REF=${WEBUI_REF}" fi # assets submodule (needed by build.mjs) if [ -f .gitmodules ] && grep -q 'taler-assets' .gitmodules 2>/dev/null; then log "submodule contrib/taler-assets" git submodule update --init contrib/taler-assets \ || git submodule update --init --recursive contrib/taler-assets \ || true fi if [ ! -f contrib/taler-assets/svg/logo/qr-logo.svg ]; then # fallback: shallow clone assets next to known relative url log "assets missing — try direct clone" rm -rf contrib/taler-assets mkdir -p contrib git clone --depth 1 https://git.taler.net/taler-assets.git contrib/taler-assets \ || die "taler-assets incomplete" fi test -f contrib/taler-assets/svg/logo/qr-logo.svg || die "taler-assets still incomplete" HEAD_SHORT=$(git rev-parse --short HEAD) HEAD_FULL=$(git rev-parse HEAD) PKG_VER=$(python3 -c "import json; print(json.load(open('packages/taler-merchant-webui/package.json'))['version'])") log "HEAD=${HEAD_SHORT} (${HEAD_FULL})" log "package.json version=${PKG_VER}" } # --------------------------------------------------------------------------- # Build + install # --------------------------------------------------------------------------- build_spa() { cd "${TTC_DIR}" log "pnpm install + compile @gnu-taler/taler-merchant-webui" pnpm install --frozen-lockfile --filter @gnu-taler/taler-merchant-webui... pnpm run --filter @gnu-taler/taler-merchant-webui... compile PROD="${TTC_DIR}/packages/taler-merchant-webui/dist/prod" test -f "${PROD}/index.js" || die "dist/prod/index.js missing" test -f "${PROD}/version.txt" || die "dist/prod/version.txt missing" GOT=$(tr -d ' \n\r' <"${PROD}/version.txt") log "built version.txt=${GOT}" if [ -n "${EXPECT_VERSION}" ] && [ "${GOT}" != "${EXPECT_VERSION}" ]; then die "expected version ${EXPECT_VERSION}, got ${GOT}" fi # sensible default when building known tag case "${WEBUI_REF}" in v1.6.11|1.6.11) [ "${GOT}" = "1.6.11" ] || die "expected 1.6.11 for ref ${WEBUI_REF}, got ${GOT}" ;; esac BUILT_VER="${GOT}" } deploy_spa() { cd "${TTC_DIR}" PROD="${TTC_DIR}/packages/taler-merchant-webui/dist/prod" HEAD_SHORT=$(git rev-parse --short HEAD) ts=$(date +%Y%m%d-%H%M%S) if [ -d "${SPA_DEST}" ] && [ "$(ls -A "${SPA_DEST}" 2>/dev/null || true)" ]; then bak="${SPA_DEST}.bak-selfbuild-${ts}" log "backup ${SPA_DEST} → ${bak}" cp -a "${SPA_DEST}" "${bak}" fi mkdir -p "${SPA_DEST}" find "${SPA_DEST}" -mindepth 1 -maxdepth 1 ! -name 'bak-*' -exec rm -rf {} + log "install SPA → ${SPA_DEST}" cp -a "${PROD}/." "${SPA_DEST}/" printf 'selfbuild-%s-%s\n' "${WEBUI_REF}" "${HEAD_SHORT}" >"${SPA_DEST}/version-overlay.txt" chown -R root:root "${SPA_DEST}" echo "=== deployed ===" cat "${SPA_DEST}/version.txt" echo cat "${SPA_DEST}/version-overlay.txt" echo wc -c "${SPA_DEST}/index.js" } # --------------------------------------------------------------------------- main() { log "selfbuild-webui REF=${WEBUI_REF}" ensure_node ensure_pnpm checkout_ttc build_spa if [ "${SKIP_DEPLOY}" = "1" ]; then log "SKIP_DEPLOY=1 — left at ${TTC_DIR}/packages/taler-merchant-webui/dist/prod" else deploy_spa fi log "DONE webui ${WEBUI_REF} → version ${BUILT_VER:-?} @ ${SPA_DEST}" } main "$@"