e3e1faece6
Extracts the cookbook_apply_patches function from
src/cook/script.rs and runs it against the real
kf6-karchive source + migration patch. Verifies the
end-to-end flow that C-7 step 2 relies on:
1. First apply: helper applies the patch via
`git apply` from inside ${COOKBOOK_SOURCE},
reports `applying 01-initial-migration.patch`
and `applied=1 skipped=0 failed=0`.
2. Idempotency: running the helper a second time
detects the patch is already applied via
`git apply --reverse --check` and reports
`already applied, skipping`.
3. Post-patch source state: the helper actually
modifies the source — verifies that
`ecm_install_po_files_as_qm` is now commented
out (line starts with `#`) in the source after
the helper runs.
4. 4-level path resolution: verifies that the
`${COOKBOOK_RECIPE}/../../../../local/patches/<name>`
path used in the recipe's [build].script
resolves to the actual patches dir
`local/patches/kf6-karchive`.
These tests use a real pristine/source/patch fixture
(not mocks) and run the actual cookbook helper
extracted from src/cook/script.rs. Any change to
the helper's behavior (path handling, idempotency
check, git apply flags) is caught by these tests.
Makefile:
- New `test-cookbook-apply-patches-e2e` target
- Added to `lint-build-system-all` aggregate
Total: 4 new tests, 164 Python tests total (160 + 4).
All 10 test files pass in <1s.
390 lines
14 KiB
Makefile
390 lines
14 KiB
Makefile
# This file contains the build system commands configuration
|
|
# and environment variables
|
|
include mk/config.mk
|
|
|
|
# Build system dependencies
|
|
include mk/depends.mk
|
|
|
|
all: lint-config $(BUILD)/harddrive.img
|
|
|
|
# ── Red Bear OS Build Cache (OBLIGATORY) ─────────────────────────────────
|
|
# Cache sync is a mandatory part of every successful build.
|
|
# The git-tracked cache survives make clean, make distclean, and git clone.
|
|
#
|
|
# Flow:
|
|
# make all → cache-restore (if needed) → build → cache-sync → cache-commit
|
|
#
|
|
# Commands:
|
|
# make cache-sync Sync built → git cache (manual)
|
|
# make cache-commit Sync + git commit (manual)
|
|
# make cache-restore Restore from git cache
|
|
# make cache-status Compare cache vs build state
|
|
|
|
CACHE_SYNC = local/scripts/cache-sync.sh
|
|
CACHE_SAVE = local/scripts/snapshot-cache.sh
|
|
CACHE_RESTORE = local/scripts/restore-cache.sh
|
|
|
|
cache-sync:
|
|
@bash $(CACHE_SYNC)
|
|
|
|
cache-commit:
|
|
@bash $(CACHE_SYNC) --commit
|
|
|
|
cache-restore:
|
|
@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:
|
|
@bash $(CACHE_RESTORE) --verify
|
|
|
|
cache-list:
|
|
@bash $(CACHE_SAVE) --list
|
|
|
|
cache-status:
|
|
@bash $(CACHE_SYNC) --status
|
|
|
|
# Obligatory cache pipeline — runs before AND after every build
|
|
cache-auto:
|
|
@# ── BEFORE BUILD: restore cache if target is empty ──
|
|
@if [ ! -f $(BUILD)/repo.tag ]; then \
|
|
if ls local/cache/pkgar/*/stage.pkgar >/dev/null 2>&1; then \
|
|
echo "Red Bear: restoring build cache..."; \
|
|
bash $(CACHE_SYNC) --restore; \
|
|
fi; \
|
|
fi
|
|
@# ── AFTER BUILD: sync cache back to git-tracked storage ──
|
|
@if [ -f $(BUILD)/harddrive.img ]; then \
|
|
echo "Red Bear: syncing build cache..."; \
|
|
bash $(CACHE_SYNC); \
|
|
echo "Red Bear: committing cache to git..."; \
|
|
bash $(CACHE_SYNC) --commit 2>/dev/null || echo "Red Bear: cache commit skipped (no changes or not in git repo)"; \
|
|
fi
|
|
|
|
$(BUILD)/harddrive.img: cache-auto
|
|
|
|
live:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -f $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) $(LIVE_ISO)
|
|
|
|
popsicle: $(LIVE_ISO)
|
|
popsicle-gtk $(LIVE_ISO)
|
|
|
|
image:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -f $(BUILD)/harddrive.img $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) all
|
|
|
|
rebuild:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -rf $(BUILD)/repo.tag $(BUILD)/harddrive.img $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) all
|
|
|
|
# To tell that it's not safe
|
|
# to execute the cookbook binary
|
|
NOT_ON_PODMAN?=0
|
|
|
|
clean:
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
ifneq ("$(wildcard $(CONTAINER_TAG))","")
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
$(info will not run cookbook clean as container is not built)
|
|
$(MAKE) clean PODMAN_BUILD=0 NOT_ON_PODMAN=1 SKIP_CHECK_TOOLS=1
|
|
endif # CONTAINER_TAG
|
|
else
|
|
ifneq ($(NOT_ON_PODMAN),1)
|
|
$(MAKE) repo_clean
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
endif # NOT_ON_PODMAN
|
|
rm -rf repo
|
|
rm -rf $(BUILD) $(PREFIX)
|
|
$(MAKE) fstools_clean
|
|
endif # PODMAN_BUILD
|
|
|
|
# distclean: removes build artifacts, toolchain, and upstream source trees.
|
|
# local/ overlay source trees are PROTECTED — the repo binary refuses to
|
|
# unfetch local overlay recipes unless REDBEAR_ALLOW_LOCAL_UNFETCH=1 is set.
|
|
# This is the safe default for Red Bear OS. local/ is NEVER deleted.
|
|
distclean:
|
|
ifneq ($(REDBEAR_RELEASE),)
|
|
$(error distclean is disabled in release mode (REDBEAR_RELEASE=$(REDBEAR_RELEASE)). Sources are immutable. Use: make clean (build artifacts only, safe))
|
|
endif
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
ifneq ("$(wildcard $(CONTAINER_TAG))","")
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
$(info will not run cookbook unfetch as container is not built)
|
|
$(MAKE) distclean PODMAN_BUILD=0 NOT_ON_PODMAN=1 SKIP_CHECK_TOOLS=1
|
|
endif # CONTAINER_TAG
|
|
else
|
|
ifneq ($(NOT_ON_PODMAN),1)
|
|
$(info ==> distclean: cleaning build artifacts and upstream source trees)
|
|
$(info ==> local/ overlay sources are PROTECTED and will NOT be deleted)
|
|
$(MAKE) fetch_clean
|
|
endif # NOT_ON_PODMAN
|
|
$(MAKE) clean NOT_ON_PODMAN=1
|
|
endif # PODMAN_BUILD
|
|
|
|
# distclean-nuclear: DESTRUCTIVE — also deletes local/ overlay source trees.
|
|
# This is the OLD distclean behavior that can destroy Red Bear work.
|
|
# You must set REDBEAR_ALLOW_LOCAL_UNFETCH=1 for this to actually delete
|
|
# local overlay sources. Without it, the repo binary still protects them.
|
|
# Use ONLY when you are certain you want to discard local overlay source code.
|
|
distclean-nuclear:
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
$(info distclean-nuclear is not supported in Podman mode; use native build)
|
|
else
|
|
$(warning !! distclean-nuclear will attempt to DELETE ALL source trees including local/ overlays)
|
|
$(warning !! This can destroy Red Bear OS work that is not committed to git)
|
|
$(warning !! The repo binary still protects local overlays unless REDBEAR_ALLOW_LOCAL_UNFETCH=1)
|
|
$(MAKE) fetch_clean REDBEAR_ALLOW_LOCAL_UNFETCH=1
|
|
$(MAKE) clean NOT_ON_PODMAN=1
|
|
endif # PODMAN_BUILD
|
|
|
|
pull:
|
|
git pull
|
|
rm -f $(FSTOOLS_TAG)
|
|
|
|
repo: $(BUILD)/repo.tag
|
|
|
|
repo_clean: c.--all
|
|
|
|
fetch_clean: u.--all
|
|
|
|
# Podman build recipes and vars
|
|
include mk/podman.mk
|
|
|
|
# Disk Imaging and Cookbook tools
|
|
include mk/fstools.mk
|
|
|
|
# Cross compiler recipes
|
|
include mk/prefix.mk
|
|
|
|
# Repository maintenance
|
|
include mk/repo.mk
|
|
|
|
# Disk images
|
|
include mk/disk.mk
|
|
|
|
# Emulation recipes
|
|
include mk/qemu.mk
|
|
include mk/virtualbox.mk
|
|
|
|
# CI
|
|
include mk/ci.mk
|
|
|
|
include mk/redbear.mk
|
|
|
|
# Ensure Red Bear OS integration runs before repo cook and disk image creation
|
|
$(BUILD)/harddrive.img: $(REDBEAR_TAG)
|
|
$(LIVE_ISO): $(REDBEAR_TAG)
|
|
$(REPO_TAG): $(REDBEAR_TAG)
|
|
|
|
env: prefix FORCE $(CONTAINER_TAG)
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
export PATH="$(PREFIX_PATH):$$PATH" && \
|
|
bash
|
|
endif
|
|
|
|
setenv: FORCE
|
|
@echo export ARCH='$(ARCH)'
|
|
@echo export BOARD='$(BOARD)'
|
|
@echo export CONFIG_NAME='$(CONFIG_NAME)'
|
|
@echo BUILD='$(BUILD)'
|
|
|
|
export RUST_GDB=gdb-multiarch # Necessary when debugging for another architecture than the host
|
|
GDB_KERNEL_FILE=recipes/core/kernel/target/$(TARGET)/build/kernel.sym
|
|
gdb: FORCE
|
|
rust-gdb $(GDB_KERNEL_FILE) --eval-command="target remote :1234"
|
|
|
|
# This target allows debugging a userspace application without requiring gdbserver running inside
|
|
# the VM. Because gdb doesn't know when the userspace application is scheduled by the kernel and as
|
|
# it stops the entire VM rather than just the userspace application that the user wants to debug,
|
|
# connecting to a gdbserver running inside the VM is highly encouraged when possible. This target
|
|
# should only be used when the application to debug runs early during boot before the network stack
|
|
# has started or you need to debug the interaction between the application and the kernel.
|
|
# tl;dr: DO NOT USE THIS TARGET UNLESS YOU HAVE TO
|
|
gdb-userspace: FORCE
|
|
rust-gdb $(GDB_APP_FILE) --eval-command="add-symbol-file $(GDB_KERNEL_FILE)" --eval-command="target remote :1234"
|
|
|
|
# An empty target
|
|
FORCE:
|
|
|
|
.PHONY: lint-patches lint-patches-full lint-kf6-deps lint-cook-failure \
|
|
lint-cook-failure-explain lint-cook-recipe lint-recipe lint-recipe.% \
|
|
lint-recipe.strict lint-recipe.%.strict \
|
|
lint-build-system lint-build-system-full \
|
|
lint-build-system-all \
|
|
test-lint-scripts test-lint-scripts-quiet \
|
|
test-migration-dry-run test-scratch-dry-run \
|
|
test-cleanup-noop-seds \
|
|
scratch-rebuild \
|
|
repair.% clean-repair.%
|
|
|
|
# Wireshark
|
|
wireshark: FORCE
|
|
wireshark $(BUILD)/network.pcap
|
|
packages-sync: ; @bash local/scripts/sync-packages.sh
|
|
packages-list: ; @ls -la Packages/*.pkgar 2>/dev/null | wc -l && echo "pkgar files in Packages/"
|
|
validate-sources:
|
|
@for d in local/sources/kernel local/sources/relibc local/sources/base local/sources/bootloader local/sources/installer; do \
|
|
if [ -d "$$d/.git" ]; then \
|
|
echo "$$d: $(shell git -C $$d rev-list --count HEAD 2>/dev/null || echo 0) commits, $(shell git -C $$d ls-files 2>/dev/null | wc -l) files"; \
|
|
else \
|
|
echo "$$d: MISSING — run local/scripts/create-forks.sh"; \
|
|
fi; \
|
|
done
|
|
|
|
# v6.0 build-system lint targets. These run the three audit scripts
|
|
# that validate the v6.0 build system: idempotent patches, KF6 dep
|
|
# accuracy, and cook-failure classification. Each target exits non-zero
|
|
# on a real problem so CI can wire them up directly.
|
|
|
|
lint-patches:
|
|
@python3 local/scripts/audit-patch-idempotency.py --no-fetch
|
|
|
|
lint-patches-full:
|
|
@python3 local/scripts/audit-patch-idempotency.py
|
|
|
|
lint-kf6-deps:
|
|
@python3 local/scripts/audit-kf6-deps.py --no-fetch
|
|
|
|
test-lint-scripts:
|
|
@python3 -m unittest discover -s local/scripts/tests -v
|
|
|
|
test-lint-scripts-quiet:
|
|
@python3 -m unittest discover -s local/scripts/tests
|
|
|
|
# Smoke test: run the KF6 sed migration script in --dry-run
|
|
# against the live recipe tree. Catches:
|
|
# - recipe discovery regression (script can't find kf6-*)
|
|
# - path-argument vs name-argument mixup
|
|
# - permission / executable issues
|
|
# Does NOT do any real fetches, cooks, or patch writes.
|
|
test-migration-dry-run:
|
|
@./local/scripts/migrate-kf6-seds-to-patches.sh --dry-run --limit=1
|
|
|
|
# Smoke test: run the #10 scratch-rebuild script in --dry-run
|
|
# against the live tree. Catches:
|
|
# - autotools discovery regression
|
|
# - dep-closure BFS errors
|
|
# - permission / executable issues
|
|
# Does NOT do any real rm, fetch, or cook. <2s wall-clock.
|
|
test-scratch-dry-run:
|
|
@./local/scripts/scratch-rebuild.sh --dry-run
|
|
|
|
# Smoke test: run the noop-sed cleanup script's python heredoc
|
|
# against a synthetic recipe fixture (no real recipes touched).
|
|
# Validates that multi-line `sed -i ... \` continuations and
|
|
# `&& cd ...` chains are correctly consumed without leaving
|
|
# orphan file-path lines.
|
|
test-cleanup-noop-seds:
|
|
@python3 -m unittest local.scripts.tests.test_cleanup_kf6_noop_seds -v
|
|
|
|
# Tests the python heredoc inside
|
|
# edit-kf6-recipes-for-patches.sh — the script that
|
|
# replaces every `sed -i ...` chain in a recipe's
|
|
# [build].script with a single cookbook_apply_patches
|
|
# call. Validates the python regex logic against
|
|
# single-sed, multi-line, chained, and real-recipe
|
|
# fixtures.
|
|
test-edit-kf6-recipes:
|
|
@python3 -m unittest local.scripts.tests.test_edit_kf6_recipes_for_patches -v
|
|
|
|
# End-to-end test of cookbook_apply_patches: extracts
|
|
# the helper from src/cook/script.rs and runs it
|
|
# against the real kf6-karchive source + migration
|
|
# patch. Verifies the first apply works, idempotency
|
|
# skips the second, the post-patch source has the
|
|
# expected state, and the 4-level path resolves.
|
|
test-cookbook-apply-patches-e2e:
|
|
@python3 -m unittest local.scripts.tests.test_cookbook_apply_patches_e2e -v
|
|
|
|
# Full scratch rebuild of autotools-using recipes + transitive
|
|
# closure. Deletes target/<arch>/{build,sysroot,stage.tmp}/ per
|
|
# recipe in the closure and re-cooks in dep order. Use after
|
|
# toolchain or relibc changes when the cookbook's fingerprint
|
|
# detection misses a real staleness. <2s wall-clock for the
|
|
# discovery + closure phase; cook time depends on closure size.
|
|
# JOBS=N (default 4) controls the parallel rebuild workers.
|
|
# SCRATCH_RECIPES_DIR / SCRATCH_LOG_DIR override defaults.
|
|
scratch-rebuild:
|
|
@./local/scripts/scratch-rebuild.sh
|
|
|
|
lint-cook-failure:
|
|
@python3 local/scripts/classify-cook-failure.py --last || \
|
|
(echo "No /tmp/redbear-cook.log or /tmp/build.log found. Run a cook first."; exit 0)
|
|
|
|
lint-cook-failure-explain:
|
|
@python3 local/scripts/classify-cook-failure.py --explain-rule qfloat16
|
|
|
|
# Per-recipe v6.0-policy lint. Catches R1/R2 violations BEFORE the
|
|
# slow cook starts. Per build-system improvement #5.
|
|
# Usage:
|
|
# make lint-recipe # all recipes in local/recipes/
|
|
# make lint-recipe.kf6-kimageformats # one recipe by bare name
|
|
# make lint-recipe.strict # all recipes, warnings as errors
|
|
# make lint-recipe.kf6-kimageformats.strict # one recipe, strict mode
|
|
lint-recipe:
|
|
@python3 local/scripts/lint-recipe.py --all
|
|
|
|
lint-recipe.%:
|
|
@python3 local/scripts/lint-recipe.py $*
|
|
|
|
lint-recipe.strict:
|
|
@python3 local/scripts/lint-recipe.py --all --strict
|
|
|
|
lint-recipe.%.strict:
|
|
@python3 local/scripts/lint-recipe.py $* --strict
|
|
|
|
lint-build-system: lint-patches lint-kf6-deps lint-cook-recipe lint-recipe
|
|
@echo "Build system lint complete."
|
|
|
|
lint-build-system-full: lint-patches-full lint-kf6-deps lint-cook-recipe lint-recipe
|
|
@echo "Full build system lint complete (with network)."
|
|
|
|
# Aggregate target: run every lint + every test + every smoke
|
|
# test. Single make target for "is the build system healthy?".
|
|
# Use this in CI to gate merges; use the individual targets
|
|
# (`make lint-recipe`, `make test-migration-dry-run`, etc.) for
|
|
# narrower checks.
|
|
#
|
|
# Note: lint-patches returns 2 in --no-fetch mode (all skipped).
|
|
# The Gitea CI workflow wraps this in a case statement that
|
|
# accepts 0 OR 2 as pass; the per-recipe lint target (.PHONY
|
|
# target) does not run lint-patches.
|
|
lint-build-system-all: test-lint-scripts test-migration-dry-run test-scratch-dry-run test-cleanup-noop-seds test-edit-kf6-recipes test-cookbook-apply-patches-e2e
|
|
@echo "All build-system lint + tests complete."
|
|
cascade.%: FORCE
|
|
@bash local/scripts/rebuild-cascade.sh $(basename $(subst cascade,, $*))
|
|
|
|
# Repair-cook wrapper: equivalent to `repo cook <recipe>` but with
|
|
# a fast-path that skips configure + compile if the existing build/
|
|
# is still valid. Per build-system improvement #2.
|
|
# Usage: make repair.qtbase (incremental, fast if cache fresh)
|
|
# make repair.qtbase CLEAN=1 (force full rebuild)
|
|
repair.%: FORCE
|
|
@if [ "$(CLEAN)" = "1" ]; then \
|
|
./local/scripts/repair-cook.sh $* --clean-build; \
|
|
else \
|
|
./local/scripts/repair-cook.sh $*; \
|
|
fi
|
|
# Use `make clean-repair.X` to force a clean rebuild
|
|
# (alias for the CLEAN=1 form above)
|
|
clean-repair.%: FORCE
|
|
@./local/scripts/repair-cook.sh $* --clean-build
|