Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ func toRepoOnly(in string) (string, error) {
return strings.Join(out, ","), nil
}

func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) {
func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, docker *dockerutil.Client) (solveOpt *client.SolveOpt, release func(), err error) {
nodeDriver := node.Driver
defers := make([]func(), 0, 2)
releaseF := func() {
Expand Down Expand Up @@ -531,14 +531,22 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
return nil, nil, notSupported(nodeDriver, driver.OCIExporter)
}
if e.Type == "docker" {
if len(opt.Platforms) > 1 || len(attests) > 0 {
features := docker.Features(ctx, e.Attrs["context"])
if features[dockerutil.OCIImporter] && e.Output == nil {
// rely on oci importer if available (which supports
// multi-platform images), otherwise fall back to docker
opt.Exports[i].Type = "oci"
} else if len(opt.Platforms) > 1 || len(attests) > 0 {
if e.Output != nil {
return nil, nil, errors.Errorf("docker exporter does not support exporting manifest lists, use the oci exporter instead")
}
return nil, nil, errors.Errorf("docker exporter does not currently support exporting manifest lists")
}
if e.Output == nil {
if nodeDriver.IsMobyDriver() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not changing in this PR but shouldn't this also have a "context" check?

e.Type = "image"
} else {
w, cancel, err := dl(e.Attrs["context"])
w, cancel, err := docker.LoadImage(ctx, e.Attrs["context"], pw)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -733,9 +741,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
hasMobyDriver = true
}
opt.Platforms = np.platforms
so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, func(name string) (io.WriteCloser, func(), error) {
return docker.LoadImage(ctx, name, w)
})
so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, docker)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1543,8 +1549,6 @@ func notSupported(d driver.Driver, f driver.Feature) error {
return errors.Errorf("%s feature is currently not supported for %s driver. Please switch to a different driver (eg. \"docker buildx create --use\")", f, d.Factory().Name())
}

type dockerLoadCallback func(name string) (io.WriteCloser, func(), error)

func noDefaultLoad() bool {
v, ok := os.LookupEnv("BUILDX_NO_DEFAULT_LOAD")
if !ok {
Expand Down
17 changes: 17 additions & 0 deletions util/dockerutil/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ func (c *Client) LoadImage(ctx context.Context, name string, status progress.Wri
}, nil
}

func (c *Client) Features(ctx context.Context, name string) map[Feature]bool {
features := make(map[Feature]bool)
if dapi, err := c.API(name); err == nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow-up this function could do caching these return values for bake and if we add any more Feature values we probably would need to ask for a specific one to make sure expensive call like info is not done needlessly.

if info, err := dapi.Info(ctx); err == nil {
for _, v := range info.DriverStatus {
switch v[0] {
case "driver-type":
if v[1] == "io.containerd.snapshotter.v1" {
features[OCIImporter] = true
}
}
}
}
}
return features
}

type waitingWriter struct {
*io.PipeWriter
f func()
Expand Down
5 changes: 5 additions & 0 deletions util/dockerutil/features.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dockerutil

type Feature string

const OCIImporter Feature = "OCI importer"