package main import ( "flag" "fmt" "log" "os" "path/filepath" "strings" "go.uber.org/zap" "skeleton/config" "skeleton/database" "skeleton/middlewares" ) func main() { var ( env = flag.String("env", "", "Atlas 环境,默认根据应用环境和数据库驱动推断") action = flag.String("action", "", "操作类型: status, diff, apply, validate, reset, baseline") name = flag.String("name", "", "迁移名称 (仅用于 diff 操作)") dryRun = flag.Bool("dry-run", false, "模拟执行,不实际应用迁移 (仅用于 apply 操作)") ) flag.Parse() if *action == "" { printUsage() os.Exit(1) } if err := database.EnsureAtlasInstalled(); err != nil { log.Fatal("Atlas CLI 未安装:", err) } cfg, err := config.Load() if err != nil { log.Fatal("加载配置失败:", err) } if err := middlewares.InitLogger(&cfg.Logger); err != nil { log.Fatal("初始化日志系统失败:", err) } defer middlewares.Sync() driver := normalizeDriver(cfg.Database.Driver) if driver != "postgres" && driver != "mysql" && driver != "sqlite" { middlewares.Logger.Fatal("不支持的数据库驱动", zap.String("driver", cfg.Database.Driver)) } if *env == "" { *env = atlasEnvironment(cfg.App.Environment, driver) } migrationConfig := &database.MigrationConfig{ Environment: *env, Directory: filepath.Join("migrations", driver), Timeout: 240, } manager := database.NewMigrationManager(migrationConfig, middlewares.Logger) if err := manager.InitMigrationDirectory(); err != nil { middlewares.Logger.Fatal("初始化迁移目录失败", zap.Error(err)) } switch *action { case "status": handleStatus(manager) case "diff": handleDiff(manager, *name) case "apply": handleApply(manager, *dryRun) case "validate": handleValidate(manager) case "reset": handleReset() case "baseline": handleBaseline(*env) default: fmt.Printf("未知操作: %s\n", *action) printUsage() os.Exit(1) } } func normalizeDriver(driver string) string { switch strings.ToLower(strings.TrimSpace(driver)) { case "postgresql": return "postgres" case "sqlite3": return "sqlite" default: return strings.ToLower(strings.TrimSpace(driver)) } } func atlasEnvironment(environment, driver string) string { prefix := "local" if strings.EqualFold(environment, "production") { prefix = "production" } return prefix + "_" + driver } func handleStatus(manager *database.MigrationManager) { fmt.Println("🔍 检查迁移状态...") if err := manager.CheckMigrations(); err != nil { middlewares.Logger.Fatal("检查迁移状态失败", zap.Error(err)) } fmt.Println("✅ 迁移状态检查完成") } func handleDiff(manager *database.MigrationManager, name string) { if name == "" { fmt.Println("📝 生成迁移文件...") } else { fmt.Printf("📝 生成迁移文件: %s\n", name) } if err := manager.GenerateMigration(name); err != nil { middlewares.Logger.Fatal("生成迁移失败", zap.Error(err)) } fmt.Println("✅ 迁移文件生成完成") } func handleApply(manager *database.MigrationManager, dryRun bool) { if dryRun { fmt.Println("🧪 模拟应用迁移 (dry-run)...") } else { fmt.Println("🚀 应用迁移...") } if err := manager.ApplyMigrations(dryRun); err != nil { middlewares.Logger.Fatal("应用迁移失败", zap.Error(err)) } fmt.Println("✅ 迁移应用完成") } func handleValidate(manager *database.MigrationManager) { fmt.Println("🔍 验证迁移文件...") if err := manager.ValidateMigrations(); err != nil { middlewares.Logger.Fatal("验证迁移失败", zap.Error(err)) } fmt.Println("✅ 迁移验证通过") } func handleReset() { fmt.Println("⚠️ 重置迁移历史是危险操作!") fmt.Println("请手动执行: atlas migrate reset --env [环境名]") fmt.Println("这将删除迁移历史表,请谨慎操作") } func handleBaseline(env string) { fmt.Println("📍 基线迁移指导") fmt.Println() fmt.Println("基线迁移用于将现有数据库纳入迁移管理。请根据你的情况选择合适的方法:") fmt.Println() fmt.Println("🔄 情况1 - 全新数据库:") fmt.Printf(" atlas migrate diff baseline --env %s\n", env) fmt.Printf(" go run cmd/migrate/main.go -action apply -env %s\n", env) fmt.Println() fmt.Println("🔄 情况2 - 现有数据库(推荐):") fmt.Printf(" atlas migrate diff baseline --env %s\n", env) fmt.Printf(" atlas migrate hash --env %s\n", env) fmt.Println(" # 然后应用后续新迁移") fmt.Println() fmt.Println("🔄 情况3 - 强制重建基线:") fmt.Printf(" atlas migrate reset --env %s\n", env) fmt.Printf(" go run cmd/migrate/main.go -action diff -name baseline -env %s\n", env) fmt.Printf(" go run cmd/migrate/main.go -action apply -env %s\n", env) fmt.Println() fmt.Println("⚠️ 注意事项:") fmt.Println(" - 在生产环境操作前请务必备份数据库") fmt.Println(" - 确保团队成员都从同一基线开始") fmt.Println(" - 建议先在开发环境测试迁移流程") } func printUsage() { fmt.Println("数据库迁移管理工具") fmt.Println() fmt.Println("用法:") fmt.Println(" go run cmd/migrate/main.go -action <操作> [选项]") fmt.Println() fmt.Println("操作:") fmt.Println(" status 检查迁移状态") fmt.Println(" diff 生成迁移文件 (可选: -name <迁移名称>)") fmt.Println(" apply 应用迁移 (可选: -dry-run)") fmt.Println(" validate 验证迁移文件") fmt.Println(" reset 重置迁移历史 (仅显示提示)") fmt.Println(" baseline 基线迁移指导 (显示基线创建命令)") fmt.Println() fmt.Println("选项:") fmt.Println(" -env Atlas 环境 (默认: local_ 或 production_)") fmt.Println(" -name 迁移名称 (仅用于 diff)") fmt.Println(" -dry-run 模拟执行 (仅用于 apply)") fmt.Println() fmt.Println("示例:") fmt.Println(" go run cmd/migrate/main.go -action status") fmt.Println(" go run cmd/migrate/main.go -action diff -name create_users") fmt.Println(" go run cmd/migrate/main.go -action apply") fmt.Println(" go run cmd/migrate/main.go -action apply -dry-run") fmt.Println(" go run cmd/migrate/main.go -action validate") fmt.Println(" go run cmd/migrate/main.go -action baseline") }