# infra/build-machines/Makefile # Usage: make remote-build PROJECT=~/projects/my-haskell-app [VM=haskell-build] VM ?= haskell-build PROJECT ?= . RDIR := /build/$(notdir $(realpath $(PROJECT))) # Sync project source to VM (exclude build artefacts) .PHONY: sync sync: rsync -av --delete \ --exclude='.git' \ --exclude='dist-newstyle' \ --exclude='.stack-work' \ --exclude='*.o' --exclude='*.hi' \ $(PROJECT)/ $(VM):$(RDIR)/ # Run cabal build on VM after sync .PHONY: remote-build remote-build: sync ssh $(VM) "cd $(RDIR) && source ~/.ghcup/env && cabal build all 2>&1" # Run tests on VM .PHONY: remote-test remote-test: sync ssh $(VM) "cd $(RDIR) && source ~/.ghcup/env && cabal test all 2>&1" # Open a GHCi session on the VM .PHONY: remote-ghci remote-ghci: sync ssh -t $(VM) "cd $(RDIR) && source ~/.ghcup/env && cabal repl" # Sync build artefacts back (for local IDE inspection) .PHONY: fetch-artifacts fetch-artifacts: rsync -av $(VM):$(RDIR)/dist-newstyle/ $(PROJECT)/dist-newstyle/ # Check which VMs are reachable .PHONY: bridge-status bridge-status: @echo "Scanning build-machine tunnel ports..." @for port in 12221 12222 12223 12224 12225; do \ result=$$(ssh -q -p $$port -o ConnectTimeout=2 \ -o StrictHostKeyChecking=no build@localhost \ "echo $$port OK: $$(hostname) — GHC: $$(~/.ghcup/bin/ghc --numeric-version)" \ 2>/dev/null) ; \ if [ -n "$$result" ]; then echo " $$result"; \ else echo " port $$port: no tunnel"; fi; \ done # Show VM system info .PHONY: vm-info vm-info: ssh $(VM) "uname -a; source ~/.ghcup/env && ghc --version && cabal --version" # Install SSH config for the build VM (idempotent) .PHONY: install-ssh-config install-ssh-config: @if grep -q '# Haskell Build VM — tunnel via workstation' ~/.ssh/config 2>/dev/null; then \ echo "SSH config already present — skipping"; \ else \ echo "" >> ~/.ssh/config; \ cat ssh-config.template >> ~/.ssh/config; \ echo "Appended build-machine SSH config to ~/.ssh/config"; \ fi