forked from Gitlink/gitea_hat
139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package migrations
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
|
|
"xorm.io/xorm"
|
|
"xorm.io/xorm/names"
|
|
)
|
|
|
|
const minHatDBVersion = 0
|
|
|
|
type Migration interface {
|
|
Description() string
|
|
Migrate(*xorm.Engine) error
|
|
}
|
|
|
|
type migration struct {
|
|
description string
|
|
migrate func(*xorm.Engine) error
|
|
}
|
|
|
|
func NewMigration(desc string, fn func(*xorm.Engine) error) Migration {
|
|
return &migration{desc, fn}
|
|
}
|
|
|
|
func (m *migration) Description() string {
|
|
return m.description
|
|
}
|
|
|
|
func (m *migration) Migrate(x *xorm.Engine) error {
|
|
return m.migrate(x)
|
|
}
|
|
|
|
type HatVersion struct {
|
|
ID int64 `xorm:"pk autoincr"`
|
|
HatVersion int64
|
|
}
|
|
|
|
var migrations = []Migration{}
|
|
|
|
func GetCurrentHatDBVersion(x *xorm.Engine) (int64, error) {
|
|
if err := x.Sync(new(HatVersion)); err != nil {
|
|
return -1, fmt.Errorf("sync: %v", err)
|
|
}
|
|
|
|
currentVersion := &HatVersion{ID: 1}
|
|
has, err := x.Get(currentVersion)
|
|
if err != nil {
|
|
return -1, fmt.Errorf("get: %v", err)
|
|
}
|
|
if !has {
|
|
return -1, nil
|
|
}
|
|
|
|
return currentVersion.HatVersion, nil
|
|
}
|
|
|
|
func ExpectedHatVersion() int64 {
|
|
return int64(minHatDBVersion + len(migrations))
|
|
}
|
|
|
|
func EnsureUpToDate(x *xorm.Engine) error {
|
|
currentDB, err := GetCurrentHatDBVersion(x)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if currentDB < 0 {
|
|
return fmt.Errorf("Database has not been initialized")
|
|
}
|
|
|
|
if minHatDBVersion > currentDB {
|
|
return fmt.Errorf("DB version %d (<= %d) is too old for auto-migration. ", currentDB, minHatDBVersion)
|
|
}
|
|
|
|
expected := ExpectedHatVersion()
|
|
|
|
if currentDB != expected {
|
|
return fmt.Errorf(`Current database version %d is not equal to the expected version %d.`, currentDB, expected)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func Migrate(x *xorm.Engine) error {
|
|
x.SetMapper(names.GonicMapper{})
|
|
if err := x.Sync(new(HatVersion)); err != nil {
|
|
return fmt.Errorf("sync: %v", err)
|
|
}
|
|
|
|
currentVersion := &HatVersion{ID: 1}
|
|
has, err := x.Get(currentVersion)
|
|
if err != nil {
|
|
return fmt.Errorf("get: %v", err)
|
|
} else if !has {
|
|
currentVersion.ID = 0
|
|
currentVersion.HatVersion = int64(minHatDBVersion)
|
|
|
|
if _, err = x.InsertOne(currentVersion); err != nil {
|
|
return fmt.Errorf("insert: %v", err)
|
|
}
|
|
}
|
|
|
|
v := currentVersion.HatVersion
|
|
if minHatDBVersion > v {
|
|
log.Fatal(`Gitea no longer supports auto-migration from your previously installed version.
|
|
Please try upgrading to a lower version first (suggested v1.6.4), then upgrade to this version.`)
|
|
return nil
|
|
}
|
|
if int(v-minHatDBVersion) > len(migrations) {
|
|
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", v, minHatDBVersion+len(migrations))
|
|
msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)."
|
|
if !setting.IsProd {
|
|
msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minHatDBVersion+len(migrations))
|
|
}
|
|
_, _ = fmt.Fprintln(os.Stderr, msg)
|
|
log.Fatal(msg)
|
|
return nil
|
|
}
|
|
|
|
for i, m := range migrations[v-minHatDBVersion:] {
|
|
log.Info("Migration[%d]: %s", v+int64(i), m.Description())
|
|
x.SetMapper(names.GonicMapper{})
|
|
if err = m.Migrate(x); err != nil {
|
|
return fmt.Errorf("migration[%d]: %s failed: %v", v+int64(i), m.Description(), err)
|
|
}
|
|
currentVersion.HatVersion = v + int64(i) + 1
|
|
if _, err = x.ID(1).Update(currentVersion); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|