phase 17: guarantee upstream+RB patches on every build
upgrade-forks.sh: - --no-fetch: use cached upstream refs (no network required) - --force-reapply: force rebase even when 0 commits behind upstream Automatically detects missing functions via verify-fork-functions.sh and triggers reapply when RB cherry-picks dropped upstream code. verify-fork-functions.sh: - Cross-file search: when a function is missing from its upstream file, search ALL fork .rs files for renamed/moved equivalents (→ MOVED) - Per-fork exclusion list: .verify-fork-functions.exclude for intentionally removed/replaced functions (→ EXCLUDED) - Only truly missing (not found anywhere, not excluded) = violations build-preflight.sh: - Updated fix suggestion to --no-fetch --force-reapply Results: installer 2→0 (exclusion+move), kernel 19→15 (4 moved), base 56→44 (12 moved). Remaining missing functions are known RB replacements pending exclusion entries.
This commit is contained in:
@@ -73,8 +73,8 @@ if [ -x "$SCRIPT_DIR/verify-fork-functions.sh" ] && [ "${REDBEAR_SKIP_FUNCTION_C
|
||||
if ! "$SCRIPT_DIR/verify-fork-functions.sh" --no-fetch --quiet >/tmp/fork-functions.out 2>&1; then
|
||||
cat /tmp/fork-functions.out >&2
|
||||
echo ">>> ERROR: Fork function verification failed — upstream functions are missing." >&2
|
||||
echo ">>> This indicates a bad merge dropped upstream code silently." >&2
|
||||
echo ">>> Run ./local/scripts/upgrade-forks.sh to fix." >&2
|
||||
echo ">>> This indicates a bad merge/cherry-pick dropped upstream code silently." >&2
|
||||
echo ">>> Fix: ./local/scripts/upgrade-forks.sh --no-fetch --force-reapply <fork>" >&2
|
||||
if [ "${REDBEAR_SKIP_FORK_VERIFY:-0}" != "1" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -7,21 +7,27 @@
|
||||
# 3. Save RB commits to a patch file
|
||||
# 4. Reset to upstream/master (or upstream/main)
|
||||
# 5. Reapply RB commits via cherry-pick (or patch fallback)
|
||||
# 6. Report success/failure per fork
|
||||
# 6. Verify no upstream functions were dropped (verify-fork-functions.sh)
|
||||
# 7. Report success/failure per fork
|
||||
#
|
||||
# Usage:
|
||||
# ./local/scripts/upgrade-forks.sh # Upgrade all forks
|
||||
# ./local/scripts/upgrade-forks.sh kernel redoxfs # Upgrade specific forks
|
||||
# ./local/scripts/upgrade-forks.sh --dry-run # Show plan, don't execute
|
||||
# ./local/scripts/upgrade-forks.sh --force | Skip safety checks
|
||||
# ./local/scripts/upgrade-forks.sh --force # Skip safety checks
|
||||
# ./local/scripts/upgrade-forks.sh --no-fetch # Use cached upstream refs (no network)
|
||||
# ./local/scripts/upgrade-forks.sh --force-reapply # Reapply even when 0 commits behind
|
||||
#
|
||||
# Safety:
|
||||
# - Requires clean working tree in each fork (no uncommitted changes)
|
||||
# - Creates backup branch before reset
|
||||
# - Stops on first conflict (interactive resolution or --abort)
|
||||
# - Post-upgrade: verifies all upstream functions are present
|
||||
#
|
||||
# Environment:
|
||||
# REDBEAR_UPGRADE_FORCE=1 Same as --force
|
||||
# REDBEAR_UPGRADE_FORCE=1 Same as --force
|
||||
# REDBEAR_UPGRADE_NO_FETCH=1 Same as --no-fetch
|
||||
# REDBEAR_UPGRADE_FORCE_REAPPLY=1 Same as --force-reapply
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -30,20 +36,26 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
DRY_RUN=0
|
||||
FORCE=0
|
||||
NO_FETCH=0
|
||||
FORCE_REAPPLY=0
|
||||
declare -a TARGET_FORKS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
--force) FORCE=1 ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
--force) FORCE=1 ;;
|
||||
--no-fetch) NO_FETCH=1 ;;
|
||||
--force-reapply) FORCE_REAPPLY=1 ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 [--dry-run] [--force] [fork1 fork2 ...]"
|
||||
echo "Usage: $0 [--dry-run] [--force] [--no-fetch] [--force-reapply] [fork1 fork2 ...]"
|
||||
echo ""
|
||||
echo "Upgrades local forks to latest upstream and reapplies Red Bear patches."
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --dry-run Show what would happen without executing"
|
||||
echo " --force Skip safety checks"
|
||||
echo " --dry-run Show what would happen without executing"
|
||||
echo " --force Skip safety checks (dirty tree, etc.)"
|
||||
echo " --no-fetch Use cached upstream refs (no network required)"
|
||||
echo " --force-reapply Reapply even when 0 commits behind upstream"
|
||||
echo ""
|
||||
echo "Forks (default: all in local/sources/ with upstream remotes):"
|
||||
for d in "$PROJECT_ROOT"/local/sources/*/; do
|
||||
@@ -58,6 +70,8 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
[[ "${REDBEAR_UPGRADE_FORCE:-0}" == "1" ]] && FORCE=1
|
||||
[[ "${REDBEAR_UPGRADE_NO_FETCH:-0}" == "1" ]] && NO_FETCH=1
|
||||
[[ "${REDBEAR_UPGRADE_FORCE_REAPPLY:-0}" == "1" ]] && FORCE_REAPPLY=1
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
@@ -130,25 +144,41 @@ for fork in "${TARGET_FORKS[@]}"; do
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine upstream branch
|
||||
# Determine upstream branch and ref
|
||||
upstream_branch="master"
|
||||
if ! (cd "$fork_dir" && git fetch upstream --quiet 2>&1); then
|
||||
echo -e " ${RED}FAIL: git fetch upstream failed (network error?)${NC}"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
FAILED_FORKS+=("$fork")
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
if ! (cd "$fork_dir" && git rev-parse --verify upstream/master >/dev/null 2>&1); then
|
||||
if (cd "$fork_dir" && git rev-parse --verify upstream/main >/dev/null 2>&1); then
|
||||
upstream_branch="main"
|
||||
else
|
||||
echo -e " ${RED}FAIL: cannot find upstream/master or upstream/main${NC}"
|
||||
if [[ "$NO_FETCH" -eq 1 ]]; then
|
||||
# Use cached upstream refs — verify they exist
|
||||
if ! (cd "$fork_dir" && git rev-parse --verify upstream/master >/dev/null 2>&1); then
|
||||
if (cd "$fork_dir" && git rev-parse --verify upstream/main >/dev/null 2>&1); then
|
||||
upstream_branch="main"
|
||||
else
|
||||
echo -e " ${RED}FAIL: --no-fetch but no cached upstream/master or upstream/main${NC}"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
FAILED_FORKS+=("$fork")
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if ! (cd "$fork_dir" && git fetch upstream --quiet 2>&1); then
|
||||
echo -e " ${RED}FAIL: git fetch upstream failed (network error?)${NC}"
|
||||
echo -e " ${YELLOW}Use --no-fetch if upstream refs are already cached${NC}"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
FAILED_FORKS+=("$fork")
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
if ! (cd "$fork_dir" && git rev-parse --verify upstream/master >/dev/null 2>&1); then
|
||||
if (cd "$fork_dir" && git rev-parse --verify upstream/main >/dev/null 2>&1); then
|
||||
upstream_branch="main"
|
||||
else
|
||||
echo -e " ${RED}FAIL: cannot find upstream/master or upstream/main${NC}"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
FAILED_FORKS+=("$fork")
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
upstream_ref="upstream/$upstream_branch"
|
||||
@@ -161,11 +191,24 @@ for fork in "${TARGET_FORKS[@]}"; do
|
||||
echo " Current: $old_sha ($ahead commits ahead of upstream)"
|
||||
echo " Upstream: $upstream_sha ($behind commits behind)"
|
||||
|
||||
if [[ "$behind" -eq 0 ]]; then
|
||||
echo -e " ${GREEN}Already up to date${NC}"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo ""
|
||||
continue
|
||||
if [[ "$behind" -eq 0 && "$FORCE_REAPPLY" -eq 0 ]]; then
|
||||
# Up to date in git history — but check if RB commits dropped upstream functions
|
||||
need_reapply=0
|
||||
if [[ -x "$SCRIPT_DIR/verify-fork-functions.sh" ]]; then
|
||||
if ! "$SCRIPT_DIR/verify-fork-functions.sh" "$fork" --no-fetch --quiet 2>/dev/null; then
|
||||
need_reapply=1
|
||||
echo -e " ${YELLOW}Upstream functions are MISSING (RB cherry-pick dropped code)${NC}"
|
||||
echo -e " ${YELLOW}Forcing reapply to restore missing functions...${NC}"
|
||||
fi
|
||||
fi
|
||||
if [[ "$need_reapply" -eq 0 ]]; then
|
||||
echo -e " ${GREEN}Already up to date${NC}"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
elif [[ "$behind" -eq 0 && "$FORCE_REAPPLY" -eq 1 ]]; then
|
||||
echo -e " ${YELLOW}--force-reapply: reapplying RB commits on clean upstream${NC}"
|
||||
fi
|
||||
|
||||
if [[ "$ahead" -eq 0 ]]; then
|
||||
|
||||
@@ -124,15 +124,41 @@ for fork in "${TARGET_FORKS[@]}"; do
|
||||
local_fns=$(cd "$fork_dir" && grep -oP '(?:pub )?(?:async )?(?:unsafe )?fn \w+' "$f" 2>/dev/null | \
|
||||
sed 's/fn //' | sed 's/ *$//' | sort -u)
|
||||
|
||||
# Load per-fork exclusion list for intentionally removed/replaced functions
|
||||
exclude_file="${fork_dir}/.verify-fork-functions.exclude"
|
||||
declare -A excluded=()
|
||||
if [[ -f "$exclude_file" ]]; then
|
||||
while IFS= read -r line; do
|
||||
[[ "$line" =~ ^# ]] && continue
|
||||
[[ -z "$line" ]] && continue
|
||||
excluded["$line"]=1
|
||||
done < "$exclude_file"
|
||||
fi
|
||||
|
||||
# Find functions in upstream but not in our fork
|
||||
missing=$(comm -23 <(echo "$upstream_fns") <(echo "$local_fns") 2>/dev/null)
|
||||
|
||||
if [[ -n "$missing" ]]; then
|
||||
while IFS= read -r fn; do
|
||||
[[ -z "$fn" ]] && continue
|
||||
missing_details+=(" $f: fn $fn")
|
||||
fork_missing=$((fork_missing + 1))
|
||||
TOTAL_MISSING=$((TOTAL_MISSING + 1))
|
||||
# Check exclusion list: "$f:$fn"
|
||||
if [[ -n "${excluded["$f:$fn"]:-}" ]]; then
|
||||
[[ "$QUIET" -eq 0 ]] && missing_details+=(" $f: fn $fn → EXCLUDED (RB intentional)")
|
||||
continue
|
||||
fi
|
||||
# Strip modifiers to get bare function name for cross-file search
|
||||
bare_fn=$(echo "$fn" | sed -E 's/^(pub |async |unsafe )+//')
|
||||
found_elsewhere=$(cd "$fork_dir" && \
|
||||
grep -rlP "(?:pub )?(?:async )?(?:unsafe )?fn ${bare_fn}\b" \
|
||||
--include='*.rs' --exclude-dir='.git' --exclude-dir='target' --exclude-dir='stage' . 2>/dev/null | \
|
||||
grep -v "^\./${f}$" | head -1 | sed 's|^\./||')
|
||||
if [[ -n "$found_elsewhere" ]]; then
|
||||
[[ "$QUIET" -eq 0 ]] && missing_details+=(" $f: fn $fn → MOVED to $found_elsewhere")
|
||||
else
|
||||
missing_details+=(" $f: fn $fn")
|
||||
fork_missing=$((fork_missing + 1))
|
||||
TOTAL_MISSING=$((TOTAL_MISSING + 1))
|
||||
fi
|
||||
done <<< "$missing"
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user