.PHONY: all build clean clean-all install test test-race lint fmt deps help fresh qualify-selfupdate .PHONY: build-linux build-windows build-macos .PHONY: build-linux-amd64 build-linux-arm64 build-win-x86_64 build-win-arm64 build-macos-intel build-macos-arm .PHONY: build-all run release checksums .PHONY: build-generator build-generator-linux build-generator-windows build-generator-macos .PHONY: frontend-deps frontend-vendor frontend-vendor-check frontend .PHONY: tailwind tailwind-watch tailwind-dev .PHONY: release-build release-package release-checksums _release-frontend-check .PHONY: _ensure-dist _ensure-manifest-trust _generate-windows-resources .PHONY: build-aur # Detect number of CPU cores for parallel builds NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) # Default to half the cores for parallel make (leave rest for system) JOBS ?= $(shell echo $$(($(NPROC) > 8 ? 8 : $(NPROC)))) GOOS?=$(shell go env GOOS) GOARCH?=$(shell go env GOARCH) BINARY_NAME=mpv-manager GENERATOR_NAME=generate-info CHECKSUMS_NAME=gen-checksums VERSION?=1.3.1 NORMALIZED_VERSION=$(patsubst v%,%,$(strip $(VERSION))) # Public channel trust is version-controlled; stable builds never include the RC key. ifneq ($(findstring -,$(firstword $(subst +, ,$(NORMALIZED_VERSION)))),) include release/rc-trust.mk else include release/stable-trust.mk endif WINDOWS_RESOURCE_VERSION=$(firstword $(subst +, ,$(firstword $(subst -, ,$(NORMALIZED_VERSION))))) BUILD_TIME:=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ") GIT_COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") # Self-update disable flag for package manager builds (Arch AUR, etc.) # Set to disable self-update: make build SELF_UPDATE_FLAG="-X 'gitgud.io/mike/mpv-manager/pkg/version.SelfUpdateDisabled=true'" SELF_UPDATE_FLAG?= # Release builds inject one or more trusted Ed25519 public keys as # "key-id=base64,key-id-2=base64". Development builds may leave this empty; # network release metadata then fails closed. MANIFEST_PUBLIC_KEYS?= MANIFEST_KEY_VALIDITY?= MANIFEST_REVOKED_KEY_IDS?= MANIFEST_TRUST_FLAG=-X gitgud.io/mike/mpv-manager/pkg/version.ManifestPublicKeys=$(strip $(MANIFEST_PUBLIC_KEYS)) -X gitgud.io/mike/mpv-manager/pkg/version.ManifestKeyValidity=$(strip $(MANIFEST_KEY_VALIDITY)) -X gitgud.io/mike/mpv-manager/pkg/version.ManifestRevokedKeyIDs=$(strip $(MANIFEST_REVOKED_KEY_IDS)) QUALIFIER_OLD_VERSION?=1.2.99 QUALIFIER_NEW_VERSION?=1.3.1 GO_WINRES=go run github.com/tc-hib/go-winres@v0.3.3 STATICCHECK_VERSION=v0.8.1 GO_STATICCHECK=go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) LDFLAGS=-ldflags "-X gitgud.io/mike/mpv-manager/pkg/version.CurrentVersion=$(NORMALIZED_VERSION) -X gitgud.io/mike/mpv-manager/pkg/version.BuildTime=$(BUILD_TIME) -X gitgud.io/mike/mpv-manager/pkg/version.GitCommit=$(GIT_COMMIT) $(MANIFEST_TRUST_FLAG) $(SELF_UPDATE_FLAG) -s -w" # -buildvcs=false: Skip VCS stamping (faster, we embed version via ldflags) # -p 4: Build up to 4 packages in parallel within each build BUILD_FLAGS=-buildvcs=false -p 4 # ============================================================================= # UTILITY TARGETS # ============================================================================= _ensure-dist: @mkdir -p dist _ensure-manifest-trust: @test -n "$(strip $(MANIFEST_PUBLIC_KEYS))" || \ (echo "Release builds require MANIFEST_PUBLIC_KEYS=key-id=base64-public-key" >&2; exit 1) @test -n "$(strip $(MANIFEST_KEY_VALIDITY))" || \ (echo "Release builds require MANIFEST_KEY_VALIDITY=key-id=not-before-unix:not-after-unix" >&2; exit 1) @MANIFEST_PUBLIC_KEYS='$(strip $(MANIFEST_PUBLIC_KEYS))' go run ./cmd/verify-manifest -keys-only # Native updater mechanics qualification. These binaries use the current # updater implementation with distinct synthetic identities; historical N-1/N-2 # release upgrades remain separate release gates. qualify-selfupdate: _ensure-dist go build -tags selfupdate_qualification $(BUILD_FLAGS) -ldflags "-X gitgud.io/mike/mpv-manager/pkg/version.CurrentVersion=$(QUALIFIER_OLD_VERSION)" -o dist/qualify-selfupdate-old$(if $(filter windows,$(GOOS)),.exe,) ./cmd/qualify-selfupdate go build -tags selfupdate_qualification $(BUILD_FLAGS) -ldflags "-X gitgud.io/mike/mpv-manager/pkg/version.CurrentVersion=$(QUALIFIER_NEW_VERSION)" -o dist/qualify-selfupdate-new$(if $(filter windows,$(GOOS)),.exe,) ./cmd/qualify-selfupdate ./dist/qualify-selfupdate-old$(if $(filter windows,$(GOOS)),.exe,) -old ./dist/qualify-selfupdate-old$(if $(filter windows,$(GOOS)),.exe,) -new ./dist/qualify-selfupdate-new$(if $(filter windows,$(GOOS)),.exe,) # Windows resources only need to be generated once, even with parallel builds _generate-windows-resources: _ensure-dist @echo "Generating Windows resources..." @cd cmd/mpv-manager && $(GO_WINRES) make \ --arch amd64,arm64 \ --product-version "$(WINDOWS_RESOURCE_VERSION)" \ --file-version "$(WINDOWS_RESOURCE_VERSION)" @test -s cmd/mpv-manager/rsrc_windows_amd64.syso @test -s cmd/mpv-manager/rsrc_windows_arm64.syso # ============================================================================= # MAIN BUILD TARGETS # ============================================================================= build: _ensure-dist @echo "Building for $(GOOS)/$(GOARCH)..." @echo "Version: $(VERSION), Commit: $(GIT_COMMIT)" go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME) ./cmd/mpv-manager build-linux: build-linux-amd64 build-linux-arm64 build-windows: build-win-x86_64 build-win-arm64 build-macos: build-macos-arm build-macos-intel # ============================================================================= # PLATFORM-SPECIFIC BUILDS # ============================================================================= build-linux-amd64: _ensure-dist @echo "Building for linux/amd64..." CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v2 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-linux-amd64 ./cmd/mpv-manager build-linux-arm64: _ensure-dist @echo "Building for linux/arm64..." CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-linux-arm64 ./cmd/mpv-manager build-win-x86_64: _ensure-dist _generate-windows-resources @echo "Building for windows/amd64 (x86-64-v2)..." CGO_ENABLED=0 GOOS=windows GOARCH=amd64 GOAMD64=v2 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-win-x86_64.exe ./cmd/mpv-manager build-win-arm64: _ensure-dist _generate-windows-resources @echo "Building for windows/arm64..." CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-win-arm64.exe ./cmd/mpv-manager build-macos-arm: _ensure-dist @echo "Building for darwin/arm64..." CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-macos-arm ./cmd/mpv-manager build-macos-intel: _ensure-dist @echo "Building for darwin/amd64..." CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 GOAMD64=v2 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(BINARY_NAME)-macos-intel ./cmd/mpv-manager # ============================================================================= # PACKAGE MANAGER BUILDS (self-update disabled) # ============================================================================= # Arch Linux AUR build (self-update disabled, package manager handles updates) build-aur: _ensure-manifest-trust _ensure-dist @echo "Building for Arch Linux AUR (self-update disabled)..." $(MAKE) build SELF_UPDATE_FLAG="-X 'gitgud.io/mike/mpv-manager/pkg/version.SelfUpdateDisabled=true'" # ============================================================================= # GENERATOR TOOL BUILDS # ============================================================================= build-generator: _ensure-dist @echo "Building generator for $(GOOS)/$(GOARCH)..." @echo "Version: $(VERSION), Commit: $(GIT_COMMIT)" CGO_ENABLED=0 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME) ./cmd/generate-info build-generator-linux: build-generator-linux-amd64 build-generator-linux-arm64 build-generator-windows: build-generator-windows-amd64 build-generator-windows-arm64 build-generator-macos: build-generator-macos-amd64 build-generator-macos-arm64 build-generator-linux-amd64: _ensure-dist @echo "Building generator for linux/amd64..." CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-linux-amd64 ./cmd/generate-info build-generator-linux-arm64: _ensure-dist @echo "Building generator for linux/arm64..." CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-linux-arm64 ./cmd/generate-info build-generator-windows-amd64: _ensure-dist _generate-windows-resources @echo "Building generator for windows/amd64..." CGO_ENABLED=0 GOOS=windows GOARCH=amd64 GOAMD64=v2 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-windows-amd64.exe ./cmd/generate-info build-generator-windows-arm64: _ensure-dist _generate-windows-resources @echo "Building generator for windows/arm64..." CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-windows-arm64.exe ./cmd/generate-info build-generator-macos-amd64: _ensure-dist @echo "Building generator for darwin/amd64..." CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-macos-amd64 ./cmd/generate-info build-generator-macos-arm64: _ensure-dist @echo "Building generator for darwin/arm64..." CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(GENERATOR_NAME)-macos-arm64 ./cmd/generate-info build-gen-checksums: _ensure-dist @echo "Building gen-checksums..." CGO_ENABLED=0 go build $(BUILD_FLAGS) $(LDFLAGS) -o dist/$(CHECKSUMS_NAME) ./cmd/gen-checksums # ============================================================================= # PARALLEL BUILD TARGETS # ============================================================================= # Build all platforms in parallel (use: make -j8 build-all-parallel) build-all-parallel: _ensure-manifest-trust _ensure-dist _generate-windows-resources @echo "Building all platforms in parallel with $(JOBS) jobs..." $(MAKE) -j$(JOBS) \ build-linux-amd64 build-linux-arm64 \ build-win-x86_64 build-win-arm64 \ build-macos-intel build-macos-arm \ build-gen-checksums build-generator @echo "All builds complete:" @ls -lh dist/$(BINARY_NAME)-* dist/$(CHECKSUMS_NAME) 2>/dev/null || echo " (none)" # All platforms (sequential for safety, use build-all-parallel for speed) all: clean @echo "Building all installers..." $(MAKE) -j$(JOBS) \ build-linux-amd64 build-linux-arm64 \ build-win-x86_64 build-win-arm64 \ build-macos-intel build-macos-arm \ build-gen-checksums build-generator @echo "Created binaries:" @ls -lh dist/$(BINARY_NAME)-* dist/$(CHECKSUMS_NAME) 2>/dev/null || echo " (none)" build-all: all # ============================================================================= # RELEASE TARGETS (PARALLEL BUILDS + SEQUENTIAL PACKAGING) # ============================================================================= # Stage 1: Build all binaries in parallel release-build: _ensure-manifest-trust _ensure-dist _generate-windows-resources @echo "=== Stage 1/3: Building all binaries ($(JOBS) parallel jobs) ===" $(MAKE) -j$(JOBS) \ build-linux-amd64 build-linux-arm64 \ build-win-x86_64 build-win-arm64 \ build-macos-intel build-macos-arm \ build-gen-checksums # Stage 2: Package binaries (sequential to avoid race conditions) release-package: @echo "=== Stage 2/3: Creating release packages for version $(VERSION) ===" @rm -rf dist/.release-package @for package in linux-amd64 linux-arm64 win-x86_64 win-arm64 macos-intel macos-arm; do \ mkdir -p "dist/.release-package/$$package"; \ cp LICENSE "dist/.release-package/$$package/LICENSE"; \ cp docs/THIRD_PARTY_NOTICES.md "dist/.release-package/$$package/THIRD_PARTY_NOTICES.md"; \ done @cp dist/$(BINARY_NAME)-linux-amd64 dist/.release-package/linux-amd64/ @cp dist/$(BINARY_NAME)-linux-arm64 dist/.release-package/linux-arm64/ @cp dist/$(BINARY_NAME)-win-x86_64.exe dist/.release-package/win-x86_64/ @cp dist/$(BINARY_NAME)-win-arm64.exe dist/.release-package/win-arm64/ @cp dist/$(BINARY_NAME)-macos-intel dist/.release-package/macos-intel/ @cp dist/$(BINARY_NAME)-macos-arm dist/.release-package/macos-arm/ @tar -C dist/.release-package/linux-amd64 -czf dist/$(BINARY_NAME)-$(VERSION)-linux-amd64.tar.gz $(BINARY_NAME)-linux-amd64 LICENSE THIRD_PARTY_NOTICES.md @tar -C dist/.release-package/linux-arm64 -czf dist/$(BINARY_NAME)-$(VERSION)-linux-arm64.tar.gz $(BINARY_NAME)-linux-arm64 LICENSE THIRD_PARTY_NOTICES.md @cd dist/.release-package/win-x86_64 && zip -q ../../../dist/$(BINARY_NAME)-$(VERSION)-win-x86_64.zip $(BINARY_NAME)-win-x86_64.exe LICENSE THIRD_PARTY_NOTICES.md @cd dist/.release-package/win-arm64 && zip -q ../../../dist/$(BINARY_NAME)-$(VERSION)-win-arm64.zip $(BINARY_NAME)-win-arm64.exe LICENSE THIRD_PARTY_NOTICES.md @cd dist/.release-package/macos-intel && zip -q ../../../dist/$(BINARY_NAME)-$(VERSION)-macos-intel.zip $(BINARY_NAME)-macos-intel LICENSE THIRD_PARTY_NOTICES.md @cd dist/.release-package/macos-arm && zip -q ../../../dist/$(BINARY_NAME)-$(VERSION)-macos-arm.zip $(BINARY_NAME)-macos-arm LICENSE THIRD_PARTY_NOTICES.md @for archive in dist/$(BINARY_NAME)-$(VERSION)-linux-*.tar.gz; do \ tar -tzf "$$archive" | grep -Fx LICENSE >/dev/null; \ tar -tzf "$$archive" | grep -Fx THIRD_PARTY_NOTICES.md >/dev/null; \ done @for archive in dist/$(BINARY_NAME)-$(VERSION)-*.zip; do \ unzip -Z1 "$$archive" | grep -Fx LICENSE >/dev/null; \ unzip -Z1 "$$archive" | grep -Fx THIRD_PARTY_NOTICES.md >/dev/null; \ done @rm -rf dist/.release-package # Stage 3: Generate checksums release-checksums: @echo "=== Stage 3/3: Generating BLAKE3 checksums ===" ./dist/$(CHECKSUMS_NAME) @echo "Release packages created:" @ls -lh dist/*$(VERSION)* dist/BLAKE3SUMS.txt # Full release: clean + parallel build + package + checksum # .NOTPARALLEL: prerequisites run in order even under make -jN, so `clean` # cannot race with builds writing to dist/. Parallelism still happens inside # release-build via its own $(MAKE) -j$(JOBS); other targets stay parallel. .NOTPARALLEL: release release: _ensure-manifest-trust _release-frontend-check clean release-build release-package release-checksums _release-frontend-check: @echo "Verifying locked frontend inputs before release..." npm ci npm run vendor:frontend:check npm test @task_css=$$(mktemp); \ trap 'rm -f "$$task_css"' EXIT; \ npx tailwindcss -i ./internal/webassets/css/input.css -o "$$task_css" --minify; \ diff "$$task_css" internal/webassets/static/css/tailwind.min.css checksums: build-gen-checksums @echo "Creating BLAKE3 checksums..." ./dist/$(CHECKSUMS_NAME) # ============================================================================= # DEVELOPMENT TARGETS # ============================================================================= clean: @echo "Cleaning build artifacts..." @rm -rf dist/* @rm -rf dist/.release-package @echo "Clean complete" clean-all: @echo "Deep cleaning (includes Go build cache)..." @rm -rf dist/* @go clean -cache @echo "Deep clean complete" install: build @echo "Installing $(BINARY_NAME) to GOPATH/bin..." @go install $(LDFLAGS) ./cmd/mpv-manager @echo "Installation complete" test: @echo "Running tests with $(JOBS) parallel packages..." go test -v -p $(JOBS) ./... test-coverage: @echo "Running tests with coverage..." go test -v -p $(JOBS) -coverprofile=coverage.out ./... go tool cover -html=coverage.out -o coverage.html @echo "Coverage report: coverage.html" test-race: @echo "Running tests with race detector..." go test -v -race -p $(JOBS) ./... lint: @echo "Running vet and pinned Staticcheck correctness analyzers..." go vet ./... $(GO_STATICCHECK) -checks='SA*' ./... fmt: @echo "Formatting code..." @go fmt ./... @if command -v goimports >/dev/null 2>&1; then \ goimports -w .; \ fi deps: @echo "Downloading dependencies..." go mod download go mod tidy @echo "Dependencies ready" deps-update: @echo "Updating dependencies..." go get -u ./... go mod tidy @echo "Dependencies updated" vendor: @echo "Vendoring dependencies..." go mod vendor first-time: @echo "Setting up for first time use..." @$(MAKE) deps @$(MAKE) build @echo "" @echo "Setup complete! Binary: dist/$(BINARY_NAME)" @echo "Run with: ./dist/$(BINARY_NAME)" fresh: @echo "Fresh build (clean + deps + build)..." @$(MAKE) clean @$(MAKE) deps @$(MAKE) build @echo "" @echo "Fresh build complete! Binary: dist/$(BINARY_NAME)" run: build ./dist/$(BINARY_NAME) # ============================================================================= # FRONTEND ASSETS # ============================================================================= frontend-deps: @echo "Installing locked frontend dependencies..." npm ci frontend-vendor: @echo "Synchronizing package-managed browser assets..." npm run vendor:frontend frontend-vendor-check: @echo "Checking package-managed browser assets..." npm run vendor:frontend:check frontend: @echo "Building all committed frontend assets..." npm run frontend:build tailwind: @echo "Building TailwindCSS..." npm run tailwind @echo "TailwindCSS build complete" tailwind-watch: @echo "Watching TailwindCSS for changes..." npm run tailwind:watch tailwind-dev: @echo "Building TailwindCSS (development - unminified)..." npm run tailwind:dev # ============================================================================= # HELP # ============================================================================= help: @echo "MPV.Rocks Manager Makefile" @echo "" @echo "Detected: $(NPROC) CPU cores, using $(JOBS) parallel jobs" @echo "" @echo "Quick Start:" @echo " make first-time - Install deps and build (for new clones)" @echo " make build - Build for current platform" @echo " make run - Build and run" @echo "" @echo "Parallel Builds (FAST):" @echo " make build-all-parallel - Build ALL platforms in parallel" @echo " make release - Full release (parallel builds)" @echo " make -j8 release - Override parallelism (8 jobs)" @echo "" @echo "Sequential Builds (SAFE):" @echo " make all - Build all platforms" @echo " make build-linux - Linux (amd64 + arm64)" @echo " make build-windows - Windows (x86_64 + arm64)" @echo " make build-macos - macOS (intel + arm)" @echo "" @echo "Single Platform:" @echo " make build-linux-amd64 - Linux x86_64" @echo " make build-linux-arm64 - Linux ARM64" @echo " make build-win-x86_64 - Windows x86_64" @echo " make build-win-arm64 - Windows ARM64" @echo " make build-macos-intel - macOS Intel" @echo " make build-macos-arm - macOS Apple Silicon" @echo "" @echo "Package Manager Builds:" @echo " make build-aur - Arch Linux AUR (self-update disabled)" @echo "" @echo "Development:" @echo " make test - Run tests" @echo " make test-race - Run tests with race detector" @echo " make test-coverage - Tests with coverage report" @echo " make lint - Run linters" @echo " make fmt - Format code" @echo " make clean - Clean dist/ (keep cache)" @echo " make clean-all - Deep clean (includes Go cache)" @echo " make frontend-deps - Install exact frontend dependencies from package-lock.json" @echo " make frontend - Sync htmx/Alpine and rebuild Tailwind" @echo " make frontend-vendor-check - Verify committed htmx/Alpine assets match npm" @echo "" @echo "Customization:" @echo " JOBS=4 make release - Use 4 parallel jobs" @echo " VERSION=1.0.0 make - Set version" @echo " MANIFEST_PUBLIC_KEYS='release-id=base64' MANIFEST_KEY_VALIDITY='release-id=not-before:not-after' make build - Trust signed release metadata" @echo " make build SELF_UPDATE_FLAG=\"-X 'gitgud.io/mike/mpv-manager/pkg/version.SelfUpdateDisabled=true'\" - Disable self-update" .DEFAULT_GOAL := help