diff --git a/build/build.go b/build/build.go index de21b8ee..075a0096 100644 --- a/build/build.go +++ b/build/build.go @@ -50,7 +50,8 @@ func Build(ctx context.Context, drivers []driver.Driver, opt map[string]Options, } pwOld := pw - c, pw, err := driver.Boot(ctx, drivers[0], pw) + d := drivers[0] + c, pw, err := driver.Boot(ctx, d, pw) if err != nil { close(pwOld.Status()) <-pwOld.Done() @@ -94,6 +95,28 @@ func Build(ctx context.Context, drivers []driver.Driver, opt map[string]Options, } } } + + for i, e := range opt.Exports { + if e.Type == "oci" && !d.Features()[driver.OCIExporter] { + return nil, notSupported(d, driver.OCIExporter) + } + if e.Type == "docker" && e.Output != nil && !d.Features()[driver.DockerExporter] { + return nil, notSupported(d, driver.DockerExporter) + } + if e.Type == "image" { + if _, ok := d.(interface { + IsDefaultMobyDriver() + }); ok { + opt.Exports[i].Type = "moby" + if e.Attrs["push"] != "" { + if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok { + return nil, errors.Errorf("auto-push is currently not implemented for moby driver") + } + } + } + } + } + // TODO: handle loading to docker daemon so.Exports = opt.Exports @@ -124,6 +147,9 @@ func Build(ctx context.Context, drivers []driver.Driver, opt map[string]Options, for i, p := range opt.Platforms { pp[i] = platforms.Format(p) } + if len(pp) > 1 && !d.Features()[driver.MultiPlatform] { + return nil, notSupported(d, driver.MultiPlatform) + } so.FrontendAttrs["platform"] = strings.Join(pp, ",") } @@ -180,3 +206,7 @@ func LoadInputs(inp Inputs, target *client.SolveOpt) error { target.FrontendAttrs["filename"] = filepath.Base(inp.DockerfilePath) return nil } + +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 new\")", f, d.Factory().Name()) +} diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index 5f126cae..796debac 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -24,6 +24,7 @@ var buildkitImage = "moby/buildkit:master" // TODO: make this verified and confi type Driver struct { driver.InitConfig + factory driver.Factory version dockertypes.Version } @@ -190,6 +191,20 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { })) } +func (d *Driver) Factory() driver.Factory { + return d.factory +} + +func (d *Driver) Features() map[driver.Feature]bool { + return map[driver.Feature]bool{ + driver.OCIExporter: true, + driver.DockerExporter: true, + + driver.CacheExport: true, + driver.MultiPlatform: true, + } +} + func demuxConn(c net.Conn) net.Conn { pr, pw := io.Pipe() // TODO: rewrite parser with Reader() to avoid goroutine switch diff --git a/driver/docker-container/factory.go b/driver/docker-container/factory.go index 752d14a3..5591b4c1 100644 --- a/driver/docker-container/factory.go +++ b/driver/docker-container/factory.go @@ -42,5 +42,5 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver return nil, errors.Wrapf(driver.ErrNotConnecting, err.Error()) } - return &Driver{InitConfig: cfg, version: v}, nil + return &Driver{factory: f, InitConfig: cfg, version: v}, nil } diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 75a1ac0d..1ba9e477 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -12,9 +12,8 @@ import ( "github.com/tonistiigi/buildx/util/progress" ) -var buildkitImage = "moby/buildkit:master" // TODO: make this verified and configuratble - type Driver struct { + factory driver.Factory driver.InitConfig version dockertypes.Version } @@ -46,3 +45,19 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { return d.DockerAPI.DialHijack(ctx, "/grpc", "h2c", nil) })) } + +func (d *Driver) Features() map[driver.Feature]bool { + return map[driver.Feature]bool{ + driver.OCIExporter: false, + driver.DockerExporter: false, + + driver.CacheExport: false, + driver.MultiPlatform: false, + } +} + +func (d *Driver) Factory() driver.Factory { + return d.factory +} + +func (d *Driver) IsDefaultMobyDriver() {} diff --git a/driver/docker/factory.go b/driver/docker/factory.go index 37c60d23..af520403 100644 --- a/driver/docker/factory.go +++ b/driver/docker/factory.go @@ -39,7 +39,7 @@ func (*factory) Priority(cfg driver.InitConfig) int { return prioritySupported } -func (*factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver, error) { +func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver, error) { if cfg.DockerAPI == nil { return nil, errors.Errorf("docker driver requires docker API access") } @@ -49,5 +49,5 @@ func (*factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver, return nil, errors.Wrapf(driver.ErrNotConnecting, err.Error()) } - return &Driver{InitConfig: cfg, version: v}, nil + return &Driver{factory: f, InitConfig: cfg, version: v}, nil } diff --git a/driver/driver.go b/driver/driver.go index 0b03c1ec..559c14ff 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -27,11 +27,13 @@ type Info struct { } type Driver interface { + Factory() Factory Bootstrap(context.Context, progress.Logger) error Info(context.Context) (*Info, error) Stop(ctx context.Context, force bool) error Rm(ctx context.Context, force bool) error Client(ctx context.Context) (*client.Client, error) + Features() map[Feature]bool } func Boot(ctx context.Context, d Driver, pw progress.Writer) (*client.Client, progress.Writer, error) { diff --git a/driver/features.go b/driver/features.go new file mode 100644 index 00000000..3438f7e0 --- /dev/null +++ b/driver/features.go @@ -0,0 +1,9 @@ +package driver + +type Feature string + +const OCIExporter Feature = "OCI exporter" +const DockerExporter Feature = "Docker exporter" + +const CacheExport Feature = "cache export" +const MultiPlatform Feature = "multiple platforms"