Browse code

vendor: buildkit to 98f1604134f945d48538ffca0e18662337b4a850

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2018/07/12 07:05:57
Showing 55 changed files
... ...
@@ -13,12 +13,13 @@ import (
13 13
 	"github.com/docker/docker/daemon/graphdriver"
14 14
 	"github.com/moby/buildkit/cache"
15 15
 	"github.com/moby/buildkit/cache/metadata"
16
-	"github.com/moby/buildkit/cache/remotecache"
16
+	registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
17 17
 	"github.com/moby/buildkit/control"
18 18
 	"github.com/moby/buildkit/exporter"
19 19
 	"github.com/moby/buildkit/frontend"
20
-	"github.com/moby/buildkit/frontend/dockerfile"
20
+	dockerfile "github.com/moby/buildkit/frontend/dockerfile/builder"
21 21
 	"github.com/moby/buildkit/frontend/gateway"
22
+	"github.com/moby/buildkit/frontend/gateway/forwarder"
22 23
 	"github.com/moby/buildkit/snapshot/blobmapping"
23 24
 	"github.com/moby/buildkit/solver/boltdbcachestorage"
24 25
 	"github.com/moby/buildkit/worker"
... ...
@@ -113,10 +114,6 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
113 113
 		return nil, err
114 114
 	}
115 115
 
116
-	frontends := map[string]frontend.Frontend{}
117
-	frontends["dockerfile.v0"] = dockerfile.NewDockerfileFrontend()
118
-	frontends["gateway.v0"] = gateway.NewGatewayFrontend()
119
-
120 116
 	wopt := mobyworker.Opt{
121 117
 		ID:                "moby",
122 118
 		SessionManager:    opt.SessionManager,
... ...
@@ -141,17 +138,17 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
141 141
 	}
142 142
 	wc.Add(w)
143 143
 
144
-	ci := remotecache.NewCacheImporter(remotecache.ImportOpt{
145
-		Worker:         w,
146
-		SessionManager: opt.SessionManager,
147
-	})
144
+	frontends := map[string]frontend.Frontend{
145
+		"dockerfile.v0": forwarder.NewGatewayForwarder(wc, dockerfile.Build),
146
+		"gateway.v0":    gateway.NewGatewayFrontend(wc),
147
+	}
148 148
 
149 149
 	return control.NewController(control.Opt{
150
-		SessionManager:   opt.SessionManager,
151
-		WorkerController: wc,
152
-		Frontends:        frontends,
153
-		CacheKeyStorage:  cacheStorage,
154
-		// CacheExporter:    ce,
155
-		CacheImporter: ci,
150
+		SessionManager:           opt.SessionManager,
151
+		WorkerController:         wc,
152
+		Frontends:                frontends,
153
+		CacheKeyStorage:          cacheStorage,
154
+		ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager),
155
+		// TODO: set ResolveCacheExporterFunc for exporting cache
156 156
 	})
157 157
 }
