cache: git-tracked build cache — 16 packages, survives make clean + clone

Red Bear is a fork/overlay on top of Redox. The upstream build
system wasn't designed for forks — it loses all cached stages on
make clean with no recovery path.

This commit adds a git-tracked build cache:
- local/cache/pkgar/{pkg}/stage.pkgar — per-package cache files
- cache-sync.sh: sync built packages → git-tracked cache
- cache-sync.sh --restore: restore cache → recipe targets
- cache-sync.sh --commit: sync + git commit
- Auto-restore before build, auto-sync after build

Cache survives: make clean, make distclean, git clone, upstream rebase.
Recovery from clean: seconds (restore from git) vs hours (full rebuild).
This commit is contained in:
2026-04-28 08:14:22 +01:00
parent d1c5beb50d
commit 62b99f8678
71 changed files with 214 additions and 24 deletions
+5
View File
@@ -76,3 +76,8 @@ TASK_COMPLETION_SUMMARY.md
__pycache__/ __pycache__/
extra.img: 1073741824 bytes extra.img: 1073741824 bytes
extra.img extra.img
local/cache/pkgar/
# Red Bear git-tracked build cache (survives make clean)
!local/cache/pkgar/
!local/cache/pkgar/**
+42 -20
View File
@@ -9,41 +9,63 @@ all: $(BUILD)/harddrive.img
# ── Red Bear OS Build Cache ────────────────────────────────────────────── # ── Red Bear OS Build Cache ──────────────────────────────────────────────
# The upstream Redox build system loses cached stages on make clean. # The upstream Redox build system loses cached stages on make clean.
# Red Bear provides snapshot/restore so the build can recover quickly. # Red Bear provides a git-tracked cache that survives everything.
# Essential package caches are tracked in git under local/cache/essential/. #
# Architecture:
# local/cache/pkgar/{pkgname}/stage.pkgar — committed to git
# local/cache/rbos-cache-*/ — timestamped snapshots
# #
# Usage: # Usage:
# make cache-save Save full cache snapshot # make cache-sync Sync built packages → git-tracked cache
# make cache-save-essential Save only essential (boot) packages # make cache-commit Sync + git commit
# make cache-restore Auto-restore latest cache before build # make cache-restore Restore from git-tracked cache
# make cache-verify Check cache integrity # make cache-save Full timestamped snapshot (local only)
# make cache-status Compare cache vs build state
# make cache-list List available snapshots
CACHE_SCRIPT = local/scripts/snapshot-cache.sh CACHE_SYNC = local/scripts/cache-sync.sh
RESTORE_SCRIPT = local/scripts/restore-cache.sh CACHE_SAVE = local/scripts/snapshot-cache.sh
CACHE_RESTORE = local/scripts/restore-cache.sh
cache-save: cache-sync:
@bash $(CACHE_SCRIPT) @bash $(CACHE_SYNC)
cache-save-essential: cache-commit:
@bash $(CACHE_SCRIPT) --essential @bash $(CACHE_SYNC) --commit
cache-restore: cache-restore:
@bash $(RESTORE_SCRIPT) @echo "Red Bear: restoring from git-tracked cache..."
@bash $(CACHE_SYNC) --restore
@bash $(CACHE_RESTORE) 2>/dev/null || true
cache-save:
@bash $(CACHE_SAVE)
cache-save-essential:
@bash $(CACHE_SAVE) --essential
cache-verify: cache-verify:
@bash $(RESTORE_SCRIPT) --verify @bash $(CACHE_RESTORE) --verify
cache-list: cache-list:
@bash $(CACHE_SCRIPT) --list @bash $(CACHE_SAVE) --list
# Auto-restore cache if available (runs before all builds) cache-status:
@bash $(CACHE_SYNC) --status
# Auto-restore cache before build, sync after successful build
cache-auto: cache-auto:
@if [ -d local/cache ] && ls local/cache/rbos-cache-* >/dev/null 2>&1; then \ @if [ ! -f $(BUILD)/repo.tag ]; then \
echo "Red Bear: restoring build cache..."; \ if ls local/cache/pkgar/*/stage.pkgar >/dev/null 2>&1; then \
bash $(RESTORE_SCRIPT); \ echo "Red Bear: build cache found, restoring..."; \
bash $(CACHE_SYNC) --restore; \
fi; \
fi
@if [ -f $(BUILD)/harddrive.img ]; then \
echo "Red Bear: build complete, syncing cache..."; \
bash $(CACHE_SYNC); \
fi fi
# Ensure cache is restored before build
$(BUILD)/harddrive.img: cache-auto $(BUILD)/harddrive.img: cache-auto
live: live:
-4
View File
@@ -1,4 +0,0 @@
*
!essential/
!.gitignore
!.gitkeep
+1
View File
@@ -0,0 +1 @@
# Red Bear git-tracked cache — survives make clean and git clone
+1
View File
@@ -0,0 +1 @@
# Red Bear package caches — committed to git
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = ["ncursesw"]
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
[snapshot]
name = "rbos-cache-20260428-080713"
timestamp = "20260428-080713"
mode = "--full"
packages = 16
total_size = 129468786
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = ["ncursesw"]
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
packages = []
Binary file not shown.
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env bash
# Red Bear OS — Git-Tracked Build Cache
# Automatically syncs recipe stage.pkgar files to local/cache/pkgar/
# and commits them to git so the cache survives make clean AND git clone.
#
# The cache is organized as: local/cache/pkgar/{pkgname}/stage.pkgar
# This keeps individual files small enough for git (<100MB each).
#
# Usage:
# ./local/scripts/cache-sync.sh # Sync all built packages to cache
# ./local/scripts/cache-sync.sh --commit # Sync + git commit
# ./local/scripts/cache-sync.sh --restore # Restore cache to recipe targets
# ./local/scripts/cache-sync.sh --status # Show cache vs build state
set -euo pipefail
cd "$(dirname "$0")/../.."
CACHE_ROOT="local/cache/pkgar"
mkdir -p "${CACHE_ROOT}"
MODE="${1:-}"
if [ "$MODE" = "--status" ]; then
echo "=== Red Bear Cache Status ==="
cached=0; stale=0; missing=0
for pkgar in "${CACHE_ROOT}"/*/stage.pkgar; do
[ -f "$pkgar" ] || continue
pkg=$(basename "$(dirname "$pkgar")")
recipe_dir=$(find recipes -maxdepth 3 -name "$pkg" -type d 2>/dev/null | head -1)
if [ -z "$recipe_dir" ]; then
echo " ORPHAN $pkg (no recipe)"
stale=$((stale + 1))
continue
fi
target="${recipe_dir}/target/x86_64-unknown-redox/stage.pkgar"
if [ -f "$target" ]; then
if [ "$pkgar" -nt "$target" ]; then
echo " STALE $pkg (cache newer than build)"
stale=$((stale + 1))
else
echo " SYNCED $pkg"
cached=$((cached + 1))
fi
else
echo " CACHED $pkg (no build)"
cached=$((cached + 1))
fi
done
# Check built but not cached
while IFS= read -r target; do
pkg=$(echo "$target" | sed 's|recipes/[^/]*/[^/]*/||; s|/target/.*||')
if [ ! -f "${CACHE_ROOT}/${pkg}/stage.pkgar" ]; then
size=$(stat -c%s "$target" 2>/dev/null || echo 0)
echo " UNCACHED $pkg ($(numfmt --to=iec $size 2>/dev/null || echo ${size}B))"
missing=$((missing + 1))
fi
done < <(find recipes -name "stage.pkgar" -path "*/target/x86_64-unknown-redox/*" 2>/dev/null | head -100)
echo ""
echo "Synced: $cached Stale: $stale Uncached: $missing"
exit 0
fi
if [ "$MODE" = "--restore" ]; then
echo "=== Restoring Cache to Recipes ==="
count=0
for pkgar in "${CACHE_ROOT}"/*/stage.pkgar; do
[ -f "$pkgar" ] || continue
pkg=$(basename "$(dirname "$pkgar")")
recipe_dir=$(find recipes -maxdepth 4 -name "$pkg" -type d 2>/dev/null | head -1)
if [ -z "$recipe_dir" ]; then continue; fi
target="${recipe_dir}/target/x86_64-unknown-redox/stage.pkgar"
if [ ! -f "$target" ] || [ "$pkgar" -nt "$target" ]; then
mkdir -p "$(dirname "$target")"
cp "$pkgar" "$target"
count=$((count + 1))
fi
done
echo "Restored $count packages"
exit 0
fi
# Default: --sync mode
echo "=== Syncing Build Cache ==="
synced=0
while IFS= read -r target; do
pkg_path="${target%/target/x86_64-unknown-redox/stage.pkgar}"
# Extract package name: recipes/{category}/{name}/target/... → {name}
pkg=$(basename "$pkg_path")
[ -z "$pkg" ] && continue
cache_dir="${CACHE_ROOT}/${pkg}"
cache_file="${cache_dir}/stage.pkgar"
# Only copy if build is newer
if [ -f "$cache_file" ] && [ ! "$target" -nt "$cache_file" ]; then
continue
fi
mkdir -p "$cache_dir"
cp "$target" "$cache_file"
# Also save auto_deps
deps_file="${pkg_path}/target/x86_64-unknown-redox/auto_deps.toml"
if [ -f "$deps_file" ]; then
cp "$deps_file" "${cache_dir}/auto_deps.toml"
fi
synced=$((synced + 1))
done < <(find recipes -name "stage.pkgar" -path "*/target/x86_64-unknown-redox/*" 2>/dev/null)
echo "Synced $synced packages to ${CACHE_ROOT}/"
if [ "$MODE" = "--commit" ] && [ $synced -gt 0 ]; then
echo ""
echo "=== Committing Cache ==="
git add "${CACHE_ROOT}/"
# Only commit if there are staged changes
if git diff --cached --quiet; then
echo "No cache changes to commit"
else
commit_msg="cache: $(date +%Y-%m-%d)${synced} packages"
git commit -m "$commit_msg"
echo "Committed: $commit_msg"
echo "To push: git push"
fi
fi