#!/usr/bin/env bash set -euo pipefail if [[ "$#" -eq 0 ]]; then echo "No cache modes specified; skipping." exit 0 fi want_bazel_cache=0 for mode in "$@"; do if [[ "$mode" == "bazel" ]]; then want_bazel_cache=1 break fi done portable_mkdir() { hash -r >/dev/null 2>&1 || true command -p mkdir "$@" } optional_timeout() { local duration="$1" shift if command -v timeout >/dev/null 2>&1; then timeout "$duration" "$@" else "$@" fi } append_bazel_storage_cache() { local bazelrc_path="$1" local cache_root="${BURROW_BAZEL_STORAGE_CACHE:-}" if [[ -z "$cache_root" && -n "${NSC_CACHE_PATH:-}" ]]; then cache_root="${NSC_CACHE_PATH}/bazel" fi if [[ -z "$cache_root" ]]; then return 0 fi portable_mkdir -p "${cache_root}/disk" "${cache_root}/repository" { echo "build --disk_cache=${cache_root}/disk" echo "build --repository_cache=${cache_root}/repository" } >> "$bazelrc_path" echo "Namespace Bazel storage cache configured: ${cache_root}" } configure_bazel_remote_cache() { if [[ "$want_bazel_cache" != "1" ]]; then return 0 fi local bazelrc_path bazelrc_path="${NSC_BAZELRC_PATH:-${TMPDIR:-/tmp}/burrow-nsc-cache.bazelrc}" portable_mkdir -p "$(dirname "$bazelrc_path")" if [[ "$(uname -s 2>/dev/null || true)" == "Darwin" ]]; then append_bazel_storage_cache "$bazelrc_path" export BURROW_BAZEL_NSCCACHE_ACTIVE=0 export BURROW_BAZEL_NSCCACHE_BAZELRC="$bazelrc_path" echo "::warning ::Namespace Bazel remote cache probe skipped on macOS; using local Bazel repository/disk cache." if [[ -n "${GITHUB_ENV:-}" ]]; then echo "BURROW_BAZEL_NSCCACHE_ACTIVE=0" >> "$GITHUB_ENV" echo "BURROW_BAZEL_NSCCACHE_BAZELRC=$bazelrc_path" >> "$GITHUB_ENV" echo "NSC_BAZELRC_PATH=$bazelrc_path" >> "$GITHUB_ENV" fi return 0 fi export BURROW_BAZEL_NSCCACHE_ACTIVE=0 if ! command -v nsc >/dev/null 2>&1; then if bash Scripts/ci/ensure-nsc.sh; then nsc_bin_dir="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/nsc-bin" if [[ -x "${nsc_bin_dir}/nsc" ]]; then export PATH="${nsc_bin_dir}:$PATH" fi else echo "::warning ::nsc not found; using local Bazel disk cache only." if [[ -n "${GITHUB_ENV:-}" ]]; then echo "BURROW_BAZEL_NSCCACHE_ACTIVE=0" >> "$GITHUB_ENV" fi return 0 fi fi local probe_timeout="${BURROW_NSC_CACHE_PROBE_TIMEOUT:-30s}" if optional_timeout "$probe_timeout" nsc auth check-login >/dev/null 2>&1 && optional_timeout "$probe_timeout" nsc cache bazel setup --bazelrc "$bazelrc_path" >/dev/null 2>&1; then append_bazel_storage_cache "$bazelrc_path" export BURROW_BAZEL_NSCCACHE_BAZELRC="$bazelrc_path" export BURROW_BAZEL_NSCCACHE_ACTIVE=1 echo "Namespace Bazel cache configured: $bazelrc_path" if [[ -n "${GITHUB_ENV:-}" ]]; then { echo "BURROW_BAZEL_NSCCACHE_ACTIVE=1" echo "BURROW_BAZEL_NSCCACHE_BAZELRC=$bazelrc_path" echo "NSC_BAZELRC_PATH=$bazelrc_path" } >> "$GITHUB_ENV" fi else append_bazel_storage_cache "$bazelrc_path" echo "::warning ::Namespace Bazel remote cache unavailable; using local Bazel repository/disk cache." if [[ -n "${GITHUB_ENV:-}" ]]; then echo "BURROW_BAZEL_NSCCACHE_ACTIVE=0" >> "$GITHUB_ENV" echo "BURROW_BAZEL_NSCCACHE_BAZELRC=$bazelrc_path" >> "$GITHUB_ENV" echo "NSC_BAZELRC_PATH=$bazelrc_path" >> "$GITHUB_ENV" fi fi } cache_root="${NSC_CACHE_PATH:-}" if [[ -z "$cache_root" ]]; then ensure_dir() { local dir="$1" if portable_mkdir -p "$dir" 2>/dev/null; then return 0 fi if [[ "$(id -u)" != "0" ]] && command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then sudo mkdir -p "$dir" >/dev/null 2>&1 || return 1 return 0 fi return 1 } if [[ "$(uname -s 2>/dev/null || true)" == "Linux" ]]; then tmp_root="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/burrow-nscloud-cache" for candidate in "/cache/nscloud" "$tmp_root" "$PWD/.nscloud-cache"; do if ensure_dir "$candidate"; then cache_root="$candidate" break fi done else tmp_root="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/burrow-nscloud-cache" for candidate in "$tmp_root" "$PWD/.nscloud-cache"; do if ensure_dir "$candidate"; then cache_root="$candidate" break fi done fi fi if [[ -z "$cache_root" ]]; then echo "NSCloud cache volume not configured (NSC_CACHE_PATH missing); skipping." configure_bazel_remote_cache exit 0 fi export NSC_CACHE_PATH="$cache_root" if [[ -n "${GITHUB_ENV:-}" ]]; then echo "NSC_CACHE_PATH=$cache_root" >> "$GITHUB_ENV" fi mode_args=() for mode in "$@"; do [[ -z "$mode" ]] && continue if [[ "$mode" == "bazel" ]]; then continue fi if [[ "$mode" == "nix" && "${BURROW_NSC_DIRECT_NIX_VOLUME:-0}" == "1" ]]; then echo "Namespace Nix cache volume is mounted directly at /nix; skipping spacectl nix mount." continue fi if [[ "$mode" == "nix" && "$(uname -s)" == "Darwin" ]]; then echo "Skipping late Nix cache mount on macOS; using existing Nix profile and Bazel cache." continue fi mode_args+=("--mode=${mode}") done if [[ "${#mode_args[@]}" -eq 0 ]]; then echo "No filesystem cache modes require mounting; skipping spacectl cache mount." configure_bazel_remote_cache exit 0 fi spacectl_bin_dir="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/spacectl-bin" if ! command -v spacectl >/dev/null 2>&1; then if ! bash Scripts/ci/ensure-spacectl.sh; then echo "::warning ::Unable to install spacectl; skipping filesystem cache mount." configure_bazel_remote_cache exit 0 fi if [[ -x "${spacectl_bin_dir}/spacectl" ]]; then export PATH="${spacectl_bin_dir}:$PATH" fi fi portable_mkdir -p "$cache_root" 2>/dev/null || true args=(-o json cache mount "--dry_run=false" "--cache_root=${cache_root}" "${mode_args[@]}") echo "Mounting NSCloud cache: spacectl ${args[*]//${cache_root}/}" spacectl_bin="$(command -v spacectl)" run_mount=("$spacectl_bin" "${args[@]}") if [[ "$(id -u)" != "0" ]]; then if ! command -v sudo >/dev/null 2>&1 || ! sudo -n true >/dev/null 2>&1; then echo "::warning ::spacectl cache mount requires passwordless sudo; skipping filesystem cache." configure_bazel_remote_cache exit 0 fi run_mount=(sudo -n env "PATH=$PATH" "$spacectl_bin" "${args[@]}") fi tmp_err="$(mktemp "${TMPDIR:-/tmp}/spacectl.XXXXXX")" cleanup() { rm -f "$tmp_err" } trap cleanup EXIT json="" if ! json="$("${run_mount[@]}" 2>"$tmp_err")"; then echo "::warning ::spacectl cache mount failed; skipping filesystem cache." if [[ -n "$json" ]]; then printf '%s\n' "$json" || true fi if [[ -s "$tmp_err" ]]; then sed -n '1,200p' "$tmp_err" || true fi configure_bazel_remote_cache exit 0 fi if command -v python3 >/dev/null 2>&1; then NSC_MOUNT_JSON="$json" python3 - <<'PY' import json import os import sys raw = os.environ.get("NSC_MOUNT_JSON", "").strip() if not raw: sys.exit(0) try: payload = json.loads(raw) except Exception as exc: print(f"::warning ::Unable to parse spacectl JSON output; skipping cache env export: {exc}") sys.exit(0) if payload.get("error"): print(f"::warning ::spacectl cache mount skipped: {payload.get('message') or 'error=true'}") sys.exit(0) add_envs = (payload.get("output") or {}).get("add_envs") or {} gh_env = os.environ.get("GITHUB_ENV") if gh_env and isinstance(add_envs, dict): with open(gh_env, "a", encoding="utf-8") as f: for key, value in add_envs.items(): if key and value is not None: f.write(f"{key}={value}\n") PY fi configure_bazel_remote_cache