github.com/solvedata/migrate/v4@v4.8.7-0.20201127053940-c9fba4ce569f/source/file/file.go (about) 1 package file 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 nurl "net/url" 8 "os" 9 "path" 10 "path/filepath" 11 12 "github.com/solvedata/migrate/v4/source" 13 ) 14 15 func init() { 16 source.Register("file", &File{}) 17 } 18 19 type File struct { 20 url string 21 path string 22 migrations *source.Migrations 23 } 24 25 func (f *File) Open(url string) (source.Driver, error) { 26 u, err := nurl.Parse(url) 27 if err != nil { 28 return nil, err 29 } 30 31 // concat host and path to restore full path 32 // host might be `.` 33 p := u.Opaque 34 if len(p) == 0 { 35 p = u.Host + u.Path 36 } 37 38 if len(p) == 0 { 39 // default to current directory if no path 40 wd, err := os.Getwd() 41 if err != nil { 42 return nil, err 43 } 44 p = wd 45 46 } else if p[0:1] == "." || p[0:1] != "/" { 47 // make path absolute if relative 48 abs, err := filepath.Abs(p) 49 if err != nil { 50 return nil, err 51 } 52 p = abs 53 } 54 55 // scan directory 56 files, err := ioutil.ReadDir(p) 57 if err != nil { 58 return nil, err 59 } 60 61 nf := &File{ 62 url: url, 63 path: p, 64 migrations: source.NewMigrations(), 65 } 66 67 for _, fi := range files { 68 if !fi.IsDir() { 69 m, err := source.DefaultParse(fi.Name()) 70 if err != nil { 71 continue // ignore files that we can't parse 72 } 73 if !nf.migrations.Append(m) { 74 return nil, fmt.Errorf("unable to parse file %v", fi.Name()) 75 } 76 } 77 } 78 return nf, nil 79 } 80 81 func (f *File) Close() error { 82 // nothing do to here 83 return nil 84 } 85 86 func (f *File) First() (version uint, err error) { 87 if v, ok := f.migrations.First(); ok { 88 return v, nil 89 } 90 return 0, &os.PathError{Op: "first", Path: f.path, Err: os.ErrNotExist} 91 } 92 93 func (f *File) Prev(version uint) (prevVersion uint, err error) { 94 if v, ok := f.migrations.Prev(version); ok { 95 return v, nil 96 } 97 return 0, &os.PathError{Op: fmt.Sprintf("prev for version %v", version), Path: f.path, Err: os.ErrNotExist} 98 } 99 100 func (f *File) Next(version uint) (nextVersion uint, err error) { 101 if v, ok := f.migrations.Next(version); ok { 102 return v, nil 103 } 104 return 0, &os.PathError{Op: fmt.Sprintf("next for version %v", version), Path: f.path, Err: os.ErrNotExist} 105 } 106 107 func (f *File) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) { 108 if m, ok := f.migrations.Up(version); ok { 109 r, err := os.Open(path.Join(f.path, m.Raw)) 110 if err != nil { 111 return nil, "", err 112 } 113 return r, m.Identifier, nil 114 } 115 return nil, "", &os.PathError{Op: fmt.Sprintf("read version %v", version), Path: f.path, Err: os.ErrNotExist} 116 } 117 118 func (f *File) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) { 119 if m, ok := f.migrations.Down(version); ok { 120 r, err := os.Open(path.Join(f.path, m.Raw)) 121 if err != nil { 122 return nil, "", err 123 } 124 return r, m.Identifier, nil 125 } 126 return nil, "", &os.PathError{Op: fmt.Sprintf("read version %v", version), Path: f.path, Err: os.ErrNotExist} 127 }