268 lines
9.8 KiB
Makefile
268 lines
9.8 KiB
Makefile
# =========================================
|
||
# 📦 XControl Account Service Makefile
|
||
# =========================================
|
||
|
||
APP_NAME := xcontrol-account
|
||
MAIN_FILE := ./cmd/accountsvc/main.go
|
||
PORT ?= 8080
|
||
OS := $(shell uname -s)
|
||
|
||
DB_NAME := account
|
||
DB_USER := shenlan
|
||
DB_PASS := password
|
||
DB_HOST := 127.0.0.1
|
||
DB_PORT := 5432
|
||
DB_URL := postgres://$(DB_USER):$(DB_PASS)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=disable
|
||
|
||
REPLICATION_MODE ?= pgsync
|
||
|
||
DB_ADMIN_USER ?= $(DB_USER)
|
||
DB_ADMIN_PASS ?= $(DB_PASS)
|
||
|
||
SCHEMA_FILE := ./sql/schema.sql
|
||
PGLOGICAL_INIT_FILE := ./sql/schema_pglogical_init.sql
|
||
PGLOGICAL_PATCH_FILE := ./sql/schema_pglogical_patch.sql
|
||
PGLOGICAL_REGION_FILE := ./sql/schema_pglogical_region.sql
|
||
|
||
ACCOUNT_EXPORT_FILE ?= account-export.yaml
|
||
ACCOUNT_IMPORT_FILE ?= account-export.yaml
|
||
ACCOUNT_EMAIL_KEYWORD ?=
|
||
ACCOUNT_SYNC_CONFIG ?= config/sync.yaml
|
||
SUPERADMIN_USERNAME ?= Admin
|
||
SUPERADMIN_PASSWORD ?= ChangeMe
|
||
SUPERADMIN_EMAIL ?= admin@svc.plus
|
||
|
||
export PATH := /usr/local/go/bin:$(PATH)
|
||
|
||
# =========================================
|
||
# 🧩 基础命令
|
||
# =========================================
|
||
|
||
.PHONY: all init build clean start stop restart dev test help \
|
||
init-db-core init-db-replication init-db-pglogical \
|
||
reinit-pglogical account-sync-push account-sync-pull account-sync-mirror
|
||
|
||
all: build
|
||
|
||
help:
|
||
@echo "🧭 XControl Account Service Makefile"
|
||
@echo "make init 初始化 Go 环境与数据库"
|
||
@echo "make init-db 执行数据库 schema(支持 REPLICATION_MODE=pgsync|pglogical)"
|
||
@echo "make migrate-db 执行数据库迁移"
|
||
@echo "make dump-schema 导出数据库 schema"
|
||
@echo "make account-export 导出账号数据为 YAML"
|
||
@echo "make account-import 从 YAML 导入账号数据"
|
||
@echo "make create-super-admin 创建超级管理员"
|
||
@echo "make reinit-db 重置业务 schema (不涉及 pglogical)"
|
||
@echo "make reinit-pglogical 重新初始化 pglogical schema"
|
||
@echo "make dev 热重载开发模式"
|
||
@echo "make clean 清理构建产物"
|
||
|
||
# =========================================
|
||
# 🧰 初始化
|
||
# =========================================
|
||
|
||
init: init-go init-db
|
||
|
||
init-go:
|
||
@echo ">>> 检查 Go 环境"
|
||
@if ! command -v go >/dev/null; then \
|
||
echo "未安装 Go,自动安装中..."; \
|
||
([ "$(OS)" = "Darwin" ] && brew install go@1.24 && brew link --overwrite --force go@1.24) || \
|
||
(sudo apt-get update && sudo apt-get install -y golang); \
|
||
fi
|
||
@echo ">>> 配置 Go Proxy"
|
||
@(curl -fsSL --max-time 5 https://goproxy.cn >/dev/null && go env -w GOPROXY=https://goproxy.cn,direct) || \
|
||
(go env -w GOPROXY=https://proxy.golang.org,direct)
|
||
@go mod tidy
|
||
|
||
init-db:
|
||
@echo ">>> 初始化数据库 schema"
|
||
@command -v psql >/dev/null || (echo "❌ 未检测到 psql,请安装 PostgreSQL 客户端" && exit 1)
|
||
@$(MAKE) init-db-core
|
||
@$(MAKE) init-db-replication
|
||
|
||
init-db-core:
|
||
@echo ">>> 初始化业务 schema ($(SCHEMA_FILE))"
|
||
@psql "$(DB_URL)" -v ON_ERROR_STOP=1 -f $(SCHEMA_FILE)
|
||
|
||
init-db-replication:
|
||
@if [ "$(REPLICATION_MODE)" = "pglogical" ]; then \
|
||
$(MAKE) init-db-pglogical; \
|
||
else \
|
||
echo ">>> 跳过 pglogical 初始化 (REPLICATION_MODE=$(REPLICATION_MODE))"; \
|
||
fi
|
||
|
||
init-db-pglogical:
|
||
@if [ -f $(PGLOGICAL_INIT_FILE) ]; then \
|
||
echo ">>> 初始化 pglogical schema (REPLICATION_MODE=pglogical)"; \
|
||
if PGPASSWORD="$(DB_ADMIN_PASS)" psql -h $(DB_HOST) -U $(DB_ADMIN_USER) -d $(DB_NAME) \
|
||
-Atc "SELECT rolsuper FROM pg_roles WHERE rolname = current_user" 2>/dev/null | grep -qx 't'; then \
|
||
PGPASSWORD="$(DB_ADMIN_PASS)" psql -h $(DB_HOST) -U $(DB_ADMIN_USER) -d $(DB_NAME) \
|
||
-v ON_ERROR_STOP=1 -f $(PGLOGICAL_INIT_FILE); \
|
||
elif psql "$(DB_URL)" -Atc "SELECT rolsuper FROM pg_roles WHERE rolname = current_user" | grep -qx 't'; then \
|
||
psql "$(DB_URL)" -v ON_ERROR_STOP=1 -f $(PGLOGICAL_INIT_FILE); \
|
||
else \
|
||
echo "⚠️ 当前用户非超级用户,跳过 pglogical 初始化"; \
|
||
fi; \
|
||
fi; \
|
||
if [ -f $(PGLOGICAL_PATCH_FILE) ]; then \
|
||
echo ">>> 应用 pglogical 默认值补丁"; \
|
||
psql "$(DB_URL)" -v ON_ERROR_STOP=1 -f $(PGLOGICAL_PATCH_FILE); \
|
||
fi
|
||
|
||
# =========================================
|
||
# 🧠 PGLogical 双节点初始化
|
||
# =========================================
|
||
|
||
init-pglogical-region:
|
||
@[ -n "$(REGION_DB_URL)" ] || (echo "❌ 缺少 REGION_DB_URL"; exit 1)
|
||
@[ -n "$(NODE_NAME)" ] || (echo "❌ 缺少 NODE_NAME"; exit 1)
|
||
@[ -n "$(NODE_DSN)" ] || (echo "❌ 缺少 NODE_DSN"; exit 1)
|
||
@[ -n "$(SUBSCRIPTION_NAME)" ] || (echo "❌ 缺少 SUBSCRIPTION_NAME"; exit 1)
|
||
@[ -n "$(PROVIDER_DSN)" ] || (echo "❌ 缺少 PROVIDER_DSN"; exit 1)
|
||
@psql "$(REGION_DB_URL)" -v ON_ERROR_STOP=1 \
|
||
-v NODE_NAME="$(NODE_NAME)" \
|
||
-v NODE_DSN="$(NODE_DSN)" \
|
||
-v SUBSCRIPTION_NAME="$(SUBSCRIPTION_NAME)" \
|
||
-v PROVIDER_DSN="$(PROVIDER_DSN)" \
|
||
-f $(PGLOGICAL_REGION_FILE)
|
||
|
||
init-pglogical-region-cn:
|
||
@$(MAKE) init-pglogical-region \
|
||
REGION_DB_URL="$(DB_URL)" \
|
||
NODE_NAME="node_cn" \
|
||
NODE_DSN="host=cn-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx" \
|
||
SUBSCRIPTION_NAME="sub_from_global" \
|
||
PROVIDER_DSN="host=global-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx"
|
||
|
||
init-pglogical-region-global:
|
||
@$(MAKE) init-pglogical-region \
|
||
REGION_DB_URL="$(DB_URL)" \
|
||
NODE_NAME="node_global" \
|
||
NODE_DSN="host=global-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx" \
|
||
SUBSCRIPTION_NAME="sub_from_cn" \
|
||
PROVIDER_DSN="host=cn-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx"
|
||
|
||
# =========================================
|
||
# 📦 数据库迁移与管理
|
||
# =========================================
|
||
|
||
migrate-db:
|
||
@echo ">>> 执行数据库迁移"
|
||
@go run ./cmd/migratectl/main.go migrate --dsn "$(DB_URL)" --dir sql/migrations
|
||
|
||
dump-schema:
|
||
@echo ">>> 导出 schema 到 $(SCHEMA_FILE)"
|
||
@pg_dump -s -O -x "$(DB_URL)" > $(SCHEMA_FILE)
|
||
|
||
drop-db:
|
||
@echo "⚠️ 即将删除数据库 $(DB_NAME) ..."
|
||
@read -p "确定要删除数据库 $(DB_NAME)? [y/N] " confirm && \
|
||
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
|
||
echo ">>> 强制断开现有连接 ..."; \
|
||
if ! PGPASSWORD="$(DB_ADMIN_PASS)" psql -h $(DB_HOST) -U $(DB_ADMIN_USER) -d postgres \
|
||
-c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='$(DB_NAME)' AND pid <> pg_backend_pid();"; then \
|
||
echo "⚠️ 无法断开所有连接(需要超级用户权限)"; \
|
||
fi; \
|
||
echo ">>> 清理 pglogical schema ..."; \
|
||
PGPASSWORD="$(DB_ADMIN_PASS)" psql -h $(DB_HOST) -U $(DB_ADMIN_USER) -d $(DB_NAME) \
|
||
-c "DROP SCHEMA IF EXISTS pglogical CASCADE;" >/dev/null 2>&1 || \
|
||
echo "⚠️ 无法删除 pglogical schema(数据库可能不存在或缺少权限)"; \
|
||
echo ">>> 删除数据库 $(DB_NAME) ..."; \
|
||
if PGPASSWORD="$(DB_ADMIN_PASS)" psql -h $(DB_HOST) -U $(DB_ADMIN_USER) -d postgres \
|
||
-c "DROP DATABASE IF EXISTS $(DB_NAME);"; then \
|
||
echo ">>> 数据库已删除"; \
|
||
else \
|
||
echo ">>> 删除失败"; \
|
||
fi; \
|
||
else \
|
||
echo "取消删除"; \
|
||
fi
|
||
|
||
reset-public-schema:
|
||
@psql "$(DB_URL)" -v ON_ERROR_STOP=1 -v db_user="$(DB_USER)" -f sql/reset_public_schema.sql
|
||
|
||
reinit-db:
|
||
@echo ">>> 重置业务 schema (sql/schema.sql)"
|
||
@$(MAKE) reset-public-schema
|
||
@$(MAKE) init-db-core
|
||
|
||
reinit-pglogical:
|
||
@if [ "$(REPLICATION_MODE)" = "pglogical" ]; then \
|
||
echo ">>> 重新初始化 pglogical schema"; \
|
||
$(MAKE) init-db-pglogical; \
|
||
else \
|
||
echo ">>> 当前 REPLICATION_MODE=$(REPLICATION_MODE),无需 pglogical 处理"; \
|
||
fi
|
||
|
||
# =========================================
|
||
# 💾 账号导入导出
|
||
# =========================================
|
||
|
||
account-export:
|
||
@go run ./cmd/migratectl/main.go export --dsn "$(DB_URL)" --output "$(ACCOUNT_EXPORT_FILE)" $(if $(ACCOUNT_EMAIL_KEYWORD),--email "$(ACCOUNT_EMAIL_KEYWORD)")
|
||
|
||
account-import:
|
||
@[ -f "$(ACCOUNT_IMPORT_FILE)" ] || (echo "❌ 未找到文件 $(ACCOUNT_IMPORT_FILE)"; exit 1)
|
||
@go run ./cmd/migratectl/main.go import --dsn "$(DB_URL)" --file "$(ACCOUNT_IMPORT_FILE)" \
|
||
$(if $(ACCOUNT_IMPORT_MERGE),--merge) \
|
||
$(if $(ACCOUNT_IMPORT_MERGE_STRATEGY),--merge-strategy "$(ACCOUNT_IMPORT_MERGE_STRATEGY)") \
|
||
$(if $(ACCOUNT_IMPORT_DRY_RUN),--dry-run) \
|
||
$(foreach UUID,$(ACCOUNT_IMPORT_MERGE_ALLOWLIST),--merge-allowlist $(UUID)) \
|
||
$(ACCOUNT_IMPORT_EXTRA_FLAGS)
|
||
|
||
account-sync-push:
|
||
@[ -f "$(ACCOUNT_SYNC_CONFIG)" ] || (echo "❌ 未找到配置文件 $(ACCOUNT_SYNC_CONFIG)"; exit 1)
|
||
@go run ./cmd/syncctl/main.go push --config "$(ACCOUNT_SYNC_CONFIG)"
|
||
|
||
account-sync-pull:
|
||
@[ -f "$(ACCOUNT_SYNC_CONFIG)" ] || (echo "❌ 未找到配置文件 $(ACCOUNT_SYNC_CONFIG)"; exit 1)
|
||
@go run ./cmd/syncctl/main.go pull --config "$(ACCOUNT_SYNC_CONFIG)"
|
||
|
||
account-sync-mirror:
|
||
@[ -f "$(ACCOUNT_SYNC_CONFIG)" ] || (echo "❌ 未找到配置文件 $(ACCOUNT_SYNC_CONFIG)"; exit 1)
|
||
@go run ./cmd/syncctl/main.go mirror --config "$(ACCOUNT_SYNC_CONFIG)"
|
||
|
||
create-super-admin:
|
||
@[ -n "$(SUPERADMIN_USERNAME)" ] && [ -n "$(SUPERADMIN_PASSWORD)" ] || (echo "❌ 请指定用户名与密码"; exit 1)
|
||
@go run ./cmd/createadmin/main.go \
|
||
--driver postgres \
|
||
--dsn "$(DB_URL)" \
|
||
--username "$(SUPERADMIN_USERNAME)" \
|
||
--password "$(SUPERADMIN_PASSWORD)" \
|
||
--email "$(SUPERADMIN_EMAIL)"
|
||
|
||
# =========================================
|
||
# ⚙️ 编译与运行
|
||
# =========================================
|
||
|
||
build:
|
||
@go build -o $(APP_NAME) $(MAIN_FILE)
|
||
|
||
upgrade: build
|
||
systemctl stop xcontrol-account
|
||
cp xcontrol-account /usr/bin/xcontrol-account
|
||
systemctl start xcontrol-account
|
||
|
||
start:
|
||
@./$(APP_NAME) --config config/account.yaml &
|
||
|
||
stop:
|
||
@pkill -f "$(APP_NAME)" || echo "⚠️ 未找到运行进程"
|
||
|
||
restart: stop start
|
||
|
||
dev:
|
||
@if command -v air >/dev/null; then \
|
||
PORT=$(PORT) air -c .air.toml; \
|
||
else \
|
||
PORT=$(PORT) go run $(MAIN_FILE); \
|
||
fi
|
||
|
||
test:
|
||
go test ./...
|
||
|
||
clean:
|
||
rm -f $(APP_NAME) *.pid *.log
|