119 lines
3.1 KiB
Go
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
|
|
}
|