Skip to content

Commit

Permalink
Merge pull request #12 from buildpacks/image-index
Browse files Browse the repository at this point in the history
More cleanup
  • Loading branch information
jjbustamante authored Apr 22, 2024
2 parents 697ac4c + d508728 commit 4aedd4c
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 332 deletions.
44 changes: 44 additions & 0 deletions layout/index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package layout

import (
"fmt"

v1 "github.com/google/go-containerregistry/pkg/v1"

"github.com/buildpacks/imgutil"
)

// NewIndex will return an OCI ImageIndex saved on disk using OCI media Types. It can be modified and saved to a registry
func NewIndex(repoName string, ops ...imgutil.IndexOption) (*imgutil.CNBIndex, error) {
options := &imgutil.IndexOptions{}
for _, op := range ops {
if err := op(options); err != nil {
return nil, err
}
}

var err error

if options.BaseIndex == nil && options.BaseIndexRepoName != "" { // options.BaseIndex supersedes options.BaseIndexRepoName
options.BaseIndex, err = newV1Index(
options.BaseIndexRepoName,
)
if err != nil {
return nil, err
}
}

return imgutil.NewCNBIndex(repoName, *options)
}

// newV1Index creates a layout image index from the given path.
func newV1Index(path string) (v1.ImageIndex, error) {
if !imageExists(path) {
return nil, nil
}
layoutPath, err := FromPath(path)
if err != nil {
return nil, fmt.Errorf("failed to load layout from path: %w", err)
}
return layoutPath.ImageIndex()
}
77 changes: 77 additions & 0 deletions layout/index_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package layout_test

import (
"os"
"path/filepath"
"testing"

"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/imgutil"
"github.com/buildpacks/imgutil/layout"
h "github.com/buildpacks/imgutil/testhelpers"
)

func TestLayoutIndex(t *testing.T) {
spec.Run(t, "LayoutNewIndex", testNewIndex, spec.Parallel(), spec.Report(report.Terminal{}))
}

func testNewIndex(t *testing.T, when spec.G, it spec.S) {
var (
idx imgutil.ImageIndex
tempDir string
repoName string
err error
)

it.Before(func() {
// creates the directory to save all the OCI images on disk
tempDir, err = os.MkdirTemp("", "image-indexes")
h.AssertNil(t, err)

// global directory and paths
testDataDir = filepath.Join("testdata", "layout")
_ = idx
})

it.After(func() {
err := os.RemoveAll(tempDir)
h.AssertNil(t, err)
})

when("#NewIndex", func() {
it.Before(func() {
repoName = "some/index"
})

when("index doesn't exists on disk", func() {
it("creates empty image index", func() {
idx, err = layout.NewIndex(
repoName,
imgutil.WithXDGRuntimePath(tempDir),
)
h.AssertNil(t, err)
})

it("ignores FromBaseIndex if it doesn't exist", func() {
idx, err = layout.NewIndex(
repoName,
imgutil.WithXDGRuntimePath(tempDir),
imgutil.FromBaseIndex("non-existent/index"),
)
h.AssertNil(t, err)
})

it("creates empty image index with Docker media-types", func() {
idx, err = layout.NewIndex(
repoName,
imgutil.WithXDGRuntimePath(tempDir),
imgutil.WithMediaType(types.DockerManifestList),
)
h.AssertNil(t, err)
})
})
})
}
50 changes: 26 additions & 24 deletions layout/layout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ func TestLayout(t *testing.T) {
os.Setenv("DOCKER_CONFIG", dockerConfigDir)
defer os.Unsetenv("DOCKER_CONFIG")

spec.Run(t, "Image", testImage, spec.Parallel(), spec.Report(report.Terminal{}))
spec.Run(t, "ImageIndex", testImageIndex, spec.Parallel(), spec.Report(report.Terminal{}))
spec.Run(t, "LayoutImage", testImage, spec.Parallel(), spec.Report(report.Terminal{}))
// FIXME: find a way to make the docker registry not-global, so that these tests can move to index_test.go
spec.Run(t, "LayoutIndex", testIndex, spec.Parallel(), spec.Report(report.Terminal{}))
}

var (
Expand Down Expand Up @@ -1137,7 +1138,7 @@ func testImage(t *testing.T, when spec.G, it spec.S) {
})
}

