Skip to content

Commit

Permalink
Merge pull request #1757 from itsdarshankumar/extension-downloader
Browse files Browse the repository at this point in the history
Add support for extensions in pack Buildpack downloader
  • Loading branch information
jkutner authored May 19, 2023
2 parents 1aa6461 + de9c113 commit aded316
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 20 deletions.
1 change: 0 additions & 1 deletion pkg/blob/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ func (b blob) Open() (r io.ReadCloser, err error) {
defer fh.Close()
return gzr.Close()
})

return rc, nil
}

Expand Down
4 changes: 1 addition & 3 deletions pkg/buildpack/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ func (c *buildpackDownloader) Download(ctx context.Context, moduleURI string, op
return nil, nil, err
}
}

var mainBP BuildModule
var depBPs []BuildModule
switch locatorType {
Expand Down Expand Up @@ -198,13 +197,12 @@ func extractPackaged(ctx context.Context, kind string, pkgImageRef string, fetch
case KindBuildpack:
mainModule, depModules, err = extractBuildpacks(pkgImage)
case KindExtension:
return nil, nil, nil // TODO: add extractExtensions when `pack extension package` is supported in https://github.com/buildpacks/pack/issues/1489
mainModule, err = extractExtensions(pkgImage)
default:
return nil, nil, fmt.Errorf("unknown module kind: %s", kind)
}
if err != nil {
return nil, nil, errors.Wrapf(err, "extracting %ss from %s", kind, style.Symbol(pkgImageRef))
}

return mainModule, depModules, nil
}
17 changes: 17 additions & 0 deletions pkg/buildpack/downloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,23 @@ func testBuildpackDownloader(t *testing.T, when spec.G, it spec.S) {
h.AssertEq(t, mainExt.Descriptor().Info().ID, "ext.one")
})
})

when("kind == packagedExtension", func() {
it("succeeds", func() {
packagedExtensionPath := filepath.Join("testdata", "tree-extension.cnb")
packagedExtensionURI, _ := paths.FilePathToURI(packagedExtensionPath, "")
mockDownloader.EXPECT().Download(gomock.Any(), packagedExtensionURI).Return(blob.NewBlob(packagedExtensionPath), nil).AnyTimes()
downloadOptions = buildpack.DownloadOptions{
ImageOS: "linux",
ModuleKind: "extension",
RelativeBaseDir: "testdata",
Daemon: true,
PullPolicy: image.PullAlways,
}
mainExt, _, _ := buildpackDownloader.Download(context.TODO(), "tree-extension.cnb", downloadOptions)
h.AssertEq(t, mainExt.Descriptor().Info().ID, "samples-tree")
})
})
})

