# spacesh — local build helpers (macOS). # `make` or `make help` lists targets. APP_DIR := app TAURI_TARGET := universal-apple-darwin DMG_DIR := $(APP_DIR)/src-tauri/target/$(TAURI_TARGET)/release/bundle/dmg NATIVE_DMG_DIR := $(APP_DIR)/src-tauri/target/release/bundle/dmg NATIVE_TRIPLE := $(shell rustc -vV 2>/dev/null | awk '/^host:/{print $$2}') SIDECAR_DIR := $(APP_DIR)/src-tauri/bin BUNDLE_CONFIG := src-tauri/tauri.bundle.conf.json APP_BUNDLE := $(APP_DIR)/src-tauri/target/$(TAURI_TARGET)/release/bundle/macos/spacesh.app NATIVE_APP_BUNDLE := $(APP_DIR)/src-tauri/target/release/bundle/macos/spacesh.app APP_VERSION := $(shell node -p "require('./$(APP_DIR)/src-tauri/tauri.conf.json').version" 2>/dev/null || echo 0.0.0) LANDING_IMAGE := spacesh-landing LANDING_VERSION := $(shell cat landing/VERSION 2>/dev/null || echo 0.0.0) REGISTRY ?= git.realmanual.ru REPO ?= spacesh # ---- Prod deploy (SSH) ---- SSH_HOST ?= 192.168.8.5 SSH_USER ?= deploy SSH_REMOTE_DIR ?= /opt/spacesh SSH_KEY ?= $(HOME)/.ssh/id_rsa SSH_OPTS := -i $(SSH_KEY) -o StrictHostKeyChecking=accept-new .DEFAULT_GOAL := help .PHONY: help help: ## show this help @echo "spacesh — make targets (app v$(APP_VERSION)):" @grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | \ awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}' # ---- App / DMG (macOS) ---- .PHONY: deps deps: ## install frontend deps (npm ci) cd $(APP_DIR) && npm ci .PHONY: targets targets: ## add rust targets for the universal build rustup target add aarch64-apple-darwin x86_64-apple-darwin .PHONY: dmg dmg: targets ## build the universal (Intel + Apple Silicon) .dmg — UNSIGNED # Tauri's universal build compiles each arch separately and expects a sidecar # named with THAT arch's triple; it lipo's them into the universal bundle and # ships spaceshd inside spacesh.app/Contents/MacOS (else the GUI is offline). cargo build --release -p spaceshd --target aarch64-apple-darwin cargo build --release -p spaceshd --target x86_64-apple-darwin rm -rf $(SIDECAR_DIR) && mkdir -p $(SIDECAR_DIR) # avoid stale sidecars poisoning the bundle cp target/aarch64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-aarch64-apple-darwin cp target/x86_64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-x86_64-apple-darwin cd $(APP_DIR) && npm run tauri build -- --target $(TAURI_TARGET) --config $(BUNDLE_CONFIG) @echo "→ $(DMG_DIR)" && ls -lh $(DMG_DIR)/*.dmg .PHONY: dmg-native dmg-native: ## build a .dmg for the current arch only (faster) cargo build --release -p spaceshd rm -rf $(SIDECAR_DIR) && mkdir -p $(SIDECAR_DIR) # avoid stale sidecars poisoning the bundle cp target/release/spaceshd $(SIDECAR_DIR)/spaceshd-$(NATIVE_TRIPLE) cd $(APP_DIR) && npm run tauri build -- --config $(BUNDLE_CONFIG) @ls -lh $(NATIVE_DMG_DIR)/*.dmg .PHONY: dev dev: ## run the app in dev mode (tauri dev) cd $(APP_DIR) && npm run tauri dev .PHONY: daemon daemon: ## build & run the daemon cargo run -p spaceshd .PHONY: kill-daemon kill-daemon: ## stop a running spaceshd so a freshly-built one takes over -pkill -x spaceshd -rm -f $$HOME/.spacesh/sock .PHONY: install install: kill-daemon ## install the native .app to /Applications, restart daemon, clear quarantine rm -rf /Applications/spacesh.app cp -R "$(NATIVE_APP_BUNDLE)" /Applications/ xattr -dr com.apple.quarantine /Applications/spacesh.app @echo "Installed (native). Quit & relaunch spacesh; the bundled daemon restarts." .PHONY: install-universal install-universal: kill-daemon ## install the universal .app to /Applications rm -rf /Applications/spacesh.app cp -R "$(APP_BUNDLE)" /Applications/ xattr -dr com.apple.quarantine /Applications/spacesh.app .PHONY: reinstall reinstall: dmg-native install ## native rebuild + reinstall + restart daemon (fast self-update) # ---- Tests ---- .PHONY: test test: ## run all tests (cargo + tsc) cargo test cd $(APP_DIR) && npx tsc --noEmit # ---- Landing ---- .PHONY: landing-image landing-image: ## build the landing nginx image docker build -t $(LANDING_IMAGE):$(LANDING_VERSION) -t $(LANDING_IMAGE):latest landing .PHONY: landing-run landing-run: landing-image ## serve the landing locally on http://localhost:8088 docker run --rm -p 8088:80 $(LANDING_IMAGE):latest .PHONY: landing-push landing-push: landing-image ## tag & push the landing image to the registry docker tag $(LANDING_IMAGE):latest $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):$(LANDING_VERSION) docker tag $(LANDING_IMAGE):latest $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):latest docker push $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):$(LANDING_VERSION) docker push $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):latest # ---- Prod deploy ---- .PHONY: deploy-dmg deploy-dmg: dmg ## upload the universal .dmg to the prod download dir (stable spacesh.dmg) ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "mkdir -p $(SSH_REMOTE_DIR)/download" scp $(SSH_OPTS) $(DMG_DIR)/*.dmg "$(SSH_USER)@$(SSH_HOST):$(SSH_REMOTE_DIR)/download/spacesh.dmg" @echo "Uploaded → https://spaceshell.ru/download/spacesh.dmg" .PHONY: deploy-stack deploy-stack: ## sync compose+proxy.conf to prod and pull/up (manual; CI does this on push) ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "mkdir -p $(SSH_REMOTE_DIR)/download" scp $(SSH_OPTS) deploy/docker-compose.yaml deploy/proxy.conf "$(SSH_USER)@$(SSH_HOST):$(SSH_REMOTE_DIR)/" ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "cd $(SSH_REMOTE_DIR) && docker compose pull && docker compose up -d" # ---- Clean ---- .PHONY: clean clean: ## remove build artifacts cargo clean rm -rf $(APP_DIR)/dist