forked from golang-migrate/migrate
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vfs.go
137 lines (120 loc) · 3.98 KB
/
vfs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Package vfs contains a driver that reads migrations from a virtual file
// system.
//
// Implementations of the filesystem interface that read from zip files and
// maps, as well as the definition of the filesystem interface can be found in
// the golang.org/x/tools/godoc/vfs package.
package godoc_vfs
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"github.com/golang-migrate/migrate/source"
"golang.org/x/tools/godoc/vfs"
)
func init() {
source.Register("godoc-vfs", &VFS{})
}
// VFS is an implementation of driver that returns migrations from a virtual
// file system.
type VFS struct {
migrations *source.Migrations
fs vfs.FileSystem
path string
}
// Open implements the source.Driver interface for VFS.
//
// Calling this function panics, instead use the WithInstance function.
// See the package level documentation for an example.
func (b *VFS) Open(url string) (source.Driver, error) {
panic("not implemented")
}
// WithInstance creates a new driver from a virtual file system.
// If a tree named searchPath exists in the virtual filesystem, WithInstance
// searches for migration files there.
// It defaults to "/".
func WithInstance(fs vfs.FileSystem, searchPath string) (source.Driver, error) {
if searchPath == "" {
searchPath = "/"
}
bn := &VFS{
fs: fs,
path: searchPath,
migrations: source.NewMigrations(),
}
files, err := fs.ReadDir(searchPath)
if err != nil {
return nil, err
}
for _, fi := range files {
m, err := source.DefaultParse(fi.Name())
if err != nil {
continue // ignore files that we can't parse
}
if !bn.migrations.Append(m) {
return nil, fmt.Errorf("unable to parse file %v", fi)
}
}
return bn, nil
}
// Close implements the source.Driver interface for VFS.
// It is a no-op and should not be used.
func (b *VFS) Close() error {
return nil
}
// First returns the first migration verion found in the file system.
// If no version is available os.ErrNotExist is returned.
func (b *VFS) First() (version uint, err error) {
v, ok := b.migrations.First()
if !ok {
return 0, &os.PathError{"first", "<vfs>://" + b.path, os.ErrNotExist}
}
return v, nil
}
// Prev returns the previous version available to the driver.
// If no previous version is available os.ErrNotExist is returned.
func (b *VFS) Prev(version uint) (prevVersion uint, err error) {
v, ok := b.migrations.Prev(version)
if !ok {
return 0, &os.PathError{fmt.Sprintf("prev for version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
}
return v, nil
}
// Prev returns the next version available to the driver.
// If no previous version is available os.ErrNotExist is returned.
func (b *VFS) Next(version uint) (nextVersion uint, err error) {
v, ok := b.migrations.Next(version)
if !ok {
return 0, &os.PathError{fmt.Sprintf("next for version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
}
return v, nil
}
// ReadUp returns the up migration body and an identifier that helps with
// finding this migration in the source.
// If there is no up migration available for this version it returns
// os.ErrNotExist.
func (b *VFS) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
if m, ok := b.migrations.Up(version); ok {
body, err := vfs.ReadFile(b.fs, path.Join(b.path, m.Raw))
if err != nil {
return nil, "", err
}
return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
}
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
}
// ReadDown returns the down migration body and an identifier that helps with
// finding this migration in the source.
func (b *VFS) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
if m, ok := b.migrations.Down(version); ok {
body, err := vfs.ReadFile(b.fs, path.Join(b.path, m.Raw))
if err != nil {
return nil, "", err
}
return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
}
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
}