ece9837d15
Replace 95-line manual symlink list with auto-discovery of all local/recipes/<category>/<name>/ directories. This fixes 15 missing symlinks that would have blocked the redbear-full build, including critical packages: libdrm, qtbase, qtwayland, libinput, libevdev, seatd, and wayland-protocols. Special-case aliases preserved: - kf6-kirigami → kirigami (KDE expects both names) - wip/wayland/qt6-wayland-smoke (historical WIP path)
312 lines
8.8 KiB
Bash
Executable File
312 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# integrate-redbear.sh — Prepare Red Bear OS custom work for standard builds.
|
|
#
|
|
# Usage:
|
|
# ./local/scripts/integrate-redbear.sh
|
|
# REDBEAR_TAG=build/x86_64-unknown-redox/redbear.tag ./local/scripts/integrate-redbear.sh
|
|
#
|
|
# This script is idempotent and safe to run repeatedly. It ensures the Red Bear OS overlay
|
|
# is wired into the main build tree, stages branding assets and firmware into local
|
|
# recipe sources, and updates a tag file consumed by the build system.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
REDBEAR_TAG="${REDBEAR_TAG:-build/redbear.tag}"
|
|
|
|
if [ -t 1 ]; then
|
|
GREEN='\033[1;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[1;36m'
|
|
RESET='\033[0m'
|
|
else
|
|
GREEN=''
|
|
YELLOW=''
|
|
CYAN=''
|
|
RESET=''
|
|
fi
|
|
|
|
cd "$PROJECT_ROOT"
|
|
|
|
status() {
|
|
echo -e "${GREEN}✅${RESET} $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}⚠️${RESET} $1"
|
|
}
|
|
|
|
section() {
|
|
echo -e "${CYAN}==>${RESET} $1"
|
|
}
|
|
|
|
require_repo_relative_path() {
|
|
local path="$1"
|
|
|
|
case "$path" in
|
|
/*|../*|*/../*|..)
|
|
warn "Refusing unsafe path outside repo: $path"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
require_real_parent_dirs() {
|
|
local path="$1"
|
|
local parent="$(dirname "$path")"
|
|
|
|
require_repo_relative_path "$path"
|
|
|
|
while [ "$parent" != "." ] && [ "$parent" != "/" ]; do
|
|
if [ -L "$parent" ]; then
|
|
warn "Refusing path with symlink parent: $path"
|
|
return 1
|
|
fi
|
|
parent="$(dirname "$parent")"
|
|
done
|
|
}
|
|
|
|
symlink() {
|
|
local target="$1"
|
|
local link="$2"
|
|
local current=""
|
|
|
|
require_real_parent_dirs "$link"
|
|
|
|
mkdir -p "$(dirname "$link")"
|
|
|
|
if [ -L "$link" ]; then
|
|
current="$(readlink "$link")"
|
|
if [ "$current" = "$target" ]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
if [ -d "$link" ] && [ ! -L "$link" ]; then
|
|
warn "Refusing to replace directory $link"
|
|
return 1
|
|
fi
|
|
|
|
if [ -e "$link" ] || [ -L "$link" ]; then
|
|
rm -f "$link"
|
|
ln -s "$target" "$link"
|
|
status "Refreshed $link -> $target"
|
|
else
|
|
ln -s "$target" "$link"
|
|
status "Linked $link -> $target"
|
|
fi
|
|
}
|
|
|
|
stage_file() {
|
|
local source_path="$1"
|
|
local dest_path="$2"
|
|
local label="$3"
|
|
|
|
if [ ! -f "$source_path" ]; then
|
|
warn "$label missing at ${source_path#$PROJECT_ROOT/}; skipping"
|
|
return 0
|
|
fi
|
|
|
|
require_real_parent_dirs "$dest_path"
|
|
|
|
if [ -L "$dest_path" ]; then
|
|
warn "$label destination is a symlink at ${dest_path#$PROJECT_ROOT/}; refusing to overwrite"
|
|
return 1
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$dest_path")"
|
|
|
|
if [ -f "$dest_path" ] && cmp -s "$source_path" "$dest_path"; then
|
|
status "$label already staged"
|
|
return 0
|
|
fi
|
|
|
|
cp "$source_path" "$dest_path"
|
|
status "Staged $label"
|
|
}
|
|
|
|
echo "========================================"
|
|
echo " Red Bear OS Pre-Build Integration"
|
|
echo "========================================"
|
|
echo "Root: ${PROJECT_ROOT##*/}"
|
|
echo "Tag: $REDBEAR_TAG"
|
|
echo ""
|
|
|
|
section "Ensuring custom recipe symlinks..."
|
|
|
|
# Auto-discover all local/recipes/<category>/<name>/ directories and symlink
|
|
# into recipes/<category>/<name>. This replaces the previous 95-line manual
|
|
# symlink list which was perpetually out of sync with local/recipes/.
|
|
linked_count=0
|
|
skipped_count=0
|
|
|
|
while IFS= read -r -d '' recipe_dir; do
|
|
rel_path="${recipe_dir#local/recipes/}"
|
|
category="${rel_path%%/*}"
|
|
name="${rel_path#*/}"
|
|
link="recipes/${category}/${name}"
|
|
|
|
# Compute relative path from link to target
|
|
# recipes/<cat>/<name> → ../../local/recipes/<cat>/<name>
|
|
target="../../local/recipes/${rel_path}"
|
|
|
|
if symlink "$target" "$link"; then
|
|
linked_count=$((linked_count + 1))
|
|
else
|
|
skipped_count=$((skipped_count + 1))
|
|
fi
|
|
done < <(find local/recipes -mindepth 2 -maxdepth 2 -type d -print0 2>/dev/null | sort -z)
|
|
|
|
# Special alias: kf6-kirigami → kirigami (KDE expects both names)
|
|
symlink "../../local/recipes/kde/kirigami" "recipes/kde/kf6-kirigami"
|
|
|
|
# WIP compat: qt6-wayland-smoke lives under wayland/ but historically
|
|
# was also linked under recipes/wip/wayland/
|
|
mkdir -p recipes/wip/wayland
|
|
symlink "../../../../local/recipes/wayland/qt6-wayland-smoke" "recipes/wip/wayland/qt6-wayland-smoke"
|
|
|
|
status "Custom recipe symlinks ready (${linked_count} linked, ${skipped_count} skipped)"
|
|
echo ""
|
|
|
|
section "Ensuring recipe patch symlinks..."
|
|
|
|
# Auto-discover patches from local/patches/<component>/ and create/refresh
|
|
# symlinks in the corresponding recipe directories. This replaces the
|
|
# previous hardcoded-per-patch approach which went stale whenever patches
|
|
# were reorganized (e.g. moved to absorbed/ subdirectories).
|
|
|
|
declare -A PATCH_COMPONENT_TO_RECIPE=(
|
|
[kernel]="recipes/core/kernel"
|
|
[base]="recipes/core/base"
|
|
[relibc]="recipes/core/relibc"
|
|
[bootloader]="recipes/core/bootloader"
|
|
[installer]="recipes/core/installer"
|
|
[userutils]="recipes/core/userutils"
|
|
)
|
|
|
|
linked=0
|
|
skipped=0
|
|
|
|
for component in "${!PATCH_COMPONENT_TO_RECIPE[@]}"; do
|
|
recipe_dir="${PATCH_COMPONENT_TO_RECIPE[$component]}"
|
|
[ -d "$recipe_dir" ] || continue
|
|
|
|
patch_dir="local/patches/${component}"
|
|
|
|
# Collect all .patch files from the component dir (skip absorbed/ subdirs).
|
|
find "$patch_dir" -maxdepth 1 -name "*.patch" -type f 2>/dev/null | while read patch_file; do
|
|
patch_name="$(basename "$patch_file")"
|
|
|
|
# Resolve the relative path from recipe dir to patch file.
|
|
# recipe_dir is e.g. recipes/core/base (2 levels deep)
|
|
# patch_file is e.g. local/patches/base/absorbed/P0-foo.patch
|
|
# We need to go up from recipe_dir to repo root, then into local/patches/...
|
|
# For recipes/core/base → ../../.. → repo root → local/patches/base/absorbed/...
|
|
# Number of directory components = slashes + 1
|
|
depth=$(($(echo "$recipe_dir" | tr -cd '/' | wc -c) + 1))
|
|
up=""
|
|
for ((i=0; i<depth; i++)); do up="${up}../"; done
|
|
rel_target="${up}${patch_file}"
|
|
link_path="${recipe_dir}/${patch_name}"
|
|
|
|
symlink "$rel_target" "$link_path"
|
|
done
|
|
done
|
|
|
|
status "Recipe patch symlinks ready"
|
|
echo ""
|
|
|
|
section "Validating Red Bear configs..."
|
|
declare -a redbear_configs=(
|
|
"config/redbear-mini.toml"
|
|
"config/redbear-full.toml"
|
|
"config/redbear-grub.toml"
|
|
)
|
|
declare -a found_configs=()
|
|
|
|
for config_path in "${redbear_configs[@]}"; do
|
|
if [ -f "$config_path" ] || [ -L "$config_path" ]; then
|
|
found_configs+=("${config_path#config/}")
|
|
fi
|
|
done
|
|
|
|
if [ "${#found_configs[@]}" -gt 0 ]; then
|
|
status "Found Red Bear target config(s): ${found_configs[*]}"
|
|
else
|
|
warn "No redbear target config found in config/"
|
|
fi
|
|
echo ""
|
|
|
|
section "Validating branding assets..."
|
|
icon_path="local/Assets/images/Red Bear OS icon.png"
|
|
background_path="local/Assets/images/Red Bear OS loading background.png"
|
|
missing_assets=0
|
|
|
|
if [ ! -f "$icon_path" ]; then
|
|
warn "Missing branding asset: $icon_path"
|
|
missing_assets=1
|
|
fi
|
|
if [ ! -f "$background_path" ]; then
|
|
warn "Missing branding asset: $background_path"
|
|
missing_assets=1
|
|
fi
|
|
if [ "$missing_assets" -eq 0 ]; then
|
|
status "Branding assets present"
|
|
fi
|
|
echo ""
|
|
|
|
section "Checking AMD firmware blobs..."
|
|
shopt -s nullglob
|
|
firmware_blobs=(local/firmware/amdgpu/*.bin)
|
|
shopt -u nullglob
|
|
|
|
if [ "${#firmware_blobs[@]}" -gt 0 ]; then
|
|
status "Found ${#firmware_blobs[@]} AMD firmware blob(s)"
|
|
else
|
|
warn "No AMD firmware blobs found in local/firmware/amdgpu/"
|
|
fi
|
|
echo ""
|
|
|
|
section "Staging branding assets into recipe source..."
|
|
stage_file "$icon_path" "local/recipes/branding/redbear-release/source/images/icon.png" "branding icon"
|
|
stage_file "$background_path" "local/recipes/branding/redbear-release/source/images/loading-background.png" "branding loading background"
|
|
echo ""
|
|
|
|
section "Staging firmware blobs into firmware-loader recipe source..."
|
|
require_real_parent_dirs "local/recipes/system/firmware-loader/source/firmware/amdgpu/.guard"
|
|
mkdir -p "local/recipes/system/firmware-loader/source/firmware/amdgpu"
|
|
shopt -s nullglob
|
|
staged_firmware=(local/recipes/system/firmware-loader/source/firmware/amdgpu/*.bin)
|
|
shopt -u nullglob
|
|
|
|
if [ "${#staged_firmware[@]}" -gt 0 ]; then
|
|
rm -f "${staged_firmware[@]}"
|
|
fi
|
|
|
|
if [ "${#firmware_blobs[@]}" -gt 0 ]; then
|
|
cp -f "${firmware_blobs[@]}" "local/recipes/system/firmware-loader/source/firmware/amdgpu/"
|
|
status "Staged ${#firmware_blobs[@]} AMD firmware blob(s)"
|
|
else
|
|
warn "Skipping firmware staging because no AMD firmware blobs were found"
|
|
fi
|
|
echo ""
|
|
|
|
section "Updating build tag..."
|
|
require_repo_relative_path "$REDBEAR_TAG"
|
|
case "$REDBEAR_TAG" in
|
|
build/*)
|
|
;;
|
|
*)
|
|
warn "Refusing tag path outside build/: $REDBEAR_TAG"
|
|
exit 1
|
|
;;
|
|
esac
|
|
require_real_parent_dirs "$REDBEAR_TAG"
|
|
mkdir -p "$(dirname "$REDBEAR_TAG")"
|
|
touch "$REDBEAR_TAG"
|
|
status "Updated tag file: $REDBEAR_TAG"
|
|
echo ""
|
|
status "Red Bear integration complete"
|
|
exit 0
|