Skip to content

Commit

Permalink
Always set CNB_TARGET_* variables during detect, build, and generate
Browse files Browse the repository at this point in the history
when the Buildpack API version is at least 0.10.

Previously, we only set these variables when the Platform API version was at least 0.12.
But, newer Buildpack APIs expect these variables regardless of the Platform API version.
If we are on an older platform, derive the target variables from the base image OS.

Fixes #1308

Signed-off-by: Natalie Arellano <[email protected]>
  • Loading branch information
natalieparellano committed Mar 12, 2024
1 parent e955b6a commit 88dc987
Show file tree
Hide file tree
Showing 13 changed files with 57 additions and 59 deletions.
7 changes: 2 additions & 5 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ func (b *Builder) Build() (*files.BuildMetadata, error) {
)
processMap := newProcessMap()
inputs := b.getBuildInputs()
if b.AnalyzeMD.RunImage != nil && b.AnalyzeMD.RunImage.TargetMetadata != nil && b.PlatformAPI.AtLeast("0.12") {
inputs.Env = env.NewBuildEnv(append(os.Environ(), platform.EnvVarsFor(*b.AnalyzeMD.RunImage.TargetMetadata)...))
} else {
inputs.Env = env.NewBuildEnv(os.Environ())
}

filteredPlan := b.Plan

Expand Down Expand Up @@ -159,6 +154,8 @@ func (b *Builder) getBuildInputs() buildpack.BuildInputs {
BuildConfigDir: b.BuildConfigDir,
LayersDir: b.LayersDir,
PlatformDir: b.PlatformDir,
Env: env.NewBuildEnv(os.Environ()),
TargetEnv: platform.EnvVarsFor(b.AnalyzeMD.RunImageTarget(), b.Logger),
Out: b.Out,
Err: b.Err,
}
Expand Down
20 changes: 10 additions & 10 deletions builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {

executor.EXPECT().Build(*bpA, gomock.Any(), gomock.Any()).DoAndReturn(
func(_ buildpack.BpDescriptor, inputs buildpack.BuildInputs, logger llog.Logger) (buildpack.BuildOutputs, error) {
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_VERSION=")
return buildpack.BuildOutputs{}, nil
},
)
Expand All @@ -201,11 +201,11 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
dirStore.EXPECT().LookupBp("B", "v2").Return(bpB, nil)
executor.EXPECT().Build(*bpB, gomock.Any(), gomock.Any()).Do(
func(_ buildpack.BpDescriptor, inputs buildpack.BuildInputs, _ llog.Logger) (buildpack.BuildOutputs, error) {
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_VERSION=")
return buildpack.BuildOutputs{}, nil
})

Expand Down
4 changes: 4 additions & 0 deletions buildpack/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type BuildInputs struct {
LayersDir string
PlatformDir string
Env BuildEnv
TargetEnv []string
Out, Err io.Writer
Plan Plan
}
Expand Down Expand Up @@ -154,6 +155,9 @@ func runBuildCmd(d BpDescriptor, bpLayersDir, planPath string, inputs BuildInput
EnvLayersDir+"="+bpLayersDir,
)
}
if api.MustParse(d.API()).AtLeast("0.10") {
cmd.Env = append(cmd.Env, inputs.TargetEnv...)
}

