2017-05-04 20:58:23 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"net/url"
|
|
|
|
|
"os"
|
|
|
|
|
|
2018-01-07 20:12:56 -08:00
|
|
|
"github.com/amacneil/dbmate/pkg/dbmate"
|
2017-05-04 20:58:23 -07:00
|
|
|
"github.com/joho/godotenv"
|
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
loadDotEnv()
|
|
|
|
|
|
|
|
|
|
app := NewApp()
|
|
|
|
|
err := app.Run(os.Args)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewApp creates a new command line app
|
|
|
|
|
func NewApp() *cli.App {
|
|
|
|
|
app := cli.NewApp()
|
|
|
|
|
app.Name = "dbmate"
|
|
|
|
|
app.Usage = "A lightweight, framework-independent database migration tool."
|
|
|
|
|
app.Version = dbmate.Version
|
|
|
|
|
|
|
|
|
|
app.Flags = []cli.Flag{
|
2018-01-22 20:38:40 -08:00
|
|
|
cli.StringFlag{
|
|
|
|
|
Name: "env, e",
|
|
|
|
|
Value: "DATABASE_URL",
|
|
|
|
|
Usage: "specify an environment variable containing the database URL",
|
|
|
|
|
},
|
2017-05-04 20:58:23 -07:00
|
|
|
cli.StringFlag{
|
|
|
|
|
Name: "migrations-dir, d",
|
|
|
|
|
Value: dbmate.DefaultMigrationsDir,
|
|
|
|
|
Usage: "specify the directory containing migration files",
|
|
|
|
|
},
|
|
|
|
|
cli.StringFlag{
|
2018-01-22 20:38:40 -08:00
|
|
|
Name: "schema-file, s",
|
|
|
|
|
Value: dbmate.DefaultSchemaFile,
|
|
|
|
|
Usage: "specify the schema file location",
|
|
|
|
|
},
|
|
|
|
|
cli.BoolFlag{
|
|
|
|
|
Name: "no-dump-schema",
|
|
|
|
|
Usage: "don't update the schema file on migrate/rollback",
|
2017-05-04 20:58:23 -07:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app.Commands = []cli.Command{
|
|
|
|
|
{
|
|
|
|
|
Name: "new",
|
|
|
|
|
Aliases: []string{"n"},
|
|
|
|
|
Usage: "Generate a new migration file",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
name := c.Args().First()
|
2018-01-22 20:38:40 -08:00
|
|
|
return db.NewMigration(name)
|
2017-05-04 20:58:23 -07:00
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "up",
|
|
|
|
|
Usage: "Create database (if necessary) and migrate to the latest version",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
2018-01-22 20:38:40 -08:00
|
|
|
return db.CreateAndMigrate()
|
2017-05-04 20:58:23 -07:00
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "create",
|
|
|
|
|
Usage: "Create database",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.Create()
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "drop",
|
|
|
|
|
Usage: "Drop database (if it exists)",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.Drop()
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "migrate",
|
|
|
|
|
Usage: "Migrate to the latest version",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.Migrate()
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "rollback",
|
|
|
|
|
Aliases: []string{"down"},
|
|
|
|
|
Usage: "Rollback the most recent migration",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.Rollback()
|
|
|
|
|
}),
|
|
|
|
|
},
|
2018-01-22 20:38:40 -08:00
|
|
|
{
|
|
|
|
|
Name: "dump",
|
|
|
|
|
Usage: "Write the database schema to disk",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.DumpSchema()
|
|
|
|
|
}),
|
|
|
|
|
},
|
2018-04-15 18:37:57 -07:00
|
|
|
{
|
|
|
|
|
Name: "wait",
|
|
|
|
|
Usage: "Wait for the database to become available",
|
|
|
|
|
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
|
|
|
|
return db.Wait()
|
|
|
|
|
}),
|
|
|
|
|
},
|
2017-05-04 20:58:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return app
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load environment variables from .env file
|
|
|
|
|
func loadDotEnv() {
|
|
|
|
|
if _, err := os.Stat(".env"); err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := godotenv.Load(); err != nil {
|
|
|
|
|
log.Fatal("Error loading .env file")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// action wraps a cli.ActionFunc with dbmate initialization logic
|
|
|
|
|
func action(f func(*dbmate.DB, *cli.Context) error) cli.ActionFunc {
|
|
|
|
|
return func(c *cli.Context) error {
|
|
|
|
|
u, err := getDatabaseURL(c)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-01-22 20:38:40 -08:00
|
|
|
db := dbmate.New(u)
|
|
|
|
|
db.AutoDumpSchema = !c.GlobalBool("no-dump-schema")
|
2017-05-04 20:58:23 -07:00
|
|
|
db.MigrationsDir = c.GlobalString("migrations-dir")
|
2018-01-22 20:38:40 -08:00
|
|
|
db.SchemaFile = c.GlobalString("schema-file")
|
2017-05-04 20:58:23 -07:00
|
|
|
|
|
|
|
|
return f(db, c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getDatabaseURL returns the current environment database url
|
|
|
|
|
func getDatabaseURL(c *cli.Context) (u *url.URL, err error) {
|
|
|
|
|
env := c.GlobalString("env")
|
|
|
|
|
value := os.Getenv(env)
|
|
|
|
|
|
|
|
|
|
return url.Parse(value)
|
|
|
|
|
}
|