From 6f4c1b3a89e963d9317be019aebe2fb162d1c8bc Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Mon, 11 Aug 2014 17:23:52 +0800 Subject: [PATCH 01/10] basic workflow --- g_migration.go | 3 +- migrate.go | 172 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 162 insertions(+), 13 deletions(-) diff --git a/g_migration.go b/g_migration.go index 2c0aafb..3eccff6 100644 --- a/g_migration.go +++ b/g_migration.go @@ -64,8 +64,7 @@ func formatSourceCode(fpath string) { cmd.Run() } -const MIGRATION_TPL = ` -package main +const MIGRATION_TPL = `package main import ( "time" diff --git a/migrate.go b/migrate.go index 1e5c37a..d11924d 100644 --- a/migrate.go +++ b/migrate.go @@ -14,7 +14,13 @@ package main -import "os" +import ( + "database/sql" + "os" + "os/exec" + "path" + "strings" +) var cmdMigrate = &Command{ UsageLine: "migrate [Command]", @@ -34,6 +40,10 @@ bee migrate refresh `, } +const ( + TMP_DIR = "temp" +) + func init() { cmdMigrate.Run = runMigration } @@ -51,40 +61,180 @@ func runMigration(cmd *Command, args []string) { if len(args) == 0 { // run all outstanding migrations - ColorLog("[INFO] running all outstanding migrations\n") + ColorLog("[INFO] Running all outstanding migrations\n") migrateUpdate() } else { mcmd := args[0] switch mcmd { case "rollback": - ColorLog("[INFO] rolling back the last migration operation\n") + ColorLog("[INFO] Rolling back the last migration operation\n") migrateRollback() case "reset": - ColorLog("[INFO] reseting all migrations\n") + ColorLog("[INFO] Reseting all migrations\n") migrateReset() case "refresh": - ColorLog("[INFO] refreshing all migrations\n") + ColorLog("[INFO] Refreshing all migrations\n") migrateReset() default: - ColorLog("[ERRO] command is missing\n") + ColorLog("[ERRO] Command is missing\n") os.Exit(2) } - ColorLog("[SUCC] migration successful!\n") + ColorLog("[SUCC] Migration successful!\n") + } +} + +func checkForSchemaUpdateTable(driver string, connStr string) { + db, err := sql.Open(driver, connStr) + if err != nil { + ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr) + os.Exit(2) + } + defer db.Close() + if rows, err := db.Query("SHOW TABLES LIKE 'migrations'"); err != nil { + ColorLog("[ERRO] Could not show migrations table: %s\n", err) + os.Exit(2) + } else if !rows.Next() { + // no migrations table, create anew + ColorLog("[INFO] Creating 'migrations' table...\n") + if _, err := db.Query(MYSQL_MIGRATION_DDL); err != nil { + ColorLog("[ERRO] Could not create migrations table: %s\n", err) + os.Exit(2) + } + } + // checking that migrations table schema are expected + if rows, err := db.Query("DESC migrations"); err != nil { + ColorLog("[ERRO] Could not show columns of migrations table: %s\n", err) + os.Exit(2) + } else { + for rows.Next() { + var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte + if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil { + ColorLog("[ERRO] Could not read column information: %s\n", err) + os.Exit(2) + } + fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr := + string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes) + if fieldStr == "id_migration" { + if keyStr != "PRI" || extraStr != "auto_increment" { + ColorLog("[ERRO] Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s\n", keyStr, extraStr) + ColorLog("[HINT] Expecting KEY: PRI, EXTRA: auto_increment\n") + os.Exit(2) + } + } else if fieldStr == "file" { + if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" { + ColorLog("[ERRO] Column migration.file type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr) + ColorLog("[HINT] Expecting TYPE: varchar, NULL: YES\n") + os.Exit(2) + } + + } else if fieldStr == "created_at" { + if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" { + ColorLog("[ERRO] Column migration.file type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr) + ColorLog("[HINT] Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP\n") + os.Exit(2) + } + } + } + } +} + +func createTempMigrationDir(path string) { + if err := os.MkdirAll(path, 0777); err != nil { + ColorLog("[ERRO] Could not create path: %s\n", err) + os.Exit(2) + } +} + +func writeMigrationSourceFile(filename string, driver string, connStr string) { + if f, err := os.OpenFile(filename+".go", os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil { + ColorLog("[ERRO] Could not create file: %s\n", err) + os.Exit(2) + } else { + content := strings.Replace(MIGRATION_MAIN_TPL, "{{DBDriver}}", driver, -1) + content = strings.Replace(content, "{{ConnStr}}", connStr, -1) + content = strings.Replace(content, "{{CurrTime}}", "123", -1) + if _, err := f.WriteString(content); err != nil { + ColorLog("[ERRO] Could not write to file: %s\n", err) + os.Exit(2) + } + f.Close() + } +} + +func buildMigrationBinary(filename string) { + cmd := exec.Command("go", "build", "-o", filename, filename+".go") + if err := cmd.Run(); err != nil { + ColorLog("[ERRO] Could not build migration binary: %s\n", err) + os.Exit(2) + } +} + +func runMigrationBinary(filename string) { + cmd := exec.Command("./" + filename) + if out, err := cmd.CombinedOutput(); err != nil { + ColorLog("[ERRO] Could not run migration binary\n") + os.Exit(2) + } else { + ColorLog("[INFO] %s", string(out)) + } +} + +func cleanUpMigrationFiles(tmpPath string) { + if err := os.RemoveAll(tmpPath); err != nil { + ColorLog("[ERRO] Could not remove temporary migration directory: %s\n", err) + os.Exit(2) } } func migrateUpdate() { - println("=>update") + connStr := "root:@tcp(127.0.0.1:3306)/sgfas?charset=utf8" + checkForSchemaUpdateTable("mysql", connStr) + filename := path.Join(TMP_DIR, "super") + createTempMigrationDir(TMP_DIR) + writeMigrationSourceFile(filename, "mysql", connStr) + buildMigrationBinary(filename) + runMigrationBinary(filename) + cleanUpMigrationFiles(TMP_DIR) } func migrateRollback() { - println("=>rollback") } func migrateReset() { - println("=>reset") } func migrateRefresh() { - println("=>refresh") + migrateReset() + migrateUpdate() } + +const ( + MIGRATION_MAIN_TPL = `package main + +import( + "github.com/astaxie/beego/orm" + "github.com/astaxie/beego/migration" +) + +func init(){ + orm.RegisterDb("default", "{{DBDriver}}","{{ConnStr}}") +} + +func main(){ + migration.Upgrade({{CurrTime}}) + //migration.Rollback() + //migration.Reset() + //migration.Refresh() +} + +` + MYSQL_MIGRATION_DDL = ` +CREATE TABLE migrations ( + id_migration int(10) unsigned NOT NULL AUTO_INCREMENT, + file varchar(255) DEFAULT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + statements text, + PRIMARY KEY (id_migration) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +` +) From 870698f5a40aa6f47a5bcf82c1de2e451aa04816 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 10:33:25 +0800 Subject: [PATCH 02/10] get latest migration from database --- migrate.go | 64 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/migrate.go b/migrate.go index d11924d..77117a7 100644 --- a/migrate.go +++ b/migrate.go @@ -83,13 +83,7 @@ func runMigration(cmd *Command, args []string) { } } -func checkForSchemaUpdateTable(driver string, connStr string) { - db, err := sql.Open(driver, connStr) - if err != nil { - ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr) - os.Exit(2) - } - defer db.Close() +func checkForSchemaUpdateTable(db *sql.DB) { if rows, err := db.Query("SHOW TABLES LIKE 'migrations'"); err != nil { ColorLog("[ERRO] Could not show migrations table: %s\n", err) os.Exit(2) @@ -138,6 +132,26 @@ func checkForSchemaUpdateTable(driver string, connStr string) { } } +func getLatestMigration(db *sql.DB) (file string, createdAt string) { + sql := "SELECT file, created_at FROM migrations ORDER BY id_migration DESC LIMIT 1" + if rows, err := db.Query(sql); err != nil { + ColorLog("[ERRO] Could not retrieve migrations: %s\n", err) + os.Exit(2) + } else { + var fileBytes, createdAtBytes []byte + if rows.Next() { + if err := rows.Scan(&fileBytes, &createdAtBytes); err != nil { + ColorLog("[ERRO] Could not read migrations in database: %s\n", err) + os.Exit(2) + } + file, createdAt = string(fileBytes), string(createdAtBytes) + } else { + file, createdAt = "", "0" + } + } + return +} + func createTempMigrationDir(path string) { if err := os.MkdirAll(path, 0777); err != nil { ColorLog("[ERRO] Could not create path: %s\n", err) @@ -145,14 +159,16 @@ func createTempMigrationDir(path string) { } } -func writeMigrationSourceFile(filename string, driver string, connStr string) { +func writeMigrationSourceFile(filename string, driver string, connStr string, latestTime string, latestName string, task string) { if f, err := os.OpenFile(filename+".go", os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil { ColorLog("[ERRO] Could not create file: %s\n", err) os.Exit(2) } else { content := strings.Replace(MIGRATION_MAIN_TPL, "{{DBDriver}}", driver, -1) content = strings.Replace(content, "{{ConnStr}}", connStr, -1) - content = strings.Replace(content, "{{CurrTime}}", "123", -1) + content = strings.Replace(content, "{{LatestTime}}", latestTime, -1) + content = strings.Replace(content, "{{LatestName}}", latestName, -1) + content = strings.Replace(content, "{{Task}}", task, -1) if _, err := f.WriteString(content); err != nil { ColorLog("[ERRO] Could not write to file: %s\n", err) os.Exit(2) @@ -188,10 +204,19 @@ func cleanUpMigrationFiles(tmpPath string) { func migrateUpdate() { connStr := "root:@tcp(127.0.0.1:3306)/sgfas?charset=utf8" - checkForSchemaUpdateTable("mysql", connStr) + driver := "mysql" filename := path.Join(TMP_DIR, "super") + // connect to database + db, err := sql.Open(driver, connStr) + if err != nil { + ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr) + os.Exit(2) + } + defer db.Close() + checkForSchemaUpdateTable(db) + latestTime, latestName := getLatestMigration(db) createTempMigrationDir(TMP_DIR) - writeMigrationSourceFile(filename, "mysql", connStr) + writeMigrationSourceFile(filename, driver, connStr, latestTime, latestName, "upgrade") buildMigrationBinary(filename) runMigrationBinary(filename) cleanUpMigrationFiles(TMP_DIR) @@ -204,8 +229,6 @@ func migrateReset() { } func migrateRefresh() { - migrateReset() - migrateUpdate() } const ( @@ -221,10 +244,17 @@ func init(){ } func main(){ - migration.Upgrade({{CurrTime}}) - //migration.Rollback() - //migration.Reset() - //migration.Refresh() + task := {{Task}} + switch task { + case "upgrade": + migration.Upgrade({{LatestTime}}) + case "rollback": + migration.Rollback("{{LatestName}}") + case "reset": + migration.Reset() + case "refresh": + migration.Refresh() + } } ` From e75bd70472865aa0fa3ee086ca5bad00508c82ca Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 15:16:29 +0800 Subject: [PATCH 03/10] schema changes, code refacter, executable template --- migrate.go | 75 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/migrate.go b/migrate.go index 77117a7..739df7a 100644 --- a/migrate.go +++ b/migrate.go @@ -58,23 +58,25 @@ func runMigration(cmd *Command, args []string) { ColorLog("[HINT] Set $GOPATH in your environment vairables\n") os.Exit(2) } - + // getting command line arguments + connStr := "root:@tcp(127.0.0.1:3306)/sgfas?charset=utf8" + driver := "mysql" if len(args) == 0 { // run all outstanding migrations ColorLog("[INFO] Running all outstanding migrations\n") - migrateUpdate() + migrateUpdate(driver, connStr) } else { mcmd := args[0] switch mcmd { case "rollback": ColorLog("[INFO] Rolling back the last migration operation\n") - migrateRollback() + migrateRollback(driver, connStr) case "reset": ColorLog("[INFO] Reseting all migrations\n") - migrateReset() + migrateReset(driver, connStr) case "refresh": ColorLog("[INFO] Refreshing all migrations\n") - migrateReset() + migrateReset(driver, connStr) default: ColorLog("[ERRO] Command is missing\n") os.Exit(2) @@ -114,16 +116,16 @@ func checkForSchemaUpdateTable(db *sql.DB) { ColorLog("[HINT] Expecting KEY: PRI, EXTRA: auto_increment\n") os.Exit(2) } - } else if fieldStr == "file" { + } else if fieldStr == "name" { if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" { - ColorLog("[ERRO] Column migration.file type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr) + ColorLog("[ERRO] Column migration.name type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr) ColorLog("[HINT] Expecting TYPE: varchar, NULL: YES\n") os.Exit(2) } } else if fieldStr == "created_at" { if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" { - ColorLog("[ERRO] Column migration.file type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr) + ColorLog("[ERRO] Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr) ColorLog("[HINT] Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP\n") os.Exit(2) } @@ -133,7 +135,7 @@ func checkForSchemaUpdateTable(db *sql.DB) { } func getLatestMigration(db *sql.DB) (file string, createdAt string) { - sql := "SELECT file, created_at FROM migrations ORDER BY id_migration DESC LIMIT 1" + sql := "SELECT name, created_at FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1" if rows, err := db.Query(sql); err != nil { ColorLog("[ERRO] Could not retrieve migrations: %s\n", err) os.Exit(2) @@ -191,7 +193,7 @@ func runMigrationBinary(filename string) { ColorLog("[ERRO] Could not run migration binary\n") os.Exit(2) } else { - ColorLog("[INFO] %s", string(out)) + ColorLog("[INFO] %s\n", string(out)) } } @@ -202,10 +204,24 @@ func cleanUpMigrationFiles(tmpPath string) { } } -func migrateUpdate() { - connStr := "root:@tcp(127.0.0.1:3306)/sgfas?charset=utf8" - driver := "mysql" - filename := path.Join(TMP_DIR, "super") +func migrateUpdate(driver, connStr string) { + migrate("upgrade", driver, connStr) +} + +func migrateRollback(driver, connStr string) { + migrate("rollback", driver, connStr) +} + +func migrateReset(driver, connStr string) { + migrate("reset", driver, connStr) +} + +func migrateRefresh(driver, connStr string) { + migrate("refresh", driver, connStr) +} + +func migrate(goal, driver, connStr string) { + filename := path.Join(TMP_DIR, "migrate") // connect to database db, err := sql.Open(driver, connStr) if err != nil { @@ -214,37 +230,30 @@ func migrateUpdate() { } defer db.Close() checkForSchemaUpdateTable(db) - latestTime, latestName := getLatestMigration(db) + latestName, latestTime := getLatestMigration(db) createTempMigrationDir(TMP_DIR) - writeMigrationSourceFile(filename, driver, connStr, latestTime, latestName, "upgrade") + writeMigrationSourceFile(filename, driver, connStr, latestTime, latestName, goal) buildMigrationBinary(filename) runMigrationBinary(filename) cleanUpMigrationFiles(TMP_DIR) } -func migrateRollback() { -} - -func migrateReset() { -} - -func migrateRefresh() { -} - const ( MIGRATION_MAIN_TPL = `package main import( "github.com/astaxie/beego/orm" "github.com/astaxie/beego/migration" + + _ "github.com/go-sql-driver/mysql" ) func init(){ - orm.RegisterDb("default", "{{DBDriver}}","{{ConnStr}}") + orm.RegisterDataBase("default", "{{DBDriver}}","{{ConnStr}}") } func main(){ - task := {{Task}} + task := "{{Task}}" switch task { case "upgrade": migration.Upgrade({{LatestTime}}) @@ -260,11 +269,13 @@ func main(){ ` MYSQL_MIGRATION_DDL = ` CREATE TABLE migrations ( - id_migration int(10) unsigned NOT NULL AUTO_INCREMENT, - file varchar(255) DEFAULT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - statements text, - PRIMARY KEY (id_migration) + id_migration int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key', + name varchar(255) DEFAULT NULL COMMENT 'migration name, unique', + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back', + statements longtext COMMENT 'SQL statements for this migration', + status ENUM('update', 'rollback') COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back', + PRIMARY KEY (id_migration), + UNIQUE KEY (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ` ) From e2ce0300a64a5d6bab0be6d967a60d829861d118 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 15:18:36 +0800 Subject: [PATCH 04/10] move final message out --- migrate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrate.go b/migrate.go index 739df7a..53d9ffd 100644 --- a/migrate.go +++ b/migrate.go @@ -81,8 +81,8 @@ func runMigration(cmd *Command, args []string) { ColorLog("[ERRO] Command is missing\n") os.Exit(2) } - ColorLog("[SUCC] Migration successful!\n") } + ColorLog("[SUCC] Migration successful!\n") } func checkForSchemaUpdateTable(db *sql.DB) { From 8d82b275029da213a999c3a4781fdbd10a8ce760 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 15:45:37 +0800 Subject: [PATCH 05/10] change migration schema and getting cmd line parameters --- migrate.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/migrate.go b/migrate.go index 53d9ffd..4849b1b 100644 --- a/migrate.go +++ b/migrate.go @@ -44,13 +44,16 @@ const ( TMP_DIR = "temp" ) +var mDriver docValue +var mConn docValue + func init() { cmdMigrate.Run = runMigration + cmdMigrate.Flag.Var(&mDriver, "driver", "database driver: mysql, postgresql, etc.") + cmdMigrate.Flag.Var(&mConn, "conn", "connection string used by the driver to connect to a database instance") } func runMigration(cmd *Command, args []string) { - //curpath, _ := os.Getwd() - gopath := os.Getenv("GOPATH") Debugf("gopath:%s", gopath) if gopath == "" { @@ -59,24 +62,34 @@ func runMigration(cmd *Command, args []string) { os.Exit(2) } // getting command line arguments - connStr := "root:@tcp(127.0.0.1:3306)/sgfas?charset=utf8" - driver := "mysql" + if len(args) != 0 { + cmd.Flag.Parse(args[1:]) + } + if mDriver == "" { + mDriver = "mysql" + } + if mConn == "" { + mConn = "root:@tcp(127.0.0.1:3306)/test" + } + ColorLog("[INFO] Using '%s' as 'driver'\n", mDriver) + ColorLog("[INFO] Using '%s' as 'conn'\n", mConn) + driverStr, connStr := string(mDriver), string(mConn) if len(args) == 0 { // run all outstanding migrations ColorLog("[INFO] Running all outstanding migrations\n") - migrateUpdate(driver, connStr) + migrateUpdate(driverStr, connStr) } else { mcmd := args[0] switch mcmd { case "rollback": ColorLog("[INFO] Rolling back the last migration operation\n") - migrateRollback(driver, connStr) + migrateRollback(driverStr, connStr) case "reset": ColorLog("[INFO] Reseting all migrations\n") - migrateReset(driver, connStr) + migrateReset(driverStr, connStr) case "refresh": ColorLog("[INFO] Refreshing all migrations\n") - migrateReset(driver, connStr) + migrateReset(driverStr, connStr) default: ColorLog("[ERRO] Command is missing\n") os.Exit(2) @@ -273,6 +286,7 @@ CREATE TABLE migrations ( name varchar(255) DEFAULT NULL COMMENT 'migration name, unique', created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back', statements longtext COMMENT 'SQL statements for this migration', + rollback_statements longtext COMMENT 'SQL statment for rolling back migration', status ENUM('update', 'rollback') COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back', PRIMARY KEY (id_migration), UNIQUE KEY (name) From 4c735647c3ed39ccd843edca959fdd15c0b0d914 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 15:48:01 +0800 Subject: [PATCH 06/10] add help message --- migrate.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/migrate.go b/migrate.go index 4849b1b..b0a7ffe 100644 --- a/migrate.go +++ b/migrate.go @@ -28,15 +28,23 @@ var cmdMigrate = &Command{ Long: ` bee migrate run all outstanding migrations + -driver: [mysql | postgresql | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test bee migrate rollback rollback the last migration operation + -driver: [mysql | postgresql | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test bee migrate reset rollback all migrations + -driver: [mysql | postgresql | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test bee migrate refresh rollback all migrations and run them all again + -driver: [mysql | postgresql | sqlite], the default is mysql + -conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test `, } From 9a728714aa6e6e421cd3acdb44e1c1244da03849 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 16:04:50 +0800 Subject: [PATCH 07/10] change directory --- migrate.go | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/migrate.go b/migrate.go index b0a7ffe..67abd06 100644 --- a/migrate.go +++ b/migrate.go @@ -48,10 +48,6 @@ bee migrate refresh `, } -const ( - TMP_DIR = "temp" -) - var mDriver docValue var mConn docValue @@ -218,9 +214,9 @@ func runMigrationBinary(filename string) { } } -func cleanUpMigrationFiles(tmpPath string) { - if err := os.RemoveAll(tmpPath); err != nil { - ColorLog("[ERRO] Could not remove temporary migration directory: %s\n", err) +func removeMigrationBinary(path string) { + if err := os.Remove(path); err != nil { + ColorLog("[ERRO] Could not remove migration binary: %s\n", err) os.Exit(2) } } @@ -242,7 +238,7 @@ func migrateRefresh(driver, connStr string) { } func migrate(goal, driver, connStr string) { - filename := path.Join(TMP_DIR, "migrate") + filepath := path.Join("database", "migrations", "migrate") // connect to database db, err := sql.Open(driver, connStr) if err != nil { @@ -252,11 +248,10 @@ func migrate(goal, driver, connStr string) { defer db.Close() checkForSchemaUpdateTable(db) latestName, latestTime := getLatestMigration(db) - createTempMigrationDir(TMP_DIR) - writeMigrationSourceFile(filename, driver, connStr, latestTime, latestName, goal) - buildMigrationBinary(filename) - runMigrationBinary(filename) - cleanUpMigrationFiles(TMP_DIR) + writeMigrationSourceFile(filepath, driver, connStr, latestTime, latestName, goal) + buildMigrationBinary(filepath) + runMigrationBinary(filepath) + removeMigrationBinary(filepath) } const ( From 5b22b195cb98176b31ec85600a85ac78435593eb Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 16:06:04 +0800 Subject: [PATCH 08/10] update migration template --- g_migration.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/g_migration.go b/g_migration.go index 3eccff6..26c4f19 100644 --- a/g_migration.go +++ b/g_migration.go @@ -67,8 +67,6 @@ func formatSourceCode(fpath string) { const MIGRATION_TPL = `package main import ( - "time" - "github.com/astaxie/beego/migration" ) From 6f3d2d31efbeeb6c016576130a2c35635bf6da07 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 16:20:11 +0800 Subject: [PATCH 09/10] minor change --- migrate.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migrate.go b/migrate.go index 67abd06..fef2474 100644 --- a/migrate.go +++ b/migrate.go @@ -198,9 +198,11 @@ func writeMigrationSourceFile(filename string, driver string, connStr string, la func buildMigrationBinary(filename string) { cmd := exec.Command("go", "build", "-o", filename, filename+".go") - if err := cmd.Run(); err != nil { + if out, err := cmd.CombinedOutput(); err != nil { ColorLog("[ERRO] Could not build migration binary: %s\n", err) os.Exit(2) + } else { + ColorLog("[INFO] %s\n", string(out)) } } From 5900befa43ca35c7225b3bf0e3131e46a70d282d Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 12 Aug 2014 18:26:34 +0800 Subject: [PATCH 10/10] getting output from shell --- migrate.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/migrate.go b/migrate.go index fef2474..3b83ced 100644 --- a/migrate.go +++ b/migrate.go @@ -197,12 +197,12 @@ func writeMigrationSourceFile(filename string, driver string, connStr string, la } func buildMigrationBinary(filename string) { - cmd := exec.Command("go", "build", "-o", filename, filename+".go") + os.Chdir(path.Join("database", "migrations")) + cmd := exec.Command("go", "build", "-o", filename) if out, err := cmd.CombinedOutput(); err != nil { ColorLog("[ERRO] Could not build migration binary: %s\n", err) + formatShellErrOutput(string(out)) os.Exit(2) - } else { - ColorLog("[INFO] %s\n", string(out)) } } @@ -212,7 +212,7 @@ func runMigrationBinary(filename string) { ColorLog("[ERRO] Could not run migration binary\n") os.Exit(2) } else { - ColorLog("[INFO] %s\n", string(out)) + formatShellOutput(string(out)) } } @@ -256,6 +256,22 @@ func migrate(goal, driver, connStr string) { removeMigrationBinary(filepath) } +func formatShellErrOutput(o string) { + for _, line := range strings.Split(o, "\n") { + if line != "" { + ColorLog("[ERRO] -| %s\n", line) + } + } +} + +func formatShellOutput(o string) { + for _, line := range strings.Split(o, "\n") { + if line != "" { + ColorLog("[INFO] -| %s\n", line) + } + } +} + const ( MIGRATION_MAIN_TPL = `package main