bake: use controller build options as an intermediate stage

With the previous changes to bring controllerapi.BuildOptions up to date
with build.Options, we can have bake generate
controllerapi.BuildOptions, and then convert those to build.Option using
the controller/build package.

This is an intermediate patch, designed to allow us to clean up some
shared logic between both build and bake. The next step will be to
modify bake to use the controller api, and completely skip the
build.Options generation step.

Signed-off-by: Justin Chadwell <me@jedevc.com>
pull/1680/head
Justin Chadwell 2 years ago
parent d8f6d554a8
commit d4e38a0ebe

@ -14,14 +14,12 @@ import (
"github.com/docker/buildx/bake/hclparser" "github.com/docker/buildx/bake/hclparser"
"github.com/docker/buildx/build" "github.com/docker/buildx/build"
cbuild "github.com/docker/buildx/controller/build"
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/util/buildflags" "github.com/docker/buildx/util/buildflags"
"github.com/docker/buildx/util/platformutil"
"github.com/docker/cli/cli/config"
"github.com/docker/docker/builder/remotecontext/urlutil" "github.com/docker/docker/builder/remotecontext/urlutil"
hcl "github.com/hashicorp/hcl/v2" hcl "github.com/hashicorp/hcl/v2"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -782,7 +780,11 @@ func (t *Target) AddOverrides(overrides map[string]Override) error {
func TargetsToBuildOpt(m map[string]*Target, inp *Input) (map[string]build.Options, error) { func TargetsToBuildOpt(m map[string]*Target, inp *Input) (map[string]build.Options, error) {
m2 := make(map[string]build.Options, len(m)) m2 := make(map[string]build.Options, len(m))
for k, v := range m { for k, v := range m {
bo, err := toBuildOpt(v, inp) opts, err := toControllerOpt(v, inp)
if err != nil {
return nil, err
}
bo, err := cbuild.ToBuildOpts(*opts, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -791,14 +793,14 @@ func TargetsToBuildOpt(m map[string]*Target, inp *Input) (map[string]build.Optio
return m2, nil return m2, nil
} }
func updateContext(t *build.Inputs, inp *Input) { func updateContext(t *controllerapi.Inputs, inp *Input) error {
if inp == nil || inp.State == nil { if inp == nil || inp.State == nil {
return return nil
} }
for k, v := range t.NamedContexts { for k, v := range t.NamedContexts {
if v.Path == "." { if v.Path == "." {
t.NamedContexts[k] = build.NamedContext{Path: inp.URL} t.NamedContexts[k] = &controllerapi.NamedContext{Path: inp.URL}
} }
if strings.HasPrefix(v.Path, "cwd://") || strings.HasPrefix(v.Path, "target:") || strings.HasPrefix(v.Path, "docker-image:") { if strings.HasPrefix(v.Path, "cwd://") || strings.HasPrefix(v.Path, "target:") || strings.HasPrefix(v.Path, "docker-image:") {
continue continue
@ -807,27 +809,36 @@ func updateContext(t *build.Inputs, inp *Input) {
continue continue
} }
st := llb.Scratch().File(llb.Copy(*inp.State, v.Path, "/"), llb.WithCustomNamef("set context %s to %s", k, v.Path)) st := llb.Scratch().File(llb.Copy(*inp.State, v.Path, "/"), llb.WithCustomNamef("set context %s to %s", k, v.Path))
t.NamedContexts[k] = build.NamedContext{State: &st} def, err := st.Marshal(context.TODO())
if err != nil {
return err
}
t.NamedContexts[k] = &controllerapi.NamedContext{Definition: def.ToPB()}
} }
if t.ContextPath == "." { if t.ContextPath == "." {
t.ContextPath = inp.URL t.ContextPath = inp.URL
return return nil
} }
if strings.HasPrefix(t.ContextPath, "cwd://") { if strings.HasPrefix(t.ContextPath, "cwd://") {
return return nil
} }
if IsRemoteURL(t.ContextPath) { if IsRemoteURL(t.ContextPath) {
return return nil
} }
st := llb.Scratch().File(llb.Copy(*inp.State, t.ContextPath, "/"), llb.WithCustomNamef("set context to %s", t.ContextPath)) st := llb.Scratch().File(llb.Copy(*inp.State, t.ContextPath, "/"), llb.WithCustomNamef("set context to %s", t.ContextPath))
t.ContextState = &st def, err := st.Marshal(context.TODO())
if err != nil {
return err
}
t.ContextDefinition = def.ToPB()
return nil
} }
// validateContextsEntitlements is a basic check to ensure contexts do not // validateContextsEntitlements is a basic check to ensure contexts do not
// escape local directories when loaded from remote sources. This is to be // escape local directories when loaded from remote sources. This is to be
// replaced with proper entitlements support in the future. // replaced with proper entitlements support in the future.
func validateContextsEntitlements(t build.Inputs, inp *Input) error { func validateContextsEntitlements(t controllerapi.Inputs, inp *Input) error {
if inp == nil || inp.State == nil { if inp == nil || inp.State == nil {
return nil return nil
} }
@ -836,13 +847,13 @@ func validateContextsEntitlements(t build.Inputs, inp *Input) error {
return nil return nil
} }
} }
if t.ContextState == nil { if t.ContextDefinition == nil {
if err := checkPath(t.ContextPath); err != nil { if err := checkPath(t.ContextPath); err != nil {
return err return err
} }
} }
for _, v := range t.NamedContexts { for _, v := range t.NamedContexts {
if v.State != nil { if v.Definition != nil {
continue continue
} }
if err := checkPath(v.Path); err != nil { if err := checkPath(v.Path); err != nil {
@ -877,7 +888,7 @@ func checkPath(p string) error {
return nil return nil
} }
func toBuildOpt(t *Target, inp *Input) (*build.Options, error) { func toControllerOpt(t *Target, inp *Input) (*controllerapi.BuildOptions, error) {
if v := t.Context; v != nil && *v == "-" { if v := t.Context; v != nil && *v == "-" {
return nil, errors.Errorf("context from stdin not allowed in bake") return nil, errors.Errorf("context from stdin not allowed in bake")
} }
@ -930,9 +941,9 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
networkMode = *t.NetworkMode networkMode = *t.NetworkMode
} }
bi := build.Inputs{ bi := controllerapi.Inputs{
ContextPath: contextPath, ContextPath: contextPath,
DockerfilePath: dockerfilePath, DockerfileName: dockerfilePath,
NamedContexts: toNamedContexts(t.Contexts), NamedContexts: toNamedContexts(t.Contexts),
} }
if t.DockerfileInline != nil { if t.DockerfileInline != nil {
@ -944,7 +955,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
} }
for k, v := range bi.NamedContexts { for k, v := range bi.NamedContexts {
if strings.HasPrefix(v.Path, "cwd://") { if strings.HasPrefix(v.Path, "cwd://") {
bi.NamedContexts[k] = build.NamedContext{Path: path.Clean(strings.TrimPrefix(v.Path, "cwd://"))} bi.NamedContexts[k] = &controllerapi.NamedContext{Path: path.Clean(strings.TrimPrefix(v.Path, "cwd://"))}
} }
} }
@ -954,82 +965,55 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
t.Context = &bi.ContextPath t.Context = &bi.ContextPath
bo := &build.Options{ opts := &controllerapi.BuildOptions{
Inputs: bi, Inputs: &bi,
Tags: t.Tags, Tags: t.Tags,
BuildArgs: args, BuildArgs: args,
Labels: labels, Labels: labels,
NoCache: noCache,
NoCacheFilter: t.NoCacheFilter, NoCacheFilter: t.NoCacheFilter,
Pull: pull,
NetworkMode: networkMode, NetworkMode: networkMode,
Linked: t.linked, Opts: &controllerapi.CommonOptions{
NoCache: noCache,
Pull: pull,
Linked: t.linked,
},
Platforms: t.Platforms,
} }
var err error
platforms, err := platformutil.Parse(t.Platforms) if t.Target != nil {
if err != nil { opts.Target = *t.Target
return nil, err
}
bo.Platforms = platforms
dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
bo.Session = append(bo.Session, authprovider.NewDockerAuthProvider(dockerConfig))
secrets, err := buildflags.ParseSecretSpecs(t.Secrets)
if err != nil {
return nil, err
}
secretAttachment, err := controllerapi.CreateSecrets(secrets)
if err != nil {
return nil, err
} }
bo.Session = append(bo.Session, secretAttachment)
sshSpecs, err := buildflags.ParseSSHSpecs(t.SSH) opts.Secrets, err = buildflags.ParseSecretSpecs(t.Secrets)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(sshSpecs) == 0 && buildflags.IsGitSSH(contextPath) { opts.SSH, err = buildflags.ParseSSHSpecs(t.SSH)
sshSpecs = append(sshSpecs, &controllerapi.SSH{ID: "default"})
}
sshAttachment, err := controllerapi.CreateSSH(sshSpecs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bo.Session = append(bo.Session, sshAttachment)
if t.Target != nil {
bo.Target = *t.Target
}
cacheImports, err := buildflags.ParseCacheEntry(t.CacheFrom) opts.CacheFrom, err = buildflags.ParseCacheEntry(t.CacheFrom)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bo.CacheFrom = controllerapi.CreateCaches(cacheImports) opts.CacheTo, err = buildflags.ParseCacheEntry(t.CacheTo)
cacheExports, err := buildflags.ParseCacheEntry(t.CacheTo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bo.CacheTo = controllerapi.CreateCaches(cacheExports)
outputs, err := buildflags.ParseExports(t.Outputs) opts.Exports, err = buildflags.ParseExports(t.Outputs)
if err != nil {
return nil, err
}
bo.Exports, err = controllerapi.CreateExports(outputs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
attests, err := buildflags.ParseAttests(t.Attest) opts.Attests, err = buildflags.ParseAttests(t.Attest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bo.Attests = controllerapi.CreateAttestations(attests)
return bo, nil return opts, nil
} }
func defaultTarget() *Target { func defaultTarget() *Target {
@ -1102,10 +1086,10 @@ func sliceEqual(s1, s2 []string) bool {
return true return true
} }
func toNamedContexts(m map[string]string) map[string]build.NamedContext { func toNamedContexts(m map[string]string) map[string]*controllerapi.NamedContext {
m2 := make(map[string]build.NamedContext, len(m)) m2 := make(map[string]*controllerapi.NamedContext, len(m))
for k, v := range m { for k, v := range m {
m2[k] = build.NamedContext{Path: v} m2[k] = &controllerapi.NamedContext{Path: v}
} }
return m2 return m2
} }

Loading…
Cancel
Save