github.com/svrana/migrate@v3.5.4+incompatible/cli/commands.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/golang-migrate/migrate" 7 _ "github.com/golang-migrate/migrate/database/stub" // TODO remove again 8 _ "github.com/golang-migrate/migrate/source/file" 9 "os" 10 "path/filepath" 11 "strconv" 12 "strings" 13 "time" 14 ) 15 16 func nextSeq(matches []string, dir string, seqDigits int) (string, error) { 17 if seqDigits <= 0 { 18 return "", errors.New("Digits must be positive") 19 } 20 21 nextSeq := 1 22 if len(matches) > 0 { 23 filename := matches[len(matches)-1] 24 matchSeqStr := strings.TrimPrefix(filename, dir) 25 idx := strings.Index(matchSeqStr, "_") 26 if idx < 1 { // Using 1 instead of 0 since there should be at least 1 digit 27 return "", errors.New("Malformed migration filename: " + filename) 28 } 29 matchSeqStr = matchSeqStr[0:idx] 30 var err error 31 nextSeq, err = strconv.Atoi(matchSeqStr) 32 if err != nil { 33 return "", err 34 } 35 nextSeq++ 36 } 37 if nextSeq <= 0 { 38 return "", errors.New("Next sequence number must be positive") 39 } 40 41 nextSeqStr := strconv.Itoa(nextSeq) 42 if len(nextSeqStr) > seqDigits { 43 return "", fmt.Errorf("Next sequence number %s too large. At most %d digits are allowed", nextSeqStr, seqDigits) 44 } 45 padding := seqDigits - len(nextSeqStr) 46 if padding > 0 { 47 nextSeqStr = strings.Repeat("0", padding) + nextSeqStr 48 } 49 return nextSeqStr, nil 50 } 51 52 func createCmd(dir string, startTime time.Time, format string, name string, ext string, seq bool, seqDigits int) { 53 var base string 54 if seq && format != defaultTimeFormat { 55 log.fatalErr(errors.New("The seq and format options are mutually exclusive")) 56 } 57 if seq { 58 if seqDigits <= 0 { 59 log.fatalErr(errors.New("Digits must be positive")) 60 } 61 matches, err := filepath.Glob(dir + "*" + ext) 62 if err != nil { 63 log.fatalErr(err) 64 } 65 nextSeqStr, err := nextSeq(matches, dir, seqDigits) 66 if err != nil { 67 log.fatalErr(err) 68 } 69 base = fmt.Sprintf("%v%v_%v.", dir, nextSeqStr, name) 70 } else { 71 switch format { 72 case "": 73 log.fatal("Time format may not be empty") 74 case "unix": 75 base = fmt.Sprintf("%v%v_%v.", dir, startTime.Unix(), name) 76 case "unixNano": 77 base = fmt.Sprintf("%v%v_%v.", dir, startTime.UnixNano(), name) 78 default: 79 base = fmt.Sprintf("%v%v_%v.", dir, startTime.Format(format), name) 80 } 81 } 82 83 os.MkdirAll(dir, os.ModePerm) 84 createFile(base + "up" + ext) 85 createFile(base + "down" + ext) 86 } 87 88 func createFile(fname string) { 89 if _, err := os.Create(fname); err != nil { 90 log.fatalErr(err) 91 } 92 } 93 94 func gotoCmd(m *migrate.Migrate, v uint) { 95 if err := m.Migrate(v); err != nil { 96 if err != migrate.ErrNoChange { 97 log.fatalErr(err) 98 } else { 99 log.Println(err) 100 } 101 } 102 } 103 104 func upCmd(m *migrate.Migrate, limit int) { 105 if limit >= 0 { 106 if err := m.Steps(limit); err != nil { 107 if err != migrate.ErrNoChange { 108 log.fatalErr(err) 109 } else { 110 log.Println(err) 111 } 112 } 113 } else { 114 if err := m.Up(); err != nil { 115 if err != migrate.ErrNoChange { 116 log.fatalErr(err) 117 } else { 118 log.Println(err) 119 } 120 } 121 } 122 } 123 124 func downCmd(m *migrate.Migrate, limit int) { 125 if limit >= 0 { 126 if err := m.Steps(-limit); err != nil { 127 if err != migrate.ErrNoChange { 128 log.fatalErr(err) 129 } else { 130 log.Println(err) 131 } 132 } 133 } else { 134 if err := m.Down(); err != nil { 135 if err != migrate.ErrNoChange { 136 log.fatalErr(err) 137 } else { 138 log.Println(err) 139 } 140 } 141 } 142 } 143 144 func dropCmd(m *migrate.Migrate) { 145 if err := m.Drop(); err != nil { 146 log.fatalErr(err) 147 } 148 } 149 150 func forceCmd(m *migrate.Migrate, v int) { 151 if err := m.Force(v); err != nil { 152 log.fatalErr(err) 153 } 154 } 155 156 func versionCmd(m *migrate.Migrate) { 157 v, dirty, err := m.Version() 158 if err != nil { 159 log.fatalErr(err) 160 } 161 if dirty { 162 log.Printf("%v (dirty)\n", v) 163 } else { 164 log.Println(v) 165 } 166 }