delegate build to buildx bake
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
208e57ded8
commit
095f65cb42
2
go.mod
2
go.mod
@ -136,7 +136,7 @@ require (
|
|||||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/moby/sys/signal v0.7.1 // indirect
|
github.com/moby/sys/signal v0.7.1 // indirect
|
||||||
github.com/moby/sys/symlink v0.3.0 // indirect
|
github.com/moby/sys/symlink v0.2.0 // indirect
|
||||||
github.com/moby/sys/user v0.3.0 // indirect
|
github.com/moby/sys/user v0.3.0 // indirect
|
||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
5
go.sum
5
go.sum
@ -337,8 +337,8 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
|
|||||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
||||||
github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
|
github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
|
||||||
github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU=
|
github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZc=
|
||||||
github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0=
|
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
|
||||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||||
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
@ -582,6 +582,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/v2/types"
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/containerd/platforms"
|
"github.com/containerd/platforms"
|
||||||
@ -38,7 +37,6 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/compose/v2/pkg/utils"
|
"github.com/docker/compose/v2/pkg/utils"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
|
||||||
bclient "github.com/moby/buildkit/client"
|
bclient "github.com/moby/buildkit/client"
|
||||||
"github.com/moby/buildkit/session"
|
"github.com/moby/buildkit/session"
|
||||||
"github.com/moby/buildkit/session/auth/authprovider"
|
"github.com/moby/buildkit/session/auth/authprovider"
|
||||||
@ -64,26 +62,16 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
|
|||||||
}, s.stdinfo(), "Building")
|
}, s.stdinfo(), "Building")
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceToBuild struct {
|
|
||||||
name string
|
|
||||||
service types.ServiceConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions, localImages map[string]string) (map[string]string, error) {
|
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions, localImages map[string]string) (map[string]string, error) {
|
||||||
buildkitEnabled, err := s.dockerCli.BuildKitEnabled()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
imageIDs := map[string]string{}
|
imageIDs := map[string]string{}
|
||||||
serviceToBeBuild := map[string]serviceToBuild{}
|
serviceToBuild := types.Services{}
|
||||||
|
|
||||||
var policy types.DependencyOption = types.IgnoreDependencies
|
var policy types.DependencyOption = types.IgnoreDependencies
|
||||||
if options.Deps {
|
if options.Deps {
|
||||||
policy = types.IncludeDependencies
|
policy = types.IncludeDependencies
|
||||||
}
|
}
|
||||||
err = project.ForEachService(options.Services, func(serviceName string, service *types.ServiceConfig) error {
|
err := project.ForEachService(options.Services, func(serviceName string, service *types.ServiceConfig) error {
|
||||||
if service.Build == nil {
|
if service.Build == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -92,14 +80,26 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
|||||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
serviceToBeBuild[serviceName] = serviceToBuild{name: serviceName, service: *service}
|
serviceToBuild[serviceName] = *service
|
||||||
return nil
|
return nil
|
||||||
}, policy)
|
}, policy)
|
||||||
if err != nil || len(serviceToBeBuild) == 0 {
|
if err != nil || len(serviceToBuild) == 0 {
|
||||||
return imageIDs, err
|
return imageIDs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bake, err := buildWithBake(s.dockerCli)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if bake {
|
||||||
|
return s.doBuildBake(ctx, project, serviceToBuild, options)
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize buildkit nodes
|
// Initialize buildkit nodes
|
||||||
|
buildkitEnabled, err := s.dockerCli.BuildKitEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
b *builder.Builder
|
b *builder.Builder
|
||||||
nodes []builder.Node
|
nodes []builder.Node
|
||||||
@ -152,12 +152,10 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
err = InDependencyOrder(ctx, project, func(ctx context.Context, name string) error {
|
err = InDependencyOrder(ctx, project, func(ctx context.Context, name string) error {
|
||||||
serviceToBuild, ok := serviceToBeBuild[name]
|
service, ok := serviceToBuild[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
service := serviceToBuild.service
|
|
||||||
|
|
||||||
cw := progress.ContextWriter(ctx)
|
cw := progress.ContextWriter(ctx)
|
||||||
serviceName := fmt.Sprintf("Service %s", name)
|
serviceName := fmt.Sprintf("Service %s", name)
|
||||||
|
|
||||||
@ -211,7 +209,8 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
|||||||
|
|
||||||
for i, imageDigest := range builtDigests {
|
for i, imageDigest := range builtDigests {
|
||||||
if imageDigest != "" {
|
if imageDigest != "" {
|
||||||
imageRef := api.GetImageNameOrDefault(project.Services[names[i]], project.Name)
|
service := project.Services[names[i]]
|
||||||
|
imageRef := api.GetImageNameOrDefault(service, project.Name)
|
||||||
imageIDs[imageRef] = imageDigest
|
imageIDs[imageRef] = imageDigest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,12 +333,7 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
|
|||||||
//
|
//
|
||||||
// Finally, standard proxy variables based on the Docker client configuration are added, but will not overwrite
|
// Finally, standard proxy variables based on the Docker client configuration are added, but will not overwrite
|
||||||
// any values if already present.
|
// any values if already present.
|
||||||
func resolveAndMergeBuildArgs(
|
func resolveAndMergeBuildArgs(dockerCli command.Cli, project *types.Project, service types.ServiceConfig, opts api.BuildOptions) types.MappingWithEquals {
|
||||||
dockerCli command.Cli,
|
|
||||||
project *types.Project,
|
|
||||||
service types.ServiceConfig,
|
|
||||||
opts api.BuildOptions,
|
|
||||||
) types.MappingWithEquals {
|
|
||||||
result := make(types.MappingWithEquals).
|
result := make(types.MappingWithEquals).
|
||||||
OverrideBy(service.Build.Args).
|
OverrideBy(service.Build.Args).
|
||||||
OverrideBy(opts.Args).
|
OverrideBy(opts.Args).
|
||||||
@ -479,16 +473,6 @@ func flatten(in types.MappingWithEquals) types.Mapping {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func dockerFilePath(ctxName string, dockerfile string) string {
|
|
||||||
if dockerfile == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if urlutil.IsGitURL(ctxName) || filepath.IsAbs(dockerfile) {
|
|
||||||
return dockerfile
|
|
||||||
}
|
|
||||||
return filepath.Join(ctxName, dockerfile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) {
|
func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) {
|
||||||
sshConfig := make([]sshprovider.AgentConfig, 0, len(sshKeys))
|
sshConfig := make([]sshprovider.AgentConfig, 0, len(sshKeys))
|
||||||
for _, sshKey := range sshKeys {
|
for _, sshKey := range sshKeys {
|
||||||
|
305
pkg/compose/build_bake.go
Normal file
305
pkg/compose/build_bake.go
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Docker Compose CLI authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
|
"github.com/docker/cli/cli-plugins/manager"
|
||||||
|
"github.com/docker/cli/cli-plugins/socket"
|
||||||
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
|
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||||
|
"github.com/moby/buildkit/client"
|
||||||
|
"github.com/moby/buildkit/util/progress/progressui"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/propagation"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildWithBake(dockerCli command.Cli) (bool, error) {
|
||||||
|
b, ok := os.LookupEnv("COMPOSE_BAKE")
|
||||||
|
if !ok {
|
||||||
|
if dockerCli.ConfigFile().Plugins["compose"]["build"] == "bake" {
|
||||||
|
b, ok = "true", true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
bake, err := strconv.ParseBool(b)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !bake {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled, err := dockerCli.BuildKitEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !enabled {
|
||||||
|
logrus.Warnf("Docker Compose is configured to build using Bake, but buildkit isn't enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = manager.GetPlugin("buildx", dockerCli, &cobra.Command{})
|
||||||
|
if err != nil {
|
||||||
|
if manager.IsNotFound(err) {
|
||||||
|
logrus.Warnf("Docker Compose is configured to build using Bake, but buildx isn't installed")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We _could_ use bake.* types from github.com/docker/buildx but long term plan is to remove buildx as a dependency
|
||||||
|
type bakeConfig struct {
|
||||||
|
Groups map[string]bakeGroup `json:"group"`
|
||||||
|
Targets map[string]bakeTarget `json:"target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type bakeGroup struct {
|
||||||
|
Targets []string `json:"targets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type bakeTarget struct {
|
||||||
|
Context string `json:"context,omitempty"`
|
||||||
|
Dockerfile string `json:"dockerfile,omitempty"`
|
||||||
|
Args map[string]string `json:"args,omitempty"`
|
||||||
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
CacheFrom []string `json:"cache-from,omitempty"`
|
||||||
|
CacheTo []string `json:"cache-to,omitempty"`
|
||||||
|
Secrets []string `json:"secret,omitempty"`
|
||||||
|
SSH []string `json:"ssh,omitempty"`
|
||||||
|
Platforms []string `json:"platforms,omitempty"`
|
||||||
|
Target string `json:"target,omitempty"`
|
||||||
|
Pull bool `json:"pull,omitempty"`
|
||||||
|
NoCache bool `json:"no-cache,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type bakeMetadata map[string]buildStatus
|
||||||
|
|
||||||
|
type buildStatus struct {
|
||||||
|
Digest string `json:"containerimage.digest"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) doBuildBake(ctx context.Context, project *types.Project, serviceToBeBuild types.Services, options api.BuildOptions) (map[string]string, error) { //nolint:gocyclo
|
||||||
|
cw := progress.ContextWriter(ctx)
|
||||||
|
for name := range serviceToBeBuild {
|
||||||
|
cw.Event(progress.BuildingEvent(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
eg := errgroup.Group{}
|
||||||
|
ch := make(chan *client.SolveStatus)
|
||||||
|
display, err := progressui.NewDisplay(os.Stdout, progressui.DisplayMode(options.Progress))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
eg.Go(func() error {
|
||||||
|
_, err := display.UpdateFrom(ctx, ch)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg := bakeConfig{
|
||||||
|
Groups: map[string]bakeGroup{},
|
||||||
|
Targets: map[string]bakeTarget{},
|
||||||
|
}
|
||||||
|
var group bakeGroup
|
||||||
|
|
||||||
|
for name, service := range serviceToBeBuild {
|
||||||
|
if service.Build == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
build := *service.Build
|
||||||
|
|
||||||
|
args := types.Mapping{}
|
||||||
|
for k, v := range resolveAndMergeBuildArgs(s.dockerCli, project, service, options) {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args[k] = *v
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Targets[name] = bakeTarget{
|
||||||
|
Context: build.Context,
|
||||||
|
Dockerfile: dockerFilePath(build.Context, build.Dockerfile),
|
||||||
|
Args: args,
|
||||||
|
Labels: build.Labels,
|
||||||
|
Tags: build.Tags,
|
||||||
|
|
||||||
|
CacheFrom: build.CacheFrom,
|
||||||
|
// CacheTo: TODO
|
||||||
|
Platforms: build.Platforms,
|
||||||
|
Target: build.Target,
|
||||||
|
Secrets: toBakeSecrets(project, build.Secrets),
|
||||||
|
SSH: toBakeSSH(build.SSH),
|
||||||
|
Pull: options.Pull,
|
||||||
|
NoCache: options.NoCache,
|
||||||
|
}
|
||||||
|
group.Targets = append(group.Targets, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Groups["default"] = group
|
||||||
|
|
||||||
|
b, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := os.CreateTemp(os.TempDir(), "compose")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buildx, err := manager.GetPlugin("buildx", s.dockerCli, &cobra.Command{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd := exec.CommandContext(ctx, buildx.Path, "bake", "--file", "-", "--progress", "rawjson", "--metadata-file", metadata.Name())
|
||||||
|
// Remove DOCKER_CLI_PLUGIN... variable so buildx can detect it run standalone
|
||||||
|
cmd.Env = filter(os.Environ(), manager.ReexecEnvvar)
|
||||||
|
|
||||||
|
// Use docker/cli mechanism to propagate termination signal to child process
|
||||||
|
server, err := socket.NewPluginServer(nil)
|
||||||
|
if err != nil {
|
||||||
|
defer server.Close() //nolint:errcheck
|
||||||
|
cmd.Cancel = server.Close
|
||||||
|
cmd.Env = replace(cmd.Env, socket.EnvKey, server.Addr().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_CONTEXT=%s", s.dockerCli.CurrentContext()))
|
||||||
|
|
||||||
|
// propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md
|
||||||
|
carrier := propagation.MapCarrier{}
|
||||||
|
otel.GetTextMapPropagator().Inject(ctx, &carrier)
|
||||||
|
cmd.Env = append(cmd.Env, types.Mapping(carrier).Values()...)
|
||||||
|
|
||||||
|
cmd.Stdout = s.stdout()
|
||||||
|
cmd.Stdin = bytes.NewBuffer(b)
|
||||||
|
pipe, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
eg.Go(cmd.Wait)
|
||||||
|
for {
|
||||||
|
decoder := json.NewDecoder(pipe)
|
||||||
|
var s client.SolveStatus
|
||||||
|
err := decoder.Decode(&s)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// bake displays build details at the end of a build, which isn't a json SolveStatus
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ch <- &s
|
||||||
|
}
|
||||||
|
close(ch) // stop build progress UI
|
||||||
|
|
||||||
|
err = eg.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = os.ReadFile(metadata.Name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var md bakeMetadata
|
||||||
|
err = json.Unmarshal(b, &md)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
results := map[string]string{}
|
||||||
|
for name, m := range md {
|
||||||
|
results[name] = m.Digest
|
||||||
|
cw.Event(progress.BuiltEvent(name))
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBakeSSH(ssh types.SSHConfig) []string {
|
||||||
|
var s []string
|
||||||
|
for _, key := range ssh {
|
||||||
|
s = append(s, fmt.Sprintf("%s=%s", key.ID, key.Path))
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig) []string {
|
||||||
|
var s []string
|
||||||
|
for _, ref := range secrets {
|
||||||
|
def := project.Secrets[ref.Source]
|
||||||
|
switch {
|
||||||
|
case def.Environment != "":
|
||||||
|
s = append(s, fmt.Sprintf("id=%s,type=env,env=%s", ref.Source, def.Environment))
|
||||||
|
case def.File != "":
|
||||||
|
s = append(s, fmt.Sprintf("id=%s,type=file,src=%s", ref.Source, def.File))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func filter(environ []string, variable string) []string {
|
||||||
|
prefix := variable + "="
|
||||||
|
filtered := make([]string, 0, len(environ))
|
||||||
|
for _, val := range environ {
|
||||||
|
if !strings.HasPrefix(val, prefix) {
|
||||||
|
filtered = append(filtered, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
func replace(environ []string, variable, value string) []string {
|
||||||
|
filtered := filter(environ, variable)
|
||||||
|
return append(filtered, fmt.Sprintf("%s=%s", variable, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func dockerFilePath(ctxName string, dockerfile string) string {
|
||||||
|
if dockerfile == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if urlutil.IsGitURL(ctxName) || filepath.IsAbs(dockerfile) {
|
||||||
|
return dockerfile
|
||||||
|
}
|
||||||
|
return filepath.Join(ctxName, dockerfile)
|
||||||
|
}
|
@ -117,7 +117,6 @@ func TestWatch_Sync(t *testing.T) {
|
|||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
cli := mocks.NewMockCli(mockCtrl)
|
cli := mocks.NewMockCli(mockCtrl)
|
||||||
cli.EXPECT().Err().Return(streams.NewOut(os.Stderr)).AnyTimes()
|
cli.EXPECT().Err().Return(streams.NewOut(os.Stderr)).AnyTimes()
|
||||||
cli.EXPECT().BuildKitEnabled().Return(true, nil)
|
|
||||||
apiClient := mocks.NewMockAPIClient(mockCtrl)
|
apiClient := mocks.NewMockAPIClient(mockCtrl)
|
||||||
apiClient.EXPECT().ContainerList(gomock.Any(), gomock.Any()).Return([]moby.Container{
|
apiClient.EXPECT().ContainerList(gomock.Any(), gomock.Any()).Return([]moby.Container{
|
||||||
testContainer("test", "123", false),
|
testContainer("test", "123", false),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user