if err = cmd.Run(); err != nil {
return NewError(err, ErrTypeBuildpack)
Expand Down
4 changes: 4 additions & 0 deletions buildpack/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type DetectInputs struct {
BuildConfigDir string
PlatformDir string
Env BuildEnv
TargetEnv []string
}

type DetectOutputs struct {
Expand Down Expand Up @@ -181,6 +182,9 @@ func runDetect(d detectable, inputs DetectInputs, planPath string, envRootDirKey
EnvBuildPlanPath+"="+planPath,
)
}
if api.MustParse(d.API()).AtLeast("0.10") {
cmd.Env = append(cmd.Env, inputs.TargetEnv...)
}

if err := cmd.Run(); err != nil {
if err, ok := err.(*exec.ExitError); ok {
Expand Down
5 changes: 5 additions & 0 deletions buildpack/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os/exec"
"path/filepath"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/internal/extend"
"github.com/buildpacks/lifecycle/launch"
"github.com/buildpacks/lifecycle/log"
Expand All @@ -25,6 +26,7 @@ type GenerateInputs struct {
OutputDir string // a temp directory provided by the lifecycle to capture extensions output
PlatformDir string
Env BuildEnv
TargetEnv []string
Out, Err io.Writer
Plan Plan
}
Expand Down Expand Up @@ -97,6 +99,9 @@ func runGenerateCmd(d ExtDescriptor, extOutputDir, planPath string, inputs Gener
EnvOutputDir+"="+extOutputDir,
EnvPlatformDir+"="+inputs.PlatformDir,
)
if api.MustParse(d.API()).AtLeast("0.10") {
cmd.Env = append(cmd.Env, inputs.TargetEnv...)
}

if err := cmd.Run(); err != nil {
return NewError(err, ErrTypeBuildpack)
Expand Down
7 changes: 2 additions & 5 deletions detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,8 @@ func (d *Detector) detectGroup(group buildpack.Group, done []buildpack.GroupElem
AppDir: d.AppDir,
BuildConfigDir: d.BuildConfigDir,
PlatformDir: d.PlatformDir,
}
if d.AnalyzeMD.RunImage != nil && d.AnalyzeMD.RunImage.TargetMetadata != nil && d.PlatformAPI.AtLeast("0.12") {
inputs.Env = env.NewBuildEnv(append(os.Environ(), platform.EnvVarsFor(*d.AnalyzeMD.RunImage.TargetMetadata)...))
} else {
inputs.Env = env.NewBuildEnv(os.Environ())
Env: env.NewBuildEnv(os.Environ()),
TargetEnv: platform.EnvVarsFor(d.AnalyzeMD.RunImageTarget(), d.Logger),
}
d.Runs.Store(key, d.Executor.Detect(descriptor, inputs, d.Logger)) // this is where we finally invoke bin/detect
}
Expand Down
10 changes: 5 additions & 5 deletions detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ func testDetector(t *testing.T, when spec.G, it spec.S) {
dirStore.EXPECT().LookupBp("A", "v1").Return(bpA1, nil).AnyTimes()
executor.EXPECT().Detect(bpA1, gomock.Any(), gomock.Any()).Do(
func(_ buildpack.Descriptor, inputs buildpack.DetectInputs, _ log.Logger) buildpack.DetectOutputs {
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_VERSION=")
return buildpack.DetectOutputs{}
})

Expand Down
5 changes: 0 additions & 5 deletions env/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ import (
// BuildEnvIncludelist are env vars that, if set in the lifecycle's execution environment - either in a builder or by the platform, are passed-through to buildpack executables
var BuildEnvIncludelist = []string{
"CNB_STACK_ID", // deprecated as of api 0.12.0
"CNB_TARGET_OS",
"CNB_TARGET_ARCH",
"CNB_TARGET_ARCH_VARIANT",
"CNB_TARGET_DISTRO_NAME",
"CNB_TARGET_DISTRO_VERSION",
"HOSTNAME",
"HOME",
"HTTPS_PROXY",
Expand Down
10 changes: 0 additions & 10 deletions env/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ func testBuildEnv(t *testing.T, when spec.G, it spec.S) {
it("includes expected vars", func() {
benv := env.NewBuildEnv([]string{
"CNB_STACK_ID=some-stack-id",
"CNB_TARGET_ARCH=st-louis",
"CNB_TARGET_ARCH_VARIANT=suburban",
"CNB_TARGET_OS=BeOS",
"CNB_TARGET_DISTRO_NAME=web",
"CNB_TARGET_DISTRO_VERSION=3.0",
"HOSTNAME=some-hostname",
"HOME=some-home",
"HTTPS_PROXY=some-https-proxy",
Expand All @@ -59,11 +54,6 @@ func testBuildEnv(t *testing.T, when spec.G, it spec.S) {
sort.Strings(out)
expectedVars := []string{
"CNB_STACK_ID=some-stack-id",
"CNB_TARGET_ARCH=st-louis",
"CNB_TARGET_ARCH_VARIANT=suburban",
"CNB_TARGET_DISTRO_NAME=web",
"CNB_TARGET_DISTRO_VERSION=3.0",
"CNB_TARGET_OS=BeOS",
"CPATH=some-cpath",
"HOME=some-home",
"HOSTNAME=some-hostname",
Expand Down
4 changes: 1 addition & 3 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,6 @@ func (g *Generator) Generate() (GenerateResult, error) {
g.Logger.Debug("Finding plan")
inputs.Plan = filteredPlan.Find(buildpack.KindExtension, ext.ID)

if g.AnalyzedMD.RunImage != nil && g.AnalyzedMD.RunImage.TargetMetadata != nil && g.PlatformAPI.AtLeast("0.12") {
inputs.Env = env.NewBuildEnv(append(inputs.Env.List(), platform.EnvVarsFor(*g.AnalyzedMD.RunImage.TargetMetadata)...))
}
g.Logger.Debug("Invoking command")
result, err := g.Executor.Generate(*descriptor, inputs, g.Logger)
if err != nil {
Expand Down Expand Up @@ -195,6 +192,7 @@ func (g *Generator) getGenerateInputs() buildpack.GenerateInputs {
BuildConfigDir: g.BuildConfigDir,
PlatformDir: g.PlatformDir,
Env: env.NewBuildEnv(os.Environ()),
TargetEnv: platform.EnvVarsFor(g.AnalyzedMD.RunImageTarget(), g.Logger),
Out: g.Out,
Err: g.Err,
}
Expand Down
20 changes: 10 additions & 10 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,21 +270,21 @@ func testGenerator(t *testing.T, when spec.G, it spec.S) {
h.Mkfile(t, "some-extend-config.toml-content-A", extendConfigPathA)
executor.EXPECT().Generate(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
func(d buildpack.ExtDescriptor, inputs buildpack.GenerateInputs, _ *log.Logger) (buildpack.GenerateOutputs, error) {
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_OS=linux")
return buildpack.GenerateOutputs{Dockerfiles: []buildpack.DockerfileInfo{{ExtensionID: d.Extension.ID,
Kind: "build", Path: buildDockerfilePathA}}}, nil
})
executor.EXPECT().Generate(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
func(d buildpack.ExtDescriptor, inputs buildpack.GenerateInputs, _ *log.Logger) (buildpack.GenerateOutputs, error) {
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.Env.List(), "CNB_TARGET_OS=linux")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH=amd64")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_ARCH_VARIANT=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_NAME=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_DISTRO_VERSION=")
h.AssertContains(t, inputs.TargetEnv, "CNB_TARGET_OS=linux")
return buildpack.GenerateOutputs{Dockerfiles: []buildpack.DockerfileInfo{{ExtensionID: d.Extension.ID,
Kind: "build", Path: buildDockerfilePathA}}}, nil
})
Expand Down
4 changes: 2 additions & 2 deletions platform/run_image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func testRunImage(t *testing.T, when spec.G, it spec.S) {
when(".EnvVarsFor", func() {
it("returns the right thing", func() {
tm := files.TargetMetadata{Arch: "pentium", ArchVariant: "mmx", ID: "my-id", OS: "linux", Distro: &files.OSDistro{Name: "nix", Version: "22.11"}}
observed := platform.EnvVarsFor(tm)
observed := platform.EnvVarsFor(tm, nil)
h.AssertContains(t, observed, "CNB_TARGET_ARCH="+tm.Arch)
h.AssertContains(t, observed, "CNB_TARGET_ARCH_VARIANT="+tm.ArchVariant)
h.AssertContains(t, observed, "CNB_TARGET_DISTRO_NAME="+tm.Distro.Name)
Expand All @@ -161,7 +161,7 @@ func testRunImage(t *testing.T, when spec.G, it spec.S) {

it("does not return the wrong thing", func() {
tm := files.TargetMetadata{Arch: "pentium", OS: "linux"}
observed := platform.EnvVarsFor(tm)
observed := platform.EnvVarsFor(tm, nil)
h.AssertContains(t, observed, "CNB_TARGET_ARCH="+tm.Arch)
h.AssertContains(t, observed, "CNB_TARGET_OS="+tm.OS)
// note: per the spec only the ID field is optional, so I guess the others should always be set: https://github.com/buildpacks/rfcs/blob/main/text/0096-remove-stacks-mixins.md#runtime-metadata
Expand Down
16 changes: 12 additions & 4 deletions platform/target_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ import (
"github.com/buildpacks/lifecycle/platform/files"
)

// Fulfills the prophecy set forth in https://github.com/buildpacks/rfcs/blob/b8abe33f2bdc58792acf0bd094dc4ce3c8a54dbb/text/0096-remove-stacks-mixins.md?plain=1#L97
// EnvVarsFor fulfills the prophecy set forth in https://github.com/buildpacks/rfcs/blob/b8abe33f2bdc58792acf0bd094dc4ce3c8a54dbb/text/0096-remove-stacks-mixins.md?plain=1#L97
// by returning an array of "VARIABLE=value" strings suitable for inclusion in your environment or complete breakfast.
func EnvVarsFor(tm files.TargetMetadata) []string {
ret := []string{"CNB_TARGET_OS=" + tm.OS, "CNB_TARGET_ARCH=" + tm.Arch}
ret = append(ret, "CNB_TARGET_ARCH_VARIANT="+tm.ArchVariant)
func EnvVarsFor(tm files.TargetMetadata, logger log.Logger) []string {
// we should always have os & arch,
// if they are not populated try to get target information from the build-time base image
if tm.OS == "" {
GetTargetOSFromFileSystem(&fsutil.Detect{}, &tm, logger)
}

Check warning on line 19 in platform/target_data.go

View check run for this annotation

Codecov / codecov/patch

platform/target_data.go#L18-L19

Added lines #L18 - L19 were not covered by tests
ret := []string{
"CNB_TARGET_OS=" + tm.OS,
"CNB_TARGET_ARCH=" + tm.Arch,
"CNB_TARGET_ARCH_VARIANT=" + tm.ArchVariant,
}
var distName, distVersion string
if tm.Distro != nil {
distName = tm.Distro.Name
Expand Down

0 comments on commit 88dc987

Please sign in to comment.