Files

134 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# sync-versions.sh — Synchronise all in-house Red Bear crate versions to match
# the current git branch name (e.g. branch "0.2.4" → version "0.2.4").
#
# Policy:
# - In-house Red Bear crates (local/recipes/) MUST use the branch version.
# - Upstream Redox forks (local/sources/) keep their upstream versioning.
# - Established projects with their own versioning (tlc, zbus) are excluded.
# - Meson test-case crates are excluded.
#
# Usage:
# ./local/scripts/sync-versions.sh # Apply
# ./local/scripts/sync-versions.sh --check # Check only, exit 1 if drift found
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$ROOT"
CHECK_ONLY=0
[[ "${1:-}" == "--check" ]] && CHECK_ONLY=1
# ---- Determine target version from branch ----
BRANCH="$(git branch --show-current 2>/dev/null || echo "")"
if [[ -z "$BRANCH" ]]; then
echo "ERROR: cannot determine current git branch" >&2
exit 1
fi
# Extract semantic version from branch name (e.g. "0.2.4" from "0.2.4")
TARGET_VERSION="$(echo "$BRANCH" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || true)"
if [[ -z "$TARGET_VERSION" ]]; then
echo "ERROR: branch '$BRANCH' does not contain a semantic version" >&2
exit 1
fi
echo "Target version: $TARGET_VERSION (from branch '$BRANCH')"
echo ""
# ---- Exclusions ----
# Crates that keep their own versioning (not branch-tracked)
EXCLUDE_NAMES=(
"zbus" # upstream zbus fork
"tlc" # established project with independent versioning
)
# Paths to exclude (substring match)
EXCLUDE_PATHS=(
"test cases" # meson test crates
"/target/" # build artifacts
)
should_exclude() {
local name="$1"
local path="$2"
for ex in "${EXCLUDE_NAMES[@]}"; do
[[ "$name" == "$ex" ]] && return 0
done
for ex in "${EXCLUDE_PATHS[@]}"; do
[[ "$path" == *"$ex"* ]] && return 0
done
return 1
}
# ---- Find and update Cargo.toml files ----
CHANGED=0
CHECKED=0
DRIFT=0
# Find all Cargo.toml in local/recipes/ (source dirs only, skip target/)
while IFS= read -r f; do
# Extract crate name (if present)
name="$(grep '^name = ' "$f" 2>/dev/null | head -1 | sed 's/name = "//;s/"//' || true)"
if should_exclude "$name" "$f"; then
continue
fi
CHECKED=$((CHECKED + 1))
# Case 1: [package] version = "x.y.z"
if grep -q '^version = "' "$f" 2>/dev/null; then
current="$(grep '^version = "' "$f" | head -1 | sed 's/version = "//;s/"//' || true)"
if [[ "$current" != "$TARGET_VERSION" ]]; then
if [[ $CHECK_ONLY -eq 1 ]]; then
echo " DRIFT: $name $current$TARGET_VERSION ($f)"
DRIFT=$((DRIFT + 1))
else
sed -i "s/^version = \"$current\"/version = \"$TARGET_VERSION\"/" "$f"
echo " UPDATED: $name $current$TARGET_VERSION ($f)"
CHANGED=$((CHANGED + 1))
fi
fi
fi
# Case 2: [workspace.package] version = "x.y.z"
if grep -A1 '^\[workspace\.package\]' "$f" 2>/dev/null | grep -q '^version = "' 2>/dev/null; then
current="$(grep -A1 '^\[workspace\.package\]' "$f" | grep '^version = "' | sed 's/version = "//;s/"//' || true)"
if [[ "$current" != "$TARGET_VERSION" ]]; then
if [[ $CHECK_ONLY -eq 1 ]]; then
echo " DRIFT (workspace): $current$TARGET_VERSION ($f)"
DRIFT=$((DRIFT + 1))
else
# Only replace the version line that appears under [workspace.package]
# Use awk for precision
awk -v new="$TARGET_VERSION" '
/^\[workspace\.package\]/ { in_wp=1 }
/^\[/ && !/^\[workspace\.package\]/ { in_wp=0 }
in_ws==0 && in_wp==1 && /^version = / { print "version = \"" new "\""; next }
{ print }
' "$f" > "${f}.tmp" && mv "${f}.tmp" "$f"
echo " UPDATED (workspace): $current$TARGET_VERSION ($f)"
CHANGED=$((CHANGED + 1))
fi
fi
fi
done < <(find local/recipes/ -name "Cargo.toml" -not -path "*/target/*" -path "*/source/*" | sort)
echo ""
if [[ $CHECK_ONLY -eq 1 ]]; then
echo "Checked $CHECKED crates, found $DRIFT with version drift"
[[ $DRIFT -gt 0 ]] && exit 1
echo "All in-house crates are at $TARGET_VERSION"
else
echo "Updated $CHANGED crates to $TARGET_VERSION (checked $CHECKED total)"
fi