# VPNWorkbench — convenience targets around xcodegen + xcodebuild.
#
#   make build          — Debug build of the app + privileged helper
#   make build-release  — Release build
#   make run            — Debug build, then open the .app
#   make clean          — xcodebuild clean + remove build/ and generated project
#   make generate       — regenerate VPNWorkbench.xcodeproj from project.yml
#   make archive        — Release archive
#   make dmg            — Release build + distributable .dmg in build/
#   make notarize       — make dmg, submit to Apple notary service, staple
#   make source-package — GPL "corresponding source" zip next to the .dmg
#   make deploy         — notarized dmg + source zip → DEPLOY_HOST, stamp the
#                         website changelog, then publish the website
#   make version        — print the version string the build will use

PROJECT      := VPNWorkbench.xcodeproj
SCHEME       := VPNWorkbench
CONFIG       ?= Debug
DERIVED_DATA := build

# Display name shown to users (Finder, disk image volume) — the internal
# SCHEME/PRODUCT_NAME stays a single space-free token everywhere else.
APP_DISPLAY_NAME := VPN Workbench

# OpenSSL + monolithic strongSwan + dnsmasq + wireguard-go + openvpn, all built
# from src/ for the app's deployment target and bundled into the app.
OPENSSL_INSTALL    := src/openssl-install
STRONGSWAN_INSTALL := src/strongswan-install
DNSMASQ_INSTALL    := src/dnsmasq-install
WIREGUARD_INSTALL  := src/wireguard-install
OPENVPN_INSTALL    := src/openvpn-install

VERSION := $(shell date +%Y).$(shell date +%-m).$(shell git rev-list HEAD --count 2>/dev/null || echo 0)
DMG     := $(DERIVED_DATA)/$(SCHEME)-$(VERSION).dmg

# GPL "complete corresponding source" zip, built next to the .dmg. VPNWorkbench links
# strongSwan (GPLv2) into the helper, so distributing the binary obliges us to
# make the source available — `deploy` publishes this alongside the .dmg.
SRC_ZIP := $(DERIVED_DATA)/$(SCHEME)-$(VERSION)-src.zip

# Notary keychain profile. Reuses the AppVersionChecker credential (same Apple ID
# + team CXJY846WKU). To use a dedicated one instead, create it once with:
#   xcrun notarytool store-credentials VPNWORKBENCH_NOTARY \
#       --apple-id <id> --team-id CXJY846WKU --password <app-specific-password>
# and override on the command line: make deploy NOTARY_PROFILE=VPNWORKBENCH_NOTARY
NOTARY_PROFILE ?= YOUR_NOTARY_PROFILE

# Developer ID identity used to sign the .dmg container (the app + helper are
# signed by the Xcode build itself).
SIGN_IDENTITY  ?= Developer ID Application: Juvex Oy (CXJY846WKU)

DEPLOY_HOST  ?= user@example.com
DEPLOY_PATH  ?= /path/to/VPNWorkbench.dmg

# Where the corresponding-source zip is published — same remote directory as the
# .dmg (defaults to <dmg-dir>/VPNWorkbench-src.zip). Override on the CLI if needed.
DEPLOY_SRC_PATH ?= $(dir $(DEPLOY_PATH))$(SCHEME)-src.zip

# Website repo (a separate git repo) that hosts the public "What's New" page.
# `make deploy` stamps its upcoming changelog entry as "Release <version>" and
# then runs that repo's own `make deploy` to publish the site.
WEB_REPO       ?= /Users/jukka/Projects/avc-web
CHANGELOG_HTML := $(WEB_REPO)/vpnworkbench/whatsnew/index.html

XCBUILD := xcodebuild \
  -project $(PROJECT) \
  -scheme $(SCHEME) \
  -configuration $(CONFIG) \
  -derivedDataPath $(DERIVED_DATA)

PRODUCT := $(DERIVED_DATA)/Build/Products/$(CONFIG)/$(SCHEME).app

.PHONY: build build-release run clean generate archive dmg notarize deploy version openssl strongswan dnsmasq wireguard openvpn stage-strongswan stage-openvpn source-package help

