Цель run зависела только от backend, а статика фронтенда попадает в бинарник через go:embed из backend/static, который обновляла лишь цель frontend. Поэтому make run пересобирал Go-код со старым UI. - run теперь зависит от frontend backend; - frontend стала инкрементальной: npm ci только при изменении package.json/ package-lock.json, npm run build и копирование в backend/static — только когда исходники или конфиги новее, чем backend/static/index.html (он же stamp); - проверки вынесены в shell-recipe, т.к. имена SvelteKit-роутов вида (app) ломают разбор имён файлов в make.
168 lines
6.2 KiB
Makefile
168 lines
6.2 KiB
Makefile
.PHONY: help build build-release frontend backend android install-android-app run migrate reconcile reconcile-delete tidy test testdata clean
|
|
|
|
# Default goal: print the list of available targets.
|
|
.DEFAULT_GOAL := help
|
|
|
|
# Android SDK location. Override when the SDK lives elsewhere.
|
|
ANDROID_SDK ?= $(HOME)/Android/sdk
|
|
|
|
# adb from the Android SDK's platform-tools (matches the SDK we build against).
|
|
ADB ?= $(ANDROID_SDK)/platform-tools/adb
|
|
|
|
# Device serial for `install-android-app` (falls back to $ANDROID_SERIAL). When
|
|
# empty, the sole connected device is used; with several connected devices the
|
|
# target lists them and stops instead of guessing. Override with SERIAL=<serial>.
|
|
SERIAL ?= $(ANDROID_SERIAL)
|
|
|
|
# Release version stamped into the binary (-X main.version). Override with VERSION=...
|
|
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
|
|
|
# Seed testdata parameters (see `make testdata`). Counts: ALBUMS, PHOTOS, SEED, TIMEOUT.
|
|
# Boolean (set to 1 to enable): TAGS, COMMENTS, LIKES, SHARE, INVITES, WAIT, DRY, VIDEO.
|
|
# VIDEO requires ffmpeg on PATH; it is skipped without it. Extra passthrough flags: ARGS.
|
|
ALBUMS ?= 2
|
|
PHOTOS ?= 10
|
|
SEED ?= 0
|
|
TIMEOUT ?= 30
|
|
|
|
# Print the list of available targets.
|
|
help:
|
|
@echo "Usage: make <target>"
|
|
@echo
|
|
@echo "Available targets:"
|
|
@grep -hE '^[a-zA-Z0-9_-]+:' $(MAKEFILE_LIST) | cut -d: -f1 | sed 's/^/ /'
|
|
|
|
# Frontend sources whose changes must trigger a rebuild. `backend/static/index.html`
|
|
# doubles as the build stamp, so a clean clone or `make clean` (which empties
|
|
# backend/static) forces the next build to regenerate.
|
|
FRONTEND_OUT := backend/static/index.html
|
|
|
|
# `npm ci` is only needed when the manifest/lockfile change.
|
|
FRONTEND_DEPS_STAMP := frontend/node_modules/.install-stamp
|
|
|
|
# Build the SvelteKit bundle and copy it into backend/static (embedded via
|
|
# go:embed). Incremental: recompile only when frontend sources are newer than the
|
|
# embedded bundle. Paths are checked from the recipe (not as make prerequisites)
|
|
# because SvelteKit route names like `(app)` break make's filename parsing.
|
|
frontend:
|
|
@set -e; \
|
|
if [ ! -f $(FRONTEND_DEPS_STAMP) ] \
|
|
|| [ frontend/package.json -nt $(FRONTEND_DEPS_STAMP) ] \
|
|
|| [ frontend/package-lock.json -nt $(FRONTEND_DEPS_STAMP) ]; then \
|
|
echo '> cd frontend && npm ci'; \
|
|
cd frontend && npm ci; \
|
|
touch node_modules/.install-stamp; \
|
|
cd ..; \
|
|
fi; \
|
|
if [ ! -f $(FRONTEND_OUT) ] \
|
|
|| [ -n "$$(find frontend/src frontend/static -newer $(FRONTEND_OUT) -print -quit)" ] \
|
|
|| [ frontend/package.json -nt $(FRONTEND_OUT) ] \
|
|
|| [ frontend/package-lock.json -nt $(FRONTEND_OUT) ] \
|
|
|| [ frontend/svelte.config.js -nt $(FRONTEND_OUT) ] \
|
|
|| [ frontend/vite.config.ts -nt $(FRONTEND_OUT) ] \
|
|
|| [ frontend/tailwind.config.ts -nt $(FRONTEND_OUT) ] \
|
|
|| [ frontend/tsconfig.json -nt $(FRONTEND_OUT) ]; then \
|
|
echo '> cd frontend && npm run build'; \
|
|
cd frontend && npm run build; \
|
|
cd ..; \
|
|
rm -rf backend/static/*; \
|
|
cp -r frontend/build/* backend/static/; \
|
|
else \
|
|
echo 'frontend: up to date'; \
|
|
fi
|
|
|
|
backend:
|
|
mkdir -p bin
|
|
# -tags nodynamic forces gen2brain/webp to use its pure-Go transpiled path
|
|
# (no purego/dlopen), keeping the binary fully static.
|
|
cd backend && CGO_ENABLED=0 go build -tags nodynamic -trimpath -ldflags="-s -w" \
|
|
-o ../bin/galo ./cmd/server
|
|
|
|
build: frontend backend
|
|
|
|
# Android client (independent of the server build). Requires the Android SDK.
|
|
android:
|
|
cd android && ANDROID_HOME=$(ANDROID_SDK) ./gradlew :app:assembleDebug
|
|
|
|
# Install the debug Android client on a connected device. Builds the APK via the
|
|
# `android` target first; only devices in the `device` state are considered.
|
|
install-android-app: android
|
|
@devices="$$($(ADB) devices | awk 'NR>1 && $$2 == "device" {print $$1}')"; \
|
|
if [ -n "$(SERIAL)" ]; then \
|
|
target="$(SERIAL)"; \
|
|
else \
|
|
count=$$(printf '%s\n' "$$devices" | grep -c .); \
|
|
if [ "$$count" -eq 0 ]; then \
|
|
echo "install-android-app: no connected device (see '$(ADB) devices')" >&2; \
|
|
exit 1; \
|
|
elif [ "$$count" -gt 1 ]; then \
|
|
echo "install-android-app: several devices connected; set SERIAL=<serial>:" >&2; \
|
|
printf '%s\n' "$$devices" | sed 's/^/ /' >&2; \
|
|
exit 1; \
|
|
else \
|
|
target="$$devices"; \
|
|
fi; \
|
|
fi; \
|
|
echo "Installing app-debug.apk on $$target"; \
|
|
$(ADB) -s "$$target" install -r android/app/build/outputs/apk/debug/app-debug.apk
|
|
|
|
# Release build: full static, stripped and (if available) UPX-compressed binary
|
|
# with the version embedded. Produces bin/galo and a copy at bin/galo-$(VERSION).
|
|
build-release: frontend
|
|
mkdir -p bin
|
|
cd backend && CGO_ENABLED=0 go build -tags nodynamic -trimpath \
|
|
-ldflags="-s -w -X main.version=$(VERSION)" -o ../bin/galo ./cmd/server
|
|
strip --strip-all bin/galo
|
|
@if command -v upx >/dev/null 2>&1; then \
|
|
upx --best --quiet bin/galo && echo "upx: bin/galo compressed"; \
|
|
else \
|
|
echo "upx not found - skipping compression (install upx-ucl to enable)"; \
|
|
fi
|
|
cp bin/galo bin/galo-$(VERSION)
|
|
@echo "release: bin/galo-$(VERSION)"
|
|
|
|
run: frontend backend
|
|
./bin/galo
|
|
|
|
migrate:
|
|
cd backend && go run ./cmd/migrate
|
|
|
|
# Reconcile object storage against the metadata journal (report only).
|
|
reconcile:
|
|
cd backend && go run ./cmd/reconcile
|
|
|
|
# Reconcile and delete orphaned blobs older than --min-age (default 1h).
|
|
# Override the grace period when needed: make reconcile-delete MIN_AGE=1m
|
|
reconcile-delete:
|
|
cd backend && go run ./cmd/reconcile --delete $(if $(MIN_AGE),--min-age $(MIN_AGE),)
|
|
|
|
tidy:
|
|
cd backend && go mod tidy
|
|
|
|
test:
|
|
cd backend && go test ./...
|
|
|
|
# Seed test data into a running instance through the public API (additive only).
|
|
# Credentials come from the environment: GALO_EMAIL, GALO_PASSWORD
|
|
# (optional GALO_BASE_URL). Example:
|
|
# make testdata ALBUMS=3 PHOTOS=5 TAGS=1 LIKES=1 SEED=42
|
|
testdata:
|
|
@python3 scripts/seed.py \
|
|
--albums $(ALBUMS) \
|
|
--photos-per-album $(PHOTOS) \
|
|
--seed $(SEED) \
|
|
--timeout $(TIMEOUT) \
|
|
$(if $(filter 1,$(TAGS)),--tags,) \
|
|
$(if $(filter 1,$(COMMENTS)),--comments,) \
|
|
$(if $(filter 1,$(LIKES)),--likes,) \
|
|
$(if $(filter 1,$(SHARE)),--share-links,) \
|
|
$(if $(filter 1,$(INVITES)),--invites,) \
|
|
$(if $(filter 1,$(VIDEO)),--video,) \
|
|
$(if $(filter 1,$(WAIT)),--wait-variants,) \
|
|
$(if $(filter 1,$(DRY)),--dry-run,) \
|
|
$(ARGS)
|
|
|
|
clean:
|
|
rm -rf bin backend/static/*
|
|
touch backend/static/.gitkeep
|