-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pkger source driver support #377
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
663520e
Add pkger source driver support
hnnsgstfssn 655a795
pkger: rename Instance to Pkger
hnnsgstfssn c177e4a
pkger: make WithInstance accept *Pkger
hnnsgstfssn 9afbbbf
pkger: refactor and add access to global pkging.Pkger instance
hnnsgstfssn 8ae7cd4
pkger: fix typo and cleanup debug logging
hnnsgstfssn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package pkger | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
stdurl "net/url" | ||
|
||
"github.com/golang-migrate/migrate/v4/source" | ||
"github.com/golang-migrate/migrate/v4/source/httpfs" | ||
"github.com/markbates/pkger" | ||
"github.com/markbates/pkger/pkging" | ||
) | ||
|
||
func init() { | ||
source.Register("pkger", &Pkger{}) | ||
} | ||
|
||
// Pkger is a source.Driver that reads migrations from instances of | ||
// pkging.Pkger. | ||
type Pkger struct { | ||
httpfs.PartialDriver | ||
} | ||
|
||
// Open implements source.Driver. The path component of url will be used as the | ||
// relative location of migrations. The returned driver will use the package | ||
// scoped pkger.Open to access migrations. The relative root and any | ||
// migrations must be added to the global pkger.Pkger instance by calling | ||
// pkger.Apply. Refer to Pkger documentation for more information. | ||
func (p *Pkger) Open(url string) (source.Driver, error) { | ||
u, err := stdurl.Parse(url) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// wrap pkger to implement http.FileSystem. | ||
fs := fsFunc(func(name string) (http.File, error) { | ||
f, err := pkger.Open(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return f.(http.File), nil | ||
}) | ||
|
||
if err := p.Init(fs, u.Path); err != nil { | ||
return nil, fmt.Errorf("failed to init driver with relative path %q: %w", u.Path, err) | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
// WithInstance returns a source.Driver that is backed by an instance of | ||
// pkging.Pkger. The relative location of migrations is indicated by path. The | ||
// path must exist on the pkging.Pkger instance for the driver to initialize | ||
// successfully. | ||
func WithInstance(instance pkging.Pkger, path string) (source.Driver, error) { | ||
if instance == nil { | ||
return nil, fmt.Errorf("expected instance of pkging.Pkger") | ||
} | ||
|
||
// wrap pkger to implement http.FileSystem. | ||
fs := fsFunc(func(name string) (http.File, error) { | ||
f, err := instance.Open(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return f.(http.File), nil | ||
}) | ||
|
||
var p Pkger | ||
|
||
if err := p.Init(fs, path); err != nil { | ||
return nil, fmt.Errorf("failed to init driver with relative path %q: %w", path, err) | ||
} | ||
|
||
return &p, nil | ||
} | ||
|
||
type fsFunc func(name string) (http.File, error) | ||
|
||
// Open implements http.FileSystem. | ||
func (f fsFunc) Open(name string) (http.File, error) { | ||
return f(name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package pkger | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
"testing" | ||
|
||
"github.com/gobuffalo/here" | ||
st "github.com/golang-migrate/migrate/v4/source/testing" | ||
"github.com/markbates/pkger" | ||
"github.com/markbates/pkger/pkging" | ||
"github.com/markbates/pkger/pkging/mem" | ||
) | ||
|
||
func Test(t *testing.T) { | ||
t.Run("WithInstance", func(t *testing.T) { | ||
i := testInstance(t) | ||
|
||
createPkgerFile(t, i, "/1_foobar.up.sql") | ||
createPkgerFile(t, i, "/1_foobar.down.sql") | ||
createPkgerFile(t, i, "/3_foobar.up.sql") | ||
createPkgerFile(t, i, "/4_foobar.up.sql") | ||
createPkgerFile(t, i, "/4_foobar.down.sql") | ||
createPkgerFile(t, i, "/5_foobar.down.sql") | ||
createPkgerFile(t, i, "/7_foobar.up.sql") | ||
createPkgerFile(t, i, "/7_foobar.down.sql") | ||
|
||
d, err := WithInstance(i, "/") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
st.Test(t, d) | ||
}) | ||
|
||
t.Run("Open", func(t *testing.T) { | ||
i := testInstance(t) | ||
|
||
createPkgerFile(t, i, "/1_foobar.up.sql") | ||
createPkgerFile(t, i, "/1_foobar.down.sql") | ||
createPkgerFile(t, i, "/3_foobar.up.sql") | ||
createPkgerFile(t, i, "/4_foobar.up.sql") | ||
createPkgerFile(t, i, "/4_foobar.down.sql") | ||
createPkgerFile(t, i, "/5_foobar.down.sql") | ||
createPkgerFile(t, i, "/7_foobar.up.sql") | ||
createPkgerFile(t, i, "/7_foobar.down.sql") | ||
|
||
registerPackageLevelInstance(t, i) | ||
|
||
d, err := (&Pkger{}).Open("pkger:///") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
st.Test(t, d) | ||
}) | ||
|
||
} | ||
|
||
func TestWithInstance(t *testing.T) { | ||
t.Run("Subdir", func(t *testing.T) { | ||
i := testInstance(t) | ||
|
||
// Make sure the relative root exists so that httpfs.PartialDriver can | ||
// initialize. | ||
createPkgerSubdir(t, i, "/subdir") | ||
|
||
_, err := WithInstance(i, "/subdir") | ||
if err != nil { | ||
t.Fatal("") | ||
} | ||
}) | ||
|
||
t.Run("NilInstance", func(t *testing.T) { | ||
_, err := WithInstance(nil, "") | ||
if err == nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
|
||
t.Run("FailInit", func(t *testing.T) { | ||
i := testInstance(t) | ||
|
||
_, err := WithInstance(i, "/fail") | ||
if err == nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
|
||
t.Run("FailWithoutMigrations", func(t *testing.T) { | ||
i := testInstance(t) | ||
|
||
createPkgerSubdir(t, i, "/") | ||
|
||
d, err := WithInstance(i, "/") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if _, err := d.First(); !errors.Is(err, os.ErrNotExist) { | ||
t.Fatal(err) | ||
} | ||
|
||
}) | ||
} | ||
|
||
func TestOpen(t *testing.T) { | ||
|
||
t.Run("InvalidURL", func(t *testing.T) { | ||
_, err := (&Pkger{}).Open(":///") | ||
if err == nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
|
||
t.Run("Root", func(t *testing.T) { | ||
_, err := (&Pkger{}).Open("pkger:///") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
|
||
t.Run("FailInit", func(t *testing.T) { | ||
_, err := (&Pkger{}).Open("pkger:///subdir") | ||
if err == nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
|
||
i := testInstance(t) | ||
createPkgerSubdir(t, i, "/subdir") | ||
|
||
// Note that this registers the instance globally so anything run after | ||
// this will have access to everything container in the registered | ||
// instance. | ||
registerPackageLevelInstance(t, i) | ||
|
||
t.Run("Subdir", func(t *testing.T) { | ||
_, err := (&Pkger{}).Open("pkger:///subdir") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
} | ||
|
||
func TestClose(t *testing.T) { | ||
d, err := (&Pkger{}).Open("pkger:///") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := d.Close(); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func registerPackageLevelInstance(t *testing.T, pkg pkging.Pkger) { | ||
if err := pkger.Apply(pkg, nil); err != nil { | ||
t.Fatalf("failed to register pkger instance: %v\n", err) | ||
} | ||
} | ||
|
||
func testInstance(t *testing.T) pkging.Pkger { | ||
pkg, err := inMemoryPkger() | ||
if err != nil { | ||
t.Fatalf("failed to create an pkging.Pkger instance: %v\n", err) | ||
} | ||
|
||
return pkg | ||
} | ||
|
||
func createPkgerSubdir(t *testing.T, pkg pkging.Pkger, subdir string) { | ||
if err := pkg.MkdirAll(subdir, os.ModePerm); err != nil { | ||
t.Fatalf("failed to create pkger subdir %q: %v\n", subdir, err) | ||
} | ||
} | ||
|
||
func createPkgerFile(t *testing.T, pkg pkging.Pkger, name string) { | ||
_, err := pkg.Create(name) | ||
if err != nil { | ||
t.Fatalf("failed to create pkger file %q: %v\n", name, err) | ||
} | ||
} | ||
|
||
func inMemoryPkger() (*mem.Pkger, error) { | ||
info, err := here.New().Current() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
pkg, err := mem.New(info) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return pkg, nil | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to refactor this to return
WithInstance(pkger, u.Path)
. Based on the pkgr.Open(), we'd probably have to use here.Current().This is not a blocker for this PR since the difference in complexity is arugable...
e.g. the setup required to use
WithInstance()
may not be worth the duplicated codeLemme know if you don't think this refactor is worth it and I'll go ahead and merge the PR as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I say go ahead and merge it as is. I'm not 100% sure, but if I change my mind I'll go ahead and contribute a refactor :)
Thanks!