#!/usr/bin/env bash
#
# Single source of truth for the SwiftPM scratch (build) directory, keyed by where the
# build is running. Prints the flags to append to `swift build/run/test` — empty on the
# host, a `--scratch-path <dir>` redirect on the macOS VM.
#
# Why this exists
# ---------------
# SwiftPM and the SwiftBuild backend bake the repository's ABSOLUTE path into the build
# tree — build.db, the *.yaml manifests, manifest.pif, everything under
# .build/out/Intermediates.noindex/XCBuildData, and the per-file `.d` dependency lists all
# contain fully-qualified source paths. That is fine until the SAME checkout is reachable
# at more than one absolute path, which is exactly our situation:
#
#     host / sandbox container : /Users/<user>/.nucleic/control/.../trunk
#     per-session macOS VM     : same /Users/... path (direct virtiofs mount)
#
# Both environments see one physical .build/ inside the shared trunk. The direct mount preserves the
# same absolute source path, but driving every object file
# through virtiofs is far slower than the guest's own disk, and SwiftPM binary-target extraction
# needs filesystem operations virtiofs does not provide.
#
# The fix
# -------
# Give each mount point its own scratch tree:
#   * Host / container  -> the default in-repo .build/ (this script prints nothing, so the
#                          existing `swift build` behaviour is untouched — zero risk).
#   * macOS VM (virtiofs) -> a scratch tree on the GUEST's local disk under $HOME, keyed by a
#                          hash of the mount path so distinct shares/worktrees never collide.
#
# Keep generated artifacts on the filesystem whose semantics and performance they require, while
# source remains shared at one stable absolute path.
#
# Escape hatch: export NUCLEIC_SCRATCH_PATH=/some/dir to force a specific scratch directory
# (useful for a throwaway build, or to pin the VM tree somewhere other than $HOME).
#
# Usage
#   SCRATCH_ARGS="$(bash scripts/lib/build-scratch.sh)" # "" or "--scratch-path /…/<hash>"
#   swift build $SCRATCH_ARGS ...                       # leave $SCRATCH_ARGS UNQUOTED
#   swift build $SCRATCH_ARGS --show-bin-path           # …and pass it to --show-bin-path too
#
# Takes the repo/working root as $1 (defaults to $PWD). Emits nothing but the flags on
# stdout, so it is safe to capture in `$(...)`.

set -euo pipefail

root="${1:-$PWD}"

# Explicit override always wins.
if [ -n "${NUCLEIC_SCRATCH_PATH:-}" ]; then
  printf -- '--scratch-path %s' "$NUCLEIC_SCRATCH_PATH"
  exit 0
fi

# Resolve symlinks for legacy guests, then classify by the mounted filesystem as well as path.
# Directly mounted macOS shares keep their /Users/... spelling under pwd -P, so pathname-only
# detection would incorrectly leave SwiftPM artifacts on virtiofs.
resolved="$root"
if cd "$root" 2>/dev/null; then
  resolved="$(pwd -P)"
fi

on_vm_share=false
case "$resolved" in
  /Volumes/*) on_vm_share=true ;;
esac

# A custom-tagged macOS share is mounted directly at the original workdir. Find any enclosing
# virtiofs mount point from mount(8)'s "<source> on <path> (<fstype>, ...)" output. Process
# substitution keeps the flag in this shell rather than a pipeline subshell.
#
# The type field is NOT spelled consistently: the guest reports "AppleVirtIOFS" (device
# "virtio-fs"), while other seeds/hosts print a plain "virtiofs". Matching only the lowercase
# literal left the guest undetected, so SwiftPM kept its scratch tree in the shared checkout and
# Sparkle's binary-target extraction failed on virtiofs. Compare the parenthesised type field
# case-insensitively against every spelling instead.
while IFS= read -r line; do
  # Options are the LAST parenthesised group, so strip to the final "(" — a mount point
  # containing "(" can't shift the field. The "(" MUST be backslash-escaped: unescaped, a
  # shell with extglob enabled reads "*(" as the start of an extglob group instead of a
  # literal, and the strip silently no-ops.
  fstype="${line##*\(}"
  fstype="${fstype%%,*}"
  fstype="${fstype%\)}"
  case "$(printf '%s' "$fstype" | tr '[:upper:]' '[:lower:]')" in
    virtiofs | virtio-fs | applevirtiofs)
      mountpoint="${line#* on }"
      mountpoint="${mountpoint% (*}"
      case "$resolved/" in
        "$mountpoint/"*) on_vm_share=true ;;
      esac
      ;;
  esac
done < <(/sbin/mount 2>/dev/null || mount 2>/dev/null || true)

if [ "$on_vm_share" = true ]; then
  # Keep build products on the guest's private disk: virtiofs is slower and cannot support all
  # clonefile/framework-symlink operations SwiftPM's binary-target extraction requires. Hash the
  # spelling used by the build so independently mounted worktrees never share a scratch tree.
  if command -v shasum >/dev/null 2>&1; then
    tag="$(printf '%s' "$root" | shasum | cut -c1-12)"
  else
    tag="$(printf '%s' "$root" | sha1sum | cut -c1-12)"
  fi
  printf -- '--scratch-path %s/.nucleic-scratch/%s' "${HOME:-/tmp}" "$tag"
fi