help:
	@echo "Targets:"
	@echo "  generate       — regenerate $(PROJECT) from project.yml"
	@echo "  build          — Debug build (default CONFIG=Debug)"
	@echo "  build-release  — CONFIG=Release"
	@echo "  run            — build then open the .app"
	@echo "  clean          — xcodebuild clean + remove build/ + generated project"
	@echo "  archive        — Release archive into build/$(SCHEME).xcarchive"
	@echo "  dmg            — Release build + $(DMG)"
	@echo "  notarize       — make dmg, notarize with Apple, staple the ticket"
	@echo "  source-package — GPL corresponding-source zip → $(SRC_ZIP)"
	@echo "  deploy         — notarized dmg + source zip → $(DEPLOY_HOST), stamp changelog, publish website"
	@echo "  version        — print $(VERSION)"
	@echo "  dnsmasq        — build + install dnsmasq into src/dnsmasq-install/"
	@echo "  wireguard      — build + install wireguard-go into src/wireguard-install/"
	@echo "  openvpn        — build + install openvpn into src/openvpn-install/"

# The .xcodeproj is generated (gitignored); (re)create it whenever project.yml
# is newer or the project is missing.
generate: $(PROJECT)

$(PROJECT): project.yml
	xcodegen generate --spec project.yml

# Build OpenSSL (for libcrypto) then the monolithic strongSwan, both from src/ for
# the app's deployment target. `make openssl` / `make strongswan` force a rebuild.
openssl: $(OPENSSL_INSTALL)

# Depend on the build script (which carries the version + checksum) so editing it
# — e.g. bumping the OpenSSL version — actually triggers a rebuild instead of
# being skipped because the install dir already exists.
$(OPENSSL_INSTALL): Scripts/build_openssl.sh
	Scripts/build_openssl.sh

# strongSwan links our OpenSSL, so build that first.
strongswan: $(STRONGSWAN_INSTALL)

$(STRONGSWAN_INSTALL): $(OPENSSL_INSTALL) Scripts/build_strongswan.sh
	Scripts/build_strongswan.sh

# dnsmasq: standalone binary, no external dependencies beyond the C toolchain.
dnsmasq: $(DNSMASQ_INSTALL)

$(DNSMASQ_INSTALL): Scripts/build_dnsmasq.sh
	Scripts/build_dnsmasq.sh

# wireguard-go: standalone binary (CGO_ENABLED=0, no dylib deps), needs a Go
# toolchain (`brew install go`) rather than the C autoconf pipeline above.
wireguard: $(WIREGUARD_INSTALL)

$(WIREGUARD_INSTALL): Scripts/build_wireguard.sh
	Scripts/build_wireguard.sh

# openvpn: C/autoconf, statically linked against our own OpenSSL (like
# strongSwan) rather than the Go pipeline above.
openvpn: $(OPENVPN_INSTALL)

$(OPENVPN_INSTALL): $(OPENSSL_INSTALL) Scripts/build_openvpn.sh
	Scripts/build_openvpn.sh

build: generate $(STRONGSWAN_INSTALL) $(DNSMASQ_INSTALL) $(WIREGUARD_INSTALL) $(OPENVPN_INSTALL)
	$(XCBUILD) build

build-release:
	$(MAKE) build CONFIG=Release

run: build
	open "$(PRODUCT)"

clean:
	-$(XCBUILD) clean
	rm -rf $(DERIVED_DATA) $(PROJECT)

archive: generate
	xcodebuild \
	  -project $(PROJECT) \
	  -scheme $(SCHEME) \
	  -configuration Release \
	  -archivePath $(DERIVED_DATA)/$(SCHEME).xcarchive \
	  archive

# Manually re-stage + relocate + codesign the bundled strongSwan into an existing
# build product. Normally runs automatically as an app build phase.
stage-strongswan:
	Scripts/stage_strongswan.sh "$(PRODUCT)"

# Manually re-stage + codesign the bundled openvpn into an existing build
# product. Normally runs automatically as an app build phase.
stage-openvpn:
	Scripts/stage_openvpn.sh "$(PRODUCT)"

