github.com/fr-nvriep/migrate/v4@v4.3.2/internal/cli/commands.go (about)

     1  package cli
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/fr-nvriep/migrate/v4"
     7  	_ "github.com/fr-nvriep/migrate/v4/database/stub" // TODO remove again
     8  	_ "github.com/fr-nvriep/migrate/v4/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  	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
    84  		log.fatalErr(err)
    85  	}
    86  
    87  	createFile(base + "up" + ext)
    88  	createFile(base + "down" + ext)
    89  }
    90  
    91  func createFile(fname string) {
    92  	if _, err := os.Create(fname); err != nil {
    93  		log.fatalErr(err)
    94  	}
    95  }
    96  
    97  func gotoCmd(m *migrate.Migrate, v uint) {
    98  	if err := m.Migrate(v); err != nil {
    99  		if err != migrate.ErrNoChange {
   100  			log.fatalErr(err)
   101  		} else {
   102  			log.Println(err)
   103  		}
   104  	}
   105  }
   106  
   107  func upCmd(m *migrate.Migrate, limit int) {
   108  	if limit >= 0 {
   109  		if err := m.Steps(limit); err != nil {
   110  			if err != migrate.ErrNoChange {
   111  				log.fatalErr(err)
   112  			} else {
   113  				log.Println(err)
   114  			}
   115  		}
   116  	} else {
   117  		if err := m.Up(); err != nil {
   118  			if err != migrate.ErrNoChange {
   119  				log.fatalErr(err)
   120  			} else {
   121  				log.Println(err)
   122  			}
   123  		}
   124  	}
   125  }
   126  
   127  func downCmd(m *migrate.Migrate, limit int) {
   128  	if limit >= 0 {
   129  		if err := m.Steps(-limit); err != nil {
   130  			if err != migrate.ErrNoChange {
   131  				log.fatalErr(err)
   132  			} else {
   133  				log.Println(err)
   134  			}
   135  		}
   136  	} else {
   137  		if err := m.Down(); err != nil {
   138  			if err != migrate.ErrNoChange {
   139  				log.fatalErr(err)
   140  			} else {
   141  				log.Println(err)
   142  			}
   143  		}
   144  	}
   145  }
   146  
   147  func dropCmd(m *migrate.Migrate) {
   148  	if err := m.Drop(); err != nil {
   149  		log.fatalErr(err)
   150  	}
   151  }
   152  
   153  func forceCmd(m *migrate.Migrate, v int) {
   154  	if err := m.Force(v); err != nil {
   155  		log.fatalErr(err)
   156  	}
   157  }
   158  
   159  func versionCmd(m *migrate.Migrate) {
   160  	v, dirty, err := m.Version()
   161  	if err != nil {
   162  		log.fatalErr(err)
   163  	}
   164  	if dirty {
   165  		log.Printf("%v (dirty)\n", v)
   166  	} else {
   167  		log.Println(v)
   168  	}
   169  }