func testImageIndex(t *testing.T, when spec.G, it spec.S) {
func testIndex(t *testing.T, when spec.G, it spec.S) {
var (
idx imgutil.ImageIndex
tmpDir string
Expand Down Expand Up @@ -1170,9 +1171,9 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
digest name.Digest
)
when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx, err = layout.NewIndex("busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath))
idx, err = layout.NewIndex("busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath))
h.AssertNil(t, err)
localPath = filepath.Join(tmpDir, "busybox-multi-platform")
})
Expand Down Expand Up @@ -1267,9 +1268,9 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {

when("#Save", func() {
when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx, err = layout.NewIndex("busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath))
idx, err = layout.NewIndex("busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath))
h.AssertNil(t, err)

localPath = filepath.Join(tmpDir, "busybox-multi-platform")
Expand All @@ -1287,11 +1288,11 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
})
})

when("#FromBaseImageIndexInstance", func() {
when("#FromBaseIndexInstance", func() {
it.Before(func() {
localIndex := h.ReadImageIndex(t, baseIndexPath)

idx, err = layout.NewIndex("busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndexInstance(localIndex))
idx, err = layout.NewIndex("busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndexInstance(localIndex))
h.AssertNil(t, err)

localPath = filepath.Join(tmpDir, "busybox-multi-platform")
Expand Down Expand Up @@ -1327,7 +1328,7 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
when("index is created from scratch", func() {
it.Before(func() {
repoName := newRepoName()
idx = setUpImageIndex(t, repoName, tmpDir)
idx = setupIndex(t, repoName, imgutil.WithXDGRuntimePath(tmpDir))
localPath = filepath.Join(tmpDir, repoName)
})

Expand All @@ -1349,9 +1350,9 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
})

when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx = setUpImageIndex(t, "busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath))
idx = setupIndex(t, "busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath))
localPath = filepath.Join(tmpDir, "busybox-multi-platform")
})

Expand All @@ -1376,10 +1377,11 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
})

when("#Push", func() {
when("index is created from scratch", func() {
when.Focus("index is created from scratch", func() {
it.Before(func() {
repoName := newTestImageIndexName("push-index-test")
idx = setUpImageIndex(t, repoName, tmpDir, imgutil.WithKeychain(authn.DefaultKeychain))
t.Log("XXX", repoName)
idx = setupIndex(t, repoName, imgutil.WithXDGRuntimePath(tmpDir), imgutil.WithKeychain(authn.DefaultKeychain))

// TODO Note in the Push operation
// Note: It will only push IndexManifest, assuming all the images it refers exists in registry
Expand Down Expand Up @@ -1411,9 +1413,9 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {

when("#Delete", func() {
when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx = setUpImageIndex(t, "busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath))
idx = setupIndex(t, "busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath))
localPath = filepath.Join(tmpDir, "busybox-multi-platform")
})

Expand All @@ -1435,9 +1437,9 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
when("#Remove", func() {
var digest name.Digest
when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx = setUpImageIndex(t, "busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath), imgutil.WithKeychain(authn.DefaultKeychain))
idx = setupIndex(t, "busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath), imgutil.WithKeychain(authn.DefaultKeychain))
localPath = filepath.Join(tmpDir, "busybox-multi-platform")
digest, err = name.NewDigest("busybox@sha256:f5b920213fc6498c0c5eaee7e04f8424202b565bb9e5e4de9e617719fb7bd873")
h.AssertNil(t, err)
Expand Down Expand Up @@ -1467,26 +1469,26 @@ func testImageIndex(t *testing.T, when spec.G, it spec.S) {
when("#Inspect", func() {
var indexString string
when("index exists on disk", func() {
when("#FromBaseImageIndex", func() {
when("#FromBaseIndex", func() {
it.Before(func() {
idx = setUpImageIndex(t, "busybox-multi-platform", tmpDir, imgutil.FromBaseImageIndex(baseIndexPath))
idx = setupIndex(t, "busybox-multi-platform", imgutil.WithXDGRuntimePath(tmpDir), imgutil.FromBaseIndex(baseIndexPath))
localPath = filepath.Join(tmpDir, "busybox-multi-platform")
})

it("returns an image index string representation", func() {
indexString, err = idx.Inspect()
h.AssertNil(t, err)

idxFromString := parseImageIndex(t, indexString)
idxFromString := parseIndex(t, indexString)
h.AssertEq(t, len(idxFromString.Manifests), 2)
})
})
})
})
}

func setUpImageIndex(t *testing.T, repoName string, tmpDir string, ops ...imgutil.IndexOption) imgutil.ImageIndex {
idx, err := layout.NewIndex(repoName, tmpDir, ops...)
func setupIndex(t *testing.T, repoName string, ops ...imgutil.IndexOption) imgutil.ImageIndex {
idx, err := layout.NewIndex(repoName, ops...)
h.AssertNil(t, err)

// TODO before adding something to the index, apparently we need initialize on disk
Expand All @@ -1503,7 +1505,7 @@ func newTestImageIndexName(name string) string {
return dockerRegistry.RepoName(name + "-" + h.RandString(10))
}

func parseImageIndex(t *testing.T, index string) *v1.IndexManifest {
func parseIndex(t *testing.T, index string) *v1.IndexManifest {
r := strings.NewReader(index)
idx, err := v1.ParseIndexManifest(r)
h.AssertNil(t, err)
Expand Down
Loading

0 comments on commit 4aedd4c

Please sign in to comment.