when("package image is not a valid package", func() {
Expand Down
1 change: 0 additions & 1 deletion pkg/buildpack/locator_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ func parseNakedLocator(locator, relativeBaseDir string, buildpacksFromBuilder []
// 2. Does it match a buildpack ID in the builder
// 3. Does it look like a Buildpack Registry ID
// 4. Does it look like a Docker ref

if isLocalFile(locator, relativeBaseDir) {
return URILocator
}
Expand Down
32 changes: 24 additions & 8 deletions pkg/buildpack/oci_layout_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"path"
"strings"
Expand Down Expand Up @@ -41,7 +42,7 @@ func IsOCILayoutBlob(blob blob2.Blob) (bool, error) {

// BuildpacksFromOCILayoutBlob constructs buildpacks from a blob in OCI layout format.
func BuildpacksFromOCILayoutBlob(blob Blob) (mainBP BuildModule, dependencies []BuildModule, err error) {
layoutPackage, err := newOCILayoutPackage(blob)
layoutPackage, err := newOCILayoutPackage(blob, KindBuildpack)
if err != nil {
return nil, nil, err
}
Expand All @@ -51,11 +52,16 @@ func BuildpacksFromOCILayoutBlob(blob Blob) (mainBP BuildModule, dependencies []

// ExtensionsFromOCILayoutBlob constructs extensions from a blob in OCI layout format.
func ExtensionsFromOCILayoutBlob(blob Blob) (mainExt BuildModule, err error) {
return nil, nil // TODO: add extractExtensions when `pack extension package` is supported in https://github.com/buildpacks/pack/issues/1489
layoutPackage, err := newOCILayoutPackage(blob, KindExtension)
if err != nil {
return nil, err
}

return extractExtensions(layoutPackage)
}

func ConfigFromOCILayoutBlob(blob Blob) (config v1.ImageConfig, err error) {
layoutPackage, err := newOCILayoutPackage(blob)
layoutPackage, err := newOCILayoutPackage(blob, KindBuildpack)
if err != nil {
return v1.ImageConfig{}, err
}
Expand All @@ -68,7 +74,7 @@ type ociLayoutPackage struct {
blob Blob
}

func newOCILayoutPackage(blob Blob) (*ociLayoutPackage, error) {
func newOCILayoutPackage(blob Blob, kind string) (*ociLayoutPackage, error) {
index := &v1.Index{}

if err := unmarshalJSONFromBlob(blob, "/index.json", index); err != nil {
Expand Down Expand Up @@ -96,10 +102,20 @@ func newOCILayoutPackage(blob Blob) (*ociLayoutPackage, error) {
if err := unmarshalJSONFromBlob(blob, pathFromDescriptor(manifest.Config), imageInfo); err != nil {
return nil, err
}

layersLabel := imageInfo.Config.Labels[dist.BuildpackLayersLabel]
if layersLabel == "" {
return nil, errors.Errorf("label %s not found", style.Symbol(dist.BuildpackLayersLabel))
var layersLabel string
switch kind {
case KindBuildpack:
layersLabel = imageInfo.Config.Labels[dist.BuildpackLayersLabel]
if layersLabel == "" {
return nil, errors.Errorf("label %s not found", style.Symbol(dist.BuildpackLayersLabel))
}
case KindExtension:
layersLabel = imageInfo.Config.Labels[dist.ExtensionLayersLabel]
if layersLabel == "" {
return nil, errors.Errorf("label %s not found", style.Symbol(dist.ExtensionLayersLabel))
}
default:
return nil, fmt.Errorf("unknown module kind: %s", kind)
}

bpLayers := dist.ModuleLayers{}
Expand Down
9 changes: 4 additions & 5 deletions pkg/buildpack/oci_layout_package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,18 @@ func testOCILayoutPackage(t *testing.T, when spec.G, it spec.S) {
})
})

when.Pend("#ExtensionsFromOCILayoutBlob", func() { // TODO: add fixture when `pack extension package` is supported in https://github.com/buildpacks/pack/issues/1489
when("#ExtensionsFromOCILayoutBlob", func() {
it("extracts buildpacks", func() {
ext, err := buildpack.ExtensionsFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "hello-extensions.cnb")))
ext, err := buildpack.ExtensionsFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "tree-extension.cnb")))
h.AssertNil(t, err)

h.AssertEq(t, ext.Descriptor().Info().ID, "io.buildpacks.samples.hello-extensions")
h.AssertEq(t, ext.Descriptor().Info().ID, "samples-tree")
h.AssertEq(t, ext.Descriptor().Info().Version, "0.0.1")
})

it("provides readable blobs", func() {
ext, err := buildpack.ExtensionsFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "hello-extensions.cnb")))
ext, err := buildpack.ExtensionsFromOCILayoutBlob(blob.NewBlob(filepath.Join("testdata", "tree-extension.cnb")))
h.AssertNil(t, err)

reader, err := ext.Open()
h.AssertNil(t, err)

Expand Down
57 changes: 57 additions & 0 deletions pkg/buildpack/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,63 @@ func extractBuildpacks(pkg Package) (mainBP BuildModule, depBPs []BuildModule, e
return mainBP, depBPs, nil
}

func extractExtensions(pkg Package) (mainExt BuildModule, err error) {
pkg = &syncPkg{pkg: pkg}
md := &Metadata{}
if found, err := dist.GetLabel(pkg, MetadataLabel, md); err != nil {
return nil, err
} else if !found {
return nil, errors.Errorf(
"could not find label %s",
style.Symbol(MetadataLabel),
)
}

pkgLayers := dist.ModuleLayers{}
ok, err := dist.GetLabel(pkg, dist.ExtensionLayersLabel, &pkgLayers)
if err != nil {
return nil, err
}

if !ok {
return nil, errors.Errorf(
"could not find label %s",
style.Symbol(dist.ExtensionLayersLabel),
)
}
for extID, v := range pkgLayers {
for extVersion, extInfo := range v {
desc := dist.ExtensionDescriptor{
WithAPI: extInfo.API,
WithInfo: dist.ModuleInfo{
ID: extID,
Version: extVersion,
Homepage: extInfo.Homepage,
Name: extInfo.Name,
},
}

diffID := extInfo.LayerDiffID // Allow use in closure
b := &openerBlob{
opener: func() (io.ReadCloser, error) {
rc, err := pkg.GetLayer(diffID)
if err != nil {
return nil, errors.Wrapf(err,
"extracting extension %s layer (diffID %s)",
style.Symbol(desc.Info().FullName()),
style.Symbol(diffID),
)
}
return rc, nil
},
}

mainExt = FromBlob(&desc, b)
}
}
return mainExt, nil
}

type openerBlob struct {
opener func() (io.ReadCloser, error)
}
Expand Down
Binary file added pkg/buildpack/testdata/tree-extension.cnb
Binary file not shown.
2 changes: 0 additions & 2 deletions pkg/client/create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ func (c *Client) addConfig(ctx context.Context, kind string, config pubbldr.Modu
if err != nil {
return errors.Wrapf(err, "getting OS from %s", style.Symbol(bldr.Image().Name()))
}

mainBP, depBPs, err := c.buildpackDownloader.Download(ctx, config.URI, buildpack.DownloadOptions{
Daemon: !opts.Publish,
ImageName: config.ImageName,
Expand All @@ -273,7 +272,6 @@ func (c *Client) addConfig(ctx context.Context, kind string, config pubbldr.Modu
if err != nil {
return errors.Wrapf(err, "downloading %s", kind)
}

err = validateModule(kind, mainBP, config.URI, config.ID, config.Version)
if err != nil {
return errors.Wrapf(err, "invalid %s", kind)
Expand Down

0 comments on commit aded316

Please sign in to comment.