From 91068293368b515c6356a7ba83b7310f568e2e66 Mon Sep 17 00:00:00 2001 From: vipg Date: Fri, 6 Feb 2026 15:34:47 +0800 Subject: [PATCH] add --- init_monorepo.py | 304 +++++++++++++++++++++++++++++++++++++++++++++++ init_monorepo.sh | 118 ++++++++++++++++++ 2 files changed, 422 insertions(+) create mode 100644 init_monorepo.py create mode 100644 init_monorepo.sh diff --git a/init_monorepo.py b/init_monorepo.py new file mode 100644 index 0000000..f57e266 --- /dev/null +++ b/init_monorepo.py @@ -0,0 +1,304 @@ +#!/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() \ No newline at end of file diff --git a/init_monorepo.sh b/init_monorepo.sh new file mode 100644 index 0000000..52da195 --- /dev/null +++ b/init_monorepo.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -euo pipefail +# 脚本编码设置,避免中文乱码 +export LANG=C.UTF-8 + +# 配置项(可按需修改) +PROJECT_NAME="go-monorepo" +PYTHON_IMAGE="python:3.11-alpine" # 轻量Python3镜像,仅80+MB +PYTHON_SCRIPT="init-monorepo.py" + +# 颜色输出函数(增强可读性) +red() { echo -e "\033[31m$1\033[0m"; } +green() { echo -e "\033[32m$1\033[0m"; } +yellow() { echo -e "\033[33m$1\033[0m"; } +blue() { echo -e "\033[34m$1\033[0m"; } + +# 第一步:检查Docker环境是否安装 +check_docker() { + blue "===== 1. 检测Docker环境 =====" + if ! command -v docker &> /dev/null; then + red "❌ 错误:本地未安装Docker,请先安装Docker后再执行!" + red "Docker官方安装地址:https://docs.docker.com/get-docker/" + exit 1 + fi + + # 检查Docker守护进程是否运行 + if ! docker info &> /dev/null; then + red "❌ 错误:Docker守护进程未启动,请先启动Docker服务!" + exit 1 + fi + green "✅ Docker环境检测通过(版本:$(docker --version | awk '{print $3}' | sed 's/,//g'))" +} + +# 第二步:检查Python脚本是否存在 +check_script() { + blue -e "\n===== 2. 检测${PYTHON_SCRIPT}脚本 =====" + if [ ! -f "${PYTHON_SCRIPT}" ]; then + red "❌ 错误:当前目录未找到${PYTHON_SCRIPT}文件!" + red "请确保${PYTHON_SCRIPT}与本sh脚本在同一目录下!" + exit 1 + fi + green "✅ ${PYTHON_SCRIPT}脚本检测通过" +} + +# 第三步:拉取Python镜像(若本地无) +pull_python_image() { + blue -e "\n===== 3. 检查Python3镜像 =====" + if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^${PYTHON_IMAGE}$"; then + green "✅ 本地已存在${PYTHON_IMAGE}镜像,无需拉取" + else + yellow "⚠️ 本地无${PYTHON_IMAGE}镜像,开始拉取(轻量镜像,仅80+MB,耗时约10s)" + docker pull "${PYTHON_IMAGE}" + green "✅ ${PYTHON_IMAGE}镜像拉取完成" + fi +} + +# 第四步:创建临时Python容器执行初始化脚本 +run_python_container() { + blue -e "\n===== 4. 启动临时Python容器,执行初始化 =====" + yellow "⚠️ 正在生成${PROJECT_NAME}基础结构,文件将保存在当前目录..." + # 核心docker run命令: + # --rm:执行完成后自动销毁容器 + # -v $(pwd):/app:将本地当前目录挂载到容器内/app目录 + # -w /app:设置容器工作目录为/app(与本地挂载目录一致) + # ${PYTHON_IMAGE}:使用的Python镜像 + # python3 ${PYTHON_SCRIPT}:在容器内执行Python脚本 + docker run --rm \ + -v "$(pwd)":/app \ + -w /app \ + --name "tmp-go-monorepo-init" \ + "${PYTHON_IMAGE}" \ + python3 "${PYTHON_SCRIPT}" + + # 检查脚本执行结果 + if [ -d "${PROJECT_NAME}" ]; then + green -e "\n✅ 容器执行完成!${PROJECT_NAME}基础结构已生成在当前目录" + else + red "❌ 容器执行失败,未生成${PROJECT_NAME}目录,请检查日志!" + exit 1 + fi +} + +# 第五步:权限修复(解决容器生成文件的权限问题) +fix_permission() { + blue -e "\n===== 5. 修复文件目录权限 =====" + # 容器内生成的文件可能属于root用户,修复为当前用户权限 + if [ -d "${PROJECT_NAME}" ] && [ "$(id -u)" -ne 0 ]; then + sudo chown -R "$(id -u)":"$(id -g)" "${PROJECT_NAME}" 2>/dev/null || true + chmod +x "${PROJECT_NAME}/Makefile" 2>/dev/null || true + green "✅ 目录权限修复完成,当前用户可正常操作${PROJECT_NAME}内文件" + else + yellow "⚠️ 无需修复权限(当前为root用户或目录不存在)" + fi +} + +# 主执行流程 +main() { + clear + blue "=====================================================" + blue " Go Monorepo 容器化初始化脚本" + blue " 无本地Python环境依赖 · 仅需Docker" + blue "=====================================================" + echo "" + + check_docker + check_script + pull_python_image + run_python_container + fix_permission + + echo "" + green "🎉 所有操作完成!" + green "👉 下一步操作:cd ${PROJECT_NAME} && make go-init" + echo "" +} + +# 执行主函数 +main \ No newline at end of file