# ============================================================================ # Liaison Makefile # ============================================================================ # # 这个 Makefile 提供了 Liaison 项目的构建、测试、打包等功能。 # # 主要功能: # 1. 本地开发构建(macOS) # - make build-local # 构建 liaison 和 liaison-edge(本地) # - make build-liaison # 仅构建 liaison # - make build-edge # 仅构建 liaison-edge # # 2. Linux 构建(使用 Docker,支持 CGO 交叉编译) # - make build-linux # 构建 Linux 版本的 liaison 和 liaison-edge # - make build-liaison-linux # 仅构建 Linux 版本的 liaison # - make build-edge-linux # 仅构建 Linux 版本的 liaison-edge # # 3. Edge 多架构构建 # - make build-edge-all # 构建所有架构的 edge 二进制文件 # - make build-edge-linux-amd64 # Linux amd64 # - make build-edge-linux-arm64 # Linux arm64 # - make build-edge-darwin-amd64 # macOS amd64 # - make build-edge-darwin-arm64 # macOS arm64 (Apple Silicon) # - make build-edge-windows-amd64 # Windows amd64 # # 4. Edge 打包(生成 tar.gz 安装包) # - make package-edge-all # 打包所有架构的 edge # - make package-edge-linux-amd64 # 打包 Linux amd64 # - make package-edge-linux-arm64 # 打包 Linux arm64 # - make package-edge-darwin-amd64 # 打包 macOS amd64 # - make package-edge-darwin-arm64 # 打包 macOS arm64 # - make package-edge-windows-amd64 # 打包 Windows amd64 # # 5. 代码生成 # - make gen # 生成 API 和 Swagger 文档 # - make gen-api # 仅生成 API 代码 # - make gen-swagger # 仅生成 Swagger 文档 # # 6. 测试 # - make test # 运行单元测试 # - make test-e2e # 运行 E2E 测试 # - make test-all # 运行所有测试 # # 7. 工具构建 # - make build-tools # 构建所有工具(本地) # - make build-tools-linux # 构建所有工具(Linux) # # 8. 前端构建 # - make build-web # 构建前端到 web/dist # # 9. 完整打包 # - make package # 打包完整的 Liaison 安装包(Linux,自动准备 guacd runtime) # 包含: # - liaison (Linux amd64) # - liaison-edge (所有平台:linux-amd64, linux-arm64, # darwin-amd64, darwin-arm64, windows-amd64) # - 前端文件 (web/dist) # - systemd 配置文件 # # 10. Docker Compose 部署(仅服务端:liaison + frontier) # 前置:先跑 `make package`(产出 bin/web/edge/frontier 等构件),Docker 镜像只做 COPY。 # - make image-liaison # 构建 liaison runtime 镜像 # - make image-frontier # 构建 frontier runtime 镜像 # - make images # 同时构建两个镜像 # - make compose-up # 启动(需要 deploy/docker/.env) # - make compose-down # 停止并移除容器 # - make compose-logs # 跟踪两个服务的日志 # - make package-docker # 输出默认 Linux 离线分发包(Docker) # liaison--linux-amd64.tar.gz 含: # - images/{liaison,frontier,guacd}.tar(docker save) # - docker-compose.yaml(release 版,无 build: 段) # - .env.example(预钉镜像 tag) # - install.sh / README.md # # 注意事项: # - liaison 需要 CGO(SQLite),本地构建需要 CGO_ENABLED=1 # - liaison-edge 使用纯 Go 实现,不需要 CGO,可以 CGO_ENABLED=0 # - Linux 构建使用 Docker,自动处理依赖安装 # - Edge 二进制文件不依赖 libpcap,可以在任何系统上运行 # # ============================================================================ include ./Makefile.defs # When running `make version=1.2.7` without explicit goals, # use version update as the default action. ifeq ($(strip $(MAKECMDGOALS)),) ifneq ($(strip $(version)),) .DEFAULT_GOAL := update-version endif endif # ============================================================================ # Docker build variables and functions # ============================================================================ DOCKER_IMAGE = golang:1.26.9 DOCKER_VOLUME = -v "$(shell pwd):/build" DOCKER_WORKDIR = -w /build DOCKER_BASE = docker run --rm $(DOCKER_VOLUME) $(DOCKER_WORKDIR) DOCKER_HOST_UID := $(shell id -u 2>/dev/null || echo 0) DOCKER_HOST_GID := $(shell id -g 2>/dev/null || echo 0) GO_BUILD_FLAGS = -trimpath -buildvcs=false -ldflags '-s -w' GUACD_IMAGE ?= guacamole/guacd:1.5.5 GUACD_CONTAINER_BINARY ?= /opt/guacamole/sbin/guacd GUACD_RUNTIME_DIR ?= ./bin/guacd-rootfs # Ensure Docker image exists (pull only if not present locally) .PHONY: docker-image docker-image: @if docker image inspect $(DOCKER_IMAGE) >/dev/null 2>&1; then \ echo "✅ Docker image $(DOCKER_IMAGE) already exists locally"; \ else \ echo "📥 Pulling Docker image $(DOCKER_IMAGE)..."; \ docker pull $(DOCKER_IMAGE) || exit 1; \ echo "✅ Docker image $(DOCKER_IMAGE) pulled successfully"; \ fi # Function to build with CGO (for liaison and tools) # Usage: $(call docker-build-cgo,platform,goos,goarch,output,source) define docker-build-cgo @echo "Building $(4) for $(2)-$(3) using Docker..." @mkdir -p ./bin @$(DOCKER_BASE) \ --platform $(1) \ -e CGO_ENABLED=1 \ -e GOOS=$(2) \ -e GOARCH=$(3) \ -e GOTOOLCHAIN=auto \ $(DOCKER_IMAGE) sh -c "\ apt-get update -qq && \ DEBIAN_FRONTEND=noninteractive apt-get install -y -qq gcc libc6-dev libsqlite3-dev >/dev/null 2>&1 && \ go env -w GOTOOLCHAIN=auto && \ go mod download && \ CC=gcc CGO_ENABLED=1 go build $(GO_BUILD_FLAGS) -o ./bin/$(4) $(5) && \ chmod +x ./bin/$(4) && \ chown $(DOCKER_HOST_UID):$(DOCKER_HOST_GID) ./bin/$(4)" @chmod +x ./bin/$(4) @echo "✅ Built: ./bin/$(4)" endef # Function to build without CGO (for edge) # Usage: $(call docker-build-no-cgo,platform,goos,goarch,output,source) define docker-build-no-cgo @echo "Building $(4) for $(2)-$(3) using Docker..." @mkdir -p ./bin @$(DOCKER_BASE) \ --platform $(1) \ -e GOOS=$(2) \ -e GOARCH=$(3) \ -e GOTOOLCHAIN=auto \ $(DOCKER_IMAGE) sh -c "\ go env -w GOTOOLCHAIN=auto && \ go mod download && \ CGO_ENABLED=0 go build $(GO_BUILD_FLAGS) -o ./bin/$(4) $(5) && \ chmod +x ./bin/$(4) && \ chown $(DOCKER_HOST_UID):$(DOCKER_HOST_GID) ./bin/$(4)" @chmod +x ./bin/$(4) @echo "✅ Built: ./bin/$(4)" endef # Function for local darwin builds # Usage: $(call local-build-darwin,goarch,output,source) define local-build-darwin @echo "Building $(2) for darwin-$(1)..." @mkdir -p ./bin @if [ "$$(uname)" != "Darwin" ]; then \ echo "❌ Error: darwin CGO builds must run on macOS"; \ exit 1; \ fi @ARCH_FLAG="$$(if [ "$(1)" = "amd64" ]; then echo "x86_64"; else echo "arm64"; fi)" && \ CGO_ENABLED=1 GOOS=darwin GOARCH=$(1) \ CC="clang -arch $$ARCH_FLAG" \ CXX="clang++ -arch $$ARCH_FLAG" \ go build $(GO_BUILD_FLAGS) -o ./bin/$(2) $(3) @chmod +x ./bin/$(2) @echo "✅ Built: ./bin/$(2)" endef # ============================================================================ # Default targets # ============================================================================ .PHONY: all all: build-local test-deps .PHONY: linux linux: build-linux # ============================================================================ # Docker images for code generation # ============================================================================ .PHONY: image-gen-swagger image-gen-swagger: docker buildx build -t liaison-gen-swagger:${VERSION} -f images/Dockerfile.liaison-swagger . .PHONY: image-gen-api image-gen-api: docker buildx build -t image-gen-api:${VERSION} -f images/Dockerfile.liaison-api . # ============================================================================ # Local development builds (for macOS) # ============================================================================ .PHONY: build-local build-local: build-liaison build-edge .PHONY: build-liaison LIAISON_BINARY ?= ./bin/liaison build-liaison: CGO_ENABLED=1 go build -trimpath -ldflags "-s -w" -o $(LIAISON_BINARY) cmd/manager/main.go .PHONY: image-overlay deploy-overlay image-overlay: ## Build a test overlay from an explicitly supplied context and image tag test -n "$(OVERLAY_CONTEXT)" && test -n "$(OVERLAY_IMAGE)" docker build -t "$(OVERLAY_IMAGE)" "$(OVERLAY_CONTEXT)" deploy-overlay: ## Recreate only the manager using explicitly supplied Compose files test -n "$(COMPOSE_BASE)" && test -n "$(COMPOSE_OVERRIDE)" && test -n "$(COMPOSE_PROJECT)" docker compose -p "$(COMPOSE_PROJECT)" -f "$(COMPOSE_BASE)" -f "$(COMPOSE_OVERRIDE)" up -d --no-deps liaison .PHONY: build-edge build-edge: go build -trimpath -ldflags "-s -w" -o ./bin/liaison-edge cmd/edge/main.go # Legacy aliases .PHONY: liaison liaison-edge liaison: build-liaison liaison-edge: build-edge # ============================================================================ # Linux builds using Docker (required for CGO cross-compilation from macOS) # ============================================================================ .PHONY: build-linux build-linux: build-liaison-linux build-edge-linux build-frontier-linux .PHONY: build-liaison-linux build-liaison-linux: docker-image $(call docker-build-cgo,linux/amd64,linux,amd64,liaison,cmd/manager/main.go) .PHONY: build-edge-linux build-edge-linux: docker-image $(call docker-build-no-cgo,linux/amd64,linux,amd64,liaison-edge,cmd/edge/main.go) .PHONY: build-frontier-linux build-frontier-linux: @mkdir -p ./bin @if [ -f "./bin/frontier" ] && command -v file >/dev/null 2>&1 && file ./bin/frontier | grep -Eq 'ELF 64-bit.*(x86-64|x86_64)'; then \ echo "✅ frontier linux-amd64 binary already exists, skipping download"; \ else \ echo "Downloading frontier-linux-amd64 from GitHub releases..."; \ rm -f ./bin/frontier; \ curl -L -o ./bin/frontier https://github.com/singchia/frontier/releases/download/v1.2.4/frontier-linux-amd64 && \ chmod +x ./bin/frontier && \ echo "✅ Downloaded: ./bin/frontier"; \ fi .PHONY: prepare-guacd-linux prepare-guacd-linux: @set -e; \ mkdir -p ./bin; \ if [ -x "./bin/guacd" ] && [ -s "$(GUACD_RUNTIME_DIR)$(GUACD_CONTAINER_BINARY)" ] && [ -s "$(GUACD_RUNTIME_DIR)/lib/ld-musl-x86_64.so.1" ]; then \ echo "✅ guacd runtime already exists, skipping download"; \ exit 0; \ fi; \ if ! command -v docker >/dev/null 2>&1; then \ echo "❌ Error: Docker is required to prepare bundled guacd. Install Docker or place ./bin/guacd and $(GUACD_RUNTIME_DIR) manually."; \ exit 1; \ fi; \ echo "Preparing bundled guacd linux/amd64 runtime from $(GUACD_IMAGE)..."; \ rm -rf "$(GUACD_RUNTIME_DIR)" "./bin/guacd"; \ mkdir -p "$(GUACD_RUNTIME_DIR)/opt" "$(GUACD_RUNTIME_DIR)/usr"; \ image_arch=$$(docker image inspect --format '{{.Architecture}}' "$(GUACD_IMAGE)" 2>/dev/null || true); \ if [ "$$image_arch" = "amd64" ]; then \ echo "✅ Docker image $(GUACD_IMAGE) already exists locally for amd64"; \ else \ echo "📥 Pulling Docker image $(GUACD_IMAGE) for linux/amd64..."; \ docker pull --platform linux/amd64 "$(GUACD_IMAGE)"; \ fi; \ tmp_tar="./bin/guacd-rootfs.tar"; \ rm -f "$$tmp_tar"; \ docker run --rm --user 0 --platform linux/amd64 --entrypoint sh "$(GUACD_IMAGE)" -c 'cd / && tar -cf - opt/guacamole lib usr/lib' > "$$tmp_tar"; \ tar -C "$(GUACD_RUNTIME_DIR)" -xf "$$tmp_tar"; \ rm -f "$$tmp_tar"; \ perl -0pi -e 's|\Q/opt/guacamole/lib\E|/opt/liaison/guacd|g' "$(GUACD_RUNTIME_DIR)$(GUACD_CONTAINER_BINARY)"; \ printf '%s\n' \ '#!/bin/sh' \ 'set -e' \ 'ROOT="$${LIAISON_GUACD_ROOT:-/opt/liaison/guacd-rootfs}"' \ 'PLUGIN_DIR="$${LIAISON_GUACD_PLUGIN_DIR:-/opt/liaison/guacd}"' \ 'export LD_LIBRARY_PATH="$${PLUGIN_DIR}:$${PLUGIN_DIR}/freerdp2:$${ROOT}/opt/guacamole/lib:$${ROOT}/lib:$${ROOT}/usr/lib:$${ROOT}/usr/lib/pulseaudio$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}}"' \ 'export FREERDP2_PLUGIN_PATH="$${PLUGIN_DIR}/freerdp2"' \ 'exec "$${ROOT}/lib/ld-musl-x86_64.so.1" --library-path "$${LD_LIBRARY_PATH}" "$${ROOT}/opt/guacamole/sbin/guacd" "$$@"' \ > ./bin/guacd; \ chmod +x ./bin/guacd "$(GUACD_RUNTIME_DIR)$(GUACD_CONTAINER_BINARY)"; \ find "$(GUACD_RUNTIME_DIR)" -name '._*' -delete 2>/dev/null || true; \ test -s ./bin/guacd; \ test -s "$(GUACD_RUNTIME_DIR)$(GUACD_CONTAINER_BINARY)"; \ test -s "$(GUACD_RUNTIME_DIR)/lib/ld-musl-x86_64.so.1"; \ echo "✅ Prepared: ./bin/guacd + $(GUACD_RUNTIME_DIR)" # Legacy aliases .PHONY: liaison-linux liaison-edge-linux liaison-linux: build-liaison-linux liaison-edge-linux: build-edge-linux # ============================================================================ # Code generation # ============================================================================ .PHONY: gen-api gen-api: docker run --rm -v ${PWD}/api/v1:/api/v1 image-gen-api:${VERSION} .PHONY: gen-swagger gen-swagger: docker run --rm -v ${PWD}:/liaison liaison-gen-swagger:${VERSION} .PHONY: gen gen: gen-api gen-swagger # ============================================================================ # Testing # ============================================================================ .PHONY: test test: go test -v ./... .PHONY: test-deps test-deps: go get github.com/stretchr/testify/assert go get github.com/stretchr/testify/require .PHONY: test-e2e test-e2e: @echo "Running E2E tests..." @./test/e2e/run_simple_test.sh .PHONY: test-e2e-full test-e2e-full: @echo "Running full E2E tests..." @./test/e2e/run_e2e_test.sh .PHONY: test-all test-all: test test-e2e # ============================================================================ # Tools # ============================================================================ .PHONY: build-tools build-tools: build-password-verifier build-password-generator .PHONY: build-password-verifier build-password-verifier: CGO_ENABLED=1 go build $(GO_BUILD_FLAGS) -o ./bin/password-verifier ./tools/password-verifier .PHONY: build-password-generator build-password-generator: CGO_ENABLED=1 go build $(GO_BUILD_FLAGS) -o ./bin/password-generator ./tools/password-generator .PHONY: build-tools-linux build-tools-linux: build-password-verifier-linux build-password-generator-linux .PHONY: build-password-verifier-linux build-password-verifier-linux: docker-image $(call docker-build-cgo,linux/amd64,linux,amd64,password-verifier,./tools/password-verifier) .PHONY: build-password-generator-linux build-password-generator-linux: docker-image $(call docker-build-cgo,linux/amd64,linux,amd64,password-generator,./tools/password-generator) # Legacy aliases .PHONY: tools tools-linux password-verifier password-generator password-verifier-linux password-generator-linux tools: build-tools tools-linux: build-tools-linux password-verifier: build-password-verifier password-generator: build-password-generator password-verifier-linux: build-password-verifier-linux password-generator-linux: build-password-generator-linux # ============================================================================ # Edge binary builds for different architectures # ============================================================================ .PHONY: build-edge-all build-edge-all: build-edge-linux-amd64 build-edge-linux-arm64 build-edge-darwin-amd64 build-edge-darwin-arm64 build-edge-windows-amd64 @echo "✅ All edge binaries built in ./bin/" .PHONY: build-edge-linux-amd64 build-edge-linux-amd64: docker-image $(call docker-build-no-cgo,linux/amd64,linux,amd64,liaison-edge-linux-amd64,cmd/edge/main.go) .PHONY: build-edge-linux-arm64 build-edge-linux-arm64: docker-image $(call docker-build-no-cgo,linux/arm64,linux,arm64,liaison-edge-linux-arm64,cmd/edge/main.go) .PHONY: build-edge-darwin-amd64 build-edge-darwin-amd64: $(call local-build-darwin,amd64,liaison-edge-darwin-amd64,cmd/edge/main.go) .PHONY: build-edge-darwin-arm64 build-edge-darwin-arm64: $(call local-build-darwin,arm64,liaison-edge-darwin-arm64,cmd/edge/main.go) .PHONY: build-edge-windows-amd64 build-edge-windows-amd64: docker-image $(call docker-build-no-cgo,linux/amd64,windows,amd64,liaison-edge-windows-amd64.exe,cmd/edge/main.go) # ============================================================================ # Tar command detection: prefer gtar (GNU tar) if available # ============================================================================ TAR_CMD := $(shell command -v gtar 2>/dev/null || command -v tar 2>/dev/null || echo tar) # ============================================================================ # Edge package creation (tar.gz with binary and config template) # ============================================================================ .PHONY: package-edge-all package-edge-all: package-edge-linux-amd64 package-edge-linux-arm64 package-edge-darwin-amd64 package-edge-darwin-arm64 package-edge-windows-amd64 @echo "✅ All edge packages created in ./packages/edge/" .PHONY: package-edge-linux-amd64 package-edge-linux-amd64: build-edge-linux-amd64 @echo "Packaging liaison-edge-linux-amd64..." @mkdir -p ./packages/edge @TMP_DIR=$$(mktemp -d) && \ PACKAGE_PATH="$$(pwd)/packages/edge/liaison-edge-linux-amd64.tar.gz" && \ COPYFILE_DISABLE=1 cp ./bin/liaison-edge-linux-amd64 "$$TMP_DIR/liaison-edge" && \ COPYFILE_DISABLE=1 cp ./dist/edge/liaison-edge.yaml.template "$$TMP_DIR/liaison-edge.yaml.template" && \ cd "$$TMP_DIR" && \ COPYFILE_DISABLE=1 $(TAR_CMD) --exclude='._*' --exclude='.DS_Store' -czf "$$PACKAGE_PATH" liaison-edge liaison-edge.yaml.template && \ rm -rf "$$TMP_DIR" && \ echo "✅ Package created: ./packages/edge/liaison-edge-linux-amd64.tar.gz" .PHONY: package-edge-linux-arm64 package-edge-linux-arm64: build-edge-linux-arm64 @echo "Packaging liaison-edge-linux-arm64..." @mkdir -p ./packages/edge @TMP_DIR=$$(mktemp -d) && \ PACKAGE_PATH="$$(pwd)/packages/edge/liaison-edge-linux-arm64.tar.gz" && \ COPYFILE_DISABLE=1 cp ./bin/liaison-edge-linux-arm64 "$$TMP_DIR/liaison-edge" && \ COPYFILE_DISABLE=1 cp ./dist/edge/liaison-edge.yaml.template "$$TMP_DIR/liaison-edge.yaml.template" && \ cd "$$TMP_DIR" && \ COPYFILE_DISABLE=1 $(TAR_CMD) --exclude='._*' --exclude='.DS_Store' -czf "$$PACKAGE_PATH" liaison-edge liaison-edge.yaml.template && \ rm -rf "$$TMP_DIR" && \ echo "✅ Package created: ./packages/edge/liaison-edge-linux-arm64.tar.gz" .PHONY: package-edge-darwin-amd64 package-edge-darwin-amd64: build-edge-darwin-amd64 @echo "Packaging liaison-edge-darwin-amd64..." @mkdir -p ./packages/edge @TMP_DIR=$$(mktemp -d) && \ PACKAGE_PATH="$$(pwd)/packages/edge/liaison-edge-darwin-amd64.tar.gz" && \ COPYFILE_DISABLE=1 cp -X ./bin/liaison-edge-darwin-amd64 "$$TMP_DIR/liaison-edge" && \ COPYFILE_DISABLE=1 cp -X ./dist/edge/liaison-edge.yaml.template "$$TMP_DIR/liaison-edge.yaml.template" && \ cd "$$TMP_DIR" && \ COPYFILE_DISABLE=1 $(TAR_CMD) --exclude='._*' --exclude='.DS_Store' -czf "$$PACKAGE_PATH" liaison-edge liaison-edge.yaml.template && \ rm -rf "$$TMP_DIR" && \ echo "✅ Package created: ./packages/edge/liaison-edge-darwin-amd64.tar.gz" .PHONY: package-edge-darwin-arm64 package-edge-darwin-arm64: build-edge-darwin-arm64 @echo "Packaging liaison-edge-darwin-arm64..." @mkdir -p ./packages/edge @TMP_DIR=$$(mktemp -d) && \ PACKAGE_PATH="$$(pwd)/packages/edge/liaison-edge-darwin-arm64.tar.gz" && \ COPYFILE_DISABLE=1 cp -X ./bin/liaison-edge-darwin-arm64 "$$TMP_DIR/liaison-edge" && \ COPYFILE_DISABLE=1 cp -X ./dist/edge/liaison-edge.yaml.template "$$TMP_DIR/liaison-edge.yaml.template" && \ cd "$$TMP_DIR" && \ COPYFILE_DISABLE=1 $(TAR_CMD) --exclude='._*' --exclude='.DS_Store' -czf "$$PACKAGE_PATH" liaison-edge liaison-edge.yaml.template && \ rm -rf "$$TMP_DIR" && \ echo "✅ Package created: ./packages/edge/liaison-edge-darwin-arm64.tar.gz" .PHONY: package-edge-windows-amd64 package-edge-windows-amd64: build-edge-windows-amd64 @echo "Packaging liaison-edge-windows-amd64..." @mkdir -p ./packages/edge @TMP_DIR=$$(mktemp -d) && \ PACKAGE_PATH="$$(pwd)/packages/edge/liaison-edge-windows-amd64.tar.gz" && \ COPYFILE_DISABLE=1 cp ./bin/liaison-edge-windows-amd64.exe "$$TMP_DIR/liaison-edge.exe" && \ COPYFILE_DISABLE=1 cp ./dist/edge/liaison-edge.yaml.template "$$TMP_DIR/liaison-edge.yaml.template" && \ cd "$$TMP_DIR" && \ COPYFILE_DISABLE=1 $(TAR_CMD) --exclude='._*' --exclude='.DS_Store' -czf "$$PACKAGE_PATH" liaison-edge.exe liaison-edge.yaml.template && \ rm -rf "$$TMP_DIR" && \ echo "✅ Package created: ./packages/edge/liaison-edge-windows-amd64.tar.gz" # Legacy aliases .PHONY: edge-packages edge-package-linux-amd64 edge-package-linux-arm64 edge-package-darwin-amd64 edge-package-darwin-arm64 edge-package-windows-amd64 edge-packages: package-edge-all edge-package-linux-amd64: package-edge-linux-amd64 edge-package-linux-arm64: package-edge-linux-arm64 edge-package-darwin-amd64: package-edge-darwin-amd64 edge-package-darwin-arm64: package-edge-darwin-arm64 edge-package-windows-amd64: package-edge-windows-amd64 # ============================================================================ # Frontend build # ============================================================================ .PHONY: build-web build-web: @echo "Building frontend..." @if [ ! -d "web" ]; then \ echo "❌ Error: web directory not found"; \ exit 1; \ fi @if [ ! -f "web/package.json" ]; then \ echo "❌ Error: web/package.json not found"; \ exit 1; \ fi @echo "Cleaning old build artifacts..." @rm -rf web/dist @( \ cd web && \ export PNPM_HOME="$$HOME/.local/share/pnpm" 2>/dev/null || true && \ export PATH="$$PNPM_HOME:$$PATH" 2>/dev/null || true && \ echo "Installing dependencies..." && \ pnpm install || (echo "❌ Error: pnpm install failed" && exit 1) && \ echo "Building frontend..." && \ pnpm run build || (echo "❌ Error: pnpm run build failed" && exit 1) && \ echo "Build completed, checking output..." && \ if [ -d "dist" ] && [ "$$(ls -A dist 2>/dev/null)" ]; then \ echo "✅ Build output found in dist/"; \ ls -1 dist | head -5; \ else \ echo "❌ Error: dist directory not found or empty in web/"; \ ls -la . | head -10; \ exit 1; \ fi \ ) || (echo "❌ Error: Frontend build failed" && exit 1) @if [ -d "web/dist" ] && [ "$$(ls -A web/dist 2>/dev/null)" ]; then \ echo "✅ Frontend built successfully in web/dist/"; \ echo " Build output: $$(ls -1 web/dist | head -5 | tr '\n' ' ')"; \ else \ echo "❌ Error: web/dist not found or empty after build"; \ echo " Checking web directory contents..."; \ ls -la web/ | head -10 || true; \ exit 1; \ fi # ============================================================================ # Full package (liaison + edge binaries for all platforms + frontend + systemd files) # ============================================================================ .PHONY: package package: build-linux build-edge-all package-edge-all build-web build-tools-linux prepare-guacd-linux @chmod +x dist/package.sh @./dist/package.sh # Legacy alias .PHONY: pack pack: package # ============================================================================ # Docker images (server-side: liaison + frontier) # Images are "thin": they COPY pre-built artifacts produced by `make package`. # Run `make package` first (or at least build-linux + build-web + build-tools-linux # + build-edge-all + package-edge-all + build-frontier-linux). # ============================================================================ DOCKER_COMPOSE_DIR = deploy/docker LIAISON_IMAGE_REGISTRY ?= liaison LIAISON_IMAGE_TAG ?= $(shell cat VERSION 2>/dev/null | tr -d 'v' || echo latest) DOCKER_IMAGE_PLATFORM ?= linux/amd64 .PHONY: image-liaison image-liaison: @if [ ! -f bin/liaison ] || [ ! -f bin/password-generator ] || [ ! -d web/dist ]; then \ echo "❌ Missing artifacts. Run 'make package' first."; \ exit 1; \ fi @if command -v file >/dev/null 2>&1; then \ for binary in bin/liaison bin/password-generator; do \ file "$$binary" | grep -Eq 'ELF 64-bit.*(x86-64|x86_64)' || { \ echo "❌ $$binary must be a Linux amd64 binary. Run 'make package' first."; \ exit 1; \ }; \ done; \ fi docker build --platform $(DOCKER_IMAGE_PLATFORM) \ -t $(LIAISON_IMAGE_REGISTRY)/liaison:$(LIAISON_IMAGE_TAG) \ -f $(DOCKER_COMPOSE_DIR)/Dockerfile.liaison . @echo "✅ Built $(LIAISON_IMAGE_REGISTRY)/liaison:$(LIAISON_IMAGE_TAG)" .PHONY: image-frontier image-frontier: build-frontier-linux @if command -v file >/dev/null 2>&1; then \ file bin/frontier | grep -Eq 'ELF 64-bit.*(x86-64|x86_64)' || { \ echo "❌ bin/frontier must be a Linux amd64 binary. Run 'make build-frontier-linux' first."; \ exit 1; \ }; \ fi docker build --platform $(DOCKER_IMAGE_PLATFORM) \ -t $(LIAISON_IMAGE_REGISTRY)/frontier:$(LIAISON_IMAGE_TAG) \ -f $(DOCKER_COMPOSE_DIR)/Dockerfile.frontier . @echo "✅ Built $(LIAISON_IMAGE_REGISTRY)/frontier:$(LIAISON_IMAGE_TAG)" .PHONY: images images: image-liaison image-frontier .PHONY: compose-up compose-up: @if [ ! -f $(DOCKER_COMPOSE_DIR)/.env ]; then \ echo "❌ $(DOCKER_COMPOSE_DIR)/.env not found. Copy .env.example and edit first."; \ exit 1; \ fi cd $(DOCKER_COMPOSE_DIR) && docker compose up -d .PHONY: compose-down compose-down: cd $(DOCKER_COMPOSE_DIR) && docker compose down .PHONY: compose-logs compose-logs: cd $(DOCKER_COMPOSE_DIR) && docker compose logs -f .PHONY: package-docker package-docker: images @chmod +x $(DOCKER_COMPOSE_DIR)/package-docker.sh @$(DOCKER_COMPOSE_DIR)/package-docker.sh # ============================================================================ # Version sync # Usage: # make update-version version=1.2.7 # make version version=1.2.7 # make version=1.2.7 # ============================================================================ .PHONY: update-version version update-version version: @if [ -z "$(version)" ]; then \ echo "❌ Error: missing version. Usage: make version=1.2.7"; \ exit 1; \ fi @chmod +x scripts/sync-release-version.sh @scripts/sync-release-version.sh "$(version)"