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

Support Buildpack API 0.10 #291

Merged
merged 4 commits into from
Jun 18, 2024
Merged
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
23 changes: 21 additions & 2 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,14 @@ type BuildContext struct {
// Platform is the contents of the platform.
Platform Platform

// StackID is the ID of the stack.
// Deprecated: StackID is the ID of the stack.
StackID string

// TargetInfo contains info of the target (os, arch, ...).
TargetInfo TargetInfo

// TargetDistro is the target distribution (name, version).
TargetDistro TargetDistro
}

// BuildResult contains the results of detection.
Expand Down Expand Up @@ -87,7 +93,7 @@ const (
MinSupportedBPVersion = "0.8"

// MaxSupportedBPVersion indicates the maximum supported version of the Buildpacks API
MaxSupportedBPVersion = "0.9"
MaxSupportedBPVersion = "0.10"
)

// NewBuildResult creates a new BuildResult instance, initializing empty fields.
Expand Down Expand Up @@ -231,6 +237,19 @@ func Build(build BuildFunc, config Config) {
config.logger.Debugf("Stack: %s", ctx.StackID)
}

if API.GreaterThan(semver.MustParse("0.9")) {
ctx.TargetInfo = TargetInfo{}
ctx.TargetInfo.OS, _ = os.LookupEnv(EnvTargetOS)
ctx.TargetInfo.Arch, _ = os.LookupEnv(EnvTargetArch)
ctx.TargetInfo.Variant, _ = os.LookupEnv(EnvTargetArchVariant)
config.logger.Debugf("System: %+v", ctx.TargetInfo)

ctx.TargetDistro = TargetDistro{}
ctx.TargetDistro.Name, _ = os.LookupEnv(EnvTargetDistroName)
ctx.TargetDistro.Version, _ = os.LookupEnv(EnvTargetDistroVersion)
config.logger.Debugf("Distro: %+v", ctx.TargetDistro)
}

result, err := build(ctx)
if err != nil {
config.exitHandler.Error(err)
Expand Down
75 changes: 75 additions & 0 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ test-key = "test-value"
Expect(os.Setenv("CNB_PLATFORM_DIR", platformPath)).To(Succeed())
Expect(os.Setenv("CNB_BP_PLAN_PATH", buildpackPlanPath)).To(Succeed())

Expect(os.Setenv("CNB_TARGET_OS", "linux")).To(Succeed())
Expect(os.Setenv("CNB_TARGET_ARCH", "arm")).To(Succeed())
Expect(os.Setenv("CNB_TARGET_ARCH_VARIANT", "v6")).To(Succeed())
Expect(os.Setenv("CNB_TARGET_DISTRO_NAME", "ubuntu")).To(Succeed())
Expect(os.Setenv("CNB_TARGET_DISTRO_VERSION", "24.04")).To(Succeed())

workingDir, err = os.Getwd()
Expect(err).NotTo(HaveOccurred())
Expect(os.Chdir(applicationPath)).To(Succeed())
Expand All @@ -178,6 +184,12 @@ test-key = "test-value"
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())

Expect(os.Unsetenv("CNB_TARGET_OS"))
Expect(os.Unsetenv("CNB_TARGET_ARCH"))
Expect(os.Unsetenv("CNB_TARGET_ARCH_VARIANT"))
Expect(os.Unsetenv("CNB_TARGET_DISTRO_NAME"))
Expect(os.Unsetenv("CNB_TARGET_DISTRO_VERSION"))

Expect(os.RemoveAll(applicationPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPlanPath)).To(Succeed())
Expand Down Expand Up @@ -320,6 +332,69 @@ version = "1.1.1"
})
})

