build system: brush versioning fix + build-redbear.sh versioning/colors/prefix honesty

sync-versions: stop stamping vendored-upstream workspaces with the Cat 1
branch version. brush is a vendored upstream (reubeno/brush) whose 12 crates
carry their own upstream versions with internal ^ requirements (brush needs
brush-parser ^0.4.0, brush-core 0.5.0, ...); rewriting them all to 0.3.1 broke
the build. The old git-untracked heuristic stopped catching brush once it was
vendored (committed). Add a provenance-based .vendored-upstream opt-out marker
(covers the whole class, not just brush) read by should_exclude.

build-redbear.sh:
- versioning: BUILD_REDBEAR_VERSION (starts 1.0), --version flag, startup
  banner, auto-bumped by pre-commit hook (bump-build-version.sh)
- colored output (TTY + NO_COLOR aware)
- prefix rebuild: stop reporting 'rebuilt successfully' on a make no-op;
  remove derived prefix markers so a stale relibc actually re-cooks into the
  sysroot; skip the rebuild when only kernel/base (which don't feed the prefix)
  advanced
- record fork source-fingerprints only after a successful build (not before
  make live), so a failed build no longer marks forks as built

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 12:30:55 +09:00
parent 0bb3e6fa4d
commit 81f738f7bd
4 changed files with 239 additions and 83 deletions
@@ -0,0 +1,14 @@
# Marker: this recipe's source/ tree is a VENDORED UPSTREAM project, not an
# in-house Red Bear crate. sync-versions.sh reads this file (via should_exclude)
# and skips it, so the Cat 1 branch-version policy never rewrites the upstream
# crate versions.
#
# brush is reubeno/brush @ 897b373e08279f644438fb19438f156fc34647cd, a Cargo
# workspace whose members carry their own upstream versions with internal
# inter-crate requirements (brush 0.4.0, brush-core 0.5.0, brush-parser 0.4.0,
# brush-interactive 0.4.0, brush-builtins 0.2.0, ...). Stamping them all to the
# Red Bear branch version (e.g. 0.3.1) breaks those `^` requirements and the
# build (brush requires brush-parser ^0.4.0, etc.). Red Bear's changes are a
# small set of reviewable Redox-port patches; the upstream versions are kept.
#
# Upstream: https://github.com/reubeno/brush
+154 -77
View File
@@ -4,6 +4,47 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# ── Build-system script version ──────────────────────────────
# Semantic version of this build orchestrator itself, independent of
# REDBEAR_VERSION (which tracks the OS release derived from the git branch).
# Starts at 1.0 and is bumped AUTOMATICALLY on every change by the pre-commit
# git hook (local/scripts/bump-build-version.sh); do not edit the minor by hand.
BUILD_REDBEAR_VERSION="1.1"
# ── Colorized output ──────────────────────────────────
# Enabled only on a TTY with NO_COLOR unset, so redirected build logs and CI
# output stay plain. Helpers preserve the existing ">>>" prefix convention.
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'
C_INFO=$'\033[1;36m'; C_OK=$'\033[1;32m'
C_WARN=$'\033[1;33m'; C_ERR=$'\033[1;31m'; C_DIM=$'\033[2m'
C_VER=$'\033[1;35m' # bright magenta — the startup version banner
else
C_RESET=; C_BOLD=; C_INFO=; C_OK=; C_WARN=; C_ERR=; C_DIM=; C_VER=
fi
log() { printf '%s>>> %s%s\n' "$C_INFO" "$*" "$C_RESET"; }
ok() { printf '%s>>> %s%s\n' "$C_OK" "$*" "$C_RESET"; }
warn() { printf '%s>>> WARNING: %s%s\n' "$C_WARN" "$*" "$C_RESET" >&2; }
err() { printf '%s>>> ERROR: %s%s\n' "$C_ERR" "$*" "$C_RESET" >&2; }
hdr() { printf '%s%s%s\n' "$C_BOLD$C_INFO" "$*" "$C_RESET"; }
# Print full version/build provenance and exit (used by --version).
print_version() {
local git_hash branch
git_hash="$(git -C "$PROJECT_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
branch="$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null || echo unknown)"
hdr "Red Bear OS build system"
printf ' build-redbear.sh : %s\n' "$BUILD_REDBEAR_VERSION"
printf ' OS version : %s\n' "$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo 0.0.0)"
printf ' repo commit : %s (branch %s)\n' "$git_hash" "$branch"
printf ' host : %s\n' "$(uname -n 2>/dev/null || echo unknown)"
printf ' arch : %s\n' "$(uname -m 2>/dev/null || echo unknown)"
}
# Startup version banner — printed first, highlighted in its own color so the
# running build script's version is always visible at a glance.
printf '%s══════ build-redbear.sh v%s ══════%s\n' "$C_VER" "$BUILD_REDBEAR_VERSION" "$C_RESET"
# Concurrent-build guard. Two builds running at once corrupt each other's
# cookbook caches, repo/ artefacts and prefix, and produce non-deterministic
# ISOs. Take an exclusive, non-blocking flock on a lockfile; if another build
@@ -13,8 +54,8 @@ if [ -z "${REDBEAR_ALLOW_CONCURRENT:-}" ] && command -v flock >/dev/null 2>&1; t
REDBEAR_BUILD_LOCK="${TMPDIR:-/tmp}/redbear-build.lock"
exec 9>"$REDBEAR_BUILD_LOCK"
if ! flock -n 9; then
echo ">>> ERROR: another RedBear build is already running (lock: $REDBEAR_BUILD_LOCK)." >&2
echo ">>> Wait for it to finish, or set REDBEAR_ALLOW_CONCURRENT=1 to override." >&2
echo "${C_ERR}>>> ERROR:${C_RESET} another RedBear build is already running (lock: $REDBEAR_BUILD_LOCK)." >&2
echo "${C_INFO}>>>${C_RESET} Wait for it to finish, or set REDBEAR_ALLOW_CONCURRENT=1 to override." >&2
exit 1
fi
fi
@@ -161,7 +202,7 @@ redbear_unstash_one() {
}
redbear_stash_all_dirty_forks() {
echo ">>> Stashing dirty fork sources (restored at exit)..."
echo "${C_INFO}>>>${C_RESET} Stashing dirty fork sources (restored at exit)..."
local any_dirty=0
local entry label dir
for entry in "${REDBEAR_FORK_SOURCES[@]}"; do
@@ -184,7 +225,7 @@ redbear_stash_all_dirty_forks() {
redbear_unstash_all_forks() {
local reason="${1:-exit}"
[ "${#REDBEAR_STASHED_REPOS[@]}" -eq 0 ] && return 0
echo ">>> Restoring stashed fork sources (reason: $reason)..."
echo "${C_INFO}>>>${C_RESET} Restoring stashed fork sources (reason: $reason)..."
local i
for ((i=${#REDBEAR_STASHED_REPOS[@]}-1; i>=0; i--)); do
local entry="${REDBEAR_STASHED_REPOS[$i]}"
@@ -223,7 +264,7 @@ if [ -z "${REDBEAR_VERSION:-}" ]; then
REDBEAR_VERSION=$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "0.0.0")
fi
export REDBEAR_VERSION
echo ">>> Red Bear OS version: $REDBEAR_VERSION (from git branch)"
echo "${C_INFO}>>>${C_RESET} Red Bear OS version: $REDBEAR_VERSION (from git branch)"
# Source .config for build settings, but NEVER auto-set REDBEAR_RELEASE.
# Release mode requires explicit REDBEAR_RELEASE= in the environment.
@@ -274,6 +315,7 @@ Options:
--upstream Allow Redox/upstream recipe source refresh during build
--no-cache Force clean rebuild, discarding cached packages
-h, --help Show this help
-V, --version Show build-system version/provenance and exit
Configs:
redbear-full Desktop/graphics target (default)
@@ -309,6 +351,10 @@ while [ $# -gt 0 ]; do
usage
exit 0
;;
-V|--version)
print_version
exit 0
;;
-*)
echo "Unknown option: $1" >&2
usage >&2
@@ -339,15 +385,16 @@ case "$CONFIG" in
;;
esac
echo "========================================"
echo " Red Bear OS Build System"
echo "========================================"
echo "Config: $CONFIG"
hdr "========================================"
hdr " Red Bear OS Build System"
hdr "========================================"
printf 'Config: %s%s%s\n' "$C_BOLD" "$CONFIG" "$C_RESET"
echo "Jobs: $JOBS"
echo "Apply patches: $APPLY_PATCHES"
echo "Upstream: $ALLOW_UPSTREAM"
echo "Root: ${PROJECT_ROOT##*/}"
echo "========================================"
echo "Script version: $BUILD_REDBEAR_VERSION"
hdr "========================================"
echo ""
cd "$PROJECT_ROOT"
@@ -394,18 +441,18 @@ if [ "${REDBEAR_ALLOW_WRONG_BRANCH:-0}" != "1" ] && [ -z "${REDBEAR_RELEASE:-}"
fi
if [ -x "$PROJECT_ROOT/local/scripts/verify-overlay-integrity.sh" ] && [ -z "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Verifying overlay integrity..."
echo "${C_INFO}>>>${C_RESET} Verifying overlay integrity..."
if ! "$PROJECT_ROOT/local/scripts/verify-overlay-integrity.sh" --quiet; then
echo ">>> Overlay integrity check FAILED — auto-repairing..."
echo "${C_INFO}>>>${C_RESET} Overlay integrity check FAILED — auto-repairing..."
"$PROJECT_ROOT/local/scripts/apply-patches.sh" || true
if "$PROJECT_ROOT/local/scripts/verify-overlay-integrity.sh" --quiet; then
echo ">>> Overlay integrity restored."
echo "${C_INFO}>>>${C_RESET} Overlay integrity restored."
else
echo "WARNING: overlay integrity check still failing after repair."
echo " Continuing build — some packages may miscompile."
fi
else
echo ">>> Overlay integrity OK."
echo "${C_INFO}>>>${C_RESET} Overlay integrity OK."
fi
echo ""
fi
@@ -414,7 +461,7 @@ fi
# Any WIP directory that shadows a local/recipes/ package must be
# replaced with a symlink to the local version.
if [ -z "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Enforcing local-over-WIP recipe policy..."
echo "${C_INFO}>>>${C_RESET} Enforcing local-over-WIP recipe policy..."
for local_recipe in "$PROJECT_ROOT"/local/recipes/*/*/; do
pkg=$(basename "$local_recipe")
[ ! -f "$local_recipe/recipe.toml" ] && continue
@@ -463,8 +510,8 @@ trap redbear_exit_trap EXIT
redbear_dump_failure_diagnostics() {
local rc="$1"
echo ""
echo "========================================"
echo " BUILD FAILED (exit code: $rc)"
printf '%s========================================%s\n' "$C_ERR" "$C_RESET"
printf '%s BUILD FAILED (exit code: %s)%s\n' "$C_ERR" "$rc" "$C_RESET"
echo "========================================"
echo ""
echo "Diagnostic state preserved at:"
@@ -532,13 +579,13 @@ redbear_dump_failure_diagnostics() {
}
if [ "$APPLY_PATCHES" = "1" ] && [ -z "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Local fork sources already have patches committed. Recipe patches (non-fork recipes) are applied atomically by 'repo fetch' via recipe.toml."
echo "${C_INFO}>>>${C_RESET} Local fork sources already have patches committed. Recipe patches (non-fork recipes) are applied atomically by 'repo fetch' via recipe.toml."
elif [ -n "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Release mode: fork sources include all patches; no separate patch step needed."
echo "${C_INFO}>>>${C_RESET} Release mode: fork sources include all patches; no separate patch step needed."
fi
if [ ! -f "target/release/repo" ]; then
echo ">>> Building cookbook binary (missing)..."
echo "${C_INFO}>>>${C_RESET} Building cookbook binary (missing)..."
cargo build --release
redbear_record_cookbook_fingerprint
else
@@ -550,11 +597,11 @@ else
[ -f "target/release/.cookbook-src-fingerprint" ] && \
STORED_COOKBOOK_HASH=$(cat "target/release/.cookbook-src-fingerprint")
if [ "$CURRENT_COOKBOOK_HASH" != "$STORED_COOKBOOK_HASH" ]; then
echo ">>> Rebuilding cookbook binary (source changed: ${CURRENT_COOKBOOK_HASH:0:12} != ${STORED_COOKBOOK_HASH:0:12})..."
echo "${C_INFO}>>>${C_RESET} Rebuilding cookbook binary (source changed: ${CURRENT_COOKBOOK_HASH:0:12} != ${STORED_COOKBOOK_HASH:0:12})..."
cargo build --release
redbear_record_cookbook_fingerprint
else
echo ">>> Cookbook binary is up to date (${CURRENT_COOKBOOK_HASH:0:12})"
echo "${C_INFO}>>>${C_RESET} Cookbook binary is up to date (${CURRENT_COOKBOOK_HASH:0:12})"
fi
fi
@@ -566,17 +613,17 @@ FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
if [ "$CONFIG" = "redbear-full" ]; then
if [ -d "$FW_AMD_DIR" ] && [ -n "$(ls -A "$FW_AMD_DIR" 2>/dev/null)" ]; then
FW_COUNT=$(ls "$FW_AMD_DIR"/*.bin 2>/dev/null | wc -l)
echo ">>> Found $FW_COUNT AMD firmware blobs"
echo "${C_INFO}>>>${C_RESET} Found $FW_COUNT AMD firmware blobs"
else
echo ">>> WARNING: No AMD firmware blobs found."
echo "${C_WARN}>>> WARNING:${C_RESET} No AMD firmware blobs found."
echo " Run: ./local/scripts/fetch-firmware.sh"
echo " GPU driver will NOT function without firmware."
fi
echo ""
fi
echo ">>> Building Red Bear OS with config: $CONFIG"
echo ">>> Build time varies by config (redbear-mini ~30-60 min, redbear-full ~60-120 min on first build)..."
echo "${C_INFO}>>>${C_RESET} Building Red Bear OS with config: $CONFIG"
echo "${C_INFO}>>>${C_RESET} Build time varies by config (redbear-mini ~30-60 min, redbear-full ~60-120 min on first build)..."
# Stale-build prevention: if a low-level source repo has commits newer
# than its pkgar, delete that package's pkgar and target dir AND clean
@@ -620,9 +667,9 @@ if [ "$NO_CACHE" != "1" ]; then
if [ -n "$src_commit" ] && { [ "$src_commit" != "$last_commit" ] || [ "$src_dirty" = "1" ]; }; then
if [ "$src_dirty" = "1" ] && [ "$src_commit" = "$last_commit" ]; then
echo ">>> Stale $src detected (working tree has uncommitted changes); invalidating..."
echo "${C_INFO}>>>${C_RESET} Stale $src detected (working tree has uncommitted changes); invalidating..."
else
echo ">>> Stale $src detected (source newer than last build); invalidating..."
echo "${C_INFO}>>>${C_RESET} Stale $src detected (source newer than last build); invalidating..."
fi
rm -f "$PROJECT_ROOT/repo/x86_64-unknown-redox/$src".*
find "$PROJECT_ROOT/recipes" -path "*/$src/target" -type d -exec rm -rf {} + 2>/dev/null || true
@@ -655,7 +702,7 @@ if [ "$NO_CACHE" != "1" ]; then
# Only act when a prior fingerprint exists (skip the first build, which
# cooks everything anyway).
if [ -n "$last_commit" ] && { [ "$src_commit" != "$last_commit" ] || [ "$src_dirty" = "1" ]; }; then
echo ">>> Stale shared fork $src detected; forcing full userspace relink (correctness)..."
echo "${C_INFO}>>>${C_RESET} Stale shared fork $src detected; forcing full userspace relink (correctness)..."
STALE_DETECTED=1
USERSPACE_RUNTIME_STALE=1
[ "$src" = "userutils" ] && rm -f "$PROJECT_ROOT/repo/x86_64-unknown-redox/userutils".*
@@ -761,10 +808,10 @@ if [ "$NO_CACHE" != "1" ]; then
[ "$relibc_rebuilding" = "1" ] && _boot_abi_changed=1
[ "$USERSPACE_RUNTIME_STALE" = "1" ] && _boot_abi_changed=1
if [ "$_boot_abi_changed" = "1" ]; then
echo ">>> Boot ABI touched (relibc / syscall protocol fork) — relinking ONLY the"
echo ">>> static initfs-critical binaries: $ABI_CRITICAL_PKGS."
echo ">>> Dynamically-linked userspace (Qt/KF6/mesa/sddm/desktop) is untouched —"
echo ">>> shared libc.so resolved at runtime (the Linux glibc model)."
echo "${C_INFO}>>>${C_RESET} Boot ABI touched (relibc / syscall protocol fork) — relinking ONLY the"
echo "${C_INFO}>>>${C_RESET} static initfs-critical binaries: $ABI_CRITICAL_PKGS."
echo "${C_INFO}>>>${C_RESET} Dynamically-linked userspace (Qt/KF6/mesa/sddm/desktop) is untouched —"
echo "${C_INFO}>>>${C_RESET} shared libc.so resolved at runtime (the Linux glibc model)."
for _pkg in $ABI_CRITICAL_PKGS; do
rm -f "$REPO_DIR/$_pkg".*
find "$PROJECT_ROOT/recipes" "$PROJECT_ROOT/local/recipes" \
@@ -802,7 +849,7 @@ if [ -d "$FSTOOLS_DIR" ]; then
fi
if { [ "$src_ts" != "0" ] && [ "$fstools_ts" != "0" ] && [ "$src_ts" -gt "$fstools_ts" ]; } \
|| [ "$src_dirty" = "1" ]; then
echo ">>> Stale host fstools detected ($src newer than build/fstools); rebuilding host installer/redoxfs..."
echo "${C_INFO}>>>${C_RESET} Stale host fstools detected ($src newer than build/fstools); rebuilding host installer/redoxfs..."
fstools_stale=1
fi
done
@@ -831,9 +878,9 @@ if [ -f "$PREFIX_LIBC" ]; then
fork_date=$(date -d "@$fork_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "unknown")
prefix_date=$(date -d "@$prefix_ts" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "unknown")
if [ "$src_dirty" = "1" ]; then
echo ">>> Stale $src detected (working tree has uncommitted changes); prefix will be rebuilt."
echo "${C_INFO}>>>${C_RESET} Stale $src detected (working tree has uncommitted changes); prefix will be rebuilt."
else
echo ">>> Stale $src detected (fork $fork_date newer than prefix $prefix_date); prefix will be rebuilt."
echo "${C_INFO}>>>${C_RESET} Stale $src detected (fork $fork_date newer than prefix $prefix_date); prefix will be rebuilt."
fi
STALE_SRCS+=("$src")
STALE_PREFIX=1
@@ -848,34 +895,54 @@ fi
# fork sources — without this, recipes link against a stale libc.a and
# runtime artefacts (initfs, base daemons) can crash on boot.
if [ "$STALE_PREFIX" = "1" ] && [ -z "${REDBEAR_SKIP_PREFIX_REBUILD:-}" ]; then
echo ">>> Auto-rebuilding prefix ($STALE_PREFIX stale fork(s))..."
for src in "${STALE_SRCS[@]}"; do
touch "$PROJECT_ROOT/local/sources/$src"
done
# ARCH and HOST_ARCH are exported at the top of this script. The
# make rule for `prefix` (mk/prefix.mk) derives TARGET from ARCH.
# Pass the explicit `TARGET` override to match how recipe builds
# pass the target triple.
if ! make prefix TARGET="${TARGET:-x86_64-unknown-redox}" 2>&1 | tail -n 20; then
echo ">>> ERROR: prefix rebuild failed. Aborting build to avoid producing broken binaries." >&2
exit 1
PREFIX_TARGET="${TARGET:-x86_64-unknown-redox}"
PREFIX_BASE="$PROJECT_ROOT/prefix/$PREFIX_TARGET"
# Only relibc actually feeds the prefix toolchain sysroot (which carries the
# cross compilers + relibc libc.a/headers). kernel/base do NOT contribute to
# the prefix, so a kernel/base-only staleness needs no toolchain rebuild.
_relibc_stale=0
for _s in "${STALE_SRCS[@]}"; do [ "$_s" = "relibc" ] && _relibc_stale=1; done
if [ "$_relibc_stale" = "1" ]; then
echo "${C_INFO}>>>${C_RESET} Auto-rebuilding prefix (${#STALE_SRCS[@]} stale fork(s): ${STALE_SRCS[*]})..."
# The `prefix` / `$(PREFIX)/sysroot` make targets have NO prerequisite on
# the relibc SOURCE tree, so once the sysroot directory exists `make
# prefix` reports "nothing to be done" and a relibc change never reaches
# the prefix libc.a. Previously the script then printed "rebuilt
# successfully" and touch'd libc.a — hiding real staleness (the #1 cause
# of undefined-reference link errors). Remove the DERIVED prefix markers
# so the relibc-install recipe re-cooks relibc and the sysroot is
# repopulated from the fresh stage. The (preserved) clang/rust/gcc-install
# markers make this cheap: only relibc is re-cooked.
rm -rf "$PREFIX_BASE/relibc-install" "$PREFIX_BASE/sysroot"
# ARCH and HOST_ARCH are exported at the top of this script. The make
# rule for `prefix` (mk/prefix.mk) derives TARGET from ARCH; pass the
# explicit TARGET override to match how recipe builds pass the triple.
if ! make prefix TARGET="$PREFIX_TARGET" 2>&1 | tail -n 20; then
echo "${C_ERR}>>> ERROR:${C_RESET} prefix rebuild failed. Aborting build to avoid producing broken binaries." >&2
exit 1
fi
# A genuine rebuild regenerates libc.a with a fresh mtime (newer than the
# fork commit), so the staleness check will not re-fire. Verify the
# artifact actually appeared — a silent no-op here must never be reported
# as success.
if [ ! -f "$PREFIX_LIBC" ]; then
echo "${C_ERR}>>> ERROR:${C_RESET} prefix rebuild did not produce $PREFIX_LIBC. Aborting." >&2
exit 1
fi
echo "${C_INFO}>>>${C_RESET} Prefix rebuilt successfully (relibc refreshed into sysroot)."
else
# kernel/base advanced but neither feeds the prefix toolchain. No rebuild
# is required; re-stamp libc.a so the mtime-based staleness check settles
# instead of firing on every subsequent build.
echo "${C_INFO}>>>${C_RESET} Prefix staleness from '${STALE_SRCS[*]}' only (does not feed the prefix toolchain); no rebuild needed."
touch "$PREFIX_LIBC"
fi
echo ">>> Prefix rebuilt successfully."
# Stamp libc.a to now so the staleness check above does not re-fire on
# every subsequent build. `make prefix` extracts a prebuilt toolchain
# tarball and is a no-op when the prefix is already present, so without
# this touch libc.a keeps its old mtime, stays "older" than the fork's
# git commit timestamp, and the (expensive) prefix step runs on every
# build forever. Touching after a successful rebuild means we only rebuild
# again when the fork actually advances past this point. The uncommitted-
# changes (src_dirty) path above is unaffected: it intentionally rebuilds
# whenever the working tree is dirty, regardless of mtime.
touch "$PREFIX_LIBC"
STALE_PREFIX=0
fi
if [ "$NO_CACHE" = "1" ]; then
echo ">>> Cleaning repo and recipe caches for clean build..."
echo "${C_INFO}>>>${C_RESET} Cleaning repo and recipe caches for clean build..."
make repo_clean 2>/dev/null || true
rm -rf "$PROJECT_ROOT"/repo
find "$PROJECT_ROOT"/local/recipes -maxdepth 4 -name "target" -type d -exec rm -rf {} + 2>/dev/null || true
@@ -915,13 +982,13 @@ bash "$PROJECT_ROOT/local/scripts/sync-versions.sh" --check || {
_REDOX_TC="$HOME/.redoxer/x86_64-unknown-redox/toolchain"
_HOST_TC_DIR="$HOME/.redoxer/x86_64-unknown-linux-gnu"
if [ ! -e "$_HOST_TC_DIR/toolchain" ] && [ -d "$_REDOX_TC" ]; then
echo ">>> Provisioning host redoxer toolchain (symlink -> redox toolchain; host toolchains are not downloadable)..."
echo "${C_INFO}>>>${C_RESET} Provisioning host redoxer toolchain (symlink -> redox toolchain; host toolchains are not downloadable)..."
mkdir -p "$_HOST_TC_DIR"
rm -rf "$_HOST_TC_DIR/toolchain.partial"
ln -sfn "$_REDOX_TC" "$_HOST_TC_DIR/toolchain"
fi
echo ">>> Pre-cooking critical packages..."
echo "${C_INFO}>>>${C_RESET} Pre-cooking critical packages..."
if [ "$CONFIG" = "redbear-full" ]; then
# The Qt stack has a strict internal build order (qtbase -> qtshadertools ->
# qtdeclarative -> qtsvg -> qtwayland) and downstream consumers (sddm, the
@@ -969,13 +1036,11 @@ for pkg in $PRECOOK_PKGS; do
fi
done
for src in relibc kernel base bootloader installer userutils syscall libredox redox-scheme; do
src_dir="$PROJECT_ROOT/local/sources/$src"
if [ -d "$src_dir/.git" ]; then
git -C "$src_dir" rev-parse HEAD 2>/dev/null > \
"$PROJECT_ROOT/repo/x86_64-unknown-redox/$src.source-fingerprint" 2>/dev/null || true
fi
done
# NB: fork source-fingerprints used to be recorded HERE, before `make live`.
# That meant a build which failed in make live (or the critical-package gate)
# still stamped every fork as "built", so the next run's staleness detection
# skipped work it should have redone. The fingerprint write now happens only
# after a successful, complete build — see below, past the critical gate.
# Per-target env propagation. The cookbook's [build.env] section is not
# read by the current parser, so per-target env-var hooks must be set
@@ -987,20 +1052,20 @@ done
if [ "$CONFIG" = "redbear-bare" ] && [ -z "${REDBEAR_BARE_INITFS:-}" ]; then
REDBEAR_BARE_INITFS=1
export REDBEAR_BARE_INITFS
echo ">>> redbear-bare target: REDBEAR_BARE_INITFS=1 (auto-set; minimal 7-daemon initfs)"
echo "${C_INFO}>>>${C_RESET} redbear-bare target: REDBEAR_BARE_INITFS=1 (auto-set; minimal 7-daemon initfs)"
fi
if [ "${REDBEAR_ALLOW_UPSTREAM:-0}" = "1" ]; then
echo ">>> WARNING: Upstream fetch ENABLED (REDBEAR_ALLOW_UPSTREAM=1)"
echo "${C_WARN}>>> WARNING:${C_RESET} Upstream fetch ENABLED (REDBEAR_ALLOW_UPSTREAM=1)"
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 REDBEAR_BARE_INITFS="${REDBEAR_BARE_INITFS:-0}" make live "CONFIG_NAME=$CONFIG" "JOBS=$JOBS" 2>&1
elif [ -n "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Release mode: building from local forks (offline)"
echo "${C_INFO}>>>${C_RESET} Release mode: building from local forks (offline)"
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 REDBEAR_BARE_INITFS="${REDBEAR_BARE_INITFS:-0}" make live "CONFIG_NAME=$CONFIG" "JOBS=$JOBS" 2>&1
elif [ "$ALLOW_UPSTREAM" -eq 1 ]; then
echo ">>> Upstream recipe refresh enabled"
echo "${C_INFO}>>>${C_RESET} Upstream recipe refresh enabled"
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 REDBEAR_BARE_INITFS="${REDBEAR_BARE_INITFS:-0}" make live "CONFIG_NAME=$CONFIG" "JOBS=$JOBS" 2>&1
else
echo ">>> Upstream recipe refresh disabled (default: offline)"
echo "${C_INFO}>>>${C_RESET} Upstream recipe refresh disabled (default: offline)"
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 REDBEAR_BARE_INITFS="${REDBEAR_BARE_INITFS:-0}" make live "CONFIG_NAME=$CONFIG" "JOBS=$JOBS" 2>&1
fi
@@ -1043,14 +1108,26 @@ if [ -n "$_missing_critical" ]; then
exit 1
fi
# Record fork source-fingerprints ONLY now — after make live and the critical-
# package gate have both succeeded. Recording earlier (before make live) stamped
# forks as "built" even when the build later failed, so the next run's staleness
# detection skipped work it should have redone.
for src in relibc kernel base bootloader installer userutils syscall libredox redox-scheme; do
src_dir="$PROJECT_ROOT/local/sources/$src"
if [ -d "$src_dir/.git" ]; then
git -C "$src_dir" rev-parse HEAD 2>/dev/null > \
"$PROJECT_ROOT/repo/x86_64-unknown-redox/$src.source-fingerprint" 2>/dev/null || true
fi
done
ARCH="${ARCH:-$(uname -m)}"
echo ""
if [ "$STALE_PREFIX" = "1" ]; then
echo ">>> REMINDER: prefix sysroot is stale. Run 'make prefix' to avoid link errors on next build."
echo "${C_WARN}>>> REMINDER:${C_RESET} prefix sysroot is stale. Run 'make prefix' to avoid link errors on next build."
fi
echo "========================================"
echo " Build Complete!"
echo "========================================"
printf '%s========================================%s\n' "$C_OK" "$C_RESET"
printf '%s Build Complete!%s\n' "$C_OK" "$C_RESET"
printf '%s========================================%s\n' "$C_OK" "$C_RESET"
echo "ISO: build/$ARCH/$CONFIG.iso"
echo ""
echo "To run in QEMU:"
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# bump-build-version.sh — git pre-commit hook.
#
# Auto-increments the minor of BUILD_REDBEAR_VERSION in
# local/scripts/build-redbear.sh whenever that file is part of the commit.
# The version starts at 1.0 and bumps to 1.1, 1.2, … on every committed change,
# so the version printed at build start always reflects how many times the
# orchestrator has changed. No manual editing of the minor is needed.
#
# Installed via: ./local/scripts/install-git-hooks.sh --all
# Bypass a single commit with: git commit --no-verify
#
# Limitation: re-staging happens at whole-file granularity, so a partial
# (`git add -p`) stage of build-redbear.sh will be promoted to the full file.
# That is the standard trade-off for a re-staging pre-commit hook.
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
FILE="local/scripts/build-redbear.sh"
# Only act if the build script is actually staged for this commit.
if ! git diff --cached --name-only -- "$FILE" | grep -qx "$FILE"; then
exit 0
fi
# Read the version from the STAGED content (what will actually be committed).
cur="$(git show ":$FILE" 2>/dev/null \
| grep -m1 -oE 'BUILD_REDBEAR_VERSION="[0-9]+\.[0-9]+"' \
| grep -oE '[0-9]+\.[0-9]+' || true)"
if [ -z "$cur" ]; then
# Version constant not found (unexpected) — do not block the commit.
exit 0
fi
major="${cur%%.*}"
minor="${cur#*.}"
new="${major}.$((minor + 1))"
# Update the working-tree file and re-stage so the commit records the bump.
sed -i -E "s/^BUILD_REDBEAR_VERSION=\"[0-9]+\.[0-9]+\"/BUILD_REDBEAR_VERSION=\"${new}\"/" \
"$REPO_ROOT/$FILE"
git add "$FILE"
echo "bump-build-version: build-redbear.sh ${cur} -> ${new}"
exit 0
+26 -6
View File
@@ -104,12 +104,32 @@ should_exclude() {
[[ "$path" == *"$ex"* ]] && return 0
done
# Skip git-fetched upstream sources. Fetched recipe sources (e.g. brush
# from github) live in gitignored, untracked source/ trees; their crate
# versions belong to upstream, not to the Cat 1 in-house branch-version
# policy. Rewriting them breaks upstream-internal version requirements
# (this happened: brush-shell was forced to 0.3.1 while brush required
# ^0.4.0, breaking the build). In-house crates are tracked trees.
# Vendored-upstream opt-out marker.
#
# A recipe under local/recipes/ whose source/ tree is a VENDORED UPSTREAM
# project (not an in-house Red Bear crate) drops a `.vendored-upstream`
# marker file in its recipe directory. Its crate versions belong to upstream
# and carry internal inter-crate `^` requirements (e.g. brush depends on
# brush-parser ^0.4.0, brush-core 0.5.0), so the Cat 1 branch-version stamp
# (0.3.1) must NOT touch them — doing so breaks the upstream-internal version
# graph and the build.
#
# This supersedes the git-untracked heuristic below for the vendored-but-
# COMMITTED case: brush was originally a git-fetched (untracked) source, so
# the untracked check excluded it; once it was vendored (committed, to pin it
# against upstream drift) the tree became tracked and the check stopped
# matching, silently pulling every brush-* crate into the Cat 1 sync. The
# explicit marker is provenance-based, not tracking-based, so it is correct
# regardless of whether the vendored tree is committed.
local recdir="${path%%/source/*}"
if [ -n "$recdir" ] && [ "$recdir" != "$path" ] && [ -f "$recdir/.vendored-upstream" ]; then
return 0
fi
# Skip git-fetched upstream sources. Fetched recipe sources live in
# gitignored, untracked source/ trees; their crate versions belong to
# upstream, not to the Cat 1 in-house branch-version policy. In-house crates
# are tracked trees. (Vendored-but-committed upstreams use the marker above.)
if ! git ls-files --error-unmatch "$path" >/dev/null 2>&1; then
return 0
fi