SHELL := /usr/bin/env bash

GO ?= go
GOFMT ?= gofmt
INSTALL ?= install
PREFIX ?= $(HOME)/.local
BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
RUNTIMEDIR ?= $(LIBDIR)/banger
DESTDIR ?=
RUNTIME_MANIFEST ?= runtime-bundle.toml
RUNTIME_SOURCE_DIR ?= runtime
RUNTIME_ARCHIVE ?= dist/banger-runtime.tar.gz
BINARIES := banger bangerd
RUNTIME_HELPERS := $(RUNTIME_SOURCE_DIR)/banger-vsock-agent
GO_SOURCES := $(shell find cmd internal -type f -name '*.go' | sort)
RUNTIME_EXECUTABLES := firecracker customize.sh packages.sh namegen banger-vsock-agent
RUNTIME_DATA_FILES := packages.apt id_ed25519 rootfs-docker.ext4
RUNTIME_OPTIONAL_DATA_FILES := rootfs.ext4 rootfs-docker.work-seed.ext4 bundle.json
RUNTIME_BOOT_FILES := wtf/root/boot/vmlinux-6.8.0-94-generic wtf/root/boot/initrd.img-6.8.0-94-generic
RUNTIME_MODULES_DIR := wtf/root/lib/modules/6.8.0-94-generic
VOID_IMAGE_NAME ?= void-exp
VOID_VM_NAME ?= void-dev

.DEFAULT_GOAL := help

.PHONY: help build banger bangerd test fmt tidy clean rootfs rootfs-void void-register void-vm verify-void install runtime-bundle runtime-package check-runtime bench-create

help:
	@printf '%s\n' \
	  'Targets:' \
	  '  make build   Build ./banger and ./bangerd' \
	  '  make runtime-bundle Fetch and unpack ./runtime from the archive referenced by $(RUNTIME_MANIFEST)' \
	  '  make runtime-package Package $(RUNTIME_SOURCE_DIR) into $(RUNTIME_ARCHIVE) and print its SHA256' \
	  '  make bench-create Benchmark vm create and SSH readiness with scripts/bench-create.sh' \
	  '  make install Build and install binaries plus the runtime bundle into $(DESTDIR)$(BINDIR) and $(DESTDIR)$(RUNTIMEDIR)' \
	  '  make test    Run go test ./...' \
	  '  make fmt     Format Go sources under cmd/ and internal/' \
	  '  make tidy    Run go mod tidy' \
	  '  make clean   Remove built Go binaries' \
	  '  make rootfs  Rebuild the source-checkout default Debian rootfs image in ./runtime' \
	  '  make rootfs-void  Build an experimental Void Linux rootfs and work-seed in ./runtime' \
	  '  make void-register  Register or update the experimental Void image as $(VOID_IMAGE_NAME)' \
	  '  make void-vm  Register the experimental Void image and create a VM named $(VOID_VM_NAME)' \
	  '  make verify-void  Register the experimental Void image and run verify.sh against it'

build: $(BINARIES) $(RUNTIME_HELPERS)

banger: $(GO_SOURCES) go.mod go.sum
	$(GO) build -o ./banger ./cmd/banger

bangerd: $(GO_SOURCES) go.mod go.sum
	$(GO) build -o ./bangerd ./cmd/bangerd

$(RUNTIME_SOURCE_DIR)/banger-vsock-agent: $(GO_SOURCES) go.mod go.sum
	mkdir -p "$(RUNTIME_SOURCE_DIR)"
	CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -o "$(RUNTIME_SOURCE_DIR)/banger-vsock-agent" ./cmd/banger-vsock-agent

test:
	$(GO) test ./...

fmt:
	$(GOFMT) -w $(GO_SOURCES)

tidy:
	$(GO) mod tidy

clean:
	rm -f ./banger ./bangerd

runtime-bundle:
	$(GO) run ./cmd/runtimebundle fetch --manifest "$(RUNTIME_MANIFEST)" --out "$(RUNTIME_SOURCE_DIR)"

runtime-package:
	$(GO) run ./cmd/runtimebundle package --manifest "$(RUNTIME_MANIFEST)" --runtime-dir "$(RUNTIME_SOURCE_DIR)" --out "$(RUNTIME_ARCHIVE)"

bench-create: build
	bash ./scripts/bench-create.sh $(ARGS)

check-runtime:
	@test -d "$(RUNTIME_SOURCE_DIR)" || { echo "missing runtime bundle directory: $(RUNTIME_SOURCE_DIR); run 'make runtime-bundle'" >&2; exit 1; }
	@for path in $(RUNTIME_EXECUTABLES) $(RUNTIME_DATA_FILES) $(RUNTIME_BOOT_FILES) $(RUNTIME_MODULES_DIR); do \
		test -e "$(RUNTIME_SOURCE_DIR)/$$path" || { echo "missing runtime artifact: $(RUNTIME_SOURCE_DIR)/$$path; run 'make runtime-bundle'" >&2; exit 1; }; \
	done

install: build check-runtime
	mkdir -p "$(DESTDIR)$(BINDIR)"
	mkdir -p "$(DESTDIR)$(RUNTIMEDIR)"
	mkdir -p "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/boot"
	mkdir -p "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/lib/modules"
	$(INSTALL) -m 0755 ./banger "$(DESTDIR)$(BINDIR)/banger"
	$(INSTALL) -m 0755 ./bangerd "$(DESTDIR)$(BINDIR)/bangerd"
	@for path in $(RUNTIME_EXECUTABLES); do \
		$(INSTALL) -m 0755 "$(RUNTIME_SOURCE_DIR)/$$path" "$(DESTDIR)$(RUNTIMEDIR)/$$path"; \
	done
	@for path in $(RUNTIME_DATA_FILES) $(RUNTIME_BOOT_FILES); do \
		$(INSTALL) -m 0644 "$(RUNTIME_SOURCE_DIR)/$$path" "$(DESTDIR)$(RUNTIMEDIR)/$$path"; \
	done
	@for path in $(RUNTIME_OPTIONAL_DATA_FILES); do \
		if test -e "$(RUNTIME_SOURCE_DIR)/$$path"; then \
			$(INSTALL) -m 0644 "$(RUNTIME_SOURCE_DIR)/$$path" "$(DESTDIR)$(RUNTIMEDIR)/$$path"; \
		fi; \
	done
	chmod 0600 "$(DESTDIR)$(RUNTIMEDIR)/id_ed25519"
	cp -a "$(RUNTIME_SOURCE_DIR)/$(RUNTIME_MODULES_DIR)" "$(DESTDIR)$(RUNTIMEDIR)/wtf/root/lib/modules/"

rootfs:
	BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./make-rootfs.sh

rootfs-void:
	BANGER_RUNTIME_DIR="$(abspath $(RUNTIME_SOURCE_DIR))" ./make-rootfs-void.sh

void-register: build
	./banger image register --name "$(VOID_IMAGE_NAME)" --rootfs "$(abspath $(RUNTIME_SOURCE_DIR))/rootfs-void.ext4" --work-seed "$(abspath $(RUNTIME_SOURCE_DIR))/rootfs-void.work-seed.ext4" --packages "$(abspath packages.void)"

void-vm: void-register
	./banger vm create --image "$(VOID_IMAGE_NAME)" --name "$(VOID_VM_NAME)"

verify-void: void-register
	./verify.sh --image "$(VOID_IMAGE_NAME)"
