SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
.NOTPARALLEL:
.PHONY: console-vm cartridge-test data-test desktop-test clean clean-preview clean-test

.PHONY: help bootstrap smoke-test check dasung dasung-test rootfs rootfs-test init-test vm tooling tooling-test kernel initramfs system-card boot-volume boot-test console-test performance-test
help:
	@printf '%s\n' 'FDS/OS — static Rust tools and native s6' \
	  'make wiki-check        Check the documentation in fds-os.wiki' \
	  'make clean-preview     Show obsolete build/test directories and Rust output selected for cleanup' \
	  'make clean             Remove that output; keep current images, latest tests, caches and releases' \
	  'make clean-test        Test cleanup protections using small disposable fixtures' \
	  'make workstation Build the Arch fds-tools package' \
	  'make workstation-install Install the Arch fds-tools package with pacman' \
	  'make workstation-binaries Build native binaries on generic Linux' \
	  'make workstation-test  Verify software builds, multi-partition images and file write/readback' \
	  'make flash-test        Verify guided/unattended flashing with disposable files' \
	  'make flash-vm-test     Verify block-device flashing and rejection paths in an isolated ARM VM' \
	  'make emulator-test     Boot FDS and test cartridge hotplug with the public emulator' \
	  'make bootstrap   Prepare Arch x86_64 host and Void build container' \
	  'make packages    Build and export every FDS base package' \
	  'make all         Build CLI, development, recovery, Pi boot and complete internal images' \
	  'make smoke-test  Cross-build and verify GNU hello + static-musl Rust' \
	  'make check       Run validation failure-path tests and formatting checks' \
	  'make kernel      Cross-build the pinned Raspberry Pi 5 kernel' \
	  'make initramfs   Build early Rust userspace in four archive formats' \
	  'make system-card PROFILE=cli  Make GPT/EROFS from the exported rootfs' \
	  'make boot-volume BOOT_MODE=production  Make a Pi FAT32 boot partition' \
	  'make boot-test   Test stage0, media insertion, recovery and all archive formats' \
	  'make desktop-test    Verify ARM WindowMaker, PROGRAM and on-demand DHCP' \
	  'make media-image-test  Check SYSTEM/DATA/ENVIRONMENT creation and legacy PROGRAM compatibility' \
	  'make media-test        Verify confirmed writes to disposable virtual USB media' \
	  'make eeprom EEPROM_PROFILE=production  Prepare a reversible EEPROM preview' \
	  'make eeprom-test       Verify EEPROM configuration and rollback without hardware' \
	  'make stress-test       Verify twelve USB devices and media I/O failure paths' \
	  'make media-fault-test  Verify write/flush/readback errors and interrupted writes' \
	  'make power-test        Verify ordered ARM shutdown, DATA safety and blocked failure paths' \
	  'make data-test       Verify writable DATA and sustained-write safe eject' \
	  'make cartridge-test  Verify virtual USB bays, metadata, mounts and eject' \
	  'make console-test  Verify the FDS user prompt and boot-event reporting' \
	  'make console-vm    Open the ordinary-user FDS console in an ARM VM' \
	  'make performance-test  Compare z/2/3 stage0 builds in the ARM VM' \
	  'make tooling     Build the static ARM FDS CLI and stage0 tools' \
	  'make tooling-test  Test shared contracts and execute the ARM tools' \
	  'make dasung      Build static ARM dasungd, XBPS package and s6 database' \
	  'make dasung-test Test the daemon with simulated hardware and inspect its package' \
	  'make rootfs PROFILE=cli  Assemble, configure and test the ARM base filesystem' \
	  'make recovery           Build the independent recovery rootfs and EROFS payload' \
	  'make recovery-test      Verify SYSTEM-independent recovery and DATA repair in ARM VMs' \
	  'make internal-image     Assemble FDS_BOOT, FDS_RECOVERY and machine settings as one GPT disk' \
	  'make internal-test      Verify virtual SD/NVMe settings, persistence and rejection paths' \
	  'make development-test   Compile, execute and debug C/C++/Rust in the development SYSTEM' \
	  'make clock-test         Verify that native startup preserves a newer guest clock' \
	  'make signing            Build the host release signer and static ARM verifier' \
	  'make signing-test       Check signatures, corruption rejection and OpenSSL interoperability' \
	  'make release-contract-test  Check frozen-lock and complete-build comparison rejection paths' \
	  'make rootfs-test         Verify the exported archive and rejection checks' \
	  'make init-test           Boot an ARM VM and verify s6 PID 1 and service control' \
	  'make vm                  Open a temporary root shell in the verified test VM'