... ...
@@ -83,7 +83,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, ref cache.ImmutableR
83 83
 	if ref != nil {
84 84
 		layersDone := oneOffProgress(ctx, "exporting layers")
85 85
 
86
-		if err := ref.Finalize(ctx); err != nil {
86
+		if err := ref.Finalize(ctx, true); err != nil {
87 87
 			return nil, err
88 88
 		}
89 89
 
... ...
@@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.5
26 26
 golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
27 27
 
28 28
 # buildkit
29
-github.com/moby/buildkit 9acf51e49185b348608e0096b2903dd72907adcb
29
+github.com/moby/buildkit 98f1604134f945d48538ffca0e18662337b4a850
30 30
 github.com/tonistiigi/fsutil 8abad97ee3969cdf5e9c367f46adba2c212b3ddb
31 31
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
32 32
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -256,7 +256,7 @@ make test TESTPKGS=./client
256 256
 make test TESTPKGS=./client TESTFLAGS="--run /TestCallDiskUsage -v" 
257 257
 
258 258
 # run all integration tests with a specific worker
259
-# supported workers are oci and containerd
259
+# supported workers: oci, oci-rootless, containerd, containerd-1.0
260 260
 make test TESTPKGS=./client TESTFLAGS="--run //worker=containerd -v" 
261 261
 ```
262 262
 
... ...
@@ -23,7 +23,6 @@
23 23
 		BytesMessage
24 24
 		ListWorkersRequest
25 25
 		ListWorkersResponse
26
-		WorkerRecord
27 26
 */
28 27
 package moby_buildkit_v1
29 28
 
... ...
@@ -33,6 +32,7 @@ import math "math"
33 33
 import _ "github.com/gogo/protobuf/gogoproto"
34 34
 import _ "github.com/golang/protobuf/ptypes/timestamp"
35 35
 import pb "github.com/moby/buildkit/solver/pb"
36
+import moby_buildkit_v1_types "github.com/moby/buildkit/api/types"
36 37
 
37 38
 import time "time"
38 39
 import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
... ...
@@ -526,7 +526,7 @@ func (m *ListWorkersRequest) GetFilter() []string {
526 526
 }
527 527
 
528 528
 type ListWorkersResponse struct {
529
-	Record []*WorkerRecord `protobuf:"bytes,1,rep,name=record" json:"record,omitempty"`
529
+	Record []*moby_buildkit_v1_types.WorkerRecord `protobuf:"bytes,1,rep,name=record" json:"record,omitempty"`
530 530
 }
531 531
 
532 532
 func (m *ListWorkersResponse) Reset()                    { *m = ListWorkersResponse{} }
... ...
@@ -534,45 +534,13 @@ func (m *ListWorkersResponse) String() string            { return proto.CompactT
534 534
 func (*ListWorkersResponse) ProtoMessage()               {}
535 535
 func (*ListWorkersResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{14} }
536 536
 
537
-func (m *ListWorkersResponse) GetRecord() []*WorkerRecord {
537
+func (m *ListWorkersResponse) GetRecord() []*moby_buildkit_v1_types.WorkerRecord {
538 538
 	if m != nil {
539 539
 		return m.Record
540 540
 	}
541 541
 	return nil
542 542
 }
543 543
 
544
-type WorkerRecord struct {
545
-	ID        string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
546
-	Labels    map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
547
-	Platforms []pb.Platform     `protobuf:"bytes,3,rep,name=platforms" json:"platforms"`
548
-}
549
-
550
-func (m *WorkerRecord) Reset()                    { *m = WorkerRecord{} }
551
-func (m *WorkerRecord) String() string            { return proto.CompactTextString(m) }
552
-func (*WorkerRecord) ProtoMessage()               {}
553
-func (*WorkerRecord) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{15} }
554
-
555
-func (m *WorkerRecord) GetID() string {
556
-	if m != nil {
557
-		return m.ID
558
-	}
559
-	return ""
560
-}
561
-
562
-func (m *WorkerRecord) GetLabels() map[string]string {
563
-	if m != nil {
564
-		return m.Labels
565
-	}
566
-	return nil
567
-}
568
-
569
-func (m *WorkerRecord) GetPlatforms() []pb.Platform {
570
-	if m != nil {
571
-		return m.Platforms
572
-	}
573
-	return nil
574
-}
575
-
576 544
 func init() {
577 545
 	proto.RegisterType((*PruneRequest)(nil), "moby.buildkit.v1.PruneRequest")
578 546
 	proto.RegisterType((*DiskUsageRequest)(nil), "moby.buildkit.v1.DiskUsageRequest")
... ...
@@ -589,7 +557,6 @@ func init() {
589 589
 	proto.RegisterType((*BytesMessage)(nil), "moby.buildkit.v1.BytesMessage")
590 590
 	proto.RegisterType((*ListWorkersRequest)(nil), "moby.buildkit.v1.ListWorkersRequest")
591 591
 	proto.RegisterType((*ListWorkersResponse)(nil), "moby.buildkit.v1.ListWorkersResponse")
592
-	proto.RegisterType((*WorkerRecord)(nil), "moby.buildkit.v1.WorkerRecord")
593 592
 }
594 593
 
595 594
 // Reference imports to suppress errors if they are not otherwise used.
... ...
@@ -1620,59 +1587,6 @@ func (m *ListWorkersResponse) MarshalTo(dAtA []byte) (int, error) {
1620 1620
 	return i, nil
1621 1621
 }
1622 1622
 
1623
-func (m *WorkerRecord) Marshal() (dAtA []byte, err error) {
1624
-	size := m.Size()
1625
-	dAtA = make([]byte, size)
1626
-	n, err := m.MarshalTo(dAtA)
1627
-	if err != nil {
1628
-		return nil, err
1629
-	}
1630
-	return dAtA[:n], nil
1631
-}
1632
-
1633
-func (m *WorkerRecord) MarshalTo(dAtA []byte) (int, error) {
1634
-	var i int
1635
-	_ = i
1636
-	var l int
1637
-	_ = l
1638
-	if len(m.ID) > 0 {
1639
-		dAtA[i] = 0xa
1640
-		i++
1641
-		i = encodeVarintControl(dAtA, i, uint64(len(m.ID)))
1642
-		i += copy(dAtA[i:], m.ID)
1643
-	}
1644
-	if len(m.Labels) > 0 {
1645
-		for k, _ := range m.Labels {
1646
-			dAtA[i] = 0x12
1647
-			i++
1648
-			v := m.Labels[k]
1649
-			mapSize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
1650
-			i = encodeVarintControl(dAtA, i, uint64(mapSize))
1651
-			dAtA[i] = 0xa
1652
-			i++
1653
-			i = encodeVarintControl(dAtA, i, uint64(len(k)))
1654
-			i += copy(dAtA[i:], k)
1655
-			dAtA[i] = 0x12
1656
-			i++
1657
-			i = encodeVarintControl(dAtA, i, uint64(len(v)))
1658
-			i += copy(dAtA[i:], v)
1659
-		}
1660
-	}
1661
-	if len(m.Platforms) > 0 {
1662
-		for _, msg := range m.Platforms {
1663
-			dAtA[i] = 0x1a
1664
-			i++
1665
-			i = encodeVarintControl(dAtA, i, uint64(msg.Size()))
1666
-			n, err := msg.MarshalTo(dAtA[i:])
1667
-			if err != nil {
1668
-				return 0, err
1669
-			}
1670
-			i += n
1671
-		}
1672
-	}
1673
-	return i, nil
1674
-}
1675
-
1676 1623
 func encodeVarintControl(dAtA []byte, offset int, v uint64) int {
1677 1624
 	for v >= 1<<7 {
1678 1625
 		dAtA[offset] = uint8(v&0x7f | 0x80)
... ...
@@ -1984,30 +1898,6 @@ func (m *ListWorkersResponse) Size() (n int) {
1984 1984
 	return n
1985 1985
 }
1986 1986
 
1987
-func (m *WorkerRecord) Size() (n int) {
1988
-	var l int
1989
-	_ = l
1990
-	l = len(m.ID)
1991
-	if l > 0 {
1992
-		n += 1 + l + sovControl(uint64(l))
1993
-	}
1994
-	if len(m.Labels) > 0 {
1995
-		for k, v := range m.Labels {
1996
-			_ = k
1997
-			_ = v
1998
-			mapEntrySize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
1999
-			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
2000
-		}
2001
-	}
2002
-	if len(m.Platforms) > 0 {
2003
-		for _, e := range m.Platforms {
2004
-			l = e.Size()
2005
-			n += 1 + l + sovControl(uint64(l))
2006
-		}
2007
-	}
2008
-	return n
2009
-}
2010
-
2011 1987
 func sovControl(x uint64) (n int) {
2012 1988
 	for {
2013 1989
 		n++
... ...
@@ -4487,7 +4377,7 @@ func (m *ListWorkersResponse) Unmarshal(dAtA []byte) error {
4487 4487
 			if postIndex > l {
4488 4488
 				return io.ErrUnexpectedEOF
4489 4489
 			}
4490
-			m.Record = append(m.Record, &WorkerRecord{})
4490
+			m.Record = append(m.Record, &moby_buildkit_v1_types.WorkerRecord{})
4491 4491
 			if err := m.Record[len(m.Record)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
4492 4492
 				return err
4493 4493
 			}
... ...
@@ -4513,234 +4403,6 @@ func (m *ListWorkersResponse) Unmarshal(dAtA []byte) error {
4513 4513
 	}
4514 4514
 	return nil
4515 4515
 }
4516
-func (m *WorkerRecord) Unmarshal(dAtA []byte) error {
4517
-	l := len(dAtA)
4518
-	iNdEx := 0
4519
-	for iNdEx < l {
4520
-		preIndex := iNdEx
4521
-		var wire uint64
4522
-		for shift := uint(0); ; shift += 7 {
4523
-			if shift >= 64 {
4524
-				return ErrIntOverflowControl
4525
-			}
4526
-			if iNdEx >= l {
4527
-				return io.ErrUnexpectedEOF
4528
-			}
4529
-			b := dAtA[iNdEx]
4530
-			iNdEx++
4531
-			wire |= (uint64(b) & 0x7F) << shift
4532
-			if b < 0x80 {
4533
-				break
4534
-			}
4535
-		}
4536
-		fieldNum := int32(wire >> 3)
4537
-		wireType := int(wire & 0x7)
4538
-		if wireType == 4 {
4539
-			return fmt.Errorf("proto: WorkerRecord: wiretype end group for non-group")
4540
-		}
4541
-		if fieldNum <= 0 {
4542
-			return fmt.Errorf("proto: WorkerRecord: illegal tag %d (wire type %d)", fieldNum, wire)
4543
-		}
4544
-		switch fieldNum {
4545
-		case 1:
4546
-			if wireType != 2 {
4547
-				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
4548
-			}
4549
-			var stringLen uint64
4550
-			for shift := uint(0); ; shift += 7 {
4551
-				if shift >= 64 {
4552
-					return ErrIntOverflowControl
4553
-				}
4554
-				if iNdEx >= l {
4555
-					return io.ErrUnexpectedEOF
4556
-				}
4557
-				b := dAtA[iNdEx]
4558
-				iNdEx++
4559
-				stringLen |= (uint64(b) & 0x7F) << shift
4560
-				if b < 0x80 {
4561
-					break
4562
-				}
4563
-			}
4564
-			intStringLen := int(stringLen)
4565
-			if intStringLen < 0 {
4566
-				return ErrInvalidLengthControl
4567
-			}
4568
-			postIndex := iNdEx + intStringLen
4569
-			if postIndex > l {
4570
-				return io.ErrUnexpectedEOF
4571
-			}
4572
-			m.ID = string(dAtA[iNdEx:postIndex])
4573
-			iNdEx = postIndex
4574
-		case 2:
4575
-			if wireType != 2 {
4576
-				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
4577
-			}
4578
-			var msglen int
4579
-			for shift := uint(0); ; shift += 7 {
4580
-				if shift >= 64 {
4581
-					return ErrIntOverflowControl
4582
-				}
4583
-				if iNdEx >= l {
4584
-					return io.ErrUnexpectedEOF
4585
-				}
4586
-				b := dAtA[iNdEx]
4587
-				iNdEx++
4588
-				msglen |= (int(b) & 0x7F) << shift
4589
-				if b < 0x80 {
4590
-					break
4591
-				}
4592
-			}
4593
-			if msglen < 0 {
4594
-				return ErrInvalidLengthControl
4595
-			}
4596
-			postIndex := iNdEx + msglen
4597
-			if postIndex > l {
4598
-				return io.ErrUnexpectedEOF
4599
-			}
4600
-			if m.Labels == nil {
4601
-				m.Labels = make(map[string]string)
4602
-			}
4603
-			var mapkey string
4604
-			var mapvalue string
4605
-			for iNdEx < postIndex {
4606
-				entryPreIndex := iNdEx
4607
-				var wire uint64
4608
-				for shift := uint(0); ; shift += 7 {
4609
-					if shift >= 64 {
4610
-						return ErrIntOverflowControl
4611
-					}
4612
-					if iNdEx >= l {
4613
-						return io.ErrUnexpectedEOF
4614
-					}
4615
-					b := dAtA[iNdEx]
4616
-					iNdEx++
4617
-					wire |= (uint64(b) & 0x7F) << shift
4618
-					if b < 0x80 {
4619
-						break
4620
-					}
4621
-				}
4622
-				fieldNum := int32(wire >> 3)
4623
-				if fieldNum == 1 {
4624
-					var stringLenmapkey uint64
4625
-					for shift := uint(0); ; shift += 7 {
4626
-						if shift >= 64 {
4627
-							return ErrIntOverflowControl
4628
-						}
4629
-						if iNdEx >= l {
4630
-							return io.ErrUnexpectedEOF
4631
-						}
4632
-						b := dAtA[iNdEx]
4633
-						iNdEx++
4634
-						stringLenmapkey |= (uint64(b) & 0x7F) << shift
4635
-						if b < 0x80 {
4636
-							break
4637
-						}
4638
-					}
4639
-					intStringLenmapkey := int(stringLenmapkey)
4640
-					if intStringLenmapkey < 0 {
4641
-						return ErrInvalidLengthControl
4642
-					}
4643
-					postStringIndexmapkey := iNdEx + intStringLenmapkey
4644
-					if postStringIndexmapkey > l {
4645
-						return io.ErrUnexpectedEOF
4646
-					}
4647
-					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
4648
-					iNdEx = postStringIndexmapkey
4649
-				} else if fieldNum == 2 {
4650
-					var stringLenmapvalue uint64
4651
-					for shift := uint(0); ; shift += 7 {
4652
-						if shift >= 64 {
4653
-							return ErrIntOverflowControl
4654
-						}
4655
-						if iNdEx >= l {
4656
-							return io.ErrUnexpectedEOF
4657
-						}
4658
-						b := dAtA[iNdEx]
4659
-						iNdEx++
4660
-						stringLenmapvalue |= (uint64(b) & 0x7F) << shift
4661
-						if b < 0x80 {
4662
-							break
4663
-						}
4664
-					}
4665
-					intStringLenmapvalue := int(stringLenmapvalue)
4666
-					if intStringLenmapvalue < 0 {
4667
-						return ErrInvalidLengthControl
4668
-					}
4669
-					postStringIndexmapvalue := iNdEx + intStringLenmapvalue
4670
-					if postStringIndexmapvalue > l {
4671
-						return io.ErrUnexpectedEOF
4672
-					}
4673
-					mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
4674
-					iNdEx = postStringIndexmapvalue
4675
-				} else {
4676
-					iNdEx = entryPreIndex
4677
-					skippy, err := skipControl(dAtA[iNdEx:])
4678
-					if err != nil {
4679
-						return err
4680
-					}
4681
-					if skippy < 0 {
4682
-						return ErrInvalidLengthControl
4683
-					}
4684
-					if (iNdEx + skippy) > postIndex {
4685
-						return io.ErrUnexpectedEOF
4686
-					}
4687
-					iNdEx += skippy
4688
-				}
4689
-			}
4690
-			m.Labels[mapkey] = mapvalue
4691
-			iNdEx = postIndex
4692
-		case 3:
4693
-			if wireType != 2 {
4694
-				return fmt.Errorf("proto: wrong wireType = %d for field Platforms", wireType)
4695
-			}
4696
-			var msglen int
4697
-			for shift := uint(0); ; shift += 7 {
4698
-				if shift >= 64 {
4699
-					return ErrIntOverflowControl
4700
-				}
4701
-				if iNdEx >= l {
4702
-					return io.ErrUnexpectedEOF
4703
-				}
4704
-				b := dAtA[iNdEx]
4705
-				iNdEx++
4706
-				msglen |= (int(b) & 0x7F) << shift
4707
-				if b < 0x80 {
4708
-					break
4709
-				}
4710
-			}
4711
-			if msglen < 0 {
4712
-				return ErrInvalidLengthControl
4713
-			}
4714
-			postIndex := iNdEx + msglen
4715
-			if postIndex > l {
4716
-				return io.ErrUnexpectedEOF
4717
-			}
4718
-			m.Platforms = append(m.Platforms, pb.Platform{})
4719
-			if err := m.Platforms[len(m.Platforms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
4720
-				return err
4721
-			}
4722
-			iNdEx = postIndex
4723
-		default:
4724
-			iNdEx = preIndex
4725
-			skippy, err := skipControl(dAtA[iNdEx:])
4726
-			if err != nil {
4727
-				return err
4728
-			}
4729
-			if skippy < 0 {
4730
-				return ErrInvalidLengthControl
4731
-			}
4732
-			if (iNdEx + skippy) > l {
4733
-				return io.ErrUnexpectedEOF
4734
-			}
4735
-			iNdEx += skippy
4736
-		}
4737
-	}
4738
-
4739
-	if iNdEx > l {
4740
-		return io.ErrUnexpectedEOF
4741
-	}
4742
-	return nil
4743
-}
4744 4516
 func skipControl(dAtA []byte) (n int, err error) {
4745 4517
 	l := len(dAtA)
4746 4518
 	iNdEx := 0
... ...
@@ -4849,81 +4511,79 @@ var (
4849 4849
 func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
4850 4850
 
4851 4851
 var fileDescriptorControl = []byte{
4852
-	// 1214 bytes of a gzipped FileDescriptorProto
4853
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0x4f, 0x6f, 0x1b, 0x55,
4854
-	0x10, 0x67, 0x6d, 0xc7, 0xf6, 0x8e, 0x9d, 0x28, 0x3c, 0xa0, 0x5a, 0x2d, 0x90, 0x98, 0x05, 0x24,
4855
-	0xab, 0x6a, 0xd7, 0x69, 0xa0, 0x08, 0x72, 0xa8, 0x5a, 0xc7, 0x45, 0x24, 0x4a, 0x44, 0xd8, 0x34,
4856
-	0x54, 0xe2, 0xb6, 0xb6, 0x5f, 0xdc, 0x55, 0xd6, 0xfb, 0x96, 0xf7, 0x9e, 0xa3, 0x86, 0x4f, 0xc1,
4857
-	0x81, 0x6f, 0xc2, 0x81, 0x33, 0x07, 0xa4, 0xde, 0xe0, 0xcc, 0x21, 0x45, 0xb9, 0xc3, 0x67, 0x40,
4858
-	0xef, 0xcf, 0xda, 0xcf, 0x5e, 0xe7, 0x8f, 0xd3, 0x93, 0xdf, 0xcc, 0xfe, 0xe6, 0xb7, 0xf3, 0x66,
4859
-	0x66, 0x67, 0xc6, 0xb0, 0xdc, 0x23, 0x09, 0xa7, 0x24, 0xf6, 0x53, 0x4a, 0x38, 0x41, 0xab, 0x43,
4860
-	0xd2, 0x3d, 0xf3, 0xbb, 0xa3, 0x28, 0xee, 0x9f, 0x44, 0xdc, 0x3f, 0x7d, 0xe0, 0xde, 0x1f, 0x44,
4861
-	0xfc, 0xc5, 0xa8, 0xeb, 0xf7, 0xc8, 0xb0, 0x35, 0x20, 0x03, 0xd2, 0x92, 0xc0, 0xee, 0xe8, 0x58,
4862
-	0x4a, 0x52, 0x90, 0x27, 0x45, 0xe0, 0xae, 0x0f, 0x08, 0x19, 0xc4, 0x78, 0x82, 0xe2, 0xd1, 0x10,
4863
-	0x33, 0x1e, 0x0e, 0x53, 0x0d, 0xb8, 0x67, 0xf0, 0x89, 0x97, 0xb5, 0xb2, 0x97, 0xb5, 0x18, 0x89,
4864
-	0x4f, 0x31, 0x6d, 0xa5, 0xdd, 0x16, 0x49, 0x99, 0x42, 0x7b, 0x2b, 0x50, 0x3f, 0xa0, 0xa3, 0x04,
4865
-	0x07, 0xf8, 0xc7, 0x11, 0x66, 0xdc, 0xbb, 0x0b, 0xab, 0x9d, 0x88, 0x9d, 0x1c, 0xb1, 0x70, 0x90,
4866
-	0xe9, 0xd0, 0x1d, 0x28, 0x1f, 0x47, 0x31, 0xc7, 0xd4, 0xb1, 0x1a, 0x56, 0xd3, 0x0e, 0xb4, 0xe4,
4867
-	0xed, 0xc2, 0xdb, 0x06, 0x96, 0xa5, 0x24, 0x61, 0x18, 0x3d, 0x84, 0x32, 0xc5, 0x3d, 0x42, 0xfb,
4868
-	0x8e, 0xd5, 0x28, 0x36, 0x6b, 0x9b, 0x1f, 0xfa, 0xb3, 0x37, 0xf6, 0xb5, 0x81, 0x00, 0x05, 0x1a,
4869
-	0xec, 0xfd, 0x5e, 0x80, 0x9a, 0xa1, 0x47, 0x2b, 0x50, 0xd8, 0xe9, 0xe8, 0xf7, 0x15, 0x76, 0x3a,
4870
-	0xc8, 0x81, 0xca, 0xfe, 0x88, 0x87, 0xdd, 0x18, 0x3b, 0x85, 0x86, 0xd5, 0xac, 0x06, 0x99, 0x88,
4871
-	0xde, 0x85, 0xa5, 0x9d, 0xe4, 0x88, 0x61, 0xa7, 0x28, 0xf5, 0x4a, 0x40, 0x08, 0x4a, 0x87, 0xd1,
4872
-	0x4f, 0xd8, 0x29, 0x35, 0xac, 0x66, 0x31, 0x90, 0x67, 0x71, 0x8f, 0x83, 0x90, 0xe2, 0x84, 0x3b,
4873
-	0x4b, 0xea, 0x1e, 0x4a, 0x42, 0x6d, 0xb0, 0xb7, 0x29, 0x0e, 0x39, 0xee, 0x3f, 0xe1, 0x4e, 0xb9,
4874
-	0x61, 0x35, 0x6b, 0x9b, 0xae, 0xaf, 0xc2, 0xec, 0x67, 0x61, 0xf6, 0x9f, 0x65, 0x61, 0x6e, 0x57,
4875
-	0x5f, 0x9d, 0xaf, 0xbf, 0xf5, 0xf3, 0xeb, 0x75, 0x2b, 0x98, 0x98, 0xa1, 0xc7, 0x00, 0x7b, 0x21,
4876
-	0xe3, 0x47, 0x4c, 0x92, 0x54, 0xae, 0x25, 0x29, 0x49, 0x02, 0xc3, 0x06, 0xad, 0x01, 0xc8, 0x00,
4877
-	0x6c, 0x93, 0x51, 0xc2, 0x9d, 0xaa, 0xf4, 0xdb, 0xd0, 0xa0, 0x06, 0xd4, 0x3a, 0x98, 0xf5, 0x68,
4878
-	0x94, 0xf2, 0x88, 0x24, 0x8e, 0x2d, 0xaf, 0x60, 0xaa, 0xbc, 0x5f, 0x4a, 0x50, 0x3f, 0x14, 0x39,
4879
-	0xce, 0x12, 0xb7, 0x0a, 0xc5, 0x00, 0x1f, 0xeb, 0x28, 0x8a, 0x23, 0xf2, 0x01, 0x3a, 0xf8, 0x38,
4880
-	0x4a, 0x22, 0xc9, 0x51, 0x90, 0x6e, 0xae, 0xf8, 0x69, 0xd7, 0x9f, 0x68, 0x03, 0x03, 0x81, 0x5c,
4881
-	0xa8, 0x3e, 0x7d, 0x99, 0x12, 0x2a, 0x92, 0x5f, 0x94, 0x34, 0x63, 0x19, 0x3d, 0x87, 0xe5, 0xec,
4882
-	0xfc, 0x84, 0x73, 0xca, 0x9c, 0x92, 0x4c, 0xf8, 0x83, 0x7c, 0xc2, 0x4d, 0xa7, 0xfc, 0x29, 0x9b,
4883
-	0xa7, 0x09, 0xa7, 0x67, 0xc1, 0x34, 0x8f, 0xc8, 0xf5, 0x21, 0x66, 0x4c, 0x78, 0xa8, 0x12, 0x95,
4884
-	0x89, 0xc2, 0x9d, 0xaf, 0x29, 0x49, 0x38, 0x4e, 0xfa, 0x32, 0x51, 0x76, 0x30, 0x96, 0x85, 0x3b,
4885
-	0xd9, 0x59, 0xb9, 0x53, 0xb9, 0x91, 0x3b, 0x53, 0x36, 0xda, 0x9d, 0x29, 0x1d, 0xda, 0x82, 0xa5,
4886
-	0xed, 0xb0, 0xf7, 0x02, 0xcb, 0x9c, 0xd4, 0x36, 0xd7, 0xf2, 0x84, 0xf2, 0xf1, 0xb7, 0x32, 0x09,
4887
-	0xac, 0x5d, 0x12, 0xe5, 0x11, 0x28, 0x13, 0xf7, 0x31, 0xa0, 0xfc, 0x7d, 0x45, 0x5e, 0x4e, 0xf0,
4888
-	0x59, 0x96, 0x97, 0x13, 0x7c, 0x26, 0x8a, 0xf8, 0x34, 0x8c, 0x47, 0xaa, 0xb8, 0xed, 0x40, 0x09,
4889
-	0x5b, 0x85, 0x2f, 0x2d, 0xc1, 0x90, 0x77, 0x71, 0x11, 0x06, 0xef, 0xb5, 0x05, 0x75, 0xd3, 0x43,
4890
-	0xf4, 0x01, 0xd8, 0xca, 0xa9, 0x49, 0x71, 0x4c, 0x14, 0xa2, 0x0e, 0x77, 0x86, 0x5a, 0x60, 0x4e,
4891
-	0xa1, 0x51, 0x6c, 0xda, 0x81, 0xa1, 0x41, 0xdf, 0x41, 0x4d, 0x81, 0x55, 0x94, 0x8b, 0x32, 0xca,
4892
-	0xad, 0xab, 0x83, 0xe2, 0x1b, 0x16, 0x2a, 0xc6, 0x26, 0x87, 0xfb, 0x08, 0x56, 0x67, 0x01, 0x0b,
4893
-	0xdd, 0xf0, 0x37, 0x0b, 0x96, 0x75, 0x52, 0x75, 0x17, 0x0a, 0x33, 0x46, 0x4c, 0x33, 0x9d, 0xee,
4894
-	0x47, 0x0f, 0x2f, 0xad, 0x07, 0x05, 0xf3, 0x67, 0xed, 0x94, 0xbf, 0x39, 0x3a, 0x77, 0x1b, 0xde,
4895
-	0x9b, 0x0b, 0x5d, 0xc8, 0xf3, 0x8f, 0x60, 0xf9, 0x90, 0x87, 0x7c, 0xc4, 0x2e, 0xfd, 0x64, 0xbd,
4896
-	0x5f, 0x2d, 0x58, 0xc9, 0x30, 0xfa, 0x76, 0x9f, 0x43, 0xf5, 0x14, 0x53, 0x8e, 0x5f, 0x62, 0xa6,
4897
-	0x6f, 0xe5, 0xe4, 0x6f, 0xf5, 0xbd, 0x44, 0x04, 0x63, 0x24, 0xda, 0x82, 0x2a, 0x93, 0x3c, 0x58,
4898
-	0xa5, 0x75, 0x6e, 0x29, 0x2b, 0x2b, 0xfd, 0xbe, 0x31, 0x1e, 0xb5, 0xa0, 0x14, 0x93, 0x41, 0x96,
4899
-	0xed, 0xf7, 0x2f, 0xb3, 0xdb, 0x23, 0x83, 0x40, 0x02, 0xbd, 0xf3, 0x02, 0x94, 0x95, 0x0e, 0xed,
4900
-	0x42, 0xb9, 0x1f, 0x0d, 0x30, 0xe3, 0xea, 0x56, 0xed, 0x4d, 0xf1, 0x81, 0xfc, 0x7d, 0xbe, 0x7e,
4901
-	0xd7, 0x18, 0x54, 0x24, 0xc5, 0x89, 0x18, 0x94, 0x61, 0x94, 0x60, 0xca, 0x5a, 0x03, 0x72, 0x5f,
4902
-	0x99, 0xf8, 0x1d, 0xf9, 0x13, 0x68, 0x06, 0xc1, 0x15, 0x25, 0xe9, 0x88, 0xeb, 0xc2, 0xbc, 0x1d,
4903
-	0x97, 0x62, 0x10, 0x23, 0x22, 0x09, 0x87, 0x58, 0xf7, 0x35, 0x79, 0x16, 0x23, 0xa2, 0x27, 0xea,
4904
-	0xb6, 0x2f, 0x07, 0x47, 0x35, 0xd0, 0x12, 0xda, 0x82, 0x0a, 0xe3, 0x21, 0xe5, 0xb8, 0x2f, 0x5b,
4905
-	0xd2, 0x4d, 0x7a, 0x7b, 0x66, 0x80, 0x1e, 0x81, 0xdd, 0x23, 0xc3, 0x34, 0xc6, 0xc2, 0xba, 0x7c,
4906
-	0x43, 0xeb, 0x89, 0x89, 0xa8, 0x1e, 0x4c, 0x29, 0xa1, 0x72, 0xaa, 0xd8, 0x81, 0x12, 0xbc, 0xff,
4907
-	0x0a, 0x50, 0x37, 0x93, 0x95, 0x9b, 0x98, 0xbb, 0x50, 0x56, 0xa9, 0x57, 0x55, 0x77, 0xbb, 0x50,
4908
-	0x29, 0x86, 0xb9, 0xa1, 0x72, 0xa0, 0xd2, 0x1b, 0x51, 0x39, 0x4e, 0xd5, 0x90, 0xcd, 0x44, 0xe1,
4909
-	0x30, 0x27, 0x3c, 0x8c, 0x65, 0xa8, 0x8a, 0x81, 0x12, 0xc4, 0x94, 0x1d, 0xaf, 0x2a, 0x8b, 0x4d,
4910
-	0xd9, 0xb1, 0x99, 0x99, 0x86, 0xca, 0x1b, 0xa5, 0xa1, 0xba, 0x70, 0x1a, 0xbc, 0x3f, 0x2c, 0xb0,
4911
-	0xc7, 0x55, 0x6e, 0x44, 0xd7, 0x7a, 0xe3, 0xe8, 0x4e, 0x45, 0xa6, 0x70, 0xbb, 0xc8, 0xdc, 0x81,
4912
-	0x32, 0xe3, 0x14, 0x87, 0x43, 0x99, 0xa3, 0x62, 0xa0, 0x25, 0xd1, 0x4f, 0x86, 0x6c, 0x20, 0x33,
4913
-	0x54, 0x0f, 0xc4, 0xd1, 0xf3, 0xa0, 0xde, 0x3e, 0xe3, 0x98, 0xed, 0x63, 0x26, 0x96, 0x0b, 0x91,
4914
-	0xdb, 0x7e, 0xc8, 0x43, 0x79, 0x8f, 0x7a, 0x20, 0xcf, 0xde, 0x3d, 0x40, 0x7b, 0x11, 0xe3, 0xcf,
4915
-	0x09, 0x3d, 0xc1, 0x94, 0xcd, 0xdb, 0x03, 0x8b, 0xc6, 0x1e, 0xb8, 0x0f, 0xef, 0x4c, 0xa1, 0x75,
4916
-	0x97, 0xfa, 0x62, 0x66, 0x13, 0x9c, 0xd3, 0x6d, 0x94, 0xc9, 0xcc, 0x2a, 0xf8, 0xa7, 0x05, 0x75,
4917
-	0xf3, 0x41, 0xae, 0xb2, 0xdb, 0x50, 0xde, 0x0b, 0xbb, 0x38, 0xce, 0xda, 0xd8, 0xdd, 0xab, 0x89,
4918
-	0x7d, 0x05, 0x56, 0x7d, 0x5c, 0x5b, 0xa2, 0x0d, 0xb0, 0xd3, 0x38, 0xe4, 0xc7, 0x84, 0x0e, 0xb3,
4919
-	0xae, 0x56, 0x17, 0x7b, 0xd0, 0x81, 0x56, 0xea, 0x31, 0x3e, 0x01, 0xb9, 0x5f, 0x41, 0xcd, 0x20,
4920
-	0x5a, 0xa4, 0xcb, 0x6f, 0xfe, 0x5b, 0x84, 0xca, 0xb6, 0xfa, 0x1b, 0x80, 0x9e, 0x81, 0x3d, 0x5e,
4921
-	0x9a, 0x91, 0x97, 0xf7, 0x7c, 0x76, 0xfb, 0x76, 0x3f, 0xbe, 0x12, 0xa3, 0x63, 0xfd, 0x0d, 0x2c,
4922
-	0xc9, 0x35, 0x1e, 0xcd, 0x09, 0xb2, 0xb9, 0xdf, 0xbb, 0x57, 0xaf, 0xe3, 0x1b, 0x96, 0x60, 0x92,
4923
-	0xf3, 0x70, 0x1e, 0x93, 0xb9, 0x38, 0xb9, 0xeb, 0xd7, 0x0c, 0x52, 0xb4, 0x0f, 0x65, 0xdd, 0x9a,
4924
-	0xe6, 0x41, 0xcd, 0xa9, 0xe7, 0x36, 0x2e, 0x07, 0x28, 0xb2, 0x0d, 0x0b, 0xed, 0x8f, 0xb7, 0xc2,
4925
-	0x79, 0xae, 0x99, 0x25, 0xed, 0x5e, 0xf3, 0xbc, 0x69, 0x6d, 0x58, 0xe8, 0x07, 0xa8, 0x19, 0x45,
4926
-	0x8b, 0x3e, 0xc9, 0x9b, 0xe4, 0xbf, 0x00, 0xf7, 0xd3, 0x6b, 0x50, 0xca, 0xd9, 0x76, 0xfd, 0xd5,
4927
-	0xc5, 0x9a, 0xf5, 0xd7, 0xc5, 0x9a, 0xf5, 0xcf, 0xc5, 0x9a, 0xd5, 0x2d, 0xcb, 0x6f, 0xf8, 0xb3,
4928
-	0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x86, 0xd4, 0x0f, 0xa1, 0x0a, 0x0e, 0x00, 0x00,
4852
+	// 1176 bytes of a gzipped FileDescriptorProto
4853
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4d, 0x6f, 0x23, 0x45,
4854
+	0x13, 0x7e, 0xc7, 0x76, 0xfc, 0x51, 0x76, 0xa2, 0xbc, 0x0d, 0xac, 0x46, 0x03, 0x24, 0x66, 0x00,
4855
+	0xc9, 0x5a, 0xed, 0xce, 0x64, 0x03, 0x2b, 0xa1, 0x08, 0xad, 0x76, 0x1d, 0x2f, 0x22, 0x51, 0x22,
4856
+	0x96, 0xce, 0x86, 0x95, 0xb8, 0x8d, 0xed, 0x8e, 0x77, 0x14, 0x7b, 0x7a, 0xe8, 0xee, 0x09, 0x6b,
4857
+	0x7e, 0x05, 0x07, 0xfe, 0x09, 0x07, 0xce, 0x1c, 0x90, 0xf6, 0xc8, 0x99, 0x43, 0x16, 0xe5, 0x0e,
4858
+	0xbf, 0x01, 0xf5, 0xc7, 0xd8, 0xed, 0xd8, 0xf9, 0xdc, 0x53, 0xba, 0x2a, 0x4f, 0x3d, 0x53, 0x5d,
4859
+	0x4f, 0xb9, 0xab, 0x60, 0xb9, 0x47, 0x13, 0xc1, 0xe8, 0x30, 0x48, 0x19, 0x15, 0x14, 0xad, 0x8e,
4860
+	0x68, 0x77, 0x1c, 0x74, 0xb3, 0x78, 0xd8, 0x3f, 0x8e, 0x45, 0x70, 0xf2, 0xc0, 0xbb, 0x3f, 0x88,
4861
+	0xc5, 0xcb, 0xac, 0x1b, 0xf4, 0xe8, 0x28, 0x1c, 0xd0, 0x01, 0x0d, 0x15, 0xb0, 0x9b, 0x1d, 0x29,
4862
+	0x4b, 0x19, 0xea, 0xa4, 0x09, 0xbc, 0xf5, 0x01, 0xa5, 0x83, 0x21, 0x99, 0xa2, 0x44, 0x3c, 0x22,
4863
+	0x5c, 0x44, 0xa3, 0xd4, 0x00, 0xee, 0x59, 0x7c, 0xf2, 0x63, 0x61, 0xfe, 0xb1, 0x90, 0xd3, 0xe1,
4864
+	0x09, 0x61, 0x61, 0xda, 0x0d, 0x69, 0xca, 0x0d, 0x3a, 0xbc, 0x10, 0x1d, 0xa5, 0x71, 0x28, 0xc6,
4865
+	0x29, 0xe1, 0xe1, 0x8f, 0x94, 0x1d, 0x13, 0xa6, 0x03, 0xfc, 0x15, 0x68, 0x3c, 0x63, 0x59, 0x42,
4866
+	0x30, 0xf9, 0x21, 0x23, 0x5c, 0xf8, 0x77, 0x61, 0xb5, 0x13, 0xf3, 0xe3, 0x43, 0x1e, 0x0d, 0x72,
4867
+	0x1f, 0xba, 0x03, 0xe5, 0xa3, 0x78, 0x28, 0x08, 0x73, 0x9d, 0xa6, 0xd3, 0xaa, 0x61, 0x63, 0xf9,
4868
+	0xbb, 0xf0, 0x7f, 0x0b, 0xcb, 0x53, 0x9a, 0x70, 0x82, 0x1e, 0x42, 0x99, 0x91, 0x1e, 0x65, 0x7d,
4869
+	0xd7, 0x69, 0x16, 0x5b, 0xf5, 0xcd, 0x0f, 0x83, 0xf3, 0x25, 0x0a, 0x4c, 0x80, 0x04, 0x61, 0x03,
4870
+	0xf6, 0x7f, 0x2f, 0x40, 0xdd, 0xf2, 0xa3, 0x15, 0x28, 0xec, 0x74, 0xcc, 0xf7, 0x0a, 0x3b, 0x1d,
4871
+	0xe4, 0x42, 0x65, 0x3f, 0x13, 0x51, 0x77, 0x48, 0xdc, 0x42, 0xd3, 0x69, 0x55, 0x71, 0x6e, 0xa2,
4872
+	0x77, 0x61, 0x69, 0x27, 0x39, 0xe4, 0xc4, 0x2d, 0x2a, 0xbf, 0x36, 0x10, 0x82, 0xd2, 0x41, 0xfc,
4873
+	0x13, 0x71, 0x4b, 0x4d, 0xa7, 0x55, 0xc4, 0xea, 0x2c, 0xef, 0xf1, 0x2c, 0x62, 0x24, 0x11, 0xee,
4874
+	0x92, 0xbe, 0x87, 0xb6, 0x50, 0x1b, 0x6a, 0xdb, 0x8c, 0x44, 0x82, 0xf4, 0x9f, 0x08, 0xb7, 0xdc,
4875
+	0x74, 0x5a, 0xf5, 0x4d, 0x2f, 0xd0, 0xba, 0x04, 0xb9, 0x2e, 0xc1, 0xf3, 0x5c, 0x97, 0x76, 0xf5,
4876
+	0xf5, 0xe9, 0xfa, 0xff, 0x7e, 0x7e, 0xb3, 0xee, 0xe0, 0x69, 0x18, 0x7a, 0x0c, 0xb0, 0x17, 0x71,
4877
+	0x71, 0xc8, 0x15, 0x49, 0xe5, 0x4a, 0x92, 0x92, 0x22, 0xb0, 0x62, 0xd0, 0x1a, 0x80, 0x2a, 0xc0,
4878
+	0x36, 0xcd, 0x12, 0xe1, 0x56, 0x55, 0xde, 0x96, 0x07, 0x35, 0xa1, 0xde, 0x21, 0xbc, 0xc7, 0xe2,
4879
+	0x54, 0xc4, 0x34, 0x71, 0x6b, 0xea, 0x0a, 0xb6, 0xcb, 0xff, 0xa5, 0x04, 0x8d, 0x03, 0xd9, 0x14,
4880
+	0xb9, 0x70, 0xab, 0x50, 0xc4, 0xe4, 0xc8, 0x54, 0x51, 0x1e, 0x51, 0x00, 0xd0, 0x21, 0x47, 0x71,
4881
+	0x12, 0x2b, 0x8e, 0x82, 0x4a, 0x73, 0x25, 0x48, 0xbb, 0xc1, 0xd4, 0x8b, 0x2d, 0x04, 0xf2, 0xa0,
4882
+	0xfa, 0xf4, 0x55, 0x4a, 0x99, 0x14, 0xbf, 0xa8, 0x68, 0x26, 0x36, 0x7a, 0x01, 0xcb, 0xf9, 0xf9,
4883
+	0x89, 0x10, 0x8c, 0xbb, 0x25, 0x25, 0xf8, 0x83, 0x79, 0xc1, 0xed, 0xa4, 0x82, 0x99, 0x98, 0xa7,
4884
+	0x89, 0x60, 0x63, 0x3c, 0xcb, 0x23, 0xb5, 0x3e, 0x20, 0x9c, 0xcb, 0x0c, 0xb5, 0x50, 0xb9, 0x29,
4885
+	0xd3, 0xf9, 0x8a, 0xd1, 0x44, 0x90, 0xa4, 0xaf, 0x84, 0xaa, 0xe1, 0x89, 0x2d, 0xd3, 0xc9, 0xcf,
4886
+	0x3a, 0x9d, 0xca, 0xb5, 0xd2, 0x99, 0x89, 0x31, 0xe9, 0xcc, 0xf8, 0xd0, 0x16, 0x2c, 0x6d, 0x47,
4887
+	0xbd, 0x97, 0x44, 0x69, 0x52, 0xdf, 0x5c, 0x9b, 0x27, 0x54, 0xff, 0xfe, 0x46, 0x89, 0xc0, 0xdb,
4888
+	0x25, 0xd9, 0x1e, 0x58, 0x87, 0x78, 0x8f, 0x01, 0xcd, 0xdf, 0x57, 0xea, 0x72, 0x4c, 0xc6, 0xb9,
4889
+	0x2e, 0xc7, 0x64, 0x2c, 0x9b, 0xf8, 0x24, 0x1a, 0x66, 0xba, 0xb9, 0x6b, 0x58, 0x1b, 0x5b, 0x85,
4890
+	0x2f, 0x1c, 0xc9, 0x30, 0x9f, 0xe2, 0x4d, 0x18, 0xfc, 0x37, 0x0e, 0x34, 0xec, 0x0c, 0xd1, 0x07,
4891
+	0x50, 0xd3, 0x49, 0x4d, 0x9b, 0x63, 0xea, 0x90, 0x7d, 0xb8, 0x33, 0x32, 0x06, 0x77, 0x0b, 0xcd,
4892
+	0x62, 0xab, 0x86, 0x2d, 0x0f, 0xfa, 0x16, 0xea, 0x1a, 0xac, 0xab, 0x5c, 0x54, 0x55, 0x0e, 0x2f,
4893
+	0x2f, 0x4a, 0x60, 0x45, 0xe8, 0x1a, 0xdb, 0x1c, 0xde, 0x23, 0x58, 0x3d, 0x0f, 0xb8, 0xd1, 0x0d,
4894
+	0x7f, 0x73, 0x60, 0xd9, 0x88, 0x6a, 0x5e, 0xa1, 0x28, 0x67, 0x24, 0x2c, 0xf7, 0x99, 0xf7, 0xe8,
4895
+	0xe1, 0x85, 0xfd, 0xa0, 0x61, 0xc1, 0xf9, 0x38, 0x9d, 0xef, 0x1c, 0x9d, 0xb7, 0x0d, 0xef, 0x2d,
4896
+	0x84, 0xde, 0x28, 0xf3, 0x8f, 0x60, 0xf9, 0x40, 0x44, 0x22, 0xe3, 0x17, 0xfe, 0x64, 0xfd, 0x5f,
4897
+	0x1d, 0x58, 0xc9, 0x31, 0xe6, 0x76, 0x9f, 0x43, 0xf5, 0x84, 0x30, 0x41, 0x5e, 0x11, 0x6e, 0x6e,
4898
+	0xe5, 0xce, 0xdf, 0xea, 0x3b, 0x85, 0xc0, 0x13, 0x24, 0xda, 0x82, 0x2a, 0x57, 0x3c, 0x44, 0xcb,
4899
+	0xba, 0xb0, 0x95, 0x75, 0x94, 0xf9, 0xde, 0x04, 0x8f, 0x42, 0x28, 0x0d, 0xe9, 0x20, 0x57, 0xfb,
4900
+	0xfd, 0x8b, 0xe2, 0xf6, 0xe8, 0x00, 0x2b, 0xa0, 0x7f, 0x5a, 0x80, 0xb2, 0xf6, 0xa1, 0x5d, 0x28,
4901
+	0xf7, 0xe3, 0x01, 0xe1, 0x42, 0xdf, 0xaa, 0xbd, 0x29, 0x7f, 0x20, 0x7f, 0x9d, 0xae, 0xdf, 0xb5,
4902
+	0x66, 0x15, 0x4d, 0x49, 0x22, 0x27, 0x6b, 0x14, 0x27, 0x84, 0xf1, 0x70, 0x40, 0xef, 0xeb, 0x90,
4903
+	0xa0, 0xa3, 0xfe, 0x60, 0xc3, 0x20, 0xb9, 0xe2, 0x24, 0xcd, 0x84, 0x69, 0xcc, 0xdb, 0x71, 0x69,
4904
+	0x06, 0x39, 0x22, 0x92, 0x68, 0x44, 0xcc, 0xbb, 0xa6, 0xce, 0x72, 0x44, 0xf4, 0x64, 0xdf, 0xf6,
4905
+	0xd5, 0xe0, 0xa8, 0x62, 0x63, 0xa1, 0x2d, 0xa8, 0x70, 0x11, 0x31, 0x41, 0xfa, 0xea, 0x49, 0xba,
4906
+	0xce, 0xdb, 0x9e, 0x07, 0xa0, 0x47, 0x50, 0xeb, 0xd1, 0x51, 0x3a, 0x24, 0x32, 0xba, 0x7c, 0xcd,
4907
+	0xe8, 0x69, 0x88, 0xec, 0x1e, 0xc2, 0x18, 0x65, 0x6a, 0xaa, 0xd4, 0xb0, 0x36, 0xfc, 0x7f, 0x0b,
4908
+	0xd0, 0xb0, 0xc5, 0x9a, 0x9b, 0x98, 0xbb, 0x50, 0xd6, 0xd2, 0xeb, 0xae, 0xbb, 0x5d, 0xa9, 0x34,
4909
+	0xc3, 0xc2, 0x52, 0xb9, 0x50, 0xe9, 0x65, 0x4c, 0x8d, 0x53, 0x3d, 0x64, 0x73, 0x53, 0x26, 0x2c,
4910
+	0xa8, 0x88, 0x86, 0xaa, 0x54, 0x45, 0xac, 0x0d, 0x39, 0x65, 0x27, 0xbb, 0xcd, 0xcd, 0xa6, 0xec,
4911
+	0x24, 0xcc, 0x96, 0xa1, 0xf2, 0x56, 0x32, 0x54, 0x6f, 0x2c, 0x83, 0xff, 0x87, 0x03, 0xb5, 0x49,
4912
+	0x97, 0x5b, 0xd5, 0x75, 0xde, 0xba, 0xba, 0x33, 0x95, 0x29, 0xdc, 0xae, 0x32, 0x77, 0xa0, 0xcc,
4913
+	0x05, 0x23, 0xd1, 0x48, 0x69, 0x54, 0xc4, 0xc6, 0x92, 0xef, 0xc9, 0x88, 0x0f, 0x94, 0x42, 0x0d,
4914
+	0x2c, 0x8f, 0xbe, 0x0f, 0x8d, 0xf6, 0x58, 0x10, 0xbe, 0x4f, 0xb8, 0x5c, 0x2e, 0xa4, 0xb6, 0xfd,
4915
+	0x48, 0x44, 0xea, 0x1e, 0x0d, 0xac, 0xce, 0xfe, 0x3d, 0x40, 0x7b, 0x31, 0x17, 0x2f, 0xd4, 0xa6,
4916
+	0xc8, 0x17, 0xed, 0x81, 0x45, 0x6b, 0x0f, 0x3c, 0x80, 0x77, 0x66, 0xd0, 0xe6, 0x95, 0xfa, 0xf2,
4917
+	0xdc, 0x26, 0xf8, 0xc9, 0xfc, 0xab, 0xa1, 0x16, 0xd2, 0x40, 0x07, 0xce, 0x2e, 0x84, 0x9b, 0xff,
4918
+	0x14, 0xa1, 0xb2, 0xad, 0x77, 0x6d, 0xf4, 0x1c, 0x6a, 0x93, 0x45, 0x13, 0xf9, 0xf3, 0x34, 0xe7,
4919
+	0x37, 0x56, 0xef, 0xe3, 0x4b, 0x31, 0x26, 0xbf, 0xaf, 0x61, 0x49, 0xad, 0xbe, 0x68, 0xc1, 0x33,
4920
+	0x68, 0xef, 0xc4, 0xde, 0xe5, 0x2b, 0xec, 0x86, 0x23, 0x99, 0xd4, 0x0c, 0x59, 0xc4, 0x64, 0x2f,
4921
+	0x1b, 0xde, 0xfa, 0x15, 0xc3, 0x07, 0xed, 0x43, 0xd9, 0xfc, 0x9c, 0x17, 0x41, 0xed, 0x49, 0xe1,
4922
+	0x35, 0x2f, 0x06, 0x68, 0xb2, 0x0d, 0x07, 0xed, 0x4f, 0x36, 0xa9, 0x45, 0xa9, 0xd9, 0x6d, 0xe0,
4923
+	0x5d, 0xf1, 0xff, 0x96, 0xb3, 0xe1, 0xa0, 0xef, 0xa1, 0x6e, 0x09, 0x8d, 0x16, 0x08, 0x3a, 0xdf,
4924
+	0x35, 0xde, 0xa7, 0x57, 0xa0, 0x74, 0xb2, 0xed, 0xc6, 0xeb, 0xb3, 0x35, 0xe7, 0xcf, 0xb3, 0x35,
4925
+	0xe7, 0xef, 0xb3, 0x35, 0xa7, 0x5b, 0x56, 0x7d, 0xff, 0xd9, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff,
4926
+	0xe1, 0xef, 0xcc, 0xf5, 0x6f, 0x0d, 0x00, 0x00,
4929 4927
 }
... ...
@@ -2,9 +2,13 @@ syntax = "proto3";
2 2
 
3 3
 package moby.buildkit.v1;
4 4
 
5
+// The control API is currently considered experimental and may break in a backwards
6
+// incompatible way.
7
+
5 8
 import "github.com/gogo/protobuf/gogoproto/gogo.proto";
6 9
 import "google/protobuf/timestamp.proto";
7 10
 import "github.com/moby/buildkit/solver/pb/ops.proto";
11
+import "github.com/moby/buildkit/api/types/worker.proto";
8 12
 
9 13
 option (gogoproto.sizer_all) = true;
10 14
 option (gogoproto.marshaler_all) = true;
... ...
@@ -17,6 +21,7 @@ service Control {
17 17
 	rpc Status(StatusRequest) returns (stream StatusResponse);
18 18
 	rpc Session(stream BytesMessage) returns (stream BytesMessage);
19 19
 	rpc ListWorkers(ListWorkersRequest) returns (ListWorkersResponse);
20
+	// rpc Info(InfoRequest) returns (InfoResponse);
20 21
 }
21 22
 
22 23
 message PruneRequest {
... ...
@@ -112,11 +117,5 @@ message ListWorkersRequest {
112 112
 }
113 113
 
114 114
 message ListWorkersResponse {
115
-	repeated WorkerRecord record = 1;
116
-}
117
-
118
-message WorkerRecord {
119
-	string ID = 1;
120
-	map<string, string> Labels = 2;
121
-	repeated pb.Platform platforms = 3 [(gogoproto.nullable) = false];
122
-}
115
+	repeated moby.buildkit.v1.types.WorkerRecord record = 1;
116
+}
123 117
\ No newline at end of file
124 118
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package moby_buildkit_v1_types
1
+
2
+//go:generate protoc -I=. -I=../../vendor/ -I=../../../../../ --gogo_out=plugins=grpc:. worker.proto
0 3
new file mode 100644
... ...
@@ -0,0 +1,523 @@
0
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
1
+// source: worker.proto
2
+
3
+/*
4
+	Package moby_buildkit_v1_types is a generated protocol buffer package.
5
+
6
+	It is generated from these files:
7
+		worker.proto
8
+
9
+	It has these top-level messages:
10
+		WorkerRecord
11
+*/
12
+package moby_buildkit_v1_types
13
+
14
+import proto "github.com/gogo/protobuf/proto"
15
+import fmt "fmt"
16
+import math "math"
17
+import _ "github.com/gogo/protobuf/gogoproto"
18
+import pb "github.com/moby/buildkit/solver/pb"
19
+
20
+import io "io"
21
+
22
+// Reference imports to suppress errors if they are not otherwise used.
23
+var _ = proto.Marshal
24
+var _ = fmt.Errorf
25
+var _ = math.Inf
26
+
27
+// This is a compile-time assertion to ensure that this generated file
28
+// is compatible with the proto package it is being compiled against.
29
+// A compilation error at this line likely means your copy of the
30
+// proto package needs to be updated.
31
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
32
+
33
+type WorkerRecord struct {
34
+	ID        string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
35
+	Labels    map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
36
+	Platforms []pb.Platform     `protobuf:"bytes,3,rep,name=platforms" json:"platforms"`
37
+}
38
+
39
+func (m *WorkerRecord) Reset()                    { *m = WorkerRecord{} }
40
+func (m *WorkerRecord) String() string            { return proto.CompactTextString(m) }
41
+func (*WorkerRecord) ProtoMessage()               {}
42
+func (*WorkerRecord) Descriptor() ([]byte, []int) { return fileDescriptorWorker, []int{0} }
43
+
44
+func (m *WorkerRecord) GetID() string {
45
+	if m != nil {
46
+		return m.ID
47
+	}
48
+	return ""
49
+}
50
+
51
+func (m *WorkerRecord) GetLabels() map[string]string {
52
+	if m != nil {
53
+		return m.Labels
54
+	}
55
+	return nil
56
+}
57
+
58
+func (m *WorkerRecord) GetPlatforms() []pb.Platform {
59
+	if m != nil {
60
+		return m.Platforms
61
+	}
62
+	return nil
63
+}
64
+
65
+func init() {
66
+	proto.RegisterType((*WorkerRecord)(nil), "moby.buildkit.v1.types.WorkerRecord")
67
+}
68
+func (m *WorkerRecord) Marshal() (dAtA []byte, err error) {
69
+	size := m.Size()
70
+	dAtA = make([]byte, size)
71
+	n, err := m.MarshalTo(dAtA)
72
+	if err != nil {
73
+		return nil, err
74
+	}
75
+	return dAtA[:n], nil
76
+}
77
+
78
+func (m *WorkerRecord) MarshalTo(dAtA []byte) (int, error) {
79
+	var i int
80
+	_ = i
81
+	var l int
82
+	_ = l
83
+	if len(m.ID) > 0 {
84
+		dAtA[i] = 0xa
85
+		i++
86
+		i = encodeVarintWorker(dAtA, i, uint64(len(m.ID)))
87
+		i += copy(dAtA[i:], m.ID)
88
+	}
89
+	if len(m.Labels) > 0 {
90
+		for k, _ := range m.Labels {
91
+			dAtA[i] = 0x12
92
+			i++
93
+			v := m.Labels[k]
94
+			mapSize := 1 + len(k) + sovWorker(uint64(len(k))) + 1 + len(v) + sovWorker(uint64(len(v)))
95
+			i = encodeVarintWorker(dAtA, i, uint64(mapSize))
96
+			dAtA[i] = 0xa
97
+			i++
98
+			i = encodeVarintWorker(dAtA, i, uint64(len(k)))
99
+			i += copy(dAtA[i:], k)
100
+			dAtA[i] = 0x12
101
+			i++
102
+			i = encodeVarintWorker(dAtA, i, uint64(len(v)))
103
+			i += copy(dAtA[i:], v)
104
+		}
105
+	}
106
+	if len(m.Platforms) > 0 {
107
+		for _, msg := range m.Platforms {
108
+			dAtA[i] = 0x1a
109
+			i++
110
+			i = encodeVarintWorker(dAtA, i, uint64(msg.Size()))
111
+			n, err := msg.MarshalTo(dAtA[i:])
112
+			if err != nil {
113
+				return 0, err
114
+			}
115
+			i += n
116
+		}
117
+	}
118
+	return i, nil
119
+}
120
+
121
+func encodeVarintWorker(dAtA []byte, offset int, v uint64) int {
122
+	for v >= 1<<7 {
123
+		dAtA[offset] = uint8(v&0x7f | 0x80)
124
+		v >>= 7
125
+		offset++
126
+	}
127
+	dAtA[offset] = uint8(v)
128
+	return offset + 1
129
+}
130
+func (m *WorkerRecord) Size() (n int) {
131
+	var l int
132
+	_ = l
133
+	l = len(m.ID)
134
+	if l > 0 {
135
+		n += 1 + l + sovWorker(uint64(l))
136
+	}
137
+	if len(m.Labels) > 0 {
138
+		for k, v := range m.Labels {
139
+			_ = k
140
+			_ = v
141
+			mapEntrySize := 1 + len(k) + sovWorker(uint64(len(k))) + 1 + len(v) + sovWorker(uint64(len(v)))
142
+			n += mapEntrySize + 1 + sovWorker(uint64(mapEntrySize))
143
+		}
144
+	}
145
+	if len(m.Platforms) > 0 {
146
+		for _, e := range m.Platforms {
147
+			l = e.Size()
148
+			n += 1 + l + sovWorker(uint64(l))
149
+		}
150
+	}
151
+	return n
152
+}
153
+
154
+func sovWorker(x uint64) (n int) {
155
+	for {
156
+		n++
157
+		x >>= 7
158
+		if x == 0 {
159
+			break
160
+		}
161
+	}
162
+	return n
163
+}
164
+func sozWorker(x uint64) (n int) {
165
+	return sovWorker(uint64((x << 1) ^ uint64((int64(x) >> 63))))
166
+}
167
+func (m *WorkerRecord) Unmarshal(dAtA []byte) error {
168
+	l := len(dAtA)
169
+	iNdEx := 0
170
+	for iNdEx < l {
171
+		preIndex := iNdEx
172
+		var wire uint64
173
+		for shift := uint(0); ; shift += 7 {
174
+			if shift >= 64 {
175
+				return ErrIntOverflowWorker
176
+			}
177
+			if iNdEx >= l {
178
+				return io.ErrUnexpectedEOF
179
+			}
180
+			b := dAtA[iNdEx]
181
+			iNdEx++
182
+			wire |= (uint64(b) & 0x7F) << shift
183
+			if b < 0x80 {
184
+				break
185
+			}
186
+		}
187
+		fieldNum := int32(wire >> 3)
188
+		wireType := int(wire & 0x7)
189
+		if wireType == 4 {
190
+			return fmt.Errorf("proto: WorkerRecord: wiretype end group for non-group")
191
+		}
192
+		if fieldNum <= 0 {
193
+			return fmt.Errorf("proto: WorkerRecord: illegal tag %d (wire type %d)", fieldNum, wire)
194
+		}
195
+		switch fieldNum {
196
+		case 1:
197
+			if wireType != 2 {
198
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
199
+			}
200
+			var stringLen uint64
201
+			for shift := uint(0); ; shift += 7 {
202
+				if shift >= 64 {
203
+					return ErrIntOverflowWorker
204
+				}
205
+				if iNdEx >= l {
206
+					return io.ErrUnexpectedEOF
207
+				}
208
+				b := dAtA[iNdEx]
209
+				iNdEx++
210
+				stringLen |= (uint64(b) & 0x7F) << shift
211
+				if b < 0x80 {
212
+					break
213
+				}
214
+			}
215
+			intStringLen := int(stringLen)
216
+			if intStringLen < 0 {
217
+				return ErrInvalidLengthWorker
218
+			}
219
+			postIndex := iNdEx + intStringLen
220
+			if postIndex > l {
221
+				return io.ErrUnexpectedEOF
222
+			}
223
+			m.ID = string(dAtA[iNdEx:postIndex])
224
+			iNdEx = postIndex
225
+		case 2:
226
+			if wireType != 2 {
227
+				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
228
+			}
229
+			var msglen int
230
+			for shift := uint(0); ; shift += 7 {
231
+				if shift >= 64 {
232
+					return ErrIntOverflowWorker
233
+				}
234
+				if iNdEx >= l {
235
+					return io.ErrUnexpectedEOF
236
+				}
237
+				b := dAtA[iNdEx]
238
+				iNdEx++
239
+				msglen |= (int(b) & 0x7F) << shift
240
+				if b < 0x80 {
241
+					break
242
+				}
243
+			}
244
+			if msglen < 0 {
245
+				return ErrInvalidLengthWorker
246
+			}
247
+			postIndex := iNdEx + msglen
248
+			if postIndex > l {
249
+				return io.ErrUnexpectedEOF
250
+			}
251
+			if m.Labels == nil {
252
+				m.Labels = make(map[string]string)
253
+			}
254
+			var mapkey string
255
+			var mapvalue string
256
+			for iNdEx < postIndex {
257
+				entryPreIndex := iNdEx
258
+				var wire uint64
259
+				for shift := uint(0); ; shift += 7 {
260
+					if shift >= 64 {
261
+						return ErrIntOverflowWorker
262
+					}
263
+					if iNdEx >= l {
264
+						return io.ErrUnexpectedEOF
265
+					}
266
+					b := dAtA[iNdEx]
267
+					iNdEx++
268
+					wire |= (uint64(b) & 0x7F) << shift
269
+					if b < 0x80 {
270
+						break
271
+					}
272
+				}
273
+				fieldNum := int32(wire >> 3)
274
+				if fieldNum == 1 {
275
+					var stringLenmapkey uint64
276
+					for shift := uint(0); ; shift += 7 {
277
+						if shift >= 64 {
278
+							return ErrIntOverflowWorker
279
+						}
280
+						if iNdEx >= l {
281
+							return io.ErrUnexpectedEOF
282
+						}
283
+						b := dAtA[iNdEx]
284
+						iNdEx++
285
+						stringLenmapkey |= (uint64(b) & 0x7F) << shift
286
+						if b < 0x80 {
287
+							break
288
+						}
289
+					}
290
+					intStringLenmapkey := int(stringLenmapkey)
291
+					if intStringLenmapkey < 0 {
292
+						return ErrInvalidLengthWorker
293
+					}
294
+					postStringIndexmapkey := iNdEx + intStringLenmapkey
295
+					if postStringIndexmapkey > l {
296
+						return io.ErrUnexpectedEOF
297
+					}
298
+					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
299
+					iNdEx = postStringIndexmapkey
300
+				} else if fieldNum == 2 {
301
+					var stringLenmapvalue uint64
302
+					for shift := uint(0); ; shift += 7 {
303
+						if shift >= 64 {
304
+							return ErrIntOverflowWorker
305
+						}
306
+						if iNdEx >= l {
307
+							return io.ErrUnexpectedEOF
308
+						}
309
+						b := dAtA[iNdEx]
310
+						iNdEx++
311
+						stringLenmapvalue |= (uint64(b) & 0x7F) << shift
312
+						if b < 0x80 {
313
+							break
314
+						}
315
+					}
316
+					intStringLenmapvalue := int(stringLenmapvalue)
317
+					if intStringLenmapvalue < 0 {
318
+						return ErrInvalidLengthWorker
319
+					}
320
+					postStringIndexmapvalue := iNdEx + intStringLenmapvalue
321
+					if postStringIndexmapvalue > l {
322
+						return io.ErrUnexpectedEOF
323
+					}
324
+					mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
325
+					iNdEx = postStringIndexmapvalue
326
+				} else {
327
+					iNdEx = entryPreIndex
328
+					skippy, err := skipWorker(dAtA[iNdEx:])
329
+					if err != nil {
330
+						return err
331
+					}
332
+					if skippy < 0 {
333
+						return ErrInvalidLengthWorker
334
+					}
335
+					if (iNdEx + skippy) > postIndex {
336
+						return io.ErrUnexpectedEOF
337
+					}
338
+					iNdEx += skippy
339
+				}
340
+			}
341
+			m.Labels[mapkey] = mapvalue
342
+			iNdEx = postIndex
343
+		case 3:
344
+			if wireType != 2 {
345
+				return fmt.Errorf("proto: wrong wireType = %d for field Platforms", wireType)
346
+			}
347
+			var msglen int
348
+			for shift := uint(0); ; shift += 7 {
349
+				if shift >= 64 {
350
+					return ErrIntOverflowWorker
351
+				}
352
+				if iNdEx >= l {
353
+					return io.ErrUnexpectedEOF
354
+				}
355
+				b := dAtA[iNdEx]
356
+				iNdEx++
357
+				msglen |= (int(b) & 0x7F) << shift
358
+				if b < 0x80 {
359
+					break
360
+				}
361
+			}
362
+			if msglen < 0 {
363
+				return ErrInvalidLengthWorker
364
+			}
365
+			postIndex := iNdEx + msglen
366
+			if postIndex > l {
367
+				return io.ErrUnexpectedEOF
368
+			}
369
+			m.Platforms = append(m.Platforms, pb.Platform{})
370
+			if err := m.Platforms[len(m.Platforms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
371
+				return err
372
+			}
373
+			iNdEx = postIndex
374
+		default:
375
+			iNdEx = preIndex
376
+			skippy, err := skipWorker(dAtA[iNdEx:])
377
+			if err != nil {
378
+				return err
379
+			}
380
+			if skippy < 0 {
381
+				return ErrInvalidLengthWorker
382
+			}
383
+			if (iNdEx + skippy) > l {
384
+				return io.ErrUnexpectedEOF
385
+			}
386
+			iNdEx += skippy
387
+		}
388
+	}
389
+
390
+	if iNdEx > l {
391
+		return io.ErrUnexpectedEOF
392
+	}
393
+	return nil
394
+}
395
+func skipWorker(dAtA []byte) (n int, err error) {
396
+	l := len(dAtA)
397
+	iNdEx := 0
398
+	for iNdEx < l {
399
+		var wire uint64
400
+		for shift := uint(0); ; shift += 7 {
401
+			if shift >= 64 {
402
+				return 0, ErrIntOverflowWorker
403
+			}
404
+			if iNdEx >= l {
405
+				return 0, io.ErrUnexpectedEOF
406
+			}
407
+			b := dAtA[iNdEx]
408
+			iNdEx++
409
+			wire |= (uint64(b) & 0x7F) << shift
410
+			if b < 0x80 {
411
+				break
412
+			}
413
+		}
414
+		wireType := int(wire & 0x7)
415
+		switch wireType {
416
+		case 0:
417
+			for shift := uint(0); ; shift += 7 {
418
+				if shift >= 64 {
419
+					return 0, ErrIntOverflowWorker
420
+				}
421
+				if iNdEx >= l {
422
+					return 0, io.ErrUnexpectedEOF
423
+				}
424
+				iNdEx++
425
+				if dAtA[iNdEx-1] < 0x80 {
426
+					break
427
+				}
428
+			}
429
+			return iNdEx, nil
430
+		case 1:
431
+			iNdEx += 8
432
+			return iNdEx, nil
433
+		case 2:
434
+			var length int
435
+			for shift := uint(0); ; shift += 7 {
436
+				if shift >= 64 {
437
+					return 0, ErrIntOverflowWorker
438
+				}
439
+				if iNdEx >= l {
440
+					return 0, io.ErrUnexpectedEOF
441
+				}
442
+				b := dAtA[iNdEx]
443
+				iNdEx++
444
+				length |= (int(b) & 0x7F) << shift
445
+				if b < 0x80 {
446
+					break
447
+				}
448
+			}
449
+			iNdEx += length
450
+			if length < 0 {
451
+				return 0, ErrInvalidLengthWorker
452
+			}
453
+			return iNdEx, nil
454
+		case 3:
455
+			for {
456
+				var innerWire uint64
457
+				var start int = iNdEx
458
+				for shift := uint(0); ; shift += 7 {
459
+					if shift >= 64 {
460
+						return 0, ErrIntOverflowWorker
461
+					}
462
+					if iNdEx >= l {
463
+						return 0, io.ErrUnexpectedEOF
464
+					}
465
+					b := dAtA[iNdEx]
466
+					iNdEx++
467
+					innerWire |= (uint64(b) & 0x7F) << shift
468
+					if b < 0x80 {
469
+						break
470
+					}
471
+				}
472
+				innerWireType := int(innerWire & 0x7)
473
+				if innerWireType == 4 {
474
+					break
475
+				}
476
+				next, err := skipWorker(dAtA[start:])
477
+				if err != nil {
478
+					return 0, err
479
+				}
480
+				iNdEx = start + next
481
+			}
482
+			return iNdEx, nil
483
+		case 4:
484
+			return iNdEx, nil
485
+		case 5:
486
+			iNdEx += 4
487
+			return iNdEx, nil
488
+		default:
489
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
490
+		}
491
+	}
492
+	panic("unreachable")
493
+}
494
+
495
+var (
496
+	ErrInvalidLengthWorker = fmt.Errorf("proto: negative length found during unmarshaling")
497
+	ErrIntOverflowWorker   = fmt.Errorf("proto: integer overflow")
498
+)
499
+
500
+func init() { proto.RegisterFile("worker.proto", fileDescriptorWorker) }
501
+
502
+var fileDescriptorWorker = []byte{
503
+	// 273 bytes of a gzipped FileDescriptorProto
504
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x8f, 0x41, 0x4b, 0xf3, 0x40,
505
+	0x10, 0x86, 0xbf, 0x4d, 0x3e, 0x0b, 0xdd, 0x06, 0x91, 0x45, 0x24, 0xe4, 0x10, 0x8b, 0xa7, 0x1e,
506
+	0x74, 0xb6, 0xea, 0x45, 0x3d, 0x96, 0x0a, 0x16, 0x3c, 0x48, 0x2e, 0x9e, 0xb3, 0xed, 0x36, 0x86,
507
+	0x24, 0xce, 0xb2, 0xd9, 0x44, 0xf2, 0x0f, 0x7b, 0xf4, 0xe2, 0x55, 0x24, 0xbf, 0x44, 0xba, 0x89,
508
+	0x98, 0x83, 0xb7, 0x79, 0x87, 0x67, 0x1e, 0xde, 0xa1, 0xde, 0x1b, 0xea, 0x4c, 0x6a, 0x50, 0x1a,
509
+	0x0d, 0xb2, 0x93, 0x02, 0x45, 0x03, 0xa2, 0x4a, 0xf3, 0x4d, 0x96, 0x1a, 0xa8, 0x2f, 0xc1, 0x34,
510
+	0x4a, 0x96, 0xc1, 0x45, 0x92, 0x9a, 0x97, 0x4a, 0xc0, 0x1a, 0x0b, 0x9e, 0x60, 0x82, 0xdc, 0xe2,
511
+	0xa2, 0xda, 0xda, 0x64, 0x83, 0x9d, 0x3a, 0x4d, 0x70, 0x3e, 0xc0, 0xf7, 0x46, 0xfe, 0x63, 0xe4,
512
+	0x25, 0xe6, 0xb5, 0xd4, 0x5c, 0x09, 0x8e, 0xaa, 0xec, 0xe8, 0xb3, 0x0f, 0x42, 0xbd, 0x67, 0xdb,
513
+	0x22, 0x92, 0x6b, 0xd4, 0x1b, 0x76, 0x48, 0x9d, 0xd5, 0xd2, 0x27, 0x53, 0x32, 0x1b, 0x47, 0xce,
514
+	0x6a, 0xc9, 0x1e, 0xe8, 0xe8, 0x31, 0x16, 0x32, 0x2f, 0x7d, 0x67, 0xea, 0xce, 0x26, 0x57, 0x73,
515
+	0xf8, 0xbb, 0x26, 0x0c, 0x2d, 0xd0, 0x9d, 0xdc, 0xbf, 0x1a, 0xdd, 0x44, 0xfd, 0x3d, 0x9b, 0xd3,
516
+	0xb1, 0xca, 0x63, 0xb3, 0x45, 0x5d, 0x94, 0xbe, 0x6b, 0x65, 0x1e, 0x28, 0x01, 0x4f, 0xfd, 0x72,
517
+	0xf1, 0x7f, 0xf7, 0x79, 0xfa, 0x2f, 0xfa, 0x85, 0x82, 0x5b, 0x3a, 0x19, 0x88, 0xd8, 0x11, 0x75,
518
+	0x33, 0xd9, 0xf4, 0xdd, 0xf6, 0x23, 0x3b, 0xa6, 0x07, 0x75, 0x9c, 0x57, 0xd2, 0x77, 0xec, 0xae,
519
+	0x0b, 0x77, 0xce, 0x0d, 0x59, 0x78, 0xbb, 0x36, 0x24, 0xef, 0x6d, 0x48, 0xbe, 0xda, 0x90, 0x88,
520
+	0x91, 0x7d, 0xf6, 0xfa, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xa9, 0x5c, 0x8f, 0x26, 0x71, 0x01, 0x00,
521
+	0x00,
522
+}
0 523
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+syntax = "proto3";
1
+
2
+package moby.buildkit.v1.types;
3
+
4
+import "github.com/gogo/protobuf/gogoproto/gogo.proto";
5
+import "github.com/moby/buildkit/solver/pb/ops.proto";
6
+
7
+option (gogoproto.sizer_all) = true;
8
+option (gogoproto.marshaler_all) = true;
9
+option (gogoproto.unmarshaler_all) = true;
10
+
11
+message WorkerRecord {
12
+	string ID = 1;
13
+	map<string, string> Labels = 2;
14
+	repeated pb.Platform platforms = 3 [(gogoproto.nullable) = false];
15
+}
... ...
@@ -225,7 +225,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
225 225
 		if err != nil {
226 226
 			return nil, err
227 227
 		}
228
-		if err := parent.Finalize(ctx); err != nil {
228
+		if err := parent.Finalize(ctx, true); err != nil {
229 229
 			return nil, err
230 230
 		}
231 231
 		parentID = parent.ID()
... ...
@@ -25,7 +25,7 @@ type Ref interface {
25 25
 type ImmutableRef interface {
26 26
 	Ref
27 27
 	Parent() ImmutableRef
28
-	Finalize(ctx context.Context) error // Make sure reference is flushed to driver
28
+	Finalize(ctx context.Context, commit bool) error // Make sure reference is flushed to driver
29 29
 	Clone() ImmutableRef
30 30
 }
31 31
 
... ...
@@ -148,7 +148,7 @@ func (cr *cacheRecord) Mount(ctx context.Context, readonly bool) (snapshot.Mount
148 148
 		return setReadonly(m), nil
149 149
 	}
150 150
 
151
-	if err := cr.finalize(ctx); err != nil {
151
+	if err := cr.finalize(ctx, true); err != nil {
152 152
 		return nil, err
153 153
 	}
154 154
 	if cr.viewMount == nil { // TODO: handle this better
... ...
@@ -233,22 +233,29 @@ func (sr *immutableRef) release(ctx context.Context) error {
233 233
 	return nil
234 234
 }
235 235
 
236
-func (sr *immutableRef) Finalize(ctx context.Context) error {
236
+func (sr *immutableRef) Finalize(ctx context.Context, b bool) error {
237 237
 	sr.mu.Lock()
238 238
 	defer sr.mu.Unlock()
239 239
 
240
-	return sr.finalize(ctx)
240
+	return sr.finalize(ctx, b)
241 241
 }
242 242
 
243 243
 func (cr *cacheRecord) Metadata() *metadata.StorageItem {
244 244
 	return cr.md
245 245
 }
246 246
 
247
-func (cr *cacheRecord) finalize(ctx context.Context) error {
247
+func (cr *cacheRecord) finalize(ctx context.Context, commit bool) error {
248 248
 	mutable := cr.equalMutable
249 249
 	if mutable == nil {
250 250
 		return nil
251 251
 	}
252
+	if !commit {
253
+		if HasCachePolicyRetain(mutable) {
254
+			CachePolicyRetain(mutable)
255
+			return mutable.Metadata().Commit()
256
+		}
257
+		return nil
258
+	}
252 259
 	err := cr.cm.Snapshotter.Commit(ctx, cr.ID(), mutable.ID())
253 260
 	if err != nil {
254 261
 		return errors.Wrapf(err, "failed to commit %s", mutable.ID())
... ...
@@ -10,35 +10,54 @@ import (
10 10
 	"github.com/containerd/containerd/content"
11 11
 	"github.com/containerd/containerd/images"
12 12
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
13
-	"github.com/moby/buildkit/session"
14 13
 	"github.com/moby/buildkit/solver"
15 14
 	"github.com/moby/buildkit/util/contentutil"
16 15
 	"github.com/moby/buildkit/util/progress"
17
-	"github.com/moby/buildkit/util/push"
18 16
 	digest "github.com/opencontainers/go-digest"
19 17
 	specs "github.com/opencontainers/image-spec/specs-go"
20 18
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
21 19
 	"github.com/pkg/errors"
22 20
 )
23 21
 
24
-type ExporterOpt struct {
25
-	SessionManager *session.Manager
22
+type ResolveCacheExporterFunc func(ctx context.Context, typ, target string) (Exporter, error)
23
+
24
+func oneOffProgress(ctx context.Context, id string) func(err error) error {
25
+	pw, _, _ := progress.FromContext(ctx)
26
+	now := time.Now()
27
+	st := progress.Status{
28
+		Started: &now,
29
+	}
30
+	pw.Write(id, st)
31
+	return func(err error) error {
32
+		now := time.Now()
33
+		st.Completed = &now
34
+		pw.Write(id, st)
35
+		pw.Close()
36
+		return err
37
+	}
26 38
 }
27 39
 
28
-func NewCacheExporter(opt ExporterOpt) *CacheExporter {
29
-	return &CacheExporter{opt: opt}
40
+type Exporter interface {
41
+	solver.CacheExporterTarget
42
+	Finalize(ctx context.Context) error
30 43
 }
31 44
 
32
-type CacheExporter struct {
33
-	opt ExporterOpt
45
+type contentCacheExporter struct {
46
+	solver.CacheExporterTarget
47
+	chains   *v1.CacheChains
48
+	ingester content.Ingester
34 49
 }
35 50
 
36
-func (ce *CacheExporter) ExporterForTarget(target string) *RegistryCacheExporter {
51
+func NewExporter(ingester content.Ingester) Exporter {
37 52
 	cc := v1.NewCacheChains()
38
-	return &RegistryCacheExporter{target: target, CacheExporterTarget: cc, chains: cc, exporter: ce}
53
+	return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester}
39 54
 }
40 55
 
41
-func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, target string) error {
56
+func (ce *contentCacheExporter) Finalize(ctx context.Context) error {
57
+	return export(ctx, ce.ingester, ce.chains)
58
+}
59
+
60
+func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains) error {
42 61
 	config, descs, err := cc.Marshal()
43 62
 	if err != nil {
44 63
 		return err
... ...
@@ -58,19 +77,16 @@ func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, targe
58 58
 	mfst.SchemaVersion = 2
59 59
 	mfst.MediaType = images.MediaTypeDockerSchema2ManifestList
60 60
 
61
-	allBlobs := map[digest.Digest]struct{}{}
62
-	mp := contentutil.NewMultiProvider(nil)
63 61
 	for _, l := range config.Layers {
64
-		if _, ok := allBlobs[l.Blob]; ok {
65
-			continue
66
-		}
67 62
 		dgstPair, ok := descs[l.Blob]
68 63
 		if !ok {
69 64
 			return errors.Errorf("missing blob %s", l.Blob)
70 65
 		}
71
-		allBlobs[l.Blob] = struct{}{}
72
-		mp.Add(l.Blob, dgstPair.Provider)
73
-
66
+		layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob))
67
+		if err := contentutil.Copy(ctx, ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
68
+			return layerDone(errors.Wrap(err, "error writing layer blob"))
69
+		}
70
+		layerDone(nil)
74 71
 		mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor)
75 72
 	}
76 73
 
... ...
@@ -85,13 +101,11 @@ func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, targe
85 85
 		MediaType: v1.CacheConfigMediaTypeV0,
86 86
 	}
87 87
 	configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
88
-	buf := contentutil.NewBuffer()
89
-	if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), desc); err != nil {
88
+	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
90 89
 		return configDone(errors.Wrap(err, "error writing config blob"))
91 90
 	}
92 91
 	configDone(nil)
93 92
 
94
-	mp.Add(dgst, buf)
95 93
 	mfst.Manifests = append(mfst.Manifests, desc)
96 94
 
97 95
 	dt, err = json.Marshal(mfst)
... ...
@@ -100,44 +114,15 @@ func (ce *CacheExporter) Finalize(ctx context.Context, cc *v1.CacheChains, targe
100 100
 	}
101 101
 	dgst = digest.FromBytes(dt)
102 102
 
103
-	buf = contentutil.NewBuffer()
104 103
 	desc = ocispec.Descriptor{
105
-		Digest: dgst,
106
-		Size:   int64(len(dt)),
104
+		Digest:    dgst,
105
+		Size:      int64(len(dt)),
106
+		MediaType: mfst.MediaType,
107 107
 	}
108 108
 	mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
109
-	if err := content.WriteBlob(ctx, buf, dgst.String(), bytes.NewReader(dt), desc); err != nil {
109
+	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
110 110
 		return mfstDone(errors.Wrap(err, "error writing manifest blob"))
111 111
 	}
112 112
 	mfstDone(nil)
113
-	mp.Add(dgst, buf)
114
-
115
-	return push.Push(ctx, ce.opt.SessionManager, mp, dgst, target, false)
116
-}
117
-
118
-type RegistryCacheExporter struct {
119
-	solver.CacheExporterTarget
120
-	chains   *v1.CacheChains
121
-	target   string
122
-	exporter *CacheExporter
123
-}
124
-
125
-func (ce *RegistryCacheExporter) Finalize(ctx context.Context) error {
126
-	return ce.exporter.Finalize(ctx, ce.chains, ce.target)
127
-}
128
-
129
-func oneOffProgress(ctx context.Context, id string) func(err error) error {
130
-	pw, _, _ := progress.FromContext(ctx)
131
-	now := time.Now()
132
-	st := progress.Status{
133
-		Started: &now,
134
-	}
135
-	pw.Write(id, st)
136
-	return func(err error) error {
137
-		now := time.Now()
138
-		st.Completed = &now
139
-		pw.Write(id, st)
140
-		pw.Close()
141
-		return err
142
-	}
113
+	return nil
143 114
 }
... ...
@@ -3,77 +3,34 @@ package remotecache
3 3
 import (
4 4
 	"context"
5 5
 	"encoding/json"
6
-	"net/http"
7
-	"time"
6
+	"io"
8 7
 
9 8
 	"github.com/containerd/containerd/content"
10
-	"github.com/containerd/containerd/remotes"
11
-	"github.com/containerd/containerd/remotes/docker"
12 9
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
13
-	"github.com/moby/buildkit/session"
14
-	"github.com/moby/buildkit/session/auth"
15 10
 	"github.com/moby/buildkit/solver"
16
-	"github.com/moby/buildkit/util/contentutil"
17 11
 	"github.com/moby/buildkit/worker"
18 12
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
19 13
 	"github.com/pkg/errors"
20 14
 )
21 15
 
22
-type ImportOpt struct {
23
-	SessionManager *session.Manager
24
-	Worker         worker.Worker // TODO: remove. This sets the worker where the cache is imported to. Should be passed on load instead.
25
-}
16
+// ResolveCacheImporterFunc returns importer and descriptor.
17
+// Currently typ needs to be an empty string.
18
+type ResolveCacheImporterFunc func(ctx context.Context, typ, ref string) (Importer, ocispec.Descriptor, error)
26 19
 
27
-func NewCacheImporter(opt ImportOpt) *CacheImporter {
28
-	return &CacheImporter{opt: opt}
20
+type Importer interface {
21
+	Resolve(ctx context.Context, desc ocispec.Descriptor, id string, w worker.Worker) (solver.CacheManager, error)
29 22
 }
30 23
 
31
-type CacheImporter struct {
32
-	opt ImportOpt
24
+func NewImporter(provider content.Provider) Importer {
25
+	return &contentCacheImporter{provider: provider}
33 26
 }
34 27
 
35
-func (ci *CacheImporter) getCredentialsFromSession(ctx context.Context) func(string) (string, string, error) {
36
-	id := session.FromContext(ctx)
37
-	if id == "" {
38
-		return nil
39
-	}
40
-
41
-	return func(host string) (string, string, error) {
42
-		timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
43
-		defer cancel()
44
-
45
-		caller, err := ci.opt.SessionManager.Get(timeoutCtx, id)
46
-		if err != nil {
47
-			return "", "", err
48
-		}
49
-
50
-		return auth.CredentialsFunc(context.TODO(), caller)(host)
51
-	}
28
+type contentCacheImporter struct {
29
+	provider content.Provider
52 30
 }
53 31
 
54
-func (ci *CacheImporter) Resolve(ctx context.Context, ref string) (solver.CacheManager, error) {
55
-	resolver := docker.NewResolver(docker.ResolverOptions{
56
-		Client:      http.DefaultClient,
57
-		Credentials: ci.getCredentialsFromSession(ctx),
58
-	})
59
-
60
-	ref, desc, err := resolver.Resolve(ctx, ref)
61
-	if err != nil {
62
-		return nil, err
63
-	}
64
-
65
-	fetcher, err := resolver.Fetcher(ctx, ref)
66
-	if err != nil {
67
-		return nil, err
68
-	}
69
-
70
-	b := contentutil.NewBuffer()
71
-
72
-	if _, err := remotes.FetchHandler(b, fetcher)(ctx, desc); err != nil {
73
-		return nil, err
74
-	}
75
-
76
-	dt, err := content.ReadBlob(ctx, b, desc)
32
+func (ci *contentCacheImporter) Resolve(ctx context.Context, desc ocispec.Descriptor, id string, w worker.Worker) (solver.CacheManager, error) {
33
+	dt, err := readBlob(ctx, ci.provider, desc)
77 34
 	if err != nil {
78 35
 		return nil, err
79 36
 	}
... ...
@@ -94,19 +51,15 @@ func (ci *CacheImporter) Resolve(ctx context.Context, ref string) (solver.CacheM
94 94
 		}
95 95
 		allLayers[m.Digest] = v1.DescriptorProviderPair{
96 96
 			Descriptor: m,
97
-			Provider:   contentutil.FromFetcher(fetcher, m),
97
+			Provider:   ci.provider,
98 98
 		}
99 99
 	}
100 100
 
101 101
 	if configDesc.Digest == "" {
102
-		return nil, errors.Errorf("invalid build cache from %s", ref)
103
-	}
104
-
105
-	if _, err := remotes.FetchHandler(b, fetcher)(ctx, configDesc); err != nil {
106
-		return nil, err
102
+		return nil, errors.Errorf("invalid build cache from %+v", desc)
107 103
 	}
108 104
 
109
-	dt, err = content.ReadBlob(ctx, b, configDesc)
105
+	dt, err = readBlob(ctx, ci.provider, configDesc)
110 106
 	if err != nil {
111 107
 		return nil, err
112 108
 	}
... ...
@@ -116,9 +69,30 @@ func (ci *CacheImporter) Resolve(ctx context.Context, ref string) (solver.CacheM
116 116
 		return nil, err
117 117
 	}
118 118
 
119
-	keysStorage, resultStorage, err := v1.NewCacheKeyStorage(cc, ci.opt.Worker)
119
+	keysStorage, resultStorage, err := v1.NewCacheKeyStorage(cc, w)
120 120
 	if err != nil {
121 121
 		return nil, err
122 122
 	}
123
-	return solver.NewCacheManager(ref, keysStorage, resultStorage), nil
123
+	return solver.NewCacheManager(id, keysStorage, resultStorage), nil
124
+}
125
+
126
+func readBlob(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]byte, error) {
127
+	maxBlobSize := int64(1 << 20)
128
+	if desc.Size > maxBlobSize {
129
+		return nil, errors.Errorf("blob %s is too large (%d > %d)", desc.Digest, desc.Size, maxBlobSize)
130
+	}
131
+	dt, err := content.ReadBlob(ctx, provider, desc)
132
+	if err != nil {
133
+		// NOTE: even if err == EOF, we might have got expected dt here.
134
+		// For instance, http.Response.Body is known to return non-zero bytes with EOF.
135
+		if err == io.EOF {
136
+			if dtDigest := desc.Digest.Algorithm().FromBytes(dt); dtDigest != desc.Digest {
137
+				err = errors.Wrapf(err, "got EOF, expected %s (%d bytes), got %s (%d bytes)",
138
+					desc.Digest, desc.Size, dtDigest, len(dt))
139
+			} else {
140
+				err = nil
141
+			}
142
+		}
143
+	}
144
+	return dt, err
124 145
 }
125 146
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+package registry
1
+
2
+import (
3
+	"context"
4
+	"time"
5
+
6
+	"github.com/containerd/containerd/remotes"
7
+	"github.com/containerd/containerd/remotes/docker"
8
+	"github.com/moby/buildkit/cache/remotecache"
9
+	"github.com/moby/buildkit/session"
10
+	"github.com/moby/buildkit/session/auth"
11
+	"github.com/moby/buildkit/util/contentutil"
12
+	"github.com/moby/buildkit/util/tracing"
13
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
14
+	"github.com/pkg/errors"
15
+)
16
+
17
+func ResolveCacheExporterFunc(sm *session.Manager) remotecache.ResolveCacheExporterFunc {
18
+	return func(ctx context.Context, typ, ref string) (remotecache.Exporter, error) {
19
+		if typ != "" {
20
+			return nil, errors.Errorf("unsupported cache exporter type: %s", typ)
21
+		}
22
+		remote := newRemoteResolver(ctx, sm)
23
+		pusher, err := remote.Pusher(ctx, ref)
24
+		if err != nil {
25
+			return nil, err
26
+		}
27
+		return remotecache.NewExporter(contentutil.FromPusher(pusher)), nil
28
+	}
29
+}
30
+
31
+func ResolveCacheImporterFunc(sm *session.Manager) remotecache.ResolveCacheImporterFunc {
32
+	return func(ctx context.Context, typ, ref string) (remotecache.Importer, specs.Descriptor, error) {
33
+		if typ != "" {
34
+			return nil, specs.Descriptor{}, errors.Errorf("unsupported cache importer type: %s", typ)
35
+		}
36
+		remote := newRemoteResolver(ctx, sm)
37
+		xref, desc, err := remote.Resolve(ctx, ref)
38
+		if err != nil {
39
+			return nil, specs.Descriptor{}, err
40
+		}
41
+		fetcher, err := remote.Fetcher(ctx, xref)
42
+		if err != nil {
43
+			return nil, specs.Descriptor{}, err
44
+		}
45
+		return remotecache.NewImporter(contentutil.FromFetcher(fetcher)), desc, nil
46
+	}
47
+}
48
+
49
+func newRemoteResolver(ctx context.Context, sm *session.Manager) remotes.Resolver {
50
+	return docker.NewResolver(docker.ResolverOptions{
51
+		Client:      tracing.DefaultClient,
52
+		Credentials: getCredentialsFunc(ctx, sm),
53
+	})
54
+}
55
+
56
+func getCredentialsFunc(ctx context.Context, sm *session.Manager) func(string) (string, string, error) {
57
+	id := session.FromContext(ctx)
58
+	if id == "" {
59
+		return nil
60
+	}
61
+	return func(host string) (string, string, error) {
62
+		timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
63
+		defer cancel()
64
+
65
+		caller, err := sm.Get(timeoutCtx, id)
66
+		if err != nil {
67
+			return "", "", err
68
+		}
69
+
70
+		return auth.CredentialsFunc(context.TODO(), caller)(host)
71
+	}
72
+}
... ...
@@ -51,6 +51,15 @@ func (s *SourceOp) Marshal(constraints *Constraints) (digest.Digest, []byte, *pb
51 51
 		return "", nil, nil, err
52 52
 	}
53 53
 
54
+	if strings.HasPrefix(s.id, "local://") {
55
+		if _, hasSession := s.attrs[pb.AttrLocalSessionID]; !hasSession {
56
+			uid := s.constraints.LocalUniqueID
57
+			if uid == "" {
58
+				uid = constraints.LocalUniqueID
59
+			}
60
+			s.attrs[pb.AttrLocalUniqueID] = uid
61
+		}
62
+	}
54 63
 	proto, md := MarshalConstraints(constraints, &s.constraints)
55 64
 
56 65
 	proto.Op = &pb.Op_Source{
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"context"
5 5
 
6 6
 	"github.com/containerd/containerd/platforms"
7
+	"github.com/moby/buildkit/identity"
7 8
 	"github.com/moby/buildkit/solver/pb"
8 9
 	"github.com/moby/buildkit/util/system"
9 10
 	digest "github.com/opencontainers/go-digest"
... ...
@@ -78,7 +79,8 @@ func (s State) Marshal(co ...ConstraintsOpt) (*Definition, error) {
78 78
 
79 79
 	defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
80 80
 	c := &Constraints{
81
-		Platform: &defaultPlatform,
81
+		Platform:      &defaultPlatform,
82
+		LocalUniqueID: identity.NewID(),
82 83
 	}
83 84
 	for _, o := range append(s.opts, co...) {
84 85
 		o.SetConstraintsOption(c)
... ...
@@ -358,6 +360,7 @@ type Constraints struct {
358 358
 	Platform          *specs.Platform
359 359
 	WorkerConstraints []string
360 360
 	Metadata          pb.OpMetadata
361
+	LocalUniqueID     string
361 362
 }
362 363
 
363 364
 func Platform(p specs.Platform) ConstraintsOpt {
... ...
@@ -366,6 +369,12 @@ func Platform(p specs.Platform) ConstraintsOpt {
366 366
 	})
367 367
 }
368 368
 
369
+func LocalUniqueID(v string) ConstraintsOpt {
370
+	return constraintsOptFunc(func(c *Constraints) {
371
+		c.LocalUniqueID = v
372
+	})
373
+}
374
+
369 375
 var (
370 376
 	LinuxAmd64   = Platform(specs.Platform{OS: "linux", Architecture: "amd64"})
371 377
 	LinuxArmhf   = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v7"})
... ...
@@ -33,7 +33,7 @@ func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]
33 33
 		wi = append(wi, &WorkerInfo{
34 34
 			ID:        w.ID,
35 35
 			Labels:    w.Labels,
36
-			Platforms: toClientPlatforms(w.Platforms),
36
+			Platforms: pb.ToSpecPlatforms(w.Platforms),
37 37
 		})
38 38
 	}
39 39
 
... ...
@@ -51,17 +51,3 @@ func WithWorkerFilter(f []string) ListWorkersOption {
51 51
 		wi.Filter = f
52 52
 	}
53 53
 }
54
-
55
-func toClientPlatforms(p []pb.Platform) []specs.Platform {
56
-	out := make([]specs.Platform, 0, len(p))
57
-	for _, pp := range p {
58
-		out = append(out, specs.Platform{
59
-			OS:           pp.OS,
60
-			Architecture: pp.Architecture,
61
-			Variant:      pp.Variant,
62
-			OSVersion:    pp.OSVersion,
63
-			OSFeatures:   pp.OSFeatures,
64
-		})
65
-	}
66
-	return out
67
-}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 
6 6
 	"github.com/docker/distribution/reference"
7 7
 	controlapi "github.com/moby/buildkit/api/services/control"
8
+	apitypes "github.com/moby/buildkit/api/types"
8 9
 	"github.com/moby/buildkit/cache/remotecache"
9 10
 	"github.com/moby/buildkit/client"
10 11
 	"github.com/moby/buildkit/exporter"
... ...
@@ -15,20 +16,21 @@ import (
15 15
 	"github.com/moby/buildkit/solver/llbsolver"
16 16
 	"github.com/moby/buildkit/solver/pb"
17 17
 	"github.com/moby/buildkit/worker"
18
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
19 18
 	"github.com/pkg/errors"
20 19
 	"github.com/sirupsen/logrus"
21 20
 	"golang.org/x/sync/errgroup"
22 21
 	"google.golang.org/grpc"
23 22
 )
24 23
 
24
+type ResolveCacheExporterFunc func(ctx context.Context, typ, target string) (remotecache.Exporter, error)
25
+
25 26
 type Opt struct {
26
-	SessionManager   *session.Manager
27
-	WorkerController *worker.Controller
28
-	Frontends        map[string]frontend.Frontend
29
-	CacheKeyStorage  solver.CacheKeyStorage
30
-	CacheExporter    *remotecache.CacheExporter
31
-	CacheImporter    *remotecache.CacheImporter
27
+	SessionManager           *session.Manager
28
+	WorkerController         *worker.Controller
29
+	Frontends                map[string]frontend.Frontend
30
+	CacheKeyStorage          solver.CacheKeyStorage
31
+	ResolveCacheExporterFunc remotecache.ResolveCacheExporterFunc
32
+	ResolveCacheImporterFunc remotecache.ResolveCacheImporterFunc
32 33
 }
33 34
 
34 35
 type Controller struct { // TODO: ControlService
... ...
@@ -37,7 +39,7 @@ type Controller struct { // TODO: ControlService
37 37
 }
38 38
 
39 39
 func NewController(opt Opt) (*Controller, error) {
40
-	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.CacheImporter)
40
+	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.ResolveCacheImporterFunc)
41 41
 	if err != nil {
42 42
 		return nil, errors.Wrap(err, "failed to create solver")
43 43
 	}
... ...
@@ -103,7 +105,7 @@ func (c *Controller) Prune(req *controlapi.PruneRequest, stream controlapi.Contr
103 103
 		}(w)
104 104
 	}
105 105
 
106
-	eg2, ctx := errgroup.WithContext(stream.Context())
106
+	eg2, _ := errgroup.WithContext(stream.Context())
107 107
 
108 108
 	eg2.Go(func() error {
109 109
 		defer close(ch)
... ...
@@ -154,14 +156,18 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
154 154
 		}
155 155
 	}
156 156
 
157
-	var cacheExporter *remotecache.RegistryCacheExporter
158
-	if ref := req.Cache.ExportRef; ref != "" {
157
+	var cacheExporter remotecache.Exporter
158
+	if ref := req.Cache.ExportRef; ref != "" && c.opt.ResolveCacheExporterFunc != nil {
159 159
 		parsed, err := reference.ParseNormalizedNamed(ref)
160 160
 		if err != nil {
161 161
 			return nil, err
162 162
 		}
163 163
 		exportCacheRef := reference.TagNameOnly(parsed).String()
164
-		cacheExporter = c.opt.CacheExporter.ExporterForTarget(exportCacheRef)
164
+		typ := "" // unimplemented yet (typically registry)
165
+		cacheExporter, err = c.opt.ResolveCacheExporterFunc(ctx, typ, exportCacheRef)
166
+		if err != nil {
167
+			return nil, err
168
+		}
165 169
 	}
166 170
 
167 171
 	var importCacheRefs []string
... ...
@@ -269,10 +275,10 @@ func (c *Controller) ListWorkers(ctx context.Context, r *controlapi.ListWorkersR
269 269
 		return nil, err
270 270
 	}
271 271
 	for _, w := range workers {
272
-		resp.Record = append(resp.Record, &controlapi.WorkerRecord{
272
+		resp.Record = append(resp.Record, &apitypes.WorkerRecord{
273 273
 			ID:        w.ID(),
274 274
 			Labels:    w.Labels(),
275
-			Platforms: toPBPlatforms(w.Platforms()),
275
+			Platforms: pb.PlatformsFromSpec(w.Platforms()),
276 276
 		})
277 277
 	}
278 278
 	return resp, nil
... ...
@@ -296,17 +302,3 @@ func parseCacheExporterOpt(opt map[string]string) solver.CacheExportMode {
296 296
 	}
297 297
 	return solver.CacheExportModeMin
298 298
 }
299
-
300
-func toPBPlatforms(p []specs.Platform) []pb.Platform {
301
-	out := make([]pb.Platform, 0, len(p))
302
-	for _, pp := range p {
303
-		out = append(out, pb.Platform{
304
-			OS:           pp.OS,
305
-			Architecture: pp.Architecture,
306
-			Variant:      pp.Variant,
307
-			OSVersion:    pp.OSVersion,
308
-			OSFeatures:   pp.OSFeatures,
309
-		})
310
-	}
311
-	return out
312
-}
... ...
@@ -21,7 +21,7 @@ import (
21 21
 	"github.com/moby/buildkit/executor"
22 22
 	"github.com/moby/buildkit/executor/oci"
23 23
 	"github.com/moby/buildkit/identity"
24
-	"github.com/moby/buildkit/util/libcontainer_specconv"
24
+	rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
25 25
 	"github.com/moby/buildkit/util/system"
26 26
 	"github.com/opencontainers/runtime-spec/specs-go"
27 27
 	"github.com/pkg/errors"
... ...
@@ -84,6 +84,8 @@ func New(opt Opt) (executor.Executor, error) {
84 84
 		LogFormat:    runc.JSON,
85 85
 		PdeathSignal: syscall.SIGKILL,
86 86
 		Setpgid:      true,
87
+		// we don't execute runc with --rootless=(true|false) explicitly,
88
+		// so as to support non-runc runtimes
87 89
 	}
88 90
 
89 91
 	w := &runcExecutor{
... ...
@@ -169,13 +171,11 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
169 169
 		return errors.Wrapf(err, "failed to create working directory %s", newp)
170 170
 	}
171 171
 
172
+	if err := setOOMScoreAdj(spec); err != nil {
173
+		return err
174
+	}
172 175
 	if w.rootless {
173
-		specconv.ToRootless(spec, nil)
174
-		// TODO(AkihiroSuda): keep Cgroups enabled if /sys/fs/cgroup/cpuset/buildkit exists and writable
175
-		spec.Linux.CgroupsPath = ""
176
-		// TODO(AkihiroSuda): ToRootless removes netns, but we should readd netns here
177
-		// if either SUID or userspace NAT is configured on the host.
178
-		if err := setOOMScoreAdj(spec); err != nil {
176
+		if err := rootlessspecconv.ToRootless(spec); err != nil {
179 177
 			return err
180 178
 		}
181 179
 	}
... ...
@@ -36,17 +36,21 @@ const (
36 36
 var httpPrefix = regexp.MustCompile("^https?://")
37 37
 var gitUrlPathWithFragmentSuffix = regexp.MustCompile("\\.git(?:#.+)?$")
38 38
 
39
-func Build(ctx context.Context, c client.Client) error {
40
-	opts := c.Opts()
39
+func Build(ctx context.Context, c client.Client) (*client.Result, error) {
40
+	opts := c.BuildOpts().Opts
41 41
 
42
-	// TODO: read buildPlatforms from workers
43
-	buildPlatforms := []specs.Platform{platforms.DefaultSpec()}
42
+	defaultBuildPlatform := platforms.DefaultSpec()
43
+	if workers := c.BuildOpts().Workers; len(workers) > 0 && len(workers[0].Platforms) > 0 {
44
+		defaultBuildPlatform = workers[0].Platforms[0]
45
+	}
46
+
47
+	buildPlatforms := []specs.Platform{defaultBuildPlatform}
44 48
 	targetPlatform := platforms.DefaultSpec()
45 49
 	if v := opts[keyTargetPlatform]; v != "" {
46 50
 		var err error
47 51
 		targetPlatform, err = platforms.Parse(v)
48 52
 		if err != nil {
49
-			return errors.Wrapf(err, "failed to parse target platform %s", v)
53
+			return nil, errors.Wrapf(err, "failed to parse target platform %s", v)
50 54
 		}
51 55
 	}
52 56
 
... ...
@@ -66,7 +70,7 @@ func Build(ctx context.Context, c client.Client) error {
66 66
 
67 67
 	src := llb.Local(LocalNameDockerfile,
68 68
 		llb.IncludePatterns([]string{filename}),
69
-		llb.SessionID(c.SessionID()),
69
+		llb.SessionID(c.BuildOpts().SessionID),
70 70
 		llb.SharedKeyHint(defaultDockerfileName),
71 71
 	)
72 72
 	var buildContext *llb.State
... ...
@@ -78,13 +82,18 @@ func Build(ctx context.Context, c client.Client) error {
78 78
 		httpContext := llb.HTTP(opts[LocalNameContext], llb.Filename("context"))
79 79
 		def, err := httpContext.Marshal()
80 80
 		if err != nil {
81
-			return err
81
+			return nil, errors.Wrapf(err, "failed to marshal httpcontext")
82 82
 		}
83
-		ref, err := c.Solve(ctx, client.SolveRequest{
83
+		res, err := c.Solve(ctx, client.SolveRequest{
84 84
 			Definition: def.ToPB(),
85
-		}, nil, false)
85
+		})
86 86
 		if err != nil {
87
-			return err
87
+			return nil, errors.Wrapf(err, "failed to resolve httpcontext")
88
+		}
89
+
90
+		ref, err := res.SingleRef()
91
+		if err != nil {
92
+			return nil, err
88 93
 		}
89 94
 
90 95
 		dt, err := ref.ReadFile(ctx, client.ReadRequest{
... ...
@@ -94,7 +103,7 @@ func Build(ctx context.Context, c client.Client) error {
94 94
 			},
95 95
 		})
96 96
 		if err != nil {
97
-			return err
97
+			return nil, errors.Errorf("failed to read downloaded context")
98 98
 		}
99 99
 		if isArchive(dt) {
100 100
 			unpack := llb.Image(dockerfile2llb.CopyImage).
... ...
@@ -112,15 +121,20 @@ func Build(ctx context.Context, c client.Client) error {
112 112
 
113 113
 	def, err := src.Marshal()
114 114
 	if err != nil {
115
-		return err
115
+		return nil, errors.Wrapf(err, "failed to marshal local source")
116 116
 	}
117 117
 
118 118
 	eg, ctx2 := errgroup.WithContext(ctx)
119 119
 	var dtDockerfile []byte
120 120
 	eg.Go(func() error {
121
-		ref, err := c.Solve(ctx2, client.SolveRequest{
121
+		res, err := c.Solve(ctx2, client.SolveRequest{
122 122
 			Definition: def.ToPB(),
123
-		}, nil, false)
123
+		})
124
+		if err != nil {
125
+			return errors.Wrapf(err, "failed to resolve dockerfile")
126
+		}
127
+
128
+		ref, err := res.SingleRef()
124 129
 		if err != nil {
125 130
 			return err
126 131
 		}
... ...
@@ -129,7 +143,7 @@ func Build(ctx context.Context, c client.Client) error {
129 129
 			Filename: filename,
130 130
 		})
131 131
 		if err != nil {
132
-			return err
132
+			return errors.Wrapf(err, "failed to read dockerfile")
133 133
 		}
134 134
 		return nil
135 135
 	})
... ...
@@ -139,7 +153,7 @@ func Build(ctx context.Context, c client.Client) error {
139 139
 			dockerignoreState := buildContext
140 140
 			if dockerignoreState == nil {
141 141
 				st := llb.Local(LocalNameContext,
142
-					llb.SessionID(c.SessionID()),
142
+					llb.SessionID(c.BuildOpts().SessionID),
143 143
 					llb.IncludePatterns([]string{dockerignoreFilename}),
144 144
 					llb.SharedKeyHint(dockerignoreFilename),
145 145
 				)
... ...
@@ -149,9 +163,13 @@ func Build(ctx context.Context, c client.Client) error {
149 149
 			if err != nil {
150 150
 				return err
151 151
 			}
152
-			ref, err := c.Solve(ctx2, client.SolveRequest{
152
+			res, err := c.Solve(ctx2, client.SolveRequest{
153 153
 				Definition: def.ToPB(),
154
-			}, nil, false)
154
+			})
155
+			if err != nil {
156
+				return err
157
+			}
158
+			ref, err := res.SingleRef()
155 159
 			if err != nil {
156 160
 				return err
157 161
 			}
... ...
@@ -169,10 +187,10 @@ func Build(ctx context.Context, c client.Client) error {
169 169
 	}
170 170
 
171 171
 	if err := eg.Wait(); err != nil {
172
-		return err
172
+		return nil, err
173 173
 	}
174 174
 
175
-	if _, ok := c.Opts()["cmdline"]; !ok {
175
+	if _, ok := opts["cmdline"]; !ok {
176 176
 		ref, cmdline, ok := dockerfile2llb.DetectSyntax(bytes.NewBuffer(dtDockerfile))
177 177
 		if ok {
178 178
 			return forwardGateway(ctx, c, ref, cmdline)
... ...
@@ -184,7 +202,7 @@ func Build(ctx context.Context, c client.Client) error {
184 184
 		MetaResolver:   c,
185 185
 		BuildArgs:      filter(opts, buildArgPrefix),
186 186
 		Labels:         filter(opts, labelPrefix),
187
-		SessionID:      c.SessionID(),
187
+		SessionID:      c.BuildOpts().SessionID,
188 188
 		BuildContext:   buildContext,
189 189
 		Excludes:       excludes,
190 190
 		IgnoreCache:    ignoreCache,
... ...
@@ -193,17 +211,17 @@ func Build(ctx context.Context, c client.Client) error {
193 193
 	})
194 194
 
195 195
 	if err != nil {
196
-		return err
196
+		return nil, errors.Wrapf(err, "failed to create LLB definition")
197 197
 	}
198 198
 
199 199
 	def, err = st.Marshal()
200 200
 	if err != nil {
201
-		return err
201
+		return nil, errors.Wrapf(err, "failed to marshal LLB definition")
202 202
 	}
203 203
 
204 204
 	config, err := json.Marshal(img)
205 205
 	if err != nil {
206
-		return err
206
+		return nil, errors.Wrapf(err, "failed to marshal image config")
207 207
 	}
208 208
 
209 209
 	var cacheFrom []string
... ...
@@ -211,30 +229,30 @@ func Build(ctx context.Context, c client.Client) error {
211 211
 		cacheFrom = strings.Split(cacheFromStr, ",")
212 212
 	}
213 213
 
214
-	_, err = c.Solve(ctx, client.SolveRequest{
214
+	res, err := c.Solve(ctx, client.SolveRequest{
215 215
 		Definition:      def.ToPB(),
216 216
 		ImportCacheRefs: cacheFrom,
217
-	}, map[string][]byte{
218
-		exporterImageConfig: config,
219
-	}, true)
217
+	})
220 218
 	if err != nil {
221
-		return err
219
+		return nil, err
222 220
 	}
223
-	return nil
221
+
222
+	res.AddMeta(exporterImageConfig, config)
223
+
224
+	return res, nil
224 225
 }
225 226
 
226
-func forwardGateway(ctx context.Context, c client.Client, ref string, cmdline string) error {
227
-	opts := c.Opts()
227
+func forwardGateway(ctx context.Context, c client.Client, ref string, cmdline string) (*client.Result, error) {
228
+	opts := c.BuildOpts().Opts
228 229
 	if opts == nil {
229 230
 		opts = map[string]string{}
230 231
 	}
231 232
 	opts["cmdline"] = cmdline
232 233
 	opts["source"] = ref
233
-	_, err := c.Solve(ctx, client.SolveRequest{
234
+	return c.Solve(ctx, client.SolveRequest{
234 235
 		Frontend:    "gateway.v0",
235 236
 		FrontendOpt: opts,
236
-	}, nil, true)
237
-	return err
237
+	})
238 238
 }
239 239
 
240 240
 func filter(opt map[string]string, key string) map[string]string {
241 241
deleted file mode 100644
... ...
@@ -1,41 +0,0 @@
1
-package dockerfile
2
-
3
-import (
4
-	"context"
5
-
6
-	"github.com/moby/buildkit/frontend"
7
-	"github.com/moby/buildkit/frontend/dockerfile/builder"
8
-	"github.com/moby/buildkit/solver"
9
-)
10
-
11
-func NewDockerfileFrontend() frontend.Frontend {
12
-	return &dfFrontend{}
13
-}
14
-
15
-type dfFrontend struct{}
16
-
17
-func (f *dfFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (retRef solver.CachedResult, exporterAttr map[string][]byte, retErr error) {
18
-
19
-	c, err := llbBridgeToGatewayClient(ctx, llbBridge, opts)
20
-	if err != nil {
21
-		return nil, nil, err
22
-	}
23
-
24
-	defer func() {
25
-		for _, r := range c.refs {
26
-			if r != nil && (c.final != r || retErr != nil) {
27
-				r.Release(context.TODO())
28
-			}
29
-		}
30
-	}()
31
-
32
-	if err := builder.Build(ctx, c); err != nil {
33
-		return nil, nil, err
34
-	}
35
-
36
-	if c.final == nil || c.final.CachedResult == nil {
37
-		return nil, c.exporterAttr, nil
38
-	}
39
-
40
-	return c.final, c.exporterAttr, nil
41
-}
... ...
@@ -80,8 +80,9 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
80 80
 		return nil, nil, err
81 81
 	}
82 82
 
83
-	for i := range metaArgs {
84
-		metaArgs[i] = setBuildArgValue(metaArgs[i], opt.BuildArgs)
83
+	optMetaArgs := []instructions.KeyValuePairOptional{}
84
+	for _, metaArg := range metaArgs {
85
+		optMetaArgs = append(optMetaArgs, setKVValue(metaArg.KeyValuePairOptional, opt.BuildArgs))
85 86
 	}
86 87
 
87 88
 	shlex := shell.NewLex(dockerfile.EscapeToken)
... ...
@@ -95,7 +96,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
95 95
 
96 96
 	// set base state for every image
97 97
 	for _, st := range stages {
98
-		name, err := shlex.ProcessWord(st.BaseName, toEnvList(metaArgs, nil))
98
+		name, err := shlex.ProcessWord(st.BaseName, toEnvList(optMetaArgs, nil))
99 99
 		if err != nil {
100 100
 			return nil, nil, err
101 101
 		}
... ...
@@ -111,7 +112,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
111 111
 		}
112 112
 
113 113
 		if v := st.Platform; v != "" {
114
-			v, err := shlex.ProcessWord(v, toEnvList(metaArgs, nil))
114
+			v, err := shlex.ProcessWord(v, toEnvList(optMetaArgs, nil))
115 115
 			if err != nil {
116 116
 				return nil, nil, errors.Wrapf(err, "failed to process arguments for platform %s", v)
117 117
 			}
... ...
@@ -268,7 +269,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
268 268
 
269 269
 		opt := dispatchOpt{
270 270
 			allDispatchStates: allDispatchStates,
271
-			metaArgs:          metaArgs,
271
+			metaArgs:          optMetaArgs,
272 272
 			buildArgValues:    opt.BuildArgs,
273 273
 			shlex:             shlex,
274 274
 			sessionID:         opt.SessionID,
... ...
@@ -359,7 +360,7 @@ func toCommand(ic instructions.Command, allDispatchStates *dispatchStates) (comm
359 359
 
360 360
 type dispatchOpt struct {
361 361
 	allDispatchStates *dispatchStates
362
-	metaArgs          []instructions.ArgCommand
362
+	metaArgs          []instructions.KeyValuePairOptional
363 363
 	buildArgValues    map[string]string
364 364
 	shlex             *shell.Lex
365 365
 	sessionID         string
... ...
@@ -442,7 +443,7 @@ type dispatchState struct {
442 442
 	stage        instructions.Stage
443 443
 	base         *dispatchState
444 444
 	deps         map[*dispatchState]struct{}
445
-	buildArgs    []instructions.ArgCommand
445
+	buildArgs    []instructions.KeyValuePairOptional
446 446
 	commands     []command
447 447
 	ctxPaths     map[string]struct{}
448 448
 	ignoreCache  bool
... ...
@@ -538,7 +539,7 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
538 538
 	}
539 539
 	opt := []llb.RunOption{llb.Args(args)}
540 540
 	for _, arg := range d.buildArgs {
541
-		opt = append(opt, llb.AddEnv(arg.Key, getArgValue(arg)))
541
+		opt = append(opt, llb.AddEnv(arg.Key, arg.ValueString()))
542 542
 	}
543 543
 	opt = append(opt, dfCmd(c))
544 544
 	if d.ignoreCache {
... ...
@@ -770,20 +771,22 @@ func dispatchShell(d *dispatchState, c *instructions.ShellCommand) error {
770 770
 	return commitToHistory(&d.image, fmt.Sprintf("SHELL %v", c.Shell), false, nil)
771 771
 }
772 772
 
773
-func dispatchArg(d *dispatchState, c *instructions.ArgCommand, metaArgs []instructions.ArgCommand, buildArgValues map[string]string) error {
773
+func dispatchArg(d *dispatchState, c *instructions.ArgCommand, metaArgs []instructions.KeyValuePairOptional, buildArgValues map[string]string) error {
774 774
 	commitStr := "ARG " + c.Key
775
+	buildArg := setKVValue(c.KeyValuePairOptional, buildArgValues)
776
+
775 777
 	if c.Value != nil {
776 778
 		commitStr += "=" + *c.Value
777 779
 	}
778
-	if c.Value == nil {
780
+	if buildArg.Value == nil {
779 781
 		for _, ma := range metaArgs {
780
-			if ma.Key == c.Key {
781
-				c.Value = ma.Value
782
+			if ma.Key == buildArg.Key {
783
+				buildArg.Value = ma.Value
782 784
 			}
783 785
 		}
784 786
 	}
785 787
 
786
-	d.buildArgs = append(d.buildArgs, setBuildArgValue(*c, buildArgValues))
788
+	d.buildArgs = append(d.buildArgs, buildArg)
787 789
 	return commitToHistory(&d.image, commitStr, false, nil)
788 790
 }
789 791
 
... ...
@@ -834,28 +837,20 @@ func addEnv(env []string, k, v string, override bool) []string {
834 834
 	return env
835 835
 }
836 836
 
837
-func setBuildArgValue(c instructions.ArgCommand, values map[string]string) instructions.ArgCommand {
838
-	if v, ok := values[c.Key]; ok {
839
-		c.Value = &v
837
+func setKVValue(kvpo instructions.KeyValuePairOptional, values map[string]string) instructions.KeyValuePairOptional {
838
+	if v, ok := values[kvpo.Key]; ok {
839
+		kvpo.Value = &v
840 840
 	}
841
-	return c
841
+	return kvpo
842 842
 }
843 843
 
844
-func toEnvList(args []instructions.ArgCommand, env []string) []string {
844
+func toEnvList(args []instructions.KeyValuePairOptional, env []string) []string {
845 845
 	for _, arg := range args {
846
-		env = addEnv(env, arg.Key, getArgValue(arg), false)
846
+		env = addEnv(env, arg.Key, arg.ValueString(), false)
847 847
 	}
848 848
 	return env
849 849
 }
850 850
 
851
-func getArgValue(arg instructions.ArgCommand) string {
852
-	v := ""
853
-	if arg.Value != nil {
854
-		v = *arg.Value
855
-	}
856
-	return v
857
-}
858
-
859 851
 func dfCmd(cmd interface{}) llb.ConstraintsOpt {
860 852
 	// TODO: add fmt.Stringer to instructions.Command to remove interface{}
861 853
 	var cmdStr string
... ...
@@ -870,10 +865,10 @@ func dfCmd(cmd interface{}) llb.ConstraintsOpt {
870 870
 	})
871 871
 }
872 872
 
873
-func runCommandString(args []string, buildArgs []instructions.ArgCommand) string {
873
+func runCommandString(args []string, buildArgs []instructions.KeyValuePairOptional) string {
874 874
 	var tmpBuildEnv []string
875 875
 	for _, arg := range buildArgs {
876
-		tmpBuildEnv = append(tmpBuildEnv, arg.Key+"="+getArgValue(arg))
876
+		tmpBuildEnv = append(tmpBuildEnv, arg.Key+"="+arg.ValueString())
877 877
 	}
878 878
 	if len(tmpBuildEnv) > 0 {
879 879
 		tmpBuildEnv = append([]string{fmt.Sprintf("|%d", len(tmpBuildEnv))}, tmpBuildEnv...)
880 880
deleted file mode 100644
... ...
@@ -1,86 +0,0 @@
1
-package dockerfile
2
-
3
-import (
4
-	"context"
5
-
6
-	"github.com/moby/buildkit/cache"
7
-	"github.com/moby/buildkit/frontend"
8
-	"github.com/moby/buildkit/frontend/gateway/client"
9
-	"github.com/moby/buildkit/session"
10
-	"github.com/moby/buildkit/solver"
11
-	"github.com/moby/buildkit/worker"
12
-	"github.com/pkg/errors"
13
-)
14
-
15
-func llbBridgeToGatewayClient(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (*bridgeClient, error) {
16
-	return &bridgeClient{opts: opts, FrontendLLBBridge: llbBridge, sid: session.FromContext(ctx)}, nil
17
-}
18
-
19
-type bridgeClient struct {
20
-	frontend.FrontendLLBBridge
21
-	opts         map[string]string
22
-	final        *ref
23
-	sid          string
24
-	exporterAttr map[string][]byte
25
-	refs         []*ref
26
-}
27
-
28
-func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest, exporterAttr map[string][]byte, final bool) (client.Reference, error) {
29
-	r, exporterAttrRes, err := c.FrontendLLBBridge.Solve(ctx, frontend.SolveRequest{
30
-		Definition:      req.Definition,
31
-		Frontend:        req.Frontend,
32
-		FrontendOpt:     req.FrontendOpt,
33
-		ImportCacheRefs: req.ImportCacheRefs,
34
-	})
35
-	if err != nil {
36
-		return nil, err
37
-	}
38
-	rr := &ref{r}
39
-	c.refs = append(c.refs, rr)
40
-	if final {
41
-		c.final = rr
42
-		if exporterAttr == nil {
43
-			exporterAttr = make(map[string][]byte)
44
-		}
45
-		for k, v := range exporterAttrRes {
46
-			exporterAttr[k] = v
47
-		}
48
-		c.exporterAttr = exporterAttr
49
-	}
50
-	return rr, nil
51
-}
52
-func (c *bridgeClient) Opts() map[string]string {
53
-	return c.opts
54
-}
55
-func (c *bridgeClient) SessionID() string {
56
-	return c.sid
57
-}
58
-
59
-type ref struct {
60
-	solver.CachedResult
61
-}
62
-
63
-func (r *ref) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
64
-	ref, err := r.getImmutableRef()
65
-	if err != nil {
66
-		return nil, err
67
-	}
68
-	newReq := cache.ReadRequest{
69
-		Filename: req.Filename,
70
-	}
71
-	if r := req.Range; r != nil {
72
-		newReq.Range = &cache.FileRange{
73
-			Offset: r.Offset,
74
-			Length: r.Length,
75
-		}
76
-	}
77
-	return cache.ReadFile(ctx, ref, newReq)
78
-}
79
-
80
-func (r *ref) getImmutableRef() (cache.ImmutableRef, error) {
81
-	ref, ok := r.CachedResult.Sys().(*worker.WorkerRef)
82
-	if !ok {
83
-		return nil, errors.Errorf("invalid ref: %T", r.CachedResult.Sys())
84
-	}
85
-	return ref.ImmutableRef, nil
86
-}
... ...
@@ -18,6 +18,20 @@ func (kvp *KeyValuePair) String() string {
18 18
 	return kvp.Key + "=" + kvp.Value
19 19
 }
20 20
 
21
+// KeyValuePairOptional is the same as KeyValuePair but Value is optional
22
+type KeyValuePairOptional struct {
23
+	Key   string
24
+	Value *string
25
+}
26
+
27
+func (kvpo *KeyValuePairOptional) ValueString() string {
28
+	v := ""
29
+	if kvpo.Value != nil {
30
+		v = *kvpo.Value
31
+	}
32
+	return v
33
+}
34
+
21 35
 // Command is implemented by every command present in a dockerfile
22 36
 type Command interface {
23 37
 	Name() string
... ...
@@ -346,8 +360,7 @@ func (c *StopSignalCommand) CheckPlatform(platform string) error {
346 346
 // Dockerfile author may optionally set a default value of this variable.
347 347
 type ArgCommand struct {
348 348
 	withNameAndCode
349
-	Key   string
350
-	Value *string
349
+	KeyValuePairOptional
351 350
 }
352 351
 
353 352
 // Expand variables
... ...
@@ -580,10 +580,7 @@ func parseArg(req parseRequest) (*ArgCommand, error) {
580 580
 		return nil, errExactlyOneArgument("ARG")
581 581
 	}
582 582
 
583
-	var (
584
-		name     string
585
-		newValue *string
586
-	)
583
+	kvpo := KeyValuePairOptional{}
587 584
 
588 585
 	arg := req.args[0]
589 586
 	// 'arg' can just be a name or name-value pair. Note that this is different
... ...
@@ -597,16 +594,15 @@ func parseArg(req parseRequest) (*ArgCommand, error) {
597 597
 			return nil, errBlankCommandNames("ARG")
598 598
 		}
599 599
 
600
-		name = parts[0]
601
-		newValue = &parts[1]
600
+		kvpo.Key = parts[0]
601
+		kvpo.Value = &parts[1]
602 602
 	} else {
603
-		name = arg
603
+		kvpo.Key = arg
604 604
 	}
605 605
 
606 606
 	return &ArgCommand{
607
-		Key:             name,
608
-		Value:           newValue,
609
-		withNameAndCode: newWithNameAndCode(req),
607
+		KeyValuePairOptional: kvpo,
608
+		withNameAndCode:      newWithNameAndCode(req),
610 609
 	}, nil
611 610
 }
612 611
 
... ...
@@ -5,26 +5,25 @@ import (
5 5
 	"io"
6 6
 
7 7
 	"github.com/moby/buildkit/cache"
8
+	"github.com/moby/buildkit/client"
8 9
 	"github.com/moby/buildkit/executor"
9
-	"github.com/moby/buildkit/solver"
10
-	"github.com/moby/buildkit/solver/pb"
10
+	gatewayclient "github.com/moby/buildkit/frontend/gateway/client"
11 11
 	digest "github.com/opencontainers/go-digest"
12 12
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
13 13
 )
14 14
 
15 15
 type Frontend interface {
16
-	Solve(ctx context.Context, llb FrontendLLBBridge, opt map[string]string) (solver.CachedResult, map[string][]byte, error)
16
+	Solve(ctx context.Context, llb FrontendLLBBridge, opt map[string]string) (*Result, error)
17 17
 }
18 18
 
19 19
 type FrontendLLBBridge interface {
20
-	Solve(ctx context.Context, req SolveRequest) (solver.CachedResult, map[string][]byte, error)
20
+	Solve(ctx context.Context, req SolveRequest) (*Result, error)
21 21
 	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
22 22
 	Exec(ctx context.Context, meta executor.Meta, rootfs cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
23 23
 }
24 24
 
25
-type SolveRequest struct {
26
-	Definition      *pb.Definition
27
-	Frontend        string
28
-	FrontendOpt     map[string]string
29
-	ImportCacheRefs []string
25
+type SolveRequest = gatewayclient.SolveRequest
26
+
27
+type WorkerInfos interface {
28
+	WorkerInfos() []client.WorkerInfo
30 29
 }
... ...
@@ -8,12 +8,10 @@ import (
8 8
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
9 9
 )
10 10
 
11
-// TODO: make this take same options as LLBBridge. Add Return()
12 11
 type Client interface {
13
-	Solve(ctx context.Context, req SolveRequest, exporterAttr map[string][]byte, final bool) (Reference, error)
12
+	Solve(ctx context.Context, req SolveRequest) (*Result, error)
14 13
 	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
15
-	Opts() map[string]string
16
-	SessionID() string
14
+	BuildOpts() BuildOpts
17 15
 }
18 16
 
19 17
 type Reference interface {
... ...
@@ -39,3 +37,16 @@ type SolveRequest struct {
39 39
 	FrontendOpt     map[string]string
40 40
 	ImportCacheRefs []string
41 41
 }
42
+
43
+type WorkerInfo struct {
44
+	ID        string
45
+	Labels    map[string]string
46
+	Platforms []specs.Platform
47
+}
48
+
49
+type BuildOpts struct {
50
+	Opts      map[string]string
51
+	SessionID string
52
+	Workers   []WorkerInfo
53
+	Product   string
54
+}
42 55
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+package client
1
+
2
+import (
3
+	"context"
4
+	"sync"
5
+
6
+	"github.com/pkg/errors"
7
+)
8
+
9
+type BuildFunc func(context.Context, Client) (*Result, error)
10
+
11
+type Result struct {
12
+	mu       sync.Mutex
13
+	Ref      Reference
14
+	Refs     map[string]Reference
15
+	Metadata map[string][]byte
16
+}
17
+
18
+func NewResult() *Result {
19
+	return &Result{}
20
+}
21
+
22
+func (r *Result) AddMeta(k string, v []byte) {
23
+	r.mu.Lock()
24
+	if r.Metadata == nil {
25
+		r.Metadata = map[string][]byte{}
26
+	}
27
+	r.Metadata[k] = v
28
+	r.mu.Unlock()
29
+}
30
+
31
+func (r *Result) AddRef(k string, ref Reference) {
32
+	r.mu.Lock()
33
+	if r.Refs == nil {
34
+		r.Refs = map[string]Reference{}
35
+	}
36
+	r.Refs[k] = ref
37
+	r.mu.Unlock()
38
+}
39
+
40
+func (r *Result) SetRef(ref Reference) {
41
+	r.Ref = ref
42
+}
43
+
44
+func (r *Result) SingleRef() (Reference, error) {
45
+	r.mu.Lock()
46
+	defer r.mu.Unlock()
47
+
48
+	if r.Refs != nil && r.Ref == nil {
49
+		return nil, errors.Errorf("invalid map result")
50
+	}
51
+
52
+	return r.Ref, nil
53
+}
0 54
new file mode 100644
... ...
@@ -0,0 +1,149 @@
0
+package forwarder
1
+
2
+import (
3
+	"context"
4
+	"sync"
5
+
6
+	"github.com/moby/buildkit/cache"
7
+	clienttypes "github.com/moby/buildkit/client"
8
+	"github.com/moby/buildkit/frontend"
9
+	"github.com/moby/buildkit/frontend/gateway/client"
10
+	"github.com/moby/buildkit/session"
11
+	"github.com/moby/buildkit/solver"
12
+	"github.com/moby/buildkit/util/apicaps"
13
+	"github.com/moby/buildkit/worker"
14
+	"github.com/pkg/errors"
15
+)
16
+
17
+func llbBridgeToGatewayClient(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string, workerInfos []clienttypes.WorkerInfo) (*bridgeClient, error) {
18
+	return &bridgeClient{
19
+		opts:              opts,
20
+		FrontendLLBBridge: llbBridge,
21
+		sid:               session.FromContext(ctx),
22
+		workerInfos:       workerInfos,
23
+		final:             map[*ref]struct{}{},
24
+	}, nil
25
+}
26
+
27
+type bridgeClient struct {
28
+	frontend.FrontendLLBBridge
29
+	mu           sync.Mutex
30
+	opts         map[string]string
31
+	final        map[*ref]struct{}
32
+	sid          string
33
+	exporterAttr map[string][]byte
34
+	refs         []*ref
35
+	workerInfos  []clienttypes.WorkerInfo
36
+}
37
+
38
+func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*client.Result, error) {
39
+	res, err := c.FrontendLLBBridge.Solve(ctx, frontend.SolveRequest{
40
+		Definition:      req.Definition,
41
+		Frontend:        req.Frontend,
42
+		FrontendOpt:     req.FrontendOpt,
43
+		ImportCacheRefs: req.ImportCacheRefs,
44
+	})
45
+	if err != nil {
46
+		return nil, err
47
+	}
48
+
49
+	cRes := &client.Result{}
50
+	c.mu.Lock()
51
+	for k, r := range res.Refs {
52
+		rr := &ref{r}
53
+		c.refs = append(c.refs, rr)
54
+		cRes.AddRef(k, rr)
55
+	}
56
+	if r := res.Ref; r != nil {
57
+		rr := &ref{r}
58
+		c.refs = append(c.refs, rr)
59
+		cRes.SetRef(rr)
60
+	}
61
+	c.mu.Unlock()
62
+	cRes.Metadata = res.Metadata
63
+
64
+	return cRes, nil
65
+}
66
+func (c *bridgeClient) BuildOpts() client.BuildOpts {
67
+	workers := make([]client.WorkerInfo, 0, len(c.workerInfos))
68
+	for _, w := range c.workerInfos {
69
+		workers = append(workers, client.WorkerInfo(w))
70
+	}
71
+
72
+	return client.BuildOpts{
73
+		Opts:      c.opts,
74
+		SessionID: c.sid,
75
+		Workers:   workers,
76
+		Product:   apicaps.ExportedProduct,
77
+	}
78
+}
79
+
80
+func (c *bridgeClient) toFrontendResult(r *client.Result) (*frontend.Result, error) {
81
+	if r == nil {
82
+		return nil, nil
83
+	}
84
+
85
+	res := &frontend.Result{}
86
+
87
+	if r.Refs != nil {
88
+		res.Refs = make(map[string]solver.CachedResult, len(r.Refs))
89
+		for k, r := range r.Refs {
90
+			rr, ok := r.(*ref)
91
+			if !ok {
92
+				return nil, errors.Errorf("invalid reference type for forward %T", r)
93
+			}
94
+			c.final[rr] = struct{}{}
95
+			res.Refs[k] = rr.CachedResult
96
+		}
97
+	}
98
+	if r := r.Ref; r != nil {
99
+		rr, ok := r.(*ref)
100
+		if !ok {
101
+			return nil, errors.Errorf("invalid reference type for forward %T", r)
102
+		}
103
+		c.final[rr] = struct{}{}
104
+		res.Ref = rr.CachedResult
105
+	}
106
+	res.Metadata = r.Metadata
107
+
108
+	return res, nil
109
+}
110
+
111
+func (c *bridgeClient) discard(err error) {
112
+	for _, r := range c.refs {
113
+		if r != nil {
114
+			if _, ok := c.final[r]; !ok || err != nil {
115
+				r.Release(context.TODO())
116
+			}
117
+		}
118
+	}
119
+}
120
+
121
+type ref struct {
122
+	solver.CachedResult
123
+}
124
+
125
+func (r *ref) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
126
+	ref, err := r.getImmutableRef()
127
+	if err != nil {
128
+		return nil, err
129
+	}
130
+	newReq := cache.ReadRequest{
131
+		Filename: req.Filename,
132
+	}
133
+	if r := req.Range; r != nil {
134
+		newReq.Range = &cache.FileRange{
135
+			Offset: r.Offset,
136
+			Length: r.Length,
137
+		}
138
+	}
139
+	return cache.ReadFile(ctx, ref, newReq)
140
+}
141
+
142
+func (r *ref) getImmutableRef() (cache.ImmutableRef, error) {
143
+	ref, ok := r.CachedResult.Sys().(*worker.WorkerRef)
144
+	if !ok {
145
+		return nil, errors.Errorf("invalid ref: %T", r.CachedResult.Sys())
146
+	}
147
+	return ref.ImmutableRef, nil
148
+}
0 149
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package forwarder
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/moby/buildkit/frontend"
6
+	"github.com/moby/buildkit/frontend/gateway/client"
7
+)
8
+
9
+func NewGatewayForwarder(w frontend.WorkerInfos, f client.BuildFunc) frontend.Frontend {
10
+	return &GatewayForwarder{
11
+		workers: w,
12
+		f:       f,
13
+	}
14
+}
15
+
16
+type GatewayForwarder struct {
17
+	workers frontend.WorkerInfos
18
+	f       client.BuildFunc
19
+}
20
+
21
+func (gf *GatewayForwarder) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (retRes *frontend.Result, retErr error) {
22
+	c, err := llbBridgeToGatewayClient(ctx, llbBridge, opts, gf.workers.WorkerInfos())
23
+	if err != nil {
24
+		return nil, err
25
+	}
26
+
27
+	defer func() {
28
+		c.discard(retErr)
29
+	}()
30
+
31
+	res, err := gf.f(ctx, c)
32
+	if err != nil {
33
+		return nil, err
34
+	}
35
+
36
+	return c.toFrontendResult(res)
37
+}
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"time"
13 13
 
14 14
 	"github.com/docker/distribution/reference"
15
+	apitypes "github.com/moby/buildkit/api/types"
15 16
 	"github.com/moby/buildkit/cache"
16 17
 	"github.com/moby/buildkit/client/llb"
17 18
 	"github.com/moby/buildkit/executor"
... ...
@@ -20,15 +21,19 @@ import (
20 20
 	"github.com/moby/buildkit/identity"
21 21
 	"github.com/moby/buildkit/session"
22 22
 	"github.com/moby/buildkit/solver"
23
+	opspb "github.com/moby/buildkit/solver/pb"
24
+	"github.com/moby/buildkit/util/apicaps"
23 25
 	"github.com/moby/buildkit/util/tracing"
24 26
 	"github.com/moby/buildkit/worker"
25 27
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
26 28
 	"github.com/pkg/errors"
27 29
 	"github.com/sirupsen/logrus"
28 30
 	"golang.org/x/net/http2"
31
+	spb "google.golang.org/genproto/googleapis/rpc/status"
29 32
 	"google.golang.org/grpc"
30 33
 	"google.golang.org/grpc/health"
31 34
 	"google.golang.org/grpc/health/grpc_health_v1"
35
+	"google.golang.org/grpc/status"
32 36
 )
33 37
 
34 38
 const (
... ...
@@ -37,11 +42,14 @@ const (
37 37
 	exporterImageConfig = "containerimage.config"
38 38
 )
39 39
 
40
-func NewGatewayFrontend() frontend.Frontend {
41
-	return &gatewayFrontend{}
40
+func NewGatewayFrontend(w frontend.WorkerInfos) frontend.Frontend {
41
+	return &gatewayFrontend{
42
+		workers: w,
43
+	}
42 44
 }
43 45
 
44 46
 type gatewayFrontend struct {
47
+	workers frontend.WorkerInfos
45 48
 }
46 49
 
47 50
 func filterPrefix(opts map[string]string, pfx string) map[string]string {
... ...
@@ -54,10 +62,10 @@ func filterPrefix(opts map[string]string, pfx string) map[string]string {
54 54
 	return m
55 55
 }
56 56
 
57
-func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (retRef solver.CachedResult, exporterAttr map[string][]byte, retErr error) {
57
+func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (ret *frontend.Result, retErr error) {
58 58
 	source, ok := opts[keySource]
59 59
 	if !ok {
60
-		return nil, nil, errors.Errorf("no source specified for gateway")
60
+		return nil, errors.Errorf("no source specified for gateway")
61 61
 	}
62 62
 
63 63
 	sid := session.FromContext(ctx)
... ...
@@ -68,46 +76,52 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
68 68
 	var readonly bool // TODO: try to switch to read-only by default.
69 69
 
70 70
 	if isDevel {
71
-		ref, exp, err := llbBridge.Solve(session.NewContext(ctx, "gateway:"+sid),
71
+		devRes, err := llbBridge.Solve(session.NewContext(ctx, "gateway:"+sid),
72 72
 			frontend.SolveRequest{
73 73
 				Frontend:    source,
74 74
 				FrontendOpt: filterPrefix(opts, "gateway-"),
75 75
 			})
76 76
 		if err != nil {
77
-			return nil, nil, err
77
+			return nil, err
78 78
 		}
79
-		defer ref.Release(context.TODO())
80
-
81
-		workerRef, ok := ref.Sys().(*worker.WorkerRef)
79
+		defer func() {
80
+			devRes.EachRef(func(ref solver.CachedResult) error {
81
+				return ref.Release(context.TODO())
82
+			})
83
+		}()
84
+		if devRes.Ref == nil {
85
+			return nil, errors.Errorf("development gateway didn't return default result")
86
+		}
87
+		workerRef, ok := devRes.Ref.Sys().(*worker.WorkerRef)
82 88
 		if !ok {
83
-			return nil, nil, errors.Errorf("invalid ref: %T", ref.Sys())
89
+			return nil, errors.Errorf("invalid ref: %T", devRes.Ref.Sys())
84 90
 		}
85 91
 		rootFS = workerRef.ImmutableRef
86
-		config, ok := exp[exporterImageConfig]
92
+		config, ok := devRes.Metadata[exporterImageConfig]
87 93
 		if ok {
88 94
 			if err := json.Unmarshal(config, &img); err != nil {
89
-				return nil, nil, err
95
+				return nil, err
90 96
 			}
91 97
 		}
92 98
 	} else {
93 99
 		sourceRef, err := reference.ParseNormalizedNamed(source)
94 100
 		if err != nil {
95
-			return nil, nil, err
101
+			return nil, err
96 102
 		}
97 103
 
98 104
 		dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), nil) // TODO:
99 105
 		if err != nil {
100
-			return nil, nil, err
106
+			return nil, err
101 107
 		}
102 108
 
103 109
 		if err := json.Unmarshal(config, &img); err != nil {
104
-			return nil, nil, err
110
+			return nil, err
105 111
 		}
106 112
 
107 113
 		if dgst != "" {
108 114
 			sourceRef, err = reference.WithDigest(sourceRef, dgst)
109 115
 			if err != nil {
110
-				return nil, nil, err
116
+				return nil, err
111 117
 			}
112 118
 		}
113 119
 
... ...
@@ -115,27 +129,35 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
115 115
 
116 116
 		def, err := src.Marshal()
117 117
 		if err != nil {
118
-			return nil, nil, err
118
+			return nil, err
119 119
 		}
120 120
 
121
-		ref, _, err := llbBridge.Solve(ctx, frontend.SolveRequest{
121
+		res, err := llbBridge.Solve(ctx, frontend.SolveRequest{
122 122
 			Definition: def.ToPB(),
123 123
 		})
124 124
 		if err != nil {
125
-			return nil, nil, err
125
+			return nil, err
126 126
 		}
127
-		defer ref.Release(context.TODO())
128
-		workerRef, ok := ref.Sys().(*worker.WorkerRef)
127
+		defer func() {
128
+			res.EachRef(func(ref solver.CachedResult) error {
129
+				return ref.Release(context.TODO())
130
+			})
131
+		}()
132
+		if res.Ref == nil {
133
+			return nil, errors.Errorf("gateway source didn't return default result")
134
+
135
+		}
136
+		workerRef, ok := res.Ref.Sys().(*worker.WorkerRef)
129 137
 		if !ok {
130
-			return nil, nil, errors.Errorf("invalid ref: %T", ref.Sys())
138
+			return nil, errors.Errorf("invalid ref: %T", res.Ref.Sys())
131 139
 		}
132 140
 		rootFS = workerRef.ImmutableRef
133 141
 	}
134 142
 
135
-	lbf, err := newLLBBridgeForwarder(ctx, llbBridge)
143
+	lbf, err := newLLBBridgeForwarder(ctx, llbBridge, gf.workers)
136 144
 	defer lbf.conn.Close()
137 145
 	if err != nil {
138
-		return nil, nil, err
146
+		return nil, err
139 147
 	}
140 148
 
141 149
 	args := []string{"/run"}
... ...
@@ -158,14 +180,32 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
158 158
 
159 159
 	env = append(env, "BUILDKIT_SESSION_ID="+sid)
160 160
 
161
+	dt, err := json.Marshal(gf.workers.WorkerInfos())
162
+	if err != nil {
163
+		return nil, errors.Wrap(err, "failed to marshal workers array")
164
+	}
165
+	env = append(env, "BUILDKIT_WORKERS="+string(dt))
166
+
161 167
 	defer func() {
162 168
 		for _, r := range lbf.refs {
163
-			if r != nil && (lbf.lastRef != r || retErr != nil) {
164
-				r.Release(context.TODO())
169
+			if retErr == nil && lbf.result != nil {
170
+				keep := false
171
+				lbf.result.EachRef(func(r2 solver.CachedResult) error {
172
+					if r == r2 {
173
+						keep = true
174
+					}
175
+					return nil
176
+				})
177
+				if keep {
178
+					continue
179
+				}
165 180
 			}
181
+			r.Release(context.TODO())
166 182
 		}
167 183
 	}()
168 184
 
185
+	env = append(env, "BUILDKIT_EXPORTEDPRODUCT="+apicaps.ExportedProduct)
186
+
169 187
 	err = llbBridge.Exec(ctx, executor.Meta{
170 188
 		Env:            env,
171 189
 		Args:           args,
... ...
@@ -173,19 +213,24 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
173 173
 		ReadonlyRootFS: readonly,
174 174
 	}, rootFS, lbf.Stdin, lbf.Stdout, os.Stderr)
175 175
 
176
+	if lbf.err != nil {
177
+		return nil, lbf.err
178
+	}
179
+
176 180
 	if err != nil {
177
-		return nil, nil, err
181
+		return nil, err
178 182
 	}
179 183
 
180
-	return lbf.lastRef, lbf.exporterAttr, nil
184
+	return lbf.result, nil
181 185
 }
182 186
 
183
-func newLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge) (*llbBridgeForwarder, error) {
187
+func newLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos) (*llbBridgeForwarder, error) {
184 188
 	lbf := &llbBridgeForwarder{
185 189
 		callCtx:   ctx,
186 190
 		llbBridge: llbBridge,
187
-		refs:      map[string]solver.Result{},
191
+		refs:      map[string]solver.CachedResult{},
188 192
 		pipe:      newPipe(),
193
+		workers:   workers,
189 194
 	}
190 195
 
191 196
 	server := grpc.NewServer()
... ...
@@ -251,12 +296,17 @@ func (d dummyAddr) String() string {
251 251
 }
252 252
 
253 253
 type llbBridgeForwarder struct {
254
-	mu           sync.Mutex
255
-	callCtx      context.Context
256
-	llbBridge    frontend.FrontendLLBBridge
257
-	refs         map[string]solver.Result
258
-	lastRef      solver.CachedResult
254
+	mu        sync.Mutex
255
+	callCtx   context.Context
256
+	llbBridge frontend.FrontendLLBBridge
257
+	refs      map[string]solver.CachedResult
258
+	// lastRef      solver.CachedResult
259
+	// lastRefs     map[string]solver.CachedResult
260
+	// err          error
261
+	result       *frontend.Result
262
+	err          error
259 263
 	exporterAttr map[string][]byte
264
+	workers      frontend.WorkerInfos
260 265
 	*pipe
261 266
 }
262 267
 
... ...
@@ -284,7 +334,7 @@ func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.R
284 284
 
285 285
 func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) (*pb.SolveResponse, error) {
286 286
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
287
-	ref, expResp, err := lbf.llbBridge.Solve(ctx, frontend.SolveRequest{
287
+	res, err := lbf.llbBridge.Solve(ctx, frontend.SolveRequest{
288 288
 		Definition:      req.Definition,
289 289
 		Frontend:        req.Frontend,
290 290
 		FrontendOpt:     req.FrontendOpt,
... ...
@@ -294,29 +344,65 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest)
294 294
 		return nil, err
295 295
 	}
296 296
 
297
-	exp := map[string][]byte{}
298
-	if err := json.Unmarshal(req.ExporterAttr, &exp); err != nil {
299
-		return nil, err
297
+	if len(res.Refs) > 0 && !req.AllowResultReturn {
298
+		// this should never happen because old client shouldn't make a map request
299
+		return nil, errors.Errorf("solve did not return default result")
300 300
 	}
301 301
 
302
-	if expResp != nil {
303
-		for k, v := range expResp {
304
-			exp[k] = v
305
-		}
306
-	}
302
+	pbRes := &pb.Result{}
303
+	var defaultID string
307 304
 
308
-	id := identity.NewID()
309 305
 	lbf.mu.Lock()
310
-	lbf.refs[id] = ref
306
+	if res.Refs != nil {
307
+		ids := make(map[string]string, len(res.Refs))
308
+		for k, ref := range res.Refs {
309
+			id := identity.NewID()
310
+			if ref == nil {
311
+				id = ""
312
+			} else {
313
+				lbf.refs[id] = ref
314
+			}
315
+			ids[k] = id
316
+		}
317
+		pbRes.Result = &pb.Result_Refs{Refs: &pb.RefMap{Refs: ids}}
318
+	} else {
319
+		id := identity.NewID()
320
+		if res.Ref == nil {
321
+			id = ""
322
+		} else {
323
+			lbf.refs[id] = res.Ref
324
+		}
325
+		defaultID = id
326
+		pbRes.Result = &pb.Result_Ref{Ref: id}
327
+	}
311 328
 	lbf.mu.Unlock()
329
+
330
+	// compatibility mode for older clients
312 331
 	if req.Final {
313
-		lbf.lastRef = ref
314
-		lbf.exporterAttr = exp
332
+		exp := map[string][]byte{}
333
+		if err := json.Unmarshal(req.ExporterAttr, &exp); err != nil {
334
+			return nil, err
335
+		}
336
+
337
+		for k, v := range res.Metadata {
338
+			exp[k] = v
339
+		}
340
+
341
+		lbf.result = &frontend.Result{
342
+			Ref:      lbf.refs[defaultID],
343
+			Metadata: exp,
344
+		}
315 345
 	}
316
-	if ref == nil {
317
-		id = ""
346
+
347
+	resp := &pb.SolveResponse{
348
+		Result: pbRes,
318 349
 	}
319
-	return &pb.SolveResponse{Ref: id}, nil
350
+
351
+	if !req.AllowResultReturn {
352
+		resp.Ref = defaultID
353
+	}
354
+
355
+	return resp, nil
320 356
 }
321 357
 func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileRequest) (*pb.ReadFileResponse, error) {
322 358
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
... ...
@@ -353,7 +439,68 @@ func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileReq
353 353
 }
354 354
 
355 355
 func (lbf *llbBridgeForwarder) Ping(context.Context, *pb.PingRequest) (*pb.PongResponse, error) {
356
-	return &pb.PongResponse{}, nil
356
+
357
+	workers := lbf.workers.WorkerInfos()
358
+	pbWorkers := make([]*apitypes.WorkerRecord, 0, len(workers))
359
+	for _, w := range workers {
360
+		pbWorkers = append(pbWorkers, &apitypes.WorkerRecord{
361
+			ID:        w.ID,
362
+			Labels:    w.Labels,
363
+			Platforms: opspb.PlatformsFromSpec(w.Platforms),
364
+		})
365
+	}
366
+
367
+	return &pb.PongResponse{
368
+		FrontendAPICaps: pb.Caps.All(),
369
+		Workers:         pbWorkers,
370
+		// TODO: add LLB info
371
+	}, nil
372
+}
373
+
374
+func (lbf *llbBridgeForwarder) Return(ctx context.Context, in *pb.ReturnRequest) (*pb.ReturnResponse, error) {
375
+	if in.Error != nil {
376
+		lbf.err = status.ErrorProto(&spb.Status{
377
+			Code:    in.Error.Code,
378
+			Message: in.Error.Message,
379
+			// Details: in.Error.Details,
380
+		})
381
+	} else {
382
+		lbf.result = &frontend.Result{
383
+			Metadata: in.Result.Metadata,
384
+		}
385
+
386
+		switch res := in.Result.Result.(type) {
387
+		case *pb.Result_Ref:
388
+			ref, err := lbf.convertRef(res.Ref)
389
+			if err != nil {
390
+				return nil, err
391
+			}
392
+			lbf.result.Ref = ref
393
+		case *pb.Result_Refs:
394
+			m := map[string]solver.CachedResult{}
395
+			for k, v := range res.Refs.Refs {
396
+				ref, err := lbf.convertRef(v)
397
+				if err != nil {
398
+					return nil, err
399
+				}
400
+				m[k] = ref
401
+			}
402
+			lbf.result.Refs = m
403
+		}
404
+	}
405
+
406
+	return &pb.ReturnResponse{}, nil
407
+}
408
+
409
+func (lbf *llbBridgeForwarder) convertRef(id string) (solver.CachedResult, error) {
410
+	if id == "" {
411
+		return nil, nil
412
+	}
413
+	r, ok := lbf.refs[id]
414
+	if !ok {
415
+		return nil, errors.Errorf("return reference %s not found", id)
416
+	}
417
+	return r, nil
357 418
 }
358 419
 
359 420
 func serve(ctx context.Context, grpcServer *grpc.Server, conn net.Conn) {
360 421
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+package moby_buildkit_v1_frontend
1
+
2
+import "github.com/moby/buildkit/util/apicaps"
3
+
4
+var Caps apicaps.CapList
5
+
6
+// Every backwards or forwards non-compatible change needs to add a new capability row.
7
+// By default new capabilities should be experimental. After merge a capability is
8
+// considered immutable. After a capability is marked stable it should not be disabled.
9
+
10
+const (
11
+	CapSolveBase         apicaps.CapID = "solve.base"
12
+	CapSolveInlineReturn apicaps.CapID = "solve.inlinereturn"
13
+	CapResolveImage      apicaps.CapID = "resolveimage"
14
+	CapReadFile          apicaps.CapID = "readfile"
15
+	CapReturnResult      apicaps.CapID = "return"
16
+	CapReturnMap         apicaps.CapID = "returnmap"
17
+)
18
+
19
+func init() {
20
+
21
+	Caps.Init(apicaps.Cap{
22
+		ID:      CapSolveBase,
23
+		Enabled: true,
24
+		Status:  apicaps.CapStatusExperimental,
25
+	})
26
+
27
+	Caps.Init(apicaps.Cap{
28
+		ID:         CapSolveInlineReturn,
29
+		Name:       "inline return from solve",
30
+		Enabled:    true,
31
+		Deprecated: true,
32
+		Status:     apicaps.CapStatusExperimental,
33
+	})
34
+
35
+	Caps.Init(apicaps.Cap{
36
+		ID:      CapResolveImage,
37
+		Name:    "resolve remote image config",
38
+		Enabled: true,
39
+		Status:  apicaps.CapStatusExperimental,
40
+	})
41
+
42
+	Caps.Init(apicaps.Cap{
43
+		ID:      CapReadFile,
44
+		Name:    "read static file",
45
+		Enabled: true,
46
+		Status:  apicaps.CapStatusExperimental,
47
+	})
48
+
49
+	Caps.Init(apicaps.Cap{
50
+		ID:      CapReturnResult,
51
+		Name:    "return solve result",
52
+		Enabled: true,
53
+		Status:  apicaps.CapStatusExperimental,
54
+	})
55
+
56
+	Caps.Init(apicaps.Cap{
57
+		ID:      CapReturnMap,
58
+		Name:    "return reference map",
59
+		Enabled: true,
60
+		Status:  apicaps.CapStatusExperimental,
61
+	})
62
+
63
+}
... ...
@@ -8,6 +8,10 @@
8 8
 		gateway.proto
9 9
 
10 10
 	It has these top-level messages:
11
+		Result
12
+		RefMap
13
+		ReturnRequest
14
+		ReturnResponse
11 15
 		ResolveImageConfigRequest
12 16
 		ResolveImageConfigResponse
13 17
 		SolveRequest
... ...
@@ -24,7 +28,10 @@ import proto "github.com/gogo/protobuf/proto"
24 24
 import fmt "fmt"
25 25
 import math "math"
26 26
 import _ "github.com/gogo/protobuf/gogoproto"
27
+import google_rpc "github.com/gogo/googleapis/google/rpc"
27 28
 import pb "github.com/moby/buildkit/solver/pb"
29
+import moby_buildkit_v1_types "github.com/moby/buildkit/api/types"
30
+import moby_buildkit_v1_apicaps "github.com/moby/buildkit/util/apicaps/pb"
28 31
 
29 32
 import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
30 33
 
... ...
@@ -44,6 +51,181 @@ var _ = math.Inf
44 44
 // proto package needs to be updated.
45 45
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
46 46
 
47
+type Result struct {
48
+	// Types that are valid to be assigned to Result:
49
+	//	*Result_Ref
50
+	//	*Result_Refs
51
+	Result   isResult_Result   `protobuf_oneof:"result"`
52
+	Metadata map[string][]byte `protobuf:"bytes,10,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
53
+}
54
+
55
+func (m *Result) Reset()                    { *m = Result{} }
56
+func (m *Result) String() string            { return proto.CompactTextString(m) }
57
+func (*Result) ProtoMessage()               {}
58
+func (*Result) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{0} }
59
+
60
+type isResult_Result interface {
61
+	isResult_Result()
62
+	MarshalTo([]byte) (int, error)
63
+	Size() int
64
+}
65
+
66
+type Result_Ref struct {
67
+	Ref string `protobuf:"bytes,1,opt,name=ref,proto3,oneof"`
68
+}
69
+type Result_Refs struct {
70
+	Refs *RefMap `protobuf:"bytes,2,opt,name=refs,oneof"`
71
+}
72
+
73
+func (*Result_Ref) isResult_Result()  {}
74
+func (*Result_Refs) isResult_Result() {}
75
+
76
+func (m *Result) GetResult() isResult_Result {
77
+	if m != nil {
78
+		return m.Result
79
+	}
80
+	return nil
81
+}
82
+
83
+func (m *Result) GetRef() string {
84
+	if x, ok := m.GetResult().(*Result_Ref); ok {
85
+		return x.Ref
86
+	}
87
+	return ""
88
+}
89
+
90
+func (m *Result) GetRefs() *RefMap {
91
+	if x, ok := m.GetResult().(*Result_Refs); ok {
92
+		return x.Refs
93
+	}
94
+	return nil
95
+}
96
+
97
+func (m *Result) GetMetadata() map[string][]byte {
98
+	if m != nil {
99
+		return m.Metadata
100
+	}
101
+	return nil
102
+}
103
+
104
+// XXX_OneofFuncs is for the internal use of the proto package.
105
+func (*Result) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
106
+	return _Result_OneofMarshaler, _Result_OneofUnmarshaler, _Result_OneofSizer, []interface{}{
107
+		(*Result_Ref)(nil),
108
+		(*Result_Refs)(nil),
109
+	}
110
+}
111
+
112
+func _Result_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
113
+	m := msg.(*Result)
114
+	// result
115
+	switch x := m.Result.(type) {
116
+	case *Result_Ref:
117
+		_ = b.EncodeVarint(1<<3 | proto.WireBytes)
118
+		_ = b.EncodeStringBytes(x.Ref)
119
+	case *Result_Refs:
120
+		_ = b.EncodeVarint(2<<3 | proto.WireBytes)
121
+		if err := b.EncodeMessage(x.Refs); err != nil {
122
+			return err
123
+		}
124
+	case nil:
125
+	default:
126
+		return fmt.Errorf("Result.Result has unexpected type %T", x)
127
+	}
128
+	return nil
129
+}
130
+
131
+func _Result_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
132
+	m := msg.(*Result)
133
+	switch tag {
134
+	case 1: // result.ref
135
+		if wire != proto.WireBytes {
136
+			return true, proto.ErrInternalBadWireType
137
+		}
138
+		x, err := b.DecodeStringBytes()
139
+		m.Result = &Result_Ref{x}
140
+		return true, err
141
+	case 2: // result.refs
142
+		if wire != proto.WireBytes {
143
+			return true, proto.ErrInternalBadWireType
144
+		}
145
+		msg := new(RefMap)
146
+		err := b.DecodeMessage(msg)
147
+		m.Result = &Result_Refs{msg}
148
+		return true, err
149
+	default:
150
+		return false, nil
151
+	}
152
+}
153
+
154
+func _Result_OneofSizer(msg proto.Message) (n int) {
155
+	m := msg.(*Result)
156
+	// result
157
+	switch x := m.Result.(type) {
158
+	case *Result_Ref:
159
+		n += proto.SizeVarint(1<<3 | proto.WireBytes)
160
+		n += proto.SizeVarint(uint64(len(x.Ref)))
161
+		n += len(x.Ref)
162
+	case *Result_Refs:
163
+		s := proto.Size(x.Refs)
164
+		n += proto.SizeVarint(2<<3 | proto.WireBytes)
165
+		n += proto.SizeVarint(uint64(s))
166
+		n += s
167
+	case nil:
168
+	default:
169
+		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
170
+	}
171
+	return n
172
+}
173
+
174
+type RefMap struct {
175
+	Refs map[string]string `protobuf:"bytes,1,rep,name=refs" json:"refs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
176
+}
177
+
178
+func (m *RefMap) Reset()                    { *m = RefMap{} }
179
+func (m *RefMap) String() string            { return proto.CompactTextString(m) }
180
+func (*RefMap) ProtoMessage()               {}
181
+func (*RefMap) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{1} }
182
+
183
+func (m *RefMap) GetRefs() map[string]string {
184
+	if m != nil {
185
+		return m.Refs
186
+	}
187
+	return nil
188
+}
189
+
190
+type ReturnRequest struct {
191
+	Result *Result            `protobuf:"bytes,1,opt,name=result" json:"result,omitempty"`
192
+	Error  *google_rpc.Status `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"`
193
+}
194
+
195
+func (m *ReturnRequest) Reset()                    { *m = ReturnRequest{} }
196
+func (m *ReturnRequest) String() string            { return proto.CompactTextString(m) }
197
+func (*ReturnRequest) ProtoMessage()               {}
198
+func (*ReturnRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{2} }
199
+
200
+func (m *ReturnRequest) GetResult() *Result {
201
+	if m != nil {
202
+		return m.Result
203
+	}
204
+	return nil
205
+}
206
+
207
+func (m *ReturnRequest) GetError() *google_rpc.Status {
208
+	if m != nil {
209
+		return m.Error
210
+	}
211
+	return nil
212
+}
213
+
214
+type ReturnResponse struct {
215
+}
216
+
217
+func (m *ReturnResponse) Reset()                    { *m = ReturnResponse{} }
218
+func (m *ReturnResponse) String() string            { return proto.CompactTextString(m) }
219
+func (*ReturnResponse) ProtoMessage()               {}
220
+func (*ReturnResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{3} }
221
+
47 222
 type ResolveImageConfigRequest struct {
48 223
 	Ref      string       `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
49 224
 	Platform *pb.Platform `protobuf:"bytes,2,opt,name=Platform" json:"Platform,omitempty"`
... ...
@@ -52,7 +234,7 @@ type ResolveImageConfigRequest struct {
52 52
 func (m *ResolveImageConfigRequest) Reset()                    { *m = ResolveImageConfigRequest{} }
53 53
 func (m *ResolveImageConfigRequest) String() string            { return proto.CompactTextString(m) }
54 54
 func (*ResolveImageConfigRequest) ProtoMessage()               {}
55
-func (*ResolveImageConfigRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{0} }
55
+func (*ResolveImageConfigRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{4} }
56 56
 
57 57
 func (m *ResolveImageConfigRequest) GetRef() string {
58 58
 	if m != nil {
... ...
@@ -77,7 +259,7 @@ func (m *ResolveImageConfigResponse) Reset()         { *m = ResolveImageConfigRe
77 77
 func (m *ResolveImageConfigResponse) String() string { return proto.CompactTextString(m) }
78 78
 func (*ResolveImageConfigResponse) ProtoMessage()    {}
79 79
 func (*ResolveImageConfigResponse) Descriptor() ([]byte, []int) {
80
-	return fileDescriptorGateway, []int{1}
80
+	return fileDescriptorGateway, []int{5}
81 81
 }
82 82
 
83 83
 func (m *ResolveImageConfigResponse) GetConfig() []byte {
... ...
@@ -88,18 +270,20 @@ func (m *ResolveImageConfigResponse) GetConfig() []byte {
88 88
 }
89 89
 
90 90
 type SolveRequest struct {
91
-	Definition      *pb.Definition    `protobuf:"bytes,1,opt,name=Definition" json:"Definition,omitempty"`
92
-	Frontend        string            `protobuf:"bytes,2,opt,name=Frontend,proto3" json:"Frontend,omitempty"`
93
-	FrontendOpt     map[string]string `protobuf:"bytes,3,rep,name=FrontendOpt" json:"FrontendOpt,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
94
-	ImportCacheRefs []string          `protobuf:"bytes,4,rep,name=ImportCacheRefs" json:"ImportCacheRefs,omitempty"`
95
-	Final           bool              `protobuf:"varint,10,opt,name=Final,proto3" json:"Final,omitempty"`
96
-	ExporterAttr    []byte            `protobuf:"bytes,11,opt,name=ExporterAttr,proto3" json:"ExporterAttr,omitempty"`
91
+	Definition        *pb.Definition    `protobuf:"bytes,1,opt,name=Definition" json:"Definition,omitempty"`
92
+	Frontend          string            `protobuf:"bytes,2,opt,name=Frontend,proto3" json:"Frontend,omitempty"`
93
+	FrontendOpt       map[string]string `protobuf:"bytes,3,rep,name=FrontendOpt" json:"FrontendOpt,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
94
+	ImportCacheRefs   []string          `protobuf:"bytes,4,rep,name=ImportCacheRefs" json:"ImportCacheRefs,omitempty"`
95
+	AllowResultReturn bool              `protobuf:"varint,5,opt,name=allowResultReturn,proto3" json:"allowResultReturn,omitempty"`
96
+	// apicaps.CapSolveInlineReturn deprecated
97
+	Final        bool   `protobuf:"varint,10,opt,name=Final,proto3" json:"Final,omitempty"`
98
+	ExporterAttr []byte `protobuf:"bytes,11,opt,name=ExporterAttr,proto3" json:"ExporterAttr,omitempty"`
97 99
 }
98 100
 
99 101
 func (m *SolveRequest) Reset()                    { *m = SolveRequest{} }
100 102
 func (m *SolveRequest) String() string            { return proto.CompactTextString(m) }
101 103
 func (*SolveRequest) ProtoMessage()               {}
102
-func (*SolveRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{2} }
104
+func (*SolveRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{6} }
103 105
 
104 106
 func (m *SolveRequest) GetDefinition() *pb.Definition {
105 107
 	if m != nil {
... ...
@@ -129,6 +313,13 @@ func (m *SolveRequest) GetImportCacheRefs() []string {
129 129
 	return nil
130 130
 }
131 131
 
132
+func (m *SolveRequest) GetAllowResultReturn() bool {
133
+	if m != nil {
134
+		return m.AllowResultReturn
135
+	}
136
+	return false
137
+}
138
+
132 139
 func (m *SolveRequest) GetFinal() bool {
133 140
 	if m != nil {
134 141
 		return m.Final
... ...
@@ -144,14 +335,16 @@ func (m *SolveRequest) GetExporterAttr() []byte {
144 144
 }
145 145
 
146 146
 type SolveResponse struct {
147
-	Ref          string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
148
-	ExporterAttr []byte `protobuf:"bytes,2,opt,name=ExporterAttr,proto3" json:"ExporterAttr,omitempty"`
147
+	// deprecated
148
+	Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
149
+	// these fields are returned when allowMapReturn was set
150
+	Result *Result `protobuf:"bytes,3,opt,name=result" json:"result,omitempty"`
149 151
 }
150 152
 
151 153
 func (m *SolveResponse) Reset()                    { *m = SolveResponse{} }
152 154
 func (m *SolveResponse) String() string            { return proto.CompactTextString(m) }
153 155
 func (*SolveResponse) ProtoMessage()               {}
154
-func (*SolveResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{3} }
156
+func (*SolveResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{7} }
155 157
 
156 158
 func (m *SolveResponse) GetRef() string {
157 159
 	if m != nil {
... ...
@@ -160,9 +353,9 @@ func (m *SolveResponse) GetRef() string {
160 160
 	return ""
161 161
 }
162 162
 
163
-func (m *SolveResponse) GetExporterAttr() []byte {
163
+func (m *SolveResponse) GetResult() *Result {
164 164
 	if m != nil {
165
-		return m.ExporterAttr
165
+		return m.Result
166 166
 	}
167 167
 	return nil
168 168
 }
... ...
@@ -176,7 +369,7 @@ type ReadFileRequest struct {
176 176
 func (m *ReadFileRequest) Reset()                    { *m = ReadFileRequest{} }
177 177
 func (m *ReadFileRequest) String() string            { return proto.CompactTextString(m) }
178 178
 func (*ReadFileRequest) ProtoMessage()               {}
179
-func (*ReadFileRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{4} }
179
+func (*ReadFileRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{8} }
180 180
 
181 181
 func (m *ReadFileRequest) GetRef() string {
182 182
 	if m != nil {
... ...
@@ -207,7 +400,7 @@ type FileRange struct {
207 207
 func (m *FileRange) Reset()                    { *m = FileRange{} }
208 208
 func (m *FileRange) String() string            { return proto.CompactTextString(m) }
209 209
 func (*FileRange) ProtoMessage()               {}
210
-func (*FileRange) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{5} }
210
+func (*FileRange) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{9} }
211 211
 
212 212
 func (m *FileRange) GetOffset() int64 {
213 213
 	if m != nil {
... ...
@@ -230,7 +423,7 @@ type ReadFileResponse struct {
230 230
 func (m *ReadFileResponse) Reset()                    { *m = ReadFileResponse{} }
231 231
 func (m *ReadFileResponse) String() string            { return proto.CompactTextString(m) }
232 232
 func (*ReadFileResponse) ProtoMessage()               {}
233
-func (*ReadFileResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{6} }
233
+func (*ReadFileResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{10} }
234 234
 
235 235
 func (m *ReadFileResponse) GetData() []byte {
236 236
 	if m != nil {
... ...
@@ -245,17 +438,45 @@ type PingRequest struct {
245 245
 func (m *PingRequest) Reset()                    { *m = PingRequest{} }
246 246
 func (m *PingRequest) String() string            { return proto.CompactTextString(m) }
247 247
 func (*PingRequest) ProtoMessage()               {}
248
-func (*PingRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{7} }
248
+func (*PingRequest) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{11} }
249 249
 
250 250
 type PongResponse struct {
251
+	FrontendAPICaps []moby_buildkit_v1_apicaps.APICap      `protobuf:"bytes,1,rep,name=FrontendAPICaps" json:"FrontendAPICaps"`
252
+	LLBCaps         []moby_buildkit_v1_apicaps.APICap      `protobuf:"bytes,2,rep,name=LLBCaps" json:"LLBCaps"`
253
+	Workers         []*moby_buildkit_v1_types.WorkerRecord `protobuf:"bytes,3,rep,name=Workers" json:"Workers,omitempty"`
251 254
 }
252 255
 
253 256
 func (m *PongResponse) Reset()                    { *m = PongResponse{} }
254 257
 func (m *PongResponse) String() string            { return proto.CompactTextString(m) }
255 258
 func (*PongResponse) ProtoMessage()               {}
256
-func (*PongResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{8} }
259
+func (*PongResponse) Descriptor() ([]byte, []int) { return fileDescriptorGateway, []int{12} }
260
+
261
+func (m *PongResponse) GetFrontendAPICaps() []moby_buildkit_v1_apicaps.APICap {
262
+	if m != nil {
263
+		return m.FrontendAPICaps
264
+	}
265
+	return nil
266
+}
267
+
268
+func (m *PongResponse) GetLLBCaps() []moby_buildkit_v1_apicaps.APICap {
269
+	if m != nil {
270
+		return m.LLBCaps
271
+	}
272
+	return nil
273
+}
274
+
275
+func (m *PongResponse) GetWorkers() []*moby_buildkit_v1_types.WorkerRecord {
276
+	if m != nil {
277
+		return m.Workers
278
+	}
279
+	return nil
280
+}
257 281
 
258 282
 func init() {
283
+	proto.RegisterType((*Result)(nil), "moby.buildkit.v1.frontend.Result")
284
+	proto.RegisterType((*RefMap)(nil), "moby.buildkit.v1.frontend.RefMap")
285
+	proto.RegisterType((*ReturnRequest)(nil), "moby.buildkit.v1.frontend.ReturnRequest")
286
+	proto.RegisterType((*ReturnResponse)(nil), "moby.buildkit.v1.frontend.ReturnResponse")
259 287
 	proto.RegisterType((*ResolveImageConfigRequest)(nil), "moby.buildkit.v1.frontend.ResolveImageConfigRequest")
260 288
 	proto.RegisterType((*ResolveImageConfigResponse)(nil), "moby.buildkit.v1.frontend.ResolveImageConfigResponse")
261 289
 	proto.RegisterType((*SolveRequest)(nil), "moby.buildkit.v1.frontend.SolveRequest")
... ...
@@ -278,10 +499,14 @@ const _ = grpc.SupportPackageIsVersion4
278 278
 // Client API for LLBBridge service
279 279
 
280 280
 type LLBBridgeClient interface {
281
+	// apicaps:CapResolveImage
281 282
 	ResolveImageConfig(ctx context.Context, in *ResolveImageConfigRequest, opts ...grpc.CallOption) (*ResolveImageConfigResponse, error)
283
+	// apicaps:CapSolveBase
282 284
 	Solve(ctx context.Context, in *SolveRequest, opts ...grpc.CallOption) (*SolveResponse, error)
285
+	// apicaps:CapReadFile
283 286
 	ReadFile(ctx context.Context, in *ReadFileRequest, opts ...grpc.CallOption) (*ReadFileResponse, error)
284 287
 	Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PongResponse, error)
288
+	Return(ctx context.Context, in *ReturnRequest, opts ...grpc.CallOption) (*ReturnResponse, error)
285 289
 }
286 290
 
287 291
 type lLBBridgeClient struct {
... ...
@@ -328,13 +553,26 @@ func (c *lLBBridgeClient) Ping(ctx context.Context, in *PingRequest, opts ...grp
328 328
 	return out, nil
329 329
 }
330 330
 
331
+func (c *lLBBridgeClient) Return(ctx context.Context, in *ReturnRequest, opts ...grpc.CallOption) (*ReturnResponse, error) {
332
+	out := new(ReturnResponse)
333
+	err := grpc.Invoke(ctx, "/moby.buildkit.v1.frontend.LLBBridge/Return", in, out, c.cc, opts...)
334
+	if err != nil {
335
+		return nil, err
336
+	}
337
+	return out, nil
338
+}
339
+
331 340
 // Server API for LLBBridge service
332 341
 
333 342
 type LLBBridgeServer interface {
343
+	// apicaps:CapResolveImage
334 344
 	ResolveImageConfig(context.Context, *ResolveImageConfigRequest) (*ResolveImageConfigResponse, error)
345
+	// apicaps:CapSolveBase
335 346
 	Solve(context.Context, *SolveRequest) (*SolveResponse, error)
347
+	// apicaps:CapReadFile
336 348
 	ReadFile(context.Context, *ReadFileRequest) (*ReadFileResponse, error)
337 349
 	Ping(context.Context, *PingRequest) (*PongResponse, error)
350
+	Return(context.Context, *ReturnRequest) (*ReturnResponse, error)
338 351
 }
339 352
 
340 353
 func RegisterLLBBridgeServer(s *grpc.Server, srv LLBBridgeServer) {
... ...
@@ -413,6 +651,24 @@ func _LLBBridge_Ping_Handler(srv interface{}, ctx context.Context, dec func(inte
413 413
 	return interceptor(ctx, in, info, handler)
414 414
 }
415 415
 
416
+func _LLBBridge_Return_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
417
+	in := new(ReturnRequest)
418
+	if err := dec(in); err != nil {
419
+		return nil, err
420
+	}
421
+	if interceptor == nil {
422
+		return srv.(LLBBridgeServer).Return(ctx, in)
423
+	}
424
+	info := &grpc.UnaryServerInfo{
425
+		Server:     srv,
426
+		FullMethod: "/moby.buildkit.v1.frontend.LLBBridge/Return",
427
+	}
428
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
429
+		return srv.(LLBBridgeServer).Return(ctx, req.(*ReturnRequest))
430
+	}
431
+	return interceptor(ctx, in, info, handler)
432
+}
433
+
416 434
 var _LLBBridge_serviceDesc = grpc.ServiceDesc{
417 435
 	ServiceName: "moby.buildkit.v1.frontend.LLBBridge",
418 436
 	HandlerType: (*LLBBridgeServer)(nil),
... ...
@@ -433,11 +689,176 @@ var _LLBBridge_serviceDesc = grpc.ServiceDesc{
433 433
 			MethodName: "Ping",
434 434
 			Handler:    _LLBBridge_Ping_Handler,
435 435
 		},
436
+		{
437
+			MethodName: "Return",
438
+			Handler:    _LLBBridge_Return_Handler,
439
+		},
436 440
 	},
437 441
 	Streams:  []grpc.StreamDesc{},
438 442
 	Metadata: "gateway.proto",
439 443
 }
440 444
 
445
+func (m *Result) Marshal() (dAtA []byte, err error) {
446
+	size := m.Size()
447
+	dAtA = make([]byte, size)
448
+	n, err := m.MarshalTo(dAtA)
449
+	if err != nil {
450
+		return nil, err
451
+	}
452
+	return dAtA[:n], nil
453
+}
454
+
455
+func (m *Result) MarshalTo(dAtA []byte) (int, error) {
456
+	var i int
457
+	_ = i
458
+	var l int
459
+	_ = l
460
+	if m.Result != nil {
461
+		nn1, err := m.Result.MarshalTo(dAtA[i:])
462
+		if err != nil {
463
+			return 0, err
464
+		}
465
+		i += nn1
466
+	}
467
+	if len(m.Metadata) > 0 {
468
+		for k, _ := range m.Metadata {
469
+			dAtA[i] = 0x52
470
+			i++
471
+			v := m.Metadata[k]
472
+			byteSize := 0
473
+			if len(v) > 0 {
474
+				byteSize = 1 + len(v) + sovGateway(uint64(len(v)))
475
+			}
476
+			mapSize := 1 + len(k) + sovGateway(uint64(len(k))) + byteSize
477
+			i = encodeVarintGateway(dAtA, i, uint64(mapSize))
478
+			dAtA[i] = 0xa
479
+			i++
480
+			i = encodeVarintGateway(dAtA, i, uint64(len(k)))
481
+			i += copy(dAtA[i:], k)
482
+			if len(v) > 0 {
483
+				dAtA[i] = 0x12
484
+				i++
485
+				i = encodeVarintGateway(dAtA, i, uint64(len(v)))
486
+				i += copy(dAtA[i:], v)
487
+			}
488
+		}
489
+	}
490
+	return i, nil
491
+}
492
+
493
+func (m *Result_Ref) MarshalTo(dAtA []byte) (int, error) {
494
+	i := 0
495
+	dAtA[i] = 0xa
496
+	i++
497
+	i = encodeVarintGateway(dAtA, i, uint64(len(m.Ref)))
498
+	i += copy(dAtA[i:], m.Ref)
499
+	return i, nil
500
+}
501
+func (m *Result_Refs) MarshalTo(dAtA []byte) (int, error) {
502
+	i := 0
503
+	if m.Refs != nil {
504
+		dAtA[i] = 0x12
505
+		i++
506
+		i = encodeVarintGateway(dAtA, i, uint64(m.Refs.Size()))
507
+		n2, err := m.Refs.MarshalTo(dAtA[i:])
508
+		if err != nil {
509
+			return 0, err
510
+		}
511
+		i += n2
512
+	}
513
+	return i, nil
514
+}
515
+func (m *RefMap) Marshal() (dAtA []byte, err error) {
516
+	size := m.Size()
517
+	dAtA = make([]byte, size)
518
+	n, err := m.MarshalTo(dAtA)
519
+	if err != nil {
520
+		return nil, err
521
+	}
522
+	return dAtA[:n], nil
523
+}
524
+
525
+func (m *RefMap) MarshalTo(dAtA []byte) (int, error) {
526
+	var i int
527
+	_ = i
528
+	var l int
529
+	_ = l
530
+	if len(m.Refs) > 0 {
531
+		for k, _ := range m.Refs {
532
+			dAtA[i] = 0xa
533
+			i++
534
+			v := m.Refs[k]
535
+			mapSize := 1 + len(k) + sovGateway(uint64(len(k))) + 1 + len(v) + sovGateway(uint64(len(v)))
536
+			i = encodeVarintGateway(dAtA, i, uint64(mapSize))
537
+			dAtA[i] = 0xa
538
+			i++
539
+			i = encodeVarintGateway(dAtA, i, uint64(len(k)))
540
+			i += copy(dAtA[i:], k)
541
+			dAtA[i] = 0x12
542
+			i++
543
+			i = encodeVarintGateway(dAtA, i, uint64(len(v)))
544
+			i += copy(dAtA[i:], v)
545
+		}
546
+	}
547
+	return i, nil
548
+}
549
+
550
+func (m *ReturnRequest) Marshal() (dAtA []byte, err error) {
551
+	size := m.Size()
552
+	dAtA = make([]byte, size)
553
+	n, err := m.MarshalTo(dAtA)
554
+	if err != nil {
555
+		return nil, err
556
+	}
557
+	return dAtA[:n], nil
558
+}
559
+
560
+func (m *ReturnRequest) MarshalTo(dAtA []byte) (int, error) {
561
+	var i int
562
+	_ = i
563
+	var l int
564
+	_ = l
565
+	if m.Result != nil {
566
+		dAtA[i] = 0xa
567
+		i++
568
+		i = encodeVarintGateway(dAtA, i, uint64(m.Result.Size()))
569
+		n3, err := m.Result.MarshalTo(dAtA[i:])
570
+		if err != nil {
571
+			return 0, err
572
+		}
573
+		i += n3
574
+	}
575
+	if m.Error != nil {
576
+		dAtA[i] = 0x12
577
+		i++
578
+		i = encodeVarintGateway(dAtA, i, uint64(m.Error.Size()))
579
+		n4, err := m.Error.MarshalTo(dAtA[i:])
580
+		if err != nil {
581
+			return 0, err
582
+		}
583
+		i += n4
584
+	}
585
+	return i, nil
586
+}
587
+
588
+func (m *ReturnResponse) Marshal() (dAtA []byte, err error) {
589
+	size := m.Size()
590
+	dAtA = make([]byte, size)
591
+	n, err := m.MarshalTo(dAtA)
592
+	if err != nil {
593
+		return nil, err
594
+	}
595
+	return dAtA[:n], nil
596
+}
597
+
598
+func (m *ReturnResponse) MarshalTo(dAtA []byte) (int, error) {
599
+	var i int
600
+	_ = i
601
+	var l int
602
+	_ = l
603
+	return i, nil
604
+}
605
+
441 606
 func (m *ResolveImageConfigRequest) Marshal() (dAtA []byte, err error) {
442 607
 	size := m.Size()
443 608
 	dAtA = make([]byte, size)
... ...
@@ -463,11 +884,11 @@ func (m *ResolveImageConfigRequest) MarshalTo(dAtA []byte) (int, error) {
463 463
 		dAtA[i] = 0x12
464 464
 		i++
465 465
 		i = encodeVarintGateway(dAtA, i, uint64(m.Platform.Size()))
466
-		n1, err := m.Platform.MarshalTo(dAtA[i:])
466
+		n5, err := m.Platform.MarshalTo(dAtA[i:])
467 467
 		if err != nil {
468 468
 			return 0, err
469 469
 		}
470
-		i += n1
470
+		i += n5
471 471
 	}
472 472
 	return i, nil
473 473
 }
... ...
@@ -521,11 +942,11 @@ func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) {
521 521
 		dAtA[i] = 0xa
522 522
 		i++
523 523
 		i = encodeVarintGateway(dAtA, i, uint64(m.Definition.Size()))
524
-		n2, err := m.Definition.MarshalTo(dAtA[i:])
524
+		n6, err := m.Definition.MarshalTo(dAtA[i:])
525 525
 		if err != nil {
526 526
 			return 0, err
527 527
 		}
528
-		i += n2
528
+		i += n6
529 529
 	}
530 530
 	if len(m.Frontend) > 0 {
531 531
 		dAtA[i] = 0x12
... ...
@@ -565,6 +986,16 @@ func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) {
565 565
 			i += copy(dAtA[i:], s)
566 566
 		}
567 567
 	}
568
+	if m.AllowResultReturn {
569
+		dAtA[i] = 0x28
570
+		i++
571
+		if m.AllowResultReturn {
572
+			dAtA[i] = 1
573
+		} else {
574
+			dAtA[i] = 0
575
+		}
576
+		i++
577
+	}
568 578
 	if m.Final {
569 579
 		dAtA[i] = 0x50
570 580
 		i++
... ...
@@ -605,11 +1036,15 @@ func (m *SolveResponse) MarshalTo(dAtA []byte) (int, error) {
605 605
 		i = encodeVarintGateway(dAtA, i, uint64(len(m.Ref)))
606 606
 		i += copy(dAtA[i:], m.Ref)
607 607
 	}
608
-	if len(m.ExporterAttr) > 0 {
609
-		dAtA[i] = 0x12
608
+	if m.Result != nil {
609
+		dAtA[i] = 0x1a
610 610
 		i++
611
-		i = encodeVarintGateway(dAtA, i, uint64(len(m.ExporterAttr)))
612
-		i += copy(dAtA[i:], m.ExporterAttr)
611
+		i = encodeVarintGateway(dAtA, i, uint64(m.Result.Size()))
612
+		n7, err := m.Result.MarshalTo(dAtA[i:])
613
+		if err != nil {
614
+			return 0, err
615
+		}
616
+		i += n7
613 617
 	}
614 618
 	return i, nil
615 619
 }
... ...
@@ -645,11 +1080,11 @@ func (m *ReadFileRequest) MarshalTo(dAtA []byte) (int, error) {
645 645
 		dAtA[i] = 0x1a
646 646
 		i++
647 647
 		i = encodeVarintGateway(dAtA, i, uint64(m.Range.Size()))
648
-		n3, err := m.Range.MarshalTo(dAtA[i:])
648
+		n8, err := m.Range.MarshalTo(dAtA[i:])
649 649
 		if err != nil {
650 650
 			return 0, err
651 651
 		}
652
-		i += n3
652
+		i += n8
653 653
 	}
654 654
 	return i, nil
655 655
 }
... ...
@@ -739,6 +1174,42 @@ func (m *PongResponse) MarshalTo(dAtA []byte) (int, error) {
739 739
 	_ = i
740 740
 	var l int
741 741
 	_ = l
742
+	if len(m.FrontendAPICaps) > 0 {
743
+		for _, msg := range m.FrontendAPICaps {
744
+			dAtA[i] = 0xa
745
+			i++
746
+			i = encodeVarintGateway(dAtA, i, uint64(msg.Size()))
747
+			n, err := msg.MarshalTo(dAtA[i:])
748
+			if err != nil {
749
+				return 0, err
750
+			}
751
+			i += n
752
+		}
753
+	}
754
+	if len(m.LLBCaps) > 0 {
755
+		for _, msg := range m.LLBCaps {
756
+			dAtA[i] = 0x12
757
+			i++
758
+			i = encodeVarintGateway(dAtA, i, uint64(msg.Size()))
759
+			n, err := msg.MarshalTo(dAtA[i:])
760
+			if err != nil {
761
+				return 0, err
762
+			}
763
+			i += n
764
+		}
765
+	}
766
+	if len(m.Workers) > 0 {
767
+		for _, msg := range m.Workers {
768
+			dAtA[i] = 0x1a
769
+			i++
770
+			i = encodeVarintGateway(dAtA, i, uint64(msg.Size()))
771
+			n, err := msg.MarshalTo(dAtA[i:])
772
+			if err != nil {
773
+				return 0, err
774
+			}
775
+			i += n
776
+		}
777
+	}
742 778
 	return i, nil
743 779
 }
744 780
 
... ...
@@ -751,6 +1222,77 @@ func encodeVarintGateway(dAtA []byte, offset int, v uint64) int {
751 751
 	dAtA[offset] = uint8(v)
752 752
 	return offset + 1
753 753
 }
754
+func (m *Result) Size() (n int) {
755
+	var l int
756
+	_ = l
757
+	if m.Result != nil {
758
+		n += m.Result.Size()
759
+	}
760
+	if len(m.Metadata) > 0 {
761
+		for k, v := range m.Metadata {
762
+			_ = k
763
+			_ = v
764
+			l = 0
765
+			if len(v) > 0 {
766
+				l = 1 + len(v) + sovGateway(uint64(len(v)))
767
+			}
768
+			mapEntrySize := 1 + len(k) + sovGateway(uint64(len(k))) + l
769
+			n += mapEntrySize + 1 + sovGateway(uint64(mapEntrySize))
770
+		}
771
+	}
772
+	return n
773
+}
774
+
775
+func (m *Result_Ref) Size() (n int) {
776
+	var l int
777
+	_ = l
778
+	l = len(m.Ref)
779
+	n += 1 + l + sovGateway(uint64(l))
780
+	return n
781
+}
782
+func (m *Result_Refs) Size() (n int) {
783
+	var l int
784
+	_ = l
785
+	if m.Refs != nil {
786
+		l = m.Refs.Size()
787
+		n += 1 + l + sovGateway(uint64(l))
788
+	}
789
+	return n
790
+}
791
+func (m *RefMap) Size() (n int) {
792
+	var l int
793
+	_ = l
794
+	if len(m.Refs) > 0 {
795
+		for k, v := range m.Refs {
796
+			_ = k
797
+			_ = v
798
+			mapEntrySize := 1 + len(k) + sovGateway(uint64(len(k))) + 1 + len(v) + sovGateway(uint64(len(v)))
799
+			n += mapEntrySize + 1 + sovGateway(uint64(mapEntrySize))
800
+		}
801
+	}
802
+	return n
803
+}
804
+
805
+func (m *ReturnRequest) Size() (n int) {
806
+	var l int
807
+	_ = l
808
+	if m.Result != nil {
809
+		l = m.Result.Size()
810
+		n += 1 + l + sovGateway(uint64(l))
811
+	}
812
+	if m.Error != nil {
813
+		l = m.Error.Size()
814
+		n += 1 + l + sovGateway(uint64(l))
815
+	}
816
+	return n
817
+}
818
+
819
+func (m *ReturnResponse) Size() (n int) {
820
+	var l int
821
+	_ = l
822
+	return n
823
+}
824
+
754 825
 func (m *ResolveImageConfigRequest) Size() (n int) {
755 826
 	var l int
756 827
 	_ = l
... ...
@@ -804,6 +1346,9 @@ func (m *SolveRequest) Size() (n int) {
804 804
 			n += 1 + l + sovGateway(uint64(l))
805 805
 		}
806 806
 	}
807
+	if m.AllowResultReturn {
808
+		n += 2
809
+	}
807 810
 	if m.Final {
808 811
 		n += 2
809 812
 	}
... ...
@@ -821,8 +1366,8 @@ func (m *SolveResponse) Size() (n int) {
821 821
 	if l > 0 {
822 822
 		n += 1 + l + sovGateway(uint64(l))
823 823
 	}
824
-	l = len(m.ExporterAttr)
825
-	if l > 0 {
824
+	if m.Result != nil {
825
+		l = m.Result.Size()
826 826
 		n += 1 + l + sovGateway(uint64(l))
827 827
 	}
828 828
 	return n
... ...
@@ -877,6 +1422,24 @@ func (m *PingRequest) Size() (n int) {
877 877
 func (m *PongResponse) Size() (n int) {
878 878
 	var l int
879 879
 	_ = l
880
+	if len(m.FrontendAPICaps) > 0 {
881
+		for _, e := range m.FrontendAPICaps {
882
+			l = e.Size()
883
+			n += 1 + l + sovGateway(uint64(l))
884
+		}
885
+	}
886
+	if len(m.LLBCaps) > 0 {
887
+		for _, e := range m.LLBCaps {
888
+			l = e.Size()
889
+			n += 1 + l + sovGateway(uint64(l))
890
+		}
891
+	}
892
+	if len(m.Workers) > 0 {
893
+		for _, e := range m.Workers {
894
+			l = e.Size()
895
+			n += 1 + l + sovGateway(uint64(l))
896
+		}
897
+	}
880 898
 	return n
881 899
 }
882 900
 
... ...
@@ -893,6 +1456,570 @@ func sovGateway(x uint64) (n int) {
893 893
 func sozGateway(x uint64) (n int) {
894 894
 	return sovGateway(uint64((x << 1) ^ uint64((int64(x) >> 63))))
895 895
 }
896
+func (m *Result) Unmarshal(dAtA []byte) error {
897
+	l := len(dAtA)
898
+	iNdEx := 0
899
+	for iNdEx < l {
900
+		preIndex := iNdEx
901
+		var wire uint64
902
+		for shift := uint(0); ; shift += 7 {
903
+			if shift >= 64 {
904
+				return ErrIntOverflowGateway
905
+			}
906
+			if iNdEx >= l {
907
+				return io.ErrUnexpectedEOF
908
+			}
909
+			b := dAtA[iNdEx]
910
+			iNdEx++
911
+			wire |= (uint64(b) & 0x7F) << shift
912
+			if b < 0x80 {
913
+				break
914
+			}
915
+		}
916
+		fieldNum := int32(wire >> 3)
917
+		wireType := int(wire & 0x7)
918
+		if wireType == 4 {
919
+			return fmt.Errorf("proto: Result: wiretype end group for non-group")
920
+		}
921
+		if fieldNum <= 0 {
922
+			return fmt.Errorf("proto: Result: illegal tag %d (wire type %d)", fieldNum, wire)
923
+		}
924
+		switch fieldNum {
925
+		case 1:
926
+			if wireType != 2 {
927
+				return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
928
+			}
929
+			var stringLen uint64
930
+			for shift := uint(0); ; shift += 7 {
931
+				if shift >= 64 {
932
+					return ErrIntOverflowGateway
933
+				}
934
+				if iNdEx >= l {
935
+					return io.ErrUnexpectedEOF
936
+				}
937
+				b := dAtA[iNdEx]
938
+				iNdEx++
939
+				stringLen |= (uint64(b) & 0x7F) << shift
940
+				if b < 0x80 {
941
+					break
942
+				}
943
+			}
944
+			intStringLen := int(stringLen)
945
+			if intStringLen < 0 {
946
+				return ErrInvalidLengthGateway
947
+			}
948
+			postIndex := iNdEx + intStringLen
949
+			if postIndex > l {
950
+				return io.ErrUnexpectedEOF
951
+			}
952
+			m.Result = &Result_Ref{string(dAtA[iNdEx:postIndex])}
953
+			iNdEx = postIndex
954
+		case 2:
955
+			if wireType != 2 {
956
+				return fmt.Errorf("proto: wrong wireType = %d for field Refs", wireType)
957
+			}
958
+			var msglen int
959
+			for shift := uint(0); ; shift += 7 {
960
+				if shift >= 64 {
961
+					return ErrIntOverflowGateway
962
+				}
963
+				if iNdEx >= l {
964
+					return io.ErrUnexpectedEOF
965
+				}
966
+				b := dAtA[iNdEx]
967
+				iNdEx++
968
+				msglen |= (int(b) & 0x7F) << shift
969
+				if b < 0x80 {
970
+					break
971
+				}
972
+			}
973
+			if msglen < 0 {
974
+				return ErrInvalidLengthGateway
975
+			}
976
+			postIndex := iNdEx + msglen
977
+			if postIndex > l {
978
+				return io.ErrUnexpectedEOF
979
+			}
980
+			v := &RefMap{}
981
+			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
982
+				return err
983
+			}
984
+			m.Result = &Result_Refs{v}
985
+			iNdEx = postIndex
986
+		case 10:
987
+			if wireType != 2 {
988
+				return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType)
989
+			}
990
+			var msglen int
991
+			for shift := uint(0); ; shift += 7 {
992
+				if shift >= 64 {
993
+					return ErrIntOverflowGateway
994
+				}
995
+				if iNdEx >= l {
996
+					return io.ErrUnexpectedEOF
997
+				}
998
+				b := dAtA[iNdEx]
999
+				iNdEx++
1000
+				msglen |= (int(b) & 0x7F) << shift
1001
+				if b < 0x80 {
1002
+					break
1003
+				}
1004
+			}
1005
+			if msglen < 0 {
1006
+				return ErrInvalidLengthGateway
1007
+			}
1008
+			postIndex := iNdEx + msglen
1009
+			if postIndex > l {
1010
+				return io.ErrUnexpectedEOF
1011
+			}
1012
+			if m.Metadata == nil {
1013
+				m.Metadata = make(map[string][]byte)
1014
+			}
1015
+			var mapkey string
1016
+			mapvalue := []byte{}
1017
+			for iNdEx < postIndex {
1018
+				entryPreIndex := iNdEx
1019
+				var wire uint64
1020
+				for shift := uint(0); ; shift += 7 {
1021
+					if shift >= 64 {
1022
+						return ErrIntOverflowGateway
1023
+					}
1024
+					if iNdEx >= l {
1025
+						return io.ErrUnexpectedEOF
1026
+					}
1027
+					b := dAtA[iNdEx]
1028
+					iNdEx++
1029
+					wire |= (uint64(b) & 0x7F) << shift
1030
+					if b < 0x80 {
1031
+						break
1032
+					}
1033
+				}
1034
+				fieldNum := int32(wire >> 3)
1035
+				if fieldNum == 1 {
1036
+					var stringLenmapkey uint64
1037
+					for shift := uint(0); ; shift += 7 {
1038
+						if shift >= 64 {
1039
+							return ErrIntOverflowGateway
1040
+						}
1041
+						if iNdEx >= l {
1042
+							return io.ErrUnexpectedEOF
1043
+						}
1044
+						b := dAtA[iNdEx]
1045
+						iNdEx++
1046
+						stringLenmapkey |= (uint64(b) & 0x7F) << shift
1047
+						if b < 0x80 {
1048
+							break
1049
+						}
1050
+					}
1051
+					intStringLenmapkey := int(stringLenmapkey)
1052
+					if intStringLenmapkey < 0 {
1053
+						return ErrInvalidLengthGateway
1054
+					}
1055
+					postStringIndexmapkey := iNdEx + intStringLenmapkey
1056
+					if postStringIndexmapkey > l {
1057
+						return io.ErrUnexpectedEOF
1058
+					}
1059
+					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
1060
+					iNdEx = postStringIndexmapkey
1061
+				} else if fieldNum == 2 {
1062
+					var mapbyteLen uint64
1063
+					for shift := uint(0); ; shift += 7 {
1064
+						if shift >= 64 {
1065
+							return ErrIntOverflowGateway
1066
+						}
1067
+						if iNdEx >= l {
1068
+							return io.ErrUnexpectedEOF
1069
+						}
1070
+						b := dAtA[iNdEx]
1071
+						iNdEx++
1072
+						mapbyteLen |= (uint64(b) & 0x7F) << shift
1073
+						if b < 0x80 {
1074
+							break
1075
+						}
1076
+					}
1077
+					intMapbyteLen := int(mapbyteLen)
1078
+					if intMapbyteLen < 0 {
1079
+						return ErrInvalidLengthGateway
1080
+					}
1081
+					postbytesIndex := iNdEx + intMapbyteLen
1082
+					if postbytesIndex > l {
1083
+						return io.ErrUnexpectedEOF
1084
+					}
1085
+					mapvalue = make([]byte, mapbyteLen)
1086
+					copy(mapvalue, dAtA[iNdEx:postbytesIndex])
1087
+					iNdEx = postbytesIndex
1088
+				} else {
1089
+					iNdEx = entryPreIndex
1090
+					skippy, err := skipGateway(dAtA[iNdEx:])
1091
+					if err != nil {
1092
+						return err
1093
+					}
1094
+					if skippy < 0 {
1095
+						return ErrInvalidLengthGateway
1096
+					}
1097
+					if (iNdEx + skippy) > postIndex {
1098
+						return io.ErrUnexpectedEOF
1099
+					}
1100
+					iNdEx += skippy
1101
+				}
1102
+			}
1103
+			m.Metadata[mapkey] = mapvalue
1104
+			iNdEx = postIndex
1105
+		default:
1106
+			iNdEx = preIndex
1107
+			skippy, err := skipGateway(dAtA[iNdEx:])
1108
+			if err != nil {
1109
+				return err
1110
+			}
1111
+			if skippy < 0 {
1112
+				return ErrInvalidLengthGateway
1113
+			}
1114
+			if (iNdEx + skippy) > l {
1115
+				return io.ErrUnexpectedEOF
1116
+			}
1117
+			iNdEx += skippy
1118
+		}
1119
+	}
1120
+
1121
+	if iNdEx > l {
1122
+		return io.ErrUnexpectedEOF
1123
+	}
1124
+	return nil
1125
+}
1126
+func (m *RefMap) Unmarshal(dAtA []byte) error {
1127
+	l := len(dAtA)
1128
+	iNdEx := 0
1129
+	for iNdEx < l {
1130
+		preIndex := iNdEx
1131
+		var wire uint64
1132
+		for shift := uint(0); ; shift += 7 {
1133
+			if shift >= 64 {
1134
+				return ErrIntOverflowGateway
1135
+			}
1136
+			if iNdEx >= l {
1137
+				return io.ErrUnexpectedEOF
1138
+			}
1139
+			b := dAtA[iNdEx]
1140
+			iNdEx++
1141
+			wire |= (uint64(b) & 0x7F) << shift
1142
+			if b < 0x80 {
1143
+				break
1144
+			}
1145
+		}
1146
+		fieldNum := int32(wire >> 3)
1147
+		wireType := int(wire & 0x7)
1148
+		if wireType == 4 {
1149
+			return fmt.Errorf("proto: RefMap: wiretype end group for non-group")
1150
+		}
1151
+		if fieldNum <= 0 {
1152
+			return fmt.Errorf("proto: RefMap: illegal tag %d (wire type %d)", fieldNum, wire)
1153
+		}
1154
+		switch fieldNum {
1155
+		case 1:
1156
+			if wireType != 2 {
1157
+				return fmt.Errorf("proto: wrong wireType = %d for field Refs", wireType)
1158
+			}
1159
+			var msglen int
1160
+			for shift := uint(0); ; shift += 7 {
1161
+				if shift >= 64 {
1162
+					return ErrIntOverflowGateway
1163
+				}
1164
+				if iNdEx >= l {
1165
+					return io.ErrUnexpectedEOF
1166
+				}
1167
+				b := dAtA[iNdEx]
1168
+				iNdEx++
1169
+				msglen |= (int(b) & 0x7F) << shift
1170
+				if b < 0x80 {
1171
+					break
1172
+				}
1173
+			}
1174
+			if msglen < 0 {
1175
+				return ErrInvalidLengthGateway
1176
+			}
1177
+			postIndex := iNdEx + msglen
1178
+			if postIndex > l {
1179
+				return io.ErrUnexpectedEOF
1180
+			}
1181
+			if m.Refs == nil {
1182
+				m.Refs = make(map[string]string)
1183
+			}
1184
+			var mapkey string
1185
+			var mapvalue string
1186
+			for iNdEx < postIndex {
1187
+				entryPreIndex := iNdEx
1188
+				var wire uint64
1189
+				for shift := uint(0); ; shift += 7 {
1190
+					if shift >= 64 {
1191
+						return ErrIntOverflowGateway
1192
+					}
1193
+					if iNdEx >= l {
1194
+						return io.ErrUnexpectedEOF
1195
+					}
1196
+					b := dAtA[iNdEx]
1197
+					iNdEx++
1198
+					wire |= (uint64(b) & 0x7F) << shift
1199
+					if b < 0x80 {
1200
+						break
1201
+					}
1202
+				}
1203
+				fieldNum := int32(wire >> 3)
1204
+				if fieldNum == 1 {
1205
+					var stringLenmapkey uint64
1206
+					for shift := uint(0); ; shift += 7 {
1207
+						if shift >= 64 {
1208
+							return ErrIntOverflowGateway
1209
+						}
1210
+						if iNdEx >= l {
1211
+							return io.ErrUnexpectedEOF
1212
+						}
1213
+						b := dAtA[iNdEx]
1214
+						iNdEx++
1215
+						stringLenmapkey |= (uint64(b) & 0x7F) << shift
1216
+						if b < 0x80 {
1217
+							break
1218
+						}
1219
+					}
1220
+					intStringLenmapkey := int(stringLenmapkey)
1221
+					if intStringLenmapkey < 0 {
1222
+						return ErrInvalidLengthGateway
1223
+					}
1224
+					postStringIndexmapkey := iNdEx + intStringLenmapkey
1225
+					if postStringIndexmapkey > l {
1226
+						return io.ErrUnexpectedEOF
1227
+					}
1228
+					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
1229
+					iNdEx = postStringIndexmapkey
1230
+				} else if fieldNum == 2 {
1231
+					var stringLenmapvalue uint64
1232
+					for shift := uint(0); ; shift += 7 {
1233
+						if shift >= 64 {
1234
+							return ErrIntOverflowGateway
1235
+						}
1236
+						if iNdEx >= l {
1237
+							return io.ErrUnexpectedEOF
1238
+						}
1239
+						b := dAtA[iNdEx]
1240
+						iNdEx++
1241
+						stringLenmapvalue |= (uint64(b) & 0x7F) << shift
1242
+						if b < 0x80 {
1243
+							break
1244
+						}
1245
+					}
1246
+					intStringLenmapvalue := int(stringLenmapvalue)
1247
+					if intStringLenmapvalue < 0 {
1248
+						return ErrInvalidLengthGateway
1249
+					}
1250
+					postStringIndexmapvalue := iNdEx + intStringLenmapvalue
1251
+					if postStringIndexmapvalue > l {
1252
+						return io.ErrUnexpectedEOF
1253
+					}
1254
+					mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
1255
+					iNdEx = postStringIndexmapvalue
1256
+				} else {
1257
+					iNdEx = entryPreIndex
1258
+					skippy, err := skipGateway(dAtA[iNdEx:])
1259
+					if err != nil {
1260
+						return err
1261
+					}
1262
+					if skippy < 0 {
1263
+						return ErrInvalidLengthGateway
1264
+					}
1265
+					if (iNdEx + skippy) > postIndex {
1266
+						return io.ErrUnexpectedEOF
1267
+					}
1268
+					iNdEx += skippy
1269
+				}
1270
+			}
1271
+			m.Refs[mapkey] = mapvalue
1272
+			iNdEx = postIndex
1273
+		default:
1274
+			iNdEx = preIndex
1275
+			skippy, err := skipGateway(dAtA[iNdEx:])
1276
+			if err != nil {
1277
+				return err
1278
+			}
1279
+			if skippy < 0 {
1280
+				return ErrInvalidLengthGateway
1281
+			}
1282
+			if (iNdEx + skippy) > l {
1283
+				return io.ErrUnexpectedEOF
1284
+			}
1285
+			iNdEx += skippy
1286
+		}
1287
+	}
1288
+
1289
+	if iNdEx > l {
1290
+		return io.ErrUnexpectedEOF
1291
+	}
1292
+	return nil
1293
+}
1294
+func (m *ReturnRequest) Unmarshal(dAtA []byte) error {
1295
+	l := len(dAtA)
1296
+	iNdEx := 0
1297
+	for iNdEx < l {
1298
+		preIndex := iNdEx
1299
+		var wire uint64
1300
+		for shift := uint(0); ; shift += 7 {
1301
+			if shift >= 64 {
1302
+				return ErrIntOverflowGateway
1303
+			}
1304
+			if iNdEx >= l {
1305
+				return io.ErrUnexpectedEOF
1306
+			}
1307
+			b := dAtA[iNdEx]
1308
+			iNdEx++
1309
+			wire |= (uint64(b) & 0x7F) << shift
1310
+			if b < 0x80 {
1311
+				break
1312
+			}
1313
+		}
1314
+		fieldNum := int32(wire >> 3)
1315
+		wireType := int(wire & 0x7)
1316
+		if wireType == 4 {
1317
+			return fmt.Errorf("proto: ReturnRequest: wiretype end group for non-group")
1318
+		}
1319
+		if fieldNum <= 0 {
1320
+			return fmt.Errorf("proto: ReturnRequest: illegal tag %d (wire type %d)", fieldNum, wire)
1321
+		}
1322
+		switch fieldNum {
1323
+		case 1:
1324
+			if wireType != 2 {
1325
+				return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType)
1326
+			}
1327
+			var msglen int
1328
+			for shift := uint(0); ; shift += 7 {
1329
+				if shift >= 64 {
1330
+					return ErrIntOverflowGateway
1331
+				}
1332
+				if iNdEx >= l {
1333
+					return io.ErrUnexpectedEOF
1334
+				}
1335
+				b := dAtA[iNdEx]
1336
+				iNdEx++
1337
+				msglen |= (int(b) & 0x7F) << shift
1338
+				if b < 0x80 {
1339
+					break
1340
+				}
1341
+			}
1342
+			if msglen < 0 {
1343
+				return ErrInvalidLengthGateway
1344
+			}
1345
+			postIndex := iNdEx + msglen
1346
+			if postIndex > l {
1347
+				return io.ErrUnexpectedEOF
1348
+			}
1349
+			if m.Result == nil {
1350
+				m.Result = &Result{}
1351
+			}
1352
+			if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1353
+				return err
1354
+			}
1355
+			iNdEx = postIndex
1356
+		case 2:
1357
+			if wireType != 2 {
1358
+				return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType)
1359
+			}
1360
+			var msglen int
1361
+			for shift := uint(0); ; shift += 7 {
1362
+				if shift >= 64 {
1363
+					return ErrIntOverflowGateway
1364
+				}
1365
+				if iNdEx >= l {
1366
+					return io.ErrUnexpectedEOF
1367
+				}
1368
+				b := dAtA[iNdEx]
1369
+				iNdEx++
1370
+				msglen |= (int(b) & 0x7F) << shift
1371
+				if b < 0x80 {
1372
+					break
1373
+				}
1374
+			}
1375
+			if msglen < 0 {
1376
+				return ErrInvalidLengthGateway
1377
+			}
1378
+			postIndex := iNdEx + msglen
1379
+			if postIndex > l {
1380
+				return io.ErrUnexpectedEOF
1381
+			}
1382
+			if m.Error == nil {
1383
+				m.Error = &google_rpc.Status{}
1384
+			}
1385
+			if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1386
+				return err
1387
+			}
1388
+			iNdEx = postIndex
1389
+		default:
1390
+			iNdEx = preIndex
1391
+			skippy, err := skipGateway(dAtA[iNdEx:])
1392
+			if err != nil {
1393
+				return err
1394
+			}
1395
+			if skippy < 0 {
1396
+				return ErrInvalidLengthGateway
1397
+			}
1398
+			if (iNdEx + skippy) > l {
1399
+				return io.ErrUnexpectedEOF
1400
+			}
1401
+			iNdEx += skippy
1402
+		}
1403
+	}
1404
+
1405
+	if iNdEx > l {
1406
+		return io.ErrUnexpectedEOF
1407
+	}
1408
+	return nil
1409
+}
1410
+func (m *ReturnResponse) Unmarshal(dAtA []byte) error {
1411
+	l := len(dAtA)
1412
+	iNdEx := 0
1413
+	for iNdEx < l {
1414
+		preIndex := iNdEx
1415
+		var wire uint64
1416
+		for shift := uint(0); ; shift += 7 {
1417
+			if shift >= 64 {
1418
+				return ErrIntOverflowGateway
1419
+			}
1420
+			if iNdEx >= l {
1421
+				return io.ErrUnexpectedEOF
1422
+			}
1423
+			b := dAtA[iNdEx]
1424
+			iNdEx++
1425
+			wire |= (uint64(b) & 0x7F) << shift
1426
+			if b < 0x80 {
1427
+				break
1428
+			}
1429
+		}
1430
+		fieldNum := int32(wire >> 3)
1431
+		wireType := int(wire & 0x7)
1432
+		if wireType == 4 {
1433
+			return fmt.Errorf("proto: ReturnResponse: wiretype end group for non-group")
1434
+		}
1435
+		if fieldNum <= 0 {
1436
+			return fmt.Errorf("proto: ReturnResponse: illegal tag %d (wire type %d)", fieldNum, wire)
1437
+		}
1438
+		switch fieldNum {
1439
+		default:
1440
+			iNdEx = preIndex
1441
+			skippy, err := skipGateway(dAtA[iNdEx:])
1442
+			if err != nil {
1443
+				return err
1444
+			}
1445
+			if skippy < 0 {
1446
+				return ErrInvalidLengthGateway
1447
+			}
1448
+			if (iNdEx + skippy) > l {
1449
+				return io.ErrUnexpectedEOF
1450
+			}
1451
+			iNdEx += skippy
1452
+		}
1453
+	}
1454
+
1455
+	if iNdEx > l {
1456
+		return io.ErrUnexpectedEOF
1457
+	}
1458
+	return nil
1459
+}
896 1460
 func (m *ResolveImageConfigRequest) Unmarshal(dAtA []byte) error {
897 1461
 	l := len(dAtA)
898 1462
 	iNdEx := 0
... ...
@@ -1353,6 +2480,26 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error {
1353 1353
 			}
1354 1354
 			m.ImportCacheRefs = append(m.ImportCacheRefs, string(dAtA[iNdEx:postIndex]))
1355 1355
 			iNdEx = postIndex
1356
+		case 5:
1357
+			if wireType != 0 {
1358
+				return fmt.Errorf("proto: wrong wireType = %d for field AllowResultReturn", wireType)
1359
+			}
1360
+			var v int
1361
+			for shift := uint(0); ; shift += 7 {
1362
+				if shift >= 64 {
1363
+					return ErrIntOverflowGateway
1364
+				}
1365
+				if iNdEx >= l {
1366
+					return io.ErrUnexpectedEOF
1367
+				}
1368
+				b := dAtA[iNdEx]
1369
+				iNdEx++
1370
+				v |= (int(b) & 0x7F) << shift
1371
+				if b < 0x80 {
1372
+					break
1373
+				}
1374
+			}
1375
+			m.AllowResultReturn = bool(v != 0)
1356 1376
 		case 10:
1357 1377
 			if wireType != 0 {
1358 1378
 				return fmt.Errorf("proto: wrong wireType = %d for field Final", wireType)
... ...
@@ -1483,11 +2630,11 @@ func (m *SolveResponse) Unmarshal(dAtA []byte) error {
1483 1483
 			}
1484 1484
 			m.Ref = string(dAtA[iNdEx:postIndex])
1485 1485
 			iNdEx = postIndex
1486
-		case 2:
1486
+		case 3:
1487 1487
 			if wireType != 2 {
1488
-				return fmt.Errorf("proto: wrong wireType = %d for field ExporterAttr", wireType)
1488
+				return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType)
1489 1489
 			}
1490
-			var byteLen int
1490
+			var msglen int
1491 1491
 			for shift := uint(0); ; shift += 7 {
1492 1492
 				if shift >= 64 {
1493 1493
 					return ErrIntOverflowGateway
... ...
@@ -1497,21 +2644,23 @@ func (m *SolveResponse) Unmarshal(dAtA []byte) error {
1497 1497
 				}
1498 1498
 				b := dAtA[iNdEx]
1499 1499
 				iNdEx++
1500
-				byteLen |= (int(b) & 0x7F) << shift
1500
+				msglen |= (int(b) & 0x7F) << shift
1501 1501
 				if b < 0x80 {
1502 1502
 					break
1503 1503
 				}
1504 1504
 			}
1505
-			if byteLen < 0 {
1505
+			if msglen < 0 {
1506 1506
 				return ErrInvalidLengthGateway
1507 1507
 			}
1508
-			postIndex := iNdEx + byteLen
1508
+			postIndex := iNdEx + msglen
1509 1509
 			if postIndex > l {
1510 1510
 				return io.ErrUnexpectedEOF
1511 1511
 			}
1512
-			m.ExporterAttr = append(m.ExporterAttr[:0], dAtA[iNdEx:postIndex]...)
1513
-			if m.ExporterAttr == nil {
1514
-				m.ExporterAttr = []byte{}
1512
+			if m.Result == nil {
1513
+				m.Result = &Result{}
1514
+			}
1515
+			if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1516
+				return err
1515 1517
 			}
1516 1518
 			iNdEx = postIndex
1517 1519
 		default:
... ...
@@ -1924,6 +3073,99 @@ func (m *PongResponse) Unmarshal(dAtA []byte) error {
1924 1924
 			return fmt.Errorf("proto: PongResponse: illegal tag %d (wire type %d)", fieldNum, wire)
1925 1925
 		}
1926 1926
 		switch fieldNum {
1927
+		case 1:
1928
+			if wireType != 2 {
1929
+				return fmt.Errorf("proto: wrong wireType = %d for field FrontendAPICaps", wireType)
1930
+			}
1931
+			var msglen int
1932
+			for shift := uint(0); ; shift += 7 {
1933
+				if shift >= 64 {
1934
+					return ErrIntOverflowGateway
1935
+				}
1936
+				if iNdEx >= l {
1937
+					return io.ErrUnexpectedEOF
1938
+				}
1939
+				b := dAtA[iNdEx]
1940
+				iNdEx++
1941
+				msglen |= (int(b) & 0x7F) << shift
1942
+				if b < 0x80 {
1943
+					break
1944
+				}
1945
+			}
1946
+			if msglen < 0 {
1947
+				return ErrInvalidLengthGateway
1948
+			}
1949
+			postIndex := iNdEx + msglen
1950
+			if postIndex > l {
1951
+				return io.ErrUnexpectedEOF
1952
+			}
1953
+			m.FrontendAPICaps = append(m.FrontendAPICaps, moby_buildkit_v1_apicaps.APICap{})
1954
+			if err := m.FrontendAPICaps[len(m.FrontendAPICaps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1955
+				return err
1956
+			}
1957
+			iNdEx = postIndex
1958
+		case 2:
1959
+			if wireType != 2 {
1960
+				return fmt.Errorf("proto: wrong wireType = %d for field LLBCaps", wireType)
1961
+			}
1962
+			var msglen int
1963
+			for shift := uint(0); ; shift += 7 {
1964
+				if shift >= 64 {
1965
+					return ErrIntOverflowGateway
1966
+				}
1967
+				if iNdEx >= l {
1968
+					return io.ErrUnexpectedEOF
1969
+				}
1970
+				b := dAtA[iNdEx]
1971
+				iNdEx++
1972
+				msglen |= (int(b) & 0x7F) << shift
1973
+				if b < 0x80 {
1974
+					break
1975
+				}
1976
+			}
1977
+			if msglen < 0 {
1978
+				return ErrInvalidLengthGateway
1979
+			}
1980
+			postIndex := iNdEx + msglen
1981
+			if postIndex > l {
1982
+				return io.ErrUnexpectedEOF
1983
+			}
1984
+			m.LLBCaps = append(m.LLBCaps, moby_buildkit_v1_apicaps.APICap{})
1985
+			if err := m.LLBCaps[len(m.LLBCaps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1986
+				return err
1987
+			}
1988
+			iNdEx = postIndex
1989
+		case 3:
1990
+			if wireType != 2 {
1991
+				return fmt.Errorf("proto: wrong wireType = %d for field Workers", wireType)
1992
+			}
1993
+			var msglen int
1994
+			for shift := uint(0); ; shift += 7 {
1995
+				if shift >= 64 {
1996
+					return ErrIntOverflowGateway
1997
+				}
1998
+				if iNdEx >= l {
1999
+					return io.ErrUnexpectedEOF
2000
+				}
2001
+				b := dAtA[iNdEx]
2002
+				iNdEx++
2003
+				msglen |= (int(b) & 0x7F) << shift
2004
+				if b < 0x80 {
2005
+					break
2006
+				}
2007
+			}
2008
+			if msglen < 0 {
2009
+				return ErrInvalidLengthGateway
2010
+			}
2011
+			postIndex := iNdEx + msglen
2012
+			if postIndex > l {
2013
+				return io.ErrUnexpectedEOF
2014
+			}
2015
+			m.Workers = append(m.Workers, &moby_buildkit_v1_types.WorkerRecord{})
2016
+			if err := m.Workers[len(m.Workers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
2017
+				return err
2018
+			}
2019
+			iNdEx = postIndex
1927 2020
 		default:
1928 2021
 			iNdEx = preIndex
1929 2022
 			skippy, err := skipGateway(dAtA[iNdEx:])
... ...
@@ -2053,46 +3295,66 @@ var (
2053 2053
 func init() { proto.RegisterFile("gateway.proto", fileDescriptorGateway) }
2054 2054
 
2055 2055
 var fileDescriptorGateway = []byte{
2056
-	// 652 bytes of a gzipped FileDescriptorProto
2057
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x4a,
2058
-	0x14, 0x7d, 0x8e, 0x01, 0x25, 0x37, 0xe6, 0x43, 0xa3, 0xa7, 0x27, 0xe3, 0x05, 0x44, 0xd6, 0x13,
2059
-	0xcf, 0xe2, 0x15, 0x5b, 0x4d, 0x5b, 0x09, 0x51, 0xa9, 0x52, 0xc3, 0x87, 0x44, 0x85, 0x44, 0x34,
2060
-	0x5d, 0x20, 0xb1, 0x1b, 0x27, 0x63, 0x33, 0xc2, 0x99, 0x71, 0xed, 0x09, 0x6d, 0xd4, 0x4d, 0xfb,
2061
-	0x73, 0xfa, 0x4f, 0x58, 0x76, 0xcd, 0x02, 0x55, 0xfc, 0x92, 0xca, 0xe3, 0x71, 0x30, 0x50, 0x52,
2062
-	0xba, 0x9b, 0x73, 0x7d, 0xef, 0x99, 0x73, 0xe7, 0xdc, 0x6b, 0x58, 0x8c, 0x89, 0xa4, 0x1f, 0xc9,
2063
-	0xc4, 0x4f, 0x33, 0x21, 0x05, 0x5a, 0x1d, 0x89, 0x70, 0xe2, 0x87, 0x63, 0x96, 0x0c, 0xcf, 0x99,
2064
-	0xf4, 0x2f, 0x9e, 0xfb, 0x51, 0x26, 0xb8, 0xa4, 0x7c, 0xe8, 0x6c, 0xc5, 0x4c, 0x9e, 0x8d, 0x43,
2065
-	0x7f, 0x20, 0x46, 0x41, 0x2c, 0x62, 0x11, 0xa8, 0x8a, 0x70, 0x1c, 0x29, 0xa4, 0x80, 0x3a, 0x95,
2066
-	0x4c, 0xce, 0xb3, 0x5a, 0x7a, 0x41, 0x1a, 0x54, 0xa4, 0x41, 0x2e, 0x92, 0x0b, 0x9a, 0x05, 0x69,
2067
-	0x18, 0x88, 0x34, 0x2f, 0xb3, 0xdd, 0x13, 0x58, 0xc5, 0x54, 0x7d, 0x38, 0x1c, 0x91, 0x98, 0xee,
2068
-	0x0a, 0x1e, 0xb1, 0x18, 0xd3, 0x0f, 0x63, 0x9a, 0x4b, 0xb4, 0x02, 0x26, 0xa6, 0x91, 0x6d, 0x74,
2069
-	0x0c, 0xaf, 0x85, 0x8b, 0x23, 0xf2, 0xa0, 0xd9, 0x4f, 0x88, 0x8c, 0x44, 0x36, 0xb2, 0x1b, 0x1d,
2070
-	0xc3, 0x6b, 0x77, 0x2d, 0x3f, 0x0d, 0xfd, 0x2a, 0x86, 0xa7, 0x5f, 0xdd, 0x2f, 0x06, 0x38, 0xbf,
2071
-	0x62, 0xce, 0x53, 0xc1, 0x73, 0x8a, 0xde, 0xc1, 0xc2, 0x1e, 0x8b, 0x69, 0x2e, 0x4b, 0xf6, 0x5e,
2072
-	0xf7, 0xf2, 0x7a, 0xfd, 0xaf, 0xab, 0xeb, 0xf5, 0xcd, 0x9a, 0x7a, 0x91, 0x52, 0x3e, 0x10, 0x5c,
2073
-	0x12, 0xc6, 0x69, 0x96, 0x07, 0xb1, 0xd8, 0x1a, 0xaa, 0x12, 0xbf, 0xac, 0xc4, 0x9a, 0x01, 0xfd,
2074
-	0x03, 0x0b, 0x25, 0xbb, 0x92, 0x64, 0x61, 0x8d, 0xdc, 0xab, 0x06, 0x58, 0xef, 0x0b, 0x01, 0x55,
2075
-	0x3f, 0x3e, 0xc0, 0x1e, 0x8d, 0x18, 0x67, 0x92, 0x09, 0xae, 0x2e, 0x6e, 0x77, 0x97, 0x0a, 0xfd,
2076
-	0xb7, 0x51, 0x5c, 0xcb, 0x40, 0x0e, 0x34, 0x0f, 0xb4, 0x0b, 0x8a, 0xba, 0x85, 0xa7, 0x18, 0x9d,
2077
-	0x42, 0xbb, 0x3a, 0x1f, 0xa7, 0xd2, 0x36, 0x3b, 0xa6, 0xd7, 0xee, 0x6e, 0xfb, 0x8f, 0xda, 0xe8,
2078
-	0xd7, 0x95, 0xf8, 0xb5, 0xd2, 0x7d, 0x2e, 0xb3, 0x09, 0xae, 0x93, 0x21, 0x0f, 0x96, 0x0f, 0x47,
2079
-	0xa9, 0xc8, 0xe4, 0x2e, 0x19, 0x9c, 0x51, 0x4c, 0xa3, 0xdc, 0x9e, 0xeb, 0x98, 0x5e, 0x0b, 0xdf,
2080
-	0x0f, 0xa3, 0xbf, 0x61, 0xfe, 0x80, 0x71, 0x92, 0xd8, 0xd0, 0x31, 0xbc, 0x26, 0x2e, 0x01, 0x72,
2081
-	0xc1, 0xda, 0xff, 0x54, 0x24, 0xd2, 0xec, 0xad, 0x94, 0x99, 0xdd, 0x56, 0xcf, 0x72, 0x27, 0xe6,
2082
-	0xbc, 0x81, 0x95, 0xfb, 0x22, 0x0a, 0xbf, 0xcf, 0xe9, 0xa4, 0xf2, 0xfb, 0x9c, 0x4e, 0x0a, 0xfe,
2083
-	0x0b, 0x92, 0x8c, 0xa9, 0x6e, 0xbf, 0x04, 0x3b, 0x8d, 0x6d, 0xc3, 0xdd, 0x87, 0x45, 0xdd, 0x91,
2084
-	0x76, 0xf4, 0xe1, 0xb0, 0xdc, 0x97, 0xd1, 0x78, 0x28, 0xc3, 0xfd, 0x0c, 0xcb, 0x98, 0x92, 0xe1,
2085
-	0x01, 0x4b, 0xe8, 0xe3, 0x53, 0x57, 0xf8, 0xc0, 0x12, 0xda, 0x27, 0xf2, 0x6c, 0xea, 0x83, 0xc6,
2086
-	0x68, 0x07, 0xe6, 0x31, 0xe1, 0x31, 0xb5, 0x4d, 0x65, 0xe7, 0xbf, 0x33, 0x1c, 0x50, 0x97, 0x14,
2087
-	0xb9, 0xb8, 0x2c, 0x71, 0x5f, 0x43, 0x6b, 0x1a, 0x2b, 0xa6, 0xe8, 0x38, 0x8a, 0x72, 0x5a, 0x4e,
2088
-	0xa4, 0x89, 0x35, 0x2a, 0xe2, 0x47, 0x94, 0xc7, 0xfa, 0x6a, 0x13, 0x6b, 0xe4, 0x6e, 0xc0, 0xca,
2089
-	0xad, 0x72, 0xfd, 0x06, 0x08, 0xe6, 0xf6, 0x88, 0x24, 0x8a, 0xc1, 0xc2, 0xea, 0xec, 0x2e, 0x42,
2090
-	0xbb, 0xcf, 0x78, 0xb5, 0x53, 0xee, 0x12, 0x58, 0x7d, 0xc1, 0xa7, 0x8b, 0xd0, 0xfd, 0x66, 0x42,
2091
-	0xeb, 0xe8, 0xa8, 0xd7, 0xcb, 0xd8, 0x30, 0xa6, 0xe8, 0xab, 0x01, 0xe8, 0xe1, 0xd6, 0xa0, 0x97,
2092
-	0x33, 0xba, 0x7a, 0x74, 0x7d, 0x9d, 0x57, 0x7f, 0x58, 0xa5, 0x9b, 0x38, 0x85, 0x79, 0xe5, 0x2c,
2093
-	0xfa, 0xef, 0x89, 0xd3, 0xec, 0x78, 0xbf, 0x4f, 0xd4, 0xdc, 0x03, 0x68, 0x56, 0x8f, 0x86, 0x36,
2094
-	0x67, 0xca, 0xbb, 0x33, 0x13, 0xce, 0xff, 0x4f, 0xca, 0xd5, 0x97, 0x9c, 0xc0, 0x5c, 0xf1, 0xe2,
2095
-	0x68, 0x63, 0x46, 0x51, 0xcd, 0x12, 0x67, 0x56, 0x9f, 0x75, 0xaf, 0x7a, 0xd6, 0xe5, 0xcd, 0x9a,
2096
-	0xf1, 0xfd, 0x66, 0xcd, 0xf8, 0x71, 0xb3, 0x66, 0x84, 0x0b, 0xea, 0x0f, 0xfa, 0xe2, 0x67, 0x00,
2097
-	0x00, 0x00, 0xff, 0xff, 0xbc, 0x68, 0x1b, 0xf0, 0xca, 0x05, 0x00, 0x00,
2056
+	// 969 bytes of a gzipped FileDescriptorProto
2057
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0x4b, 0x6f, 0xdb, 0x46,
2058
+	0x10, 0x0e, 0x4d, 0x49, 0x91, 0x46, 0x52, 0xac, 0x2e, 0x8a, 0x42, 0xe1, 0xc1, 0x51, 0x89, 0x22,
2059
+	0x65, 0xf3, 0x20, 0x51, 0xa5, 0x45, 0xd2, 0x04, 0x48, 0x1b, 0xd9, 0x31, 0xe2, 0x56, 0x41, 0x84,
2060
+	0xcd, 0xc1, 0x40, 0xd0, 0x1e, 0x56, 0xd2, 0x92, 0x26, 0x4c, 0x71, 0xd9, 0xe5, 0xca, 0xae, 0xd0,
2061
+	0x4b, 0xdb, 0x53, 0x7e, 0x5a, 0x8e, 0x3d, 0xf7, 0x10, 0x14, 0xbe, 0xf5, 0x5f, 0x14, 0xfb, 0xa0,
2062
+	0x4c, 0xbf, 0x64, 0xfb, 0xa4, 0x9d, 0xe5, 0x7c, 0x33, 0xdf, 0xce, 0x7c, 0xb3, 0x2b, 0x68, 0x47,
2063
+	0x44, 0xd0, 0x43, 0xb2, 0xf0, 0x33, 0xce, 0x04, 0x43, 0xb7, 0x67, 0x6c, 0xbc, 0xf0, 0xc7, 0xf3,
2064
+	0x38, 0x99, 0xee, 0xc7, 0xc2, 0x3f, 0xf8, 0xda, 0x0f, 0x39, 0x4b, 0x05, 0x4d, 0xa7, 0xce, 0xc3,
2065
+	0x28, 0x16, 0x7b, 0xf3, 0xb1, 0x3f, 0x61, 0xb3, 0x20, 0x62, 0x11, 0x0b, 0x14, 0x62, 0x3c, 0x0f,
2066
+	0x95, 0xa5, 0x0c, 0xb5, 0xd2, 0x91, 0x9c, 0xfe, 0x69, 0xf7, 0x88, 0xb1, 0x28, 0xa1, 0x24, 0x8b,
2067
+	0x73, 0xb3, 0x0c, 0x78, 0x36, 0x09, 0x72, 0x41, 0xc4, 0x3c, 0x37, 0x98, 0x07, 0x25, 0x8c, 0x24,
2068
+	0x12, 0x14, 0x44, 0x82, 0x9c, 0x25, 0x07, 0x94, 0x07, 0xd9, 0x38, 0x60, 0x59, 0xe1, 0x1d, 0x5c,
2069
+	0xe8, 0x4d, 0xb2, 0x38, 0x10, 0x8b, 0x8c, 0xe6, 0xc1, 0x21, 0xe3, 0xfb, 0x94, 0x1b, 0xc0, 0xa3,
2070
+	0x0b, 0x01, 0x73, 0x11, 0x27, 0x12, 0x35, 0x21, 0x59, 0x2e, 0x93, 0xc8, 0x5f, 0x0d, 0x72, 0xff,
2071
+	0xb3, 0xa0, 0x86, 0x69, 0x3e, 0x4f, 0x04, 0x42, 0x60, 0x73, 0x1a, 0x76, 0xad, 0x9e, 0xe5, 0x35,
2072
+	0x5e, 0xdd, 0xc0, 0xd2, 0x40, 0x8f, 0xa1, 0xc2, 0x69, 0x98, 0x77, 0xd7, 0x7a, 0x96, 0xd7, 0xec,
2073
+	0x7f, 0xee, 0x5f, 0x58, 0x3f, 0x1f, 0xd3, 0xf0, 0x35, 0xc9, 0x5e, 0xdd, 0xc0, 0x0a, 0x80, 0x7e,
2074
+	0x82, 0xfa, 0x8c, 0x0a, 0x32, 0x25, 0x82, 0x74, 0xa1, 0x67, 0x7b, 0xcd, 0x7e, 0xb0, 0x12, 0x2c,
2075
+	0x19, 0xf8, 0xaf, 0x0d, 0xe2, 0x65, 0x2a, 0xf8, 0x02, 0x2f, 0x03, 0x38, 0xcf, 0xa0, 0x7d, 0xe2,
2076
+	0x13, 0xea, 0x80, 0xbd, 0x4f, 0x17, 0x9a, 0x2a, 0x96, 0x4b, 0xf4, 0x29, 0x54, 0x0f, 0x48, 0x32,
2077
+	0xa7, 0x8a, 0x69, 0x0b, 0x6b, 0xe3, 0xe9, 0xda, 0x13, 0x6b, 0x50, 0x87, 0x1a, 0x57, 0xe1, 0xdd,
2078
+	0xbf, 0xd4, 0x59, 0x25, 0x4d, 0xf4, 0xbd, 0x39, 0x97, 0xa5, 0xa8, 0xdd, 0xbf, 0xf4, 0x5c, 0xf2,
2079
+	0x27, 0xd7, 0xb4, 0x14, 0xd0, 0x79, 0x0c, 0x8d, 0xe5, 0xd6, 0x65, 0x74, 0x1a, 0x25, 0x3a, 0xae,
2080
+	0x80, 0x36, 0xa6, 0x62, 0xce, 0x53, 0x4c, 0x7f, 0x9d, 0xd3, 0x5c, 0xa0, 0xef, 0x0a, 0x7e, 0x0a,
2081
+	0x7f, 0x59, 0x91, 0xa5, 0x23, 0x36, 0x00, 0xe4, 0x41, 0x95, 0x72, 0xce, 0xb8, 0x69, 0x0f, 0xf2,
2082
+	0xb5, 0xf2, 0x7c, 0x9e, 0x4d, 0xfc, 0xb7, 0x4a, 0x79, 0x58, 0x3b, 0xb8, 0x1d, 0xb8, 0x55, 0x64,
2083
+	0xcd, 0x33, 0x96, 0xe6, 0xd4, 0xdd, 0x85, 0xdb, 0x98, 0x2a, 0xdd, 0xed, 0xcc, 0x48, 0x44, 0x37,
2084
+	0x59, 0x1a, 0xc6, 0x51, 0xc1, 0xa9, 0x03, 0x36, 0x2e, 0xa4, 0x80, 0xe5, 0x12, 0x79, 0x50, 0x1f,
2085
+	0x25, 0x44, 0x84, 0x8c, 0xcf, 0x4c, 0xb6, 0x96, 0x9f, 0x8d, 0xfd, 0x62, 0x0f, 0x2f, 0xbf, 0xba,
2086
+	0x7f, 0x58, 0xe0, 0x9c, 0x17, 0x59, 0xe7, 0x45, 0x3f, 0x42, 0x6d, 0x2b, 0x8e, 0x68, 0xae, 0x8f,
2087
+	0xdb, 0x18, 0xf4, 0x3f, 0x7c, 0xbc, 0x73, 0xe3, 0x9f, 0x8f, 0x77, 0xee, 0x95, 0xd4, 0xcb, 0x32,
2088
+	0x9a, 0x4e, 0x58, 0x2a, 0x48, 0x9c, 0x52, 0x2e, 0xe7, 0xe9, 0xe1, 0x54, 0x41, 0x7c, 0x8d, 0xc4,
2089
+	0x26, 0x02, 0xfa, 0x0c, 0x6a, 0x3a, 0xba, 0xe9, 0xba, 0xb1, 0xdc, 0xf7, 0x36, 0xb4, 0xde, 0x4a,
2090
+	0x02, 0xc5, 0x79, 0x7c, 0x80, 0x2d, 0x1a, 0xc6, 0x69, 0x2c, 0x62, 0x96, 0x9a, 0x3a, 0xdf, 0x92,
2091
+	0xfc, 0x8f, 0x77, 0x71, 0xc9, 0x03, 0x39, 0x50, 0xdf, 0x36, 0x35, 0x37, 0x1d, 0x5c, 0xda, 0xe8,
2092
+	0x1d, 0x34, 0x8b, 0xf5, 0x9b, 0x4c, 0x74, 0x6d, 0xa5, 0xa0, 0x27, 0x2b, 0x9a, 0x56, 0x66, 0xe2,
2093
+	0x97, 0xa0, 0x5a, 0x4e, 0xe5, 0x60, 0xc8, 0x83, 0xf5, 0x9d, 0x59, 0xc6, 0xb8, 0xd8, 0x24, 0x93,
2094
+	0x3d, 0x2a, 0x05, 0xd6, 0xad, 0xf4, 0x6c, 0xaf, 0x81, 0x4f, 0x6f, 0xa3, 0x07, 0xf0, 0x09, 0x49,
2095
+	0x12, 0x76, 0x68, 0x14, 0xa1, 0x7a, 0xdb, 0xad, 0xf6, 0x2c, 0xaf, 0x8e, 0xcf, 0x7e, 0x90, 0x72,
2096
+	0xdc, 0x8e, 0x53, 0x92, 0x74, 0x41, 0x79, 0x68, 0x03, 0xb9, 0xd0, 0x7a, 0xf9, 0x9b, 0x0c, 0x4b,
2097
+	0xf9, 0x0b, 0x21, 0x78, 0xb7, 0xa9, 0x8a, 0x78, 0x62, 0xcf, 0x79, 0x0e, 0x9d, 0xd3, 0x94, 0xaf,
2098
+	0x25, 0xf7, 0x9f, 0xa1, 0x6d, 0xce, 0x6f, 0xfa, 0xdf, 0x29, 0xdd, 0x32, 0xfa, 0x8e, 0x39, 0x1e,
2099
+	0x00, 0xfb, 0x9a, 0x03, 0xe0, 0xfe, 0x0e, 0xeb, 0x98, 0x92, 0xe9, 0x76, 0x9c, 0xd0, 0x8b, 0xa5,
2100
+	0x2b, 0x9b, 0x19, 0x27, 0x74, 0x44, 0xc4, 0xde, 0xb2, 0x99, 0xc6, 0x46, 0x4f, 0xa1, 0x8a, 0x49,
2101
+	0x1a, 0x51, 0x93, 0xfa, 0x8b, 0x15, 0xa9, 0x55, 0x12, 0xe9, 0x8b, 0x35, 0xc4, 0x7d, 0x06, 0x8d,
2102
+	0xe5, 0x9e, 0x94, 0xe2, 0x9b, 0x30, 0xcc, 0xa9, 0x96, 0xb5, 0x8d, 0x8d, 0x25, 0xf7, 0x87, 0x34,
2103
+	0x8d, 0x4c, 0x6a, 0x1b, 0x1b, 0xcb, 0xbd, 0x0b, 0x9d, 0x63, 0xe6, 0xa6, 0x34, 0x08, 0x2a, 0x5b,
2104
+	0xf2, 0xbe, 0xb4, 0x54, 0x1f, 0xd4, 0xda, 0x6d, 0x43, 0x73, 0x14, 0xa7, 0xc5, 0x60, 0xba, 0x47,
2105
+	0x16, 0xb4, 0x46, 0x2c, 0x3d, 0x1e, 0xa7, 0x11, 0xac, 0x17, 0xfd, 0x79, 0x31, 0xda, 0xd9, 0x24,
2106
+	0x59, 0x71, 0xa7, 0xf5, 0xce, 0x1e, 0xc5, 0xbc, 0x00, 0xbe, 0x76, 0x1c, 0x54, 0xe4, 0xe4, 0xe1,
2107
+	0xd3, 0x70, 0xf4, 0x03, 0xdc, 0x1c, 0x0e, 0x07, 0x2a, 0xd2, 0xda, 0xb5, 0x22, 0x15, 0x30, 0xf4,
2108
+	0x1c, 0x6e, 0xee, 0xaa, 0x87, 0x29, 0x37, 0xd3, 0x71, 0x4e, 0x59, 0xd5, 0xfb, 0xe5, 0x6b, 0x37,
2109
+	0x4c, 0x27, 0x8c, 0x4f, 0x71, 0x01, 0xea, 0xbf, 0xaf, 0x40, 0x63, 0x38, 0x1c, 0x0c, 0x78, 0x3c,
2110
+	0x8d, 0x28, 0xfa, 0xd3, 0x02, 0x74, 0xf6, 0x3e, 0x41, 0xdf, 0xac, 0x56, 0xc9, 0xf9, 0x17, 0x9b,
2111
+	0xf3, 0xed, 0x35, 0x51, 0xa6, 0xca, 0xef, 0xa0, 0xaa, 0x54, 0x8c, 0xbe, 0xbc, 0xe2, 0x9c, 0x3b,
2112
+	0xde, 0xe5, 0x8e, 0x26, 0xf6, 0x04, 0xea, 0x85, 0x12, 0xd0, 0xbd, 0x95, 0xf4, 0x4e, 0x08, 0xdd,
2113
+	0xb9, 0x7f, 0x25, 0x5f, 0x93, 0x64, 0x17, 0x2a, 0x52, 0x46, 0xe8, 0xee, 0x0a, 0x50, 0x49, 0x67,
2114
+	0xce, 0xaa, 0x73, 0x9e, 0xd0, 0xdf, 0x2f, 0xf2, 0x49, 0x55, 0x77, 0x8c, 0xb7, 0x92, 0x4f, 0xe9,
2115
+	0xc5, 0x73, 0xbe, 0xba, 0x82, 0xa7, 0x0e, 0x3f, 0x68, 0x7d, 0x38, 0xda, 0xb0, 0xfe, 0x3e, 0xda,
2116
+	0xb0, 0xfe, 0x3d, 0xda, 0xb0, 0xc6, 0x35, 0xf5, 0x9f, 0xe5, 0xd1, 0xff, 0x01, 0x00, 0x00, 0xff,
2117
+	0xff, 0xb8, 0xcb, 0x8c, 0xfa, 0xd6, 0x09, 0x00, 0x00,
2098 2118
 }
... ...
@@ -3,17 +3,44 @@ syntax = "proto3";
3 3
 package moby.buildkit.v1.frontend;
4 4
 
5 5
 import "github.com/gogo/protobuf/gogoproto/gogo.proto";
6
+import "github.com/gogo/googleapis/google/rpc/status.proto";
6 7
 import "github.com/moby/buildkit/solver/pb/ops.proto";
8
+import "github.com/moby/buildkit/api/types/worker.proto";
9
+import "github.com/moby/buildkit/util/apicaps/pb/caps.proto";
7 10
 
8 11
 option (gogoproto.sizer_all) = true;
9 12
 option (gogoproto.marshaler_all) = true;
10 13
 option (gogoproto.unmarshaler_all) = true;
11 14
 
12 15
 service LLBBridge {
16
+	// apicaps:CapResolveImage
13 17
 	rpc ResolveImageConfig(ResolveImageConfigRequest) returns (ResolveImageConfigResponse);
18
+	// apicaps:CapSolveBase
14 19
 	rpc Solve(SolveRequest) returns (SolveResponse);
20
+	// apicaps:CapReadFile
15 21
 	rpc ReadFile(ReadFileRequest) returns (ReadFileResponse);
16 22
 	rpc Ping(PingRequest) returns (PongResponse);
23
+	rpc Return(ReturnRequest) returns (ReturnResponse);
24
+}
25
+
26
+message Result {
27
+	oneof result {
28
+		string ref = 1;
29
+		RefMap refs = 2;
30
+	}
31
+	map<string, bytes> metadata = 10;
32
+}
33
+
34
+message RefMap {
35
+	map<string, string> refs = 1;
36
+}
37
+
38
+message ReturnRequest {
39
+	Result result = 1;
40
+	google.rpc.Status error = 2;
41
+}
42
+
43
+message ReturnResponse {
17 44
 }
18 45
 
19 46
 message ResolveImageConfigRequest {
... ...
@@ -31,13 +58,21 @@ message SolveRequest {
31 31
 	string Frontend = 2;
32 32
 	map<string, string> FrontendOpt = 3;
33 33
 	repeated string ImportCacheRefs = 4;
34
+	bool allowResultReturn = 5;
35
+	
36
+	// apicaps.CapSolveInlineReturn deprecated
34 37
 	bool Final = 10;
35 38
 	bytes ExporterAttr = 11;
36 39
 }
37 40
 
38 41
 message SolveResponse {
39
-	string Ref = 1; // can be used by readfile request
40
-	bytes ExporterAttr = 2;
42
+	// deprecated
43
+	string ref = 1; // can be used by readfile request
44
+	// deprecated
45
+/*	bytes ExporterAttr = 2;*/
46
+	
47
+	// these fields are returned when allowMapReturn was set
48
+	Result result = 3;
41 49
 }
42 50
 
43 51
 message ReadFileRequest {
... ...
@@ -58,4 +93,7 @@ message ReadFileResponse {
58 58
 message PingRequest{
59 59
 }
60 60
 message PongResponse{
61
+	repeated moby.buildkit.v1.apicaps.APICap FrontendAPICaps = 1 [(gogoproto.nullable) = false];
62
+	repeated moby.buildkit.v1.apicaps.APICap LLBCaps = 2 [(gogoproto.nullable) = false];
63
+	repeated moby.buildkit.v1.types.WorkerRecord Workers = 3;
61 64
 }
62 65
\ No newline at end of file
63 66
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+package frontend
1
+
2
+import "github.com/moby/buildkit/solver"
3
+
4
+type Result struct {
5
+	Ref      solver.CachedResult
6
+	Refs     map[string]solver.CachedResult
7
+	Metadata map[string][]byte
8
+}
9
+
10
+func (r *Result) EachRef(fn func(solver.CachedResult) error) (err error) {
11
+	if r.Ref != nil {
12
+		err = fn(r.Ref)
13
+	}
14
+	for _, r := range r.Refs {
15
+		if r != nil {
16
+			if err1 := fn(r); err1 != nil && err == nil {
17
+				err = err1
18
+			}
19
+		}
20
+	}
21
+	return err
22
+}
... ...
@@ -20,16 +20,20 @@ import (
20 20
 )
21 21
 
22 22
 type llbBridge struct {
23
-	builder       solver.Builder
24
-	frontends     map[string]frontend.Frontend
25
-	resolveWorker func() (worker.Worker, error)
26
-	ci            *remotecache.CacheImporter
27
-	cms           map[string]solver.CacheManager
28
-	cmsMu         sync.Mutex
29
-	platforms     []specs.Platform
23
+	builder              solver.Builder
24
+	frontends            map[string]frontend.Frontend
25
+	resolveWorker        func() (worker.Worker, error)
26
+	resolveCacheImporter remotecache.ResolveCacheImporterFunc
27
+	cms                  map[string]solver.CacheManager
28
+	cmsMu                sync.Mutex
29
+	platforms            []specs.Platform
30 30
 }
31 31
 
32
-func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res solver.CachedResult, exp map[string][]byte, err error) {
32
+func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *frontend.Result, err error) {
33
+	w, err := b.resolveWorker()
34
+	if err != nil {
35
+		return nil, err
36
+	}
33 37
 	var cms []solver.CacheManager
34 38
 	for _, ref := range req.ImportCacheRefs {
35 39
 		b.cmsMu.Lock()
... ...
@@ -37,14 +41,22 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res s
37 37
 		if prevCm, ok := b.cms[ref]; !ok {
38 38
 			r, err := reference.ParseNormalizedNamed(ref)
39 39
 			if err != nil {
40
-				return nil, nil, err
40
+				return nil, err
41 41
 			}
42 42
 			ref = reference.TagNameOnly(r).String()
43 43
 			func(ref string) {
44 44
 				cm = newLazyCacheManager(ref, func() (solver.CacheManager, error) {
45 45
 					var cmNew solver.CacheManager
46 46
 					if err := b.builder.Call(ctx, "importing cache manifest from "+ref, func(ctx context.Context) error {
47
-						cmNew, err = b.ci.Resolve(ctx, ref)
47
+						if b.resolveCacheImporter == nil {
48
+							return errors.New("no cache importer is available")
49
+						}
50
+						typ := "" // TODO: support non-registry type
51
+						ci, desc, err := b.resolveCacheImporter(ctx, typ, ref)
52
+						if err != nil {
53
+							return err
54
+						}
55
+						cmNew, err = ci.Resolve(ctx, desc, ref, w)
48 56
 						return err
49 57
 					}); err != nil {
50 58
 						return nil, err
... ...
@@ -63,38 +75,43 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res s
63 63
 	if req.Definition != nil && req.Definition.Def != nil {
64 64
 		edge, err := Load(req.Definition, WithCacheSources(cms), RuntimePlatforms(b.platforms))
65 65
 		if err != nil {
66
-			return nil, nil, err
66
+			return nil, err
67 67
 		}
68
-		res, err = b.builder.Build(ctx, edge)
68
+		ref, err := b.builder.Build(ctx, edge)
69 69
 		if err != nil {
70
-			return nil, nil, err
70
+			return nil, err
71 71
 		}
72
+
73
+		res = &frontend.Result{Ref: ref}
72 74
 	}
73 75
 	if req.Frontend != "" {
74 76
 		f, ok := b.frontends[req.Frontend]
75 77
 		if !ok {
76
-			return nil, nil, errors.Errorf("invalid frontend: %s", req.Frontend)
78
+			return nil, errors.Errorf("invalid frontend: %s", req.Frontend)
77 79
 		}
78
-		res, exp, err = f.Solve(ctx, b, req.FrontendOpt)
80
+		res, err = f.Solve(ctx, b, req.FrontendOpt)
79 81
 		if err != nil {
80
-			return nil, nil, err
82
+			return nil, err
81 83
 		}
82 84
 	} else {
83 85
 		if req.Definition == nil || req.Definition.Def == nil {
84
-			return nil, nil, nil
86
+			return &frontend.Result{}, nil
85 87
 		}
86 88
 	}
87 89
 
88
-	if res != nil {
89
-		wr, ok := res.Sys().(*worker.WorkerRef)
90
+	if err := res.EachRef(func(r solver.CachedResult) error {
91
+		wr, ok := r.Sys().(*worker.WorkerRef)
90 92
 		if !ok {
91
-			return nil, nil, errors.Errorf("invalid reference for exporting: %T", res.Sys())
93
+			return errors.Errorf("invalid reference for exporting: %T", r.Sys())
92 94
 		}
93 95
 		if wr.ImmutableRef != nil {
94
-			if err := wr.ImmutableRef.Finalize(ctx); err != nil {
95
-				return nil, nil, err
96
+			if err := wr.ImmutableRef.Finalize(ctx, false); err != nil {
97
+				return err
96 98
 			}
97 99
 		}
100
+		return nil
101
+	}); err != nil {
102
+		return nil, err
98 103
 	}
99 104
 	return
100 105
 }
... ...
@@ -117,12 +117,16 @@ func (b *buildOp) Exec(ctx context.Context, inputs []solver.Result) (outputs []s
117 117
 	lm.Unmount()
118 118
 	lm = nil
119 119
 
120
-	newref, _, err := b.b.Solve(ctx, frontend.SolveRequest{
120
+	newRes, err := b.b.Solve(ctx, frontend.SolveRequest{
121 121
 		Definition: def.ToPB(),
122 122
 	})
123 123
 	if err != nil {
124 124
 		return nil, err
125 125
 	}
126 126
 
127
-	return []solver.Result{newref}, err
127
+	for _, r := range newRes.Refs {
128
+		r.Release(context.TODO())
129
+	}
130
+
131
+	return []solver.Result{newRes.Ref}, err
128 132
 }
... ...
@@ -19,7 +19,7 @@ import (
19 19
 
20 20
 type ExporterRequest struct {
21 21
 	Exporter        exporter.ExporterInstance
22
-	CacheExporter   *remotecache.RegistryCacheExporter
22
+	CacheExporter   remotecache.Exporter
23 23
 	CacheExportMode solver.CacheExportMode
24 24
 }
25 25
 
... ...
@@ -27,18 +27,18 @@ type ExporterRequest struct {
27 27
 type ResolveWorkerFunc func() (worker.Worker, error)
28 28
 
29 29
 type Solver struct {
30
-	solver        *solver.Solver
31
-	resolveWorker ResolveWorkerFunc
32
-	frontends     map[string]frontend.Frontend
33
-	ci            *remotecache.CacheImporter
34
-	platforms     []specs.Platform
30
+	solver               *solver.Solver
31
+	resolveWorker        ResolveWorkerFunc
32
+	frontends            map[string]frontend.Frontend
33
+	resolveCacheImporter remotecache.ResolveCacheImporterFunc
34
+	platforms            []specs.Platform
35 35
 }
36 36
 
37
-func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, ci *remotecache.CacheImporter) (*Solver, error) {
37
+func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, resolveCI remotecache.ResolveCacheImporterFunc) (*Solver, error) {
38 38
 	s := &Solver{
39
-		resolveWorker: defaultResolver(wc),
40
-		frontends:     f,
41
-		ci:            ci,
39
+		resolveWorker:        defaultResolver(wc),
40
+		frontends:            f,
41
+		resolveCacheImporter: resolveCI,
42 42
 	}
43 43
 
44 44
 	results := newCacheResultStorage(wc)
... ...
@@ -71,12 +71,12 @@ func (s *Solver) resolver() solver.ResolveOpFunc {
71 71
 
72 72
 func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
73 73
 	return &llbBridge{
74
-		builder:       b,
75
-		frontends:     s.frontends,
76
-		resolveWorker: s.resolveWorker,
77
-		ci:            s.ci,
78
-		cms:           map[string]solver.CacheManager{},
79
-		platforms:     s.platforms,
74
+		builder:              b,
75
+		frontends:            s.frontends,
76
+		resolveWorker:        s.resolveWorker,
77
+		resolveCacheImporter: s.resolveCacheImporter,
78
+		cms:                  map[string]solver.CacheManager{},
79
+		platforms:            s.platforms,
80 80
 	}
81 81
 }
82 82
 
... ...
@@ -90,21 +90,22 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
90 90
 
91 91
 	j.SessionID = session.FromContext(ctx)
92 92
 
93
-	res, exporterOpt, err := s.Bridge(j).Solve(ctx, req)
93
+	res, err := s.Bridge(j).Solve(ctx, req)
94 94
 	if err != nil {
95 95
 		return nil, err
96 96
 	}
97 97
 
98 98
 	defer func() {
99
-		if res != nil {
100
-			go res.Release(context.TODO())
101
-		}
99
+		res.EachRef(func(ref solver.CachedResult) error {
100
+			go ref.Release(context.TODO())
101
+			return nil
102
+		})
102 103
 	}()
103 104
 
104 105
 	var exporterResponse map[string]string
105 106
 	if exp := exp.Exporter; exp != nil {
106 107
 		var immutable cache.ImmutableRef
107
-		if res != nil {
108
+		if res := res.Ref; res != nil { // FIXME(tonistiigi):
108 109
 			workerRef, ok := res.Sys().(*worker.WorkerRef)
109 110
 			if !ok {
110 111
 				return nil, errors.Errorf("invalid reference: %T", res.Sys())
... ...
@@ -113,7 +114,7 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
113 113
 		}
114 114
 
115 115
 		if err := j.Call(ctx, exp.Name(), func(ctx context.Context) error {
116
-			exporterResponse, err = exp.Export(ctx, immutable, exporterOpt)
116
+			exporterResponse, err = exp.Export(ctx, immutable, res.Metadata)
117 117
 			return err
118 118
 		}); err != nil {
119 119
 			return nil, err
... ...
@@ -123,14 +124,16 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
123 123
 	if e := exp.CacheExporter; e != nil {
124 124
 		if err := j.Call(ctx, "exporting cache", func(ctx context.Context) error {
125 125
 			prepareDone := oneOffProgress(ctx, "preparing build cache for export")
126
-			if _, err := res.CacheKey().Exporter.ExportTo(ctx, e, solver.CacheExportOpt{
127
-				Convert: workerRefConverter,
128
-				Mode:    exp.CacheExportMode,
126
+			if err := res.EachRef(func(res solver.CachedResult) error {
127
+				_, err := res.CacheKey().Exporter.ExportTo(ctx, e, solver.CacheExportOpt{
128
+					Convert: workerRefConverter,
129
+					Mode:    exp.CacheExportMode,
130
+				})
131
+				return err
129 132
 			}); err != nil {
130 133
 				return prepareDone(err)
131 134
 			}
132 135
 			prepareDone(nil)
133
-
134 136
 			return e.Finalize(ctx)
135 137
 		}); err != nil {
136 138
 			return nil, err
... ...
@@ -51,8 +51,9 @@ func WithCacheSources(cms []solver.CacheManager) LoadOpt {
51 51
 
52 52
 func RuntimePlatforms(p []specs.Platform) LoadOpt {
53 53
 	var defaultPlatform *pb.Platform
54
+	pp := make([]specs.Platform, len(p))
54 55
 	for i := range p {
55
-		p[i] = platforms.Normalize(p[i])
56
+		pp[i] = platforms.Normalize(p[i])
56 57
 	}
57 58
 	return func(op *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
58 59
 		if op.Platform == nil {
... ...
@@ -67,7 +68,7 @@ func RuntimePlatforms(p []specs.Platform) LoadOpt {
67 67
 		}
68 68
 		if _, ok := op.Op.(*pb.Op_Exec); ok {
69 69
 			var found bool
70
-			for _, pp := range p {
70
+			for _, pp := range pp {
71 71
 				if pp.OS == op.Platform.OS && pp.Architecture == op.Platform.Architecture && pp.Variant == op.Platform.Variant {
72 72
 					found = true
73 73
 					break
... ...
@@ -3,6 +3,7 @@ package pb
3 3
 const AttrKeepGitDir = "git.keepgitdir"
4 4
 const AttrFullRemoteURL = "git.fullurl"
5 5
 const AttrLocalSessionID = "local.session"
6
+const AttrLocalUniqueID = "local.unique"
6 7
 const AttrIncludePatterns = "local.includepattern"
7 8
 const AttrFollowPaths = "local.followpaths"
8 9
 const AttrExcludePatterns = "local.excludepatterns"
... ...
@@ -609,6 +609,7 @@ func (m *SourceOp) GetAttrs() map[string]string {
609 609
 }
610 610
 
611 611
 // BuildOp is used for nested build invocation.
612
+// BuildOp is experimental and can break without backwards compatibility
612 613
 type BuildOp struct {
613 614
 	Builder InputIndex             `protobuf:"varint,1,opt,name=builder,proto3,customtype=InputIndex" json:"builder"`
614 615
 	Inputs  map[string]*BuildInput `protobuf:"bytes,2,rep,name=inputs" json:"inputs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
... ...
@@ -114,6 +114,7 @@ message SourceOp {
114 114
 }
115 115
 
116 116
 // BuildOp is used for nested build invocation.
117
+// BuildOp is experimental and can break without backwards compatibility
117 118
 message BuildOp {
118 119
 	int64 builder = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false];
119 120
 	map<string, BuildInput> inputs = 2;
120 121
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+package pb
1
+
2
+import (
3
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
4
+)
5
+
6
+func (p *Platform) Spec() specs.Platform {
7
+	return specs.Platform{
8
+		OS:           p.OS,
9
+		Architecture: p.Architecture,
10
+		Variant:      p.Variant,
11
+		OSVersion:    p.OSVersion,
12
+		OSFeatures:   p.OSFeatures,
13
+	}
14
+}
15
+
16
+func PlatformFromSpec(p specs.Platform) Platform {
17
+	return Platform{
18
+		OS:           p.OS,
19
+		Architecture: p.Architecture,
20
+		Variant:      p.Variant,
21
+		OSVersion:    p.OSVersion,
22
+		OSFeatures:   p.OSFeatures,
23
+	}
24
+}
25
+
26
+func ToSpecPlatforms(p []Platform) []specs.Platform {
27
+	out := make([]specs.Platform, 0, len(p))
28
+	for _, pp := range p {
29
+		out = append(out, pp.Spec())
30
+	}
31
+	return out
32
+}
33
+
34
+func PlatformsFromSpec(p []specs.Platform) []Platform {
35
+	out := make([]Platform, 0, len(p))
36
+	for _, pp := range p {
37
+		out = append(out, PlatformFromSpec(pp))
38
+	}
39
+	return out
40
+}
0 41
new file mode 100644
... ...
@@ -0,0 +1,161 @@
0
+package apicaps
1
+
2
+import (
3
+	"fmt"
4
+	"sort"
5
+	"strings"
6
+
7
+	pb "github.com/moby/buildkit/util/apicaps/pb"
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+type PBCap = pb.APICap
12
+
13
+// ExportedProduct is the name of the product using this package.
14
+// Users vendoring this library may override it to provide better versioning hints
15
+// for their users (or set it with a flag to buildkitd).
16
+var ExportedProduct string
17
+
18
+// CapStatus defines the stability properties of a capability
19
+type CapStatus int
20
+
21
+const (
22
+	// CapStatusStable refers to a capability that should never be changed in
23
+	// backwards incompatible manner unless there is a serious security issue.
24
+	CapStatusStable CapStatus = iota
25
+	// CapStatusExperimental refers to a capability that may be removed in the future.
26
+	// If incompatible changes are made the previous ID is disabled and new is added.
27
+	CapStatusExperimental
28
+	// CapStatusPrerelease is same as CapStatusExperimental that can be used for new
29
+	// features before they move to stable.
30
+	CapStatusPrerelease
31
+)
32
+
33
+// CapID is type for capability identifier
34
+type CapID string
35
+
36
+// Cap describes an API feature
37
+type Cap struct {
38
+	ID                  CapID
39
+	Name                string // readable name, may contain spaces but keep in one sentence
40
+	Status              CapStatus
41
+	Enabled             bool
42
+	Deprecated          bool
43
+	SupportedHint       map[string]string
44
+	DisabledReason      string
45
+	DisabledReasonMsg   string
46
+	DisabledAlternative string
47
+}
48
+
49
+// CapList is a collection of capability definitions
50
+type CapList struct {
51
+	m map[CapID]Cap
52
+}
53
+
54
+// Init initializes definition for a new capability.
55
+// Not safe to be called concurrently with other methods.
56
+func (l *CapList) Init(cc ...Cap) {
57
+	if l.m == nil {
58
+		l.m = make(map[CapID]Cap, len(cc))
59
+	}
60
+	for _, c := range cc {
61
+		l.m[c.ID] = c
62
+	}
63
+}
64
+
65
+// All reports the configuration of all known capabilities
66
+func (l *CapList) All() []pb.APICap {
67
+	out := make([]pb.APICap, 0, len(l.m))
68
+	for _, c := range l.m {
69
+		out = append(out, pb.APICap{
70
+			ID:                  string(c.ID),
71
+			Enabled:             c.Enabled,
72
+			Deprecated:          c.Deprecated,
73
+			DisabledReason:      c.DisabledReason,
74
+			DisabledReasonMsg:   c.DisabledReasonMsg,
75
+			DisabledAlternative: c.DisabledAlternative,
76
+		})
77
+	}
78
+	sort.Slice(out, func(i, j int) bool {
79
+		return out[i].ID < out[j].ID
80
+	})
81
+	return out
82
+}
83
+
84
+// CapSet returns a CapSet for an capability configuration
85
+func (l *CapList) CapSet(caps []pb.APICap) CapSet {
86
+	m := make(map[string]*pb.APICap, len(caps))
87
+	for _, c := range caps {
88
+		if c.ID != "" {
89
+			m[c.ID] = &c
90
+		}
91
+	}
92
+	return CapSet{
93
+		list: l,
94
+		set:  m,
95
+	}
96
+}
97
+
98
+// CapSet is a configuration for detecting supported capabilities
99
+type CapSet struct {
100
+	list *CapList
101
+	set  map[string]*pb.APICap
102
+}
103
+
104
+// Supports returns an error if capability is not supported
105
+func (s *CapSet) Supports(id CapID) error {
106
+	err := &CapError{ID: id}
107
+	c, ok := s.list.m[id]
108
+	if !ok {
109
+		return errors.WithStack(err)
110
+	}
111
+	err.Definition = &c
112
+	state, ok := s.set[string(id)]
113
+	if !ok {
114
+		return errors.WithStack(err)
115
+	}
116
+	err.State = state
117
+	if !state.Enabled {
118
+		return errors.WithStack(err)
119
+	}
120
+	return nil
121
+}
122
+
123
+// CapError is an error for unsupported capability
124
+type CapError struct {
125
+	ID         CapID
126
+	Definition *Cap
127
+	State      *pb.APICap
128
+}
129
+
130
+func (e CapError) Error() string {
131
+	if e.Definition == nil {
132
+		return fmt.Sprintf("unknown API capability %s", e.ID)
133
+	}
134
+	typ := ""
135
+	if e.Definition.Status == CapStatusExperimental {
136
+		typ = "experimental "
137
+	}
138
+	if e.Definition.Status == CapStatusPrerelease {
139
+		typ = "prerelease "
140
+	}
141
+	name := ""
142
+	if e.Definition.Name != "" {
143
+		name = "(" + e.Definition.Name + ")"
144
+	}
145
+	b := &strings.Builder{}
146
+	fmt.Fprintf(b, "requested %sfeature %s %s", typ, e.ID, name)
147
+	if e.State == nil {
148
+		fmt.Fprint(b, " is not supported by build server")
149
+		if hint, ok := e.Definition.SupportedHint[ExportedProduct]; ok {
150
+			fmt.Fprintf(b, " (added in %s)", hint)
151
+		}
152
+		fmt.Fprintf(b, ", please update %s", ExportedProduct)
153
+	} else {
154
+		fmt.Fprint(b, " has been disabled on the build server")
155
+		if e.State.DisabledReasonMsg != "" {
156
+			fmt.Fprintf(b, ": %s", e.State.DisabledReasonMsg)
157
+		}
158
+	}
159
+	return b.String()
160
+}
0 161
new file mode 100644
... ...
@@ -0,0 +1,535 @@
0
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
1
+// source: caps.proto
2
+
3
+/*
4
+	Package moby_buildkit_v1_apicaps is a generated protocol buffer package.
5
+
6
+	It is generated from these files:
7
+		caps.proto
8
+
9
+	It has these top-level messages:
10
+		APICap
11
+*/
12
+package moby_buildkit_v1_apicaps
13
+
14
+import proto "github.com/gogo/protobuf/proto"
15
+import fmt "fmt"
16
+import math "math"
17
+import _ "github.com/gogo/protobuf/gogoproto"
18
+
19
+import io "io"
20
+
21
+// Reference imports to suppress errors if they are not otherwise used.
22
+var _ = proto.Marshal
23
+var _ = fmt.Errorf
24
+var _ = math.Inf
25
+
26
+// This is a compile-time assertion to ensure that this generated file
27
+// is compatible with the proto package it is being compiled against.
28
+// A compilation error at this line likely means your copy of the
29
+// proto package needs to be updated.
30
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
31
+
32
+// APICap defines a capability supported by the service
33
+type APICap struct {
34
+	ID                  string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
35
+	Enabled             bool   `protobuf:"varint,2,opt,name=Enabled,proto3" json:"Enabled,omitempty"`
36
+	Deprecated          bool   `protobuf:"varint,3,opt,name=Deprecated,proto3" json:"Deprecated,omitempty"`
37
+	DisabledReason      string `protobuf:"bytes,4,opt,name=DisabledReason,proto3" json:"DisabledReason,omitempty"`
38
+	DisabledReasonMsg   string `protobuf:"bytes,5,opt,name=DisabledReasonMsg,proto3" json:"DisabledReasonMsg,omitempty"`
39
+	DisabledAlternative string `protobuf:"bytes,6,opt,name=DisabledAlternative,proto3" json:"DisabledAlternative,omitempty"`
40
+}
41
+
42
+func (m *APICap) Reset()                    { *m = APICap{} }
43
+func (m *APICap) String() string            { return proto.CompactTextString(m) }
44
+func (*APICap) ProtoMessage()               {}
45
+func (*APICap) Descriptor() ([]byte, []int) { return fileDescriptorCaps, []int{0} }
46
+
47
+func (m *APICap) GetID() string {
48
+	if m != nil {
49
+		return m.ID
50
+	}
51
+	return ""
52
+}
53
+
54
+func (m *APICap) GetEnabled() bool {
55
+	if m != nil {
56
+		return m.Enabled
57
+	}
58
+	return false
59
+}
60
+
61
+func (m *APICap) GetDeprecated() bool {
62
+	if m != nil {
63
+		return m.Deprecated
64
+	}
65
+	return false
66
+}
67
+
68
+func (m *APICap) GetDisabledReason() string {
69
+	if m != nil {
70
+		return m.DisabledReason
71
+	}
72
+	return ""
73
+}
74
+
75
+func (m *APICap) GetDisabledReasonMsg() string {
76
+	if m != nil {
77
+		return m.DisabledReasonMsg
78
+	}
79
+	return ""
80
+}
81
+
82
+func (m *APICap) GetDisabledAlternative() string {
83
+	if m != nil {
84
+		return m.DisabledAlternative
85
+	}
86
+	return ""
87
+}
88
+
89
+func init() {
90
+	proto.RegisterType((*APICap)(nil), "moby.buildkit.v1.apicaps.APICap")
91
+}
92
+func (m *APICap) Marshal() (dAtA []byte, err error) {
93
+	size := m.Size()
94
+	dAtA = make([]byte, size)
95
+	n, err := m.MarshalTo(dAtA)
96
+	if err != nil {
97
+		return nil, err
98
+	}
99
+	return dAtA[:n], nil
100
+}
101
+
102
+func (m *APICap) MarshalTo(dAtA []byte) (int, error) {
103
+	var i int
104
+	_ = i
105
+	var l int
106
+	_ = l
107
+	if len(m.ID) > 0 {
108
+		dAtA[i] = 0xa
109
+		i++
110
+		i = encodeVarintCaps(dAtA, i, uint64(len(m.ID)))
111
+		i += copy(dAtA[i:], m.ID)
112
+	}
113
+	if m.Enabled {
114
+		dAtA[i] = 0x10
115
+		i++
116
+		if m.Enabled {
117
+			dAtA[i] = 1
118
+		} else {
119
+			dAtA[i] = 0
120
+		}
121
+		i++
122
+	}
123
+	if m.Deprecated {
124
+		dAtA[i] = 0x18
125
+		i++
126
+		if m.Deprecated {
127
+			dAtA[i] = 1
128
+		} else {
129
+			dAtA[i] = 0
130
+		}
131
+		i++
132
+	}
133
+	if len(m.DisabledReason) > 0 {
134
+		dAtA[i] = 0x22
135
+		i++
136
+		i = encodeVarintCaps(dAtA, i, uint64(len(m.DisabledReason)))
137
+		i += copy(dAtA[i:], m.DisabledReason)
138
+	}
139
+	if len(m.DisabledReasonMsg) > 0 {
140
+		dAtA[i] = 0x2a
141
+		i++
142
+		i = encodeVarintCaps(dAtA, i, uint64(len(m.DisabledReasonMsg)))
143
+		i += copy(dAtA[i:], m.DisabledReasonMsg)
144
+	}
145
+	if len(m.DisabledAlternative) > 0 {
146
+		dAtA[i] = 0x32
147
+		i++
148
+		i = encodeVarintCaps(dAtA, i, uint64(len(m.DisabledAlternative)))
149
+		i += copy(dAtA[i:], m.DisabledAlternative)
150
+	}
151
+	return i, nil
152
+}
153
+
154
+func encodeVarintCaps(dAtA []byte, offset int, v uint64) int {
155
+	for v >= 1<<7 {
156
+		dAtA[offset] = uint8(v&0x7f | 0x80)
157
+		v >>= 7
158
+		offset++
159
+	}
160
+	dAtA[offset] = uint8(v)
161
+	return offset + 1
162
+}
163
+func (m *APICap) Size() (n int) {
164
+	var l int
165
+	_ = l
166
+	l = len(m.ID)
167
+	if l > 0 {
168
+		n += 1 + l + sovCaps(uint64(l))
169
+	}
170
+	if m.Enabled {
171
+		n += 2
172
+	}
173
+	if m.Deprecated {
174
+		n += 2
175
+	}
176
+	l = len(m.DisabledReason)
177
+	if l > 0 {
178
+		n += 1 + l + sovCaps(uint64(l))
179
+	}
180
+	l = len(m.DisabledReasonMsg)
181
+	if l > 0 {
182
+		n += 1 + l + sovCaps(uint64(l))
183
+	}
184
+	l = len(m.DisabledAlternative)
185
+	if l > 0 {
186
+		n += 1 + l + sovCaps(uint64(l))
187
+	}
188
+	return n
189
+}
190
+
191
+func sovCaps(x uint64) (n int) {
192
+	for {
193
+		n++
194
+		x >>= 7
195
+		if x == 0 {
196
+			break
197
+		}
198
+	}
199
+	return n
200
+}
201
+func sozCaps(x uint64) (n int) {
202
+	return sovCaps(uint64((x << 1) ^ uint64((int64(x) >> 63))))
203
+}
204
+func (m *APICap) Unmarshal(dAtA []byte) error {
205
+	l := len(dAtA)
206
+	iNdEx := 0
207
+	for iNdEx < l {
208
+		preIndex := iNdEx
209
+		var wire uint64
210
+		for shift := uint(0); ; shift += 7 {
211
+			if shift >= 64 {
212
+				return ErrIntOverflowCaps
213
+			}
214
+			if iNdEx >= l {
215
+				return io.ErrUnexpectedEOF
216
+			}
217
+			b := dAtA[iNdEx]
218
+			iNdEx++
219
+			wire |= (uint64(b) & 0x7F) << shift
220
+			if b < 0x80 {
221
+				break
222
+			}
223
+		}
224
+		fieldNum := int32(wire >> 3)
225
+		wireType := int(wire & 0x7)
226
+		if wireType == 4 {
227
+			return fmt.Errorf("proto: APICap: wiretype end group for non-group")
228
+		}
229
+		if fieldNum <= 0 {
230
+			return fmt.Errorf("proto: APICap: illegal tag %d (wire type %d)", fieldNum, wire)
231
+		}
232
+		switch fieldNum {
233
+		case 1:
234
+			if wireType != 2 {
235
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
236
+			}
237
+			var stringLen uint64
238
+			for shift := uint(0); ; shift += 7 {
239
+				if shift >= 64 {
240
+					return ErrIntOverflowCaps
241
+				}
242
+				if iNdEx >= l {
243
+					return io.ErrUnexpectedEOF
244
+				}
245
+				b := dAtA[iNdEx]
246
+				iNdEx++
247
+				stringLen |= (uint64(b) & 0x7F) << shift
248
+				if b < 0x80 {
249
+					break
250
+				}
251
+			}
252
+			intStringLen := int(stringLen)
253
+			if intStringLen < 0 {
254
+				return ErrInvalidLengthCaps
255
+			}
256
+			postIndex := iNdEx + intStringLen
257
+			if postIndex > l {
258
+				return io.ErrUnexpectedEOF
259
+			}
260
+			m.ID = string(dAtA[iNdEx:postIndex])
261
+			iNdEx = postIndex
262
+		case 2:
263
+			if wireType != 0 {
264
+				return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType)
265
+			}
266
+			var v int
267
+			for shift := uint(0); ; shift += 7 {
268
+				if shift >= 64 {
269
+					return ErrIntOverflowCaps
270
+				}
271
+				if iNdEx >= l {
272
+					return io.ErrUnexpectedEOF
273
+				}
274
+				b := dAtA[iNdEx]
275
+				iNdEx++
276
+				v |= (int(b) & 0x7F) << shift
277
+				if b < 0x80 {
278
+					break
279
+				}
280
+			}
281
+			m.Enabled = bool(v != 0)
282
+		case 3:
283
+			if wireType != 0 {
284
+				return fmt.Errorf("proto: wrong wireType = %d for field Deprecated", wireType)
285
+			}
286
+			var v int
287
+			for shift := uint(0); ; shift += 7 {
288
+				if shift >= 64 {
289
+					return ErrIntOverflowCaps
290
+				}
291
+				if iNdEx >= l {
292
+					return io.ErrUnexpectedEOF
293
+				}
294
+				b := dAtA[iNdEx]
295
+				iNdEx++
296
+				v |= (int(b) & 0x7F) << shift
297
+				if b < 0x80 {
298
+					break
299
+				}
300
+			}
301
+			m.Deprecated = bool(v != 0)
302
+		case 4:
303
+			if wireType != 2 {
304
+				return fmt.Errorf("proto: wrong wireType = %d for field DisabledReason", wireType)
305
+			}
306
+			var stringLen uint64
307
+			for shift := uint(0); ; shift += 7 {
308
+				if shift >= 64 {
309
+					return ErrIntOverflowCaps
310
+				}
311
+				if iNdEx >= l {
312
+					return io.ErrUnexpectedEOF
313
+				}
314
+				b := dAtA[iNdEx]
315
+				iNdEx++
316
+				stringLen |= (uint64(b) & 0x7F) << shift
317
+				if b < 0x80 {
318
+					break
319
+				}
320
+			}
321
+			intStringLen := int(stringLen)
322
+			if intStringLen < 0 {
323
+				return ErrInvalidLengthCaps
324
+			}
325
+			postIndex := iNdEx + intStringLen
326
+			if postIndex > l {
327
+				return io.ErrUnexpectedEOF
328
+			}
329
+			m.DisabledReason = string(dAtA[iNdEx:postIndex])
330
+			iNdEx = postIndex
331
+		case 5:
332
+			if wireType != 2 {
333
+				return fmt.Errorf("proto: wrong wireType = %d for field DisabledReasonMsg", wireType)
334
+			}
335
+			var stringLen uint64
336
+			for shift := uint(0); ; shift += 7 {
337
+				if shift >= 64 {
338
+					return ErrIntOverflowCaps
339
+				}
340
+				if iNdEx >= l {
341
+					return io.ErrUnexpectedEOF
342
+				}
343
+				b := dAtA[iNdEx]
344
+				iNdEx++
345
+				stringLen |= (uint64(b) & 0x7F) << shift
346
+				if b < 0x80 {
347
+					break
348
+				}
349
+			}
350
+			intStringLen := int(stringLen)
351
+			if intStringLen < 0 {
352
+				return ErrInvalidLengthCaps
353
+			}
354
+			postIndex := iNdEx + intStringLen
355
+			if postIndex > l {
356
+				return io.ErrUnexpectedEOF
357
+			}
358
+			m.DisabledReasonMsg = string(dAtA[iNdEx:postIndex])
359
+			iNdEx = postIndex
360
+		case 6:
361
+			if wireType != 2 {
362
+				return fmt.Errorf("proto: wrong wireType = %d for field DisabledAlternative", wireType)
363
+			}
364
+			var stringLen uint64
365
+			for shift := uint(0); ; shift += 7 {
366
+				if shift >= 64 {
367
+					return ErrIntOverflowCaps
368
+				}
369
+				if iNdEx >= l {
370
+					return io.ErrUnexpectedEOF
371
+				}
372
+				b := dAtA[iNdEx]
373
+				iNdEx++
374
+				stringLen |= (uint64(b) & 0x7F) << shift
375
+				if b < 0x80 {
376
+					break
377
+				}
378
+			}
379
+			intStringLen := int(stringLen)
380
+			if intStringLen < 0 {
381
+				return ErrInvalidLengthCaps
382
+			}
383
+			postIndex := iNdEx + intStringLen
384
+			if postIndex > l {
385
+				return io.ErrUnexpectedEOF
386
+			}
387
+			m.DisabledAlternative = string(dAtA[iNdEx:postIndex])
388
+			iNdEx = postIndex
389
+		default:
390
+			iNdEx = preIndex
391
+			skippy, err := skipCaps(dAtA[iNdEx:])
392
+			if err != nil {
393
+				return err
394
+			}
395
+			if skippy < 0 {
396
+				return ErrInvalidLengthCaps
397
+			}
398
+			if (iNdEx + skippy) > l {
399
+				return io.ErrUnexpectedEOF
400
+			}
401
+			iNdEx += skippy
402
+		}
403
+	}
404
+
405
+	if iNdEx > l {
406
+		return io.ErrUnexpectedEOF
407
+	}
408
+	return nil
409
+}
410
+func skipCaps(dAtA []byte) (n int, err error) {
411
+	l := len(dAtA)
412
+	iNdEx := 0
413
+	for iNdEx < l {
414
+		var wire uint64
415
+		for shift := uint(0); ; shift += 7 {
416
+			if shift >= 64 {
417
+				return 0, ErrIntOverflowCaps
418
+			}
419
+			if iNdEx >= l {
420
+				return 0, io.ErrUnexpectedEOF
421
+			}
422
+			b := dAtA[iNdEx]
423
+			iNdEx++
424
+			wire |= (uint64(b) & 0x7F) << shift
425
+			if b < 0x80 {
426
+				break
427
+			}
428
+		}
429
+		wireType := int(wire & 0x7)
430
+		switch wireType {
431
+		case 0:
432
+			for shift := uint(0); ; shift += 7 {
433
+				if shift >= 64 {
434
+					return 0, ErrIntOverflowCaps
435
+				}
436
+				if iNdEx >= l {
437
+					return 0, io.ErrUnexpectedEOF
438
+				}
439
+				iNdEx++
440
+				if dAtA[iNdEx-1] < 0x80 {
441
+					break
442
+				}
443
+			}
444
+			return iNdEx, nil
445
+		case 1:
446
+			iNdEx += 8
447
+			return iNdEx, nil
448
+		case 2:
449
+			var length int
450
+			for shift := uint(0); ; shift += 7 {
451
+				if shift >= 64 {
452
+					return 0, ErrIntOverflowCaps
453
+				}
454
+				if iNdEx >= l {
455
+					return 0, io.ErrUnexpectedEOF
456
+				}
457
+				b := dAtA[iNdEx]
458
+				iNdEx++
459
+				length |= (int(b) & 0x7F) << shift
460
+				if b < 0x80 {
461
+					break
462
+				}
463
+			}
464
+			iNdEx += length
465
+			if length < 0 {
466
+				return 0, ErrInvalidLengthCaps
467
+			}
468
+			return iNdEx, nil
469
+		case 3:
470
+			for {
471
+				var innerWire uint64
472
+				var start int = iNdEx
473
+				for shift := uint(0); ; shift += 7 {
474
+					if shift >= 64 {
475
+						return 0, ErrIntOverflowCaps
476
+					}
477
+					if iNdEx >= l {
478
+						return 0, io.ErrUnexpectedEOF
479
+					}
480
+					b := dAtA[iNdEx]
481
+					iNdEx++
482
+					innerWire |= (uint64(b) & 0x7F) << shift
483
+					if b < 0x80 {
484
+						break
485
+					}
486
+				}
487
+				innerWireType := int(innerWire & 0x7)
488
+				if innerWireType == 4 {
489
+					break
490
+				}
491
+				next, err := skipCaps(dAtA[start:])
492
+				if err != nil {
493
+					return 0, err
494
+				}
495
+				iNdEx = start + next
496
+			}
497
+			return iNdEx, nil
498
+		case 4:
499
+			return iNdEx, nil
500
+		case 5:
501
+			iNdEx += 4
502
+			return iNdEx, nil
503
+		default:
504
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
505
+		}
506
+	}
507
+	panic("unreachable")
508
+}
509
+
510
+var (
511
+	ErrInvalidLengthCaps = fmt.Errorf("proto: negative length found during unmarshaling")
512
+	ErrIntOverflowCaps   = fmt.Errorf("proto: integer overflow")
513
+)
514
+
515
+func init() { proto.RegisterFile("caps.proto", fileDescriptorCaps) }
516
+
517
+var fileDescriptorCaps = []byte{
518
+	// 236 bytes of a gzipped FileDescriptorProto
519
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x4e, 0x2c, 0x28,
520
+	0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4, 0x4b, 0x2a, 0xcd,
521
+	0xcc, 0x49, 0xc9, 0xce, 0x2c, 0xd1, 0x2b, 0x33, 0xd4, 0x4b, 0x2c, 0xc8, 0x04, 0xc9, 0x4b, 0xe9,
522
+	0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xa7, 0xe7, 0xeb,
523
+	0x83, 0x35, 0x24, 0x95, 0xa6, 0x81, 0x79, 0x60, 0x0e, 0x98, 0x05, 0x31, 0x48, 0xe9, 0x16, 0x23,
524
+	0x17, 0x9b, 0x63, 0x80, 0xa7, 0x73, 0x62, 0x81, 0x10, 0x1f, 0x17, 0x93, 0xa7, 0x8b, 0x04, 0xa3,
525
+	0x02, 0xa3, 0x06, 0x67, 0x10, 0x93, 0xa7, 0x8b, 0x90, 0x04, 0x17, 0xbb, 0x6b, 0x5e, 0x62, 0x52,
526
+	0x4e, 0x6a, 0x8a, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x8c, 0x2b, 0x24, 0xc7, 0xc5, 0xe5,
527
+	0x92, 0x5a, 0x50, 0x94, 0x9a, 0x9c, 0x58, 0x92, 0x9a, 0x22, 0xc1, 0x0c, 0x96, 0x44, 0x12, 0x11,
528
+	0x52, 0xe3, 0xe2, 0x73, 0xc9, 0x2c, 0x06, 0xab, 0x0d, 0x4a, 0x4d, 0x2c, 0xce, 0xcf, 0x93, 0x60,
529
+	0x01, 0x9b, 0x8a, 0x26, 0x2a, 0xa4, 0xc3, 0x25, 0x88, 0x2a, 0xe2, 0x5b, 0x9c, 0x2e, 0xc1, 0x0a,
530
+	0x56, 0x8a, 0x29, 0x21, 0x64, 0xc0, 0x25, 0x0c, 0x13, 0x74, 0xcc, 0x29, 0x49, 0x2d, 0xca, 0x4b,
531
+	0x2c, 0xc9, 0x2c, 0x4b, 0x95, 0x60, 0x03, 0xab, 0xc7, 0x26, 0xe5, 0xc4, 0x73, 0xe2, 0x91, 0x1c,
532
+	0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x26, 0xb1, 0x81, 0x7d, 0x6c, 0x0c, 0x08,
533
+	0x00, 0x00, 0xff, 0xff, 0x02, 0x2d, 0x9e, 0x91, 0x48, 0x01, 0x00, 0x00,
534
+}
0 535
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+syntax = "proto3";
1
+
2
+package moby.buildkit.v1.apicaps;
3
+
4
+import "github.com/gogo/protobuf/gogoproto/gogo.proto";
5
+
6
+option (gogoproto.sizer_all) = true;
7
+option (gogoproto.marshaler_all) = true;
8
+option (gogoproto.unmarshaler_all) = true;
9
+
10
+// APICap defines a capability supported by the service
11
+message APICap {
12
+	string ID = 1;
13
+	bool Enabled = 2;
14
+	bool Deprecated = 3; // Unused. May be used for warnings in the future
15
+	string DisabledReason = 4; // Reason key for detection code
16
+	string DisabledReasonMsg = 5; // Message to the user
17
+	string DisabledAlternative = 6; // Identifier that updated client could catch.
18
+}
0 19
\ No newline at end of file
1 20
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package moby_buildkit_v1_apicaps
1
+
2
+//go:generate protoc -I=. -I=../../../vendor/ -I=../../../../../../ --gogo_out=plugins=grpc:. caps.proto
... ...
@@ -5,35 +5,28 @@ import (
5 5
 	"io"
6 6
 
7 7
 	"github.com/containerd/containerd/content"
8
-	"github.com/containerd/containerd/errdefs"
9 8
 	"github.com/containerd/containerd/remotes"
10 9
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
11 10
 	"github.com/pkg/errors"
12 11
 )
13 12
 
14
-func FromFetcher(f remotes.Fetcher, desc ocispec.Descriptor) content.Provider {
13
+func FromFetcher(f remotes.Fetcher) content.Provider {
15 14
 	return &fetchedProvider{
16
-		f:    f,
17
-		desc: desc,
15
+		f: f,
18 16
 	}
19 17
 }
20 18
 
21 19
 type fetchedProvider struct {
22
-	f    remotes.Fetcher
23
-	desc ocispec.Descriptor
20
+	f remotes.Fetcher
24 21
 }
25 22
 
26 23
 func (p *fetchedProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
27
-	if desc.Digest != p.desc.Digest {
28
-		return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", desc.Digest)
29
-	}
30
-
31
-	rc, err := p.f.Fetch(ctx, p.desc)
24
+	rc, err := p.f.Fetch(ctx, desc)
32 25
 	if err != nil {
33 26
 		return nil, err
34 27
 	}
35 28
 
36
-	return &readerAt{Reader: rc, Closer: rc, size: p.desc.Size}, nil
29
+	return &readerAt{Reader: rc, Closer: rc, size: desc.Size}, nil
37 30
 }
38 31
 
39 32
 type readerAt struct {
40 33
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+package contentutil
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/containerd/containerd/content"
6
+	"github.com/containerd/containerd/errdefs"
7
+	"github.com/containerd/containerd/remotes"
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+func FromPusher(p remotes.Pusher) content.Ingester {
12
+	return &pushingIngester{
13
+		p: p,
14
+	}
15
+}
16
+
17
+type pushingIngester struct {
18
+	p remotes.Pusher
19
+}
20
+
21
+// Writer implements content.Ingester. desc.MediaType must be set for manifest blobs.
22
+func (i *pushingIngester) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
23
+	var wOpts content.WriterOpts
24
+	for _, opt := range opts {
25
+		if err := opt(&wOpts); err != nil {
26
+			return nil, err
27
+		}
28
+	}
29
+	if wOpts.Ref == "" {
30
+		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
31
+	}
32
+	// pusher requires desc.MediaType to determine the PUT URL, especially for manifest blobs.
33
+	contentWriter, err := i.p.Push(ctx, wOpts.Desc)
34
+	if err != nil {
35
+		return nil, err
36
+	}
37
+	return &writer{
38
+		Writer:           contentWriter,
39
+		contentWriterRef: wOpts.Ref,
40
+	}, nil
41
+}
42
+
43
+type writer struct {
44
+	content.Writer          // returned from pusher.Push
45
+	contentWriterRef string // ref passed for Writer()
46
+}
47
+
48
+func (w *writer) Status() (content.Status, error) {
49
+	st, err := w.Writer.Status()
50
+	if err != nil {
51
+		return st, err
52
+	}
53
+	if w.contentWriterRef != "" {
54
+		st.Ref = w.contentWriterRef
55
+	}
56
+	return st, nil
57
+}
0 58
deleted file mode 100644
... ...
@@ -1 +0,0 @@
1
-Temporary forked from https://github.com/opencontainers/runc/pull/1692
2 1
deleted file mode 100644
... ...
@@ -1,190 +0,0 @@
1
-package specconv
2
-
3
-import (
4
-	"os"
5
-	"sort"
6
-	"strings"
7
-
8
-	"github.com/opencontainers/runc/libcontainer/system"
9
-	"github.com/opencontainers/runc/libcontainer/user"
10
-	"github.com/opencontainers/runtime-spec/specs-go"
11
-)
12
-
13
-// RootlessOpts is an optional spec for ToRootless
14
-type RootlessOpts struct {
15
-	// Add sub{u,g}id to spec.Linux.{U,G}IDMappings.
16
-	// Requires newuidmap(1) and newgidmap(1) with suid bit.
17
-	// Ignored when running in userns.
18
-	MapSubUIDGID bool
19
-}
20
-
21
-// Run-time context for ToRootless.
22
-type RootlessContext struct {
23
-	EUID     uint32
24
-	EGID     uint32
25
-	SubUIDs  []user.SubID
26
-	SubGIDs  []user.SubID
27
-	UIDMap   []user.IDMap
28
-	GIDMap   []user.IDMap
29
-	InUserNS bool
30
-}
31
-
32
-// ToRootless converts the given spec file into one that should work with
33
-// rootless containers, by removing incompatible options and adding others that
34
-// are needed.
35
-func ToRootless(spec *specs.Spec, opts *RootlessOpts) error {
36
-	var err error
37
-	ctx := RootlessContext{}
38
-	ctx.EUID = uint32(os.Geteuid())
39
-	ctx.EGID = uint32(os.Getegid())
40
-	ctx.SubUIDs, err = user.CurrentUserSubUIDs()
41
-	if err != nil && !os.IsNotExist(err) {
42
-		return err
43
-	}
44
-	ctx.SubGIDs, err = user.CurrentGroupSubGIDs()
45
-	if err != nil && !os.IsNotExist(err) {
46
-		return err
47
-	}
48
-	ctx.UIDMap, err = user.CurrentProcessUIDMap()
49
-	if err != nil && !os.IsNotExist(err) {
50
-		return err
51
-	}
52
-	uidMapExists := !os.IsNotExist(err)
53
-	ctx.GIDMap, err = user.CurrentProcessUIDMap()
54
-	if err != nil && !os.IsNotExist(err) {
55
-		return err
56
-	}
57
-	ctx.InUserNS = uidMapExists && system.UIDMapInUserNS(ctx.UIDMap)
58
-	return ToRootlessWithContext(ctx, spec, opts)
59
-}
60
-
61
-// ToRootlessWithContext converts the spec with the run-time context.
62
-// ctx can be internally modified for sorting.
63
-func ToRootlessWithContext(ctx RootlessContext, spec *specs.Spec, opts *RootlessOpts) error {
64
-	if opts == nil {
65
-		opts = &RootlessOpts{}
66
-	}
67
-	var namespaces []specs.LinuxNamespace
68
-
69
-	// Remove networkns from the spec.
70
-	for _, ns := range spec.Linux.Namespaces {
71
-		switch ns.Type {
72
-		case specs.NetworkNamespace, specs.UserNamespace:
73
-			// Do nothing.
74
-		default:
75
-			namespaces = append(namespaces, ns)
76
-		}
77
-	}
78
-	// Add userns to the spec.
79
-	namespaces = append(namespaces, specs.LinuxNamespace{
80
-		Type: specs.UserNamespace,
81
-	})
82
-	spec.Linux.Namespaces = namespaces
83
-
84
-	// Add mappings for the current user.
85
-	if ctx.InUserNS {
86
-		uNextContainerID := int64(0)
87
-		sort.Sort(idmapSorter(ctx.UIDMap))
88
-		for _, uidmap := range ctx.UIDMap {
89
-			spec.Linux.UIDMappings = append(spec.Linux.UIDMappings,
90
-				specs.LinuxIDMapping{
91
-					HostID:      uint32(uidmap.ID),
92
-					ContainerID: uint32(uNextContainerID),
93
-					Size:        uint32(uidmap.Count),
94
-				})
95
-			uNextContainerID += uidmap.Count
96
-		}
97
-		gNextContainerID := int64(0)
98
-		sort.Sort(idmapSorter(ctx.GIDMap))
99
-		for _, gidmap := range ctx.GIDMap {
100
-			spec.Linux.GIDMappings = append(spec.Linux.GIDMappings,
101
-				specs.LinuxIDMapping{
102
-					HostID:      uint32(gidmap.ID),
103
-					ContainerID: uint32(gNextContainerID),
104
-					Size:        uint32(gidmap.Count),
105
-				})
106
-			gNextContainerID += gidmap.Count
107
-		}
108
-		// opts.MapSubUIDGID is ignored in userns
109
-	} else {
110
-		spec.Linux.UIDMappings = []specs.LinuxIDMapping{{
111
-			HostID:      ctx.EUID,
112
-			ContainerID: 0,
113
-			Size:        1,
114
-		}}
115
-		spec.Linux.GIDMappings = []specs.LinuxIDMapping{{
116
-			HostID:      ctx.EGID,
117
-			ContainerID: 0,
118
-			Size:        1,
119
-		}}
120
-		if opts.MapSubUIDGID {
121
-			uNextContainerID := int64(1)
122
-			sort.Sort(subIDSorter(ctx.SubUIDs))
123
-			for _, subuid := range ctx.SubUIDs {
124
-				spec.Linux.UIDMappings = append(spec.Linux.UIDMappings,
125
-					specs.LinuxIDMapping{
126
-						HostID:      uint32(subuid.SubID),
127
-						ContainerID: uint32(uNextContainerID),
128
-						Size:        uint32(subuid.Count),
129
-					})
130
-				uNextContainerID += subuid.Count
131
-			}
132
-			gNextContainerID := int64(1)
133
-			sort.Sort(subIDSorter(ctx.SubGIDs))
134
-			for _, subgid := range ctx.SubGIDs {
135
-				spec.Linux.GIDMappings = append(spec.Linux.GIDMappings,
136
-					specs.LinuxIDMapping{
137
-						HostID:      uint32(subgid.SubID),
138
-						ContainerID: uint32(gNextContainerID),
139
-						Size:        uint32(subgid.Count),
140
-					})
141
-				gNextContainerID += subgid.Count
142
-			}
143
-		}
144
-	}
145
-
146
-	// Fix up mounts.
147
-	var mounts []specs.Mount
148
-	for _, mount := range spec.Mounts {
149
-		// Ignore all mounts that are under /sys.
150
-		if strings.HasPrefix(mount.Destination, "/sys") {
151
-			continue
152
-		}
153
-
154
-		// Remove all gid= and uid= mappings.
155
-		var options []string
156
-		for _, option := range mount.Options {
157
-			if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
158
-				options = append(options, option)
159
-			}
160
-		}
161
-
162
-		mount.Options = options
163
-		mounts = append(mounts, mount)
164
-	}
165
-	// Add the sysfs mount as an rbind.
166
-	mounts = append(mounts, specs.Mount{
167
-		Source:      "/sys",
168
-		Destination: "/sys",
169
-		Type:        "none",
170
-		Options:     []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
171
-	})
172
-	spec.Mounts = mounts
173
-
174
-	// Remove cgroup settings.
175
-	spec.Linux.Resources = nil
176
-	return nil
177
-}
178
-
179
-// subIDSorter is required for Go <= 1.7
180
-type subIDSorter []user.SubID
181
-
182
-func (x subIDSorter) Len() int           { return len(x) }
183
-func (x subIDSorter) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
184
-func (x subIDSorter) Less(i, j int) bool { return x[i].SubID < x[j].SubID }
185
-
186
-type idmapSorter []user.IDMap
187
-
188
-func (x idmapSorter) Len() int           { return len(x) }
189
-func (x idmapSorter) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
190
-func (x idmapSorter) Less(i, j int) bool { return x[i].ID < x[j].ID }
191 1
deleted file mode 100644
... ...
@@ -1,184 +0,0 @@
1
-package push
2
-
3
-import (
4
-	"context"
5
-	"encoding/json"
6
-	"fmt"
7
-	"sync"
8
-	"time"
9
-
10
-	"github.com/containerd/containerd/content"
11
-	"github.com/containerd/containerd/images"
12
-	"github.com/containerd/containerd/remotes"
13
-	"github.com/containerd/containerd/remotes/docker"
14
-	"github.com/docker/distribution/reference"
15
-	"github.com/moby/buildkit/session"
16
-	"github.com/moby/buildkit/session/auth"
17
-	"github.com/moby/buildkit/util/imageutil"
18
-	"github.com/moby/buildkit/util/progress"
19
-	"github.com/moby/buildkit/util/tracing"
20
-	digest "github.com/opencontainers/go-digest"
21
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
22
-	"github.com/sirupsen/logrus"
23
-)
24
-
25
-func getCredentialsFunc(ctx context.Context, sm *session.Manager) func(string) (string, string, error) {
26
-	id := session.FromContext(ctx)
27
-	if id == "" {
28
-		return nil
29
-	}
30
-	return func(host string) (string, string, error) {
31
-		timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
32
-		defer cancel()
33
-
34
-		caller, err := sm.Get(timeoutCtx, id)
35
-		if err != nil {
36
-			return "", "", err
37
-		}
38
-
39
-		return auth.CredentialsFunc(context.TODO(), caller)(host)
40
-	}
41
-}
42
-
43
-func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst digest.Digest, ref string, insecure bool) error {
44
-	desc := ocispec.Descriptor{
45
-		Digest: dgst,
46
-	}
47
-	parsed, err := reference.ParseNormalizedNamed(ref)
48
-	if err != nil {
49
-		return err
50
-	}
51
-	ref = reference.TagNameOnly(parsed).String()
52
-
53
-	resolver := docker.NewResolver(docker.ResolverOptions{
54
-		Client:      tracing.DefaultClient,
55
-		Credentials: getCredentialsFunc(ctx, sm),
56
-		PlainHTTP:   insecure,
57
-	})
58
-
59
-	pusher, err := resolver.Pusher(ctx, ref)
60
-	if err != nil {
61
-		return err
62
-	}
63
-
64
-	var m sync.Mutex
65
-	manifestStack := []ocispec.Descriptor{}
66
-
67
-	filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
68
-		switch desc.MediaType {
69
-		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
70
-			images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
71
-			m.Lock()
72
-			manifestStack = append(manifestStack, desc)
73
-			m.Unlock()
74
-			return nil, images.ErrStopHandler
75
-		default:
76
-			return nil, nil
77
-		}
78
-	})
79
-
80
-	pushHandler := remotes.PushHandler(pusher, cs)
81
-
82
-	handlers := append([]images.Handler{},
83
-		childrenHandler(cs),
84
-		filterHandler,
85
-		pushHandler,
86
-	)
87
-
88
-	ra, err := cs.ReaderAt(ctx, desc)
89
-	if err != nil {
90
-		return err
91
-	}
92
-
93
-	mtype, err := imageutil.DetectManifestMediaType(ra)
94
-	if err != nil {
95
-		return err
96
-	}
97
-
98
-	layersDone := oneOffProgress(ctx, "pushing layers")
99
-	err = images.Dispatch(ctx, images.Handlers(handlers...), ocispec.Descriptor{
100
-		Digest:    dgst,
101
-		Size:      ra.Size(),
102
-		MediaType: mtype,
103
-	})
104
-	layersDone(err)
105
-	if err != nil {
106
-		return err
107
-	}
108
-
109
-	mfstDone := oneOffProgress(ctx, fmt.Sprintf("pushing manifest for %s", ref))
110
-	for i := len(manifestStack) - 1; i >= 0; i-- {
111
-		_, err := pushHandler(ctx, manifestStack[i])
112
-		if err != nil {
113
-			mfstDone(err)
114
-			return err
115
-		}
116
-	}
117
-	mfstDone(nil)
118
-	return nil
119
-}
120
-
121
-func oneOffProgress(ctx context.Context, id string) func(err error) error {
122
-	pw, _, _ := progress.FromContext(ctx)
123
-	now := time.Now()
124
-	st := progress.Status{
125
-		Started: &now,
126
-	}
127
-	pw.Write(id, st)
128
-	return func(err error) error {
129
-		// TODO: set error on status
130
-		now := time.Now()
131
-		st.Completed = &now
132
-		pw.Write(id, st)
133
-		pw.Close()
134
-		return err
135
-	}
136
-}
137
-
138
-func childrenHandler(provider content.Provider) images.HandlerFunc {
139
-	return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
140
-		var descs []ocispec.Descriptor
141
-		switch desc.MediaType {
142
-		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
143
-			p, err := content.ReadBlob(ctx, provider, desc)
144
-			if err != nil {
145
-				return nil, err
146
-			}
147
-
148
-			// TODO(stevvooe): We just assume oci manifest, for now. There may be
149
-			// subtle differences from the docker version.
150
-			var manifest ocispec.Manifest
151
-			if err := json.Unmarshal(p, &manifest); err != nil {
152
-				return nil, err
153
-			}
154
-
155
-			descs = append(descs, manifest.Config)
156
-			descs = append(descs, manifest.Layers...)
157
-		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
158
-			p, err := content.ReadBlob(ctx, provider, desc)
159
-			if err != nil {
160
-				return nil, err
161
-			}
162
-
163
-			var index ocispec.Index
164
-			if err := json.Unmarshal(p, &index); err != nil {
165
-				return nil, err
166
-			}
167
-
168
-			for _, m := range index.Manifests {
169
-				if m.Digest != "" {
170
-					descs = append(descs, m)
171
-				}
172
-			}
173
-		case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip,
174
-			images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
175
-			ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip:
176
-			// childless data types.
177
-			return nil, nil
178
-		default:
179
-			logrus.Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType)
180
-		}
181
-
182
-		return descs, nil
183
-	}
184
-}
185 1
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+package specconv
1
+
2
+import (
3
+	"os"
4
+	"sort"
5
+	"strings"
6
+
7
+	"github.com/opencontainers/runc/libcontainer/system"
8
+	"github.com/opencontainers/runc/libcontainer/user"
9
+	"github.com/opencontainers/runtime-spec/specs-go"
10
+	"github.com/pkg/errors"
11
+)
12
+
13
+// ToRootless converts spec to be compatible with "rootless" runc.
14
+// * Adds userns (Note: since we are already in userns, ideally we should not need to do this. runc-side issue is tracked at https://github.com/opencontainers/runc/issues/1837)
15
+// * Fix up mount flags (same as above)
16
+// * Replace /sys with bind-mount (FIXME: we don't need to do this if netns is unshared)
17
+func ToRootless(spec *specs.Spec) error {
18
+	if !system.RunningInUserNS() {
19
+		return errors.New("needs to be in user namespace")
20
+	}
21
+	uidMap, err := user.CurrentProcessUIDMap()
22
+	if err != nil && !os.IsNotExist(err) {
23
+		return err
24
+	}
25
+	gidMap, err := user.CurrentProcessUIDMap()
26
+	if err != nil && !os.IsNotExist(err) {
27
+		return err
28
+	}
29
+	return toRootless(spec, uidMap, gidMap)
30
+}
31
+
32
+// toRootless was forked from github.com/opencontainers/runc/libcontainer/specconv
33
+func toRootless(spec *specs.Spec, uidMap, gidMap []user.IDMap) error {
34
+	if err := configureUserNS(spec, uidMap, gidMap); err != nil {
35
+		return err
36
+	}
37
+	if err := configureMounts(spec); err != nil {
38
+		return err
39
+	}
40
+
41
+	// Remove cgroup settings.
42
+	spec.Linux.Resources = nil
43
+	spec.Linux.CgroupsPath = ""
44
+	return nil
45
+}
46
+
47
+// configureUserNS add suserns and the current ID map to the spec.
48
+// Since we are already in userns, ideally we should not need to add userns.
49
+// However, currently rootless runc always requires userns to be added.
50
+// https://github.com/opencontainers/runc/issues/1837
51
+func configureUserNS(spec *specs.Spec, uidMap, gidMap []user.IDMap) error {
52
+	spec.Linux.Namespaces = append(spec.Linux.Namespaces, specs.LinuxNamespace{
53
+		Type: specs.UserNamespace,
54
+	})
55
+
56
+	sort.Slice(uidMap, func(i, j int) bool { return uidMap[i].ID < uidMap[j].ID })
57
+	uNextContainerID := int64(0)
58
+	for _, u := range uidMap {
59
+		spec.Linux.UIDMappings = append(spec.Linux.UIDMappings,
60
+			specs.LinuxIDMapping{
61
+				HostID:      uint32(u.ID),
62
+				ContainerID: uint32(uNextContainerID),
63
+				Size:        uint32(u.Count),
64
+			})
65
+		uNextContainerID += int64(u.Count)
66
+	}
67
+	sort.Slice(gidMap, func(i, j int) bool { return gidMap[i].ID < gidMap[j].ID })
68
+	gNextContainerID := int64(0)
69
+	for _, g := range gidMap {
70
+		spec.Linux.GIDMappings = append(spec.Linux.GIDMappings,
71
+			specs.LinuxIDMapping{
72
+				HostID:      uint32(g.ID),
73
+				ContainerID: uint32(gNextContainerID),
74
+				Size:        uint32(g.Count),
75
+			})
76
+		gNextContainerID += int64(g.Count)
77
+	}
78
+	return nil
79
+}
80
+
81
+func configureMounts(spec *specs.Spec) error {
82
+	var mounts []specs.Mount
83
+	for _, mount := range spec.Mounts {
84
+		// Ignore all mounts that are under /sys, because we add /sys later.
85
+		if strings.HasPrefix(mount.Destination, "/sys") {
86
+			continue
87
+		}
88
+
89
+		// Remove all gid= and uid= mappings.
90
+		// Since we are already in userns, ideally we should not need to do this.
91
+		// https://github.com/opencontainers/runc/issues/1837
92
+		var options []string
93
+		for _, option := range mount.Options {
94
+			if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
95
+				options = append(options, option)
96
+			}
97
+		}
98
+		mount.Options = options
99
+		mounts = append(mounts, mount)
100
+	}
101
+
102
+	// Add the sysfs mount as an rbind, because we can't mount /sys unless we have netns.
103
+	// TODO: keep original /sys mount when we have netns.
104
+	mounts = append(mounts, specs.Mount{
105
+		Source:      "/sys",
106
+		Destination: "/sys",
107
+		Type:        "none",
108
+		Options:     []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
109
+	})
110
+	spec.Mounts = mounts
111
+	return nil
112
+}
... ...
@@ -6,8 +6,8 @@ github.com/davecgh/go-spew v1.1.0
6 6
 github.com/pmezard/go-difflib v1.0.0
