Skip to content

Commit c3779f9

Browse files
Prometheus2677FPiety0521
authored and
FPiety0521
committed
Revert "Merge pull request #481 from johejo/revert-472-iofs_source_driver"
This reverts commit b690b78e22b7aea506ef68bdcfa37b0f10994a99, reversing changes made to 15931649a23b380e66a229c61ecd6097ea2fa807.
1 parent 95358eb commit c3779f9

16 files changed

+317
-22
lines changed

source/file/file.go

+5-22
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
package file
22

33
import (
4-
"net/http"
54
nurl "net/url"
65
"os"
76
"path/filepath"
87

98
"github.com/golang-migrate/migrate/v4/source"
10-
"github.com/golang-migrate/migrate/v4/source/httpfs"
119
)
1210

1311
func init() {
1412
source.Register("file", &File{})
1513
}
1614

17-
type File struct {
18-
httpfs.PartialDriver
19-
url string
20-
path string
21-
}
22-
23-
func (f *File) Open(url string) (source.Driver, error) {
15+
func parseURL(url string) (string, error) {
2416
u, err := nurl.Parse(url)
2517
if err != nil {
26-
return nil, err
18+
return "", err
2719
}
28-
2920
// concat host and path to restore full path
3021
// host might be `.`
3122
p := u.Opaque
@@ -37,25 +28,17 @@ func (f *File) Open(url string) (source.Driver, error) {
3728
// default to current directory if no path
3829
wd, err := os.Getwd()
3930
if err != nil {
40-
return nil, err
31+
return "", err
4132
}
4233
p = wd
4334

4435
} else if p[0:1] == "." || p[0:1] != "/" {
4536
// make path absolute if relative
4637
abs, err := filepath.Abs(p)
4738
if err != nil {
48-
return nil, err
39+
return "", err
4940
}
5041
p = abs
5142
}
52-
53-
nf := &File{
54-
url: url,
55-
path: p,
56-
}
57-
if err := nf.Init(http.Dir(p), ""); err != nil {
58-
return nil, err
59-
}
60-
return nf, nil
43+
return p, nil
6144
}

source/file/file_go115.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// +build !go1.16
2+
3+
package file
4+
5+
import (
6+
"net/http"
7+
8+
"github.com/golang-migrate/migrate/v4/source"
9+
"github.com/golang-migrate/migrate/v4/source/httpfs"
10+
)
11+
12+
type File struct {
13+
httpfs.PartialDriver
14+
url string
15+
path string
16+
}
17+
18+
func (f *File) Open(url string) (source.Driver, error) {
19+
p, err := parseURL(url)
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
nf := &File{
25+
url: url,
26+
path: p,
27+
}
28+
if err := nf.Init(http.Dir(p), ""); err != nil {
29+
return nil, err
30+
}
31+
return nf, nil
32+
}

source/file/file_go116.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// +build go1.16
2+
3+
package file
4+
5+
import (
6+
"os"
7+
8+
"github.com/golang-migrate/migrate/v4/source"
9+
"github.com/golang-migrate/migrate/v4/source/iofs"
10+
)
11+
12+
type File struct {
13+
iofs.PartialDriver
14+
url string
15+
path string
16+
}
17+
18+
func (f *File) Open(url string) (source.Driver, error) {
19+
p, err := parseURL(url)
20+
if err != nil {
21+
return nil, err
22+
}
23+
nf := &File{
24+
url: url,
25+
path: p,
26+
}
27+
if err := nf.Init(os.DirFS(p), "."); err != nil {
28+
return nil, err
29+
}
30+
return nf, nil
31+
}

source/iofs/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# iofs
2+
3+
https://pkg.go.dev/github.com/golang-migrate/migrate/v4/source/iofs

source/iofs/doc.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
Package iofs provides the Go 1.16+ io/fs#FS driver.
3+
4+
It can accept various file systems (like embed.FS, archive/zip#Reader) implementing io/fs#FS.
5+
6+
This driver cannot be used with Go versions 1.15 and below.
7+
8+
Also, Opening with a URL scheme is not supported.
9+
*/
10+
package iofs

source/iofs/example_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// +build go1.16
2+
3+
package iofs_test
4+
5+
import (
6+
"embed"
7+
"log"
8+
9+
"github.com/golang-migrate/migrate/v4"
10+
_ "github.com/golang-migrate/migrate/v4/database/postgres"
11+
"github.com/golang-migrate/migrate/v4/source/iofs"
12+
)
13+
14+
//go:embed testdata/migrations/*.sql
15+
var fs embed.FS
16+
17+
func Example() {
18+
d, err := iofs.New(fs, "testdata/migrations")
19+
if err != nil {
20+
log.Fatal(err)
21+
}
22+
m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@localhost/postgres?sslmode=disable")
23+
if err != nil {
24+
log.Fatal(err)
25+
}
26+
err = m.Up()
27+
if err != nil {
28+
// ...
29+
}
30+
// ...
31+
}

source/iofs/iofs.go

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// +build go1.16
2+
3+
package iofs
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"io"
9+
"io/fs"
10+
"path"
11+
"strconv"
12+
13+
"github.com/golang-migrate/migrate/v4/source"
14+
)
15+
16+
type driver struct {
17+
PartialDriver
18+
}
19+
20+
// New returns a new Driver from io/fs#FS and a relative path.
21+
func New(fsys fs.FS, path string) (source.Driver, error) {
22+
var i driver
23+
if err := i.Init(fsys, path); err != nil {
24+
return nil, fmt.Errorf("failed to init driver with path %s: %w", path, err)
25+
}
26+
return &i, nil
27+
}
28+
29+
// Open is part of source.Driver interface implementation.
30+
// Open cannot be called on the iofs passthrough driver.
31+
func (d *driver) Open(url string) (source.Driver, error) {
32+
return nil, errors.New("Open() cannot be called on the iofs passthrough driver")
33+
}
34+
35+
// PartialDriver is a helper service for creating new source drivers working with
36+
// io/fs.FS instances. It implements all source.Driver interface methods
37+
// except for Open(). New driver could embed this struct and add missing Open()
38+
// method.
39+
//
40+
// To prepare PartialDriver for use Init() function.
41+
type PartialDriver struct {
42+
migrations *source.Migrations
43+
fsys fs.FS
44+
path string
45+
}
46+
47+
// Init prepares not initialized IoFS instance to read migrations from a
48+
// io/fs#FS instance and a relative path.
49+
func (d *PartialDriver) Init(fsys fs.FS, path string) error {
50+
entries, err := fs.ReadDir(fsys, path)
51+
if err != nil {
52+
return err
53+
}
54+
55+
ms := source.NewMigrations()
56+
for _, e := range entries {
57+
if e.IsDir() {
58+
continue
59+
}
60+
m, err := source.DefaultParse(e.Name())
61+
if err != nil {
62+
continue
63+
}
64+
file, err := e.Info()
65+
if err != nil {
66+
return err
67+
}
68+
if !ms.Append(m) {
69+
return source.ErrDuplicateMigration{
70+
Migration: *m,
71+
FileInfo: file,
72+
}
73+
}
74+
}
75+
76+
d.fsys = fsys
77+
d.path = path
78+
d.migrations = ms
79+
return nil
80+
}
81+
82+
// Close is part of source.Driver interface implementation.
83+
// Closes the file system if possible.
84+
func (d *PartialDriver) Close() error {
85+
c, ok := d.fsys.(io.Closer)
86+
if !ok {
87+
return nil
88+
}
89+
return c.Close()
90+
}
91+
92+
// First is part of source.Driver interface implementation.
93+
func (d *PartialDriver) First() (version uint, err error) {
94+
if version, ok := d.migrations.First(); ok {
95+
return version, nil
96+
}
97+
return 0, &fs.PathError{
98+
Op: "first",
99+
Path: d.path,
100+
Err: fs.ErrNotExist,
101+
}
102+
}
103+
104+
// Prev is part of source.Driver interface implementation.
105+
func (d *PartialDriver) Prev(version uint) (prevVersion uint, err error) {
106+
if version, ok := d.migrations.Prev(version); ok {
107+
return version, nil
108+
}
109+
return 0, &fs.PathError{
110+
Op: "prev for version " + strconv.FormatUint(uint64(version), 10),
111+
Path: d.path,
112+
Err: fs.ErrNotExist,
113+
}
114+
}
115+
116+
// Next is part of source.Driver interface implementation.
117+
func (d *PartialDriver) Next(version uint) (nextVersion uint, err error) {
118+
if version, ok := d.migrations.Next(version); ok {
119+
return version, nil
120+
}
121+
return 0, &fs.PathError{
122+
Op: "next for version " + strconv.FormatUint(uint64(version), 10),
123+
Path: d.path,
124+
Err: fs.ErrNotExist,
125+
}
126+
}
127+
128+
// ReadUp is part of source.Driver interface implementation.
129+
func (d *PartialDriver) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
130+
if m, ok := d.migrations.Up(version); ok {
131+
body, err := d.open(path.Join(d.path, m.Raw))
132+
if err != nil {
133+
return nil, "", err
134+
}
135+
return body, m.Identifier, nil
136+
}
137+
return nil, "", &fs.PathError{
138+
Op: "read up for version " + strconv.FormatUint(uint64(version), 10),
139+
Path: d.path,
140+
Err: fs.ErrNotExist,
141+
}
142+
}
143+
144+
// ReadDown is part of source.Driver interface implementation.
145+
func (d *PartialDriver) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
146+
if m, ok := d.migrations.Down(version); ok {
147+
body, err := d.open(path.Join(d.path, m.Raw))
148+
if err != nil {
149+
return nil, "", err
150+
}
151+
return body, m.Identifier, nil
152+
}
153+
return nil, "", &fs.PathError{
154+
Op: "read down for version " + strconv.FormatUint(uint64(version), 10),
155+
Path: d.path,
156+
Err: fs.ErrNotExist,
157+
}
158+
}
159+
160+
func (d *PartialDriver) open(path string) (fs.File, error) {
161+
f, err := d.fsys.Open(path)
162+
if err == nil {
163+
return f, nil
164+
}
165+
// Some non-standard file systems may return errors that don't include the path, that
166+
// makes debugging harder.
167+
if !errors.As(err, new(*fs.PathError)) {
168+
err = &fs.PathError{
169+
Op: "open",
170+
Path: path,
171+
Err: err,
172+
}
173+
}
174+
return nil, err
175+
}

source/iofs/iofs_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// +build go1.16
2+
3+
package iofs_test
4+
5+
import (
6+
"embed"
7+
"testing"
8+
9+
"github.com/golang-migrate/migrate/v4/source/iofs"
10+
st "github.com/golang-migrate/migrate/v4/source/testing"
11+
)
12+
13+
func Test(t *testing.T) {
14+
//go:embed testdata/migrations/*.sql
15+
var fs embed.FS
16+
d, err := iofs.New(fs, "testdata/migrations")
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
21+
st.Test(t, d)
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1 down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1 up
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3 up
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4 down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4 up
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
5 down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7 down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7 up

0 commit comments

Comments
 (0)