.PHONY: wiki-check
wiki-check:
	python3 tests/integration/wiki-checks.py

clean-preview:
	./tools/clean-builds --dry-run

clean:
	./tools/clean-builds

clean-test:
	python3 tests/integration/clean-checks.py

bootstrap:
	@mkdir -p out/logs
	./tools/bootstrap-host 2>&1 | tee out/logs/bootstrap.log

.PHONY: packages all
packages:
	@mkdir -p out/logs
	./tools/build-base-packages 2>&1 | tee out/logs/packages-build.log

all:
	$(MAKE) bootstrap
	$(MAKE) packages
	$(MAKE) rootfs PROFILE=cli
	$(MAKE) system-card PROFILE=cli
	$(MAKE) rootfs PROFILE=development
	$(MAKE) system-card PROFILE=development
	$(MAKE) recovery
	$(MAKE) initramfs
	$(MAKE) boot-volume BOOT_MODE=production
	$(MAKE) internal-image
	$(MAKE) signing
	$(MAKE) eeprom EEPROM_PROFILE=production

smoke-test:
	@mkdir -p out/logs
	./tools/smoke-test 2>&1 | tee out/logs/smoke-test.log

check: wiki-check
	python3 tests/integration/version-checks.py
	./tests/integration/m0-checks
	cargo fmt --all -- --check
	$(MAKE) clean-test

dasung:
	@mkdir -p out/logs
	./tools/build-dasungd 2>&1 | tee out/logs/dasung-build.log

dasung-test:
	@mkdir -p out/logs
	./tests/integration/dasung-checks 2>&1 | tee out/logs/dasung-checks.log

rootfs:
	@mkdir -p out/logs
	PROFILE=$(or $(PROFILE),cli) ./tools/build-rootfs 2>&1 | tee out/logs/rootfs-build.log

rootfs-test:
	@mkdir -p out/logs
	./tests/integration/m1-checks 2>&1 | tee out/logs/rootfs-checks.log

init-test:
	@mkdir -p out/logs
	./tests/integration/m2-checks 2>&1 | tee out/logs/init-checks.log

vm:
	./tools/run-vm out/m2-vm-latest --shell

tooling:
	@mkdir -p out/logs
	./tools/build-fds 2>&1 | tee out/logs/fds-tools-build.log

tooling-test:
	@mkdir -p out/logs
	./tests/integration/m3-checks 2>&1 | tee out/logs/fds-tools-checks.log

kernel:
	@mkdir -p out/logs
	./tools/build-kernel 2>&1 | tee out/logs/kernel-build.log

initramfs: tooling dasung
	./image/build-initramfs 2>&1 | tee out/logs/initramfs-build.log

system-card:
	./tools/prepare-image-tools
	./image/build-system-cartridge --profile $(or $(PROFILE),cli) --rootfs out/rootfs-$(or $(PROFILE),cli).tar 2>&1 | tee out/logs/system-card-build.log

boot-volume:
	./image/build-boot-volume --mode $(or $(BOOT_MODE),production) 2>&1 | tee out/logs/boot-volume-build.log

boot-test:
	./tests/integration/m4-checks 2>&1 | tee out/logs/boot-checks.log

console-test:
	python3 tests/integration/m5-runtime.py 2>&1 | tee out/logs/console-checks.log

console-vm:
	./tools/run-system-vm

performance-test:
	./tools/compare-rust-profiles 2>&1 | tee out/logs/performance-checks.log

cartridge-test:
	cargo test --locked --offline --target x86_64-unknown-linux-gnu -p fds-common -p fds-cartridged
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-test-helpers --bin m6-client
	cp target/aarch64-unknown-linux-musl/release/m6-client out/m6-client
	python3 tests/integration/m6-runtime.py 2>&1 | tee out/logs/cartridge-checks.log

data-test:
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-test-helpers --bin m7-writer
	cp target/aarch64-unknown-linux-musl/release/m7-writer out/m7-writer
	python3 tests/integration/m7-runtime.py 2>&1 | tee out/logs/data-checks.log

desktop-test:
	python3 tests/integration/m8-runtime.py 2>&1 | tee out/logs/desktop-checks.log

.PHONY: media-image-test media-test
media-image-test: tooling
	python3 tests/integration/m9-images.py 2>&1 | tee out/logs/media-image-checks.log

media-test: tooling
	python3 tests/integration/m9-runtime.py 2>&1 | tee out/logs/media-checks.log
	python3 tests/integration/m9-system.py 2>&1 | tee out/logs/media-system-checks.log