7 7
 golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993
8 8
 
9
-github.com/containerd/containerd 08f7ee9828af1783dc98cc5cc1739e915697c667
10
-github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
9
+github.com/containerd/containerd b41633746ed4833f52c3c071e8edcfa2713e5677
10
+github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
11 11
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
12 12
 github.com/sirupsen/logrus v1.0.0
13 13
 google.golang.org/grpc v1.12.0
... ...
@@ -23,7 +23,7 @@ github.com/Microsoft/go-winio v0.4.7
23 23
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
24 24
 github.com/opencontainers/runtime-spec v1.0.1
25 25
 github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
26
-github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08
26
+github.com/containerd/console 5d1b48d6114b8c9666f0c8b916f871af97b0a761
27 27
 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
28 28
 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
29 29
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
... ...
@@ -46,7 +46,7 @@ github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b
46 46
 github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
47 47
 github.com/docker/distribution 30578ca32960a4d368bf6db67b0a33c2a1f3dc6f
48 48
 
49
-github.com/tonistiigi/units 29de085e9400559bd68aea2e7bc21566e7b8281d
49
+github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
50 50
 github.com/docker/cli 99576756eb3303b7af8102c502f21a912e3c1af6 https://github.com/tonistiigi/docker-cli.git
51 51
 github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
