forked from topfreegames/khan
/
migrate.go
143 lines (124 loc) · 3.77 KB
/
migrate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>
package cmd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/topfreegames/extensions/gorp"
"github.com/topfreegames/goose/lib/goose"
"github.com/topfreegames/khan/db"
"github.com/topfreegames/khan/models"
)
var migrationVersion int64
func createTempDbDir() (string, error) {
dir, err := ioutil.TempDir("", "migrations")
if err != nil {
fmt.Println(err.Error())
return "", err
}
fmt.Printf("Created temporary directory %s.\n", dir)
assetNames := db.AssetNames()
for _, assetName := range assetNames {
asset, err := db.Asset(assetName)
if err != nil {
return "", err
}
fileName := strings.SplitN(assetName, "/", 2)[1] // remove migrations folder from fileName
err = ioutil.WriteFile(filepath.Join(dir, fileName), asset, 0777)
if err != nil {
return "", err
}
fmt.Printf("Wrote migration file %s.\n", fileName)
}
return dir, nil
}
func getDatabase() (*gorp.Database, error) {
viper.SetEnvPrefix("khan")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
host := viper.GetString("postgres.host")
user := viper.GetString("postgres.user")
dbName := viper.GetString("postgres.dbname")
password := viper.GetString("postgres.password")
port := viper.GetInt("postgres.port")
sslMode := viper.GetString("postgres.sslMode")
fmt.Printf(
"\nConnecting to %s:%d as %s using sslMode=%s to db %s...\n\n",
host, port, user, sslMode, dbName,
)
db, err := models.GetDB(host, user, port, sslMode, dbName, password)
return db.(*gorp.Database), err
}
func getGooseConf() *goose.DBConf {
migrationsDir, err := createTempDbDir()
if err != nil {
panic("Could not create migration files...")
}
return &goose.DBConf{
MigrationsDir: migrationsDir,
Env: "production",
Driver: goose.DBDriver{
Name: "postgres",
OpenStr: "",
Dialect: &goose.PostgresDialect{},
},
}
}
// MigrationError identified rigrations running error
type MigrationError struct {
Message string
}
func (err *MigrationError) Error() string {
return fmt.Sprintf("Could not run migrations: %s", err.Message)
}
//RunMigrations in selected DB
func RunMigrations(migrationVersion int64) error {
conf := getGooseConf()
defer os.RemoveAll(conf.MigrationsDir)
db, err := getDatabase()
if err != nil {
return &MigrationError{fmt.Sprintf("could not connect to database: %s", err.Error())}
}
targetVersion := migrationVersion
if targetVersion == -1 {
// Get the latest possible migration
latest, err := goose.GetMostRecentDBVersion(conf.MigrationsDir)
if err != nil {
return &MigrationError{fmt.Sprintf("could not get migrations at %s: %s", conf.MigrationsDir, err.Error())}
}
targetVersion = latest
}
// Migrate up to the latest version
err = goose.RunMigrationsOnDb(conf, conf.MigrationsDir, targetVersion, db.Inner().Db)
if err != nil {
return &MigrationError{fmt.Sprintf("could not run migrations to %d: %s", targetVersion, err.Error())}
}
fmt.Printf("Migrated database successfully to version %d.\n", targetVersion)
return nil
}
// migrateCmd represents the migrate command
var migrateCmd = &cobra.Command{
Use: "migrate",
Short: "migrates the database up or down",
Long: `Migrate the database specified in the configuration file to the given version (or latest if none provided)`,
Run: func(cmd *cobra.Command, args []string) {
InitConfig()
err := RunMigrations(migrationVersion)
if err != nil {
panic(err.Error())
}
},
}
func init() {
RootCmd.AddCommand(migrateCmd)
migrateCmd.Flags().Int64VarP(&migrationVersion, "target", "t", -1, "Version to run up to or down to")
}