#!/usr/bin/env bash # bump-fork.sh — Auto-bump a local fork to match upstream version # # Usage: bump-fork.sh [--version=X.Y.Z] # # If --version is provided, bumps to that version. # If --version is omitted, queries Cargo to determine the required version # from the build graph. # # Implements: AGENTS.md "Local Fork Priority and Version Sync (MANDATORY)" set -euo pipefail COMPONENT="${1:-}" if [[ -z "$COMPONENT" ]]; then echo "Usage: $0 [--version=X.Y.Z]" echo "" echo "Components with local forks:" for d in local/sources/*/; do if [[ -d "$d" ]] && [[ -f "${d}Cargo.toml" ]]; then echo " $(basename "$d")" fi done exit 1 fi shift VERSION="" while [[ $# -gt 0 ]]; do case "$1" in --version=*) VERSION="${1#*=}" shift ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done LOCAL_DIR="local/sources/${COMPONENT}" RECIPE_DIR="recipes/core/${COMPONENT}" if [[ ! -d "$LOCAL_DIR" ]]; then echo "ERROR: $LOCAL_DIR does not exist" >&2 exit 1 fi # Detect current local version if [[ -f "${LOCAL_DIR}/Cargo.toml" ]]; then CURRENT_VERSION=$(grep -E '^version\s*=' "${LOCAL_DIR}/Cargo.toml" | head -1 | sed 's/.*"\(.*\)".*/\1/') echo "Current local version: ${CURRENT_VERSION:-unknown}" else echo "WARNING: ${LOCAL_DIR}/Cargo.toml not found — not a Cargo crate?" CURRENT_VERSION="" fi # Detect required version from build graph if not specified if [[ -z "$VERSION" ]]; then echo "Querying build graph for required version of ${COMPONENT}..." # Search Cargo.lock files for the required version REQUIRED_VERSION="" while IFS= read -r lockfile; do # Look for [[package]] entries that match this component entry=$(awk ' /^name = "'"${COMPONENT}"'"$/ { found=1; next } found && /^version = / { gsub(/"/, ""); print; exit } ' "$lockfile" 2>/dev/null) if [[ -n "$entry" ]]; then REQUIRED_VERSION="$entry" break fi done < <(find . -name 'Cargo.lock' -not -path '*/.git/*' 2>/dev/null) if [[ -z "$REQUIRED_VERSION" ]]; then echo "ERROR: Could not determine required version for ${COMPONENT}" >&2 echo " Pass --version=X.Y.Z explicitly" >&2 exit 1 fi VERSION="$REQUIRED_VERSION" echo "Required version (from Cargo.lock): ${VERSION}" fi # Check if bump is needed if [[ -n "$CURRENT_VERSION" ]] && [[ "$CURRENT_VERSION" == "$VERSION" ]]; then echo "Local fork already at v${VERSION} — no bump needed" exit 0 fi echo "Bumping ${COMPONENT}: v${CURRENT_VERSION:-unknown} → v${VERSION}" # Fetch upstream source at the required version echo "Fetching upstream source at v${VERSION}..." # Find the upstream repo URL from the recipe if [[ -f "${RECIPE_DIR}/recipe.toml" ]]; then UPSTREAM_GIT=$(grep -E '^git\s*=' "${RECIPE_DIR}/recipe.toml" | head -1 | sed 's/.*"\(.*\)".*/\1/') fi if [[ -z "${UPSTREAM_GIT:-}" ]]; then echo "ERROR: Cannot determine upstream git URL from ${RECIPE_DIR}/recipe.toml" >&2 echo " Set up the recipe or pass --upstream-git=" >&2 exit 1 fi echo "Upstream git: ${UPSTREAM_GIT}" # Fetch into a staging directory STAGING_DIR="/tmp/redbear-bump-${COMPONENT}-$$" trap "rm -rf ${STAGING_DIR}" EXIT echo "Cloning ${UPSTREAM_GIT} at v${VERSION} into ${STAGING_DIR}..." git clone --depth 1 --branch "v${VERSION}" "${UPSTREAM_GIT}" "${STAGING_DIR}" 2>/dev/null \ || git clone --depth 1 "${UPSTREAM_GIT}" "${STAGING_DIR}" cd "${STAGING_DIR}" git fetch --tags if git tag -e "v${VERSION}" 2>/dev/null; then git checkout "v${VERSION}" else echo "WARNING: tag v${VERSION} not found — using main branch HEAD" fi cd - >/dev/null # Apply Red Bear patches PATCH_DIR="local/patches/${COMPONENT}" if [[ -d "$PATCH_DIR" ]]; then echo "Applying Red Bear patches from ${PATCH_DIR}..." for patch in "${PATCH_DIR}"/*.patch; do if [[ -f "$patch" ]]; then echo " Applying $(basename "$patch")..." if ! patch -p1 -d "${STAGING_DIR}" --dry-run < "$patch" >/dev/null 2>&1; then echo "ERROR: Patch $(basename "$patch") fails to apply to upstream v${VERSION}" >&2 echo " Manual intervention required — patch may need rebasing" >&2 exit 1 fi patch -p1 -d "${STAGING_DIR}" < "$patch" fi done fi # Update version in Cargo.toml if [[ -f "${STAGING_DIR}/Cargo.toml" ]]; then sed -i "s/^version = \"${CURRENT_VERSION}\"/version = \"${VERSION}\"/" "${STAGING_DIR}/Cargo.toml" fi # Replace local fork contents with staged (atomic via temp dir rename) echo "Updating ${LOCAL_DIR}..." mv "${LOCAL_DIR}" "${LOCAL_DIR}.old-${$$}" mv "${STAGING_DIR}" "${LOCAL_DIR}" rm -rf "${LOCAL_DIR}.old-${$$}" echo "" echo "SUCCESS: ${COMPONENT} bumped to v${VERSION}" echo "" echo "Next steps:" echo " 1. cd ${LOCAL_DIR}" echo " 2. git diff (verify patches applied correctly)" echo " 3. git add -A && git commit -m 'bump: ${COMPONENT} v${CURRENT_VERSION} -> v${VERSION}'" echo " 4. git push origin submodule/${COMPONENT}" echo " 5. Rebuild affected packages: ./local/scripts/build-redbear.sh redbear-mini"