Skip to content
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 support for docker URI images in buildpackstore. #301

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions buildpack_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ type CacheManager interface {
Close() error
}

//go:generate faux --interface BPStoreDockerPull --output fakes/docker_pull.go
type BPStoreDockerPull interface {
Execute(string) error
}

type BuildpackStore struct {
Get BuildpackStoreGet
}
Expand Down Expand Up @@ -71,6 +76,11 @@ func (bs BuildpackStore) WithRemoteFetcher(fetcher RemoteFetcher) BuildpackStore
return bs
}

func (bs BuildpackStore) WithOCIFetcher(fetcher BPStoreDockerPull) BuildpackStore {
bs.Get.oci = fetcher
return bs
}

func (bs BuildpackStore) WithCacheManager(manager CacheManager) BuildpackStore {
bs.Get.cacheManager = manager
return bs
Expand All @@ -86,12 +96,21 @@ type BuildpackStoreGet struct {
cacheManager CacheManager
local LocalFetcher
remote RemoteFetcher
oci BPStoreDockerPull

offline bool
version string
}

func (g BuildpackStoreGet) Execute(url string) (string, error) {
if strings.HasPrefix(url, "docker://") {
if g.oci == nil {
return "", fmt.Errorf("must provide OCI fetcher to fetch OCI images")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of gross, but it's the only way I could see to make this backwards-compatible and avoid a breaking change in the exported function signatures.

The OCI fetcher has to be injected, so either we force the user to inject it at construction time (i.e. NewBuildpackStore(dockerPull BPStoreDockerPull)) which is a breaking change, or we accept that it might be nil when we try to use it.

}
url := strings.TrimPrefix(url, "docker://")
return url, g.oci.Execute(url)
}

err := g.cacheManager.Open()
if err != nil {
return "", fmt.Errorf("failed to open cacheManager: %s", err)
Expand Down
72 changes: 71 additions & 1 deletion buildpack_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,79 @@ func testBuildpackStore(t *testing.T, when spec.G, it spec.S) {
fakeRemoteFetcher *fakes.RemoteFetcher
fakeLocalFetcher *fakes.LocalFetcher
fakeCacheManager *fakes.CacheManager
fakeDockerPull *fakes.BPStoreDockerPull
)

it.Before(func() {
fakeRemoteFetcher = &fakes.RemoteFetcher{}
fakeLocalFetcher = &fakes.LocalFetcher{}
fakeCacheManager = &fakes.CacheManager{}
fakeDockerPull = &fakes.BPStoreDockerPull{}

buildpackStore = occam.NewBuildpackStore()

buildpackStore = buildpackStore.WithLocalFetcher(fakeLocalFetcher).
WithRemoteFetcher(fakeRemoteFetcher).
WithCacheManager(fakeCacheManager)
WithCacheManager(fakeCacheManager).
WithOCIFetcher(fakeDockerPull)
})

when("getting an online buildpack", func() {
when("from a docker uri", func() {
it("returns the URI to the OCI image, stripping the docker:// protocol", func() {
local_url, err := buildpackStore.Get.
Execute("docker://some-image:tag")
Expect(err).NotTo(HaveOccurred())

Expect(local_url).To(Equal("some-image:tag"))

Expect(fakeDockerPull.ExecuteCall.CallCount).To(Equal(1))
Expect(fakeDockerPull.ExecuteCall.Receives.String).To(Equal("some-image:tag"))

Expect(fakeCacheManager.OpenCall.CallCount).To(Equal(0))
Expect(fakeCacheManager.CloseCall.CallCount).To(Equal(0))

Expect(fakeRemoteFetcher.GetCall.CallCount).To(Equal(0))
Expect(fakeLocalFetcher.GetCall.CallCount).To(Equal(0))
})

it("ignores the online/offline flags", func() {
local_url, err := buildpackStore.Get.
WithOfflineDependencies().
Execute("docker://some-image:tag")
Expect(err).NotTo(HaveOccurred())

Expect(local_url).To(Equal("some-image:tag"))

Expect(fakeDockerPull.ExecuteCall.CallCount).To(Equal(1))
Expect(fakeDockerPull.ExecuteCall.Receives.String).To(Equal("some-image:tag"))

Expect(fakeCacheManager.OpenCall.CallCount).To(Equal(0))
Expect(fakeCacheManager.CloseCall.CallCount).To(Equal(0))

Expect(fakeRemoteFetcher.GetCall.CallCount).To(Equal(0))
Expect(fakeLocalFetcher.GetCall.CallCount).To(Equal(0))
})

it("ignores the version flag", func() {
local_url, err := buildpackStore.Get.
WithVersion("some-version").
Execute("docker://some-image:tag")
Expect(err).NotTo(HaveOccurred())

Expect(local_url).To(Equal("some-image:tag"))

Expect(fakeDockerPull.ExecuteCall.CallCount).To(Equal(1))
Expect(fakeDockerPull.ExecuteCall.Receives.String).To(Equal("some-image:tag"))

Expect(fakeCacheManager.OpenCall.CallCount).To(Equal(0))
Expect(fakeCacheManager.CloseCall.CallCount).To(Equal(0))

Expect(fakeRemoteFetcher.GetCall.CallCount).To(Equal(0))
Expect(fakeLocalFetcher.GetCall.CallCount).To(Equal(0))
})
})

when("from a local uri", func() {
it.Before(func() {
fakeLocalFetcher.GetCall.Returns.String = "/path/to/cool-buildpack/"
Expand Down Expand Up @@ -151,6 +209,18 @@ func testBuildpackStore(t *testing.T, when spec.G, it spec.S) {
})

when("failure cases", func() {
when("attempting to fetch OCI image without OCI fetcher", func() {
it.Before(func() {
buildpackStore = occam.NewBuildpackStore()
})

it("returns an error", func() {
_, err := buildpackStore.Get.Execute("docker://some-image:tag")

Expect(err).To(MatchError("must provide OCI fetcher to fetch OCI images"))
})
})

when("unable to open cacheManager", func() {
it.Before(func() {
fakeCacheManager.OpenCall.Returns.Error = errors.New("bad bad error")
Expand Down
28 changes: 28 additions & 0 deletions fakes/docker_pull.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package fakes

import "sync"

type BPStoreDockerPull struct {
ExecuteCall struct {
mutex sync.Mutex
CallCount int
Receives struct {
String string
}
Returns struct {
Error error
}
Stub func(string) error
}
}

func (f *BPStoreDockerPull) Execute(param1 string) error {
f.ExecuteCall.mutex.Lock()
defer f.ExecuteCall.mutex.Unlock()
f.ExecuteCall.CallCount++
f.ExecuteCall.Receives.String = param1
if f.ExecuteCall.Stub != nil {
return f.ExecuteCall.Stub(param1)
}
return f.ExecuteCall.Returns.Error
}
Loading