ffbe098ef8
TLC (Twilight Commander) was missing from both ISO configs. Added
tlc = {} to [packages] in redbear-mini.toml and redbear-full.toml.
Created missing symlink: recipes/tui/tlc -> ../../local/recipes/tui/tlc.
285 lines
8.2 KiB
Bash
Executable File
285 lines
8.2 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}"
|
|
|
|
# Precompute the entire dependency graph in a single pass. With 3000+ recipes,
|
|
# doing per-target awk invocations in the BFS loop is O(N²) and unworkable.
|
|
# Precompute once, query in O(1). Function definitions must come before
|
|
# their use; place them here so the index build below can call them.
|
|
|
|
extract_recipe_deps() {
|
|
local pkg_dir="$1"
|
|
local recipe_toml="${pkg_dir}/recipe.toml"
|
|
local deps=""
|
|
|
|
if [ ! -f "${recipe_toml}" ]; then
|
|
echo ""
|
|
return
|
|
fi
|
|
|
|
# Both [package] and [build] sections contribute deps. The cookbook's
|
|
# get_build_deps_recursive() walks both; this script must match.
|
|
local in_section=""
|
|
local in_deps=0
|
|
while IFS= read -r line; do
|
|
if [[ "${line}" =~ ^[[:space:]]*\[([^]]+)\][[:space:]]*$ ]]; then
|
|
local sect="${BASH_REMATCH[1]// /}"
|
|
if [ "${sect}" = "package" ] || [ "${sect}" = "build" ]; then
|
|
in_section="${sect}"
|
|
else
|
|
in_section=""
|
|
fi
|
|
in_deps=0
|
|
continue
|
|
fi
|
|
[ -z "${in_section}" ] && continue
|
|
|
|
if [ "${in_deps}" = 1 ]; then
|
|
local item="${line}"
|
|
item="${item## }"; item="${item%% }"
|
|
item="${item#\"}"; item="${item%\"}"
|
|
item="${item%,}"
|
|
[ -n "${item}" ] && deps+="${item},"
|
|
if [[ "${line}" =~ ^[[:space:]]*\] ]]; then
|
|
in_deps=0
|
|
fi
|
|
continue
|
|
fi
|
|
if [[ "${line}" =~ ^[[:space:]]*(dependencies|dev_dependencies)[[:space:]]*=[[:space:]]*\[ ]]; then
|
|
in_deps=1
|
|
local inline="${line#*=}"
|
|
inline="${inline#[}"
|
|
if [[ "${inline}" == *\]* ]]; then
|
|
in_deps=0
|
|
inline="${inline%]*}"
|
|
for item in ${inline//,/ }; do
|
|
item="${item## }"; item="${item%% }"
|
|
item="${item#\"}"; item="${item%\"}"
|
|
[ -n "${item}" ] && deps+="${item},"
|
|
done
|
|
fi
|
|
fi
|
|
done < "${recipe_toml}"
|
|
|
|
echo "${deps}"
|
|
}
|
|
|
|
recipe_source_dir() {
|
|
local pkg_dir="$1"
|
|
local recipe_toml="${pkg_dir}/recipe.toml"
|
|
[ -f "${recipe_toml}" ] || return 0
|
|
local rel
|
|
rel="$(awk '/^\[source\]/{flag=1; next} /^\[/{flag=0} flag' \
|
|
"${recipe_toml}" 2>/dev/null | \
|
|
awk -F'=' '/^path[[:space:]]*=/{gsub(/[" ]/, "", $2); print $2; exit}')"
|
|
if [ -n "${rel}" ]; then
|
|
(cd "${pkg_dir}" && cd "${rel}" 2>/dev/null && pwd)
|
|
fi
|
|
}
|
|
|
|
mapfile -t ALL_RECIPE_TOMLS < <(find recipes/ local/recipes/ -name "recipe.toml" 2>/dev/null)
|
|
echo "Cached ${#ALL_RECIPE_TOMLS[@]} recipe.toml paths"
|
|
|
|
# recipe_index maps pkg_name -> "pkg_dir|recipe_toml|depends_csv"
|
|
declare -A recipe_index=()
|
|
for recipe_toml in "${ALL_RECIPE_TOMLS[@]}"; do
|
|
pkg_dir="$(dirname "${recipe_toml}")"
|
|
pkg_name="$(basename "${pkg_dir}")"
|
|
deps="$(extract_recipe_deps "${pkg_dir}")"
|
|
recipe_index["${pkg_name}"]="${pkg_dir}|${recipe_toml}|${deps}"
|
|
done
|
|
|
|
# Find all recipes that depend on the target by querying the precomputed
|
|
# index. Returns newline-separated pkg names that depend on target.
|
|
find_reverse_deps() {
|
|
local target="$1"
|
|
local result=()
|
|
|
|
# Empty target would match every empty-deps entry — reject early.
|
|
if [ -z "${target}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
local pkg_name entry
|
|
for pkg_name in "${!recipe_index[@]}"; do
|
|
if [ "${pkg_name}" = "${target}" ]; then
|
|
continue
|
|
fi
|
|
entry="${recipe_index[${pkg_name}]}"
|
|
# entry format: "pkg_dir|recipe_toml|deps_csv"
|
|
local deps_csv="${entry##*|}"
|
|
if [[ ",${deps_csv}," == *",${target},"* ]]; then
|
|
result+=("${pkg_name}")
|
|
fi
|
|
done
|
|
|
|
if [ ${#result[@]} -gt 0 ]; then
|
|
printf '%s\n' "${result[@]}" | sort -u
|
|
fi
|
|
}
|
|
|
|
# Validate that the requested package names exist in the index
|
|
for pkg in "${PACKAGES[@]}"; do
|
|
if [ -z "${recipe_index[${pkg}]+_}" ]; then
|
|
echo "ERROR: recipe not found for package '${pkg}'" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# 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
|