Files
go-common/templates/migrate/main.go

158 lines
3.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"flag"
"fmt"
"os"
"git.toowon.com/jimmy/go-common/factory"
"git.toowon.com/jimmy/go-common/migration"
)
// 数据库迁移 CLI 脚手架。
//
// mkdir -p cmd/migrate
// cp templates/migrate/main.go cmd/migrate/main.go
// go build -o bin/migrate cmd/migrate/main.go
// ./bin/migrate up|status|down
//
// 默认已接好Factory 初始化、日志、Database Warmup、Migrator、Close 收口。
// 配置优先级:-config/-dir > 环境变量 CONFIG_FILE/MIGRATIONS_DIR > 默认值。
func main() {
var (
configFile string
migrationsDir string
showHelp bool
)
flag.StringVar(&configFile, "config", "", "配置文件路径(默认 config.json")
flag.StringVar(&configFile, "c", "", "配置文件路径(简写)")
flag.StringVar(&migrationsDir, "dir", "", "迁移目录(默认 migrations")
flag.StringVar(&migrationsDir, "d", "", "迁移目录(简写)")
flag.BoolVar(&showHelp, "help", false, "显示帮助")
flag.BoolVar(&showHelp, "h", false, "显示帮助(简写)")
flag.Parse()
if showHelp {
printHelp()
return
}
command := "up"
if args := flag.Args(); len(args) > 0 {
command = args[0]
}
if command != "up" && command != "down" && command != "status" {
fmt.Fprintf(os.Stderr, "未知命令: %s\n\n", command)
printHelp()
os.Exit(1)
}
if configFile == "" {
configFile = envOr("CONFIG_FILE", "config.json")
}
if migrationsDir == "" {
migrationsDir = envOr("MIGRATIONS_DIR", "migrations")
}
app := factory.MustInit(configFile, buildOptions()...)
defer app.Close()
log := app.MustLogger()
if err := app.Warmup(factory.ModuleLogger, factory.ModuleDatabase); err != nil {
log.Error("warmup failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
m, err := app.Migrator(migrationsDir)
if err != nil {
log.Error("create migrator failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
switch command {
case "up":
if err := m.Up(); err != nil {
log.Error("migrate up failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
log.Info("migrate up ok", map[string]any{"dir": migrationsDir})
fmt.Println("✓ 迁移执行成功")
case "down":
if err := m.Down(); err != nil {
log.Error("migrate down failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
log.Info("migrate down ok", map[string]any{"dir": migrationsDir})
fmt.Println("✓ 迁移回滚成功")
case "status":
status, err := m.Status()
if err != nil {
log.Error("migrate status failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
printStatus(status)
}
}
// buildOptions 组装 Factory Option自定义 DB / Logger 等在此注入)
func buildOptions() []factory.Option {
// 默认走 config.json。需要替换时例如
//
// return []factory.Option{
// factory.WithLogger(customLogger),
// factory.WithDatabase(db),
// }
return nil
}
func printStatus(status []migration.MigrationStatus) {
if len(status) == 0 {
fmt.Println("没有找到迁移")
return
}
fmt.Println("\n迁移状态:")
fmt.Printf("%-20s %-40s %-10s\n", "版本", "描述", "状态")
for _, s := range status {
st := "待执行"
if s.Applied {
st = "已应用"
}
fmt.Printf("%-20s %-40s %-10s\n", s.Version, s.Description, st)
}
fmt.Println()
}
func envOr(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func printHelp() {
fmt.Println(`数据库迁移工具
用法:
migrate [命令] [选项]
命令:
up 执行待执行迁移(默认)
down 回滚最后一个迁移
status 查看状态
选项:
-config, -c 配置文件(默认: config.json可用 CONFIG_FILE
-dir, -d 迁移目录(默认: migrations可用 MIGRATIONS_DIR
-help, -h 帮助
示例:
migrate up
migrate up -config /etc/app/config.json -dir db/migrations
CONFIG_FILE=config.json migrate status`)
}