cee25393d8
- 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)
215 lines
5.7 KiB
Bash
Executable File
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
|