#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys from pathlib import Path # ===================== 可自定义配置(按需修改) ===================== PROJECT_ROOT = "go-monorepo" # 项目根目录名 GO_VERSION = "1.21" # 团队统一Go版本 # ==================================================================== def create_dirs(base_path: Path): """创建所有核心目录结构""" dirs = [ # 公共模块目录 "common/db", "common/redis", "common/logger", "common/utils", "common/middleware", # 业务服务根目录(无具体业务) "services", # 部署资源目录 "deploy/postgres", "deploy/redis", # 日志目录 "logs" ] for dir_path in dirs: full_path = base_path / dir_path full_path.mkdir(parents=True, exist_ok=True) print(f"✅ 创建目录: {full_path}") def write_file(file_path: Path, content: str, overwrite: bool = False): """写入文件(避免覆盖已有文件)""" if file_path.exists() and not overwrite: print(f"⚠️ 文件已存在,跳过: {file_path}") return with open(file_path, "w", encoding="utf-8") as f: f.write(content) print(f"✅ 生成文件: {file_path}") def generate_go_work(base_path: Path): """生成Go工作区核心文件 go.work + go.work.sum""" # go.work content = f"""go {GO_VERSION} # 公共模块 use ./common # 业务服务根目录(新增业务时手动追加 use ./services/xxx) use ./services """ write_file(base_path / "go.work", content) # 空的go.work.sum write_file(base_path / "go.work.sum", "") def generate_common_module(base_path: Path): """生成公共模块common的基础文件""" common_path = base_path / "common" # common/go.mod mod_content = f"""module {PROJECT_ROOT}/common go {GO_VERSION} require ( github.com/gin-gonic/gin v1.9.1 github.com/jmoiron/sqlx v1.3.5 github.com/redis/go-redis/v9 v9.3.0 go.uber.org/zap v1.26.0 github.com/lib/pq v1.10.9 ) """ write_file(common_path / "go.mod", mod_content) # 空的go.sum write_file(common_path / "go.sum", "") # 公共模块基础空文件(占位) empty_files = [ "db/postgres.go", "db/options.go", "redis/redis.go", "logger/logger.go", "utils/common.go", "middleware/cors.go" ] for file in empty_files: write_file(common_path / file, "") def generate_deploy_files(base_path: Path): """生成部署资源deploy的基础文件""" deploy_path = base_path / "deploy" # postgres/init.sql pg_sql = """-- PostgresSQL全局初始化脚本 -- 所有业务公共建库/建表语句写在这里,单独业务表建议在各自业务中处理 CREATE DATABASE IF NOT EXISTS monorepo; \\c monorepo; """ write_file(deploy_path / "postgres/init.sql", pg_sql) # redis/redis.conf redis_conf = """# Redis基础配置 bind 0.0.0.0 protected-mode no port 6379 daemonize no requirepass 123456 appendonly yes appendfsync everysec """ write_file(deploy_path / "redis/redis.conf", redis_conf) def generate_docker_compose(base_path: Path): """生成根目录docker-compose.yml(聚合中间件+业务模板)""" compose_content = f"""version: '3.8' services: # 公共PostgresSQL postgres: image: postgres:16-alpine container_name: {PROJECT_ROOT}-postgres environment: POSTGRES_USER: ${{PG_USER:-root}} POSTGRES_PASSWORD: ${{PG_PWD:-123456}} POSTGRES_DB: ${{PG_DB:-monorepo}} ports: - "${{PG_PORT:-5432}}:5432" volumes: - ./deploy/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql - pg_data:/var/lib/postgresql/data networks: - monorepo-net restart: always # 公共Redis redis: image: redis:7-alpine container_name: {PROJECT_ROOT}-redis ports: - "${{REDIS_PORT:-6379}}:6379" volumes: - ./deploy/redis/redis.conf:/etc/redis/redis.conf - redis_data:/data command: redis-server /etc/redis/redis.conf networks: - monorepo-net restart: always # 【业务服务模板】新增业务时复制以下块修改 # user: # build: # context: ./services/user # dockerfile: Dockerfile # container_name: {PROJECT_ROOT}-user # environment: # - GIN_MODE=release # - PG_ADDR=postgres:5432 # - REDIS_ADDR=redis:6379 # ports: # - "8080:8080" # volumes: # - ./logs/user:/app/logs # networks: # - monorepo-net # restart: always # depends_on: # - postgres # - redis # deploy: # resources: # limits: # cpus: "0.5" # memory: "512M" # 全局网络 networks: monorepo-net: driver: bridge # 全局数据卷 volumes: pg_data: redis_data: """ write_file(base_path / "docker-compose.yml", compose_content) # 日志目录占位文件 write_file(base_path / "logs/.gitkeep", "") def generate_global_config(base_path: Path): """生成全局配置文件 .env + Makefile""" # .env 全局环境变量 env_content = """# 全局环境变量 - 所有服务共享 # PostgresSQL PG_USER=root PG_PWD=123456 PG_DB=monorepo PG_PORT=5432 # Redis REDIS_PORT=6379 REDIS_PWD=123456 # Go服务通用 GIN_MODE=release """ write_file(base_path / ".env", env_content) # Makefile 全局快捷命令 makefile_content = f"""# Go Monorepo 全局快捷命令(3人团队统一使用) PROJECT_NAME={PROJECT_ROOT} # 全局启动所有服务(中间件+已配置业务) up: \tdocker compose up -d # 单独启动某一个服务(如:make up-svc svc=user) up-svc: \tdocker compose up -d $(svc) # 全局停止所有服务 down: \tdocker compose down # 单独停止某一个服务 down-svc: \tdocker compose stop $(svc) # 构建所有业务镜像 build: \tdocker compose build # 单独构建某一个业务镜像(发布核心命令) build-svc: \tdocker compose build $(svc) # 查看所有服务日志 logs: \tdocker compose logs -f # 查看某一个服务日志 logs-svc: \tdocker compose logs -f $(svc) # 重新启动某一个服务(代码修改后快速重启) restart-svc: \tdocker compose restart $(svc) # 清理Docker无用镜像/容器 clean: \tdocker system prune -f # 初始化Go工作区(新成员拉取代码后执行) go-init: \tgo work init \tgo work use ./common \tgo work use ./services \tgo mod tidy -C ./common # 进入某一个服务容器(如:make exec svc=user) exec: \tdocker exec -it ${PROJECT_NAME}-$(svc) /bin/sh # 查看所有服务状态 ps: \tdocker compose ps """ write_file(base_path / "Makefile", makefile_content) def main(): """主执行函数""" print(f"===== 开始生成Go Monorepo基础结构,根目录:{PROJECT_ROOT} =====") try: # 项目根路径 base_path = Path(os.getcwd()) / PROJECT_ROOT # 1. 创建核心目录 create_dirs(base_path) # 2. 生成Go工作区文件 generate_go_work(base_path) # 3. 生成公共模块common generate_common_module(base_path) # 4. 生成部署资源文件 generate_deploy_files(base_path) # 5. 生成Docker Compose generate_docker_compose(base_path) # 6. 生成全局配置(.env/Makefile) generate_global_config(base_path) # 日志目录权限处理(Ubuntu/Docker) if sys.platform != "win32": logs_path = base_path / "logs" os.chmod(logs_path, 0o777) print(f"✅ 配置日志目录权限: {logs_path}") print("="*50) print("🎉 Go Monorepo基础结构生成完成!") print("="*50) print("核心操作步骤:") print(f"1. 进入项目根目录:cd {PROJECT_ROOT}") print("2. 新成员初始化工作区:make go-init") print("3. 启动公共中间件:make up-svc svc=postgres && make up-svc svc=redis") print("4. 新增业务:在services/下创建业务目录,复制模板配置即可独立部署") print("5. 常用命令:make ps(查看状态)、make logs-svc svc=postgres(查看日志)") except Exception as e: print(f"❌ 生成失败,错误信息:{str(e)}") sys.exit(1) if __name__ == "__main__": main()