#!/usr/bin/env bash # Shared helpers for the patch workflow. Sourced by every script in this dir. # # Layout (see README.md): # upstream/ pristine clone of the vendor repo -- never edited by hand # work/ upstream@REV + patches/ applied -- where you actually edit # patches/ the source of truth -- tracked in git set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" UPSTREAM_URL="${UPSTREAM_URL:-https://github.com/xai-org/grok-build.git}" UPSTREAM_BRANCH="${UPSTREAM_BRANCH:-main}" UPSTREAM_DIR="$ROOT/upstream" WORK_DIR="$ROOT/work" PATCHES_DIR="$ROOT/patches" REV_FILE="$ROOT/upstream.rev" # Branch created inside work/, and the tag marking the pristine upstream commit # that patches are generated against. `base` is the boundary: everything after # it is ours. # # shellcheck disable=SC2034 # consumed by the scripts that source this file WORK_BRANCH="fork" BASE_TAG="base" # The package that produces the shipping binary. # shellcheck disable=SC2034 # consumed by the scripts that source this file BIN_PKG="xai-grok-pager-bin" # shellcheck disable=SC2034 # consumed by the scripts that source this file BIN_NAME="xai-grok-pager" if [[ -t 1 ]]; then C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'; C_RED=$'\033[31m' C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_BLUE=$'\033[34m' else C_RESET=""; C_BOLD=""; C_RED=""; C_GREEN=""; C_YELLOW=""; C_BLUE="" fi info() { printf '%s==>%s %s\n' "$C_BLUE$C_BOLD" "$C_RESET" "$*"; } step() { printf '%s ->%s %s\n' "$C_GREEN" "$C_RESET" "$*"; } warn() { printf '%s==> warning:%s %s\n' "$C_YELLOW$C_BOLD" "$C_RESET" "$*" >&2; } die() { printf '%s==> error:%s %s\n' "$C_RED$C_BOLD" "$C_RESET" "$*" >&2; exit 1; } # Rust lives in CARGO_HOME/bin, which is not on PATH by default in # non-interactive shells. Every script that shells out to cargo needs this. setup_path() { export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" export RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" case ":$PATH:" in *":$CARGO_HOME/bin:"*) ;; *) export PATH="$CARGO_HOME/bin:$PATH" ;; esac } require_cmd() { command -v "$1" >/dev/null 2>&1 \ || die "'$1' not found on PATH.${2:+ $2}" } # The pinned upstream commit. Comments and blank lines are allowed in the file # so the pin can carry a note about which sync it corresponds to. read_rev() { [[ -f "$REV_FILE" ]] || die "missing $REV_FILE -- run 'make update' to pin an upstream revision" local rev rev="$(grep -vE '^\s*(#|$)' "$REV_FILE" | head -n1 | tr -d '[:space:]')" [[ -n "$rev" ]] || die "$REV_FILE contains no revision" printf '%s' "$rev" } write_rev() { local rev="$1" { echo "# Pinned upstream revision of $UPSTREAM_URL" echo "# Bump with: make update (never edit by hand unless you know why)" echo "$rev" } > "$REV_FILE" } # Clone on first use, otherwise fetch. Deliberately NOT a shallow clone: forward # -porting patches across upstream syncs needs real history for merge bases. ensure_upstream() { if [[ ! -d "$UPSTREAM_DIR/.git" ]]; then info "Cloning upstream $UPSTREAM_URL -> upstream/" git clone --branch "$UPSTREAM_BRANCH" "$UPSTREAM_URL" "$UPSTREAM_DIR" else step "Fetching upstream" git -C "$UPSTREAM_DIR" fetch --tags --prune origin \ "+refs/heads/$UPSTREAM_BRANCH:refs/remotes/origin/$UPSTREAM_BRANCH" fi } # Number of .patch files currently in patches/ (0 when the dir is empty). count_patches() { shopt -s nullglob local files=("$PATCHES_DIR"/*.patch) shopt -u nullglob printf '%s' "${#files[@]}" } # Guard against running rebuild/build while a patch application is half-done. assert_no_am_in_progress() { local gitdir gitdir="$(git -C "$WORK_DIR" rev-parse --git-dir)" if [[ -d "$WORK_DIR/$gitdir/rebase-apply" ]]; then die "a 'git am' is still in progress in work/. Resolve it first: cd work && git status # fix conflicts, then: git add -A && git am --continue # or abandon it with: git am --abort" fi } assert_work_ready() { [[ -d "$WORK_DIR/.git" ]] || die "work/ does not exist yet -- run 'make apply' first" assert_no_am_in_progress git -C "$WORK_DIR" rev-parse -q --verify "refs/tags/$BASE_TAG" >/dev/null \ || die "work/ has no '$BASE_TAG' tag -- it was not created by apply-patches.sh. Run 'make apply'." }