dmg: build-release
	@release_app="$(DERIVED_DATA)/Build/Products/Release/$(SCHEME).app"; \
	  staging="$(DERIVED_DATA)/dmg-staging"; \
	  if [ ! -d "$$release_app" ]; then echo "error: $$release_app not found"; exit 1; fi; \
	  rm -rf "$$staging" "$(DMG)"; \
	  mkdir -p "$$staging"; \
	  cp -RL "$$release_app" "$$staging/"; \
	  ln -s /Applications "$$staging/Applications"; \
	  hdiutil create \
	    -volname "$(APP_DISPLAY_NAME) $(VERSION)" \
	    -srcfolder "$$staging" \
	    -ov -format UDZO \
	    "$(DMG)"; \
	  rm -rf "$$staging"; \
	  echo "Created $(DMG)"

notarize: dmg
	@set -e; \
	  if [ ! -f "$(DMG)" ]; then echo "error: $(DMG) not found"; exit 1; fi; \
	  echo "Signing dmg with '$(SIGN_IDENTITY)' ..."; \
	  codesign --force --timestamp --sign "$(SIGN_IDENTITY)" "$(DMG)"; \
	  echo "Notarizing $(DMG) (keychain profile: $(NOTARY_PROFILE)) ..."; \
	  xcrun notarytool submit "$(DMG)" --keychain-profile "$(NOTARY_PROFILE)" --wait; \
	  echo "Stapling ticket ..."; \
	  xcrun stapler staple "$(DMG)"; \
	  xcrun stapler validate "$(DMG)"; \
	  echo "Notarized + stapled $(DMG)"

# GPL: package VPNWorkbench's own corresponding source + build system into
# $(SRC_ZIP), next to the .dmg. The bundled strongSwan/OpenSSL source is not
# redistributed here — README-SOURCE.txt carries a written offer (GPLv2 §3b)
# with each release's exact version + SHA-256. Uses an allowlist + a secret scan
# that aborts if any signing/cert/key material, deploy host, or build artifact
# slips in. Reads src/*.tar.gz only to record their checksums.
source-package:
	@mkdir -p $(DERIVED_DATA)
	Scripts/package_source.sh "$(VERSION)" "$(SRC_ZIP)"

deploy: notarize source-package
	@set -e; \
	  if [ ! -f "$(DMG)" ]; then echo "error: $(DMG) not found"; exit 1; fi; \
	  if [ ! -f "$(SRC_ZIP)" ]; then echo "error: $(SRC_ZIP) not found"; exit 1; fi; \
	  echo "Deploying $(DMG) -> $(DEPLOY_HOST):$(DEPLOY_PATH)"; \
	  scp "$(DMG)" "$(DEPLOY_HOST):$(DEPLOY_PATH)"; \
	  echo "Publishing source $(SRC_ZIP) -> $(DEPLOY_HOST):$(DEPLOY_SRC_PATH)"; \
	  scp "$(SRC_ZIP)" "$(DEPLOY_HOST):$(DEPLOY_SRC_PATH)"; \
	  echo "Deployed VPNWorkbench $(VERSION) (binary + GPL corresponding source)"
	@if [ -f "$(CHANGELOG_HTML)" ]; then \
	    echo "Stamping changelog as Release $(VERSION) ..."; \
	    Scripts/stamp_changelog.py "$(CHANGELOG_HTML)" "$(VERSION)"; \
	    if [ -d "$(WEB_REPO)/.git" ] && ! git -C "$(WEB_REPO)" diff --quiet -- "$(CHANGELOG_HTML)"; then \
	        echo "Committing stamped changelog in $(WEB_REPO) ..."; \
	        git -C "$(WEB_REPO)" add "$(CHANGELOG_HTML)"; \
	        git -C "$(WEB_REPO)" commit -m "whatsnew: stamp release $(VERSION)"; \
	    fi; \
	  else \
	    echo "warning: $(CHANGELOG_HTML) not found — skipping changelog stamp"; \
	  fi
	@if [ -d "$(WEB_REPO)" ]; then \
	    echo "Publishing website ($(WEB_REPO)) ..."; \
	    $(MAKE) -C "$(WEB_REPO)" deploy; \
	  else \
	    echo "warning: $(WEB_REPO) not found — skipping website deploy"; \
	  fi

version:
	@echo "$(VERSION)"
