1 package httpfs
2
3 import (
4 "errors"
5 "io"
6 "net/http"
7 "os"
8 "path"
9 "strconv"
10
11 "github.com/golang-migrate/migrate/v4/source"
12 )
13
14
15
16
17
18
19
20 type PartialDriver struct {
21 migrations *source.Migrations
22 fs http.FileSystem
23 path string
24 }
25
26
27
28 func (p *PartialDriver) Init(fs http.FileSystem, path string) error {
29 root, err := fs.Open(path)
30 if err != nil {
31 return err
32 }
33
34 files, err := root.Readdir(0)
35 if err != nil {
36 _ = root.Close()
37 return err
38 }
39 if err = root.Close(); err != nil {
40 return err
41 }
42
43 ms := source.NewMigrations()
44 for _, file := range files {
45 if file.IsDir() {
46 continue
47 }
48
49 m, err := source.DefaultParse(file.Name())
50 if err != nil {
51 continue
52 }
53
54 if !ms.Append(m) {
55 return source.ErrDuplicateMigration{
56 Migration: *m,
57 FileInfo: file,
58 }
59 }
60 }
61
62 p.fs = fs
63 p.path = path
64 p.migrations = ms
65 return nil
66 }
67
68
69 func (p *PartialDriver) Close() error {
70 return nil
71 }
72
73
74 func (p *PartialDriver) First() (version uint, err error) {
75 if version, ok := p.migrations.First(); ok {
76 return version, nil
77 }
78 return 0, &os.PathError{
79 Op: "first",
80 Path: p.path,
81 Err: os.ErrNotExist,
82 }
83 }
84
85
86 func (p *PartialDriver) Prev(version uint) (prevVersion uint, err error) {
87 if version, ok := p.migrations.Prev(version); ok {
88 return version, nil
89 }
90 return 0, &os.PathError{
91 Op: "prev for version " + strconv.FormatUint(uint64(version), 10),
92 Path: p.path,
93 Err: os.ErrNotExist,
94 }
95 }
96
97
98 func (p *PartialDriver) Next(version uint) (nextVersion uint, err error) {
99 if version, ok := p.migrations.Next(version); ok {
100 return version, nil
101 }
102 return 0, &os.PathError{
103 Op: "next for version " + strconv.FormatUint(uint64(version), 10),
104 Path: p.path,
105 Err: os.ErrNotExist,
106 }
107 }
108
109
110 func (p *PartialDriver) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
111 if m, ok := p.migrations.Up(version); ok {
112 body, err := p.open(path.Join(p.path, m.Raw))
113 if err != nil {
114 return nil, "", err
115 }
116 return body, m.Identifier, nil
117 }
118 return nil, "", &os.PathError{
119 Op: "read up for version " + strconv.FormatUint(uint64(version), 10),
120 Path: p.path,
121 Err: os.ErrNotExist,
122 }
123 }
124
125
126 func (p *PartialDriver) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
127 if m, ok := p.migrations.Down(version); ok {
128 body, err := p.open(path.Join(p.path, m.Raw))
129 if err != nil {
130 return nil, "", err
131 }
132 return body, m.Identifier, nil
133 }
134 return nil, "", &os.PathError{
135 Op: "read down for version " + strconv.FormatUint(uint64(version), 10),
136 Path: p.path,
137 Err: os.ErrNotExist,
138 }
139 }
140
141 func (p *PartialDriver) open(path string) (http.File, error) {
142 f, err := p.fs.Open(path)
143 if err == nil {
144 return f, nil
145 }
146
147
148 if !errors.As(err, new(*os.PathError)) {
149 err = &os.PathError{
150 Op: "open",
151 Path: path,
152 Err: err,
153 }
154 }
155 return nil, err
156 }
157
View as plain text