1+ package main
2+
3+ import (
4+ "bufio"
5+ "flag"
6+ "fmt"
7+ "github.com/LineoIT/go-migrate"
8+ "log"
9+ "os"
10+ _ "github.com/lib/pq"
11+ "strings"
12+ )
13+
14+ const HELP = `
15+ Usage:
16+ console <cli> [arguments]
17+ The commands are:
18+ help Help
19+ up Migration database
20+ --dsn <string> Database source url
21+ --dir <string> Migration files folder
22+ --production <string> Specify production environment, default true
23+ down Migration rollback database
24+ --dsn <string> Database source url
25+ --dir <string> Migration files folder
26+ --production <string> Specify production environment, default true
27+ create CreateFile user
28+ --name <string> file name
29+ --dir <string> Migration files folder
30+ `
31+ const (
32+ ACTION_HELP = "help"
33+ ACTION_UP = "up"
34+ ACTION_DOWN = "down"
35+ ACTION_CREATE = "create"
36+ )
37+
38+ func main () {
39+
40+ if len (os .Args ) < 2 {
41+ fmt .Print (HELP )
42+ os .Exit (0 )
43+ }
44+
45+ switch os .Args [1 ] {
46+ case ACTION_HELP :
47+ fmt .Print (HELP )
48+ case ACTION_UP :
49+ migrateDatabaseCmd (ACTION_UP )
50+ case ACTION_DOWN :
51+ migrateDatabaseCmd (ACTION_DOWN )
52+ case ACTION_CREATE :
53+ createMigrationCmd ()
54+ default :
55+ fmt .Println ("Command not found" )
56+ fmt .Print (HELP )
57+ }
58+ }
59+
60+ func migrateDatabaseCmd (action string ){
61+ cmd := flag .NewFlagSet (action , flag .ExitOnError )
62+ dsn := cmd .String ("dsn" , "" , "database url" )
63+ dir := cmd .String ("dir" , "" , "migration files folder" )
64+ isProd := cmd .Bool ("production" , true , "Production environment" )
65+ msg := "Do you sure to migrate database in production mode?"
66+ if action == ACTION_DOWN {
67+ msg = "Do you really want to delete all tables in production mode?"
68+ }
69+ if confirm (msg , * isProd ) {
70+ if err := cmd .Parse (os .Args [2 :]); err != nil {
71+ fmt .Println (err .Error ())
72+ cmd .PrintDefaults ()
73+ os .Exit (1 )
74+ }
75+
76+ if * dsn == "" {
77+ fmt .Println ("Error: database source required" )
78+ os .Exit (1 )
79+ }
80+
81+ if * dir == "" {
82+ fmt .Println ("Error: migration files folder required" )
83+ os .Exit (1 )
84+ }
85+
86+ isRollback := action == ACTION_DOWN
87+
88+ if err := migrateTables (* dsn , * dir , isRollback ); err != nil {
89+ fmt .Println (err )
90+ os .Exit (1 )
91+ }
92+
93+ }
94+
95+ }
96+
97+ func createMigrationCmd () {
98+ cmd := flag .NewFlagSet (ACTION_CREATE , flag .ExitOnError )
99+ name := cmd .String ("name" , "" , "Migration name" )
100+ dir := cmd .String ("dir" , "" , "migration files folder" )
101+ if err := cmd .Parse (os .Args [2 :]); err != nil {
102+ fmt .Println (err .Error ())
103+ }
104+ if * name == "" {
105+ fmt .Println ("Migration name needed" )
106+ cmd .PrintDefaults ()
107+ os .Exit (1 )
108+ return
109+ }
110+ if * dir == "" {
111+ fmt .Println ("Migration output directory needed" )
112+ cmd .PrintDefaults ()
113+ os .Exit (1 )
114+ return
115+ }
116+ migrate .CreateFile (* dir , * name )
117+ }
118+
119+ func migrateTables (dns , dir string , isRollback bool ) error {
120+ migration , err := migrate .New ("postgres" , dns , dir )
121+ if err != nil {
122+ return err
123+ }
124+ defer migration .Close ()
125+ if isRollback {
126+ return migration .Rollback ()
127+ }
128+ return migration .Migrate ()
129+ }
130+
131+ func confirm (msg string , isProd bool ) bool {
132+ if isProd {
133+ reader := bufio .NewReader (os .Stdin )
134+ for {
135+ fmt .Printf ("%s [y/n]: " , msg )
136+ response , err := reader .ReadString ('\n' )
137+ if err != nil {
138+ log .Fatal (err )
139+ }
140+ response = strings .ToLower (strings .TrimSpace (response ))
141+
142+ if response == "y" || response == "yes" {
143+ return true
144+ } else if response == "n" || response == "no" {
145+ return false
146+ }
147+ }
148+ }
149+ return true
150+ }
0 commit comments