diff --git a/cmd_create.go b/cmd_create.go index 56335b1..a3cbcd1 100644 --- a/cmd_create.go +++ b/cmd_create.go @@ -64,20 +64,19 @@ func init() { } var goMigrationScaffoldTmpl = template.Must(template.New("driver").Parse(` -package migration_{{ . }} +package main import ( "database/sql" - "fmt" ) // Up is executed when this migration is applied -func Up(txn *sql.Tx) { +func Up_{{ . }}(txn *sql.Tx) { } // Down is executed when this migration is rolled back -func Down(txn *sql.Tx) { +func Down_{{ . }}(txn *sql.Tx) { } `)) diff --git a/db-sample/migrations/003_and_again.go b/db-sample/migrations/003_and_again.go deleted file mode 100644 index 776ae5d..0000000 --- a/db-sample/migrations/003_and_again.go +++ /dev/null @@ -1,15 +0,0 @@ - -package migration_003 - -import ( - "database/sql" - "fmt" -) - -func Up(txn *sql.Tx) { - fmt.Println("Hello from migration_003 Up!") -} - -func Down(txn *sql.Tx) { - fmt.Println("Hello from migration_003 Down!") -} diff --git a/db-sample/migrations/20130106222315_and_again.go b/db-sample/migrations/20130106222315_and_again.go new file mode 100644 index 0000000..1aac8ba --- /dev/null +++ b/db-sample/migrations/20130106222315_and_again.go @@ -0,0 +1,15 @@ + +package main + +import ( + "database/sql" + "fmt" +) + +func Up_20130106222315(txn *sql.Tx) { + fmt.Println("Hello from migration 20130106222315 Up!") +} + +func Down_20130106222315(txn *sql.Tx) { + fmt.Println("Hello from migration 20130106222315 Down!") +} diff --git a/migration_go.go b/migration_go.go index fef6127..5d33729 100644 --- a/migration_go.go +++ b/migration_go.go @@ -1,37 +1,21 @@ package main import ( - "bufio" "fmt" - "io" "io/ioutil" "log" "os" "os/exec" "path/filepath" - "strings" "text/template" ) -const ( - UpDecl = "func Up(txn *sql.Tx) {" - UpDeclFmt = "func migration_%d_Up(txn *sql.Tx) {\n" - DownDecl = "func Down(txn *sql.Tx) {" - DownDeclFmt = "func migration_%d_Down(txn *sql.Tx) {\n" -) - type TemplateData struct { Version int64 DBDriver string DBOpen string - Direction string -} - -func directionStr(direction bool) string { - if direction { - return "Up" - } - return "Down" + Direction bool + Func string } // @@ -50,11 +34,17 @@ func runGoMigration(conf *DBConf, path string, version int64, direction bool) er } defer os.RemoveAll(d) + directionStr := "Down" + if direction { + directionStr = "Up" + } + td := &TemplateData{ Version: version, DBDriver: conf.Driver, DBOpen: conf.OpenStr, - Direction: directionStr(direction), + Direction: direction, + Func: fmt.Sprintf("%v_%v", directionStr, version), } main, e := writeTemplateToFile(filepath.Join(d, "goose_main.go"), goMigrationTmpl, td) if e != nil { @@ -62,7 +52,7 @@ func runGoMigration(conf *DBConf, path string, version int64, direction bool) er } outpath := filepath.Join(d, filepath.Base(path)) - if e = writeSubstituted(path, outpath, version); e != nil { + if _, e = copyFile(outpath, path); e != nil { log.Fatal(e) } @@ -76,82 +66,6 @@ func runGoMigration(conf *DBConf, path string, version int64, direction bool) er return nil } -// -// a little cheesy, but do a simple text substitution on the contents of the -// migration script. this has 2 motivations: -// * rewrite the package to 'main' so that we can run as part of `go run` -// * namespace the Up() and Down() funcs so we can compile several -// .go migrations into the same binary for execution -// -func writeSubstituted(inpath, outpath string, version int64) error { - - fin, e := os.Open(inpath) - if e != nil { - return e - } - defer fin.Close() - - fout, e := os.OpenFile(outpath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) - if e != nil { - return e - } - defer fout.Close() - - rw := bufio.NewReadWriter(bufio.NewReader(fin), bufio.NewWriter(fout)) - - for { - // XXX: could optimize the case in which we've already found - // everything we're looking for, and just copy the rest in bulk - - line, _, e := rw.ReadLine() - // XXX: handle isPrefix from ReadLine() - - if e != nil { - if e != io.EOF { - log.Fatal("failed to read from migration script:", e) - } - - rw.Flush() - break - } - - lineStr := string(line) - - if strings.HasPrefix(lineStr, "package migration_") { - if _, e := rw.WriteString("package main\n"); e != nil { - return e - } - continue - } - - if lineStr == UpDecl { - up := fmt.Sprintf(UpDeclFmt, version) - if _, e := rw.WriteString(up); e != nil { - return e - } - continue - } - - if lineStr == DownDecl { - down := fmt.Sprintf(DownDeclFmt, version) - if _, e := rw.WriteString(down); e != nil { - return e - } - continue - } - - // default case - if _, e := rw.Write(line); e != nil { - return e - } - if _, e := rw.WriteRune('\n'); e != nil { - return e - } - } - - return nil -} - // // template for the main entry point to a go-based migration. // this gets linked against the substituted versions of the user-supplied @@ -179,11 +93,11 @@ func main() { log.Fatal("db.Begin:", err) } - migration_{{ .Version }}_{{ .Direction }}(txn) + {{ .Func }}(txn) // XXX: drop goose_db_version table on some minimum version number? - isApplied := "{{ .Direction }}" == "Up" - versionStmt := fmt.Sprintf("INSERT INTO goose_db_version (version_id, is_applied) VALUES (%d, %t);", {{ .Version }}, isApplied) + versionFmt := "INSERT INTO goose_db_version (version_id, is_applied) VALUES (%v, %t);" + versionStmt := fmt.Sprintf(versionFmt, int64({{ .Version }}), {{ .Direction }}) if _, err = txn.Exec(versionStmt); err != nil { txn.Rollback() log.Fatal("failed to write version: ", err) diff --git a/util.go b/util.go index 591eb64..4bb74af 100644 --- a/util.go +++ b/util.go @@ -1,6 +1,7 @@ package main import ( + "io" "os" "text/template" ) @@ -21,3 +22,19 @@ func writeTemplateToFile(path string, t *template.Template, data interface{}) (s return f.Name(), nil } + +func copyFile(dst, src string) (int64, error) { + sf, err := os.Open(src) + if err != nil { + return 0, err + } + defer sf.Close() + + df, err := os.Create(dst) + if err != nil { + return 0, err + } + defer df.Close() + + return io.Copy(df, sf) +}