SHELL := /usr/bin/env bash

GO ?= go
GOFMT ?= gofmt
INSTALL ?= install
PREFIX ?= $(HOME)/.local
BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
DESTDIR ?=
BUILD_DIR ?= build
BUILD_BIN_DIR ?= $(BUILD_DIR)/bin
BUILD_MANUAL_DIR ?= $(BUILD_DIR)/manual
BANGER_BIN ?= $(BUILD_BIN_DIR)/banger
BANGERD_BIN ?= $(BUILD_BIN_DIR)/bangerd
VSOCK_AGENT_BIN ?= $(BUILD_BIN_DIR)/banger-vsock-agent
BINARIES := $(BANGER_BIN) $(BANGERD_BIN) $(VSOCK_AGENT_BIN)
GO_SOURCES := $(shell find cmd internal -type f -name '*.go' | sort)
VOID_IMAGE_NAME ?= void-exp
VOID_VM_NAME ?= void-dev
ALPINE_RELEASE ?= 3.23.3
ALPINE_IMAGE_NAME ?= alpine
ALPINE_VM_NAME ?= alpine-dev

.DEFAULT_GOAL := help

.PHONY: help build banger bangerd test fmt tidy clean rootfs rootfs-void void-kernel void-register void-vm verify-void alpine-kernel rootfs-alpine alpine-register alpine-vm verify-alpine install bench-create

help:
	@printf '%s\n' \
	  'Targets:' \
	  '  make build   Build ./build/bin/banger, ./build/bin/bangerd, and ./build/bin/banger-vsock-agent' \
	  '  make bench-create Benchmark vm create and SSH readiness with scripts/bench-create.sh' \
	  '  make install Build and install banger, bangerd, and the companion vsock helper' \
	  '  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 manual Debian rootfs image in ./build/manual' \
	  '  make void-kernel  Download and stage a Void kernel, initramfs, and modules under ./build/manual/void-kernel' \
	  '  make rootfs-void  Build an experimental Void Linux rootfs and work-seed in ./build/manual' \
	  '  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 scripts/verify.sh against it' \
	  '  make alpine-kernel  Download and stage an Alpine virt kernel, initramfs, and modules under ./build/manual/alpine-kernel' \
	  '  make rootfs-alpine  Build an experimental Alpine Linux rootfs and work-seed in ./build/manual' \
	  '  make alpine-register  Register or update the experimental Alpine image as $(ALPINE_IMAGE_NAME)' \
	  '  make alpine-vm  Register the experimental Alpine image and create a VM named $(ALPINE_VM_NAME)' \
	  '  make verify-alpine  Register the experimental Alpine image and run scripts/verify.sh against it'

build: $(BINARIES)

$(BANGER_BIN): $(GO_SOURCES) go.mod go.sum
	mkdir -p "$(BUILD_BIN_DIR)"
	$(GO) build -o "$(BANGER_BIN)" ./cmd/banger

$(BANGERD_BIN): $(GO_SOURCES) go.mod go.sum
	mkdir -p "$(BUILD_BIN_DIR)"
	$(GO) build -o "$(BANGERD_BIN)" ./cmd/bangerd

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

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

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

tidy:
	$(GO) mod tidy

clean:
	rm -rf "$(BUILD_BIN_DIR)"

bench-create: build
	BANGER_BIN="$(abspath $(BANGER_BIN))" bash ./scripts/bench-create.sh $(ARGS)

install: build
	mkdir -p "$(DESTDIR)$(BINDIR)"
	mkdir -p "$(DESTDIR)$(LIBDIR)/banger"
	$(INSTALL) -m 0755 "$(BANGER_BIN)" "$(DESTDIR)$(BINDIR)/banger"
	$(INSTALL) -m 0755 "$(BANGERD_BIN)" "$(DESTDIR)$(BINDIR)/bangerd"
	$(INSTALL) -m 0755 "$(VSOCK_AGENT_BIN)" "$(DESTDIR)$(LIBDIR)/banger/banger-vsock-agent"

rootfs:
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/make-rootfs.sh $(ARGS)

void-kernel:
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" ./scripts/make-void-kernel.sh $(ARGS)

rootfs-void:
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/make-rootfs-void.sh $(ARGS)

void-register: build
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" VOID_IMAGE_NAME="$(VOID_IMAGE_NAME)" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/register-void-image.sh

void-vm: void-register
	"$(abspath $(BANGER_BIN))" vm create --image "$(VOID_IMAGE_NAME)" --name "$(VOID_VM_NAME)"

verify-void: void-register
	BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/verify.sh --image "$(VOID_IMAGE_NAME)"

alpine-kernel:
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" ALPINE_RELEASE="$(ALPINE_RELEASE)" ./scripts/make-alpine-kernel.sh $(ARGS)

rootfs-alpine:
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" ALPINE_RELEASE="$(ALPINE_RELEASE)" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/make-rootfs-alpine.sh $(ARGS)

alpine-register: build
	BANGER_MANUAL_DIR="$(abspath $(BUILD_MANUAL_DIR))" ALPINE_IMAGE_NAME="$(ALPINE_IMAGE_NAME)" BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/register-alpine-image.sh

alpine-vm: alpine-register
	"$(abspath $(BANGER_BIN))" vm create --image "$(ALPINE_IMAGE_NAME)" --name "$(ALPINE_VM_NAME)"

verify-alpine: alpine-register
	BANGER_BIN="$(abspath $(BANGER_BIN))" ./scripts/verify.sh --image "$(ALPINE_IMAGE_NAME)"
