Skip to content

Commit

Permalink
Implement Buildpack API 0.5
Browse files Browse the repository at this point in the history
* Writes BOM entries to launch.toml
* Writes Build BOM entries to build.toml
* Writes unmet plan entries to build.toml
* Does not modify buildpack plan

Signed-off-by: Emily Casey <ecasey@vmware.com>
  • Loading branch information
ekcasey committed Feb 1, 2021
1 parent d530f08 commit 30ddc33
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 111 deletions.
42 changes: 40 additions & 2 deletions application.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ type Slice struct {
Paths []string `toml:"paths"`
}

// Launch represents the contents of launch.toml.
type Launch struct {
// LaunchTOML represents the contents of launch.toml.
type LaunchTOML struct {

// Labels is the collection of image labels contributed by the buildpack.
Labels []Label `toml:"labels"`
Expand All @@ -67,6 +67,44 @@ type Launch struct {

// Slices is the collection of slices contributed by the buildpack.
Slices []Slice `toml:"slices"`

// BOM is a collection of entries for the bill of materials.
BOM []BOMEntry `toml:"bom"`
}

func (l LaunchTOML) isEmpty() bool {
return len(l.Labels) == 0 && len(l.Processes) == 0 && len(l.Slices) == 0 && len(l.BOM) == 0
}

// BuildTOML represents the contents of build.toml.
type BuildTOML struct {
// BOM contains the build-time bill of materials.
BOM []BOMEntry `toml:"bom"`

// Unmet is a collection of buildpack plan entries that should be passed through to subsequent providers.
Unmet []UnmetPlanEntry
}

func (b BuildTOML) isEmpty() bool {
return len(b.Unmet) == 0
}

// BOMEntry contains a bill of materials entry.
type BOMEntry struct {
// Name represents the name of the entry.
Name string `toml:"name"`

// Metadata is the metadata of the entry. Optional.
Metadata map[string]interface{} `toml:"metadata,omitempty"`

// Launch indicates whether the given entry is included in app image. If launch is true the entry
// will be added to the app image Bill of Materials. Launch should be true if the entry describes
// the contents of a launch layer or app layer.
Launch bool `toml:"-"`

// Build indicates whether the given entry is available at build time. If build is true the entry
// will be added to the build Bill of Materials.
Build bool `toml:"-"`
}

// Store represents the contents of store.toml
Expand Down
75 changes: 55 additions & 20 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package libcnb

import (
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -56,6 +57,8 @@ type BuildContext struct {

// BuildResult contains the results of detection.
type BuildResult struct {
// BOM contains entries to be appended to the app image Bill of Materials and/or build Bill of Materials.
BOM *BOM

// Labels are the image labels contributed by the buildpack.
Labels []Label
Expand All @@ -66,21 +69,27 @@ type BuildResult struct {
// PersistentMetadata is metadata that is persisted even across cache cleaning.
PersistentMetadata map[string]interface{}

// Plan is the buildpack plan contributed by the buildpack.
Plan *BuildpackPlan

// Processes are the process types contributed by the buildpack.
Processes []Process

// Slices are the application slices contributed by the buildpack.
Slices []Slice

// Unmet contains buildpack plan entries that were not satisfied by the buildpack and therefore should be
// passed to subsequent providers.
Unmet []UnmetPlanEntry
}

// BOM contains all Bill of Materials entries
type BOM struct {
Entries []BOMEntry
}

// NewBuildResult creates a new BuildResult instance, initializing empty fields.
func NewBuildResult() BuildResult {
return BuildResult{
PersistentMetadata: make(map[string]interface{}),
Plan: &BuildpackPlan{},
BOM: &BOM{},
}
}

Expand All @@ -90,8 +99,10 @@ func (b BuildResult) String() string {
l = append(l, reflect.TypeOf(c).Name())
}

return fmt.Sprintf("{Labels:%+v Layers:%s PersistentMetadata:%+v Plan:%+v Processes:%+v Slices:%+v}",
b.Labels, l, b.PersistentMetadata, b.Plan, b.PersistentMetadata, b.Slices)
return fmt.Sprintf(
"{BOM: %+v, Labels:%+v Layers:%s PersistentMetadata:%+v Processes:%+v Slices:%+v, Unmet:%+v}",
b.BOM, b.Labels, l, b.PersistentMetadata, b.PersistentMetadata, b.Slices, b.Unmet,
)
}

//go:generate mockery -name Builder -case=underscore
Expand Down Expand Up @@ -154,6 +165,11 @@ func Build(builder Builder, options ...Option) {
}
logger.Debugf("Buildpack: %+v", ctx.Buildpack)

if strings.TrimSpace(ctx.Buildpack.API) != "0.5" {
config.exitHandler.Error(errors.New("this version of libcnb is only compatible with buildpack API 0.5"))
return
}

ctx.Layers = Layers{config.arguments[1]}
logger.Debugf("Layers: %+v", ctx.Layers)

Expand Down Expand Up @@ -277,12 +293,26 @@ func Build(builder Builder, options ...Option) {
}
}

if len(result.Labels) > 0 || len(result.Processes) > 0 || len(result.Slices) > 0 {
launch := Launch{
Labels: result.Labels,
Processes: result.Processes,
Slices: result.Slices,
var launchBOM, buildBOM []BOMEntry
if result.BOM != nil {
for _, entry := range result.BOM.Entries {
if entry.Launch {
launchBOM = append(launchBOM, entry)
}
if entry.Build {
buildBOM = append(buildBOM, entry)
}
}
}

launch := LaunchTOML{
Labels: result.Labels,
Processes: result.Processes,
Slices: result.Slices,
BOM: launchBOM,
}

if !launch.isEmpty() {
file = filepath.Join(ctx.Layers.Path, "launch.toml")
logger.Debugf("Writing application metadata: %s <= %+v", file, launch)
if err = config.tomlWriter.Write(file, launch); err != nil {
Expand All @@ -291,6 +321,20 @@ func Build(builder Builder, options ...Option) {
}
}

build := BuildTOML{
Unmet: result.Unmet,
BOM: buildBOM,
}

if !build.isEmpty() {
file = filepath.Join(ctx.Layers.Path, "build.toml")
logger.Debugf("Writing build metadata: %s <= %+v", file, build)
if err = config.tomlWriter.Write(file, build); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write build metadata %s\n%w", file, err))
return
}
}

if len(result.PersistentMetadata) > 0 {
store = Store{
Metadata: result.PersistentMetadata,
Expand All @@ -302,15 +346,6 @@ func Build(builder Builder, options ...Option) {
return
}
}

if result.Plan != nil && len(result.Plan.Entries) > 0 {
file = config.arguments[3]
logger.Debugf("Writing buildpack plan: %s <= %+v", file, result.Plan)
if err = config.tomlWriter.Write(file, result.Plan); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write buildpack plan %s\n%w", file, err))
return
}
}
}

func contains(candidates []string, s string) bool {
Expand Down
Loading

0 comments on commit 30ddc33

Please sign in to comment.