github.com/bingtel/dbmate@v1.4.1/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net/url"
     7  	"os"
     8  
     9  	"github.com/amacneil/dbmate/pkg/dbmate"
    10  	"github.com/joho/godotenv"
    11  	"github.com/urfave/cli"
    12  )
    13  
    14  func main() {
    15  	loadDotEnv()
    16  
    17  	app := NewApp()
    18  	err := app.Run(os.Args)
    19  	if err != nil {
    20  		_, _ = fmt.Fprintf(os.Stderr, "Error: %s\n", err)
    21  		os.Exit(1)
    22  	}
    23  }
    24  
    25  // NewApp creates a new command line app
    26  func NewApp() *cli.App {
    27  	app := cli.NewApp()
    28  	app.Name = "dbmate"
    29  	app.Usage = "A lightweight, framework-independent database migration tool."
    30  	app.Version = dbmate.Version
    31  
    32  	app.Flags = []cli.Flag{
    33  		cli.StringFlag{
    34  			Name:  "env, e",
    35  			Value: "DATABASE_URL",
    36  			Usage: "specify an environment variable containing the database URL",
    37  		},
    38  		cli.StringFlag{
    39  			Name:  "migrations-dir, d",
    40  			Value: dbmate.DefaultMigrationsDir,
    41  			Usage: "specify the directory containing migration files",
    42  		},
    43  		cli.StringFlag{
    44  			Name:  "schema-file, s",
    45  			Value: dbmate.DefaultSchemaFile,
    46  			Usage: "specify the schema file location",
    47  		},
    48  		cli.BoolFlag{
    49  			Name:  "no-dump-schema",
    50  			Usage: "don't update the schema file on migrate/rollback",
    51  		},
    52  	}
    53  
    54  	app.Commands = []cli.Command{
    55  		{
    56  			Name:    "new",
    57  			Aliases: []string{"n"},
    58  			Usage:   "Generate a new migration file",
    59  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    60  				name := c.Args().First()
    61  				return db.NewMigration(name)
    62  			}),
    63  		},
    64  		{
    65  			Name:  "up",
    66  			Usage: "Create database (if necessary) and migrate to the latest version",
    67  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    68  				return db.CreateAndMigrate()
    69  			}),
    70  		},
    71  		{
    72  			Name:  "create",
    73  			Usage: "Create database",
    74  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    75  				return db.Create()
    76  			}),
    77  		},
    78  		{
    79  			Name:  "drop",
    80  			Usage: "Drop database (if it exists)",
    81  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    82  				return db.Drop()
    83  			}),
    84  		},
    85  		{
    86  			Name:  "migrate",
    87  			Usage: "Migrate to the latest version",
    88  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    89  				return db.Migrate()
    90  			}),
    91  		},
    92  		{
    93  			Name:    "rollback",
    94  			Aliases: []string{"down"},
    95  			Usage:   "Rollback the most recent migration",
    96  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
    97  				return db.Rollback()
    98  			}),
    99  		},
   100  		{
   101  			Name:  "dump",
   102  			Usage: "Write the database schema to disk",
   103  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
   104  				return db.DumpSchema()
   105  			}),
   106  		},
   107  		{
   108  			Name:  "wait",
   109  			Usage: "Wait for the database to become available",
   110  			Action: action(func(db *dbmate.DB, c *cli.Context) error {
   111  				return db.Wait()
   112  			}),
   113  		},
   114  	}
   115  
   116  	return app
   117  }
   118  
   119  // load environment variables from .env file
   120  func loadDotEnv() {
   121  	if _, err := os.Stat(".env"); err != nil {
   122  		return
   123  	}
   124  
   125  	if err := godotenv.Load(); err != nil {
   126  		log.Fatal("Error loading .env file")
   127  	}
   128  }
   129  
   130  // action wraps a cli.ActionFunc with dbmate initialization logic
   131  func action(f func(*dbmate.DB, *cli.Context) error) cli.ActionFunc {
   132  	return func(c *cli.Context) error {
   133  		u, err := getDatabaseURL(c)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		db := dbmate.New(u)
   138  		db.AutoDumpSchema = !c.GlobalBool("no-dump-schema")
   139  		db.MigrationsDir = c.GlobalString("migrations-dir")
   140  		db.SchemaFile = c.GlobalString("schema-file")
   141  
   142  		return f(db, c)
   143  	}
   144  }
   145  
   146  // getDatabaseURL returns the current environment database url
   147  func getDatabaseURL(c *cli.Context) (u *url.URL, err error) {
   148  	env := c.GlobalString("env")
   149  	value := os.Getenv(env)
   150  
   151  	return url.Parse(value)
   152  }