137da99644
The script uses '${BRANCH_VERSION:-0.0.0}' as the +rb suffix when
bumping a fork to a new upstream version. BRANCH_VERSION was never
set, so any fork bump would have produced 'X.Y.Z+rb0.0.0' instead
of the correct 'X.Y.Z+rb0.3.2' (or whichever branch is current).
Derive BRANCH_VERSION from 'git branch --show-current' using the same
pattern as local/scripts/build-redbear.sh:158-165. Falls back to
'0.0.0' if the branch name doesn't match semver (e.g., on 'master').
(NO AI attribution)
196 lines
6.7 KiB
Bash
Executable File
196 lines
6.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# bump-fork.sh — Auto-bump a local fork to match upstream version
|
|
#
|
|
# Usage: bump-fork.sh <component> [--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
|
|
|
|
# Derive Red Bear OS version from the current git branch name.
|
|
# Branch "0.3.1" → BRANCH_VERSION="0.3.1". Same pattern as
|
|
# local/scripts/build-redbear.sh:158-165. Falls back to "0.0.0" if
|
|
# the branch name doesn't match semver.
|
|
BRANCH_VERSION=$(git -C "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" branch --show-current 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
|
|
BRANCH_VERSION="${BRANCH_VERSION:-0.0.0}"
|
|
export BRANCH_VERSION
|
|
|
|
COMPONENT="${1:-}"
|
|
if [[ -z "$COMPONENT" ]]; then
|
|
echo "Usage: $0 <component> [--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=<url>" >&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}..."
|
|
if ! git clone --depth 1 --branch "v${VERSION}" "${UPSTREAM_GIT}" "${STAGING_DIR}" 2>&1; then
|
|
echo "WARNING: clone with tag v${VERSION} failed, trying without tag..."
|
|
if ! git clone --depth 1 "${UPSTREAM_GIT}" "${STAGING_DIR}" 2>&1; then
|
|
echo "ERROR: git clone of ${UPSTREAM_GIT} failed" >&2
|
|
exit 1
|
|
fi
|
|
cd "${STAGING_DIR}"
|
|
git fetch --tags --quiet
|
|
if git rev-parse --verify "refs/tags/v${VERSION}" >/dev/null 2>&1; then
|
|
git checkout "v${VERSION}" --quiet
|
|
elif git rev-parse --verify "refs/tags/${VERSION}" >/dev/null 2>&1; then
|
|
git checkout "${VERSION}" --quiet
|
|
else
|
|
echo "WARNING: tag v${VERSION} not found — using default branch HEAD"
|
|
fi
|
|
cd - >/dev/null
|
|
else
|
|
cd "${STAGING_DIR}"
|
|
git fetch --tags --quiet 2>/dev/null || true
|
|
cd - >/dev/null
|
|
fi
|
|
|
|
# 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" && -n "${CURRENT_VERSION}" ]]; then
|
|
escaped_current=$(printf '%s\n' "${CURRENT_VERSION}" | sed 's/[.[\*^$()+?{|\\]/\\&/g')
|
|
sed -i "s/^version = \"${escaped_current}\"/version = \"${VERSION}+rb${BRANCH_VERSION:-0.0.0}\"/" "${STAGING_DIR}/Cargo.toml"
|
|
fi
|
|
|
|
# Replace local fork contents
|
|
echo "Updating ${LOCAL_DIR}..."
|
|
OLD_DIR="${LOCAL_DIR}.old-${$}"
|
|
if ! mv "${STAGING_DIR}" "${LOCAL_DIR}.new-${$}" 2>/dev/null; then
|
|
echo "ERROR: cannot move staging dir — disk full or permission denied" >&2
|
|
rm -rf "${STAGING_DIR}"
|
|
exit 1
|
|
fi
|
|
mv "${LOCAL_DIR}" "${OLD_DIR}" && mv "${LOCAL_DIR}.new-${$}" "${LOCAL_DIR}"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "ERROR: swap failed — restoring original" >&2
|
|
mv "${OLD_DIR}" "${LOCAL_DIR}" 2>/dev/null || true
|
|
rm -rf "${LOCAL_DIR}.new-${$}"
|
|
exit 1
|
|
fi
|
|
rm -rf "${OLD_DIR}"
|
|
|
|
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. Update local/fork-upstream-map.toml if the upstream tag changed"
|
|
echo " 5. Rebuild affected packages: ./local/scripts/build-redbear.sh redbear-mini" |