52 52
 github.com/docker/libnetwork 822e5b59d346b7ad0735df2c8e445e9787320e67
... ...
@@ -60,8 +60,10 @@ github.com/uber/jaeger-lib c48167d9cae5887393dd5e61efd06a4a48b7fbb3
60 60
 github.com/codahale/hdrhistogram f8ad88b59a584afeee9d334eff879b104439117b
61 61
 
62 62
 github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc
63
-github.com/opencontainers/selinux 74a747aeaf2d66097b6908f572794f49f07dda2c
64 63
 
65 64
 # used by dockerfile tests
66 65
 gotest.tools v2.1.0
67 66
 github.com/google/go-cmp v0.2.0
67
+
68
+# used by rootless spec conv test
69
+github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"sync"
5 5
 
6 6
 	"github.com/containerd/containerd/filters"
7
+	"github.com/moby/buildkit/client"
7 8
 	"github.com/pkg/errors"
8 9
 )
9 10
 
... ...
@@ -58,3 +59,19 @@ func (c *Controller) Get(id string) (Worker, error) {
58 58
 }
59 59
 
60 60
 // TODO: add Get(Constraint) (*Worker, error)
61
+
62
+func (c *Controller) WorkerInfos() []client.WorkerInfo {
63
+	workers, err := c.List()
64
+	if err != nil {
65
+		return nil
66
+	}
67
+	out := make([]client.WorkerInfo, 0, len(workers))
68
+	for _, w := range workers {
69
+		out = append(out, client.WorkerInfo{
70
+			ID:        w.ID(),
71
+			Labels:    w.Labels(),
72
+			Platforms: w.Platforms(),
73
+		})
74
+	}
75
+	return out
76
+}