diff --git a/internal/build/lifecycle_execution.go b/internal/build/lifecycle_execution.go index 092fc9bf1..716317725 100644 --- a/internal/build/lifecycle_execution.go +++ b/internal/build/lifecycle_execution.go @@ -491,8 +491,16 @@ func (l *LifecycleExecution) Restore(ctx context.Context, buildCache Cache, kani registryOp = WithRegistryAccess(authConfig) } + // for export to OCI layout + layoutOp := NullOp() + layoutBindOp := NullOp() + if l.opts.Layout && l.platformAPI.AtLeast("0.12") { + layoutOp = withLayoutOperation() + layoutBindOp = WithBinds(l.opts.Volumes...) + } + dockerOp := NullOp() - if !l.opts.Publish && l.platformAPI.AtLeast("0.12") { + if !l.opts.Publish && !l.opts.Layout && l.platformAPI.AtLeast("0.12") { dockerOp = WithDaemonAccess(l.opts.DockerHost) flags = append(flags, "-daemon") } @@ -517,6 +525,8 @@ func (l *LifecycleExecution) Restore(ctx context.Context, buildCache Cache, kani flagsOp, kanikoCacheBindOp, registryOp, + layoutOp, + layoutBindOp, ) restore := phaseFactory.New(configProvider) @@ -604,10 +614,15 @@ func (l *LifecycleExecution) Analyze(ctx context.Context, buildCache, launchCach } } + layoutOp := NullOp() + if l.opts.Layout && l.platformAPI.AtLeast("0.12") { + layoutOp = withLayoutOperation() + } + flagsOp := WithFlags(flags...) var analyze RunnerCleaner - if l.opts.Publish { + if l.opts.Publish || l.opts.Layout { authConfig, err := auth.BuildEnvVar(l.opts.Keychain, l.opts.Image.String(), l.opts.RunImage, l.opts.CacheImage, l.opts.PreviousImage) if err != nil { return err @@ -627,6 +642,7 @@ func (l *LifecycleExecution) Analyze(ctx context.Context, buildCache, launchCach cacheBindOp, stackOp, runOp, + layoutOp, ) analyze = phaseFactory.New(configProvider) @@ -802,8 +818,17 @@ func (l *LifecycleExecution) Export(ctx context.Context, buildCache, launchCache expEnv, } + if l.opts.Layout && l.platformAPI.AtLeast("0.12") { + var err error + opts, err = l.appendLayoutOperations(opts) + if err != nil { + return err + } + opts = append(opts, WithBinds(l.opts.Volumes...)) + } + var export RunnerCleaner - if l.opts.Publish { + if l.opts.Publish || l.opts.Layout { authConfig, err := auth.BuildEnvVar(l.opts.Keychain, l.opts.Image.String(), l.opts.RunImage, l.opts.CacheImage, l.opts.PreviousImage) if err != nil { return err @@ -892,11 +917,15 @@ func (l *LifecycleExecution) runImageChanged() bool { } func (l *LifecycleExecution) appendLayoutOperations(opts []PhaseConfigProviderOperation) ([]PhaseConfigProviderOperation, error) { - layoutDir := filepath.Join(paths.RootDir, "layout-repo") - opts = append(opts, WithEnv("CNB_USE_LAYOUT=true", "CNB_LAYOUT_DIR="+layoutDir, "CNB_EXPERIMENTAL_MODE=warn")) + opts = append(opts, withLayoutOperation()) return opts, nil } +func withLayoutOperation() PhaseConfigProviderOperation { + layoutDir := filepath.Join(paths.RootDir, "layout-repo") + return WithEnv("CNB_USE_LAYOUT=true", "CNB_LAYOUT_DIR="+layoutDir, "CNB_EXPERIMENTAL_MODE=warn") +} + func prependArg(arg string, args []string) []string { return append([]string{arg}, args...) } diff --git a/internal/build/lifecycle_execution_test.go b/internal/build/lifecycle_execution_test.go index c4af17b24..7902d9ee3 100644 --- a/internal/build/lifecycle_execution_test.go +++ b/internal/build/lifecycle_execution_test.go @@ -1409,6 +1409,17 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { "-stack", ) }) + + when("layout is true", func() { + providedLayout = true + + it("configures the phase with the expected environment variables", func() { + layoutDir := filepath.Join(paths.RootDir, "layout-repo") + h.AssertSliceContains(t, + configProvider.ContainerConfig().Env, "CNB_USE_LAYOUT=true", fmt.Sprintf("CNB_LAYOUT_DIR=%s", layoutDir), + ) + }) + }) }) when("publish", func() { @@ -1862,6 +1873,25 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { }) }) }) + + when("layout is true", func() { + when("platform >= 0.12", func() { + platformAPI = api.MustParse("0.12") + providedLayout = true + + it("it configures the phase with access to provided volumes", func() { + // this is required to read the /layout-repo + h.AssertSliceContains(t, configProvider.HostConfig().Binds, providedVolumes...) + }) + + it("configures the phase with the expected environment variables", func() { + layoutDir := filepath.Join(paths.RootDir, "layout-repo") + h.AssertSliceContains(t, + configProvider.ContainerConfig().Env, "CNB_USE_LAYOUT=true", fmt.Sprintf("CNB_LAYOUT_DIR=%s", layoutDir), + ) + }) + }) + }) }) when("#Build", func() { @@ -2053,6 +2083,22 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { }) }) }) + + when("layout is true", func() { + providedLayout = true + + it("it configures the phase with access to provided volumes", func() { + // this is required to read the /layout-repo + h.AssertSliceContains(t, configProvider.HostConfig().Binds, providedVolumes...) + }) + + it("configures the phase with the expected environment variables", func() { + layoutDir := filepath.Join(paths.RootDir, "layout-repo") + h.AssertSliceContains(t, + configProvider.ContainerConfig().Env, "CNB_USE_LAYOUT=true", fmt.Sprintf("CNB_LAYOUT_DIR=%s", layoutDir), + ) + }) + }) }) when("additional tags are specified", func() {