# yah-source-fetch <dest> — materialize the step's source context (R971-F5,
# W363 §6.4). qed hands this script to every step that has a published source
# context as $YAH_SOURCE_FETCH; a step runs it as
#
#     sh -c "$YAH_SOURCE_FETCH" yah-source-fetch /work
#
# It is the ONE materialization path for both transports, and the in-process
# twin `source_git::fetch_checkout` runs this same text, so the two cannot drift.
#
#   git+<remote>#<ref>  fetch <ref> into a persistent bare cache repo (only the
#                       objects it lacks), then check its tree out into <dest>.
#                       Token from $YAH_SOURCE_GIT_TOKEN, via GIT_CONFIG_* env —
#                       never argv.
#   https://...         today's tarball: curl | tar.
#
# A git failure FAILS the step and names YAH_QED_SOURCE_TRANSPORT=tar. There is
# deliberately no worker-side fallback: it would hide that the git path is down.
set -eu
dest="${1:?usage: yah-source-fetch <dest>}"
url="${YAH_SOURCE_CONTEXT_URL:?no source context published — this step declares source_context, so qed should have set it; check the runner has a build-context publisher wired}"
mkdir -p "$dest"
case "$url" in
git+*)
  fail() {
    echo "yah-source-fetch: $1. The fleet git transport failed; rerun with YAH_QED_SOURCE_TRANSPORT=tar to ship the source context as a tarball instead." >&2
    exit 1
  }
  command -v git >/dev/null 2>&1 || fail "git is not on PATH in this step (the host or image must provide it)"
  spec="${url#git+}"
  remote="${spec%%#*}"
  ref="${spec#*#}"
  [ -n "$remote" ] && [ -n "$ref" ] && [ "$ref" != "$spec" ] || fail "malformed git source URL"
  # Node-persistent when qed bound /yah/source-git (remote container steps);
  # otherwise a scratch repo, which is correct but fetches the whole tree.
  if [ -n "${YAH_SOURCE_GIT_CACHE:-}" ]; then
    cache="$YAH_SOURCE_GIT_CACHE"
  elif [ -d /yah/source-git ] && [ -w /yah/source-git ]; then
    cache=/yah/source-git/src.git
  else
    cache="${TMPDIR:-/tmp}/yah-source-git.git"
  fi
  local_ref="refs/remotes/fleet/${ref#refs/}"
  export GIT_TERMINAL_PROMPT=0
  if [ -n "${YAH_SOURCE_GIT_TOKEN:-}" ]; then
    export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader
    export GIT_CONFIG_VALUE_0="Authorization: Bearer $YAH_SOURCE_GIT_TOKEN"
  fi
  mkdir -p "$cache" || fail "cannot create cache repo $cache"
  # Concurrent steps on one node share the cache: serialize on it when the
  # host has flock (util-linux and busybox both ship one).
  exec 9>"$cache.lock"
  if command -v flock >/dev/null 2>&1; then flock 9; fi
  [ -f "$cache/HEAD" ] || git init --bare -q "$cache" || fail "git init $cache"
  export GIT_DIR="$cache"
  git fetch --no-tags --verbose --progress "$remote" "+$ref:$local_ref" || fail "git fetch $ref from $remote"
  oid="$(git rev-parse "$local_ref^{commit}")" || fail "git rev-parse $local_ref"
  # A fresh dir, not a mktemp file: git refuses a zero-byte file as an index.
  idx_dir="$(mktemp -d)"
  GIT_INDEX_FILE="$idx_dir/index" git --work-tree="$dest" checkout -f "$oid" -- . || { rm -rf "$idx_dir"; fail "git checkout $oid"; }
  rm -rf "$idx_dir"
  # Prune fetched qed refs older than 7 days (the server's GC horizon).
  now="$(date +%s)"
  git for-each-ref --format='%(refname) %(committerdate:unix)' refs/remotes/fleet/qed/ |
    while read -r name ts; do
      if [ $((now - ts)) -gt 604800 ]; then git update-ref -d "$name" || true; fi
    done
  git gc --auto --quiet || true
  echo "yah-source-fetch: checked out $oid from $ref" >&2
  ;;
*)
  command -v curl >/dev/null 2>&1 || { echo "yah-source-fetch: curl is not on PATH; the tar source context needs it" >&2; exit 1; }
  tmp="$(mktemp)"
  curl -fsSL "$url" -o "$tmp" || { rm -f "$tmp"; echo "yah-source-fetch: downloading the source tarball failed" >&2; exit 1; }
  # --no-same-owner: the tar is packed by a camp-Mac uid that does not exist here.
  tar --no-same-owner -xzf "$tmp" -C "$dest" || { rm -f "$tmp"; exit 1; }
  rm -f "$tmp"
  ;;
esac
