diff --git a/pkg/compose/build_bake.go b/pkg/compose/build_bake.go index 777e69942a6..a2a8a59cc44 100644 --- a/pkg/compose/build_bake.go +++ b/pkg/compose/build_bake.go @@ -37,10 +37,10 @@ import ( "github.com/containerd/errdefs" "github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/command/image/build" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/progress" "github.com/docker/docker/api/types/versions" - "github.com/docker/docker/builder/remotecontext/urlutil" "github.com/moby/buildkit/client" gitutil "github.com/moby/buildkit/frontend/dockerfile/dfgitutil" "github.com/moby/buildkit/util/progress/progressui" @@ -505,7 +505,7 @@ func dockerFilePath(ctxName string, dockerfile string) string { if dockerfile == "" { return "" } - if urlutil.IsGitURL(ctxName) { + if contextType, _ := build.DetectContextType(ctxName); contextType == build.ContextTypeGit { return dockerfile } if !filepath.IsAbs(dockerfile) { diff --git a/pkg/compose/build_classic.go b/pkg/compose/build_classic.go index 7e85b5bf201..a84929193e5 100644 --- a/pkg/compose/build_classic.go +++ b/pkg/compose/build_classic.go @@ -34,7 +34,6 @@ import ( buildtypes "github.com/docker/docker/api/types/build" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/registry" - "github.com/docker/docker/builder/remotecontext/urlutil" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" @@ -48,17 +47,9 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj buildCtx io.ReadCloser dockerfileCtx io.ReadCloser contextDir string - tempDir string relDockerfile string - - err error ) - dockerfileName := dockerFilePath(service.Build.Context, service.Build.Dockerfile) - specifiedContext := service.Build.Context - progBuff := s.stdout() - buildBuff := s.stdout() - if len(service.Build.Platforms) > 1 { return "", fmt.Errorf("the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit") } @@ -80,34 +71,51 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj } service.Build.Labels[api.ImageBuilderLabel] = "classic" - switch { - case isLocalDir(specifiedContext): + dockerfileName := dockerFilePath(service.Build.Context, service.Build.Dockerfile) + specifiedContext := service.Build.Context + progBuff := s.stdout() + buildBuff := s.stdout() + + contextType, err := build.DetectContextType(specifiedContext) + if err != nil { + return "", err + } + + switch contextType { + case build.ContextTypeStdin: + return "", fmt.Errorf("building from STDIN is not supported") + case build.ContextTypeLocal: contextDir, relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, dockerfileName) - if err == nil && strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) { - // Dockerfile is outside of build-context; read the Dockerfile and pass it as dockerfileCtx + if err != nil { + return "", fmt.Errorf("unable to prepare context: %w", err) + } + if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) { + // Dockerfile is outside build-context; read the Dockerfile and pass it as dockerfileCtx dockerfileCtx, err = os.Open(dockerfileName) if err != nil { return "", fmt.Errorf("unable to open Dockerfile: %w", err) } defer dockerfileCtx.Close() //nolint:errcheck } - case urlutil.IsGitURL(specifiedContext): + case build.ContextTypeGit: + var tempDir string tempDir, relDockerfile, err = build.GetContextFromGitURL(specifiedContext, dockerfileName) - case urlutil.IsURL(specifiedContext): + if err != nil { + return "", fmt.Errorf("unable to prepare context: %w", err) + } + defer func() { + _ = os.RemoveAll(tempDir) + }() + contextDir = tempDir + case build.ContextTypeRemote: buildCtx, relDockerfile, err = build.GetContextFromURL(progBuff, specifiedContext, dockerfileName) + if err != nil { + return "", fmt.Errorf("unable to prepare context: %w", err) + } default: return "", fmt.Errorf("unable to prepare context: path %q not found", specifiedContext) } - if err != nil { - return "", fmt.Errorf("unable to prepare context: %w", err) - } - - if tempDir != "" { - defer os.RemoveAll(tempDir) //nolint:errcheck - contextDir = tempDir - } - // read from a directory into tar archive if buildCtx == nil { excludes, err := build.ReadDockerignore(contextDir) @@ -125,7 +133,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj excludes = build.TrimBuildFilesFromExcludes(excludes, relDockerfile, false) buildCtx, err = archive.TarWithOptions(contextDir, &archive.TarOptions{ ExcludePatterns: excludes, - ChownOpts: &archive.ChownOpts{}, + ChownOpts: &archive.ChownOpts{UID: 0, GID: 0}, }) if err != nil { return "", err @@ -145,6 +153,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj return "", err } + // Setup an upload progress bar progressOutput := streamformatter.NewProgressOutput(progBuff) body := progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon") @@ -166,16 +175,16 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj RegistryToken: authConfig.RegistryToken, } } - buildOptions := imageBuildOptions(s.dockerCli, project, service, options) + buildOpts := imageBuildOptions(s.dockerCli, project, service, options) imageName := api.GetImageNameOrDefault(service, project.Name) - buildOptions.Tags = append(buildOptions.Tags, imageName) - buildOptions.Dockerfile = relDockerfile - buildOptions.AuthConfigs = authConfigs - buildOptions.Memory = options.Memory + buildOpts.Tags = append(buildOpts.Tags, imageName) + buildOpts.Dockerfile = relDockerfile + buildOpts.AuthConfigs = authConfigs + buildOpts.Memory = options.Memory ctx, cancel := context.WithCancel(ctx) defer cancel() - response, err := s.apiClient().ImageBuild(ctx, body, buildOptions) + response, err := s.apiClient().ImageBuild(ctx, body, buildOpts) if err != nil { return "", err } @@ -206,11 +215,6 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj return imageID, nil } -func isLocalDir(c string) bool { - _, err := os.Stat(c) - return err == nil -} - func imageBuildOptions(dockerCli command.Cli, project *types.Project, service types.ServiceConfig, options api.BuildOptions) buildtypes.ImageBuildOptions { config := service.Build return buildtypes.ImageBuildOptions{