diff --git a/internal/build/lifecycle_executor.go b/internal/build/lifecycle_executor.go index 355fd7ae3..b19a7f851 100644 --- a/internal/build/lifecycle_executor.go +++ b/internal/build/lifecycle_executor.go @@ -16,6 +16,7 @@ import ( "github.com/buildpacks/pack/internal/container" "github.com/buildpacks/pack/pkg/cache" "github.com/buildpacks/pack/pkg/dist" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) @@ -104,6 +105,7 @@ type LifecycleOptions struct { CreationTime *time.Time Keychain authn.Keychain DetectOnly bool + FetchOptions image.FetchOptions } func NewLifecycleExecutor(logger logging.Logger, docker DockerClient) *LifecycleExecutor { diff --git a/pkg/client/build.go b/pkg/client/build.go index 5c73a2d18..840d3a940 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -294,304 +294,17 @@ var IsTrustedBuilderFunc = func(b string) bool { // If any configuration is deemed invalid, or if any lifecycle phases fail, // an error will be returned and no image produced. func (c *Client) Build(ctx context.Context, opts BuildOptions) error { - var pathsConfig layoutPathConfig - - imageRef, err := c.parseReference(opts) - if err != nil { - return errors.Wrapf(err, "invalid image name '%s'", opts.Image) - } - imgRegistry := imageRef.Context().RegistryStr() - imageName := imageRef.Name() - - if opts.Layout() { - pathsConfig, err = c.processLayoutPath(opts.LayoutConfig.InputImage, opts.LayoutConfig.PreviousInputImage) - if err != nil { - if opts.LayoutConfig.PreviousInputImage != nil { - return errors.Wrapf(err, "invalid layout paths image name '%s' or previous-image name '%s'", opts.LayoutConfig.InputImage.Name(), - opts.LayoutConfig.PreviousInputImage.Name()) - } - return errors.Wrapf(err, "invalid layout paths image name '%s'", opts.LayoutConfig.InputImage.Name()) - } - } - - appPath, err := c.processAppPath(opts.AppPath) - if err != nil { - return errors.Wrapf(err, "invalid app path '%s'", opts.AppPath) - } - - proxyConfig := c.processProxyConfig(opts.ProxyConfig) - - builderRef, err := c.processBuilderName(opts.Builder) - if err != nil { - return errors.Wrapf(err, "invalid builder '%s'", opts.Builder) - } - - rawBuilderImage, err := c.imageFetcher.Fetch(ctx, builderRef.Name(), image.FetchOptions{Daemon: true, PullPolicy: opts.PullPolicy}) - if err != nil { - return errors.Wrapf(err, "failed to fetch builder image '%s'", builderRef.Name()) - } - - builderOS, err := rawBuilderImage.OS() - if err != nil { - return errors.Wrapf(err, "getting builder OS") - } - - builderArch, err := rawBuilderImage.Architecture() - if err != nil { - return errors.Wrapf(err, "getting builder architecture") - } - - bldr, err := c.getBuilder(rawBuilderImage) - if err != nil { - return errors.Wrapf(err, "invalid builder %s", style.Symbol(opts.Builder)) - } - - fetchOptions := image.FetchOptions{ - Daemon: !opts.Publish, - PullPolicy: opts.PullPolicy, - Platform: fmt.Sprintf("%s/%s", builderOS, builderArch), - } - runImageName := c.resolveRunImage(opts.RunImage, imgRegistry, builderRef.Context().RegistryStr(), bldr.DefaultRunImage(), opts.AdditionalMirrors, opts.Publish, fetchOptions) - - if opts.Layout() { - targetRunImagePath, err := layout.ParseRefToPath(runImageName) - if err != nil { - return err - } - hostRunImagePath := filepath.Join(opts.LayoutConfig.LayoutRepoDir, targetRunImagePath) - targetRunImagePath = filepath.Join(paths.RootDir, "layout-repo", targetRunImagePath) - fetchOptions.LayoutOption = image.LayoutOption{ - Path: hostRunImagePath, - Sparse: opts.LayoutConfig.Sparse, - } - fetchOptions.Daemon = false - pathsConfig.targetRunImagePath = targetRunImagePath - pathsConfig.hostRunImagePath = hostRunImagePath - } - runImage, err := c.validateRunImage(ctx, runImageName, fetchOptions, bldr.StackID) - if err != nil { - return errors.Wrapf(err, "invalid run-image '%s'", runImageName) - } - - var runMixins []string - if _, err := dist.GetLabel(runImage, stack.MixinsLabel, &runMixins); err != nil { - return err - } - - fetchedBPs, order, err := c.processBuildpacks(ctx, bldr.Image(), bldr.Buildpacks(), bldr.Order(), bldr.StackID, opts) + lifecycleOpts, err := c.ResolveLifecycleOptions(ctx, opts) if err != nil { return err } - fetchedExs, orderExtensions, err := c.processExtensions(ctx, bldr.Image(), bldr.Extensions(), bldr.OrderExtensions(), bldr.StackID, opts) - if err != nil { - return err - } - - // Default mode: if the TrustBuilder option is not set, trust the suggested builders. - if opts.TrustBuilder == nil { - opts.TrustBuilder = IsTrustedBuilderFunc - } - - // Ensure the builder's platform APIs are supported - var builderPlatformAPIs builder.APISet - builderPlatformAPIs = append(builderPlatformAPIs, bldr.LifecycleDescriptor().APIs.Platform.Deprecated...) - builderPlatformAPIs = append(builderPlatformAPIs, bldr.LifecycleDescriptor().APIs.Platform.Supported...) - if !supportsPlatformAPI(builderPlatformAPIs) { - c.logger.Debugf("pack %s supports Platform API(s): %s", c.version, strings.Join(build.SupportedPlatformAPIVersions.AsStrings(), ", ")) - c.logger.Debugf("Builder %s supports Platform API(s): %s", style.Symbol(opts.Builder), strings.Join(builderPlatformAPIs.AsStrings(), ", ")) - return errors.Errorf("Builder %s is incompatible with this version of pack", style.Symbol(opts.Builder)) - } - - // Get the platform API version to use - lifecycleVersion := bldr.LifecycleDescriptor().Info.Version - useCreator := supportsCreator(lifecycleVersion) && opts.TrustBuilder(opts.Builder) - var ( - lifecycleOptsLifecycleImage string - lifecycleAPIs []string - ) - if !(useCreator) { - // fetch the lifecycle image - if supportsLifecycleImage(lifecycleVersion) { - lifecycleImageName := opts.LifecycleImage - if lifecycleImageName == "" { - lifecycleImageName = fmt.Sprintf("%s:%s", internalConfig.DefaultLifecycleImageRepo, lifecycleVersion.String()) - } - - lifecycleImage, err := c.imageFetcher.Fetch( - ctx, - lifecycleImageName, - image.FetchOptions{ - Daemon: true, - PullPolicy: opts.PullPolicy, - Platform: fmt.Sprintf("%s/%s", builderOS, builderArch), - }, - ) - if err != nil { - return fmt.Errorf("fetching lifecycle image: %w", err) - } - - // if lifecyle container os isn't windows, use ephemeral lifecycle to add /workspace with correct ownership - imageOS, err := lifecycleImage.OS() - if err != nil { - return errors.Wrap(err, "getting lifecycle image OS") - } - if imageOS != "windows" { - // obtain uid/gid from builder to use when extending lifecycle image - uid, gid, err := userAndGroupIDs(rawBuilderImage) - if err != nil { - return fmt.Errorf("obtaining build uid/gid from builder image: %w", err) - } - - c.logger.Debugf("Creating ephemeral lifecycle from %s with uid %d and gid %d. With workspace dir %s", lifecycleImage.Name(), uid, gid, opts.Workspace) - // extend lifecycle image with mountpoints, and use it instead of current lifecycle image - lifecycleImage, err = c.createEphemeralLifecycle(lifecycleImage, opts.Workspace, uid, gid) - if err != nil { - return err - } - c.logger.Debugf("Selecting ephemeral lifecycle image %s for build", lifecycleImage.Name()) - // cleanup the extended lifecycle image when done - defer c.docker.ImageRemove(context.Background(), lifecycleImage.Name(), types.ImageRemoveOptions{Force: true}) - } - - lifecycleOptsLifecycleImage = lifecycleImage.Name() - labels, err := lifecycleImage.Labels() - if err != nil { - return fmt.Errorf("reading labels of lifecycle image: %w", err) - } - - lifecycleAPIs, err = extractSupportedLifecycleApis(labels) - if err != nil { - return fmt.Errorf("reading api versions of lifecycle image: %w", err) - } - } - } - - usingPlatformAPI, err := build.FindLatestSupported(append( - bldr.LifecycleDescriptor().APIs.Platform.Deprecated, - bldr.LifecycleDescriptor().APIs.Platform.Supported...), - lifecycleAPIs) - if err != nil { - return fmt.Errorf("finding latest supported Platform API: %w", err) - } - if usingPlatformAPI.LessThan("0.12") { - if err = c.validateMixins(fetchedBPs, bldr, runImageName, runMixins); err != nil { - return fmt.Errorf("validating stack mixins: %w", err) - } - } - - buildEnvs := map[string]string{} - for _, envVar := range opts.ProjectDescriptor.Build.Env { - buildEnvs[envVar.Name] = envVar.Value - } - - for k, v := range opts.Env { - buildEnvs[k] = v - } - - ephemeralBuilder, err := c.createEphemeralBuilder(rawBuilderImage, buildEnvs, order, fetchedBPs, orderExtensions, fetchedExs, usingPlatformAPI.LessThan("0.12"), opts.RunImage) - if err != nil { - return err - } - defer c.docker.ImageRemove(context.Background(), ephemeralBuilder.Name(), types.ImageRemoveOptions{Force: true}) - - if len(bldr.OrderExtensions()) > 0 || len(ephemeralBuilder.OrderExtensions()) > 0 { - if builderOS == "windows" { - return fmt.Errorf("builder contains image extensions which are not supported for Windows builds") - } - if !(opts.PullPolicy == image.PullAlways) { - return fmt.Errorf("pull policy must be 'always' when builder contains image extensions") - } - } - - if opts.Layout() { - opts.ContainerConfig.Volumes = appendLayoutVolumes(opts.ContainerConfig.Volumes, pathsConfig) - } - - processedVolumes, warnings, err := processVolumes(builderOS, opts.ContainerConfig.Volumes) - if err != nil { - return err - } - - for _, warning := range warnings { - c.logger.Warn(warning) - } - - fileFilter, err := getFileFilter(opts.ProjectDescriptor) - if err != nil { - return err - } - - runImageName, err = pname.TranslateRegistry(runImageName, c.registryMirrors, c.logger) - if err != nil { - return err - } - - projectMetadata := files.ProjectMetadata{} - if c.experimental { - version := opts.ProjectDescriptor.Project.Version - sourceURL := opts.ProjectDescriptor.Project.SourceURL - if version != "" || sourceURL != "" { - projectMetadata.Source = &files.ProjectSource{ - Type: "project", - Version: map[string]interface{}{"declared": version}, - Metadata: map[string]interface{}{"url": sourceURL}, - } - } else { - projectMetadata.Source = v02.GitMetadata(opts.AppPath) - } - } - - lifecycleOpts := build.LifecycleOptions{ - AppPath: appPath, - Image: imageRef, - Builder: ephemeralBuilder, - BuilderImage: builderRef.Name(), - LifecycleImage: ephemeralBuilder.Name(), - RunImage: runImageName, - ProjectMetadata: projectMetadata, - ClearCache: opts.ClearCache, - Publish: opts.Publish, - TrustBuilder: opts.TrustBuilder(opts.Builder), - UseCreator: useCreator, - UseCreatorWithExtensions: supportsCreatorWithExtensions(lifecycleVersion), - DockerHost: opts.DockerHost, - Cache: opts.Cache, - CacheImage: opts.CacheImage, - HTTPProxy: proxyConfig.HTTPProxy, - HTTPSProxy: proxyConfig.HTTPSProxy, - NoProxy: proxyConfig.NoProxy, - Network: opts.ContainerConfig.Network, - AdditionalTags: opts.AdditionalTags, - Volumes: processedVolumes, - DefaultProcessType: opts.DefaultProcessType, - FileFilter: fileFilter, - Workspace: opts.Workspace, - GID: opts.GroupID, - UID: opts.UserID, - PreviousImage: opts.PreviousImage, - Interactive: opts.Interactive, - Termui: termui.NewTermui(imageName, ephemeralBuilder, runImageName), - ReportDestinationDir: opts.ReportDestinationDir, - SBOMDestinationDir: opts.SBOMDestinationDir, - CreationTime: opts.CreationTime, - Layout: opts.Layout(), - Keychain: c.keychain, - } - - switch { - case useCreator: - lifecycleOpts.UseCreator = true - case supportsLifecycleImage(lifecycleVersion): - lifecycleOpts.LifecycleImage = lifecycleOptsLifecycleImage - lifecycleOpts.LifecycleApis = lifecycleAPIs - case !opts.TrustBuilder(opts.Builder): - return errors.Errorf("Lifecycle %s does not have an associated lifecycle image. Builder must be trusted.", lifecycleVersion.String()) - } + defer c.docker.ImageRemove(context.Background(), lifecycleOpts.LifecycleImage, types.ImageRemoveOptions{Force: true}) + defer c.docker.ImageRemove(context.Background(), lifecycleOpts.Builder.Name(), types.ImageRemoveOptions{Force: true}) lifecycleOpts.FetchRunImageWithLifecycleLayer = func(runImageName string) (string, error) { ephemeralRunImageName := fmt.Sprintf("pack.local/run-image/%x:latest", randString(10)) - runImage, err := c.imageFetcher.Fetch(ctx, runImageName, fetchOptions) + runImage, err := c.imageFetcher.Fetch(ctx, runImageName, lifecycleOpts.FetchOptions) if err != nil { return "", err } @@ -733,10 +446,10 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { return ephemeralRunImageName, nil } - if err = c.lifecycleExecutor.Execute(ctx, lifecycleOpts); err != nil { + if err = c.lifecycleExecutor.Execute(ctx, *lifecycleOpts); err != nil { return fmt.Errorf("executing lifecycle: %w", err) } - return c.logImageNameAndSha(ctx, opts.Publish, imageRef) + return c.logImageNameAndSha(ctx, opts.Publish, lifecycleOpts.Image) } func extractSupportedLifecycleApis(labels map[string]string) ([]string, error) { @@ -1830,6 +1543,27 @@ func (c *Client) ResolveLifecycleOptions(ctx context.Context, opts BuildOptions) return nil, fmt.Errorf("fetching lifecycle image: %w", err) } + // if lifecyle container os isn't windows, use ephemeral lifecycle to add /workspace with correct ownership + imageOS, err := lifecycleImage.OS() + if err != nil { + return nil, errors.Wrap(err, "getting lifecycle image OS") + } + if imageOS != "windows" { + // obtain uid/gid from builder to use when extending lifecycle image + uid, gid, err := userAndGroupIDs(rawBuilderImage) + if err != nil { + return nil, fmt.Errorf("obtaining build uid/gid from builder image: %w", err) + } + + c.logger.Debugf("Creating ephemeral lifecycle from %s with uid %d and gid %d. With workspace dir %s", lifecycleImage.Name(), uid, gid, opts.Workspace) + // extend lifecycle image with mountpoints, and use it instead of current lifecycle image + lifecycleImage, err = c.createEphemeralLifecycle(lifecycleImage, opts.Workspace, uid, gid) + if err != nil { + return nil, err + } + c.logger.Debugf("Selecting ephemeral lifecycle image %s for build", lifecycleImage.Name()) + } + lifecycleOptsLifecycleImage = lifecycleImage.Name() labels, err := lifecycleImage.Labels() if err != nil { @@ -1871,9 +1605,6 @@ func (c *Client) ResolveLifecycleOptions(ctx context.Context, opts BuildOptions) } if len(bldr.OrderExtensions()) > 0 || len(ephemeralBuilder.OrderExtensions()) > 0 { - if !c.experimental { - return nil, fmt.Errorf("experimental features must be enabled when builder contains image extensions") - } if builderOS == "windows" { return nil, fmt.Errorf("builder contains image extensions which are not supported for Windows builds") } @@ -1920,7 +1651,7 @@ func (c *Client) ResolveLifecycleOptions(ctx context.Context, opts BuildOptions) } } - lifecycleOpts := &build.LifecycleOptions{ + lifecycleOpts := build.LifecycleOptions{ AppPath: appPath, Image: imageRef, Builder: ephemeralBuilder, @@ -1955,7 +1686,7 @@ func (c *Client) ResolveLifecycleOptions(ctx context.Context, opts BuildOptions) CreationTime: opts.CreationTime, Layout: opts.Layout(), Keychain: c.keychain, - DetectOnly: opts.DetectOnly, + FetchOptions: fetchOptions, } switch { @@ -1968,5 +1699,284 @@ func (c *Client) ResolveLifecycleOptions(ctx context.Context, opts BuildOptions) return nil, errors.Errorf("Lifecycle %s does not have an associated lifecycle image. Builder must be trusted.", lifecycleVersion.String()) } - return lifecycleOpts, nil + return &lifecycleOpts, nil } + +// func (c *Client) ResolveLifecycleOptions2(ctx context.Context, opts BuildOptions) (*build.LifecycleOptions, error) { +// var pathsConfig layoutPathConfig + +// imageRef, err := c.parseReference(opts) +// if err != nil { +// return nil, errors.Wrapf(err, "invalid image name '%s'", opts.Image) +// } +// imgRegistry := imageRef.Context().RegistryStr() +// imageName := imageRef.Name() + +// if opts.Layout() { +// pathsConfig, err = c.processLayoutPath(opts.LayoutConfig.InputImage, opts.LayoutConfig.PreviousInputImage) +// if err != nil { +// if opts.LayoutConfig.PreviousInputImage != nil { +// return nil, errors.Wrapf(err, "invalid layout paths image name '%s' or previous-image name '%s'", opts.LayoutConfig.InputImage.Name(), +// opts.LayoutConfig.PreviousInputImage.Name()) +// } +// return nil, errors.Wrapf(err, "invalid layout paths image name '%s'", opts.LayoutConfig.InputImage.Name()) +// } +// } + +// appPath, err := c.processAppPath(opts.AppPath) +// if err != nil { +// return nil, errors.Wrapf(err, "invalid app path '%s'", opts.AppPath) +// } + +// proxyConfig := c.processProxyConfig(opts.ProxyConfig) + +// builderRef, err := c.processBuilderName(opts.Builder) +// if err != nil { +// return nil, errors.Wrapf(err, "invalid builder '%s'", opts.Builder) +// } + +// rawBuilderImage, err := c.imageFetcher.Fetch(ctx, builderRef.Name(), image.FetchOptions{Daemon: true, PullPolicy: opts.PullPolicy}) +// if err != nil { +// return nil, errors.Wrapf(err, "failed to fetch builder image '%s'", builderRef.Name()) +// } + +// builderOS, err := rawBuilderImage.OS() +// if err != nil { +// return nil, errors.Wrapf(err, "getting builder OS") +// } + +// builderArch, err := rawBuilderImage.Architecture() +// if err != nil { +// return nil, errors.Wrapf(err, "getting builder architecture") +// } + +// bldr, err := c.getBuilder(rawBuilderImage) +// if err != nil { +// return nil, errors.Wrapf(err, "invalid builder %s", style.Symbol(opts.Builder)) +// } + +// fetchOptions := image.FetchOptions{ +// Daemon: !opts.Publish, +// PullPolicy: opts.PullPolicy, +// Platform: fmt.Sprintf("%s/%s", builderOS, builderArch), +// } +// runImageName := c.resolveRunImage(opts.RunImage, imgRegistry, builderRef.Context().RegistryStr(), bldr.DefaultRunImage(), opts.AdditionalMirrors, opts.Publish, fetchOptions) + +// if opts.Layout() { +// targetRunImagePath, err := layout.ParseRefToPath(runImageName) +// if err != nil { +// return nil, err +// } +// hostRunImagePath := filepath.Join(opts.LayoutConfig.LayoutRepoDir, targetRunImagePath) +// targetRunImagePath = filepath.Join(paths.RootDir, "layout-repo", targetRunImagePath) +// fetchOptions.LayoutOption = image.LayoutOption{ +// Path: hostRunImagePath, +// Sparse: opts.LayoutConfig.Sparse, +// } +// fetchOptions.Daemon = false +// pathsConfig.targetRunImagePath = targetRunImagePath +// pathsConfig.hostRunImagePath = hostRunImagePath +// } +// runImage, err := c.validateRunImage(ctx, runImageName, fetchOptions, bldr.StackID) +// if err != nil { +// return nil, errors.Wrapf(err, "invalid run-image '%s'", runImageName) +// } + +// var runMixins []string +// if _, err := dist.GetLabel(runImage, stack.MixinsLabel, &runMixins); err != nil { +// return nil, err +// } + +// fetchedBPs, order, err := c.processBuildpacks(ctx, bldr.Image(), bldr.Buildpacks(), bldr.Order(), bldr.StackID, opts) +// if err != nil { +// return nil, err +// } + +// fetchedExs, orderExtensions, err := c.processExtensions(ctx, bldr.Image(), bldr.Extensions(), bldr.OrderExtensions(), bldr.StackID, opts) +// if err != nil { +// return nil, err +// } + +// // Default mode: if the TrustBuilder option is not set, trust the suggested builders. +// if opts.TrustBuilder == nil { +// opts.TrustBuilder = IsTrustedBuilderFunc +// } + +// // Ensure the builder's platform APIs are supported +// var builderPlatformAPIs builder.APISet +// builderPlatformAPIs = append(builderPlatformAPIs, bldr.LifecycleDescriptor().APIs.Platform.Deprecated...) +// builderPlatformAPIs = append(builderPlatformAPIs, bldr.LifecycleDescriptor().APIs.Platform.Supported...) +// if !supportsPlatformAPI(builderPlatformAPIs) { +// c.logger.Debugf("pack %s supports Platform API(s): %s", c.version, strings.Join(build.SupportedPlatformAPIVersions.AsStrings(), ", ")) +// c.logger.Debugf("Builder %s supports Platform API(s): %s", style.Symbol(opts.Builder), strings.Join(builderPlatformAPIs.AsStrings(), ", ")) +// return nil, errors.Errorf("Builder %s is incompatible with this version of pack", style.Symbol(opts.Builder)) +// } + +// // Get the platform API version to use +// lifecycleVersion := bldr.LifecycleDescriptor().Info.Version +// useCreator := supportsCreator(lifecycleVersion) && opts.TrustBuilder(opts.Builder) +// var ( +// lifecycleOptsLifecycleImage string +// lifecycleAPIs []string +// ) +// if !(useCreator) { +// // fetch the lifecycle image +// if supportsLifecycleImage(lifecycleVersion) { +// lifecycleImageName := opts.LifecycleImage +// if lifecycleImageName == "" { +// lifecycleImageName = fmt.Sprintf("%s:%s", internalConfig.DefaultLifecycleImageRepo, lifecycleVersion.String()) +// } + +// lifecycleImage, err := c.imageFetcher.Fetch( +// ctx, +// lifecycleImageName, +// image.FetchOptions{ +// Daemon: true, +// PullPolicy: opts.PullPolicy, +// Platform: fmt.Sprintf("%s/%s", builderOS, builderArch), +// }, +// ) +// if err != nil { +// return nil, fmt.Errorf("fetching lifecycle image: %w", err) +// } + +// lifecycleOptsLifecycleImage = lifecycleImage.Name() +// labels, err := lifecycleImage.Labels() +// if err != nil { +// return nil, fmt.Errorf("reading labels of lifecycle image: %w", err) +// } + +// lifecycleAPIs, err = extractSupportedLifecycleApis(labels) +// if err != nil { +// return nil, fmt.Errorf("reading api versions of lifecycle image: %w", err) +// } +// } +// } + +// usingPlatformAPI, err := build.FindLatestSupported(append( +// bldr.LifecycleDescriptor().APIs.Platform.Deprecated, +// bldr.LifecycleDescriptor().APIs.Platform.Supported...), +// lifecycleAPIs) +// if err != nil { +// return nil, fmt.Errorf("finding latest supported Platform API: %w", err) +// } +// if usingPlatformAPI.LessThan("0.12") { +// if err = c.validateMixins(fetchedBPs, bldr, runImageName, runMixins); err != nil { +// return nil, fmt.Errorf("validating stack mixins: %w", err) +// } +// } + +// buildEnvs := map[string]string{} +// for _, envVar := range opts.ProjectDescriptor.Build.Env { +// buildEnvs[envVar.Name] = envVar.Value +// } + +// for k, v := range opts.Env { +// buildEnvs[k] = v +// } + +// ephemeralBuilder, err := c.createEphemeralBuilder(rawBuilderImage, buildEnvs, order, fetchedBPs, orderExtensions, fetchedExs, usingPlatformAPI.LessThan("0.12"), opts.RunImage) +// if err != nil { +// return nil, err +// } + +// if len(bldr.OrderExtensions()) > 0 || len(ephemeralBuilder.OrderExtensions()) > 0 { +// if !c.experimental { +// return nil, fmt.Errorf("experimental features must be enabled when builder contains image extensions") +// } +// if builderOS == "windows" { +// return nil, fmt.Errorf("builder contains image extensions which are not supported for Windows builds") +// } +// if !(opts.PullPolicy == image.PullAlways) { +// return nil, fmt.Errorf("pull policy must be 'always' when builder contains image extensions") +// } +// } + +// if opts.Layout() { +// opts.ContainerConfig.Volumes = appendLayoutVolumes(opts.ContainerConfig.Volumes, pathsConfig) +// } + +// processedVolumes, warnings, err := processVolumes(builderOS, opts.ContainerConfig.Volumes) +// if err != nil { +// return nil, err +// } + +// for _, warning := range warnings { +// c.logger.Warn(warning) +// } + +// fileFilter, err := getFileFilter(opts.ProjectDescriptor) +// if err != nil { +// return nil, err +// } + +// runImageName, err = pname.TranslateRegistry(runImageName, c.registryMirrors, c.logger) +// if err != nil { +// return nil, err +// } + +// projectMetadata := files.ProjectMetadata{} +// if c.experimental { +// version := opts.ProjectDescriptor.Project.Version +// sourceURL := opts.ProjectDescriptor.Project.SourceURL +// if version != "" || sourceURL != "" { +// projectMetadata.Source = &files.ProjectSource{ +// Type: "project", +// Version: map[string]interface{}{"declared": version}, +// Metadata: map[string]interface{}{"url": sourceURL}, +// } +// } else { +// projectMetadata.Source = v02.GitMetadata(opts.AppPath) +// } +// } + +// lifecycleOpts := &build.LifecycleOptions{ +// AppPath: appPath, +// Image: imageRef, +// Builder: ephemeralBuilder, +// BuilderImage: builderRef.Name(), +// LifecycleImage: ephemeralBuilder.Name(), +// RunImage: runImageName, +// ProjectMetadata: projectMetadata, +// ClearCache: opts.ClearCache, +// Publish: opts.Publish, +// TrustBuilder: opts.TrustBuilder(opts.Builder), +// UseCreator: useCreator, +// UseCreatorWithExtensions: supportsCreatorWithExtensions(lifecycleVersion), +// DockerHost: opts.DockerHost, +// Cache: opts.Cache, +// CacheImage: opts.CacheImage, +// HTTPProxy: proxyConfig.HTTPProxy, +// HTTPSProxy: proxyConfig.HTTPSProxy, +// NoProxy: proxyConfig.NoProxy, +// Network: opts.ContainerConfig.Network, +// AdditionalTags: opts.AdditionalTags, +// Volumes: processedVolumes, +// DefaultProcessType: opts.DefaultProcessType, +// FileFilter: fileFilter, +// Workspace: opts.Workspace, +// GID: opts.GroupID, +// UID: opts.UserID, +// PreviousImage: opts.PreviousImage, +// Interactive: opts.Interactive, +// Termui: termui.NewTermui(imageName, ephemeralBuilder, runImageName), +// ReportDestinationDir: opts.ReportDestinationDir, +// SBOMDestinationDir: opts.SBOMDestinationDir, +// CreationTime: opts.CreationTime, +// Layout: opts.Layout(), +// Keychain: c.keychain, +// DetectOnly: opts.DetectOnly, +// } + +// switch { +// case useCreator: +// lifecycleOpts.UseCreator = true +// case supportsLifecycleImage(lifecycleVersion): +// lifecycleOpts.LifecycleImage = lifecycleOptsLifecycleImage +// lifecycleOpts.LifecycleApis = lifecycleAPIs +// case !opts.TrustBuilder(opts.Builder): +// return nil, errors.Errorf("Lifecycle %s does not have an associated lifecycle image. Builder must be trusted.", lifecycleVersion.String()) +// } + +// return lifecycleOpts, nil +// } diff --git a/pkg/client/detect.go b/pkg/client/detect.go index 57ce532e3..20703c9fa 100644 --- a/pkg/client/detect.go +++ b/pkg/client/detect.go @@ -13,6 +13,7 @@ func (c *Client) Detect(ctx context.Context, opts BuildOptions) error { return err } + defer c.docker.ImageRemove(context.Background(), lifecycleOpts.LifecycleImage, types.ImageRemoveOptions{Force: true}) defer c.docker.ImageRemove(context.Background(), lifecycleOpts.Builder.Name(), types.ImageRemoveOptions{Force: true}) if err = c.lifecycleExecutor.Detect(ctx, *lifecycleOpts); err != nil {