Files
RedBear-OS/local/scripts/rebuild-cascade.sh
T
vasilito cee25393d8 fix: boot process improvements — dependency cycle, INIT_NOTIFY, probing loop, and log spam fixes
- Fix P15-8-init-cycle-detection.patch: replace visiting+error with seen+silent-skip
  to eliminate 11 false-positive 'dependency cycle detected' errors on shared deps
- Fix P0-daemon-fix-init-notify-unwrap.patch: remove eprintln! for missing
  INIT_NOTIFY (expected for oneshot_async services, ~7 daemons affected)
- Fix driver-manager hotplug loop: add PERMANENTLY_SKIPPED static set shared
  between hotplug handler and DriverConfig::probe() to stop infinite re-probing
  of Fatal/NotSupported/deferred-exhausted device+driver pairs (e.g. ided)
- Fix driver-manager log_timeline: suppress repeated EPIPE/ENOENT errors with
  AtomicI32 dedup and AtomicBool one-shot guards for boot timeline JSON
- Add driver-manager SIGTERM handler, ACPI bus registration, --status mode,
  driver reap loop, graceful shutdown, and reduced deferred retries (30→3)
2026-05-17 12:34:02 +03:00

215 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# rebuild-cascade.sh — Rebuild a package and all packages that depend on it
#
# Usage:
# ./local/scripts/rebuild-cascade.sh <package> [package2 ...]
# ./local/scripts/rebuild-cascade.sh --dry-run <package>
#
# When a low-level package (e.g. relibc) changes, every package that
# transitively depends on it must be rebuilt. This script:
# 1. Identifies all packages that depend on the target(s)
# 2. Cooks the target package(s) first
# 3. Cooks all dependents in dependency order
# 4. Pushes all rebuilt packages to the sysroot
#
# A package is considered a dependent if its recipe.toml lists the target
# in its [package].dependencies array, OR if its recipe.toml has
# dependencies = [...] that includes the target.
#
# Exit codes:
# 0 — all packages rebuilt and pushed successfully
# 1 — one or more packages failed to build
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
REPO_BIN="${ROOT_DIR}/target/release/repo"
DRY_RUN=0
PACKAGES=()
for arg in "$@"; do
case "$arg" in
--dry-run|-n)
DRY_RUN=1
;;
--help|-h)
echo "Usage: $0 [--dry-run] <package> [package2 ...]"
echo ""
echo "Rebuilds the named package(s) and all packages that transitively"
echo "depend on them, then pushes all to the sysroot."
exit 0
;;
-*)
echo "Unknown option: $arg" >&2
exit 1
;;
*)
PACKAGES+=("$arg")
;;
esac
done
if [ ${#PACKAGES[@]} -eq 0 ]; then
echo "Usage: $0 [--dry-run] <package> [package2 ...]" >&2
exit 1
fi
# Build the repo binary if needed
if [ ! -x "${REPO_BIN}" ]; then
echo "Building repo binary..."
(cd "${ROOT_DIR}" && cargo build --release --bin repo)
fi
cd "${ROOT_DIR}"
# Collect all recipe directories
RECIPE_DIRS=()
for pkg in "${PACKAGES[@]}"; do
# Find the recipe directory
found=0
for dir in recipes/*/; do
if [ -d "${dir}${pkg}" ]; then
RECIPE_DIRS+=("${dir}${pkg}")
found=1
break
fi
done
# Also check local/recipes
if [ $found -eq 0 ]; then
for dir in local/recipes/*/; do
if [ -d "${dir}${pkg}" ]; then
RECIPE_DIRS+=("${dir}${pkg}")
found=1
break
fi
done
fi
if [ $found -eq 0 ]; then
echo "ERROR: recipe not found for package '${pkg}'" >&2
exit 1
fi
done
# Find all recipes that depend on any of the target packages
# by scanning their recipe.toml for dependency entries
find_reverse_deps() {
local target="$1"
local result=()
# Search all recipe.toml files for dependencies
while IFS= read -r -d '' recipe_toml; do
# Get the package name from the directory
pkg_dir="$(dirname "${recipe_toml}")"
pkg_name="$(basename "${pkg_dir}")"
# Skip the target itself
if [ "${pkg_name}" = "${target}" ]; then
continue
fi
# Check if this recipe depends on the target
if grep -q "dependencies.*=.*\[.*${target}.*\]" "${recipe_toml}" 2>/dev/null; then
result+=("${pkg_name}")
fi
done < <(find recipes/ local/recipes/ -name "recipe.toml" -print0 2>/dev/null)
printf '%s\n' "${result[@]}" | sort -u
}
# Build a complete cascade set using BFS
echo "=== Analyzing dependency cascade ==="
CASCADE=()
VISITED=()
QUEUE=("${PACKAGES[@]}")
while [ ${#QUEUE[@]} -gt 0 ]; do
current="${QUEUE[0]}"
QUEUE=("${QUEUE[@]:1}")
# Skip if already visited
for v in "${VISITED[@]}"; do
if [ "$v" = "$current" ]; then
continue 2
fi
done
VISITED+=("$current")
# Find packages that depend on current
mapfile -t rdeps < <(find_reverse_deps "$current" 2>/dev/null || true)
for dep in "${rdeps[@]}"; do
CASCADE+=("${dep}")
QUEUE+=("${dep}")
done
done
# Remove duplicates and sort
UNIQUE_CASCADE=($(printf '%s\n' "${CASCADE[@]}" | sort -u))
# Build order: cook the target packages first, then dependents
BUILD_ORDER=("${PACKAGES[@]}" "${UNIQUE_CASCADE[@]}")
TOTAL=${#BUILD_ORDER[@]}
echo ""
echo "=== Cascade rebuild plan (${TOTAL} packages) ==="
for i in "${!BUILD_ORDER[@]}"; do
pkg="${BUILD_ORDER[$i]}"
if printf '%s\n' "${PACKAGES[@]}" | grep -q "^${pkg}$"; then
echo " [$((i+1))/${TOTAL}] ${pkg} (ROOT)"
else
echo " [$((i+1))/${TOTAL}] ${pkg} (dependent)"
fi
done
if [ $DRY_RUN -eq 1 ]; then
echo ""
echo "=== Dry run — no packages will be built ==="
exit 0
fi
echo ""
echo "=== Starting cascade rebuild ==="
FAILED=()
BUILT=()
export REDOXER_TOOLCHAIN="${ROOT_DIR}/prefix/x86_64-unknown-redox/relibc-install"
for i in "${!BUILD_ORDER[@]}"; do
pkg="${BUILD_ORDER[$i]}"
echo ""
echo "--- [$((i+1))/${TOTAL}] Building ${pkg} ---"
if "${REPO_BIN}" cook "${pkg}"; then
BUILT+=("${pkg}")
echo "--- ${pkg} built successfully ---"
else
FAILED+=("${pkg}")
echo "ERROR: ${pkg} failed to build" >&2
echo "Continuing with remaining packages..."
fi
done
echo ""
echo "=== Pushing ${#BUILT[@]} built packages to sysroot ==="
for pkg in "${BUILT[@]}"; do
echo "Pushing ${pkg}..."
"${REPO_BIN}" push "${pkg}" || echo "WARNING: push ${pkg} failed"
done
echo ""
echo "=== Cascade rebuild summary ==="
echo " Built: ${#BUILT[@]}/${TOTAL}"
echo " Failed: ${#FAILED[@]}/${TOTAL}"
if [ ${#FAILED[@]} -gt 0 ]; then
echo " Failed packages:"
for pkg in "${FAILED[@]}"; do
echo " - ${pkg}"
done
exit 1
fi
echo " All packages rebuilt and pushed successfully."
exit 0