Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions builder/config_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Config struct {
Run RunConfig `toml:"run"`
Build BuildConfig `toml:"build"`
Targets []dist.Target `toml:"targets"`
System dist.System `toml:"system"`
}

// ModuleCollection is a list of ModuleConfigs
Expand Down
33 changes: 33 additions & 0 deletions builder/config_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,39 @@ uri = "noop-buildpack.tgz"
})
})
})

when("system buildpack is defined", func() {
it.Before(func() {
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
[[system.pre.buildpacks]]
id = "id-1"
version = "1.0"
optional = false

[[system.post.buildpacks]]
id = "id-2"
version = "2.0"
optional = true
`), 0666))
})

it("returns a builder config", func() {
builderConfig, _, err := builder.ReadConfig(builderConfigPath)
h.AssertNil(t, err)
h.AssertEq(t, len(builderConfig.System.Pre.Buildpacks), 1)
h.AssertEq(t, len(builderConfig.System.Post.Buildpacks), 1)

// Verify system.pre.buildpacks
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].ID, "id-1")
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].Version, "1.0")
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].Optional, false)

// Verify system.post.buildpacks
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].ID, "id-2")
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].Version, "2.0")
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].Optional, true)
})
})
})

when("#ValidateConfig()", func() {
Expand Down
85 changes: 85 additions & 0 deletions internal/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (

orderPath = "/cnb/order.toml"
stackPath = "/cnb/stack.toml"
systemPath = "/cnb/system.toml"
runPath = "/cnb/run.toml"
platformDir = "/platform"
lifecycleDir = "/cnb/lifecycle"
Expand Down Expand Up @@ -84,6 +85,7 @@ type Builder struct {
replaceOrder bool
order dist.Order
orderExtensions dist.Order
system dist.System
validateMixins bool
saveProhibited bool
}
Expand All @@ -93,6 +95,10 @@ type orderTOML struct {
OrderExt dist.Order `toml:"order-extensions,omitempty"`
}

type systemTOML struct {
System dist.System `toml:"system"`
}

// moduleWithDiffID is a Build Module which content was written on disk in a tar file and the content hash was calculated
type moduleWithDiffID struct {
tarPath string
Expand Down Expand Up @@ -303,6 +309,9 @@ func (b *Builder) Stack() StackMetadata {
return b.metadata.Stack
}

// System returns the system buildpacks configuration
func (b *Builder) System() dist.System { return b.system }

// RunImages returns all run image metadata
func (b *Builder) RunImages() []RunImageMetadata {
return append(b.metadata.RunImages, b.Stack().RunImage)
Expand Down Expand Up @@ -425,6 +434,11 @@ func (b *Builder) SetStack(stackConfig builder.StackConfig) {
}
}

// SetSystem sets the system buildpacks of the builder
func (b *Builder) SetSystem(system dist.System) {
b.system = system
}

// SetRunImage sets the run image of the builder
func (b *Builder) SetRunImage(runConfig builder.RunConfig) {
var runImages []RunImageMetadata
Expand Down Expand Up @@ -555,6 +569,24 @@ func (b *Builder) Save(logger logging.Logger, creatorMetadata CreatorMetadata) e
}
}

if len(b.system.Pre.Buildpacks) > 0 || len(b.system.Post.Buildpacks) > 0 {
resolvedSystemBp, err := processSystem(b.metadata.Buildpacks, b.system, buildpack.KindBuildpack)
if err != nil {
return errors.Wrap(err, "processing system buildpacks")
}

systemTar, err := b.systemLayer(resolvedSystemBp, tmpDir)
if err != nil {
return err
}
if err := b.image.AddLayer(systemTar); err != nil {
return errors.Wrap(err, "adding system.tar layer")
}
if err := dist.SetLabel(b.image, SystemLabel, b.system); err != nil {
return err
}
}

stackTar, err := b.stackLayer(tmpDir)
if err != nil {
return err
Expand Down Expand Up @@ -766,6 +798,36 @@ func processOrder(modulesOnBuilder []dist.ModuleInfo, order dist.Order, kind str
return resolved, nil
}

func processSystem(modulesOnBuilder []dist.ModuleInfo, system dist.System, kind string) (dist.System, error) {
resolved := dist.System{}

// Pre buildpacks
for _, bp := range system.Pre.Buildpacks {
var (
ref dist.ModuleRef
err error
)
if ref, err = resolveRef(modulesOnBuilder, bp, kind); err != nil {
return dist.System{}, err
}
resolved.Pre.Buildpacks = append(resolved.Pre.Buildpacks, ref)
}

// Post buildpacks
for _, bp := range system.Post.Buildpacks {
var (
ref dist.ModuleRef
err error
)
if ref, err = resolveRef(modulesOnBuilder, bp, kind); err != nil {
return dist.System{}, err
}
resolved.Post.Buildpacks = append(resolved.Post.Buildpacks, ref)
}

return resolved, nil
}

func resolveRef(moduleList []dist.ModuleInfo, ref dist.ModuleRef, kind string) (dist.ModuleRef, error) {
var matching []dist.ModuleInfo
for _, bp := range moduleList {
Expand Down Expand Up @@ -1093,6 +1155,29 @@ func orderFileContents(order dist.Order, orderExt dist.Order) (string, error) {
return buf.String(), nil
}

func (b *Builder) systemLayer(system dist.System, dest string) (string, error) {
contents, err := systemFileContents(system)
if err != nil {
return "", err
}
layerTar := filepath.Join(dest, "system.tar")
err = layer.CreateSingleFileTar(layerTar, systemPath, contents, b.layerWriterFactory)
if err != nil {
return "", errors.Wrapf(err, "failed to create system.toml layer tar")
}

return layerTar, nil
}

func systemFileContents(system dist.System) (string, error) {
buf := &bytes.Buffer{}
tomlData := systemTOML{System: system}
if err := toml.NewEncoder(buf).Encode(tomlData); err != nil {
return "", errors.Wrapf(err, "failed to system.toml")
Comment thread
jjbustamante marked this conversation as resolved.
Outdated
}
return buf.String(), nil
}

func (b *Builder) stackLayer(dest string) (string, error) {
buf := &bytes.Buffer{}
var err error
Expand Down
31 changes: 30 additions & 1 deletion internal/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,8 +920,37 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
h.AssertTrue(t, strings.Contains(layers[2], h.LayerFileName(ext2v1)))
})
})
})

when("system buildpacks", func() {
it.Before(func() {
subject.SetLifecycle(mockLifecycle)
subject.AddBuildpack(bp1v1)
subject.SetSystem(dist.System{
Pre: dist.SystemBuildpacks{
Buildpacks: []dist.ModuleRef{
{ModuleInfo: dist.ModuleInfo{ID: bp1v1.Descriptor().Info().ID}}},
},
})
})

it("should write system buildpacks to system.toml)", func() {
err := subject.Save(logger, builder.CreatorMetadata{})
h.AssertNil(t, err)

layerTar, err := baseImage.FindLayerWithPath("/cnb/system.toml")
h.AssertNil(t, err)
h.AssertOnTarEntry(t, layerTar, "/cnb/system.toml", h.ContentEquals(`[system]
[system.pre]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@natalieparellano could you give me a hint here, I don't know how to avoid writing this key to the system.toml . Did I do something wrong in the dist file?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure I follow - looks like valid TOML to me. Are you trying to avoid specifying the super tables? These are probably being inserted by our serializer.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

When I write the system.toml I ended up with

[system]
  [system.pre]
    [[system.pre.buildpacks]]
        id = "buildpack-1-id"
        version = "buildpack-1-version-1"

but we probably don't want the system.pre to be there, just:

[system]
    [[system.pre.buildpacks]]
        id = "buildpack-1-id"
        version = "buildpack-1-version-1"

if it is not gonna hurt anybody, I am ok with living it as it is, but I wasn't sure

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@jkutner, I am trying to implement the System Buildpacks RFC and I have some doubts with the system.toml


[[system.pre.buildpacks]]
id = "buildpack-1-id"
version = "buildpack-1-version-1"
`))
// TODO: do we always need to show optional = false?
// TODO: how do I remove [system.pre] ??
})
})
})
when("#SetLifecycle", func() {
it.Before(func() {
h.AssertNil(t, subject.Save(logger, builder.CreatorMetadata{}))
Expand Down
1 change: 1 addition & 0 deletions internal/builder/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "github.com/buildpacks/pack/pkg/dist"
const (
OrderLabel = "io.buildpacks.buildpack.order"
OrderExtensionsLabel = "io.buildpacks.buildpack.order-extensions"
SystemLabel = "io.buildpacks.buildpack.system"
)

type Metadata struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/client/create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func (c *Client) createBuilderTarget(ctx context.Context, opts CreateBuilderOpti

bldr.SetOrder(opts.Config.Order)
bldr.SetOrderExtensions(opts.Config.OrderExtensions)
bldr.SetSystem(opts.Config.System)

if opts.Config.Stack.ID != "" {
bldr.SetStack(opts.Config.Stack)
Expand Down
9 changes: 9 additions & 0 deletions pkg/dist/dist.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ type OrderEntry struct {
Group []ModuleRef `toml:"group" json:"group"`
}

type System struct {
Pre SystemBuildpacks `toml:"pre,omitempty" json:"pre,omitempty"`
Post SystemBuildpacks `toml:"post,omitempty" json:"post,omitempty"`
}

type SystemBuildpacks struct {
Buildpacks []ModuleRef `toml:"buildpacks,omitempty" json:"buildpacks,omitempty"`
}

type ModuleRef struct {
ModuleInfo `yaml:"buildpackinfo,inline"`
Optional bool `toml:"optional,omitempty" json:"optional,omitempty" yaml:"optional,omitempty"`
Expand Down