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

fix builkit progressui integration #10535

Merged
merged 1 commit into from
May 8, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 64 additions & 36 deletions pkg/compose/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import (
"context"
"fmt"
"os"
"path/filepath"

"github.com/compose-spec/compose-go/types"
Expand Down Expand Up @@ -53,68 +54,83 @@
}, s.stderr(), "Building")
}

func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) {
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) { //nolint:gocyclo
args := options.Args.Resolve(envResolver(project.Environment))

buildkitEnabled, err := s.dockerCli.BuildKitEnabled()
if err != nil {
return nil, err
}

// Progress needs its own context that lives longer than the
// build one otherwise it won't read all the messages from
// build and will lock
progressCtx, cancel := context.WithCancel(context.Background())
defer cancel()
w, err := xprogress.NewPrinter(progressCtx, s.stdout(), os.Stdout, options.Progress)
if err != nil {
return nil, err
}

Check warning on line 73 in pkg/compose/build.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build.go#L72-L73

Added lines #L72 - L73 were not covered by tests

builtIDs := make([]string, len(project.Services))
err = InDependencyOrder(ctx, project, func(ctx context.Context, name string) error {
if len(options.Services) > 0 && !utils.Contains(options.Services, name) {
return nil
}
for i, service := range project.Services {
if service.Name != name {
continue
}

if service.Build == nil {
return nil
}
service, idx := getServiceIndex(project, name)

if !buildkitEnabled {
if service.Build.Args == nil {
service.Build.Args = args
} else {
service.Build.Args = service.Build.Args.OverrideBy(args)
}
id, err := s.doBuildClassic(ctx, service, options)
if err != nil {
return err
}
builtIDs[i] = id

if options.Push {
return s.push(ctx, project, api.PushOptions{})
}
return nil
}
if service.Build == nil {
return nil
}

if options.Memory != 0 {
fmt.Fprintln(s.stderr(), "WARNING: --memory is not supported by BuildKit and will be ignored.")
if !buildkitEnabled {
if service.Build.Args == nil {
service.Build.Args = args
} else {
service.Build.Args = service.Build.Args.OverrideBy(args)
}

buildOptions, err := s.toBuildOptions(project, service, options)
id, err := s.doBuildClassic(ctx, service, options)
if err != nil {
return err
}
buildOptions.BuildArgs = mergeArgs(buildOptions.BuildArgs, flatten(args))
opts := map[string]build.Options{service.Name: buildOptions}
builtIDs[idx] = id

ids, err := s.doBuildBuildkit(ctx, opts, options.Progress)
if err != nil {
return err
if options.Push {
return s.push(ctx, project, api.PushOptions{})

Check warning on line 99 in pkg/compose/build.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build.go#L99

Added line #L99 was not covered by tests
}
builtIDs[i] = ids[service.Name]
return nil
}

if options.Memory != 0 {
fmt.Fprintln(s.stderr(), "WARNING: --memory is not supported by BuildKit and will be ignored.")
}

Check warning on line 106 in pkg/compose/build.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build.go#L105-L106

Added lines #L105 - L106 were not covered by tests

buildOptions, err := s.toBuildOptions(project, service, options)
if err != nil {
return err
}
buildOptions.BuildArgs = mergeArgs(buildOptions.BuildArgs, flatten(args))

ids, err := s.doBuildBuildkit(ctx, service.Name, buildOptions, w)
if err != nil {
return err
}
builtIDs[idx] = ids[service.Name]

return nil
}, func(traversal *graphTraversal) {
traversal.maxConcurrency = s.maxConcurrency
})

// enforce all build event get consumed
if errw := w.Wait(); errw != nil {
return nil, errw
}

Check warning on line 128 in pkg/compose/build.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build.go#L127-L128

Added lines #L127 - L128 were not covered by tests

if err != nil {
return nil, err
}

imageIDs := map[string]string{}
for i, d := range builtIDs {
if d != "" {
Expand All @@ -124,6 +140,18 @@
return imageIDs, err
}

func getServiceIndex(project *types.Project, name string) (types.ServiceConfig, int) {
var service types.ServiceConfig
var idx int
for i, s := range project.Services {
if s.Name == name {
idx, service = i, s
break
}
}
return service, idx
}

func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, quietPull bool) error {
for _, service := range project.Services {
if service.Image == "" && service.Build == nil {
Expand Down
64 changes: 24 additions & 40 deletions pkg/compose/build_buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,22 @@
"context"
"crypto/sha1"
"fmt"
"os"
"path/filepath"

_ "github.com/docker/buildx/driver/docker" //nolint:blank-imports
_ "github.com/docker/buildx/driver/docker-container" //nolint:blank-imports
_ "github.com/docker/buildx/driver/kubernetes" //nolint:blank-imports
_ "github.com/docker/buildx/driver/remote" //nolint:blank-imports
buildx "github.com/docker/buildx/util/progress"
"github.com/moby/buildkit/client"

"github.com/docker/buildx/build"
"github.com/docker/buildx/builder"
"github.com/docker/buildx/util/dockerutil"
xprogress "github.com/docker/buildx/util/progress"
"github.com/docker/compose/v2/pkg/progress"
)

func (s *composeService) doBuildBuildkit(ctx context.Context, opts map[string]build.Options, mode string) (map[string]string, error) {
func (s *composeService) doBuildBuildkit(ctx context.Context, service string, opts build.Options, p *buildx.Printer) (map[string]string, error) {
b, err := builder.New(s.dockerCli)
if err != nil {
return nil, err
Expand All @@ -49,22 +48,9 @@

var response map[string]*client.SolveResponse
if s.dryRun {
response = s.dryRunBuildResponse(ctx, opts)
response = s.dryRunBuildResponse(ctx, service, opts)

Check warning on line 51 in pkg/compose/build_buildkit.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build_buildkit.go#L51

Added line #L51 was not covered by tests
} else {
// Progress needs its own context that lives longer than the
// build one otherwise it won't read all the messages from
// build and will lock
progressCtx, cancel := context.WithCancel(context.Background())
defer cancel()
w, err := xprogress.NewPrinter(progressCtx, s.stdout(), os.Stdout, mode)
if err != nil {
return nil, err
}
response, err = build.Build(ctx, nodes, opts, dockerutil.NewClient(s.dockerCli), filepath.Dir(s.configFile().Filename), w)
errW := w.Wait()
if err == nil {
err = errW
}
response, err = build.Build(ctx, nodes, map[string]build.Options{service: opts}, dockerutil.NewClient(s.dockerCli), filepath.Dir(s.configFile().Filename), buildx.WithPrefix(p, service, true))
if err != nil {
return nil, WrapCategorisedComposeError(err, BuildFailure)
}
Expand All @@ -85,29 +71,27 @@
return imagesBuilt, err
}

func (s composeService) dryRunBuildResponse(ctx context.Context, options map[string]build.Options) map[string]*client.SolveResponse {
func (s composeService) dryRunBuildResponse(ctx context.Context, name string, options build.Options) map[string]*client.SolveResponse {

Check warning on line 74 in pkg/compose/build_buildkit.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build_buildkit.go#L74

Added line #L74 was not covered by tests
w := progress.ContextWriter(ctx)
buildResponse := map[string]*client.SolveResponse{}
for name, option := range options {
dryRunUUID := fmt.Sprintf("dryRun-%x", sha1.Sum([]byte(name)))
w.Event(progress.Event{
ID: " ",
Status: progress.Done,
Text: fmt.Sprintf("build service %s", name),
})
w.Event(progress.Event{
ID: "==>",
Status: progress.Done,
Text: fmt.Sprintf("==> writing image %s", dryRunUUID),
})
w.Event(progress.Event{
ID: "==> ==>",
Status: progress.Done,
Text: fmt.Sprintf(`naming to %s`, option.Tags[0]),
})
buildResponse[name] = &client.SolveResponse{ExporterResponse: map[string]string{
"containerimage.digest": dryRunUUID,
}}
}
dryRunUUID := fmt.Sprintf("dryRun-%x", sha1.Sum([]byte(name)))
w.Event(progress.Event{
ID: " ",
Status: progress.Done,
Text: fmt.Sprintf("build service %s", name),
})
w.Event(progress.Event{
ID: "==>",
Status: progress.Done,
Text: fmt.Sprintf("==> writing image %s", dryRunUUID),
})
w.Event(progress.Event{
ID: "==> ==>",
Status: progress.Done,
Text: fmt.Sprintf(`naming to %s`, options.Tags[0]),
})
buildResponse[name] = &client.SolveResponse{ExporterResponse: map[string]string{
"containerimage.digest": dryRunUUID,
}}

Check warning on line 95 in pkg/compose/build_buildkit.go

View check run for this annotation

Codecov / codecov/patch

pkg/compose/build_buildkit.go#L77-L95

Added lines #L77 - L95 were not covered by tests
return buildResponse
}
2 changes: 1 addition & 1 deletion pkg/e2e/cancel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func TestComposeCancel(t *testing.T) {
}, 30*time.Second, 1*time.Second)

err = syscall.Kill(-cmd.Process.Pid, syscall.SIGINT) // simulate Ctrl-C : send signal to processGroup, children will have same groupId by default

assert.NilError(t, err)

c.WaitForCondition(t, func() (bool, string) {
out := stdout.String()
errors := stderr.String()
Expand Down