.PHONY: power-test
power-test:
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-test-helpers --bin m7-writer
	cp target/aarch64-unknown-linux-musl/release/m7-writer out/m7-writer
	python3 tests/integration/m10-runtime.py 2>&1 | tee out/logs/power-checks.log

.PHONY: stress-test media-fault-test
stress-test:
	@mkdir -p out/logs
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-test-helpers --bin m11-stress
	cp target/aarch64-unknown-linux-musl/release/m11-stress out/m11-stress
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-test-helpers --bin m7-writer
	cp target/aarch64-unknown-linux-musl/release/m7-writer out/m7-writer
	python3 tests/integration/m11-runtime.py 2>&1 | tee out/logs/stress-checks.log
	$(MAKE) media-fault-test

media-fault-test:
	@mkdir -p out/logs
	python3 tests/integration/m11-media-faults.py 2>&1 | tee out/logs/media-fault-checks.log

.PHONY: eeprom eeprom-test
eeprom:
	./tools/configure-pi-eeprom --profile $(or $(EEPROM_PROFILE),production)

eeprom-test:
	@mkdir -p out/logs
	python3 tests/integration/m12-eeprom.py 2>&1 | tee out/logs/eeprom-checks.log

.PHONY: recovery recovery-test
recovery:
	$(MAKE) rootfs PROFILE=recovery
	./tools/prepare-image-tools
	./image/build-recovery 2>&1 | tee out/logs/recovery-build.log

recovery-test:
	python3 tests/integration/m12-recovery.py 2>&1 | tee out/logs/recovery-checks.log

.PHONY: internal-image internal-test
internal-image:
	./image/build-internal $(if $(MACHINE_CONFIG),--machine-config "$(MACHINE_CONFIG)") 2>&1 | tee out/logs/internal-build.log

internal-test:
	cargo test --locked --offline --target x86_64-unknown-linux-gnu -p fds-cli
	python3 tests/integration/m12-internal.py 2>&1 | tee out/logs/internal-checks.log

.PHONY: development-test clock-test
development-test:
	python3 tests/integration/m12-development.py 2>&1 | tee out/logs/development-checks.log

clock-test:
	python3 tests/integration/m12-clock.py 2>&1 | tee out/logs/clock-checks.log

.PHONY: signing signing-test
signing:
	@mkdir -p out/logs
	./tools/cargo-build --locked --offline --release --target x86_64-unknown-linux-gnu -p fds-release
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-release
	./tools/verify-elf target/aarch64-unknown-linux-musl/release/fds-release aarch64 static

signing-test: signing
	cargo test --locked --offline --target x86_64-unknown-linux-gnu -p fds-release
	python3 tests/integration/m12-signing.py 2>&1 | tee out/logs/signing-checks.log

.PHONY: release-contract-test
release-contract-test:
	@mkdir -p out/logs
	python3 tests/integration/m12-release-build.py 2>&1 | tee out/logs/release-contract-checks.log

.PHONY: workstation workstation-install workstation-binaries workstation-package-test workstation-test emulator-test
workstation:
	@mkdir -p out/logs
	./tools/build-workstation 2>&1 | tee out/logs/workstation-build.log

workstation-package-test: workstation
	python3 tests/integration/arch-package.py

workstation-install: workstation
	./tools/install-workstation

workstation-binaries:
	./tools/build-workstation-binaries

workstation-test: workstation-binaries
	cargo test --locked --offline --target $$(rustc -vV | sed -n 's/^host: //p') -p fds-common -p fds-burn -p fds-software -p fds-workstation
	python3 tests/integration/workstation-flash.py --cli out/workstation/fds-flash
	python3 tests/integration/workstation-images.py --cli out/workstation/fds-cartridge --image-tool-runner tools/in-image-tools --xbps-tool-runner tools/in-void --xbps-bin "$(CURDIR)/.host/xbps/usr/bin" 2>&1 | tee out/logs/workstation-images.log

emulator-test: workstation-binaries
	python3 tests/integration/workstation-emulator.py --cli out/workstation/fds-emulator --qemu-runner tools/in-void 2>&1 | tee out/logs/workstation-emulator.log

.PHONY: flash-test flash-vm-test
flash-test: workstation-binaries
	cargo test --locked --offline --target $$(rustc -vV | sed -n 's/^host: //p') -p fds-workstation flash::
	python3 tests/integration/workstation-flash.py --cli out/workstation/fds-flash

flash-vm-test: flash-test
	./tools/cargo-build --locked --offline --release --target aarch64-unknown-linux-musl -p fds-workstation --bin fds-flash
	./tools/verify-elf target/aarch64-unknown-linux-musl/release/fds-flash aarch64 static
	python3 tests/integration/workstation-flash-vm.py
