Files
2026-09-11 01:41:52 +08:00

119 lines
3.1 KiB
Go

// Command migrate 是独立的数据库结构迁移入口:手动执行,服务启动不会触发迁移。
//
// 用法:
//
// go run ./cmd/migrate up # 执行到最新版本
// go run ./cmd/migrate down # 全量回滚
// go run ./cmd/migrate steps 2 # 向上 2 步(负数向下)
// go run ./cmd/migrate version # 查看当前版本与脏库状态
// go run ./cmd/migrate force 3 # 修复脏库:强制设置版本号
package main
import (
"fmt"
"os"
"strconv"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/migration"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/setting"
)
const usage = `用法:
go run ./cmd/migrate up 执行到最新版本
go run ./cmd/migrate down 全量回滚所有迁移
go run ./cmd/migrate steps N 向上 N 步(N 为负数时向下)
go run ./cmd/migrate version 查看当前版本与脏库状态
go run ./cmd/migrate force V 强制设置版本号并清除脏标记`
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "migrate failed: %v\n", err)
os.Exit(1)
}
}
func run(args []string) error {
if len(args) == 0 {
fmt.Println(usage)
return nil
}
// 仅读取 Mysql 配置段,不复用 main.go 的 setupSetting(后者会强制校验 JWT 等无关配置)。
mysqlSetting, err := loadMysqlSetting()
if err != nil {
return err
}
switch args[0] {
case "up":
if err := migration.Up(mysqlSetting); err != nil {
return err
}
fmt.Println("migrate up: done")
return nil
case "down":
if err := migration.Down(mysqlSetting); err != nil {
return err
}
fmt.Println("migrate down: done")
return nil
case "steps":
if len(args) < 2 {
return fmt.Errorf("steps 缺少步数参数\n%s", usage)
}
n, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("steps 参数必须为整数: %w", err)
}
if err := migration.Steps(mysqlSetting, n); err != nil {
return err
}
fmt.Printf("migrate steps %d: done\n", n)
return nil
case "version":
version, dirty, err := migration.Version(mysqlSetting)
if err != nil {
return err
}
fmt.Printf("version: %d, dirty: %t\n", version, dirty)
return nil
case "force":
if len(args) < 2 {
return fmt.Errorf("force 缺少版本号参数\n%s", usage)
}
v, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("force 参数必须为整数: %w", err)
}
if err := migration.Force(mysqlSetting, v); err != nil {
return err
}
fmt.Printf("migrate force %d: done\n", v)
return nil
default:
return fmt.Errorf("unknown command: %s\n%s", args[0], usage)
}
}
// loadMysqlSetting 读取 configs/config.yaml 的 Mysql 配置段。
func loadMysqlSetting() (*setting.MysqlSettingS, error) {
s, err := setting.NewSetting()
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
var mysqlSetting setting.MysqlSettingS
if err := s.ReadSection("Mysql", &mysqlSetting); err != nil {
return nil, fmt.Errorf("read Mysql section: %w", err)
}
if mysqlSetting.DBName == "" {
return nil, fmt.Errorf("Mysql.DBName is empty in configs/config.yaml")
}
return &mysqlSetting, nil
}