context("has a build environment specifying target metadata", func() {
var ctx libcnb.BuildContext

it.Before(func() {
Expect(os.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.10"

[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"

[[targets]]
os = "linux"
arch = "amd64"

[[targets.distros]]
name = "ubuntu"
version = "18.04"

[[targets.distros]]
name = "debian"

[[targets]]
os = "linux"
arch = "arm"
variant = "v6"
`), 0600),
).To(Succeed())

buildFunc = func(context libcnb.BuildContext) (libcnb.BuildResult, error) {
ctx = context
return libcnb.NewBuildResult(), nil
}
})

it("provides target information", func() {
libcnb.Build(buildFunc,
libcnb.NewConfig(
libcnb.WithArguments([]string{commandPath}),
libcnb.WithLogger(log.New(os.Stdout)),
),
)

Expect(ctx.Buildpack.Targets).To(HaveLen(2))
Expect(ctx.Buildpack.Targets[0].OS).To(Equal("linux"))
Expect(ctx.Buildpack.Targets[0].Arch).To(Equal("amd64"))
Expect(ctx.Buildpack.Targets[0].Distros).To(HaveLen(2))
Expect(ctx.Buildpack.Targets[0].Distros[0].Name).To(Equal("ubuntu"))
Expect(ctx.Buildpack.Targets[0].Distros[0].Version).To(Equal("18.04"))
Expect(ctx.Buildpack.Targets[0].Distros[1].Name).To(Equal("debian"))

Expect(ctx.Buildpack.Targets[1].Variant).To(Equal("v6"))

Expect(ctx.TargetInfo.OS).To(Equal("linux"))
Expect(ctx.TargetInfo.Arch).To(Equal("arm"))
Expect(ctx.TargetInfo.Variant).To(Equal("v6"))
Expect(ctx.TargetDistro.Name).To(Equal("ubuntu"))
Expect(ctx.TargetDistro.Version).To(Equal("24.04"))
})
})

it("fails if CNB_BUILDPACK_DIR is not set", func() {
Expect(os.Unsetenv("CNB_BUILDPACK_DIR")).To(Succeed())

Expand Down
36 changes: 34 additions & 2 deletions buildpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type BuildpackOrder struct {
Groups []BuildpackOrderBuildpack `toml:"group"`
}

// BuildpackStack is a stack supported by the buildpack.
// Deprecated: BuildpackStack is a stack supported by the buildpack.
type BuildpackStack struct {
// ID is the id of the stack.
ID string `toml:"id"`
Expand All @@ -85,6 +85,35 @@ type BuildpackStack struct {
Mixins []string `toml:"mixins"`
}

// TargetDistro is the supported target distro
type TargetDistro struct {
// Name is the name of the supported distro.
Name string `toml:"name"`

// Version is the version of the supported distro.
Version string `toml:"version"`
}

// TargetInfo is the supported target
type TargetInfo struct {
// OS is the supported os.
OS string `toml:"os"`

// Arch is the supported architecture.
Arch string `toml:"arch"`

// Variant is the supported variant of the architecture.
Variant string `toml:"variant"`
}

// Target is a target supported by the buildpack.
type Target struct {
TargetInfo

// Distros is the collection of distros associated with the target.
Distros []TargetDistro `toml:"distros"`
}

// Buildpack is the contents of the buildpack.toml file.
type Buildpack struct {
// API is the api version expected by the buildpack.
Expand All @@ -96,9 +125,12 @@ type Buildpack struct {
// Path is the path to the buildpack.
Path string `toml:"-"`

// Stacks is the collection of stacks supported by the buildpack.
// Deprecated: Stacks is the collection of stacks supported by the buildpack.
Stacks []BuildpackStack `toml:"stacks"`

// Targets is the collection of targets supported by the buildpack.
Targets []Target `toml:"targets"`

// Metadata is arbitrary metadata attached to the buildpack.
Metadata map[string]interface{} `toml:"metadata"`
}
3 changes: 3 additions & 0 deletions extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type Extension struct {
// Path is the path to the extension.
Path string `toml:"-"`

// Targets is the collection of targets supported by the buildpack.
Targets []Target `toml:"targets"`

// Metadata is arbitrary metadata attached to the extension.
Metadata map[string]interface{} `toml:"metadata"`
}
76 changes: 72 additions & 4 deletions generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,44 @@ type GenerateContext struct {
// Platform is the contents of the platform.
Platform Platform

// StackID is the ID of the stack.
// TargetInfo contains info of the target (os, arch, ...).
TargetInfo TargetInfo

// TargetDistro is the target distribution (name, version).
TargetDistro TargetDistro

// Deprecated: StackID is the ID of the stack.
StackID string
}

// GenerateResult contains the results of detection.
type GenerateResult struct {
// Unmet contains buildpack plan entries that were not satisfied by the buildpack and therefore should be
// passed to subsequent providers.
Unmet []UnmetPlanEntry
Unmet []UnmetPlanEntry
RunDockerfile []byte
BuildDockerfile []byte
Config *ExtendConfig
}

// DockerfileArg is a Dockerfile argument
type DockerfileArg struct {
Name string `toml:"name"`
Value string `toml:"value"`
}

// NewBuildResult creates a new BuildResult instance, initializing empty fields.
// BuildConfig contains additional arguments passed to the generated Dockerfiles
type BuildConfig struct {
Args []DockerfileArg `toml:"args"`
}

// ExtendConfig contains additional configuration for the Dockerfiles
type ExtendConfig struct {
Build BuildConfig `toml:"build"`
Run BuildConfig `toml:"run"`
}

// NewGenerateResult creates a new BuildResult instance, initializing empty fields.
func NewGenerateResult() GenerateResult {
return GenerateResult{}
}
Expand All @@ -73,7 +99,7 @@ func (b GenerateResult) String() string {
)
}

// BuildFunc takes a context and returns a result, performing extension generate behaviors.
// GenerateFunc takes a context and returns a result, performing extension generate behaviors.
type GenerateFunc func(context GenerateContext) (GenerateResult, error)

// Generate is called by the main function of a extension, for generate phase
Expand Down Expand Up @@ -184,10 +210,52 @@ func Generate(generate GenerateFunc, config Config) {
config.logger.Debugf("Stack: %s", ctx.StackID)
}

if API.GreaterThan(semver.MustParse("0.9")) {
ctx.TargetInfo = TargetInfo{}
ctx.TargetInfo.OS, _ = os.LookupEnv(EnvTargetOS)
ctx.TargetInfo.Arch, _ = os.LookupEnv(EnvTargetArch)
ctx.TargetInfo.Variant, _ = os.LookupEnv(EnvTargetArchVariant)
config.logger.Debugf("System: %+v", ctx.TargetInfo)

ctx.TargetDistro = TargetDistro{}
ctx.TargetDistro.Name, _ = os.LookupEnv(EnvTargetDistroName)
ctx.TargetDistro.Version, _ = os.LookupEnv(EnvTargetDistroVersion)
config.logger.Debugf("Distro: %+v", ctx.TargetDistro)
}

result, err := generate(ctx)
if err != nil {
config.exitHandler.Error(err)
return
}
config.logger.Debugf("Result: %+v", result)

if len(result.RunDockerfile) > 0 {
// #nosec
if err := os.WriteFile(filepath.Join(ctx.OutputDirectory, "run.Dockerfile"), result.RunDockerfile, 0644); err != nil {
config.exitHandler.Error(err)
return
}
}

if len(result.BuildDockerfile) > 0 {
// #nosec
if err := os.WriteFile(filepath.Join(ctx.OutputDirectory, "build.Dockerfile"), result.BuildDockerfile, 0644); err != nil {
config.exitHandler.Error(err)
return
}
}

if result.Config != nil {
configFile, err := os.Create(filepath.Join(ctx.OutputDirectory, "extend-config.toml"))
if err != nil {
config.exitHandler.Error(err)
return
}

if err := toml.NewEncoder(configFile).Encode(result.Config); err != nil {
config.exitHandler.Error(err)
return
}
}
}
Loading