Browse code

vendor: update buildkit to cce2080ddb

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2018/06/27 02:59:57
Showing 38 changed files
... ...
@@ -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 dbf67a691ce77023a0a5ce9b005298631f8bbb4e
29
+github.com/moby/buildkit cce2080ddbe4698912f2290892b247c83627efa8
30 30
 github.com/tonistiigi/fsutil 8abad97ee3969cdf5e9c367f46adba2c212b3ddb
31 31
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
32 32
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -542,8 +542,9 @@ func (m *ListWorkersResponse) GetRecord() []*WorkerRecord {
542 542
 }
543 543
 
544 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"`
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"`
547 548
 }
548 549
 
549 550
 func (m *WorkerRecord) Reset()                    { *m = WorkerRecord{} }
... ...
@@ -565,6 +566,13 @@ func (m *WorkerRecord) GetLabels() map[string]string {
565 565
 	return nil
566 566
 }
567 567
 
568
+func (m *WorkerRecord) GetPlatforms() []pb.Platform {
569
+	if m != nil {
570
+		return m.Platforms
571
+	}
572
+	return nil
573
+}
574
+
568 575
 func init() {
569 576
 	proto.RegisterType((*PruneRequest)(nil), "moby.buildkit.v1.PruneRequest")
570 577
 	proto.RegisterType((*DiskUsageRequest)(nil), "moby.buildkit.v1.DiskUsageRequest")
... ...
@@ -1650,6 +1658,18 @@ func (m *WorkerRecord) MarshalTo(dAtA []byte) (int, error) {
1650 1650
 			i += copy(dAtA[i:], v)
1651 1651
 		}
1652 1652
 	}
1653
+	if len(m.Platforms) > 0 {
1654
+		for _, msg := range m.Platforms {
1655
+			dAtA[i] = 0x1a
1656
+			i++
1657
+			i = encodeVarintControl(dAtA, i, uint64(msg.Size()))
1658
+			n, err := msg.MarshalTo(dAtA[i:])
1659
+			if err != nil {
1660
+				return 0, err
1661
+			}
1662
+			i += n
1663
+		}
1664
+	}
1653 1665
 	return i, nil
1654 1666
 }
1655 1667
 
... ...
@@ -1979,6 +1999,12 @@ func (m *WorkerRecord) Size() (n int) {
1979 1979
 			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
1980 1980
 		}
1981 1981
 	}
1982
+	if len(m.Platforms) > 0 {
1983
+		for _, e := range m.Platforms {
1984
+			l = e.Size()
1985
+			n += 1 + l + sovControl(uint64(l))
1986
+		}
1987
+	}
1982 1988
 	return n
1983 1989
 }
1984 1990
 
... ...
@@ -4663,6 +4689,37 @@ func (m *WorkerRecord) Unmarshal(dAtA []byte) error {
4663 4663
 			}
4664 4664
 			m.Labels[mapkey] = mapvalue
4665 4665
 			iNdEx = postIndex
4666
+		case 3:
4667
+			if wireType != 2 {
4668
+				return fmt.Errorf("proto: wrong wireType = %d for field Platforms", wireType)
4669
+			}
4670
+			var msglen int
4671
+			for shift := uint(0); ; shift += 7 {
4672
+				if shift >= 64 {
4673
+					return ErrIntOverflowControl
4674
+				}
4675
+				if iNdEx >= l {
4676
+					return io.ErrUnexpectedEOF
4677
+				}
4678
+				b := dAtA[iNdEx]
4679
+				iNdEx++
4680
+				msglen |= (int(b) & 0x7F) << shift
4681
+				if b < 0x80 {
4682
+					break
4683
+				}
4684
+			}
4685
+			if msglen < 0 {
4686
+				return ErrInvalidLengthControl
4687
+			}
4688
+			postIndex := iNdEx + msglen
4689
+			if postIndex > l {
4690
+				return io.ErrUnexpectedEOF
4691
+			}
4692
+			m.Platforms = append(m.Platforms, pb.Platform{})
4693
+			if err := m.Platforms[len(m.Platforms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
4694
+				return err
4695
+			}
4696
+			iNdEx = postIndex
4666 4697
 		default:
4667 4698
 			iNdEx = preIndex
4668 4699
 			skippy, err := skipControl(dAtA[iNdEx:])
... ...
@@ -4792,80 +4849,81 @@ var (
4792 4792
 func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
4793 4793
 
4794 4794
 var fileDescriptorControl = []byte{
4795
-	// 1192 bytes of a gzipped FileDescriptorProto
4796
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcd, 0x6e, 0x23, 0x45,
4797
-	0x10, 0x66, 0x6c, 0xc7, 0x3f, 0x65, 0x27, 0x0a, 0x0d, 0xac, 0x46, 0x03, 0x24, 0x66, 0x00, 0xc9,
4798
-	0x8a, 0x76, 0xc7, 0xd9, 0xc0, 0x22, 0xc8, 0x61, 0xb5, 0xeb, 0x78, 0x11, 0x89, 0x12, 0xb1, 0x74,
4799
-	0x36, 0xac, 0xc4, 0x6d, 0x6c, 0x77, 0xbc, 0xa3, 0xd8, 0xd3, 0xa6, 0xbb, 0x27, 0xda, 0xf0, 0x14,
4800
-	0x1c, 0xb8, 0xf2, 0x14, 0x1c, 0x38, 0x73, 0x40, 0xda, 0x23, 0x67, 0x0e, 0x59, 0x94, 0x3b, 0x3c,
4801
-	0x03, 0xea, 0x9f, 0xb1, 0xdb, 0x1e, 0xe7, 0xc7, 0xd9, 0x53, 0xba, 0x3a, 0x5f, 0x7d, 0x53, 0x5d,
4802
-	0x5f, 0xb9, 0xaa, 0x60, 0xb9, 0x4b, 0x63, 0xc1, 0xe8, 0x20, 0x18, 0x31, 0x2a, 0x28, 0x5a, 0x1d,
4803
-	0xd2, 0xce, 0x59, 0xd0, 0x49, 0xa2, 0x41, 0xef, 0x24, 0x12, 0xc1, 0xe9, 0x7d, 0xef, 0x5e, 0x3f,
4804
-	0x12, 0x2f, 0x92, 0x4e, 0xd0, 0xa5, 0xc3, 0x66, 0x9f, 0xf6, 0x69, 0x53, 0x01, 0x3b, 0xc9, 0xb1,
4805
-	0xb2, 0x94, 0xa1, 0x4e, 0x9a, 0xc0, 0x5b, 0xef, 0x53, 0xda, 0x1f, 0x90, 0x09, 0x4a, 0x44, 0x43,
4806
-	0xc2, 0x45, 0x38, 0x1c, 0x19, 0xc0, 0x5d, 0x8b, 0x4f, 0x7e, 0xac, 0x99, 0x7e, 0xac, 0xc9, 0xe9,
4807
-	0xe0, 0x94, 0xb0, 0xe6, 0xa8, 0xd3, 0xa4, 0x23, 0xae, 0xd1, 0xfe, 0x0a, 0xd4, 0x9e, 0xb2, 0x24,
4808
-	0x26, 0x98, 0xfc, 0x98, 0x10, 0x2e, 0xfc, 0x0d, 0x58, 0x6d, 0x47, 0xfc, 0xe4, 0x88, 0x87, 0xfd,
4809
-	0xf4, 0x0e, 0xdd, 0x81, 0xe2, 0x71, 0x34, 0x10, 0x84, 0xb9, 0x4e, 0xdd, 0x69, 0x54, 0xb0, 0xb1,
4810
-	0xfc, 0x3d, 0x78, 0xdb, 0xc2, 0xf2, 0x11, 0x8d, 0x39, 0x41, 0x0f, 0xa0, 0xc8, 0x48, 0x97, 0xb2,
4811
-	0x9e, 0xeb, 0xd4, 0xf3, 0x8d, 0xea, 0xd6, 0x87, 0xc1, 0xec, 0x8b, 0x03, 0xe3, 0x20, 0x41, 0xd8,
4812
-	0x80, 0xfd, 0x3f, 0x72, 0x50, 0xb5, 0xee, 0xd1, 0x0a, 0xe4, 0x76, 0xdb, 0xe6, 0x7b, 0xb9, 0xdd,
4813
-	0x36, 0x72, 0xa1, 0x74, 0x90, 0x88, 0xb0, 0x33, 0x20, 0x6e, 0xae, 0xee, 0x34, 0xca, 0x38, 0x35,
4814
-	0xd1, 0xbb, 0xb0, 0xb4, 0x1b, 0x1f, 0x71, 0xe2, 0xe6, 0xd5, 0xbd, 0x36, 0x10, 0x82, 0xc2, 0x61,
4815
-	0xf4, 0x13, 0x71, 0x0b, 0x75, 0xa7, 0x91, 0xc7, 0xea, 0x2c, 0xdf, 0xf1, 0x34, 0x64, 0x24, 0x16,
4816
-	0xee, 0x92, 0x7e, 0x87, 0xb6, 0x50, 0x0b, 0x2a, 0x3b, 0x8c, 0x84, 0x82, 0xf4, 0x1e, 0x0b, 0xb7,
4817
-	0x58, 0x77, 0x1a, 0xd5, 0x2d, 0x2f, 0xd0, 0x69, 0x0e, 0xd2, 0x34, 0x07, 0xcf, 0xd2, 0x34, 0xb7,
4818
-	0xca, 0xaf, 0xce, 0xd7, 0xdf, 0xfa, 0xf9, 0xf5, 0xba, 0x83, 0x27, 0x6e, 0xe8, 0x11, 0xc0, 0x7e,
4819
-	0xc8, 0xc5, 0x11, 0x57, 0x24, 0xa5, 0x6b, 0x49, 0x0a, 0x8a, 0xc0, 0xf2, 0x41, 0x6b, 0x00, 0x2a,
4820
-	0x01, 0x3b, 0x34, 0x89, 0x85, 0x5b, 0x56, 0x71, 0x5b, 0x37, 0xa8, 0x0e, 0xd5, 0x36, 0xe1, 0x5d,
4821
-	0x16, 0x8d, 0x44, 0x44, 0x63, 0xb7, 0xa2, 0x9e, 0x60, 0x5f, 0xf9, 0xbf, 0x14, 0xa0, 0x76, 0x28,
4822
-	0x35, 0x4e, 0x85, 0x5b, 0x85, 0x3c, 0x26, 0xc7, 0x26, 0x8b, 0xf2, 0x88, 0x02, 0x80, 0x36, 0x39,
4823
-	0x8e, 0xe2, 0x48, 0x71, 0xe4, 0x54, 0x98, 0x2b, 0xc1, 0xa8, 0x13, 0x4c, 0x6e, 0xb1, 0x85, 0x40,
4824
-	0x1e, 0x94, 0x9f, 0xbc, 0x1c, 0x51, 0x26, 0xc5, 0xcf, 0x2b, 0x9a, 0xb1, 0x8d, 0x9e, 0xc3, 0x72,
4825
-	0x7a, 0x7e, 0x2c, 0x04, 0xe3, 0x6e, 0x41, 0x09, 0x7e, 0x3f, 0x2b, 0xb8, 0x1d, 0x54, 0x30, 0xe5,
4826
-	0xf3, 0x24, 0x16, 0xec, 0x0c, 0x4f, 0xf3, 0x48, 0xad, 0x0f, 0x09, 0xe7, 0x32, 0x42, 0x2d, 0x54,
4827
-	0x6a, 0xca, 0x70, 0xbe, 0x66, 0x34, 0x16, 0x24, 0xee, 0x29, 0xa1, 0x2a, 0x78, 0x6c, 0xcb, 0x70,
4828
-	0xd2, 0xb3, 0x0e, 0xa7, 0x74, 0xa3, 0x70, 0xa6, 0x7c, 0x4c, 0x38, 0x53, 0x77, 0x68, 0x1b, 0x96,
4829
-	0x76, 0xc2, 0xee, 0x0b, 0xa2, 0x34, 0xa9, 0x6e, 0xad, 0x65, 0x09, 0xd5, 0xbf, 0xbf, 0x55, 0x22,
4830
-	0xf0, 0x56, 0x41, 0x96, 0x07, 0xd6, 0x2e, 0xde, 0x23, 0x40, 0xd9, 0xf7, 0x4a, 0x5d, 0x4e, 0xc8,
4831
-	0x59, 0xaa, 0xcb, 0x09, 0x39, 0x93, 0x45, 0x7c, 0x1a, 0x0e, 0x12, 0x5d, 0xdc, 0x15, 0xac, 0x8d,
4832
-	0xed, 0xdc, 0x97, 0x8e, 0x64, 0xc8, 0x86, 0xb8, 0x08, 0x83, 0xff, 0xda, 0x81, 0x9a, 0x1d, 0x21,
4833
-	0xfa, 0x00, 0x2a, 0x3a, 0xa8, 0x49, 0x71, 0x4c, 0x2e, 0x64, 0x1d, 0xee, 0x0e, 0x8d, 0xc1, 0xdd,
4834
-	0x5c, 0x3d, 0xdf, 0xa8, 0x60, 0xeb, 0x06, 0x7d, 0x07, 0x55, 0x0d, 0xd6, 0x59, 0xce, 0xab, 0x2c,
4835
-	0x37, 0xaf, 0x4e, 0x4a, 0x60, 0x79, 0xe8, 0x1c, 0xdb, 0x1c, 0xde, 0x43, 0x58, 0x9d, 0x05, 0x2c,
4836
-	0xf4, 0xc2, 0xdf, 0x1d, 0x58, 0x36, 0xa2, 0x9a, 0x2e, 0x14, 0xa6, 0x8c, 0x84, 0xa5, 0x77, 0xa6,
4837
-	0x1f, 0x3d, 0xb8, 0xb4, 0x1e, 0x34, 0x2c, 0x98, 0xf5, 0xd3, 0xf1, 0x66, 0xe8, 0xbc, 0x1d, 0x78,
4838
-	0x6f, 0x2e, 0x74, 0xa1, 0xc8, 0x3f, 0x82, 0xe5, 0x43, 0x11, 0x8a, 0x84, 0x5f, 0xfa, 0x93, 0xf5,
4839
-	0x7f, 0x73, 0x60, 0x25, 0xc5, 0x98, 0xd7, 0x7d, 0x0e, 0xe5, 0x53, 0xc2, 0x04, 0x79, 0x49, 0xb8,
4840
-	0x79, 0x95, 0x9b, 0x7d, 0xd5, 0xf7, 0x0a, 0x81, 0xc7, 0x48, 0xb4, 0x0d, 0x65, 0xae, 0x78, 0x88,
4841
-	0x96, 0x75, 0x6e, 0x29, 0x6b, 0x2f, 0xf3, 0xbd, 0x31, 0x1e, 0x35, 0xa1, 0x30, 0xa0, 0xfd, 0x54,
4842
-	0xed, 0xf7, 0x2f, 0xf3, 0xdb, 0xa7, 0x7d, 0xac, 0x80, 0xfe, 0x79, 0x0e, 0x8a, 0xfa, 0x0e, 0xed,
4843
-	0x41, 0xb1, 0x17, 0xf5, 0x09, 0x17, 0xfa, 0x55, 0xad, 0x2d, 0xf9, 0x03, 0xf9, 0xfb, 0x7c, 0x7d,
4844
-	0xc3, 0x1a, 0x54, 0x74, 0x44, 0x62, 0x39, 0x28, 0xc3, 0x28, 0x26, 0x8c, 0x37, 0xfb, 0xf4, 0x9e,
4845
-	0x76, 0x09, 0xda, 0xea, 0x0f, 0x36, 0x0c, 0x92, 0x2b, 0x8a, 0x47, 0x89, 0x30, 0x85, 0x79, 0x3b,
4846
-	0x2e, 0xcd, 0x20, 0x47, 0x44, 0x1c, 0x0e, 0x89, 0xe9, 0x6b, 0xea, 0x2c, 0x47, 0x44, 0x57, 0xd6,
4847
-	0x6d, 0x4f, 0x0d, 0x8e, 0x32, 0x36, 0x16, 0xda, 0x86, 0x12, 0x17, 0x21, 0x13, 0xa4, 0xa7, 0x5a,
4848
-	0xd2, 0x4d, 0x7a, 0x7b, 0xea, 0x80, 0x1e, 0x42, 0xa5, 0x4b, 0x87, 0xa3, 0x01, 0x91, 0xde, 0xc5,
4849
-	0x1b, 0x7a, 0x4f, 0x5c, 0x64, 0xf5, 0x10, 0xc6, 0x28, 0x53, 0x53, 0xa5, 0x82, 0xb5, 0xe1, 0xff,
4850
-	0x97, 0x83, 0x9a, 0x2d, 0x56, 0x66, 0x62, 0xee, 0x41, 0x51, 0x4b, 0xaf, 0xab, 0xee, 0x76, 0xa9,
4851
-	0xd2, 0x0c, 0x73, 0x53, 0xe5, 0x42, 0xa9, 0x9b, 0x30, 0x35, 0x4e, 0xf5, 0x90, 0x4d, 0x4d, 0x19,
4852
-	0xb0, 0xa0, 0x22, 0x1c, 0xa8, 0x54, 0xe5, 0xb1, 0x36, 0xe4, 0x94, 0x1d, 0xaf, 0x2a, 0x8b, 0x4d,
4853
-	0xd9, 0xb1, 0x9b, 0x2d, 0x43, 0xe9, 0x8d, 0x64, 0x28, 0x2f, 0x2c, 0x83, 0xff, 0xa7, 0x03, 0x95,
4854
-	0x71, 0x95, 0x5b, 0xd9, 0x75, 0xde, 0x38, 0xbb, 0x53, 0x99, 0xc9, 0xdd, 0x2e, 0x33, 0x77, 0xa0,
4855
-	0xc8, 0x05, 0x23, 0xe1, 0x50, 0x69, 0x94, 0xc7, 0xc6, 0x92, 0xfd, 0x64, 0xc8, 0xfb, 0x4a, 0xa1,
4856
-	0x1a, 0x96, 0x47, 0xdf, 0x87, 0x5a, 0xeb, 0x4c, 0x10, 0x7e, 0x40, 0xb8, 0x5c, 0x2e, 0xa4, 0xb6,
4857
-	0xbd, 0x50, 0x84, 0xea, 0x1d, 0x35, 0xac, 0xce, 0xfe, 0x5d, 0x40, 0xfb, 0x11, 0x17, 0xcf, 0x29,
4858
-	0x3b, 0x21, 0x8c, 0xcf, 0xdb, 0x03, 0xf3, 0xd6, 0x1e, 0x78, 0x00, 0xef, 0x4c, 0xa1, 0x4d, 0x97,
4859
-	0xfa, 0x62, 0x66, 0x13, 0x9c, 0xd3, 0x6d, 0xb4, 0xcb, 0xcc, 0x2a, 0xf8, 0xab, 0x03, 0x35, 0xfb,
4860
-	0x1f, 0x99, 0xca, 0x6e, 0x41, 0x71, 0x3f, 0xec, 0x90, 0x41, 0xda, 0xc6, 0x36, 0xae, 0x26, 0x0e,
4861
-	0x34, 0x58, 0xf7, 0x71, 0xe3, 0xe9, 0x7d, 0x05, 0x55, 0xeb, 0x7a, 0x91, 0x9e, 0xbd, 0xf5, 0x6f,
4862
-	0x1e, 0x4a, 0x3b, 0x7a, 0xa9, 0x47, 0xcf, 0xa0, 0x32, 0x5e, 0x81, 0x91, 0x9f, 0x8d, 0x63, 0x76,
4863
-	0x97, 0xf6, 0x3e, 0xbe, 0x12, 0x63, 0x32, 0xf7, 0x0d, 0x2c, 0xa9, 0xa5, 0x1c, 0xcd, 0x49, 0x99,
4864
-	0xbd, 0xad, 0x7b, 0x57, 0x2f, 0xd7, 0x9b, 0x8e, 0x64, 0x52, 0xd3, 0x6d, 0x1e, 0x93, 0xbd, 0x06,
4865
-	0x79, 0xeb, 0xd7, 0x8c, 0x45, 0x74, 0x00, 0x45, 0xd3, 0x68, 0xe6, 0x41, 0xed, 0x19, 0xe6, 0xd5,
4866
-	0x2f, 0x07, 0x68, 0xb2, 0x4d, 0x07, 0x1d, 0x8c, 0x77, 0xbc, 0x79, 0xa1, 0xd9, 0x05, 0xea, 0x5d,
4867
-	0xf3, 0xff, 0x86, 0xb3, 0xe9, 0xa0, 0x1f, 0xa0, 0x6a, 0x95, 0x20, 0xfa, 0x24, 0xeb, 0x92, 0xad,
4868
-	0x67, 0xef, 0xd3, 0x6b, 0x50, 0x3a, 0xd8, 0x56, 0xed, 0xd5, 0xc5, 0x9a, 0xf3, 0xd7, 0xc5, 0x9a,
4869
-	0xf3, 0xcf, 0xc5, 0x9a, 0xd3, 0x29, 0xaa, 0x5f, 0xe4, 0x67, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff,
4870
-	0x4d, 0x94, 0x5a, 0xb6, 0xd8, 0x0d, 0x00, 0x00,
4795
+	// 1214 bytes of a gzipped FileDescriptorProto
4796
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0x4f, 0x6f, 0x1b, 0x55,
4797
+	0x10, 0x67, 0x6d, 0xc7, 0xf6, 0x8e, 0x9d, 0x28, 0x3c, 0xa0, 0x5a, 0x2d, 0x90, 0x98, 0x05, 0x24,
4798
+	0xab, 0x6a, 0xd7, 0x69, 0xa0, 0x08, 0x72, 0xa8, 0x5a, 0xc7, 0x45, 0x24, 0x4a, 0x44, 0xd8, 0x34,
4799
+	0x54, 0xe2, 0xb6, 0xb6, 0x5f, 0xdc, 0x55, 0xd6, 0xfb, 0x96, 0xf7, 0x9e, 0xa3, 0x86, 0x4f, 0xc1,
4800
+	0x81, 0x6f, 0xc2, 0x81, 0x33, 0x07, 0xa4, 0xde, 0xe0, 0xcc, 0x21, 0x45, 0xb9, 0xc3, 0x67, 0x40,
4801
+	0xef, 0xcf, 0xda, 0xcf, 0x5e, 0xe7, 0x8f, 0xd3, 0x93, 0xdf, 0xcc, 0xfe, 0xe6, 0xb7, 0xf3, 0x66,
4802
+	0x66, 0x67, 0xc6, 0xb0, 0xdc, 0x23, 0x09, 0xa7, 0x24, 0xf6, 0x53, 0x4a, 0x38, 0x41, 0xab, 0x43,
4803
+	0xd2, 0x3d, 0xf3, 0xbb, 0xa3, 0x28, 0xee, 0x9f, 0x44, 0xdc, 0x3f, 0x7d, 0xe0, 0xde, 0x1f, 0x44,
4804
+	0xfc, 0xc5, 0xa8, 0xeb, 0xf7, 0xc8, 0xb0, 0x35, 0x20, 0x03, 0xd2, 0x92, 0xc0, 0xee, 0xe8, 0x58,
4805
+	0x4a, 0x52, 0x90, 0x27, 0x45, 0xe0, 0xae, 0x0f, 0x08, 0x19, 0xc4, 0x78, 0x82, 0xe2, 0xd1, 0x10,
4806
+	0x33, 0x1e, 0x0e, 0x53, 0x0d, 0xb8, 0x67, 0xf0, 0x89, 0x97, 0xb5, 0xb2, 0x97, 0xb5, 0x18, 0x89,
4807
+	0x4f, 0x31, 0x6d, 0xa5, 0xdd, 0x16, 0x49, 0x99, 0x42, 0x7b, 0x2b, 0x50, 0x3f, 0xa0, 0xa3, 0x04,
4808
+	0x07, 0xf8, 0xc7, 0x11, 0x66, 0xdc, 0xbb, 0x0b, 0xab, 0x9d, 0x88, 0x9d, 0x1c, 0xb1, 0x70, 0x90,
4809
+	0xe9, 0xd0, 0x1d, 0x28, 0x1f, 0x47, 0x31, 0xc7, 0xd4, 0xb1, 0x1a, 0x56, 0xd3, 0x0e, 0xb4, 0xe4,
4810
+	0xed, 0xc2, 0xdb, 0x06, 0x96, 0xa5, 0x24, 0x61, 0x18, 0x3d, 0x84, 0x32, 0xc5, 0x3d, 0x42, 0xfb,
4811
+	0x8e, 0xd5, 0x28, 0x36, 0x6b, 0x9b, 0x1f, 0xfa, 0xb3, 0x37, 0xf6, 0xb5, 0x81, 0x00, 0x05, 0x1a,
4812
+	0xec, 0xfd, 0x5e, 0x80, 0x9a, 0xa1, 0x47, 0x2b, 0x50, 0xd8, 0xe9, 0xe8, 0xf7, 0x15, 0x76, 0x3a,
4813
+	0xc8, 0x81, 0xca, 0xfe, 0x88, 0x87, 0xdd, 0x18, 0x3b, 0x85, 0x86, 0xd5, 0xac, 0x06, 0x99, 0x88,
4814
+	0xde, 0x85, 0xa5, 0x9d, 0xe4, 0x88, 0x61, 0xa7, 0x28, 0xf5, 0x4a, 0x40, 0x08, 0x4a, 0x87, 0xd1,
4815
+	0x4f, 0xd8, 0x29, 0x35, 0xac, 0x66, 0x31, 0x90, 0x67, 0x71, 0x8f, 0x83, 0x90, 0xe2, 0x84, 0x3b,
4816
+	0x4b, 0xea, 0x1e, 0x4a, 0x42, 0x6d, 0xb0, 0xb7, 0x29, 0x0e, 0x39, 0xee, 0x3f, 0xe1, 0x4e, 0xb9,
4817
+	0x61, 0x35, 0x6b, 0x9b, 0xae, 0xaf, 0xc2, 0xec, 0x67, 0x61, 0xf6, 0x9f, 0x65, 0x61, 0x6e, 0x57,
4818
+	0x5f, 0x9d, 0xaf, 0xbf, 0xf5, 0xf3, 0xeb, 0x75, 0x2b, 0x98, 0x98, 0xa1, 0xc7, 0x00, 0x7b, 0x21,
4819
+	0xe3, 0x47, 0x4c, 0x92, 0x54, 0xae, 0x25, 0x29, 0x49, 0x02, 0xc3, 0x06, 0xad, 0x01, 0xc8, 0x00,
4820
+	0x6c, 0x93, 0x51, 0xc2, 0x9d, 0xaa, 0xf4, 0xdb, 0xd0, 0xa0, 0x06, 0xd4, 0x3a, 0x98, 0xf5, 0x68,
4821
+	0x94, 0xf2, 0x88, 0x24, 0x8e, 0x2d, 0xaf, 0x60, 0xaa, 0xbc, 0x5f, 0x4a, 0x50, 0x3f, 0x14, 0x39,
4822
+	0xce, 0x12, 0xb7, 0x0a, 0xc5, 0x00, 0x1f, 0xeb, 0x28, 0x8a, 0x23, 0xf2, 0x01, 0x3a, 0xf8, 0x38,
4823
+	0x4a, 0x22, 0xc9, 0x51, 0x90, 0x6e, 0xae, 0xf8, 0x69, 0xd7, 0x9f, 0x68, 0x03, 0x03, 0x81, 0x5c,
4824
+	0xa8, 0x3e, 0x7d, 0x99, 0x12, 0x2a, 0x92, 0x5f, 0x94, 0x34, 0x63, 0x19, 0x3d, 0x87, 0xe5, 0xec,
4825
+	0xfc, 0x84, 0x73, 0xca, 0x9c, 0x92, 0x4c, 0xf8, 0x83, 0x7c, 0xc2, 0x4d, 0xa7, 0xfc, 0x29, 0x9b,
4826
+	0xa7, 0x09, 0xa7, 0x67, 0xc1, 0x34, 0x8f, 0xc8, 0xf5, 0x21, 0x66, 0x4c, 0x78, 0xa8, 0x12, 0x95,
4827
+	0x89, 0xc2, 0x9d, 0xaf, 0x29, 0x49, 0x38, 0x4e, 0xfa, 0x32, 0x51, 0x76, 0x30, 0x96, 0x85, 0x3b,
4828
+	0xd9, 0x59, 0xb9, 0x53, 0xb9, 0x91, 0x3b, 0x53, 0x36, 0xda, 0x9d, 0x29, 0x1d, 0xda, 0x82, 0xa5,
4829
+	0xed, 0xb0, 0xf7, 0x02, 0xcb, 0x9c, 0xd4, 0x36, 0xd7, 0xf2, 0x84, 0xf2, 0xf1, 0xb7, 0x32, 0x09,
4830
+	0xac, 0x5d, 0x12, 0xe5, 0x11, 0x28, 0x13, 0xf7, 0x31, 0xa0, 0xfc, 0x7d, 0x45, 0x5e, 0x4e, 0xf0,
4831
+	0x59, 0x96, 0x97, 0x13, 0x7c, 0x26, 0x8a, 0xf8, 0x34, 0x8c, 0x47, 0xaa, 0xb8, 0xed, 0x40, 0x09,
4832
+	0x5b, 0x85, 0x2f, 0x2d, 0xc1, 0x90, 0x77, 0x71, 0x11, 0x06, 0xef, 0xb5, 0x05, 0x75, 0xd3, 0x43,
4833
+	0xf4, 0x01, 0xd8, 0xca, 0xa9, 0x49, 0x71, 0x4c, 0x14, 0xa2, 0x0e, 0x77, 0x86, 0x5a, 0x60, 0x4e,
4834
+	0xa1, 0x51, 0x6c, 0xda, 0x81, 0xa1, 0x41, 0xdf, 0x41, 0x4d, 0x81, 0x55, 0x94, 0x8b, 0x32, 0xca,
4835
+	0xad, 0xab, 0x83, 0xe2, 0x1b, 0x16, 0x2a, 0xc6, 0x26, 0x87, 0xfb, 0x08, 0x56, 0x67, 0x01, 0x0b,
4836
+	0xdd, 0xf0, 0x37, 0x0b, 0x96, 0x75, 0x52, 0x75, 0x17, 0x0a, 0x33, 0x46, 0x4c, 0x33, 0x9d, 0xee,
4837
+	0x47, 0x0f, 0x2f, 0xad, 0x07, 0x05, 0xf3, 0x67, 0xed, 0x94, 0xbf, 0x39, 0x3a, 0x77, 0x1b, 0xde,
4838
+	0x9b, 0x0b, 0x5d, 0xc8, 0xf3, 0x8f, 0x60, 0xf9, 0x90, 0x87, 0x7c, 0xc4, 0x2e, 0xfd, 0x64, 0xbd,
4839
+	0x5f, 0x2d, 0x58, 0xc9, 0x30, 0xfa, 0x76, 0x9f, 0x43, 0xf5, 0x14, 0x53, 0x8e, 0x5f, 0x62, 0xa6,
4840
+	0x6f, 0xe5, 0xe4, 0x6f, 0xf5, 0xbd, 0x44, 0x04, 0x63, 0x24, 0xda, 0x82, 0x2a, 0x93, 0x3c, 0x58,
4841
+	0xa5, 0x75, 0x6e, 0x29, 0x2b, 0x2b, 0xfd, 0xbe, 0x31, 0x1e, 0xb5, 0xa0, 0x14, 0x93, 0x41, 0x96,
4842
+	0xed, 0xf7, 0x2f, 0xb3, 0xdb, 0x23, 0x83, 0x40, 0x02, 0xbd, 0xf3, 0x02, 0x94, 0x95, 0x0e, 0xed,
4843
+	0x42, 0xb9, 0x1f, 0x0d, 0x30, 0xe3, 0xea, 0x56, 0xed, 0x4d, 0xf1, 0x81, 0xfc, 0x7d, 0xbe, 0x7e,
4844
+	0xd7, 0x18, 0x54, 0x24, 0xc5, 0x89, 0x18, 0x94, 0x61, 0x94, 0x60, 0xca, 0x5a, 0x03, 0x72, 0x5f,
4845
+	0x99, 0xf8, 0x1d, 0xf9, 0x13, 0x68, 0x06, 0xc1, 0x15, 0x25, 0xe9, 0x88, 0xeb, 0xc2, 0xbc, 0x1d,
4846
+	0x97, 0x62, 0x10, 0x23, 0x22, 0x09, 0x87, 0x58, 0xf7, 0x35, 0x79, 0x16, 0x23, 0xa2, 0x27, 0xea,
4847
+	0xb6, 0x2f, 0x07, 0x47, 0x35, 0xd0, 0x12, 0xda, 0x82, 0x0a, 0xe3, 0x21, 0xe5, 0xb8, 0x2f, 0x5b,
4848
+	0xd2, 0x4d, 0x7a, 0x7b, 0x66, 0x80, 0x1e, 0x81, 0xdd, 0x23, 0xc3, 0x34, 0xc6, 0xc2, 0xba, 0x7c,
4849
+	0x43, 0xeb, 0x89, 0x89, 0xa8, 0x1e, 0x4c, 0x29, 0xa1, 0x72, 0xaa, 0xd8, 0x81, 0x12, 0xbc, 0xff,
4850
+	0x0a, 0x50, 0x37, 0x93, 0x95, 0x9b, 0x98, 0xbb, 0x50, 0x56, 0xa9, 0x57, 0x55, 0x77, 0xbb, 0x50,
4851
+	0x29, 0x86, 0xb9, 0xa1, 0x72, 0xa0, 0xd2, 0x1b, 0x51, 0x39, 0x4e, 0xd5, 0x90, 0xcd, 0x44, 0xe1,
4852
+	0x30, 0x27, 0x3c, 0x8c, 0x65, 0xa8, 0x8a, 0x81, 0x12, 0xc4, 0x94, 0x1d, 0xaf, 0x2a, 0x8b, 0x4d,
4853
+	0xd9, 0xb1, 0x99, 0x99, 0x86, 0xca, 0x1b, 0xa5, 0xa1, 0xba, 0x70, 0x1a, 0xbc, 0x3f, 0x2c, 0xb0,
4854
+	0xc7, 0x55, 0x6e, 0x44, 0xd7, 0x7a, 0xe3, 0xe8, 0x4e, 0x45, 0xa6, 0x70, 0xbb, 0xc8, 0xdc, 0x81,
4855
+	0x32, 0xe3, 0x14, 0x87, 0x43, 0x99, 0xa3, 0x62, 0xa0, 0x25, 0xd1, 0x4f, 0x86, 0x6c, 0x20, 0x33,
4856
+	0x54, 0x0f, 0xc4, 0xd1, 0xf3, 0xa0, 0xde, 0x3e, 0xe3, 0x98, 0xed, 0x63, 0x26, 0x96, 0x0b, 0x91,
4857
+	0xdb, 0x7e, 0xc8, 0x43, 0x79, 0x8f, 0x7a, 0x20, 0xcf, 0xde, 0x3d, 0x40, 0x7b, 0x11, 0xe3, 0xcf,
4858
+	0x09, 0x3d, 0xc1, 0x94, 0xcd, 0xdb, 0x03, 0x8b, 0xc6, 0x1e, 0xb8, 0x0f, 0xef, 0x4c, 0xa1, 0x75,
4859
+	0x97, 0xfa, 0x62, 0x66, 0x13, 0x9c, 0xd3, 0x6d, 0x94, 0xc9, 0xcc, 0x2a, 0xf8, 0xa7, 0x05, 0x75,
4860
+	0xf3, 0x41, 0xae, 0xb2, 0xdb, 0x50, 0xde, 0x0b, 0xbb, 0x38, 0xce, 0xda, 0xd8, 0xdd, 0xab, 0x89,
4861
+	0x7d, 0x05, 0x56, 0x7d, 0x5c, 0x5b, 0xa2, 0x0d, 0xb0, 0xd3, 0x38, 0xe4, 0xc7, 0x84, 0x0e, 0xb3,
4862
+	0xae, 0x56, 0x17, 0x7b, 0xd0, 0x81, 0x56, 0xea, 0x31, 0x3e, 0x01, 0xb9, 0x5f, 0x41, 0xcd, 0x20,
4863
+	0x5a, 0xa4, 0xcb, 0x6f, 0xfe, 0x5b, 0x84, 0xca, 0xb6, 0xfa, 0x1b, 0x80, 0x9e, 0x81, 0x3d, 0x5e,
4864
+	0x9a, 0x91, 0x97, 0xf7, 0x7c, 0x76, 0xfb, 0x76, 0x3f, 0xbe, 0x12, 0xa3, 0x63, 0xfd, 0x0d, 0x2c,
4865
+	0xc9, 0x35, 0x1e, 0xcd, 0x09, 0xb2, 0xb9, 0xdf, 0xbb, 0x57, 0xaf, 0xe3, 0x1b, 0x96, 0x60, 0x92,
4866
+	0xf3, 0x70, 0x1e, 0x93, 0xb9, 0x38, 0xb9, 0xeb, 0xd7, 0x0c, 0x52, 0xb4, 0x0f, 0x65, 0xdd, 0x9a,
4867
+	0xe6, 0x41, 0xcd, 0xa9, 0xe7, 0x36, 0x2e, 0x07, 0x28, 0xb2, 0x0d, 0x0b, 0xed, 0x8f, 0xb7, 0xc2,
4868
+	0x79, 0xae, 0x99, 0x25, 0xed, 0x5e, 0xf3, 0xbc, 0x69, 0x6d, 0x58, 0xe8, 0x07, 0xa8, 0x19, 0x45,
4869
+	0x8b, 0x3e, 0xc9, 0x9b, 0xe4, 0xbf, 0x00, 0xf7, 0xd3, 0x6b, 0x50, 0xca, 0xd9, 0x76, 0xfd, 0xd5,
4870
+	0xc5, 0x9a, 0xf5, 0xd7, 0xc5, 0x9a, 0xf5, 0xcf, 0xc5, 0x9a, 0xd5, 0x2d, 0xcb, 0x6f, 0xf8, 0xb3,
4871
+	0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x86, 0xd4, 0x0f, 0xa1, 0x0a, 0x0e, 0x00, 0x00,
4871 4872
 }
... ...
@@ -118,4 +118,5 @@ message ListWorkersResponse {
118 118
 message WorkerRecord {
119 119
 	string ID = 1;
120 120
 	map<string, string> Labels = 2;
121
+	repeated pb.Platform platforms = 3 [(gogoproto.nullable) = false];
121 122
 }
... ...
@@ -17,7 +17,7 @@ import (
17 17
 )
18 18
 
19 19
 var (
20
-	errLocked   = errors.New("locked")
20
+	ErrLocked   = errors.New("locked")
21 21
 	errNotFound = errors.New("not found")
22 22
 	errInvalid  = errors.New("invalid")
23 23
 )
... ...
@@ -122,7 +122,7 @@ func (cm *cacheManager) get(ctx context.Context, id string, fromSnapshotter bool
122 122
 
123 123
 	if rec.mutable {
124 124
 		if len(rec.refs) != 0 {
125
-			return nil, errors.Wrapf(errLocked, "%s is locked", id)
125
+			return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
126 126
 		}
127 127
 		if rec.equalImmutable != nil {
128 128
 			return rec.equalImmutable.ref(), nil
... ...
@@ -279,12 +279,12 @@ func (cm *cacheManager) GetMutable(ctx context.Context, id string) (MutableRef,
279 279
 	}
280 280
 
281 281
 	if len(rec.refs) != 0 {
282
-		return nil, errors.Wrapf(errLocked, "%s is locked", id)
282
+		return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
283 283
 	}
284 284
 
285 285
 	if rec.equalImmutable != nil {
286 286
 		if len(rec.equalImmutable.refs) != 0 {
287
-			return nil, errors.Wrapf(errLocked, "%s is locked", id)
287
+			return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
288 288
 		}
289 289
 		delete(cm.records, rec.equalImmutable.ID())
290 290
 		if err := rec.equalImmutable.remove(ctx, false); err != nil {
... ...
@@ -513,7 +513,7 @@ func (cm *cacheManager) DiskUsage(ctx context.Context, opt client.DiskUsageInfo)
513 513
 }
514 514
 
515 515
 func IsLocked(err error) bool {
516
-	return errors.Cause(err) == errLocked
516
+	return errors.Cause(err) == ErrLocked
517 517
 }
518 518
 
519 519
 func IsNotFound(err error) bool {
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"crypto/tls"
6 6
 	"crypto/x509"
7 7
 	"io/ioutil"
8
-	"time"
9 8
 
10 9
 	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
11 10
 	controlapi "github.com/moby/buildkit/api/services/control"
... ...
@@ -23,7 +22,7 @@ type Client struct {
23 23
 type ClientOpt interface{}
24 24
 
25 25
 // New returns a new buildkit client. Address can be empty for the system-default address.
26
-func New(address string, opts ...ClientOpt) (*Client, error) {
26
+func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) {
27 27
 	gopts := []grpc.DialOption{
28 28
 		grpc.WithDialer(dialer),
29 29
 		grpc.FailOnNonTempDialError(true),
... ...
@@ -54,9 +53,6 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
54 54
 		address = appdefaults.Address
55 55
 	}
56 56
 
57
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
58
-	defer cancel()
59
-
60 57
 	conn, err := grpc.DialContext(ctx, address, gopts...)
61 58
 	if err != nil {
62 59
 		return nil, errors.Wrapf(err, "failed to dial %q . make sure buildkitd is running", address)
... ...
@@ -17,8 +17,8 @@ type Meta struct {
17 17
 	ProxyEnv *ProxyEnv
18 18
 }
19 19
 
20
-func NewExecOp(root Output, meta Meta, readOnly bool, md OpMetadata) *ExecOp {
21
-	e := &ExecOp{meta: meta, cachedOpMetadata: md}
20
+func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp {
21
+	e := &ExecOp{meta: meta, constraints: c}
22 22
 	rootMount := &mount{
23 23
 		target:   pb.RootMount,
24 24
 		source:   root,
... ...
@@ -28,32 +28,35 @@ func NewExecOp(root Output, meta Meta, readOnly bool, md OpMetadata) *ExecOp {
28 28
 	if readOnly {
29 29
 		e.root = root
30 30
 	} else {
31
-		e.root = &output{vertex: e, getIndex: e.getMountIndexFn(rootMount)}
31
+		o := &output{vertex: e, getIndex: e.getMountIndexFn(rootMount)}
32
+		if p := c.Platform; p != nil {
33
+			o.platform = p
34
+		}
35
+		e.root = o
32 36
 	}
33 37
 	rootMount.output = e.root
34
-
35 38
 	return e
36 39
 }
37 40
 
38 41
 type mount struct {
39
-	target   string
40
-	readonly bool
41
-	source   Output
42
-	output   Output
43
-	selector string
44
-	cacheID  string
45
-	tmpfs    bool
42
+	target       string
43
+	readonly     bool
44
+	source       Output
45
+	output       Output
46
+	selector     string
47
+	cacheID      string
48
+	tmpfs        bool
49
+	cacheSharing CacheMountSharingMode
46 50
 	// hasOutput bool
47 51
 }
48 52
 
49 53
 type ExecOp struct {
50
-	root             Output
51
-	mounts           []*mount
52
-	meta             Meta
53
-	cachedPBDigest   digest.Digest
54
-	cachedPB         []byte
55
-	cachedOpMetadata OpMetadata
56
-	isValidated      bool
54
+	MarshalCache
55
+	root        Output
56
+	mounts      []*mount
57
+	meta        Meta
58
+	constraints Constraints
59
+	isValidated bool
57 60
 }
58 61
 
59 62
 func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output {
... ...
@@ -70,9 +73,13 @@ func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Outp
70 70
 	} else if m.tmpfs {
71 71
 		m.output = &output{vertex: e, err: errors.Errorf("tmpfs mount for %s can't be used as a parent", target)}
72 72
 	} else {
73
-		m.output = &output{vertex: e, getIndex: e.getMountIndexFn(m)}
73
+		o := &output{vertex: e, getIndex: e.getMountIndexFn(m)}
74
+		if p := e.constraints.Platform; p != nil {
75
+			o.platform = p
76
+		}
77
+		m.output = o
74 78
 	}
75
-	e.cachedPB = nil
79
+	e.Store(nil, nil, nil)
76 80
 	e.isValidated = false
77 81
 	return m.output
78 82
 }
... ...
@@ -107,9 +114,9 @@ func (e *ExecOp) Validate() error {
107 107
 	return nil
108 108
 }
109 109
 
110
-func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
111
-	if e.cachedPB != nil {
112
-		return e.cachedPBDigest, e.cachedPB, &e.cachedOpMetadata, nil
110
+func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
111
+	if e.Cached(c) {
112
+		return e.Load()
113 113
 	}
114 114
 	if err := e.Validate(); err != nil {
115 115
 		return "", nil, nil, err
... ...
@@ -137,10 +144,9 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
137 137
 		}
138 138
 	}
139 139
 
140
-	pop := &pb.Op{
141
-		Op: &pb.Op_Exec{
142
-			Exec: peo,
143
-		},
140
+	pop, md := MarshalConstraints(c, &e.constraints)
141
+	pop.Op = &pb.Op_Exec{
142
+		Exec: peo,
144 143
 	}
145 144
 
146 145
 	outIndex := 0
... ...
@@ -150,7 +156,7 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
150 150
 			if m.tmpfs {
151 151
 				return "", nil, nil, errors.Errorf("tmpfs mounts must use scratch")
152 152
 			}
153
-			inp, err := m.source.ToInput()
153
+			inp, err := m.source.ToInput(c)
154 154
 			if err != nil {
155 155
 				return "", nil, nil, err
156 156
 			}
... ...
@@ -190,6 +196,14 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
190 190
 			pm.CacheOpt = &pb.CacheOpt{
191 191
 				ID: m.cacheID,
192 192
 			}
193
+			switch m.cacheSharing {
194
+			case CacheMountShared:
195
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_SHARED
196
+			case CacheMountPrivate:
197
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_PRIVATE
198
+			case CacheMountLocked:
199
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_LOCKED
200
+			}
193 201
 		}
194 202
 		if m.tmpfs {
195 203
 			pm.MountType = pb.MountType_TMPFS
... ...
@@ -201,9 +215,8 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
201 201
 	if err != nil {
202 202
 		return "", nil, nil, err
203 203
 	}
204
-	e.cachedPBDigest = digest.FromBytes(dt)
205
-	e.cachedPB = dt
206
-	return e.cachedPBDigest, dt, &e.cachedOpMetadata, nil
204
+	e.Store(dt, md, c)
205
+	return e.Load()
207 206
 }
208 207
 
209 208
 func (e *ExecOp) Output() Output {
... ...
@@ -273,9 +286,10 @@ func SourcePath(src string) MountOption {
273 273
 	}
274 274
 }
275 275
 
276
-func AsPersistentCacheDir(id string) MountOption {
276
+func AsPersistentCacheDir(id string, sharing CacheMountSharingMode) MountOption {
277 277
 	return func(m *mount) {
278 278
 		m.cacheID = id
279
+		m.cacheSharing = sharing
279 280
 	}
280 281
 }
281 282
 
... ...
@@ -366,7 +380,7 @@ func WithProxy(ps ProxyEnv) RunOption {
366 366
 }
367 367
 
368 368
 type ExecInfo struct {
369
-	opMetaWrapper
369
+	constraintsWrapper
370 370
 	State          State
371 371
 	Mounts         []MountInfo
372 372
 	ReadonlyRootFS bool
... ...
@@ -385,3 +399,11 @@ type ProxyEnv struct {
385 385
 	FtpProxy   string
386 386
 	NoProxy    string
387 387
 }
388
+
389
+type CacheMountSharingMode int
390
+
391
+const (
392
+	CacheMountShared CacheMountSharingMode = iota
393
+	CacheMountPrivate
394
+	CacheMountLocked
395
+)
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/moby/buildkit/util/contentutil"
13 13
 	"github.com/moby/buildkit/util/imageutil"
14 14
 	digest "github.com/opencontainers/go-digest"
15
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
15 16
 )
16 17
 
17 18
 var defaultImageMetaResolver llb.ImageMetaResolver
... ...
@@ -22,12 +23,12 @@ var WithDefault = llb.ImageOptionFunc(func(ii *llb.ImageInfo) {
22 22
 })
23 23
 
24 24
 type imageMetaResolverOpts struct {
25
-	platform string
25
+	platform *specs.Platform
26 26
 }
27 27
 
28 28
 type ImageMetaResolverOpt func(o *imageMetaResolverOpts)
29 29
 
30
-func WithPlatform(p string) ImageMetaResolverOpt {
30
+func WithDefaultPlatform(p *specs.Platform) ImageMetaResolverOpt {
31 31
 	return func(o *imageMetaResolverOpts) {
32 32
 		o.platform = p
33 33
 	}
... ...
@@ -59,7 +60,7 @@ func Default() llb.ImageMetaResolver {
59 59
 type imageMetaResolver struct {
60 60
 	resolver remotes.Resolver
61 61
 	buffer   contentutil.Buffer
62
-	platform string
62
+	platform *specs.Platform
63 63
 	locker   *locker.Locker
64 64
 	cache    map[string]resolveResult
65 65
 }
... ...
@@ -69,7 +70,7 @@ type resolveResult struct {
69 69
 	dgst   digest.Digest
70 70
 }
71 71
 
72
-func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
72
+func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error) {
73 73
 	imr.locker.Lock(ref)
74 74
 	defer imr.locker.Unlock(ref)
75 75
 
... ...
@@ -77,7 +78,11 @@ func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string
77 77
 		return res.dgst, res.config, nil
78 78
 	}
79 79
 
80
-	dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, imr.platform)
80
+	if platform == nil {
81
+		platform = imr.platform
82
+	}
83
+
84
+	dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, platform)
81 85
 	if err != nil {
82 86
 		return "", nil, err
83 87
 	}
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"io"
5 5
 	"io/ioutil"
6 6
 
7
+	"github.com/containerd/containerd/platforms"
7 8
 	"github.com/moby/buildkit/solver/pb"
8 9
 	digest "github.com/opencontainers/go-digest"
9 10
 )
... ...
@@ -12,11 +13,11 @@ import (
12 12
 // Corresponds to the Definition structure defined in solver/pb.Definition.
13 13
 type Definition struct {
14 14
 	Def      [][]byte
15
-	Metadata map[digest.Digest]OpMetadata
15
+	Metadata map[digest.Digest]pb.OpMetadata
16 16
 }
17 17
 
18 18
 func (def *Definition) ToPB() *pb.Definition {
19
-	md := make(map[digest.Digest]OpMetadata)
19
+	md := make(map[digest.Digest]pb.OpMetadata)
20 20
 	for k, v := range def.Metadata {
21 21
 		md[k] = v
22 22
 	}
... ...
@@ -28,14 +29,12 @@ func (def *Definition) ToPB() *pb.Definition {
28 28
 
29 29
 func (def *Definition) FromPB(x *pb.Definition) {
30 30
 	def.Def = x.Def
31
-	def.Metadata = make(map[digest.Digest]OpMetadata)
31
+	def.Metadata = make(map[digest.Digest]pb.OpMetadata)
32 32
 	for k, v := range x.Metadata {
33 33
 		def.Metadata[k] = v
34 34
 	}
35 35
 }
36 36
 
37
-type OpMetadata = pb.OpMetadata
38
-
39 37
 func WriteTo(def *Definition, w io.Writer) error {
40 38
 	b, err := def.ToPB().Marshal()
41 39
 	if err != nil {
... ...
@@ -58,3 +57,56 @@ func ReadFrom(r io.Reader) (*Definition, error) {
58 58
 	def.FromPB(&pbDef)
59 59
 	return &def, nil
60 60
 }
61
+
62
+func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) {
63
+	c := *base
64
+	c.WorkerConstraints = append([]string{}, c.WorkerConstraints...)
65
+
66
+	if p := override.Platform; p != nil {
67
+		c.Platform = p
68
+	}
69
+
70
+	for _, wc := range override.WorkerConstraints {
71
+		c.WorkerConstraints = append(c.WorkerConstraints, wc)
72
+	}
73
+
74
+	c.Metadata = mergeMetadata(c.Metadata, override.Metadata)
75
+
76
+	if c.Platform == nil {
77
+		defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
78
+		c.Platform = &defaultPlatform
79
+	}
80
+
81
+	return &pb.Op{
82
+		Platform: &pb.Platform{
83
+			OS:           c.Platform.OS,
84
+			Architecture: c.Platform.Architecture,
85
+			Variant:      c.Platform.Variant,
86
+			OSVersion:    c.Platform.OSVersion,
87
+			OSFeatures:   c.Platform.OSFeatures,
88
+		},
89
+		Constraints: &pb.WorkerConstraints{
90
+			Filter: c.WorkerConstraints,
91
+		},
92
+	}, &c.Metadata
93
+}
94
+
95
+type MarshalCache struct {
96
+	digest      digest.Digest
97
+	dt          []byte
98
+	md          *pb.OpMetadata
99
+	constraints *Constraints
100
+}
101
+
102
+func (mc *MarshalCache) Cached(c *Constraints) bool {
103
+	return mc.dt != nil && mc.constraints == c
104
+}
105
+func (mc *MarshalCache) Load() (digest.Digest, []byte, *pb.OpMetadata, error) {
106
+	return mc.digest, mc.dt, mc.md, nil
107
+}
108
+func (mc *MarshalCache) Store(dt []byte, md *pb.OpMetadata, c *Constraints) {
109
+	mc.digest = digest.FromBytes(dt)
110
+	mc.dt = dt
111
+	mc.md = md
112
+	mc.constraints = c
113
+}
... ...
@@ -4,16 +4,19 @@ import (
4 4
 	"fmt"
5 5
 	"path"
6 6
 
7
+	"github.com/containerd/containerd/platforms"
7 8
 	"github.com/google/shlex"
9
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
8 10
 )
9 11
 
10 12
 type contextKeyT string
11 13
 
12 14
 var (
13
-	keyArgs = contextKeyT("llb.exec.args")
14
-	keyDir  = contextKeyT("llb.exec.dir")
15
-	keyEnv  = contextKeyT("llb.exec.env")
16
-	keyUser = contextKeyT("llb.exec.user")
15
+	keyArgs     = contextKeyT("llb.exec.args")
16
+	keyDir      = contextKeyT("llb.exec.dir")
17
+	keyEnv      = contextKeyT("llb.exec.env")
18
+	keyUser     = contextKeyT("llb.exec.user")
19
+	keyPlatform = contextKeyT("llb.platform")
17 20
 )
18 21
 
19 22
 func addEnv(key, value string) StateOption {
... ...
@@ -106,6 +109,21 @@ func shlexf(str string, v ...interface{}) StateOption {
106 106
 	}
107 107
 }
108 108
 
109
+func platform(p specs.Platform) StateOption {
110
+	return func(s State) State {
111
+		return s.WithValue(keyPlatform, platforms.Normalize(p))
112
+	}
113
+}
114
+
115
+func getPlatform(s State) *specs.Platform {
116
+	v := s.Value(keyPlatform)
117
+	if v != nil {
118
+		p := v.(specs.Platform)
119
+		return &p
120
+	}
121
+	return nil
122
+}
123
+
109 124
 type EnvList []KeyValue
110 125
 
111 126
 type KeyValue struct {
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"context"
5 5
 
6 6
 	digest "github.com/opencontainers/go-digest"
7
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
7 8
 )
8 9
 
9 10
 func WithMetaResolver(mr ImageMetaResolver) ImageOption {
... ...
@@ -13,5 +14,5 @@ func WithMetaResolver(mr ImageMetaResolver) ImageOption {
13 13
 }
14 14
 
15 15
 type ImageMetaResolver interface {
16
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
16
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
17 17
 }
... ...
@@ -15,22 +15,21 @@ import (
15 15
 )
16 16
 
17 17
 type SourceOp struct {
18
-	id               string
19
-	attrs            map[string]string
20
-	output           Output
21
-	cachedPBDigest   digest.Digest
22
-	cachedPB         []byte
23
-	cachedOpMetadata OpMetadata
24
-	err              error
18
+	MarshalCache
19
+	id          string
20
+	attrs       map[string]string
21
+	output      Output
22
+	constraints Constraints
23
+	err         error
25 24
 }
26 25
 
27
-func NewSource(id string, attrs map[string]string, md OpMetadata) *SourceOp {
26
+func NewSource(id string, attrs map[string]string, c Constraints) *SourceOp {
28 27
 	s := &SourceOp{
29
-		id:               id,
30
-		attrs:            attrs,
31
-		cachedOpMetadata: md,
28
+		id:          id,
29
+		attrs:       attrs,
30
+		constraints: c,
32 31
 	}
33
-	s.output = &output{vertex: s}
32
+	s.output = &output{vertex: s, platform: c.Platform}
34 33
 	return s
35 34
 }
36 35
 
... ...
@@ -44,26 +43,26 @@ func (s *SourceOp) Validate() error {
44 44
 	return nil
45 45
 }
46 46
 
47
-func (s *SourceOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
48
-	if s.cachedPB != nil {
49
-		return s.cachedPBDigest, s.cachedPB, &s.cachedOpMetadata, nil
47
+func (s *SourceOp) Marshal(constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
48
+	if s.Cached(constraints) {
49
+		return s.Load()
50 50
 	}
51 51
 	if err := s.Validate(); err != nil {
52 52
 		return "", nil, nil, err
53 53
 	}
54 54
 
55
-	proto := &pb.Op{
56
-		Op: &pb.Op_Source{
57
-			Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
58
-		},
55
+	proto, md := MarshalConstraints(constraints, &s.constraints)
56
+
57
+	proto.Op = &pb.Op_Source{
58
+		Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
59 59
 	}
60 60
 	dt, err := proto.Marshal()
61 61
 	if err != nil {
62 62
 		return "", nil, nil, err
63 63
 	}
64
-	s.cachedPB = dt
65
-	s.cachedPBDigest = digest.FromBytes(dt)
66
-	return s.cachedPBDigest, dt, &s.cachedOpMetadata, nil
64
+
65
+	s.Store(dt, md, constraints)
66
+	return s.Load()
67 67
 }
68 68
 
69 69
 func (s *SourceOp) Output() Output {
... ...
@@ -74,10 +73,6 @@ func (s *SourceOp) Inputs() []Output {
74 74
 	return nil
75 75
 }
76 76
 
77
-func Source(id string) State {
78
-	return NewState(NewSource(id, nil, OpMetadata{}).Output())
79
-}
80
-
81 77
 func Image(ref string, opts ...ImageOption) State {
82 78
 	r, err := reference.ParseNormalizedNamed(ref)
83 79
 	if err == nil {
... ...
@@ -87,12 +82,12 @@ func Image(ref string, opts ...ImageOption) State {
87 87
 	for _, opt := range opts {
88 88
 		opt.SetImageOption(&info)
89 89
 	}
90
-	src := NewSource("docker-image://"+ref, nil, info.Metadata()) // controversial
90
+	src := NewSource("docker-image://"+ref, nil, info.Constraints) // controversial
91 91
 	if err != nil {
92 92
 		src.err = err
93 93
 	}
94 94
 	if info.metaResolver != nil {
95
-		_, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref)
95
+		_, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref, info.Constraints.Platform)
96 96
 		if err != nil {
97 97
 			src.err = err
98 98
 		} else {
... ...
@@ -136,7 +131,7 @@ func (fn ImageOptionFunc) SetImageOption(ii *ImageInfo) {
136 136
 }
137 137
 
138 138
 type ImageInfo struct {
139
-	opMetaWrapper
139
+	constraintsWrapper
140 140
 	metaResolver ImageMetaResolver
141 141
 }
142 142
 
... ...
@@ -169,7 +164,7 @@ func Git(remote, ref string, opts ...GitOption) State {
169 169
 	if url != "" {
170 170
 		attrs[pb.AttrFullRemoteURL] = url
171 171
 	}
172
-	source := NewSource("git://"+id, attrs, gi.Metadata())
172
+	source := NewSource("git://"+id, attrs, gi.Constraints)
173 173
 	return NewState(source.Output())
174 174
 }
175 175
 
... ...
@@ -183,7 +178,7 @@ func (fn gitOptionFunc) SetGitOption(gi *GitInfo) {
183 183
 }
184 184
 
185 185
 type GitInfo struct {
186
-	opMetaWrapper
186
+	constraintsWrapper
187 187
 	KeepGitDir bool
188 188
 }
189 189
 
... ...
@@ -220,7 +215,7 @@ func Local(name string, opts ...LocalOption) State {
220 220
 		attrs[pb.AttrSharedKeyHint] = gi.SharedKeyHint
221 221
 	}
222 222
 
223
-	source := NewSource("local://"+name, attrs, gi.Metadata())
223
+	source := NewSource("local://"+name, attrs, gi.Constraints)
224 224
 	return NewState(source.Output())
225 225
 }
226 226
 
... ...
@@ -280,7 +275,7 @@ func SharedKeyHint(h string) LocalOption {
280 280
 }
281 281
 
282 282
 type LocalInfo struct {
283
-	opMetaWrapper
283
+	constraintsWrapper
284 284
 	SessionID       string
285 285
 	IncludePatterns string
286 286
 	ExcludePatterns string
... ...
@@ -310,12 +305,12 @@ func HTTP(url string, opts ...HTTPOption) State {
310 310
 		attrs[pb.AttrHTTPGID] = strconv.Itoa(hi.GID)
311 311
 	}
312 312
 
313
-	source := NewSource(url, attrs, hi.Metadata())
313
+	source := NewSource(url, attrs, hi.Constraints)
314 314
 	return NewState(source.Output())
315 315
 }
316 316
 
317 317
 type HTTPInfo struct {
318
-	opMetaWrapper
318
+	constraintsWrapper
319 319
 	Checksum digest.Digest
320 320
 	Filename string
321 321
 	Perm     int
... ...
@@ -3,21 +3,23 @@ package llb
3 3
 import (
4 4
 	"context"
5 5
 
6
+	"github.com/containerd/containerd/platforms"
6 7
 	"github.com/moby/buildkit/solver/pb"
7 8
 	"github.com/moby/buildkit/util/system"
8 9
 	digest "github.com/opencontainers/go-digest"
10
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
9 11
 )
10 12
 
11 13
 type StateOption func(State) State
12 14
 
13 15
 type Output interface {
14
-	ToInput() (*pb.Input, error)
16
+	ToInput(*Constraints) (*pb.Input, error)
15 17
 	Vertex() Vertex
16 18
 }
17 19
 
18 20
 type Vertex interface {
19 21
 	Validate() error
20
-	Marshal() (digest.Digest, []byte, *OpMetadata, error)
22
+	Marshal(*Constraints) (digest.Digest, []byte, *pb.OpMetadata, error)
21 23
 	Output() Output
22 24
 	Inputs() []Output
23 25
 }
... ...
@@ -29,12 +31,25 @@ func NewState(o Output) State {
29 29
 	}
30 30
 	s = dir("/")(s)
31 31
 	s = addEnv("PATH", system.DefaultPathEnv)(s)
32
+	s = s.ensurePlatform()
32 33
 	return s
33 34
 }
34 35
 
35 36
 type State struct {
36
-	out Output
37
-	ctx context.Context
37
+	out  Output
38
+	ctx  context.Context
39
+	opts []ConstraintsOpt
40
+}
41
+
42
+func (s State) ensurePlatform() State {
43
+	if o, ok := s.out.(interface {
44
+		Platform() *specs.Platform
45
+	}); ok {
46
+		if p := o.Platform(); p != nil {
47
+			s = platform(*p)(s)
48
+		}
49
+	}
50
+	return s
38 51
 }
39 52
 
40 53
 func (s State) WithValue(k, v interface{}) State {
... ...
@@ -48,18 +63,32 @@ func (s State) Value(k interface{}) interface{} {
48 48
 	return s.ctx.Value(k)
49 49
 }
50 50
 
51
-func (s State) Marshal(md ...MetadataOpt) (*Definition, error) {
51
+func (s State) SetMarhalDefaults(co ...ConstraintsOpt) State {
52
+	s.opts = co
53
+	return s
54
+}
55
+
56
+func (s State) Marshal(co ...ConstraintsOpt) (*Definition, error) {
52 57
 	def := &Definition{
53
-		Metadata: make(map[digest.Digest]OpMetadata, 0),
58
+		Metadata: make(map[digest.Digest]pb.OpMetadata, 0),
54 59
 	}
55 60
 	if s.Output() == nil {
56 61
 		return def, nil
57 62
 	}
58
-	def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, md)
63
+
64
+	defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
65
+	c := &Constraints{
66
+		Platform: &defaultPlatform,
67
+	}
68
+	for _, o := range append(s.opts, co...) {
69
+		o.SetConstraintsOption(c)
70
+	}
71
+
72
+	def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, c)
59 73
 	if err != nil {
60 74
 		return def, err
61 75
 	}
62
-	inp, err := s.Output().ToInput()
76
+	inp, err := s.Output().ToInput(c)
63 77
 	if err != nil {
64 78
 		return def, err
65 79
 	}
... ...
@@ -72,29 +101,25 @@ func (s State) Marshal(md ...MetadataOpt) (*Definition, error) {
72 72
 	return def, nil
73 73
 }
74 74
 
75
-func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, md []MetadataOpt) (*Definition, error) {
75
+func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, c *Constraints) (*Definition, error) {
76 76
 	if _, ok := vertexCache[v]; ok {
77 77
 		return def, nil
78 78
 	}
79 79
 	for _, inp := range v.Inputs() {
80 80
 		var err error
81
-		def, err = marshal(inp.Vertex(), def, cache, vertexCache, md)
81
+		def, err = marshal(inp.Vertex(), def, cache, vertexCache, c)
82 82
 		if err != nil {
83 83
 			return def, err
84 84
 		}
85 85
 	}
86 86
 
87
-	dgst, dt, opMeta, err := v.Marshal()
87
+	dgst, dt, opMeta, err := v.Marshal(c)
88 88
 	if err != nil {
89 89
 		return def, err
90 90
 	}
91 91
 	vertexCache[v] = struct{}{}
92 92
 	if opMeta != nil {
93
-		m := mergeMetadata(def.Metadata[dgst], *opMeta)
94
-		for _, f := range md {
95
-			f.SetMetadataOption(&m)
96
-		}
97
-		def.Metadata[dgst] = m
93
+		def.Metadata[dgst] = mergeMetadata(def.Metadata[dgst], *opMeta)
98 94
 	}
99 95
 	if _, ok := cache[dgst]; ok {
100 96
 		return def, nil
... ...
@@ -113,14 +138,19 @@ func (s State) Output() Output {
113 113
 }
114 114
 
115 115
 func (s State) WithOutput(o Output) State {
116
-	return State{
116
+	s = State{
117 117
 		out: o,
118 118
 		ctx: s.ctx,
119 119
 	}
120
+	s = s.ensurePlatform()
121
+	return s
120 122
 }
121 123
 
122 124
 func (s State) Run(ro ...RunOption) ExecState {
123 125
 	ei := &ExecInfo{State: s}
126
+	if p := s.GetPlatform(); p != nil {
127
+		ei.Constraints.Platform = p
128
+	}
124 129
 	for _, o := range ro {
125 130
 		o.SetRunOption(ei)
126 131
 	}
... ...
@@ -132,7 +162,7 @@ func (s State) Run(ro ...RunOption) ExecState {
132 132
 		ProxyEnv: ei.ProxyEnv,
133 133
 	}
134 134
 
135
-	exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Metadata())
135
+	exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Constraints)
136 136
 	for _, m := range ei.Mounts {
137 137
 		exec.AddMount(m.Target, m.Source, m.Opts...)
138 138
 	}
... ...
@@ -178,6 +208,14 @@ func (s State) User(v string) State {
178 178
 	return user(v)(s)
179 179
 }
180 180
 
181
+func (s State) Platform(p specs.Platform) State {
182
+	return platform(p)(s)
183
+}
184
+
185
+func (s State) GetPlatform() *specs.Platform {
186
+	return getPlatform(s)
187
+}
188
+
181 189
 func (s State) With(so ...StateOption) State {
182 190
 	for _, o := range so {
183 191
 		s = o(s)
... ...
@@ -189,9 +227,10 @@ type output struct {
189 189
 	vertex   Vertex
190 190
 	getIndex func() (pb.OutputIndex, error)
191 191
 	err      error
192
+	platform *specs.Platform
192 193
 }
193 194
 
194
-func (o *output) ToInput() (*pb.Input, error) {
195
+func (o *output) ToInput(c *Constraints) (*pb.Input, error) {
195 196
 	if o.err != nil {
196 197
 		return nil, o.err
197 198
 	}
... ...
@@ -203,7 +242,7 @@ func (o *output) ToInput() (*pb.Input, error) {
203 203
 			return nil, err
204 204
 		}
205 205
 	}
206
-	dgst, _, _, err := o.vertex.Marshal()
206
+	dgst, _, _, err := o.vertex.Marshal(c)
207 207
 	if err != nil {
208 208
 		return nil, err
209 209
 	}
... ...
@@ -214,8 +253,12 @@ func (o *output) Vertex() Vertex {
214 214
 	return o.vertex
215 215
 }
216 216
 
217
-type MetadataOpt interface {
218
-	SetMetadataOption(*OpMetadata)
217
+func (o *output) Platform() *specs.Platform {
218
+	return o.platform
219
+}
220
+
221
+type ConstraintsOpt interface {
222
+	SetConstraintsOption(*Constraints)
219 223
 	RunOption
220 224
 	LocalOption
221 225
 	HTTPOption
... ...
@@ -223,33 +266,33 @@ type MetadataOpt interface {
223 223
 	GitOption
224 224
 }
225 225
 
226
-type metadataOptFunc func(m *OpMetadata)
226
+type constraintsOptFunc func(m *Constraints)
227 227
 
228
-func (fn metadataOptFunc) SetMetadataOption(m *OpMetadata) {
228
+func (fn constraintsOptFunc) SetConstraintsOption(m *Constraints) {
229 229
 	fn(m)
230 230
 }
231 231
 
232
-func (fn metadataOptFunc) SetRunOption(ei *ExecInfo) {
233
-	ei.ApplyMetadata(fn)
232
+func (fn constraintsOptFunc) SetRunOption(ei *ExecInfo) {
233
+	ei.applyConstraints(fn)
234 234
 }
235 235
 
236
-func (fn metadataOptFunc) SetLocalOption(li *LocalInfo) {
237
-	li.ApplyMetadata(fn)
236
+func (fn constraintsOptFunc) SetLocalOption(li *LocalInfo) {
237
+	li.applyConstraints(fn)
238 238
 }
239 239
 
240
-func (fn metadataOptFunc) SetHTTPOption(hi *HTTPInfo) {
241
-	hi.ApplyMetadata(fn)
240
+func (fn constraintsOptFunc) SetHTTPOption(hi *HTTPInfo) {
241
+	hi.applyConstraints(fn)
242 242
 }
243 243
 
244
-func (fn metadataOptFunc) SetImageOption(ii *ImageInfo) {
245
-	ii.ApplyMetadata(fn)
244
+func (fn constraintsOptFunc) SetImageOption(ii *ImageInfo) {
245
+	ii.applyConstraints(fn)
246 246
 }
247 247
 
248
-func (fn metadataOptFunc) SetGitOption(gi *GitInfo) {
249
-	gi.ApplyMetadata(fn)
248
+func (fn constraintsOptFunc) SetGitOption(gi *GitInfo) {
249
+	gi.applyConstraints(fn)
250 250
 }
251 251
 
252
-func mergeMetadata(m1, m2 OpMetadata) OpMetadata {
252
+func mergeMetadata(m1, m2 pb.OpMetadata) pb.OpMetadata {
253 253
 	if m2.IgnoreCache {
254 254
 		m1.IgnoreCache = true
255 255
 	}
... ...
@@ -268,49 +311,77 @@ func mergeMetadata(m1, m2 OpMetadata) OpMetadata {
268 268
 	return m1
269 269
 }
270 270
 
271
-var IgnoreCache = metadataOptFunc(func(md *OpMetadata) {
272
-	md.IgnoreCache = true
271
+var IgnoreCache = constraintsOptFunc(func(c *Constraints) {
272
+	c.Metadata.IgnoreCache = true
273 273
 })
274 274
 
275
-func WithDescription(m map[string]string) MetadataOpt {
276
-	return metadataOptFunc(func(md *OpMetadata) {
277
-		md.Description = m
275
+func WithDescription(m map[string]string) ConstraintsOpt {
276
+	return constraintsOptFunc(func(c *Constraints) {
277
+		c.Metadata.Description = m
278 278
 	})
279 279
 }
280 280
 
281 281
 // WithExportCache forces results for this vertex to be exported with the cache
282
-func WithExportCache() MetadataOpt {
283
-	return metadataOptFunc(func(md *OpMetadata) {
284
-		md.ExportCache = &pb.ExportCache{Value: true}
282
+func WithExportCache() ConstraintsOpt {
283
+	return constraintsOptFunc(func(c *Constraints) {
284
+		c.Metadata.ExportCache = &pb.ExportCache{Value: true}
285 285
 	})
286 286
 }
287 287
 
288 288
 // WithoutExportCache sets results for this vertex to be not exported with
289 289
 // the cache
290
-func WithoutExportCache() MetadataOpt {
291
-	return metadataOptFunc(func(md *OpMetadata) {
290
+func WithoutExportCache() ConstraintsOpt {
291
+	return constraintsOptFunc(func(c *Constraints) {
292 292
 		// ExportCache with value false means to disable exporting
293
-		md.ExportCache = &pb.ExportCache{Value: false}
293
+		c.Metadata.ExportCache = &pb.ExportCache{Value: false}
294 294
 	})
295 295
 }
296 296
 
297 297
 // WithoutDefaultExportCache resets the cache export for the vertex to use
298 298
 // the default defined by the build configuration.
299
-func WithoutDefaultExportCache() MetadataOpt {
300
-	return metadataOptFunc(func(md *OpMetadata) {
299
+func WithoutDefaultExportCache() ConstraintsOpt {
300
+	return constraintsOptFunc(func(c *Constraints) {
301 301
 		// nil means no vertex based config has been set
302
-		md.ExportCache = nil
302
+		c.Metadata.ExportCache = nil
303 303
 	})
304 304
 }
305 305
 
306
-type opMetaWrapper struct {
307
-	OpMetadata
306
+type constraintsWrapper struct {
307
+	Constraints
308
+}
309
+
310
+func (cw *constraintsWrapper) applyConstraints(f func(c *Constraints)) {
311
+	f(&cw.Constraints)
308 312
 }
309 313
 
310
-func (mw *opMetaWrapper) ApplyMetadata(f func(m *OpMetadata)) {
311
-	f(&mw.OpMetadata)
314
+type Constraints struct {
315
+	Platform          *specs.Platform
316
+	WorkerConstraints []string
317
+	Metadata          pb.OpMetadata
312 318
 }
313 319
 
314
-func (mw *opMetaWrapper) Metadata() OpMetadata {
315
-	return mw.OpMetadata
320
+func Platform(p specs.Platform) ConstraintsOpt {
321
+	return constraintsOptFunc(func(c *Constraints) {
322
+		c.Platform = &p
323
+	})
324
+}
325
+
326
+var (
327
+	LinuxAmd64   = Platform(specs.Platform{OS: "linux", Architecture: "amd64"})
328
+	LinuxArmhf   = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v7"})
329
+	LinuxArm     = LinuxArmhf
330
+	LinuxArmel   = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v6"})
331
+	LinuxArm64   = Platform(specs.Platform{OS: "linux", Architecture: "arm64"})
332
+	LinuxS390x   = Platform(specs.Platform{OS: "linux", Architecture: "s390x"})
333
+	LinuxPpc64le = Platform(specs.Platform{OS: "linux", Architecture: "ppc64le"})
334
+	Darwin       = Platform(specs.Platform{OS: "darwin", Architecture: "amd64"})
335
+	Windows      = Platform(specs.Platform{OS: "windows", Architecture: "amd64"})
336
+)
337
+
338
+func Require(filters ...string) ConstraintsOpt {
339
+	return constraintsOptFunc(func(c *Constraints) {
340
+		for _, f := range filters {
341
+			c.WorkerConstraints = append(c.WorkerConstraints, f)
342
+		}
343
+	})
316 344
 }
... ...
@@ -4,12 +4,15 @@ import (
4 4
 	"context"
5 5
 
6 6
 	controlapi "github.com/moby/buildkit/api/services/control"
7
+	"github.com/moby/buildkit/solver/pb"
8
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
7 9
 	"github.com/pkg/errors"
8 10
 )
9 11
 
10 12
 type WorkerInfo struct {
11
-	ID     string
12
-	Labels map[string]string
13
+	ID        string
14
+	Labels    map[string]string
15
+	Platforms []specs.Platform
13 16
 }
14 17
 
15 18
 func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]*WorkerInfo, error) {
... ...
@@ -28,8 +31,9 @@ func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]
28 28
 
29 29
 	for _, w := range resp.Record {
30 30
 		wi = append(wi, &WorkerInfo{
31
-			ID:     w.ID,
32
-			Labels: w.Labels,
31
+			ID:        w.ID,
32
+			Labels:    w.Labels,
33
+			Platforms: toClientPlatforms(w.Platforms),
33 34
 		})
34 35
 	}
35 36
 
... ...
@@ -47,3 +51,17 @@ func WithWorkerFilter(f []string) ListWorkersOption {
47 47
 		wi.Filter = f
48 48
 	}
49 49
 }
50
+
51
+func toClientPlatforms(p []pb.Platform) []specs.Platform {
52
+	out := make([]specs.Platform, 0, len(p))
53
+	for _, pp := range p {
54
+		out = append(out, specs.Platform{
55
+			OS:           pp.OS,
56
+			Architecture: pp.Architecture,
57
+			Variant:      pp.Variant,
58
+			OSVersion:    pp.OSVersion,
59
+			OSFeatures:   pp.OSFeatures,
60
+		})
61
+	}
62
+	return out
63
+}
... ...
@@ -13,7 +13,9 @@ import (
13 13
 	"github.com/moby/buildkit/session/grpchijack"
14 14
 	"github.com/moby/buildkit/solver"
15 15
 	"github.com/moby/buildkit/solver/llbsolver"
16
+	"github.com/moby/buildkit/solver/pb"
16 17
 	"github.com/moby/buildkit/worker"
18
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
17 19
 	"github.com/pkg/errors"
18 20
 	"github.com/sirupsen/logrus"
19 21
 	"golang.org/x/sync/errgroup"
... ...
@@ -35,7 +37,10 @@ type Controller struct { // TODO: ControlService
35 35
 }
36 36
 
37 37
 func NewController(opt Opt) (*Controller, error) {
38
-	solver := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.CacheImporter)
38
+	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.CacheImporter)
39
+	if err != nil {
40
+		return nil, errors.Wrap(err, "failed to create solver")
41
+	}
39 42
 
40 43
 	c := &Controller{
41 44
 		opt:    opt,
... ...
@@ -265,8 +270,9 @@ func (c *Controller) ListWorkers(ctx context.Context, r *controlapi.ListWorkersR
265 265
 	}
266 266
 	for _, w := range workers {
267 267
 		resp.Record = append(resp.Record, &controlapi.WorkerRecord{
268
-			ID:     w.ID(),
269
-			Labels: w.Labels(),
268
+			ID:        w.ID(),
269
+			Labels:    w.Labels(),
270
+			Platforms: toPBPlatforms(w.Platforms()),
270 271
 		})
271 272
 	}
272 273
 	return resp, nil
... ...
@@ -290,3 +296,17 @@ func parseCacheExporterOpt(opt map[string]string) solver.CacheExportMode {
290 290
 	}
291 291
 	return solver.CacheExportModeMin
292 292
 }
293
+
294
+func toPBPlatforms(p []specs.Platform) []pb.Platform {
295
+	out := make([]pb.Platform, 0, len(p))
296
+	for _, pp := range p {
297
+		out = append(out, pb.Platform{
298
+			OS:           pp.OS,
299
+			Architecture: pp.Architecture,
300
+			Variant:      pp.Variant,
301
+			OSVersion:    pp.OSVersion,
302
+			OSFeatures:   pp.OSFeatures,
303
+		})
304
+	}
305
+	return out
306
+}
... ...
@@ -8,10 +8,12 @@ import (
8 8
 	"regexp"
9 9
 	"strings"
10 10
 
11
+	"github.com/containerd/containerd/platforms"
11 12
 	"github.com/docker/docker/builder/dockerignore"
12 13
 	"github.com/moby/buildkit/client/llb"
13 14
 	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
14 15
 	"github.com/moby/buildkit/frontend/gateway/client"
16
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
15 17
 	"github.com/pkg/errors"
16 18
 	"golang.org/x/sync/errgroup"
17 19
 )
... ...
@@ -28,14 +30,26 @@ const (
28 28
 	buildArgPrefix        = "build-arg:"
29 29
 	labelPrefix           = "label:"
30 30
 	keyNoCache            = "no-cache"
31
+	keyTargetPlatform     = "platform"
31 32
 )
32 33
 
33 34
 var httpPrefix = regexp.MustCompile("^https?://")
34
-var gitUrlPathWithFragmentSuffix = regexp.MustCompile(".git(?:#.+)?$")
35
+var gitUrlPathWithFragmentSuffix = regexp.MustCompile("\\.git(?:#.+)?$")
35 36
 
36 37
 func Build(ctx context.Context, c client.Client) error {
37 38
 	opts := c.Opts()
38 39
 
40
+	// TODO: read buildPlatforms from workers
41
+	buildPlatforms := []specs.Platform{platforms.DefaultSpec()}
42
+	targetPlatform := platforms.DefaultSpec()
43
+	if v := opts[keyTargetPlatform]; v != "" {
44
+		var err error
45
+		targetPlatform, err = platforms.Parse(v)
46
+		if err != nil {
47
+			return errors.Wrapf(err, "failed to parse target platform %s", v)
48
+		}
49
+	}
50
+
39 51
 	filename := opts[keyFilename]
40 52
 	if filename == "" {
41 53
 		filename = defaultDockerfileName
... ...
@@ -166,14 +180,16 @@ func Build(ctx context.Context, c client.Client) error {
166 166
 	}
167 167
 
168 168
 	st, img, err := dockerfile2llb.Dockerfile2LLB(ctx, dtDockerfile, dockerfile2llb.ConvertOpt{
169
-		Target:       opts[keyTarget],
170
-		MetaResolver: c,
171
-		BuildArgs:    filter(opts, buildArgPrefix),
172
-		Labels:       filter(opts, labelPrefix),
173
-		SessionID:    c.SessionID(),
174
-		BuildContext: buildContext,
175
-		Excludes:     excludes,
176
-		IgnoreCache:  ignoreCache,
169
+		Target:         opts[keyTarget],
170
+		MetaResolver:   c,
171
+		BuildArgs:      filter(opts, buildArgPrefix),
172
+		Labels:         filter(opts, labelPrefix),
173
+		SessionID:      c.SessionID(),
174
+		BuildContext:   buildContext,
175
+		Excludes:       excludes,
176
+		IgnoreCache:    ignoreCache,
177
+		TargetPlatform: &targetPlatform,
178
+		BuildPlatforms: buildPlatforms,
177 179
 	})
178 180
 
179 181
 	if err != nil {
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"strconv"
13 13
 	"strings"
14 14
 
15
+	"github.com/containerd/containerd/platforms"
15 16
 	"github.com/docker/distribution/reference"
16 17
 	"github.com/docker/docker/pkg/signal"
17 18
 	"github.com/docker/go-connections/nat"
... ...
@@ -20,7 +21,7 @@ import (
20 20
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
21 21
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
22 22
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
23
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
23
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
24 24
 	"github.com/pkg/errors"
25 25
 	"golang.org/x/sync/errgroup"
26 26
 )
... ...
@@ -30,7 +31,7 @@ const (
30 30
 	localNameContext = "context"
31 31
 	historyComment   = "buildkit.dockerfile.v0"
32 32
 
33
-	CopyImage = "tonistiigi/copy:v0.1.3@sha256:87c46e7b413cdd2c2702902b481b390ce263ac9d942253d366f3b1a3c16f96d6"
33
+	CopyImage = "tonistiigi/copy:v0.1.3@sha256:e57a3b4d6240f55bac26b655d2cfb751f8b9412d6f7bb1f787e946391fb4b21b"
34 34
 )
35 35
 
36 36
 type ConvertOpt struct {
... ...
@@ -46,6 +47,8 @@ type ConvertOpt struct {
46 46
 	IgnoreCache []string
47 47
 	// CacheIDNamespace scopes the IDs for different cache mounts
48 48
 	CacheIDNamespace string
49
+	TargetPlatform   *specs.Platform
50
+	BuildPlatforms   []specs.Platform
49 51
 }
50 52
 
51 53
 func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) {
... ...
@@ -53,6 +56,18 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
53 53
 		return nil, nil, errors.Errorf("the Dockerfile cannot be empty")
54 54
 	}
55 55
 
56
+	if opt.TargetPlatform != nil && opt.BuildPlatforms == nil {
57
+		opt.BuildPlatforms = []specs.Platform{*opt.TargetPlatform}
58
+	}
59
+	if len(opt.BuildPlatforms) == 0 {
60
+		opt.BuildPlatforms = []specs.Platform{platforms.DefaultSpec()}
61
+	}
62
+	implicitTargetPlatform := false
63
+	if opt.TargetPlatform == nil {
64
+		implicitTargetPlatform = true
65
+		opt.TargetPlatform = &opt.BuildPlatforms[0]
66
+	}
67
+
56 68
 	dockerfile, err := parser.Parse(bytes.NewReader(dt))
57 69
 	if err != nil {
58 70
 		return nil, nil, err
... ...
@@ -92,6 +107,20 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
92 92
 			deps:     make(map[*dispatchState]struct{}),
93 93
 			ctxPaths: make(map[string]struct{}),
94 94
 		}
95
+
96
+		if v := st.Platform; v != "" {
97
+			v, err := shlex.ProcessWord(v, toEnvList(metaArgs, nil))
98
+			if err != nil {
99
+				return nil, nil, errors.Wrapf(err, "failed to process arguments for platform %s", v)
100
+			}
101
+
102
+			p, err := platforms.Parse(v)
103
+			if err != nil {
104
+				return nil, nil, errors.Wrapf(err, "failed to parse platform %s", v)
105
+			}
106
+			ds.platform = &p
107
+		}
108
+
95 109
 		if d, ok := dispatchStatesByName[st.BaseName]; ok {
96 110
 			ds.base = d
97 111
 		}
... ...
@@ -150,7 +179,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
150 150
 		if d.base == nil {
151 151
 			if d.stage.BaseName == emptyImageName {
152 152
 				d.state = llb.Scratch()
153
-				d.image = emptyImage()
153
+				d.image = emptyImage(*opt.TargetPlatform)
154 154
 				continue
155 155
 			}
156 156
 			func(i int, d *dispatchState) {
... ...
@@ -159,16 +188,25 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
159 159
 					if err != nil {
160 160
 						return err
161 161
 					}
162
+					platform := d.platform
163
+					if platform == nil {
164
+						platform = opt.TargetPlatform
165
+					}
162 166
 					d.stage.BaseName = reference.TagNameOnly(ref).String()
163 167
 					var isScratch bool
164 168
 					if metaResolver != nil && reachable {
165
-						dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName)
169
+						dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, platform)
166 170
 						if err == nil { // handle the error while builder is actually running
167 171
 							var img Image
168 172
 							if err := json.Unmarshal(dt, &img); err != nil {
169 173
 								return err
170 174
 							}
171 175
 							img.Created = nil
176
+							// if there is no explicit target platform, try to match based on image config
177
+							if d.platform == nil && implicitTargetPlatform {
178
+								p := autoDetectPlatform(img, *platform, opt.BuildPlatforms)
179
+								platform = &p
180
+							}
172 181
 							d.image = img
173 182
 							if dgst != "" {
174 183
 								ref, err = reference.WithDigest(ref, dgst)
... ...
@@ -186,7 +224,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
186 186
 					if isScratch {
187 187
 						d.state = llb.Scratch()
188 188
 					} else {
189
-						d.state = llb.Image(d.stage.BaseName, dfCmd(d.stage.SourceCode))
189
+						d.state = llb.Image(d.stage.BaseName, dfCmd(d.stage.SourceCode), llb.Platform(*platform))
190 190
 					}
191 191
 					return nil
192 192
 				})
... ...
@@ -242,6 +280,8 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
242 242
 			buildContext:         llb.NewState(buildContext),
243 243
 			proxyEnv:             proxyEnv,
244 244
 			cacheIDNamespace:     opt.CacheIDNamespace,
245
+			buildPlatforms:       opt.BuildPlatforms,
246
+			targetPlatform:       *opt.TargetPlatform,
245 247
 		}
246 248
 
247 249
 		if err = dispatchOnBuild(d, d.image.Config.OnBuild, opt); err != nil {
... ...
@@ -280,7 +320,14 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
280 280
 	}
281 281
 	buildContext.Output = bc.Output()
282 282
 
283
-	return &target.state, &target.image, nil
283
+	st := target.state.SetMarhalDefaults(llb.Platform(*opt.TargetPlatform))
284
+
285
+	if !implicitTargetPlatform {
286
+		target.image.OS = opt.TargetPlatform.OS
287
+		target.image.Architecture = opt.TargetPlatform.Architecture
288
+	}
289
+
290
+	return &st, &target.image, nil
284 291
 }
285 292
 
286 293
 func toCommand(ic instructions.Command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) (command, error) {
... ...
@@ -325,6 +372,8 @@ type dispatchOpt struct {
325 325
 	buildContext         llb.State
326 326
 	proxyEnv             *llb.ProxyEnv
327 327
 	cacheIDNamespace     string
328
+	targetPlatform       specs.Platform
329
+	buildPlatforms       []specs.Platform
328 330
 }
329 331
 
330 332
 func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
... ...
@@ -348,7 +397,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
348 348
 	case *instructions.WorkdirCommand:
349 349
 		err = dispatchWorkdir(d, c, true)
350 350
 	case *instructions.AddCommand:
351
-		err = dispatchCopy(d, c.SourcesAndDest, opt.buildContext, true, c, "")
351
+		err = dispatchCopy(d, c.SourcesAndDest, opt.buildContext, true, c, "", opt)
352 352
 		if err == nil {
353 353
 			for _, src := range c.Sources() {
354 354
 				d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{}
... ...
@@ -381,7 +430,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
381 381
 		if len(cmd.sources) != 0 {
382 382
 			l = cmd.sources[0].state
383 383
 		}
384
-		err = dispatchCopy(d, c.SourcesAndDest, l, false, c, c.Chown)
384
+		err = dispatchCopy(d, c.SourcesAndDest, l, false, c, c.Chown, opt)
385 385
 		if err == nil && len(cmd.sources) == 0 {
386 386
 			for _, src := range c.Sources() {
387 387
 				d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{}
... ...
@@ -395,6 +444,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
395 395
 type dispatchState struct {
396 396
 	state        llb.State
397 397
 	image        Image
398
+	platform     *specs.Platform
398 399
 	stage        instructions.Stage
399 400
 	base         *dispatchState
400 401
 	deps         map[*dispatchState]struct{}
... ...
@@ -467,7 +517,11 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
467 467
 		opt = append(opt, llb.WithProxy(*proxy))
468 468
 	}
469 469
 
470
-	opt = append(opt, dispatchRunMounts(d, c, sources, dopt)...)
470
+	runMounts, err := dispatchRunMounts(d, c, sources, dopt)
471
+	if err != nil {
472
+		return err
473
+	}
474
+	opt = append(opt, runMounts...)
471 475
 
472 476
 	d.state = d.state.Run(opt...).Root()
473 477
 	return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs), true, &d.state)
... ...
@@ -486,9 +540,9 @@ func dispatchWorkdir(d *dispatchState, c *instructions.WorkdirCommand, commit bo
486 486
 	return nil
487 487
 }
488 488
 
489
-func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState llb.State, isAddCommand bool, cmdToPrint interface{}, chown string) error {
489
+func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState llb.State, isAddCommand bool, cmdToPrint interface{}, chown string, opt dispatchOpt) error {
490 490
 	// TODO: this should use CopyOp instead. Current implementation is inefficient
491
-	img := llb.Image(CopyImage)
491
+	img := llb.Image(CopyImage, llb.Platform(opt.buildPlatforms[0]))
492 492
 
493 493
 	dest := path.Join(".", pathRelativeToWorkingDir(d.state, c.Dest()))
494 494
 	if c.Dest() == "." || c.Dest()[len(c.Dest())-1] == filepath.Separator {
... ...
@@ -554,12 +608,12 @@ func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState l
554 554
 		args = append(args[:1], append([]string{"--unpack"}, args[1:]...)...)
555 555
 	}
556 556
 
557
-	opt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint)}
557
+	runOpt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint)}
558 558
 	if d.ignoreCache {
559
-		opt = append(opt, llb.IgnoreCache)
559
+		runOpt = append(runOpt, llb.IgnoreCache)
560 560
 	}
561
-	run := img.Run(append(opt, mounts...)...)
562
-	d.state = run.AddMount("/dest", d.state)
561
+	run := img.Run(append(runOpt, mounts...)...)
562
+	d.state = run.AddMount("/dest", d.state).Platform(opt.targetPlatform)
563 563
 
564 564
 	return commitToHistory(&d.image, commitMessage.String(), true, &d.state)
565 565
 }
... ...
@@ -767,7 +821,7 @@ func getArgValue(arg instructions.ArgCommand) string {
767 767
 	return v
768 768
 }
769 769
 
770
-func dfCmd(cmd interface{}) llb.MetadataOpt {
770
+func dfCmd(cmd interface{}) llb.ConstraintsOpt {
771 771
 	// TODO: add fmt.Stringer to instructions.Command to remove interface{}
772 772
 	var cmdStr string
773 773
 	if cmd, ok := cmd.(fmt.Stringer); ok {
... ...
@@ -798,7 +852,7 @@ func commitToHistory(img *Image, msg string, withLayer bool, st *llb.State) erro
798 798
 		msg += " # buildkit"
799 799
 	}
800 800
 
801
-	img.History = append(img.History, ocispec.History{
801
+	img.History = append(img.History, specs.History{
802 802
 		CreatedBy:  msg,
803 803
 		Comment:    historyComment,
804 804
 		EmptyLayer: !withLayer,
... ...
@@ -930,3 +984,17 @@ func withShell(img Image, args []string) []string {
930 930
 	}
931 931
 	return append(shell, strings.Join(args, " "))
932 932
 }
933
+
934
+func autoDetectPlatform(img Image, target specs.Platform, supported []specs.Platform) specs.Platform {
935
+	os := img.OS
936
+	arch := img.Architecture
937
+	if target.OS == os && target.Architecture == arch {
938
+		return target
939
+	}
940
+	for _, p := range supported {
941
+		if p.OS == os && p.Architecture == arch {
942
+			return p
943
+		}
944
+	}
945
+	return target
946
+}
... ...
@@ -11,6 +11,6 @@ func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState
11 11
 	return false
12 12
 }
13 13
 
14
-func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) []llb.RunOption {
15
-	return nil
14
+func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) ([]llb.RunOption, error) {
15
+	return nil, nil
16 16
 }
... ...
@@ -9,6 +9,7 @@ import (
9 9
 
10 10
 	"github.com/moby/buildkit/client/llb"
11 11
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
12
+	"github.com/pkg/errors"
12 13
 )
13 14
 
14 15
 func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) bool {
... ...
@@ -40,7 +41,7 @@ func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState
40 40
 	return false
41 41
 }
42 42
 
43
-func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) []llb.RunOption {
43
+func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) ([]llb.RunOption, error) {
44 44
 	var out []llb.RunOption
45 45
 	mounts := instructions.GetMounts(c)
46 46
 
... ...
@@ -61,14 +62,25 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
61 61
 			mountOpts = append(mountOpts, llb.Readonly)
62 62
 		}
63 63
 		if mount.Type == instructions.MountTypeCache {
64
-			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID))
64
+			sharing := llb.CacheMountShared
65
+			if mount.CacheSharing == instructions.MountSharingPrivate {
66
+				sharing = llb.CacheMountPrivate
67
+			}
68
+			if mount.CacheSharing == instructions.MountSharingLocked {
69
+				sharing = llb.CacheMountLocked
70
+			}
71
+			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, sharing))
72
+		}
73
+		target := path.Join("/", mount.Target)
74
+		if target == "/" {
75
+			return nil, errors.Errorf("invalid mount target %q", mount.Target)
65 76
 		}
66 77
 		if src := path.Join("/", mount.Source); src != "/" {
67 78
 			mountOpts = append(mountOpts, llb.SourcePath(src))
68 79
 		}
69
-		out = append(out, llb.AddMount(path.Join("/", mount.Target), st, mountOpts...))
80
+		out = append(out, llb.AddMount(target, st, mountOpts...))
70 81
 
71 82
 		d.ctxPaths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{}
72 83
 	}
73
-	return out
84
+	return out, nil
74 85
 }
... ...
@@ -1,12 +1,11 @@
1 1
 package dockerfile2llb
2 2
 
3 3
 import (
4
-	"runtime"
5 4
 	"time"
6 5
 
7 6
 	"github.com/docker/docker/api/types/strslice"
8 7
 	"github.com/moby/buildkit/util/system"
9
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
8
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
10 9
 )
11 10
 
12 11
 // HealthConfig holds configuration settings for the HEALTHCHECK feature.
... ...
@@ -31,7 +30,7 @@ type HealthConfig struct {
31 31
 }
32 32
 
33 33
 type ImageConfig struct {
34
-	ocispec.ImageConfig
34
+	specs.ImageConfig
35 35
 
36 36
 	Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
37 37
 	ArgsEscaped bool          `json:",omitempty"` // True if command is already escaped (Windows specific)
... ...
@@ -46,7 +45,7 @@ type ImageConfig struct {
46 46
 // Image is the JSON structure which describes some basic information about the image.
47 47
 // This provides the `application/vnd.oci.image.config.v1+json` mediatype when marshalled to JSON.
48 48
 type Image struct {
49
-	ocispec.Image
49
+	specs.Image
50 50
 
51 51
 	// Config defines the execution parameters which should be used as a base when running a container using the image.
52 52
 	Config ImageConfig `json:"config,omitempty"`
... ...
@@ -61,11 +60,11 @@ func clone(src Image) Image {
61 61
 	return img
62 62
 }
63 63
 
64
-func emptyImage() Image {
64
+func emptyImage(platform specs.Platform) Image {
65 65
 	img := Image{
66
-		Image: ocispec.Image{
67
-			Architecture: runtime.GOARCH,
68
-			OS:           runtime.GOOS,
66
+		Image: specs.Image{
67
+			Architecture: platform.Architecture,
68
+			OS:           platform.OS,
69 69
 		},
70 70
 	}
71 71
 	img.RootFS.Type = "layers"
... ...
@@ -6,7 +6,6 @@ import (
6 6
 
7 7
 	"github.com/docker/docker/api/types/container"
8 8
 	"github.com/docker/docker/api/types/strslice"
9
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
10 9
 )
11 10
 
12 11
 // KeyValuePair represent an arbitrary named value (useful in slice instead of map[string] string to preserve ordering)
... ...
@@ -382,7 +381,7 @@ type Stage struct {
382 382
 	Commands   []Command
383 383
 	BaseName   string
384 384
 	SourceCode string
385
-	Platform   specs.Platform
385
+	Platform   string
386 386
 }
387 387
 
388 388
 // AddCommand to the stage
... ...
@@ -20,6 +20,16 @@ var allowedMountTypes = map[string]struct{}{
20 20
 	MountTypeTmpfs: {},
21 21
 }
22 22
 
23
+const MountSharingShared = "shared"
24
+const MountSharingPrivate = "private"
25
+const MountSharingLocked = "locked"
26
+
27
+var allowedSharingTypes = map[string]struct{}{
28
+	MountSharingShared:  {},
29
+	MountSharingPrivate: {},
30
+	MountSharingLocked:  {},
31
+}
32
+
23 33
 type mountsKeyT string
24 34
 
25 35
 var mountsKey = mountsKeyT("dockerfile/run/mounts")
... ...
@@ -76,12 +86,13 @@ type mountState struct {
76 76
 }
77 77
 
78 78
 type Mount struct {
79
-	Type     string
80
-	From     string
81
-	Source   string
82
-	Target   string
83
-	ReadOnly bool
84
-	CacheID  string
79
+	Type         string
80
+	From         string
81
+	Source       string
82
+	Target       string
83
+	ReadOnly     bool
84
+	CacheID      string
85
+	CacheSharing string
85 86
 }
86 87
 
87 88
 func parseMount(value string) (*Mount, error) {
... ...
@@ -120,7 +131,7 @@ func parseMount(value string) (*Mount, error) {
120 120
 		switch key {
121 121
 		case "type":
122 122
 			if !isValidMountType(strings.ToLower(value)) {
123
-				return nil, errors.Errorf("invalid mount type %q", value)
123
+				return nil, errors.Errorf("unsupported mount type %q", value)
124 124
 			}
125 125
 			m.Type = strings.ToLower(value)
126 126
 		case "from":
... ...
@@ -144,6 +155,11 @@ func parseMount(value string) (*Mount, error) {
144 144
 			roAuto = false
145 145
 		case "id":
146 146
 			m.CacheID = value
147
+		case "sharing":
148
+			if _, ok := allowedSharingTypes[strings.ToLower(value)]; !ok {
149
+				return nil, errors.Errorf("unsupported sharing value %q", value)
150
+			}
151
+			m.CacheSharing = strings.ToLower(value)
147 152
 		default:
148 153
 			return nil, errors.Errorf("unexpected key '%s' in '%s'", key, field)
149 154
 		}
... ...
@@ -157,5 +173,9 @@ func parseMount(value string) (*Mount, error) {
157 157
 		}
158 158
 	}
159 159
 
160
+	if m.CacheSharing != "" && m.Type != MountTypeCache {
161
+		return nil, errors.Errorf("invalid cache sharing set for %v mount", m.Type)
162
+	}
163
+
160 164
 	return m, nil
161 165
 }
... ...
@@ -10,7 +10,6 @@ import (
10 10
 
11 11
 	"github.com/docker/docker/api/types/container"
12 12
 	"github.com/docker/docker/api/types/strslice"
13
-	"github.com/docker/docker/pkg/system"
14 13
 	"github.com/moby/buildkit/frontend/dockerfile/command"
15 14
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
16 15
 	"github.com/pkg/errors"
... ...
@@ -279,13 +278,14 @@ func parseFrom(req parseRequest) (*Stage, error) {
279 279
 	if err := req.flags.Parse(); err != nil {
280 280
 		return nil, err
281 281
 	}
282
+
282 283
 	code := strings.TrimSpace(req.original)
283 284
 	return &Stage{
284 285
 		BaseName:   req.args[0],
285 286
 		Name:       stageName,
286 287
 		SourceCode: code,
287 288
 		Commands:   []Command{},
288
-		Platform:   *system.ParsePlatform(flPlatform.Value),
289
+		Platform:   flPlatform.Value,
289 290
 	}, nil
290 291
 
291 292
 }
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"github.com/moby/buildkit/solver"
10 10
 	"github.com/moby/buildkit/solver/pb"
11 11
 	digest "github.com/opencontainers/go-digest"
12
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
12 13
 )
13 14
 
14 15
 type Frontend interface {
... ...
@@ -17,7 +18,7 @@ type Frontend interface {
17 17
 
18 18
 type FrontendLLBBridge interface {
19 19
 	Solve(ctx context.Context, req SolveRequest) (solver.CachedResult, map[string][]byte, error)
20
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
20
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
21 21
 	Exec(ctx context.Context, meta executor.Meta, rootfs cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
22 22
 }
23 23
 
... ...
@@ -5,12 +5,13 @@ import (
5 5
 
6 6
 	"github.com/moby/buildkit/solver/pb"
7 7
 	digest "github.com/opencontainers/go-digest"
8
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
8 9
 )
9 10
 
10 11
 // TODO: make this take same options as LLBBridge. Add Return()
11 12
 type Client interface {
12 13
 	Solve(ctx context.Context, req SolveRequest, exporterAttr map[string][]byte, final bool) (Reference, error)
13
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
14
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
14 15
 	Opts() map[string]string
15 16
 	SessionID() string
16 17
 }
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"net"
9 9
 	"os"
10 10
 	"strings"
11
+	"sync"
11 12
 	"time"
12 13
 
13 14
 	"github.com/docker/distribution/reference"
... ...
@@ -21,7 +22,7 @@ import (
21 21
 	"github.com/moby/buildkit/solver"
22 22
 	"github.com/moby/buildkit/util/tracing"
23 23
 	"github.com/moby/buildkit/worker"
24
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
24
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
25 25
 	"github.com/pkg/errors"
26 26
 	"github.com/sirupsen/logrus"
27 27
 	"golang.org/x/net/http2"
... ...
@@ -62,7 +63,7 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
62 62
 	sid := session.FromContext(ctx)
63 63
 
64 64
 	_, isDevel := opts[keyDevel]
65
-	var img ocispec.Image
65
+	var img specs.Image
66 66
 	var rootFS cache.ImmutableRef
67 67
 	var readonly bool // TODO: try to switch to read-only by default.
68 68
 
... ...
@@ -94,7 +95,7 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
94 94
 			return nil, nil, err
95 95
 		}
96 96
 
97
-		dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String())
97
+		dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), nil) // TODO:
98 98
 		if err != nil {
99 99
 			return nil, nil, err
100 100
 		}
... ...
@@ -103,9 +104,11 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
103 103
 			return nil, nil, err
104 104
 		}
105 105
 
106
-		sourceRef, err = reference.WithDigest(sourceRef, dgst)
107
-		if err != nil {
108
-			return nil, nil, err
106
+		if dgst != "" {
107
+			sourceRef, err = reference.WithDigest(sourceRef, dgst)
108
+			if err != nil {
109
+				return nil, nil, err
110
+			}
109 111
 		}
110 112
 
111 113
 		src := llb.Image(sourceRef.String())
... ...
@@ -248,6 +251,7 @@ func (d dummyAddr) String() string {
248 248
 }
249 249
 
250 250
 type llbBridgeForwarder struct {
251
+	mu           sync.Mutex
251 252
 	callCtx      context.Context
252 253
 	llbBridge    frontend.FrontendLLBBridge
253 254
 	refs         map[string]solver.Result
... ...
@@ -258,7 +262,17 @@ type llbBridgeForwarder struct {
258 258
 
259 259
 func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.ResolveImageConfigRequest) (*pb.ResolveImageConfigResponse, error) {
260 260
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
261
-	dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref)
261
+	var platform *specs.Platform
262
+	if p := req.Platform; p != nil {
263
+		platform = &specs.Platform{
264
+			OS:           p.OS,
265
+			Architecture: p.Architecture,
266
+			Variant:      p.Variant,
267
+			OSVersion:    p.OSVersion,
268
+			OSFeatures:   p.OSFeatures,
269
+		}
270
+	}
271
+	dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref, platform)
262 272
 	if err != nil {
263 273
 		return nil, err
264 274
 	}
... ...
@@ -292,7 +306,9 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest)
292 292
 	}
293 293
 
294 294
 	id := identity.NewID()
295
+	lbf.mu.Lock()
295 296
 	lbf.refs[id] = ref
297
+	lbf.mu.Unlock()
296 298
 	if req.Final {
297 299
 		lbf.lastRef = ref
298 300
 		lbf.exporterAttr = exp
... ...
@@ -304,7 +320,9 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest)
304 304
 }
305 305
 func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileRequest) (*pb.ReadFileResponse, error) {
306 306
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
307
+	lbf.mu.Lock()
307 308
 	ref, ok := lbf.refs[req.Ref]
309
+	lbf.mu.Unlock()
308 310
 	if !ok {
309 311
 		return nil, errors.Errorf("no such ref: %v", req.Ref)
310 312
 	}
... ...
@@ -45,7 +45,8 @@ var _ = math.Inf
45 45
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
46 46
 
47 47
 type ResolveImageConfigRequest struct {
48
-	Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
48
+	Ref      string       `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
49
+	Platform *pb.Platform `protobuf:"bytes,2,opt,name=Platform" json:"Platform,omitempty"`
49 50
 }
50 51
 
51 52
 func (m *ResolveImageConfigRequest) Reset()                    { *m = ResolveImageConfigRequest{} }
... ...
@@ -60,6 +61,13 @@ func (m *ResolveImageConfigRequest) GetRef() string {
60 60
 	return ""
61 61
 }
62 62
 
63
+func (m *ResolveImageConfigRequest) GetPlatform() *pb.Platform {
64
+	if m != nil {
65
+		return m.Platform
66
+	}
67
+	return nil
68
+}
69
+
63 70
 type ResolveImageConfigResponse struct {
64 71
 	Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=Digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"Digest"`
65 72
 	Config []byte                                     `protobuf:"bytes,2,opt,name=Config,proto3" json:"Config,omitempty"`
... ...
@@ -451,6 +459,16 @@ func (m *ResolveImageConfigRequest) MarshalTo(dAtA []byte) (int, error) {
451 451
 		i = encodeVarintGateway(dAtA, i, uint64(len(m.Ref)))
452 452
 		i += copy(dAtA[i:], m.Ref)
453 453
 	}
454
+	if m.Platform != nil {
455
+		dAtA[i] = 0x12
456
+		i++
457
+		i = encodeVarintGateway(dAtA, i, uint64(m.Platform.Size()))
458
+		n1, err := m.Platform.MarshalTo(dAtA[i:])
459
+		if err != nil {
460
+			return 0, err
461
+		}
462
+		i += n1
463
+	}
454 464
 	return i, nil
455 465
 }
456 466
 
... ...
@@ -503,11 +521,11 @@ func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) {
503 503
 		dAtA[i] = 0xa
504 504
 		i++
505 505
 		i = encodeVarintGateway(dAtA, i, uint64(m.Definition.Size()))
506
-		n1, err := m.Definition.MarshalTo(dAtA[i:])
506
+		n2, err := m.Definition.MarshalTo(dAtA[i:])
507 507
 		if err != nil {
508 508
 			return 0, err
509 509
 		}
510
-		i += n1
510
+		i += n2
511 511
 	}
512 512
 	if len(m.Frontend) > 0 {
513 513
 		dAtA[i] = 0x12
... ...
@@ -627,11 +645,11 @@ func (m *ReadFileRequest) MarshalTo(dAtA []byte) (int, error) {
627 627
 		dAtA[i] = 0x1a
628 628
 		i++
629 629
 		i = encodeVarintGateway(dAtA, i, uint64(m.Range.Size()))
630
-		n2, err := m.Range.MarshalTo(dAtA[i:])
630
+		n3, err := m.Range.MarshalTo(dAtA[i:])
631 631
 		if err != nil {
632 632
 			return 0, err
633 633
 		}
634
-		i += n2
634
+		i += n3
635 635
 	}
636 636
 	return i, nil
637 637
 }
... ...
@@ -740,6 +758,10 @@ func (m *ResolveImageConfigRequest) Size() (n int) {
740 740
 	if l > 0 {
741 741
 		n += 1 + l + sovGateway(uint64(l))
742 742
 	}
743
+	if m.Platform != nil {
744
+		l = m.Platform.Size()
745
+		n += 1 + l + sovGateway(uint64(l))
746
+	}
743 747
 	return n
744 748
 }
745 749
 
... ...
@@ -929,6 +951,39 @@ func (m *ResolveImageConfigRequest) Unmarshal(dAtA []byte) error {
929 929
 			}
930 930
 			m.Ref = string(dAtA[iNdEx:postIndex])
931 931
 			iNdEx = postIndex
932
+		case 2:
933
+			if wireType != 2 {
934
+				return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType)
935
+			}
936
+			var msglen int
937
+			for shift := uint(0); ; shift += 7 {
938
+				if shift >= 64 {
939
+					return ErrIntOverflowGateway
940
+				}
941
+				if iNdEx >= l {
942
+					return io.ErrUnexpectedEOF
943
+				}
944
+				b := dAtA[iNdEx]
945
+				iNdEx++
946
+				msglen |= (int(b) & 0x7F) << shift
947
+				if b < 0x80 {
948
+					break
949
+				}
950
+			}
951
+			if msglen < 0 {
952
+				return ErrInvalidLengthGateway
953
+			}
954
+			postIndex := iNdEx + msglen
955
+			if postIndex > l {
956
+				return io.ErrUnexpectedEOF
957
+			}
958
+			if m.Platform == nil {
959
+				m.Platform = &pb.Platform{}
960
+			}
961
+			if err := m.Platform.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
962
+				return err
963
+			}
964
+			iNdEx = postIndex
932 965
 		default:
933 966
 			iNdEx = preIndex
934 967
 			skippy, err := skipGateway(dAtA[iNdEx:])
... ...
@@ -1998,45 +2053,46 @@ var (
1998 1998
 func init() { proto.RegisterFile("gateway.proto", fileDescriptorGateway) }
1999 1999
 
2000 2000
 var fileDescriptorGateway = []byte{
2001
-	// 629 bytes of a gzipped FileDescriptorProto
2002
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x40,
2003
-	0x10, 0xad, 0x63, 0x40, 0x64, 0x12, 0x3e, 0xb4, 0xaa, 0x2a, 0xe3, 0x03, 0x44, 0x56, 0x45, 0x2d,
2004
-	0x5a, 0x6c, 0x35, 0x6d, 0x25, 0x44, 0xa5, 0x4a, 0x0d, 0x1f, 0x12, 0x15, 0x12, 0x68, 0x7b, 0xa8,
2005
-	0xc4, 0xcd, 0x4e, 0xc6, 0x66, 0x45, 0xb2, 0xeb, 0xda, 0x1b, 0xda, 0xa8, 0x97, 0xf6, 0xe7, 0xf4,
2006
-	0x9f, 0x70, 0xec, 0x99, 0x03, 0xaa, 0xf8, 0x25, 0x95, 0xd7, 0xeb, 0x60, 0x48, 0x49, 0xe9, 0x6d,
2007
-	0xdf, 0x78, 0xe6, 0xed, 0x9b, 0x79, 0xb3, 0x86, 0x85, 0x38, 0x90, 0xf8, 0x25, 0x18, 0x79, 0x49,
2008
-	0x2a, 0xa4, 0x20, 0x2b, 0x03, 0x11, 0x8e, 0xbc, 0x70, 0xc8, 0xfa, 0xbd, 0x33, 0x26, 0xbd, 0xf3,
2009
-	0x97, 0x5e, 0x94, 0x0a, 0x2e, 0x91, 0xf7, 0xec, 0xcd, 0x98, 0xc9, 0xd3, 0x61, 0xe8, 0x75, 0xc5,
2010
-	0xc0, 0x8f, 0x45, 0x2c, 0x7c, 0x55, 0x11, 0x0e, 0x23, 0x85, 0x14, 0x50, 0xa7, 0x82, 0xc9, 0x7e,
2011
-	0x51, 0x49, 0xcf, 0x49, 0xfd, 0x92, 0xd4, 0xcf, 0x44, 0xff, 0x1c, 0x53, 0x3f, 0x09, 0x7d, 0x91,
2012
-	0x64, 0x45, 0xb6, 0xb3, 0x09, 0x2b, 0x14, 0xd5, 0x87, 0x83, 0x41, 0x10, 0xe3, 0x8e, 0xe0, 0x11,
2013
-	0x8b, 0x29, 0x7e, 0x1e, 0x62, 0x26, 0xc9, 0x32, 0x98, 0x14, 0x23, 0xcb, 0x68, 0x19, 0x6e, 0x9d,
2014
-	0xe6, 0x47, 0xe7, 0xbb, 0x01, 0xf6, 0xdf, 0xf2, 0xb3, 0x44, 0xf0, 0x0c, 0xc9, 0x07, 0x98, 0xdb,
2015
-	0x65, 0x31, 0x66, 0xb2, 0xa8, 0xe9, 0xb4, 0x2f, 0xae, 0xd6, 0x1e, 0x5d, 0x5e, 0xad, 0x6d, 0x54,
2016
-	0x34, 0x89, 0x04, 0x79, 0x57, 0x70, 0x19, 0x30, 0x8e, 0x69, 0xe6, 0xc7, 0x62, 0xb3, 0xa7, 0x4a,
2017
-	0xbc, 0xa2, 0x92, 0x6a, 0x06, 0xf2, 0x04, 0xe6, 0x0a, 0x76, 0xab, 0xd6, 0x32, 0xdc, 0x26, 0xd5,
2018
-	0xc8, 0xb9, 0xac, 0x41, 0xf3, 0x63, 0x2e, 0xa0, 0x54, 0xe9, 0x01, 0xec, 0x62, 0xc4, 0x38, 0x93,
2019
-	0x4c, 0x70, 0x75, 0x71, 0xa3, 0xbd, 0xe8, 0x25, 0xa1, 0x77, 0x13, 0xa5, 0x95, 0x0c, 0x62, 0xc3,
2020
-	0xfc, 0xbe, 0x9e, 0xad, 0xa2, 0xae, 0xd3, 0x31, 0x26, 0x27, 0xd0, 0x28, 0xcf, 0x47, 0x89, 0xb4,
2021
-	0xcc, 0x96, 0xe9, 0x36, 0xda, 0x5b, 0xde, 0xbd, 0xe6, 0x78, 0x55, 0x25, 0x5e, 0xa5, 0x74, 0x8f,
2022
-	0xcb, 0x74, 0x44, 0xab, 0x64, 0xc4, 0x85, 0xa5, 0x83, 0x41, 0x22, 0x52, 0xb9, 0x13, 0x74, 0x4f,
2023
-	0x91, 0x62, 0x94, 0x59, 0x33, 0x2d, 0xd3, 0xad, 0xd3, 0xbb, 0x61, 0xf2, 0x18, 0x66, 0xf7, 0x19,
2024
-	0x0f, 0xfa, 0x16, 0xb4, 0x0c, 0x77, 0x9e, 0x16, 0x80, 0x38, 0xd0, 0xdc, 0xfb, 0x9a, 0x27, 0x62,
2025
-	0xfa, 0x5e, 0xca, 0xd4, 0x6a, 0xa8, 0xb1, 0xdc, 0x8a, 0xd9, 0xef, 0x60, 0xf9, 0xae, 0x88, 0xdc,
2026
-	0xc5, 0x33, 0x1c, 0x95, 0x2e, 0x9e, 0xe1, 0x28, 0xe7, 0x3f, 0x0f, 0xfa, 0x43, 0xd4, 0xed, 0x17,
2027
-	0x60, 0xbb, 0xb6, 0x65, 0x38, 0x7b, 0xb0, 0xa0, 0x3b, 0xd2, 0x8e, 0x4e, 0xac, 0xc0, 0x84, 0x8c,
2028
-	0xda, 0xa4, 0x0c, 0xe7, 0x1b, 0x2c, 0x51, 0x0c, 0x7a, 0xfb, 0xac, 0x8f, 0xf7, 0xee, 0x92, 0xf2,
2029
-	0x81, 0xf5, 0xf1, 0x38, 0x90, 0xa7, 0x63, 0x1f, 0x34, 0x26, 0xdb, 0x30, 0x4b, 0x03, 0x1e, 0xa3,
2030
-	0x65, 0x2a, 0x3b, 0x9f, 0x4e, 0x71, 0x40, 0x5d, 0x92, 0xe7, 0xd2, 0xa2, 0xc4, 0x79, 0x0b, 0xf5,
2031
-	0x71, 0x2c, 0xdf, 0xa2, 0xa3, 0x28, 0xca, 0xb0, 0xd8, 0x48, 0x93, 0x6a, 0x94, 0xc7, 0x0f, 0x91,
2032
-	0xc7, 0xfa, 0x6a, 0x93, 0x6a, 0xe4, 0xac, 0xc3, 0xf2, 0x8d, 0x72, 0x3d, 0x03, 0x02, 0x33, 0xbb,
2033
-	0x81, 0x0c, 0x14, 0x43, 0x93, 0xaa, 0xb3, 0xb3, 0x00, 0x8d, 0x63, 0xc6, 0xcb, 0x97, 0xe2, 0x2c,
2034
-	0x42, 0xf3, 0x58, 0xf0, 0xf1, 0x43, 0x68, 0xff, 0x34, 0xa1, 0x7e, 0x78, 0xd8, 0xe9, 0xa4, 0xac,
2035
-	0x17, 0x23, 0xf9, 0x61, 0x00, 0x99, 0x7c, 0x35, 0xe4, 0xf5, 0x94, 0xae, 0xee, 0x7d, 0x94, 0xf6,
2036
-	0x9b, 0xff, 0xac, 0xd2, 0x4d, 0x9c, 0xc0, 0xac, 0x72, 0x96, 0x3c, 0x7b, 0xe0, 0x36, 0xdb, 0xee,
2037
-	0xbf, 0x13, 0x35, 0x77, 0x17, 0xe6, 0xcb, 0xa1, 0x91, 0x8d, 0xa9, 0xf2, 0x6e, 0xed, 0x84, 0xfd,
2038
-	0xfc, 0x41, 0xb9, 0xfa, 0x92, 0x4f, 0x30, 0x93, 0x4f, 0x9c, 0xac, 0x4f, 0x29, 0xaa, 0x58, 0x62,
2039
-	0x4f, 0xeb, 0xb3, 0xea, 0x55, 0xa7, 0x79, 0x71, 0xbd, 0x6a, 0xfc, 0xba, 0x5e, 0x35, 0x7e, 0x5f,
2040
-	0xaf, 0x1a, 0xe1, 0x9c, 0xfa, 0x2f, 0xbe, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x21, 0xd1,
2041
-	0x98, 0xa0, 0x05, 0x00, 0x00,
2001
+	// 652 bytes of a gzipped FileDescriptorProto
2002
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x4a,
2003
+	0x14, 0x7d, 0x8e, 0x01, 0x25, 0x37, 0xe6, 0x43, 0xa3, 0xa7, 0x27, 0xe3, 0x05, 0x44, 0xd6, 0x13,
2004
+	0xcf, 0xe2, 0x15, 0x5b, 0x4d, 0x5b, 0x09, 0x51, 0xa9, 0x52, 0xc3, 0x87, 0x44, 0x85, 0x44, 0x34,
2005
+	0x5d, 0x20, 0xb1, 0x1b, 0x27, 0x63, 0x33, 0xc2, 0x99, 0x71, 0xed, 0x09, 0x6d, 0xd4, 0x4d, 0xfb,
2006
+	0x73, 0xfa, 0x4f, 0x58, 0x76, 0xcd, 0x02, 0x55, 0xfc, 0x92, 0xca, 0xe3, 0x71, 0x30, 0x50, 0x52,
2007
+	0xba, 0x9b, 0x73, 0x7d, 0xef, 0x99, 0x73, 0xe7, 0xdc, 0x6b, 0x58, 0x8c, 0x89, 0xa4, 0x1f, 0xc9,
2008
+	0xc4, 0x4f, 0x33, 0x21, 0x05, 0x5a, 0x1d, 0x89, 0x70, 0xe2, 0x87, 0x63, 0x96, 0x0c, 0xcf, 0x99,
2009
+	0xf4, 0x2f, 0x9e, 0xfb, 0x51, 0x26, 0xb8, 0xa4, 0x7c, 0xe8, 0x6c, 0xc5, 0x4c, 0x9e, 0x8d, 0x43,
2010
+	0x7f, 0x20, 0x46, 0x41, 0x2c, 0x62, 0x11, 0xa8, 0x8a, 0x70, 0x1c, 0x29, 0xa4, 0x80, 0x3a, 0x95,
2011
+	0x4c, 0xce, 0xb3, 0x5a, 0x7a, 0x41, 0x1a, 0x54, 0xa4, 0x41, 0x2e, 0x92, 0x0b, 0x9a, 0x05, 0x69,
2012
+	0x18, 0x88, 0x34, 0x2f, 0xb3, 0xdd, 0x13, 0x58, 0xc5, 0x54, 0x7d, 0x38, 0x1c, 0x91, 0x98, 0xee,
2013
+	0x0a, 0x1e, 0xb1, 0x18, 0xd3, 0x0f, 0x63, 0x9a, 0x4b, 0xb4, 0x02, 0x26, 0xa6, 0x91, 0x6d, 0x74,
2014
+	0x0c, 0xaf, 0x85, 0x8b, 0x23, 0xf2, 0xa0, 0xd9, 0x4f, 0x88, 0x8c, 0x44, 0x36, 0xb2, 0x1b, 0x1d,
2015
+	0xc3, 0x6b, 0x77, 0x2d, 0x3f, 0x0d, 0xfd, 0x2a, 0x86, 0xa7, 0x5f, 0xdd, 0x2f, 0x06, 0x38, 0xbf,
2016
+	0x62, 0xce, 0x53, 0xc1, 0x73, 0x8a, 0xde, 0xc1, 0xc2, 0x1e, 0x8b, 0x69, 0x2e, 0x4b, 0xf6, 0x5e,
2017
+	0xf7, 0xf2, 0x7a, 0xfd, 0xaf, 0xab, 0xeb, 0xf5, 0xcd, 0x9a, 0x7a, 0x91, 0x52, 0x3e, 0x10, 0x5c,
2018
+	0x12, 0xc6, 0x69, 0x96, 0x07, 0xb1, 0xd8, 0x1a, 0xaa, 0x12, 0xbf, 0xac, 0xc4, 0x9a, 0x01, 0xfd,
2019
+	0x03, 0x0b, 0x25, 0xbb, 0x92, 0x64, 0x61, 0x8d, 0xdc, 0xab, 0x06, 0x58, 0xef, 0x0b, 0x01, 0x55,
2020
+	0x3f, 0x3e, 0xc0, 0x1e, 0x8d, 0x18, 0x67, 0x92, 0x09, 0xae, 0x2e, 0x6e, 0x77, 0x97, 0x0a, 0xfd,
2021
+	0xb7, 0x51, 0x5c, 0xcb, 0x40, 0x0e, 0x34, 0x0f, 0xb4, 0x0b, 0x8a, 0xba, 0x85, 0xa7, 0x18, 0x9d,
2022
+	0x42, 0xbb, 0x3a, 0x1f, 0xa7, 0xd2, 0x36, 0x3b, 0xa6, 0xd7, 0xee, 0x6e, 0xfb, 0x8f, 0xda, 0xe8,
2023
+	0xd7, 0x95, 0xf8, 0xb5, 0xd2, 0x7d, 0x2e, 0xb3, 0x09, 0xae, 0x93, 0x21, 0x0f, 0x96, 0x0f, 0x47,
2024
+	0xa9, 0xc8, 0xe4, 0x2e, 0x19, 0x9c, 0x51, 0x4c, 0xa3, 0xdc, 0x9e, 0xeb, 0x98, 0x5e, 0x0b, 0xdf,
2025
+	0x0f, 0xa3, 0xbf, 0x61, 0xfe, 0x80, 0x71, 0x92, 0xd8, 0xd0, 0x31, 0xbc, 0x26, 0x2e, 0x01, 0x72,
2026
+	0xc1, 0xda, 0xff, 0x54, 0x24, 0xd2, 0xec, 0xad, 0x94, 0x99, 0xdd, 0x56, 0xcf, 0x72, 0x27, 0xe6,
2027
+	0xbc, 0x81, 0x95, 0xfb, 0x22, 0x0a, 0xbf, 0xcf, 0xe9, 0xa4, 0xf2, 0xfb, 0x9c, 0x4e, 0x0a, 0xfe,
2028
+	0x0b, 0x92, 0x8c, 0xa9, 0x6e, 0xbf, 0x04, 0x3b, 0x8d, 0x6d, 0xc3, 0xdd, 0x87, 0x45, 0xdd, 0x91,
2029
+	0x76, 0xf4, 0xe1, 0xb0, 0xdc, 0x97, 0xd1, 0x78, 0x28, 0xc3, 0xfd, 0x0c, 0xcb, 0x98, 0x92, 0xe1,
2030
+	0x01, 0x4b, 0xe8, 0xe3, 0x53, 0x57, 0xf8, 0xc0, 0x12, 0xda, 0x27, 0xf2, 0x6c, 0xea, 0x83, 0xc6,
2031
+	0x68, 0x07, 0xe6, 0x31, 0xe1, 0x31, 0xb5, 0x4d, 0x65, 0xe7, 0xbf, 0x33, 0x1c, 0x50, 0x97, 0x14,
2032
+	0xb9, 0xb8, 0x2c, 0x71, 0x5f, 0x43, 0x6b, 0x1a, 0x2b, 0xa6, 0xe8, 0x38, 0x8a, 0x72, 0x5a, 0x4e,
2033
+	0xa4, 0x89, 0x35, 0x2a, 0xe2, 0x47, 0x94, 0xc7, 0xfa, 0x6a, 0x13, 0x6b, 0xe4, 0x6e, 0xc0, 0xca,
2034
+	0xad, 0x72, 0xfd, 0x06, 0x08, 0xe6, 0xf6, 0x88, 0x24, 0x8a, 0xc1, 0xc2, 0xea, 0xec, 0x2e, 0x42,
2035
+	0xbb, 0xcf, 0x78, 0xb5, 0x53, 0xee, 0x12, 0x58, 0x7d, 0xc1, 0xa7, 0x8b, 0xd0, 0xfd, 0x66, 0x42,
2036
+	0xeb, 0xe8, 0xa8, 0xd7, 0xcb, 0xd8, 0x30, 0xa6, 0xe8, 0xab, 0x01, 0xe8, 0xe1, 0xd6, 0xa0, 0x97,
2037
+	0x33, 0xba, 0x7a, 0x74, 0x7d, 0x9d, 0x57, 0x7f, 0x58, 0xa5, 0x9b, 0x38, 0x85, 0x79, 0xe5, 0x2c,
2038
+	0xfa, 0xef, 0x89, 0xd3, 0xec, 0x78, 0xbf, 0x4f, 0xd4, 0xdc, 0x03, 0x68, 0x56, 0x8f, 0x86, 0x36,
2039
+	0x67, 0xca, 0xbb, 0x33, 0x13, 0xce, 0xff, 0x4f, 0xca, 0xd5, 0x97, 0x9c, 0xc0, 0x5c, 0xf1, 0xe2,
2040
+	0x68, 0x63, 0x46, 0x51, 0xcd, 0x12, 0x67, 0x56, 0x9f, 0x75, 0xaf, 0x7a, 0xd6, 0xe5, 0xcd, 0x9a,
2041
+	0xf1, 0xfd, 0x66, 0xcd, 0xf8, 0x71, 0xb3, 0x66, 0x84, 0x0b, 0xea, 0x0f, 0xfa, 0xe2, 0x67, 0x00,
2042
+	0x00, 0x00, 0xff, 0xff, 0xbc, 0x68, 0x1b, 0xf0, 0xca, 0x05, 0x00, 0x00,
2042 2043
 }
... ...
@@ -18,6 +18,7 @@ service LLBBridge {
18 18
 
19 19
 message ResolveImageConfigRequest {
20 20
 	string Ref = 1;
21
+	pb.Platform Platform = 2;
21 22
 }
22 23
 
23 24
 message ResolveImageConfigResponse {
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	"github.com/moby/buildkit/util/tracing"
16 16
 	"github.com/moby/buildkit/worker"
17 17
 	digest "github.com/opencontainers/go-digest"
18
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
18 19
 	"github.com/pkg/errors"
19 20
 )
20 21
 
... ...
@@ -25,6 +26,7 @@ type llbBridge struct {
25 25
 	ci            *remotecache.CacheImporter
26 26
 	cms           map[string]solver.CacheManager
27 27
 	cmsMu         sync.Mutex
28
+	platforms     []specs.Platform
28 29
 }
29 30
 
30 31
 func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res solver.CachedResult, exp map[string][]byte, err error) {
... ...
@@ -59,7 +61,7 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res s
59 59
 	}
60 60
 
61 61
 	if req.Definition != nil && req.Definition.Def != nil {
62
-		edge, err := Load(req.Definition, WithCacheSources(cms))
62
+		edge, err := Load(req.Definition, WithCacheSources(cms), RuntimePlatforms(b.platforms))
63 63
 		if err != nil {
64 64
 			return nil, nil, err
65 65
 		}
... ...
@@ -108,12 +110,12 @@ func (s *llbBridge) Exec(ctx context.Context, meta executor.Meta, root cache.Imm
108 108
 	return err
109 109
 }
110 110
 
111
-func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
111
+func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error) {
112 112
 	w, err := s.resolveWorker()
113 113
 	if err != nil {
114 114
 		return "", nil, err
115 115
 	}
116
-	return w.ResolveImageConfig(ctx, ref)
116
+	return w.ResolveImageConfig(ctx, ref, platform)
117 117
 }
118 118
 
119 119
 type lazyCacheManager struct {
... ...
@@ -11,9 +11,11 @@ import (
11 11
 	"sort"
12 12
 	"strings"
13 13
 	"sync"
14
+	"time"
14 15
 
15 16
 	"github.com/boltdb/bolt"
16 17
 	"github.com/containerd/containerd/mount"
18
+	"github.com/docker/docker/pkg/locker"
17 19
 	"github.com/moby/buildkit/cache"
18 20
 	"github.com/moby/buildkit/cache/metadata"
19 21
 	"github.com/moby/buildkit/executor"
... ...
@@ -37,16 +39,19 @@ type execOp struct {
37 37
 	exec      executor.Executor
38 38
 	w         worker.Worker
39 39
 	numInputs int
40
+
41
+	cacheMounts map[string]*cacheRefShare
40 42
 }
41 43
 
42 44
 func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, md *metadata.Store, exec executor.Executor, w worker.Worker) (solver.Op, error) {
43 45
 	return &execOp{
44
-		op:        op.Exec,
45
-		cm:        cm,
46
-		md:        md,
47
-		exec:      exec,
48
-		numInputs: len(v.Inputs()),
49
-		w:         w,
46
+		op:          op.Exec,
47
+		cm:          cm,
48
+		md:          md,
49
+		exec:        exec,
50
+		numInputs:   len(v.Inputs()),
51
+		w:           w,
52
+		cacheMounts: map[string]*cacheRefShare{},
50 53
 	}, nil
51 54
 }
52 55
 
... ...
@@ -165,32 +170,72 @@ func (e *execOp) getMountDeps() ([]dep, error) {
165 165
 	return deps, nil
166 166
 }
167 167
 
168
-func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
168
+func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount, sharing pb.CacheSharingOpt) (mref cache.MutableRef, err error) {
169 169
 
170 170
 	key := "cache-dir:" + id
171 171
 	if ref != nil {
172 172
 		key += ":" + ref.ID()
173 173
 	}
174 174
 
175
-	return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
176
-		return e.getRefCacheDirNoCache(ctx, key, ref, id, m)
177
-	})
175
+	if ref, ok := e.cacheMounts[key]; ok {
176
+		return ref.clone(), nil
177
+	}
178
+	defer func() {
179
+		if err == nil {
180
+			share := &cacheRefShare{MutableRef: mref, refs: map[*cacheRef]struct{}{}}
181
+			e.cacheMounts[key] = share
182
+			mref = share.clone()
183
+		}
184
+	}()
185
+
186
+	switch sharing {
187
+	case pb.CacheSharingOpt_SHARED:
188
+		return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
189
+			return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
190
+		})
191
+	case pb.CacheSharingOpt_PRIVATE:
192
+		return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
193
+	case pb.CacheSharingOpt_LOCKED:
194
+		return e.getRefCacheDirNoCache(ctx, key, ref, id, m, true)
195
+	default:
196
+		return nil, errors.Errorf("invalid cache sharing option: %s", sharing.String())
197
+	}
198
+
178 199
 }
179 200
 
180
-func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
201
+func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount, block bool) (cache.MutableRef, error) {
181 202
 	makeMutable := func(cache.ImmutableRef) (cache.MutableRef, error) {
182 203
 		desc := fmt.Sprintf("cached mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " "))
183 204
 		return e.cm.New(ctx, ref, cache.WithDescription(desc), cache.CachePolicyRetain)
184 205
 	}
185 206
 
186
-	sis, err := e.md.Search(key)
187
-	if err != nil {
188
-		return nil, err
189
-	}
190
-	for _, si := range sis {
191
-		if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
192
-			logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
193
-			return mRef, nil
207
+	cacheRefsLocker.Lock(key)
208
+	defer cacheRefsLocker.Unlock(key)
209
+	for {
210
+		sis, err := e.md.Search(key)
211
+		if err != nil {
212
+			return nil, err
213
+		}
214
+		locked := false
215
+		for _, si := range sis {
216
+			if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
217
+				logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
218
+				return mRef, nil
219
+			} else if errors.Cause(err) == cache.ErrLocked {
220
+				locked = true
221
+			}
222
+		}
223
+		if block && locked {
224
+			cacheRefsLocker.Unlock(key)
225
+			select {
226
+			case <-ctx.Done():
227
+				cacheRefsLocker.Lock(key)
228
+				return nil, ctx.Err()
229
+			case <-time.After(100 * time.Millisecond):
230
+				cacheRefsLocker.Lock(key)
231
+			}
232
+		} else {
233
+			break
194 234
 		}
195 235
 	}
196 236
 	mRef, err := makeMutable(ref)
... ...
@@ -287,7 +332,7 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res
287 287
 			if m.CacheOpt == nil {
288 288
 				return nil, errors.Errorf("missing cache mount options")
289 289
 			}
290
-			mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m)
290
+			mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m, m.CacheOpt.Sharing)
291 291
 			if err != nil {
292 292
 				return nil, err
293 293
 			}
... ...
@@ -418,6 +463,7 @@ func (m *tmpfsMount) Release() error {
418 418
 	return nil
419 419
 }
420 420
 
421
+var cacheRefsLocker = locker.New()
421 422
 var sharedCacheRefs = &cacheRefs{}
422 423
 
423 424
 type cacheRefs struct {
... ...
@@ -466,9 +512,11 @@ func (r *cacheRefShare) clone() cache.MutableRef {
466 466
 }
467 467
 
468 468
 func (r *cacheRefShare) release(ctx context.Context) error {
469
-	r.main.mu.Lock()
470
-	defer r.main.mu.Unlock()
471
-	delete(r.main.shares, r.key)
469
+	if r.main != nil {
470
+		r.main.mu.Lock()
471
+		defer r.main.mu.Unlock()
472
+		delete(r.main.shares, r.key)
473
+	}
472 474
 	return r.MutableRef.Release(ctx)
473 475
 }
474 476
 
... ...
@@ -14,18 +14,20 @@ import (
14 14
 const sourceCacheType = "buildkit.source.v0"
15 15
 
16 16
 type sourceOp struct {
17
-	mu  sync.Mutex
18
-	op  *pb.Op_Source
19
-	sm  *source.Manager
20
-	src source.SourceInstance
21
-	w   worker.Worker
17
+	mu       sync.Mutex
18
+	op       *pb.Op_Source
19
+	platform *pb.Platform
20
+	sm       *source.Manager
21
+	src      source.SourceInstance
22
+	w        worker.Worker
22 23
 }
23 24
 
24
-func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, sm *source.Manager, w worker.Worker) (solver.Op, error) {
25
+func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, platform *pb.Platform, sm *source.Manager, w worker.Worker) (solver.Op, error) {
25 26
 	return &sourceOp{
26
-		op: op,
27
-		sm: sm,
28
-		w:  w,
27
+		op:       op,
28
+		sm:       sm,
29
+		w:        w,
30
+		platform: platform,
29 31
 	}, nil
30 32
 }
31 33
 
... ...
@@ -35,7 +37,7 @@ func (s *sourceOp) instance(ctx context.Context) (source.SourceInstance, error)
35 35
 	if s.src != nil {
36 36
 		return s.src, nil
37 37
 	}
38
-	id, err := source.FromLLB(s.op)
38
+	id, err := source.FromLLB(s.op, s.platform)
39 39
 	if err != nil {
40 40
 		return nil, err
41 41
 	}
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/moby/buildkit/solver"
14 14
 	"github.com/moby/buildkit/util/progress"
15 15
 	"github.com/moby/buildkit/worker"
16
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
16 17
 	"github.com/pkg/errors"
17 18
 )
18 19
 
... ...
@@ -30,9 +31,10 @@ type Solver struct {
30 30
 	resolveWorker ResolveWorkerFunc
31 31
 	frontends     map[string]frontend.Frontend
32 32
 	ci            *remotecache.CacheImporter
33
+	platforms     []specs.Platform
33 34
 }
34 35
 
35
-func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, ci *remotecache.CacheImporter) *Solver {
36
+func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, ci *remotecache.CacheImporter) (*Solver, error) {
36 37
 	s := &Solver{
37 38
 		resolveWorker: defaultResolver(wc),
38 39
 		frontends:     f,
... ...
@@ -43,11 +45,18 @@ func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solve
43 43
 
44 44
 	cache := solver.NewCacheManager("local", cacheStore, results)
45 45
 
46
+	// executing is currently only allowed on default worker
47
+	w, err := wc.GetDefault()
48
+	if err != nil {
49
+		return nil, err
50
+	}
51
+	s.platforms = w.Platforms()
52
+
46 53
 	s.solver = solver.NewSolver(solver.SolverOpt{
47 54
 		ResolveOpFunc: s.resolver(),
48 55
 		DefaultCache:  cache,
49 56
 	})
50
-	return s
57
+	return s, nil
51 58
 }
52 59
 
53 60
 func (s *Solver) resolver() solver.ResolveOpFunc {
... ...
@@ -67,6 +76,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
67 67
 		resolveWorker: s.resolveWorker,
68 68
 		ci:            s.ci,
69 69
 		cms:           map[string]solver.CacheManager{},
70
+		platforms:     s.platforms,
70 71
 	}
71 72
 }
72 73
 
... ...
@@ -3,10 +3,12 @@ package llbsolver
3 3
 import (
4 4
 	"strings"
5 5
 
6
+	"github.com/containerd/containerd/platforms"
6 7
 	"github.com/moby/buildkit/solver"
7 8
 	"github.com/moby/buildkit/solver/pb"
8 9
 	"github.com/moby/buildkit/source"
9 10
 	digest "github.com/opencontainers/go-digest"
11
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
10 12
 	"github.com/pkg/errors"
11 13
 )
12 14
 
... ...
@@ -38,11 +40,44 @@ func (v *vertex) Name() string {
38 38
 	return v.name
39 39
 }
40 40
 
41
-type LoadOpt func(*solver.VertexOptions)
41
+type LoadOpt func(*pb.Op, *pb.OpMetadata, *solver.VertexOptions) error
42 42
 
43 43
 func WithCacheSources(cms []solver.CacheManager) LoadOpt {
44
-	return func(opt *solver.VertexOptions) {
44
+	return func(_ *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
45 45
 		opt.CacheSources = cms
46
+		return nil
47
+	}
48
+}
49
+
50
+func RuntimePlatforms(p []specs.Platform) LoadOpt {
51
+	var defaultPlatform *pb.Platform
52
+	for i := range p {
53
+		p[i] = platforms.Normalize(p[i])
54
+	}
55
+	return func(op *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
56
+		if op.Platform == nil {
57
+			if defaultPlatform == nil {
58
+				p := platforms.DefaultSpec()
59
+				defaultPlatform = &pb.Platform{
60
+					OS:           p.OS,
61
+					Architecture: p.Architecture,
62
+				}
63
+			}
64
+			op.Platform = defaultPlatform
65
+		}
66
+		if _, ok := op.Op.(*pb.Op_Exec); ok {
67
+			var found bool
68
+			for _, pp := range p {
69
+				if pp.OS == op.Platform.OS && pp.Architecture == op.Platform.Architecture && pp.Variant == op.Platform.Variant {
70
+					found = true
71
+					break
72
+				}
73
+			}
74
+			if !found {
75
+				return errors.Errorf("runtime execution on platform %s not supported", platforms.Format(specs.Platform{OS: op.Platform.OS, Architecture: op.Platform.Architecture, Variant: op.Platform.Variant}))
76
+			}
77
+		}
78
+		return nil
46 79
 	}
47 80
 }
48 81
 
... ...
@@ -67,9 +102,11 @@ func newVertex(dgst digest.Digest, op *pb.Op, opMeta *pb.OpMetadata, load func(d
67 67
 		}
68 68
 	}
69 69
 	for _, fn := range opts {
70
-		fn(&opt)
70
+		if err := fn(op, opMeta, &opt); err != nil {
71
+			return nil, err
72
+		}
71 73
 	}
72
-	vtx := &vertex{sys: op.Op, options: opt, digest: dgst, name: llbOpName(op)}
74
+	vtx := &vertex{sys: op, options: opt, digest: dgst, name: llbOpName(op)}
73 75
 	for _, in := range op.Inputs {
74 76
 		sub, err := load(in.Digest)
75 77
 		if err != nil {
... ...
@@ -129,7 +166,7 @@ func loadLLB(def *pb.Definition, fn func(digest.Digest, *pb.Op, func(digest.Dige
129 129
 func llbOpName(op *pb.Op) string {
130 130
 	switch op := op.Op.(type) {
131 131
 	case *pb.Op_Source:
132
-		if id, err := source.FromLLB(op); err == nil {
132
+		if id, err := source.FromLLB(op, nil); err == nil {
133 133
 			if id, ok := id.(*source.LocalIdentifier); ok {
134 134
 				if len(id.IncludePatterns) == 1 {
135 135
 					return op.Source.Identifier + " (" + id.IncludePatterns[0] + ")"
... ...
@@ -12,6 +12,7 @@
12 12
 
13 13
 	It has these top-level messages:
14 14
 		Op
15
+		Platform
15 16
 		Input
16 17
 		ExecOp
17 18
 		Meta
... ...
@@ -25,7 +26,7 @@
25 25
 		OpMetadata
26 26
 		ExportCache
27 27
 		ProxyEnv
28
-		WorkerConstraint
28
+		WorkerConstraints
29 29
 		Definition
30 30
 */
31 31
 package pb
... ...
@@ -50,6 +51,7 @@ var _ = math.Inf
50 50
 // proto package needs to be updated.
51 51
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
52 52
 
53
+// MountType defines a type of a mount from a supported set
53 54
 type MountType int32
54 55
 
55 56
 const (
... ...
@@ -80,6 +82,34 @@ func (x MountType) String() string {
80 80
 }
81 81
 func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{0} }
82 82
 
83
+// CacheSharingOpt defines different sharing modes for cache mount
84
+type CacheSharingOpt int32
85
+
86
+const (
87
+	// SHARED cache mount can be used concurrently by multiple writers
88
+	CacheSharingOpt_SHARED CacheSharingOpt = 0
89
+	// PRIVATE creates a new mount if there are multiple writers
90
+	CacheSharingOpt_PRIVATE CacheSharingOpt = 1
91
+	// LOCKED pauses second writer until first one releases the mount
92
+	CacheSharingOpt_LOCKED CacheSharingOpt = 2
93
+)
94
+
95
+var CacheSharingOpt_name = map[int32]string{
96
+	0: "SHARED",
97
+	1: "PRIVATE",
98
+	2: "LOCKED",
99
+}
100
+var CacheSharingOpt_value = map[string]int32{
101
+	"SHARED":  0,
102
+	"PRIVATE": 1,
103
+	"LOCKED":  2,
104
+}
105
+
106
+func (x CacheSharingOpt) String() string {
107
+	return proto.EnumName(CacheSharingOpt_name, int32(x))
108
+}
109
+func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
110
+
83 111
 // Op represents a vertex of the LLB DAG.
84 112
 type Op struct {
85 113
 	// inputs is a set of input edges.
... ...
@@ -89,7 +119,9 @@ type Op struct {
89 89
 	//	*Op_Source
90 90
 	//	*Op_Copy
91 91
 	//	*Op_Build
92
-	Op isOp_Op `protobuf_oneof:"op"`
92
+	Op          isOp_Op            `protobuf_oneof:"op"`
93
+	Platform    *Platform          `protobuf:"bytes,10,opt,name=platform" json:"platform,omitempty"`
94
+	Constraints *WorkerConstraints `protobuf:"bytes,11,opt,name=constraints" json:"constraints,omitempty"`
93 95
 }
94 96
 
95 97
 func (m *Op) Reset()                    { *m = Op{} }
... ...
@@ -163,6 +195,20 @@ func (m *Op) GetBuild() *BuildOp {
163 163
 	return nil
164 164
 }
165 165
 
166
+func (m *Op) GetPlatform() *Platform {
167
+	if m != nil {
168
+		return m.Platform
169
+	}
170
+	return nil
171
+}
172
+
173
+func (m *Op) GetConstraints() *WorkerConstraints {
174
+	if m != nil {
175
+		return m.Constraints
176
+	}
177
+	return nil
178
+}
179
+
166 180
 // XXX_OneofFuncs is for the internal use of the proto package.
167 181
 func (*Op) 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{}) {
168 182
 	return _Op_OneofMarshaler, _Op_OneofUnmarshaler, _Op_OneofSizer, []interface{}{
... ...
@@ -275,6 +321,55 @@ func _Op_OneofSizer(msg proto.Message) (n int) {
275 275
 	return n
276 276
 }
277 277
 
278
+// Platform is github.com/opencontainers/image-spec/specs-go/v1.Platform
279
+type Platform struct {
280
+	Architecture string   `protobuf:"bytes,1,opt,name=Architecture,proto3" json:"Architecture,omitempty"`
281
+	OS           string   `protobuf:"bytes,2,opt,name=OS,proto3" json:"OS,omitempty"`
282
+	Variant      string   `protobuf:"bytes,3,opt,name=Variant,proto3" json:"Variant,omitempty"`
283
+	OSVersion    string   `protobuf:"bytes,4,opt,name=OSVersion,proto3" json:"OSVersion,omitempty"`
284
+	OSFeatures   []string `protobuf:"bytes,5,rep,name=OSFeatures" json:"OSFeatures,omitempty"`
285
+}
286
+
287
+func (m *Platform) Reset()                    { *m = Platform{} }
288
+func (m *Platform) String() string            { return proto.CompactTextString(m) }
289
+func (*Platform) ProtoMessage()               {}
290
+func (*Platform) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
291
+
292
+func (m *Platform) GetArchitecture() string {
293
+	if m != nil {
294
+		return m.Architecture
295
+	}
296
+	return ""
297
+}
298
+
299
+func (m *Platform) GetOS() string {
300
+	if m != nil {
301
+		return m.OS
302
+	}
303
+	return ""
304
+}
305
+
306
+func (m *Platform) GetVariant() string {
307
+	if m != nil {
308
+		return m.Variant
309
+	}
310
+	return ""
311
+}
312
+
313
+func (m *Platform) GetOSVersion() string {
314
+	if m != nil {
315
+		return m.OSVersion
316
+	}
317
+	return ""
318
+}
319
+
320
+func (m *Platform) GetOSFeatures() []string {
321
+	if m != nil {
322
+		return m.OSFeatures
323
+	}
324
+	return nil
325
+}
326
+
278 327
 // Input represents an input edge for an Op.
279 328
 type Input struct {
280 329
 	// digest of the marshaled input Op
... ...
@@ -286,7 +381,7 @@ type Input struct {
286 286
 func (m *Input) Reset()                    { *m = Input{} }
287 287
 func (m *Input) String() string            { return proto.CompactTextString(m) }
288 288
 func (*Input) ProtoMessage()               {}
289
-func (*Input) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
289
+func (*Input) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{2} }
290 290
 
291 291
 // ExecOp executes a command in a container.
292 292
 type ExecOp struct {
... ...
@@ -297,7 +392,7 @@ type ExecOp struct {
297 297
 func (m *ExecOp) Reset()                    { *m = ExecOp{} }
298 298
 func (m *ExecOp) String() string            { return proto.CompactTextString(m) }
299 299
 func (*ExecOp) ProtoMessage()               {}
300
-func (*ExecOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{2} }
300
+func (*ExecOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{3} }
301 301
 
302 302
 func (m *ExecOp) GetMeta() *Meta {
303 303
 	if m != nil {
... ...
@@ -327,7 +422,7 @@ type Meta struct {
327 327
 func (m *Meta) Reset()                    { *m = Meta{} }
328 328
 func (m *Meta) String() string            { return proto.CompactTextString(m) }
329 329
 func (*Meta) ProtoMessage()               {}
330
-func (*Meta) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{3} }
330
+func (*Meta) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{4} }
331 331
 
332 332
 func (m *Meta) GetArgs() []string {
333 333
 	if m != nil {
... ...
@@ -378,7 +473,7 @@ type Mount struct {
378 378
 func (m *Mount) Reset()                    { *m = Mount{} }
379 379
 func (m *Mount) String() string            { return proto.CompactTextString(m) }
380 380
 func (*Mount) ProtoMessage()               {}
381
-func (*Mount) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{4} }
381
+func (*Mount) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{5} }
382 382
 
383 383
 func (m *Mount) GetSelector() string {
384 384
 	if m != nil {
... ...
@@ -415,14 +510,18 @@ func (m *Mount) GetCacheOpt() *CacheOpt {
415 415
 	return nil
416 416
 }
417 417
 
418
+// CacheOpt defines options specific to cache mounts
418 419
 type CacheOpt struct {
420
+	// ID is an optional namespace for the mount
419 421
 	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
422
+	// Sharing is the sharing mode for the mount
423
+	Sharing CacheSharingOpt `protobuf:"varint,2,opt,name=sharing,proto3,enum=pb.CacheSharingOpt" json:"sharing,omitempty"`
420 424
 }
421 425
 
422 426
 func (m *CacheOpt) Reset()                    { *m = CacheOpt{} }
423 427
 func (m *CacheOpt) String() string            { return proto.CompactTextString(m) }
424 428
 func (*CacheOpt) ProtoMessage()               {}
425
-func (*CacheOpt) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{5} }
429
+func (*CacheOpt) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{6} }
426 430
 
427 431
 func (m *CacheOpt) GetID() string {
428 432
 	if m != nil {
... ...
@@ -431,6 +530,13 @@ func (m *CacheOpt) GetID() string {
431 431
 	return ""
432 432
 }
433 433
 
434
+func (m *CacheOpt) GetSharing() CacheSharingOpt {
435
+	if m != nil {
436
+		return m.Sharing
437
+	}
438
+	return CacheSharingOpt_SHARED
439
+}
440
+
434 441
 // CopyOp copies files across Ops.
435 442
 type CopyOp struct {
436 443
 	Src  []*CopySource `protobuf:"bytes,1,rep,name=src" json:"src,omitempty"`
... ...
@@ -440,7 +546,7 @@ type CopyOp struct {
440 440
 func (m *CopyOp) Reset()                    { *m = CopyOp{} }
441 441
 func (m *CopyOp) String() string            { return proto.CompactTextString(m) }
442 442
 func (*CopyOp) ProtoMessage()               {}
443
-func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{6} }
443
+func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{7} }
444 444
 
445 445
 func (m *CopyOp) GetSrc() []*CopySource {
446 446
 	if m != nil {
... ...
@@ -465,7 +571,7 @@ type CopySource struct {
465 465
 func (m *CopySource) Reset()                    { *m = CopySource{} }
466 466
 func (m *CopySource) String() string            { return proto.CompactTextString(m) }
467 467
 func (*CopySource) ProtoMessage()               {}
468
-func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{7} }
468
+func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
469 469
 
470 470
 func (m *CopySource) GetSelector() string {
471 471
 	if m != nil {
... ...
@@ -486,7 +592,7 @@ type SourceOp struct {
486 486
 func (m *SourceOp) Reset()                    { *m = SourceOp{} }
487 487
 func (m *SourceOp) String() string            { return proto.CompactTextString(m) }
488 488
 func (*SourceOp) ProtoMessage()               {}
489
-func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
489
+func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
490 490
 
491 491
 func (m *SourceOp) GetIdentifier() string {
492 492
 	if m != nil {
... ...
@@ -513,7 +619,7 @@ type BuildOp struct {
513 513
 func (m *BuildOp) Reset()                    { *m = BuildOp{} }
514 514
 func (m *BuildOp) String() string            { return proto.CompactTextString(m) }
515 515
 func (*BuildOp) ProtoMessage()               {}
516
-func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
516
+func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
517 517
 
518 518
 func (m *BuildOp) GetInputs() map[string]*BuildInput {
519 519
 	if m != nil {
... ...
@@ -544,22 +650,23 @@ type BuildInput struct {
544 544
 func (m *BuildInput) Reset()                    { *m = BuildInput{} }
545 545
 func (m *BuildInput) String() string            { return proto.CompactTextString(m) }
546 546
 func (*BuildInput) ProtoMessage()               {}
547
-func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
547
+func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
548 548
 
549 549
 // OpMetadata is a per-vertex metadata entry, which can be defined for arbitrary Op vertex and overridable on the run time.
550 550
 type OpMetadata struct {
551 551
 	// ignore_cache specifies to ignore the cache for this Op.
552 552
 	IgnoreCache bool `protobuf:"varint,1,opt,name=ignore_cache,json=ignoreCache,proto3" json:"ignore_cache,omitempty"`
553 553
 	// Description can be used for keeping any text fields that builder doesn't parse
554
-	Description      map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
555
-	WorkerConstraint *WorkerConstraint `protobuf:"bytes,3,opt,name=worker_constraint,json=workerConstraint" json:"worker_constraint,omitempty"`
556
-	ExportCache      *ExportCache      `protobuf:"bytes,4,opt,name=export_cache,json=exportCache" json:"export_cache,omitempty"`
554
+	Description map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
555
+	// index 3 reserved for WorkerConstraint in previous versions
556
+	// WorkerConstraint worker_constraint = 3;
557
+	ExportCache *ExportCache `protobuf:"bytes,4,opt,name=export_cache,json=exportCache" json:"export_cache,omitempty"`
557 558
 }
558 559
 
559 560
 func (m *OpMetadata) Reset()                    { *m = OpMetadata{} }
560 561
 func (m *OpMetadata) String() string            { return proto.CompactTextString(m) }
561 562
 func (*OpMetadata) ProtoMessage()               {}
562
-func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
563
+func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
563 564
 
564 565
 func (m *OpMetadata) GetIgnoreCache() bool {
565 566
 	if m != nil {
... ...
@@ -575,13 +682,6 @@ func (m *OpMetadata) GetDescription() map[string]string {
575 575
 	return nil
576 576
 }
577 577
 
578
-func (m *OpMetadata) GetWorkerConstraint() *WorkerConstraint {
579
-	if m != nil {
580
-		return m.WorkerConstraint
581
-	}
582
-	return nil
583
-}
584
-
585 578
 func (m *OpMetadata) GetExportCache() *ExportCache {
586 579
 	if m != nil {
587 580
 		return m.ExportCache
... ...
@@ -596,7 +696,7 @@ type ExportCache struct {
596 596
 func (m *ExportCache) Reset()                    { *m = ExportCache{} }
597 597
 func (m *ExportCache) String() string            { return proto.CompactTextString(m) }
598 598
 func (*ExportCache) ProtoMessage()               {}
599
-func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
599
+func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
600 600
 
601 601
 func (m *ExportCache) GetValue() bool {
602 602
 	if m != nil {
... ...
@@ -615,7 +715,7 @@ type ProxyEnv struct {
615 615
 func (m *ProxyEnv) Reset()                    { *m = ProxyEnv{} }
616 616
 func (m *ProxyEnv) String() string            { return proto.CompactTextString(m) }
617 617
 func (*ProxyEnv) ProtoMessage()               {}
618
-func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
618
+func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
619 619
 
620 620
 func (m *ProxyEnv) GetHttpProxy() string {
621 621
 	if m != nil {
... ...
@@ -645,17 +745,17 @@ func (m *ProxyEnv) GetNoProxy() string {
645 645
 	return ""
646 646
 }
647 647
 
648
-// WorkerConstraint is experimental and likely to be changed.
649
-type WorkerConstraint struct {
648
+// WorkerConstraints defines conditions for the worker
649
+type WorkerConstraints struct {
650 650
 	Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
651 651
 }
652 652
 
653
-func (m *WorkerConstraint) Reset()                    { *m = WorkerConstraint{} }
654
-func (m *WorkerConstraint) String() string            { return proto.CompactTextString(m) }
655
-func (*WorkerConstraint) ProtoMessage()               {}
656
-func (*WorkerConstraint) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
653
+func (m *WorkerConstraints) Reset()                    { *m = WorkerConstraints{} }
654
+func (m *WorkerConstraints) String() string            { return proto.CompactTextString(m) }
655
+func (*WorkerConstraints) ProtoMessage()               {}
656
+func (*WorkerConstraints) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
657 657
 
658
-func (m *WorkerConstraint) GetFilter() []string {
658
+func (m *WorkerConstraints) GetFilter() []string {
659 659
 	if m != nil {
660 660
 		return m.Filter
661 661
 	}
... ...
@@ -674,7 +774,7 @@ type Definition struct {
674 674
 func (m *Definition) Reset()                    { *m = Definition{} }
675 675
 func (m *Definition) String() string            { return proto.CompactTextString(m) }
676 676
 func (*Definition) ProtoMessage()               {}
677
-func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
677
+func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{16} }
678 678
 
679 679
 func (m *Definition) GetDef() [][]byte {
680 680
 	if m != nil {
... ...
@@ -692,6 +792,7 @@ func (m *Definition) GetMetadata() map[github_com_opencontainers_go_digest.Diges
692 692
 
693 693
 func init() {
694 694
 	proto.RegisterType((*Op)(nil), "pb.Op")
695
+	proto.RegisterType((*Platform)(nil), "pb.Platform")
695 696
 	proto.RegisterType((*Input)(nil), "pb.Input")
696 697
 	proto.RegisterType((*ExecOp)(nil), "pb.ExecOp")
697 698
 	proto.RegisterType((*Meta)(nil), "pb.Meta")
... ...
@@ -705,9 +806,10 @@ func init() {
705 705
 	proto.RegisterType((*OpMetadata)(nil), "pb.OpMetadata")
706 706
 	proto.RegisterType((*ExportCache)(nil), "pb.ExportCache")
707 707
 	proto.RegisterType((*ProxyEnv)(nil), "pb.ProxyEnv")
708
-	proto.RegisterType((*WorkerConstraint)(nil), "pb.WorkerConstraint")
708
+	proto.RegisterType((*WorkerConstraints)(nil), "pb.WorkerConstraints")
709 709
 	proto.RegisterType((*Definition)(nil), "pb.Definition")
710 710
 	proto.RegisterEnum("pb.MountType", MountType_name, MountType_value)
711
+	proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value)
711 712
 }
712 713
 func (m *Op) Marshal() (dAtA []byte, err error) {
713 714
 	size := m.Size()
... ...
@@ -743,6 +845,26 @@ func (m *Op) MarshalTo(dAtA []byte) (int, error) {
743 743
 		}
744 744
 		i += nn1
745 745
 	}
746
+	if m.Platform != nil {
747
+		dAtA[i] = 0x52
748
+		i++
749
+		i = encodeVarintOps(dAtA, i, uint64(m.Platform.Size()))
750
+		n2, err := m.Platform.MarshalTo(dAtA[i:])
751
+		if err != nil {
752
+			return 0, err
753
+		}
754
+		i += n2
755
+	}
756
+	if m.Constraints != nil {
757
+		dAtA[i] = 0x5a
758
+		i++
759
+		i = encodeVarintOps(dAtA, i, uint64(m.Constraints.Size()))
760
+		n3, err := m.Constraints.MarshalTo(dAtA[i:])
761
+		if err != nil {
762
+			return 0, err
763
+		}
764
+		i += n3
765
+	}
746 766
 	return i, nil
747 767
 }
748 768
 
... ...
@@ -752,11 +874,11 @@ func (m *Op_Exec) MarshalTo(dAtA []byte) (int, error) {
752 752
 		dAtA[i] = 0x12
753 753
 		i++
754 754
 		i = encodeVarintOps(dAtA, i, uint64(m.Exec.Size()))
755
-		n2, err := m.Exec.MarshalTo(dAtA[i:])
755
+		n4, err := m.Exec.MarshalTo(dAtA[i:])
756 756
 		if err != nil {
757 757
 			return 0, err
758 758
 		}
759
-		i += n2
759
+		i += n4
760 760
 	}
761 761
 	return i, nil
762 762
 }
... ...
@@ -766,11 +888,11 @@ func (m *Op_Source) MarshalTo(dAtA []byte) (int, error) {
766 766
 		dAtA[i] = 0x1a
767 767
 		i++
768 768
 		i = encodeVarintOps(dAtA, i, uint64(m.Source.Size()))
769
-		n3, err := m.Source.MarshalTo(dAtA[i:])
769
+		n5, err := m.Source.MarshalTo(dAtA[i:])
770 770
 		if err != nil {
771 771
 			return 0, err
772 772
 		}
773
-		i += n3
773
+		i += n5
774 774
 	}
775 775
 	return i, nil
776 776
 }
... ...
@@ -780,11 +902,11 @@ func (m *Op_Copy) MarshalTo(dAtA []byte) (int, error) {
780 780
 		dAtA[i] = 0x22
781 781
 		i++
782 782
 		i = encodeVarintOps(dAtA, i, uint64(m.Copy.Size()))
783
-		n4, err := m.Copy.MarshalTo(dAtA[i:])
783
+		n6, err := m.Copy.MarshalTo(dAtA[i:])
784 784
 		if err != nil {
785 785
 			return 0, err
786 786
 		}
787
-		i += n4
787
+		i += n6
788 788
 	}
789 789
 	return i, nil
790 790
 }
... ...
@@ -794,14 +916,71 @@ func (m *Op_Build) MarshalTo(dAtA []byte) (int, error) {
794 794
 		dAtA[i] = 0x2a
795 795
 		i++
796 796
 		i = encodeVarintOps(dAtA, i, uint64(m.Build.Size()))
797
-		n5, err := m.Build.MarshalTo(dAtA[i:])
797
+		n7, err := m.Build.MarshalTo(dAtA[i:])
798 798
 		if err != nil {
799 799
 			return 0, err
800 800
 		}
801
-		i += n5
801
+		i += n7
802
+	}
803
+	return i, nil
804
+}
805
+func (m *Platform) Marshal() (dAtA []byte, err error) {
806
+	size := m.Size()
807
+	dAtA = make([]byte, size)
808
+	n, err := m.MarshalTo(dAtA)
809
+	if err != nil {
810
+		return nil, err
811
+	}
812
+	return dAtA[:n], nil
813
+}
814
+
815
+func (m *Platform) MarshalTo(dAtA []byte) (int, error) {
816
+	var i int
817
+	_ = i
818
+	var l int
819
+	_ = l
820
+	if len(m.Architecture) > 0 {
821
+		dAtA[i] = 0xa
822
+		i++
823
+		i = encodeVarintOps(dAtA, i, uint64(len(m.Architecture)))
824
+		i += copy(dAtA[i:], m.Architecture)
825
+	}
826
+	if len(m.OS) > 0 {
827
+		dAtA[i] = 0x12
828
+		i++
829
+		i = encodeVarintOps(dAtA, i, uint64(len(m.OS)))
830
+		i += copy(dAtA[i:], m.OS)
831
+	}
832
+	if len(m.Variant) > 0 {
833
+		dAtA[i] = 0x1a
834
+		i++
835
+		i = encodeVarintOps(dAtA, i, uint64(len(m.Variant)))
836
+		i += copy(dAtA[i:], m.Variant)
837
+	}
838
+	if len(m.OSVersion) > 0 {
839
+		dAtA[i] = 0x22
840
+		i++
841
+		i = encodeVarintOps(dAtA, i, uint64(len(m.OSVersion)))
842
+		i += copy(dAtA[i:], m.OSVersion)
843
+	}
844
+	if len(m.OSFeatures) > 0 {
845
+		for _, s := range m.OSFeatures {
846
+			dAtA[i] = 0x2a
847
+			i++
848
+			l = len(s)
849
+			for l >= 1<<7 {
850
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
851
+				l >>= 7
852
+				i++
853
+			}
854
+			dAtA[i] = uint8(l)
855
+			i++
856
+			i += copy(dAtA[i:], s)
857
+		}
802 858
 	}
803 859
 	return i, nil
804 860
 }
861
+
805 862
 func (m *Input) Marshal() (dAtA []byte, err error) {
806 863
 	size := m.Size()
807 864
 	dAtA = make([]byte, size)
... ...
@@ -850,11 +1029,11 @@ func (m *ExecOp) MarshalTo(dAtA []byte) (int, error) {
850 850
 		dAtA[i] = 0xa
851 851
 		i++
852 852
 		i = encodeVarintOps(dAtA, i, uint64(m.Meta.Size()))
853
-		n6, err := m.Meta.MarshalTo(dAtA[i:])
853
+		n8, err := m.Meta.MarshalTo(dAtA[i:])
854 854
 		if err != nil {
855 855
 			return 0, err
856 856
 		}
857
-		i += n6
857
+		i += n8
858 858
 	}
859 859
 	if len(m.Mounts) > 0 {
860 860
 		for _, msg := range m.Mounts {
... ...
@@ -932,11 +1111,11 @@ func (m *Meta) MarshalTo(dAtA []byte) (int, error) {
932 932
 		dAtA[i] = 0x2a
933 933
 		i++
934 934
 		i = encodeVarintOps(dAtA, i, uint64(m.ProxyEnv.Size()))
935
-		n7, err := m.ProxyEnv.MarshalTo(dAtA[i:])
935
+		n9, err := m.ProxyEnv.MarshalTo(dAtA[i:])
936 936
 		if err != nil {
937 937
 			return 0, err
938 938
 		}
939
-		i += n7
939
+		i += n9
940 940
 	}
941 941
 	return i, nil
942 942
 }
... ...
@@ -999,11 +1178,11 @@ func (m *Mount) MarshalTo(dAtA []byte) (int, error) {
999 999
 		dAtA[i] = 0x1
1000 1000
 		i++
1001 1001
 		i = encodeVarintOps(dAtA, i, uint64(m.CacheOpt.Size()))
1002
-		n8, err := m.CacheOpt.MarshalTo(dAtA[i:])
1002
+		n10, err := m.CacheOpt.MarshalTo(dAtA[i:])
1003 1003
 		if err != nil {
1004 1004
 			return 0, err
1005 1005
 		}
1006
-		i += n8
1006
+		i += n10
1007 1007
 	}
1008 1008
 	return i, nil
1009 1009
 }
... ...
@@ -1029,6 +1208,11 @@ func (m *CacheOpt) MarshalTo(dAtA []byte) (int, error) {
1029 1029
 		i = encodeVarintOps(dAtA, i, uint64(len(m.ID)))
1030 1030
 		i += copy(dAtA[i:], m.ID)
1031 1031
 	}
1032
+	if m.Sharing != 0 {
1033
+		dAtA[i] = 0x10
1034
+		i++
1035
+		i = encodeVarintOps(dAtA, i, uint64(m.Sharing))
1036
+	}
1032 1037
 	return i, nil
1033 1038
 }
1034 1039
 
... ...
@@ -1178,11 +1362,11 @@ func (m *BuildOp) MarshalTo(dAtA []byte) (int, error) {
1178 1178
 				dAtA[i] = 0x12
1179 1179
 				i++
1180 1180
 				i = encodeVarintOps(dAtA, i, uint64(v.Size()))
1181
-				n9, err := v.MarshalTo(dAtA[i:])
1181
+				n11, err := v.MarshalTo(dAtA[i:])
1182 1182
 				if err != nil {
1183 1183
 					return 0, err
1184 1184
 				}
1185
-				i += n9
1185
+				i += n11
1186 1186
 			}
1187 1187
 		}
1188 1188
 	}
... ...
@@ -1190,11 +1374,11 @@ func (m *BuildOp) MarshalTo(dAtA []byte) (int, error) {
1190 1190
 		dAtA[i] = 0x1a
1191 1191
 		i++
1192 1192
 		i = encodeVarintOps(dAtA, i, uint64(m.Def.Size()))
1193
-		n10, err := m.Def.MarshalTo(dAtA[i:])
1193
+		n12, err := m.Def.MarshalTo(dAtA[i:])
1194 1194
 		if err != nil {
1195 1195
 			return 0, err
1196 1196
 		}
1197
-		i += n10
1197
+		i += n12
1198 1198
 	}
1199 1199
 	if len(m.Attrs) > 0 {
1200 1200
 		for k, _ := range m.Attrs {
... ...
@@ -1281,25 +1465,15 @@ func (m *OpMetadata) MarshalTo(dAtA []byte) (int, error) {
1281 1281
 			i += copy(dAtA[i:], v)
1282 1282
 		}
1283 1283
 	}
1284
-	if m.WorkerConstraint != nil {
1285
-		dAtA[i] = 0x1a
1286
-		i++
1287
-		i = encodeVarintOps(dAtA, i, uint64(m.WorkerConstraint.Size()))
1288
-		n11, err := m.WorkerConstraint.MarshalTo(dAtA[i:])
1289
-		if err != nil {
1290
-			return 0, err
1291
-		}
1292
-		i += n11
1293
-	}
1294 1284
 	if m.ExportCache != nil {
1295 1285
 		dAtA[i] = 0x22
1296 1286
 		i++
1297 1287
 		i = encodeVarintOps(dAtA, i, uint64(m.ExportCache.Size()))
1298
-		n12, err := m.ExportCache.MarshalTo(dAtA[i:])
1288
+		n13, err := m.ExportCache.MarshalTo(dAtA[i:])
1299 1289
 		if err != nil {
1300 1290
 			return 0, err
1301 1291
 		}
1302
-		i += n12
1292
+		i += n13
1303 1293
 	}
1304 1294
 	return i, nil
1305 1295
 }
... ...
@@ -1374,7 +1548,7 @@ func (m *ProxyEnv) MarshalTo(dAtA []byte) (int, error) {
1374 1374
 	return i, nil
1375 1375
 }
1376 1376
 
1377
-func (m *WorkerConstraint) Marshal() (dAtA []byte, err error) {
1377
+func (m *WorkerConstraints) Marshal() (dAtA []byte, err error) {
1378 1378
 	size := m.Size()
1379 1379
 	dAtA = make([]byte, size)
1380 1380
 	n, err := m.MarshalTo(dAtA)
... ...
@@ -1384,7 +1558,7 @@ func (m *WorkerConstraint) Marshal() (dAtA []byte, err error) {
1384 1384
 	return dAtA[:n], nil
1385 1385
 }
1386 1386
 
1387
-func (m *WorkerConstraint) MarshalTo(dAtA []byte) (int, error) {
1387
+func (m *WorkerConstraints) MarshalTo(dAtA []byte) (int, error) {
1388 1388
 	var i int
1389 1389
 	_ = i
1390 1390
 	var l int
... ...
@@ -1449,11 +1623,11 @@ func (m *Definition) MarshalTo(dAtA []byte) (int, error) {
1449 1449
 			dAtA[i] = 0x12
1450 1450
 			i++
1451 1451
 			i = encodeVarintOps(dAtA, i, uint64((&v).Size()))
1452
-			n13, err := (&v).MarshalTo(dAtA[i:])
1452
+			n14, err := (&v).MarshalTo(dAtA[i:])
1453 1453
 			if err != nil {
1454 1454
 				return 0, err
1455 1455
 			}
1456
-			i += n13
1456
+			i += n14
1457 1457
 		}
1458 1458
 	}
1459 1459
 	return i, nil
... ...
@@ -1480,6 +1654,14 @@ func (m *Op) Size() (n int) {
1480 1480
 	if m.Op != nil {
1481 1481
 		n += m.Op.Size()
1482 1482
 	}
1483
+	if m.Platform != nil {
1484
+		l = m.Platform.Size()
1485
+		n += 1 + l + sovOps(uint64(l))
1486
+	}
1487
+	if m.Constraints != nil {
1488
+		l = m.Constraints.Size()
1489
+		n += 1 + l + sovOps(uint64(l))
1490
+	}
1483 1491
 	return n
1484 1492
 }
1485 1493
 
... ...
@@ -1519,6 +1701,34 @@ func (m *Op_Build) Size() (n int) {
1519 1519
 	}
1520 1520
 	return n
1521 1521
 }
1522
+func (m *Platform) Size() (n int) {
1523
+	var l int
1524
+	_ = l
1525
+	l = len(m.Architecture)
1526
+	if l > 0 {
1527
+		n += 1 + l + sovOps(uint64(l))
1528
+	}
1529
+	l = len(m.OS)
1530
+	if l > 0 {
1531
+		n += 1 + l + sovOps(uint64(l))
1532
+	}
1533
+	l = len(m.Variant)
1534
+	if l > 0 {
1535
+		n += 1 + l + sovOps(uint64(l))
1536
+	}
1537
+	l = len(m.OSVersion)
1538
+	if l > 0 {
1539
+		n += 1 + l + sovOps(uint64(l))
1540
+	}
1541
+	if len(m.OSFeatures) > 0 {
1542
+		for _, s := range m.OSFeatures {
1543
+			l = len(s)
1544
+			n += 1 + l + sovOps(uint64(l))
1545
+		}
1546
+	}
1547
+	return n
1548
+}
1549
+
1522 1550
 func (m *Input) Size() (n int) {
1523 1551
 	var l int
1524 1552
 	_ = l
... ...
@@ -1615,6 +1825,9 @@ func (m *CacheOpt) Size() (n int) {
1615 1615
 	if l > 0 {
1616 1616
 		n += 1 + l + sovOps(uint64(l))
1617 1617
 	}
1618
+	if m.Sharing != 0 {
1619
+		n += 1 + sovOps(uint64(m.Sharing))
1620
+	}
1618 1621
 	return n
1619 1622
 }
1620 1623
 
... ...
@@ -1722,10 +1935,6 @@ func (m *OpMetadata) Size() (n int) {
1722 1722
 			n += mapEntrySize + 1 + sovOps(uint64(mapEntrySize))
1723 1723
 		}
1724 1724
 	}
1725
-	if m.WorkerConstraint != nil {
1726
-		l = m.WorkerConstraint.Size()
1727
-		n += 1 + l + sovOps(uint64(l))
1728
-	}
1729 1725
 	if m.ExportCache != nil {
1730 1726
 		l = m.ExportCache.Size()
1731 1727
 		n += 1 + l + sovOps(uint64(l))
... ...
@@ -1764,7 +1973,7 @@ func (m *ProxyEnv) Size() (n int) {
1764 1764
 	return n
1765 1765
 }
1766 1766
 
1767
-func (m *WorkerConstraint) Size() (n int) {
1767
+func (m *WorkerConstraints) Size() (n int) {
1768 1768
 	var l int
1769 1769
 	_ = l
1770 1770
 	if len(m.Filter) > 0 {
... ...
@@ -1998,6 +2207,267 @@ func (m *Op) Unmarshal(dAtA []byte) error {
1998 1998
 			}
1999 1999
 			m.Op = &Op_Build{v}
2000 2000
 			iNdEx = postIndex
2001
+		case 10:
2002
+			if wireType != 2 {
2003
+				return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType)
2004
+			}
2005
+			var msglen int
2006
+			for shift := uint(0); ; shift += 7 {
2007
+				if shift >= 64 {
2008
+					return ErrIntOverflowOps
2009
+				}
2010
+				if iNdEx >= l {
2011
+					return io.ErrUnexpectedEOF
2012
+				}
2013
+				b := dAtA[iNdEx]
2014
+				iNdEx++
2015
+				msglen |= (int(b) & 0x7F) << shift
2016
+				if b < 0x80 {
2017
+					break
2018
+				}
2019
+			}
2020
+			if msglen < 0 {
2021
+				return ErrInvalidLengthOps
2022
+			}
2023
+			postIndex := iNdEx + msglen
2024
+			if postIndex > l {
2025
+				return io.ErrUnexpectedEOF
2026
+			}
2027
+			if m.Platform == nil {
2028
+				m.Platform = &Platform{}
2029
+			}
2030
+			if err := m.Platform.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
2031
+				return err
2032
+			}
2033
+			iNdEx = postIndex
2034
+		case 11:
2035
+			if wireType != 2 {
2036
+				return fmt.Errorf("proto: wrong wireType = %d for field Constraints", wireType)
2037
+			}
2038
+			var msglen int
2039
+			for shift := uint(0); ; shift += 7 {
2040
+				if shift >= 64 {
2041
+					return ErrIntOverflowOps
2042
+				}
2043
+				if iNdEx >= l {
2044
+					return io.ErrUnexpectedEOF
2045
+				}
2046
+				b := dAtA[iNdEx]
2047
+				iNdEx++
2048
+				msglen |= (int(b) & 0x7F) << shift
2049
+				if b < 0x80 {
2050
+					break
2051
+				}
2052
+			}
2053
+			if msglen < 0 {
2054
+				return ErrInvalidLengthOps
2055
+			}
2056
+			postIndex := iNdEx + msglen
2057
+			if postIndex > l {
2058
+				return io.ErrUnexpectedEOF
2059
+			}
2060
+			if m.Constraints == nil {
2061
+				m.Constraints = &WorkerConstraints{}
2062
+			}
2063
+			if err := m.Constraints.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
2064
+				return err
2065
+			}
2066
+			iNdEx = postIndex
2067
+		default:
2068
+			iNdEx = preIndex
2069
+			skippy, err := skipOps(dAtA[iNdEx:])
2070
+			if err != nil {
2071
+				return err
2072
+			}
2073
+			if skippy < 0 {
2074
+				return ErrInvalidLengthOps
2075
+			}
2076
+			if (iNdEx + skippy) > l {
2077
+				return io.ErrUnexpectedEOF
2078
+			}
2079
+			iNdEx += skippy
2080
+		}
2081
+	}
2082
+
2083
+	if iNdEx > l {
2084
+		return io.ErrUnexpectedEOF
2085
+	}
2086
+	return nil
2087
+}
2088
+func (m *Platform) Unmarshal(dAtA []byte) error {
2089
+	l := len(dAtA)
2090
+	iNdEx := 0
2091
+	for iNdEx < l {
2092
+		preIndex := iNdEx
2093
+		var wire uint64
2094
+		for shift := uint(0); ; shift += 7 {
2095
+			if shift >= 64 {
2096
+				return ErrIntOverflowOps
2097
+			}
2098
+			if iNdEx >= l {
2099
+				return io.ErrUnexpectedEOF
2100
+			}
2101
+			b := dAtA[iNdEx]
2102
+			iNdEx++
2103
+			wire |= (uint64(b) & 0x7F) << shift
2104
+			if b < 0x80 {
2105
+				break
2106
+			}
2107
+		}
2108
+		fieldNum := int32(wire >> 3)
2109
+		wireType := int(wire & 0x7)
2110
+		if wireType == 4 {
2111
+			return fmt.Errorf("proto: Platform: wiretype end group for non-group")
2112
+		}
2113
+		if fieldNum <= 0 {
2114
+			return fmt.Errorf("proto: Platform: illegal tag %d (wire type %d)", fieldNum, wire)
2115
+		}
2116
+		switch fieldNum {
2117
+		case 1:
2118
+			if wireType != 2 {
2119
+				return fmt.Errorf("proto: wrong wireType = %d for field Architecture", wireType)
2120
+			}
2121
+			var stringLen uint64
2122
+			for shift := uint(0); ; shift += 7 {
2123
+				if shift >= 64 {
2124
+					return ErrIntOverflowOps
2125
+				}
2126
+				if iNdEx >= l {
2127
+					return io.ErrUnexpectedEOF
2128
+				}
2129
+				b := dAtA[iNdEx]
2130
+				iNdEx++
2131
+				stringLen |= (uint64(b) & 0x7F) << shift
2132
+				if b < 0x80 {
2133
+					break
2134
+				}
2135
+			}
2136
+			intStringLen := int(stringLen)
2137
+			if intStringLen < 0 {
2138
+				return ErrInvalidLengthOps
2139
+			}
2140
+			postIndex := iNdEx + intStringLen
2141
+			if postIndex > l {
2142
+				return io.ErrUnexpectedEOF
2143
+			}
2144
+			m.Architecture = string(dAtA[iNdEx:postIndex])
2145
+			iNdEx = postIndex
2146
+		case 2:
2147
+			if wireType != 2 {
2148
+				return fmt.Errorf("proto: wrong wireType = %d for field OS", wireType)
2149
+			}
2150
+			var stringLen uint64
2151
+			for shift := uint(0); ; shift += 7 {
2152
+				if shift >= 64 {
2153
+					return ErrIntOverflowOps
2154
+				}
2155
+				if iNdEx >= l {
2156
+					return io.ErrUnexpectedEOF
2157
+				}
2158
+				b := dAtA[iNdEx]
2159
+				iNdEx++
2160
+				stringLen |= (uint64(b) & 0x7F) << shift
2161
+				if b < 0x80 {
2162
+					break
2163
+				}
2164
+			}
2165
+			intStringLen := int(stringLen)
2166
+			if intStringLen < 0 {
2167
+				return ErrInvalidLengthOps
2168
+			}
2169
+			postIndex := iNdEx + intStringLen
2170
+			if postIndex > l {
2171
+				return io.ErrUnexpectedEOF
2172
+			}
2173
+			m.OS = string(dAtA[iNdEx:postIndex])
2174
+			iNdEx = postIndex
2175
+		case 3:
2176
+			if wireType != 2 {
2177
+				return fmt.Errorf("proto: wrong wireType = %d for field Variant", wireType)
2178
+			}
2179
+			var stringLen uint64
2180
+			for shift := uint(0); ; shift += 7 {
2181
+				if shift >= 64 {
2182
+					return ErrIntOverflowOps
2183
+				}
2184
+				if iNdEx >= l {
2185
+					return io.ErrUnexpectedEOF
2186
+				}
2187
+				b := dAtA[iNdEx]
2188
+				iNdEx++
2189
+				stringLen |= (uint64(b) & 0x7F) << shift
2190
+				if b < 0x80 {
2191
+					break
2192
+				}
2193
+			}
2194
+			intStringLen := int(stringLen)
2195
+			if intStringLen < 0 {
2196
+				return ErrInvalidLengthOps
2197
+			}
2198
+			postIndex := iNdEx + intStringLen
2199
+			if postIndex > l {
2200
+				return io.ErrUnexpectedEOF
2201
+			}
2202
+			m.Variant = string(dAtA[iNdEx:postIndex])
2203
+			iNdEx = postIndex
2204
+		case 4:
2205
+			if wireType != 2 {
2206
+				return fmt.Errorf("proto: wrong wireType = %d for field OSVersion", wireType)
2207
+			}
2208
+			var stringLen uint64
2209
+			for shift := uint(0); ; shift += 7 {
2210
+				if shift >= 64 {
2211
+					return ErrIntOverflowOps
2212
+				}
2213
+				if iNdEx >= l {
2214
+					return io.ErrUnexpectedEOF
2215
+				}
2216
+				b := dAtA[iNdEx]
2217
+				iNdEx++
2218
+				stringLen |= (uint64(b) & 0x7F) << shift
2219
+				if b < 0x80 {
2220
+					break
2221
+				}
2222
+			}
2223
+			intStringLen := int(stringLen)
2224
+			if intStringLen < 0 {
2225
+				return ErrInvalidLengthOps
2226
+			}
2227
+			postIndex := iNdEx + intStringLen
2228
+			if postIndex > l {
2229
+				return io.ErrUnexpectedEOF
2230
+			}
2231
+			m.OSVersion = string(dAtA[iNdEx:postIndex])
2232
+			iNdEx = postIndex
2233
+		case 5:
2234
+			if wireType != 2 {
2235
+				return fmt.Errorf("proto: wrong wireType = %d for field OSFeatures", wireType)
2236
+			}
2237
+			var stringLen uint64
2238
+			for shift := uint(0); ; shift += 7 {
2239
+				if shift >= 64 {
2240
+					return ErrIntOverflowOps
2241
+				}
2242
+				if iNdEx >= l {
2243
+					return io.ErrUnexpectedEOF
2244
+				}
2245
+				b := dAtA[iNdEx]
2246
+				iNdEx++
2247
+				stringLen |= (uint64(b) & 0x7F) << shift
2248
+				if b < 0x80 {
2249
+					break
2250
+				}
2251
+			}
2252
+			intStringLen := int(stringLen)
2253
+			if intStringLen < 0 {
2254
+				return ErrInvalidLengthOps
2255
+			}
2256
+			postIndex := iNdEx + intStringLen
2257
+			if postIndex > l {
2258
+				return io.ErrUnexpectedEOF
2259
+			}
2260
+			m.OSFeatures = append(m.OSFeatures, string(dAtA[iNdEx:postIndex]))
2261
+			iNdEx = postIndex
2001 2262
 		default:
2002 2263
 			iNdEx = preIndex
2003 2264
 			skippy, err := skipOps(dAtA[iNdEx:])
... ...
@@ -2706,6 +3176,25 @@ func (m *CacheOpt) Unmarshal(dAtA []byte) error {
2706 2706
 			}
2707 2707
 			m.ID = string(dAtA[iNdEx:postIndex])
2708 2708
 			iNdEx = postIndex
2709
+		case 2:
2710
+			if wireType != 0 {
2711
+				return fmt.Errorf("proto: wrong wireType = %d for field Sharing", wireType)
2712
+			}
2713
+			m.Sharing = 0
2714
+			for shift := uint(0); ; shift += 7 {
2715
+				if shift >= 64 {
2716
+					return ErrIntOverflowOps
2717
+				}
2718
+				if iNdEx >= l {
2719
+					return io.ErrUnexpectedEOF
2720
+				}
2721
+				b := dAtA[iNdEx]
2722
+				iNdEx++
2723
+				m.Sharing |= (CacheSharingOpt(b) & 0x7F) << shift
2724
+				if b < 0x80 {
2725
+					break
2726
+				}
2727
+			}
2709 2728
 		default:
2710 2729
 			iNdEx = preIndex
2711 2730
 			skippy, err := skipOps(dAtA[iNdEx:])
... ...
@@ -3711,39 +4200,6 @@ func (m *OpMetadata) Unmarshal(dAtA []byte) error {
3711 3711
 			}
3712 3712
 			m.Description[mapkey] = mapvalue
3713 3713
 			iNdEx = postIndex
3714
-		case 3:
3715
-			if wireType != 2 {
3716
-				return fmt.Errorf("proto: wrong wireType = %d for field WorkerConstraint", wireType)
3717
-			}
3718
-			var msglen int
3719
-			for shift := uint(0); ; shift += 7 {
3720
-				if shift >= 64 {
3721
-					return ErrIntOverflowOps
3722
-				}
3723
-				if iNdEx >= l {
3724
-					return io.ErrUnexpectedEOF
3725
-				}
3726
-				b := dAtA[iNdEx]
3727
-				iNdEx++
3728
-				msglen |= (int(b) & 0x7F) << shift
3729
-				if b < 0x80 {
3730
-					break
3731
-				}
3732
-			}
3733
-			if msglen < 0 {
3734
-				return ErrInvalidLengthOps
3735
-			}
3736
-			postIndex := iNdEx + msglen
3737
-			if postIndex > l {
3738
-				return io.ErrUnexpectedEOF
3739
-			}
3740
-			if m.WorkerConstraint == nil {
3741
-				m.WorkerConstraint = &WorkerConstraint{}
3742
-			}
3743
-			if err := m.WorkerConstraint.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
3744
-				return err
3745
-			}
3746
-			iNdEx = postIndex
3747 3714
 		case 4:
3748 3715
 			if wireType != 2 {
3749 3716
 				return fmt.Errorf("proto: wrong wireType = %d for field ExportCache", wireType)
... ...
@@ -4034,7 +4490,7 @@ func (m *ProxyEnv) Unmarshal(dAtA []byte) error {
4034 4034
 	}
4035 4035
 	return nil
4036 4036
 }
4037
-func (m *WorkerConstraint) Unmarshal(dAtA []byte) error {
4037
+func (m *WorkerConstraints) Unmarshal(dAtA []byte) error {
4038 4038
 	l := len(dAtA)
4039 4039
 	iNdEx := 0
4040 4040
 	for iNdEx < l {
... ...
@@ -4057,10 +4513,10 @@ func (m *WorkerConstraint) Unmarshal(dAtA []byte) error {
4057 4057
 		fieldNum := int32(wire >> 3)
4058 4058
 		wireType := int(wire & 0x7)
4059 4059
 		if wireType == 4 {
4060
-			return fmt.Errorf("proto: WorkerConstraint: wiretype end group for non-group")
4060
+			return fmt.Errorf("proto: WorkerConstraints: wiretype end group for non-group")
4061 4061
 		}
4062 4062
 		if fieldNum <= 0 {
4063
-			return fmt.Errorf("proto: WorkerConstraint: illegal tag %d (wire type %d)", fieldNum, wire)
4063
+			return fmt.Errorf("proto: WorkerConstraints: illegal tag %d (wire type %d)", fieldNum, wire)
4064 4064
 		}
4065 4065
 		switch fieldNum {
4066 4066
 		case 1:
... ...
@@ -4423,72 +4879,81 @@ var (
4423 4423
 func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
4424 4424
 
4425 4425
 var fileDescriptorOps = []byte{
4426
-	// 1062 bytes of a gzipped FileDescriptorProto
4427
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0x1b, 0xc5,
4428
-	0x17, 0xcf, 0xae, 0x3f, 0xb2, 0x7b, 0x36, 0xed, 0xdf, 0xff, 0x21, 0x2a, 0xc6, 0x94, 0xc4, 0x6c,
4429
-	0x11, 0x72, 0xd3, 0xc6, 0x91, 0x8c, 0x84, 0x2a, 0x2e, 0x2a, 0xe2, 0x0f, 0x14, 0x83, 0x42, 0xaa,
4430
-	0x49, 0x04, 0x97, 0x91, 0xbd, 0x1e, 0x3b, 0xab, 0x3a, 0x3b, 0xab, 0xdd, 0xd9, 0x24, 0xbe, 0x00,
4431
-	0x89, 0x3e, 0x01, 0x12, 0x4f, 0xc1, 0x43, 0xc0, 0x75, 0x2f, 0xb9, 0x85, 0x8b, 0x82, 0xc2, 0x8b,
4432
-	0xa0, 0x73, 0x66, 0xbc, 0xeb, 0x86, 0x22, 0xb5, 0x82, 0x2b, 0xcf, 0x9c, 0xf3, 0x3b, 0x67, 0xce,
4433
-	0xf9, 0x9d, 0x8f, 0x35, 0xb8, 0x32, 0x4e, 0xdb, 0x71, 0x22, 0x95, 0x64, 0x76, 0x3c, 0x6e, 0xec,
4434
-	0xce, 0x42, 0x75, 0x96, 0x8d, 0xdb, 0x81, 0x3c, 0xdf, 0x9b, 0xc9, 0x99, 0xdc, 0x23, 0xd5, 0x38,
4435
-	0x9b, 0xd2, 0x8d, 0x2e, 0x74, 0xd2, 0x26, 0xfe, 0xcf, 0x16, 0xd8, 0x47, 0x31, 0x7b, 0x1f, 0xaa,
4436
-	0x61, 0x14, 0x67, 0x2a, 0xad, 0x5b, 0xcd, 0x52, 0xcb, 0xeb, 0xb8, 0xed, 0x78, 0xdc, 0x1e, 0xa2,
4437
-	0x84, 0x1b, 0x05, 0x6b, 0x42, 0x59, 0x5c, 0x89, 0xa0, 0x6e, 0x37, 0xad, 0x96, 0xd7, 0x01, 0x04,
4438
-	0x0c, 0xae, 0x44, 0x70, 0x14, 0x1f, 0xac, 0x71, 0xd2, 0xb0, 0x0f, 0xa1, 0x9a, 0xca, 0x2c, 0x09,
4439
-	0x44, 0xbd, 0x44, 0x98, 0x0d, 0xc4, 0x1c, 0x93, 0x84, 0x50, 0x46, 0x8b, 0x9e, 0x02, 0x19, 0x2f,
4440
-	0xea, 0xe5, 0xc2, 0x53, 0x4f, 0xc6, 0x0b, 0xed, 0x09, 0x35, 0xec, 0x1e, 0x54, 0xc6, 0x59, 0x38,
4441
-	0x9f, 0xd4, 0x2b, 0x04, 0xf1, 0x10, 0xd2, 0x45, 0x01, 0x61, 0xb4, 0xae, 0x5b, 0x06, 0x5b, 0xc6,
4442
-	0xfe, 0xb7, 0x50, 0xa1, 0x38, 0xd9, 0xe7, 0x50, 0x9d, 0x84, 0x33, 0x91, 0xaa, 0xba, 0xd5, 0xb4,
4443
-	0x5a, 0x6e, 0xb7, 0xf3, 0xfc, 0xc5, 0xf6, 0xda, 0x6f, 0x2f, 0xb6, 0x77, 0x56, 0x08, 0x91, 0xb1,
4444
-	0x88, 0x02, 0x19, 0xa9, 0x51, 0x18, 0x89, 0x24, 0xdd, 0x9b, 0xc9, 0x5d, 0x6d, 0xd2, 0xee, 0xd3,
4445
-	0x0f, 0x37, 0x1e, 0xd8, 0x7d, 0xa8, 0x84, 0xd1, 0x44, 0x5c, 0x51, 0xb2, 0xa5, 0xee, 0x5b, 0xc6,
4446
-	0x95, 0x77, 0x94, 0xa9, 0x38, 0x53, 0x43, 0x54, 0x71, 0x8d, 0xf0, 0x87, 0x50, 0xd5, 0x34, 0xb0,
4447
-	0xbb, 0x50, 0x3e, 0x17, 0x6a, 0x44, 0xcf, 0x7b, 0x1d, 0x07, 0x63, 0x3e, 0x14, 0x6a, 0xc4, 0x49,
4448
-	0x8a, 0x0c, 0x9f, 0xcb, 0x2c, 0x52, 0x69, 0xdd, 0x2e, 0x18, 0x3e, 0x44, 0x09, 0x37, 0x0a, 0xff,
4449
-	0x1b, 0x28, 0xa3, 0x01, 0x63, 0x50, 0x1e, 0x25, 0x33, 0x5d, 0x0a, 0x97, 0xd3, 0x99, 0xd5, 0xa0,
4450
-	0x24, 0xa2, 0x0b, 0xb2, 0x75, 0x39, 0x1e, 0x51, 0x12, 0x5c, 0x4e, 0x88, 0x6a, 0x97, 0xe3, 0x11,
4451
-	0xed, 0xb2, 0x54, 0x24, 0xc4, 0xab, 0xcb, 0xe9, 0xcc, 0xee, 0x83, 0x1b, 0x27, 0xf2, 0x6a, 0x71,
4452
-	0x8a, 0xd6, 0x95, 0xa2, 0x2c, 0x4f, 0x50, 0x38, 0x88, 0x2e, 0xb8, 0x13, 0x9b, 0x93, 0xff, 0x9d,
4453
-	0x0d, 0x15, 0x0a, 0x88, 0xb5, 0x30, 0xfd, 0x38, 0xd3, 0x4c, 0x96, 0xba, 0xcc, 0xa4, 0x0f, 0x44,
4454
-	0x74, 0x9e, 0x3d, 0x92, 0xde, 0x00, 0x27, 0x15, 0x73, 0x11, 0x28, 0x99, 0x10, 0x57, 0x2e, 0xcf,
4455
-	0xef, 0x18, 0xce, 0x04, 0xcb, 0xa1, 0x23, 0xa4, 0x33, 0x7b, 0x00, 0x55, 0x49, 0x1c, 0x52, 0x90,
4456
-	0xff, 0xc0, 0xac, 0x81, 0xa0, 0xf3, 0x44, 0x8c, 0x26, 0x32, 0x9a, 0x2f, 0x28, 0x74, 0x87, 0xe7,
4457
-	0x77, 0xf6, 0x00, 0x5c, 0x62, 0xed, 0x64, 0x11, 0x8b, 0x7a, 0xb5, 0x69, 0xb5, 0x6e, 0x77, 0x6e,
4458
-	0xe5, 0x8c, 0xa2, 0x90, 0x17, 0x7a, 0xd6, 0x02, 0x27, 0x18, 0x05, 0x67, 0xe2, 0x28, 0x56, 0xf5,
4459
-	0xcd, 0x82, 0x83, 0x9e, 0x91, 0xf1, 0x5c, 0xeb, 0x37, 0xc0, 0x59, 0x4a, 0xd9, 0x6d, 0xb0, 0x87,
4460
-	0x7d, 0xdd, 0x4c, 0xdc, 0x1e, 0xf6, 0xfd, 0xc7, 0x50, 0xd5, 0x6d, 0xca, 0x9a, 0x50, 0x4a, 0x93,
4461
-	0xc0, 0x8c, 0xca, 0xed, 0x65, 0xff, 0xea, 0x4e, 0xe7, 0xa8, 0xca, 0x73, 0xb7, 0x8b, 0xdc, 0x7d,
4462
-	0x0e, 0x50, 0xc0, 0xfe, 0x1b, 0x8e, 0xfd, 0x1f, 0x2c, 0x70, 0x96, 0x13, 0xc6, 0xb6, 0x00, 0xc2,
4463
-	0x89, 0x88, 0x54, 0x38, 0x0d, 0x45, 0x62, 0x02, 0x5f, 0x91, 0xb0, 0x5d, 0xa8, 0x8c, 0x94, 0x4a,
4464
-	0x96, 0x1d, 0xf8, 0xf6, 0xea, 0x78, 0xb6, 0xf7, 0x51, 0x33, 0x88, 0x54, 0xb2, 0xe0, 0x1a, 0xd5,
4465
-	0x78, 0x04, 0x50, 0x08, 0xb1, 0xdd, 0x9e, 0x8a, 0x85, 0xf1, 0x8a, 0x47, 0xb6, 0x09, 0x95, 0x8b,
4466
-	0xd1, 0x3c, 0x13, 0x26, 0x28, 0x7d, 0xf9, 0xc4, 0x7e, 0x64, 0xf9, 0x3f, 0xd9, 0xb0, 0x6e, 0xc6,
4467
-	0x95, 0x3d, 0x84, 0x75, 0x1a, 0x57, 0x13, 0xd1, 0xab, 0x33, 0x5d, 0x42, 0xd8, 0x5e, 0xbe, 0x87,
4468
-	0x56, 0x62, 0x34, 0xae, 0xf4, 0x3e, 0x32, 0x31, 0x16, 0x5b, 0xa9, 0x34, 0x11, 0x53, 0xb3, 0x70,
4469
-	0xa8, 0x14, 0x7d, 0x31, 0x0d, 0xa3, 0x50, 0x85, 0x32, 0xe2, 0xa8, 0x62, 0x0f, 0x97, 0x59, 0x97,
4470
-	0xc9, 0xe3, 0x9d, 0x55, 0x8f, 0x7f, 0x4f, 0x7a, 0x08, 0xde, 0xca, 0x33, 0xaf, 0xc8, 0xfa, 0x83,
4471
-	0xd5, 0xac, 0xcd, 0x93, 0xe4, 0x4e, 0x6f, 0xcb, 0x82, 0x85, 0x7f, 0xc1, 0xdf, 0xc7, 0x00, 0x85,
4472
-	0xcb, 0xd7, 0xef, 0x14, 0xff, 0x47, 0x1b, 0xe0, 0x28, 0xc6, 0x1d, 0x32, 0x19, 0xd1, 0xca, 0xd9,
4473
-	0x08, 0x67, 0x91, 0x4c, 0xc4, 0x29, 0xf5, 0x37, 0xd9, 0x3b, 0xdc, 0xd3, 0x32, 0x6a, 0x73, 0xb6,
4474
-	0x0f, 0xde, 0x44, 0xa4, 0x41, 0x12, 0xc6, 0x48, 0x98, 0x21, 0x7d, 0x1b, 0x73, 0x2a, 0xfc, 0xb4,
4475
-	0xfb, 0x05, 0x42, 0x73, 0xb5, 0x6a, 0xc3, 0xf6, 0xe1, 0xff, 0x97, 0x32, 0x79, 0x2a, 0x92, 0xd3,
4476
-	0x40, 0x46, 0xa9, 0x4a, 0x46, 0x61, 0xa4, 0x4c, 0x3d, 0x36, 0xd1, 0xd1, 0xd7, 0xa4, 0xec, 0xe5,
4477
-	0x3a, 0x5e, 0xbb, 0xbc, 0x21, 0x61, 0x1d, 0xd8, 0x10, 0x57, 0xb1, 0x4c, 0x94, 0x09, 0x54, 0x7f,
4478
-	0x18, 0xfe, 0xa7, 0x3f, 0x31, 0x28, 0xa7, 0x60, 0xb9, 0x27, 0x8a, 0x4b, 0xe3, 0x31, 0xd4, 0x6e,
4479
-	0xc6, 0xf5, 0x46, 0x1c, 0xdf, 0x03, 0x6f, 0xc5, 0x37, 0x02, 0xbf, 0x22, 0xa0, 0x26, 0x49, 0x5f,
4480
-	0xfc, 0x67, 0x16, 0x38, 0xcb, 0x4d, 0xc9, 0xde, 0x03, 0x38, 0x53, 0x2a, 0x3e, 0xa5, 0x85, 0x69,
4481
-	0x1e, 0x71, 0x51, 0x42, 0x08, 0xb6, 0x0d, 0x1e, 0x5e, 0x52, 0xa3, 0xd7, 0x0f, 0x92, 0x45, 0xaa,
4482
-	0x01, 0xef, 0x82, 0x3b, 0xcd, 0xcd, 0xf5, 0x52, 0x74, 0xa6, 0x4b, 0xeb, 0x77, 0xc0, 0x89, 0xa4,
4483
-	0xd1, 0xe9, 0xfd, 0xbd, 0x1e, 0x49, 0x52, 0xf9, 0x3b, 0x50, 0xbb, 0xc9, 0x21, 0xbb, 0x03, 0xd5,
4484
-	0x69, 0x38, 0x57, 0x34, 0x54, 0xf8, 0x45, 0x30, 0x37, 0xff, 0x57, 0x0b, 0xa0, 0x18, 0x00, 0x24,
4485
-	0x04, 0xa7, 0x03, 0x31, 0x1b, 0x7a, 0x1a, 0xe6, 0xe0, 0x9c, 0x9b, 0xba, 0x9a, 0x6a, 0xdf, 0x7d,
4486
-	0x79, 0x68, 0xda, 0xcb, 0xb2, 0x13, 0xa5, 0xfa, 0x2b, 0xfa, 0xec, 0xf7, 0x37, 0xfa, 0x8a, 0xe6,
4487
-	0x2f, 0x34, 0xbe, 0x80, 0x5b, 0x2f, 0xb9, 0x7b, 0xcd, 0x79, 0x2a, 0x7a, 0x6f, 0xa5, 0x62, 0x3b,
4488
-	0x9f, 0x82, 0x9b, 0x6f, 0x77, 0xe6, 0x40, 0xb9, 0x3b, 0xfc, 0xb2, 0x5f, 0x5b, 0x63, 0x00, 0xd5,
4489
-	0xe3, 0x41, 0x8f, 0x0f, 0x4e, 0x6a, 0x16, 0x5b, 0x87, 0xd2, 0xf1, 0xf1, 0x41, 0xcd, 0x66, 0x2e,
4490
-	0x54, 0x7a, 0xfb, 0xbd, 0x83, 0x41, 0xad, 0x84, 0xc7, 0x93, 0xc3, 0x27, 0x9f, 0x1d, 0xd7, 0xca,
4491
-	0xdd, 0xda, 0xf3, 0xeb, 0x2d, 0xeb, 0x97, 0xeb, 0x2d, 0xeb, 0x8f, 0xeb, 0x2d, 0xeb, 0xfb, 0x3f,
4492
-	0xb7, 0xd6, 0xc6, 0x55, 0xfa, 0x17, 0xf4, 0xd1, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x76,
4493
-	0x25, 0x54, 0x45, 0x09, 0x00, 0x00,
4426
+	// 1203 bytes of a gzipped FileDescriptorProto
4427
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4d, 0x8f, 0x1b, 0x45,
4428
+	0x13, 0xde, 0x19, 0x7f, 0xcd, 0xd4, 0x6c, 0x36, 0x7e, 0x3b, 0x79, 0x83, 0x59, 0xc2, 0xae, 0x99,
4429
+	0x20, 0xe4, 0x7c, 0xac, 0x57, 0x32, 0x52, 0x88, 0x38, 0x44, 0xac, 0x3f, 0xa2, 0x35, 0x21, 0x38,
4430
+	0x6a, 0xaf, 0x96, 0x63, 0x34, 0x1e, 0xb7, 0xbd, 0xa3, 0x78, 0xa7, 0x47, 0x3d, 0xed, 0xb0, 0x3e,
4431
+	0x80, 0x44, 0x7e, 0x01, 0x12, 0x12, 0x77, 0x7e, 0x08, 0xf7, 0x1c, 0xb9, 0xc2, 0x21, 0xa0, 0x20,
4432
+	0xf1, 0x3b, 0x50, 0x75, 0xb7, 0x67, 0x66, 0x93, 0x20, 0x25, 0x82, 0x93, 0xbb, 0xab, 0x9e, 0x7a,
4433
+	0xba, 0xea, 0xe9, 0x9a, 0x6a, 0x83, 0xcb, 0x93, 0xb4, 0x9d, 0x08, 0x2e, 0x39, 0xb1, 0x93, 0xc9,
4434
+	0xf6, 0xde, 0x3c, 0x92, 0x27, 0xcb, 0x49, 0x3b, 0xe4, 0xa7, 0xfb, 0x73, 0x3e, 0xe7, 0xfb, 0xca,
4435
+	0x35, 0x59, 0xce, 0xd4, 0x4e, 0x6d, 0xd4, 0x4a, 0x87, 0xf8, 0x3f, 0xd9, 0x60, 0x8f, 0x12, 0xf2,
4436
+	0x01, 0x54, 0xa3, 0x38, 0x59, 0xca, 0xb4, 0x61, 0x35, 0x4b, 0x2d, 0xaf, 0xe3, 0xb6, 0x93, 0x49,
4437
+	0x7b, 0x88, 0x16, 0x6a, 0x1c, 0xa4, 0x09, 0x65, 0x76, 0xc6, 0xc2, 0x86, 0xdd, 0xb4, 0x5a, 0x5e,
4438
+	0x07, 0x10, 0x30, 0x38, 0x63, 0xe1, 0x28, 0x39, 0xdc, 0xa0, 0xca, 0x43, 0x3e, 0x82, 0x6a, 0xca,
4439
+	0x97, 0x22, 0x64, 0x8d, 0x92, 0xc2, 0x6c, 0x22, 0x66, 0xac, 0x2c, 0x0a, 0x65, 0xbc, 0xc8, 0x14,
4440
+	0xf2, 0x64, 0xd5, 0x28, 0xe7, 0x4c, 0x3d, 0x9e, 0xac, 0x34, 0x13, 0x7a, 0xc8, 0x35, 0xa8, 0x4c,
4441
+	0x96, 0xd1, 0x62, 0xda, 0xa8, 0x28, 0x88, 0x87, 0x90, 0x2e, 0x1a, 0x14, 0x46, 0xfb, 0x48, 0x0b,
4442
+	0x9c, 0x64, 0x11, 0xc8, 0x19, 0x17, 0xa7, 0x0d, 0xc8, 0x0f, 0x7c, 0x68, 0x6c, 0x34, 0xf3, 0x92,
4443
+	0x4f, 0xc0, 0x0b, 0x79, 0x9c, 0x4a, 0x11, 0x44, 0xb1, 0x4c, 0x1b, 0x9e, 0x02, 0xff, 0x1f, 0xc1,
4444
+	0x5f, 0x71, 0xf1, 0x98, 0x89, 0x5e, 0xee, 0xa4, 0x45, 0x64, 0xb7, 0x0c, 0x36, 0x4f, 0xfc, 0x1f,
4445
+	0x2d, 0x70, 0xd6, 0xac, 0xc4, 0x87, 0xcd, 0x03, 0x11, 0x9e, 0x44, 0x92, 0x85, 0x72, 0x29, 0x58,
4446
+	0xc3, 0x6a, 0x5a, 0x2d, 0x97, 0x9e, 0xb3, 0x91, 0x2d, 0xb0, 0x47, 0x63, 0x25, 0x94, 0x4b, 0xed,
4447
+	0xd1, 0x98, 0x34, 0xa0, 0x76, 0x1c, 0x88, 0x28, 0x88, 0xa5, 0x52, 0xc6, 0xa5, 0xeb, 0x2d, 0xb9,
4448
+	0x0a, 0xee, 0x68, 0x7c, 0xcc, 0x44, 0x1a, 0xf1, 0x58, 0xe9, 0xe1, 0xd2, 0xdc, 0x40, 0x76, 0x00,
4449
+	0x46, 0xe3, 0x7b, 0x2c, 0x40, 0xd2, 0xb4, 0x51, 0x69, 0x96, 0x5a, 0x2e, 0x2d, 0x58, 0xfc, 0x6f,
4450
+	0xa1, 0xa2, 0xee, 0x88, 0x7c, 0x0e, 0xd5, 0x69, 0x34, 0x67, 0xa9, 0xd4, 0xe9, 0x74, 0x3b, 0xcf,
4451
+	0x9e, 0xef, 0x6e, 0xfc, 0xf6, 0x7c, 0xf7, 0x46, 0xa1, 0x19, 0x78, 0xc2, 0xe2, 0x90, 0xc7, 0x32,
4452
+	0x88, 0x62, 0x26, 0xd2, 0xfd, 0x39, 0xdf, 0xd3, 0x21, 0xed, 0xbe, 0xfa, 0xa1, 0x86, 0x81, 0x5c,
4453
+	0x87, 0x4a, 0x14, 0x4f, 0xd9, 0x99, 0xca, 0xbf, 0xd4, 0xbd, 0x64, 0xa8, 0xbc, 0xd1, 0x52, 0x26,
4454
+	0x4b, 0x39, 0x44, 0x17, 0xd5, 0x08, 0x7f, 0x08, 0x55, 0xdd, 0x02, 0xe4, 0x2a, 0x94, 0x4f, 0x99,
4455
+	0x0c, 0xd4, 0xf1, 0x5e, 0xc7, 0x41, 0x69, 0x1f, 0x30, 0x19, 0x50, 0x65, 0xc5, 0xee, 0x3a, 0xe5,
4456
+	0x4b, 0x94, 0xde, 0xce, 0xbb, 0xeb, 0x01, 0x5a, 0xa8, 0x71, 0xf8, 0xdf, 0x40, 0x19, 0x03, 0x08,
4457
+	0x81, 0x72, 0x20, 0xe6, 0xba, 0x0d, 0x5d, 0xaa, 0xd6, 0xa4, 0x0e, 0x25, 0x16, 0x3f, 0x51, 0xb1,
4458
+	0x2e, 0xc5, 0x25, 0x5a, 0xc2, 0xaf, 0xa7, 0x46, 0x4c, 0x5c, 0x62, 0xdc, 0x32, 0x65, 0xc2, 0x68,
4459
+	0xa8, 0xd6, 0xe4, 0x3a, 0xb8, 0x89, 0xe0, 0x67, 0xab, 0x47, 0x18, 0x5d, 0x29, 0x74, 0x08, 0x1a,
4460
+	0x07, 0xf1, 0x13, 0xea, 0x24, 0x66, 0xe5, 0x7f, 0x67, 0x43, 0x45, 0x25, 0x44, 0x5a, 0x58, 0x7e,
4461
+	0xb2, 0xd4, 0x4a, 0x96, 0xba, 0xc4, 0x94, 0x0f, 0x4a, 0xe8, 0xac, 0x7a, 0x14, 0x7d, 0x1b, 0x9c,
4462
+	0x94, 0x2d, 0x58, 0x28, 0xb9, 0x30, 0x77, 0x9d, 0xed, 0x31, 0x9d, 0x29, 0x5e, 0x87, 0xce, 0x50,
4463
+	0xad, 0xc9, 0x4d, 0xa8, 0x72, 0xa5, 0xa1, 0x4a, 0xf2, 0x1f, 0x94, 0x35, 0x10, 0x24, 0x17, 0x2c,
4464
+	0x98, 0xf2, 0x78, 0xb1, 0x52, 0xa9, 0x3b, 0x34, 0xdb, 0x93, 0x9b, 0xe0, 0x2a, 0xd5, 0x8e, 0x56,
4465
+	0x09, 0x6b, 0x54, 0x9b, 0x56, 0x6b, 0xab, 0x73, 0x21, 0x53, 0x14, 0x8d, 0x34, 0xf7, 0xe3, 0x57,
4466
+	0x12, 0x06, 0xe1, 0x09, 0x1b, 0x25, 0xb2, 0x71, 0x39, 0xd7, 0xa0, 0x67, 0x6c, 0x34, 0xf3, 0xfa,
4467
+	0x43, 0x70, 0xd6, 0x56, 0xec, 0xe0, 0x61, 0xdf, 0xf4, 0xb6, 0x3d, 0xec, 0x93, 0x3d, 0xa8, 0xa5,
4468
+	0x27, 0x81, 0x88, 0xe2, 0xb9, 0x2a, 0x75, 0xab, 0x73, 0x29, 0x23, 0x19, 0x6b, 0x3b, 0x72, 0xad,
4469
+	0x31, 0xfe, 0x5d, 0xa8, 0xea, 0x2f, 0x9a, 0x34, 0xa1, 0x94, 0x8a, 0xd0, 0x4c, 0x95, 0xad, 0xf5,
4470
+	0xa7, 0xae, 0x87, 0x02, 0x45, 0x57, 0x26, 0x95, 0x9d, 0x4b, 0xe5, 0x53, 0x80, 0x1c, 0xf6, 0xdf,
4471
+	0x5c, 0x89, 0xff, 0x83, 0x05, 0xce, 0x7a, 0x18, 0xe1, 0x97, 0x15, 0x4d, 0x59, 0x2c, 0xa3, 0x59,
4472
+	0xc4, 0x84, 0xa9, 0xb3, 0x60, 0x21, 0x7b, 0x50, 0x09, 0xa4, 0x14, 0xeb, 0x86, 0x7d, 0xa7, 0x38,
4473
+	0xc9, 0xda, 0x07, 0xe8, 0x19, 0xc4, 0x52, 0xac, 0xa8, 0x46, 0x6d, 0xdf, 0x01, 0xc8, 0x8d, 0xd8,
4474
+	0x9d, 0x8f, 0xd9, 0xca, 0xb0, 0xe2, 0x92, 0x5c, 0x86, 0xca, 0x93, 0x60, 0xb1, 0x64, 0x26, 0x29,
4475
+	0xbd, 0xf9, 0xd4, 0xbe, 0x63, 0xf9, 0x3f, 0xdb, 0x50, 0x33, 0x93, 0x8d, 0xdc, 0x82, 0x9a, 0x9a,
4476
+	0x6c, 0x26, 0xa3, 0xd7, 0x57, 0xba, 0x86, 0x90, 0xfd, 0x6c, 0x64, 0x17, 0x72, 0x34, 0x54, 0x7a,
4477
+	0x74, 0x9b, 0x1c, 0xf3, 0x01, 0x5e, 0x9a, 0xb2, 0x99, 0x99, 0xcd, 0xea, 0x2a, 0xfa, 0x6c, 0x16,
4478
+	0xc5, 0x91, 0x8c, 0x78, 0x4c, 0xd1, 0x45, 0x6e, 0xad, 0xab, 0x2e, 0x2b, 0xc6, 0x2b, 0x45, 0xc6,
4479
+	0x57, 0x8b, 0x1e, 0x82, 0x57, 0x38, 0xe6, 0x35, 0x55, 0x7f, 0x58, 0xac, 0xda, 0x1c, 0xa9, 0xe8,
4480
+	0xf4, 0xc3, 0x92, 0xab, 0xf0, 0x2f, 0xf4, 0xbb, 0x0d, 0x90, 0x53, 0xbe, 0x79, 0xa7, 0xf8, 0x7f,
4481
+	0x59, 0x00, 0xa3, 0x04, 0x47, 0xce, 0x34, 0x50, 0x13, 0x6a, 0x33, 0x9a, 0xc7, 0x5c, 0xb0, 0x47,
4482
+	0xea, 0x73, 0x50, 0xf1, 0x0e, 0xf5, 0xb4, 0x4d, 0xb5, 0x39, 0x39, 0x00, 0x6f, 0xca, 0xd2, 0x50,
4483
+	0x44, 0x09, 0x0a, 0x66, 0x44, 0xdf, 0xc5, 0x9a, 0x72, 0x9e, 0x76, 0x3f, 0x47, 0x68, 0xad, 0x8a,
4484
+	0x31, 0xa4, 0x03, 0x9b, 0xec, 0x2c, 0xe1, 0x42, 0x9a, 0x53, 0xf4, 0x03, 0x78, 0x51, 0x3f, 0xa5,
4485
+	0x68, 0x57, 0x27, 0x51, 0x8f, 0xe5, 0x9b, 0xed, 0xbb, 0x50, 0x7f, 0x99, 0xf4, 0xad, 0x04, 0xba,
4486
+	0x06, 0x5e, 0x81, 0x1b, 0x81, 0xc7, 0x0a, 0xa8, 0x2b, 0xd4, 0x1b, 0xff, 0x29, 0xbe, 0x70, 0x66,
4487
+	0x16, 0x92, 0xf7, 0x01, 0x4e, 0xa4, 0x4c, 0x1e, 0xa9, 0xe1, 0x68, 0x0e, 0x71, 0xd1, 0xa2, 0x10,
4488
+	0x64, 0x17, 0x3c, 0xdc, 0xa4, 0xc6, 0xaf, 0x0f, 0x54, 0x11, 0xa9, 0x06, 0xbc, 0x07, 0xee, 0x2c,
4489
+	0x0b, 0xd7, 0x03, 0xd0, 0x99, 0xad, 0xa3, 0xdf, 0x05, 0x27, 0xe6, 0xc6, 0xa7, 0x67, 0x75, 0x2d,
4490
+	0xe6, 0xca, 0xe5, 0xdf, 0x84, 0xff, 0xbd, 0xf2, 0x1c, 0x93, 0x2b, 0x50, 0x9d, 0x45, 0x0b, 0xa9,
4491
+	0x3e, 0x09, 0x1c, 0xff, 0x66, 0xe7, 0xff, 0x6a, 0x01, 0xe4, 0xed, 0x8b, 0x8a, 0x60, 0x6f, 0x23,
4492
+	0x66, 0x53, 0xf7, 0xf2, 0x02, 0x9c, 0x53, 0x73, 0x2b, 0xe6, 0xae, 0xae, 0x9e, 0x6f, 0xf9, 0xf6,
4493
+	0xfa, 0xd2, 0x94, 0xa6, 0xfa, 0xc9, 0x7c, 0xfa, 0xfb, 0x5b, 0x3d, 0x99, 0xd9, 0x09, 0xdb, 0xf7,
4494
+	0xe1, 0xc2, 0x39, 0xba, 0x37, 0xfc, 0x1a, 0xf2, 0xce, 0x29, 0x5c, 0xd9, 0x8d, 0xcf, 0xc0, 0xcd,
4495
+	0x46, 0x39, 0x71, 0xa0, 0xdc, 0x1d, 0x7e, 0xd9, 0xaf, 0x6f, 0x10, 0x80, 0xea, 0x78, 0xd0, 0xa3,
4496
+	0x83, 0xa3, 0xba, 0x45, 0x6a, 0x50, 0x1a, 0x8f, 0x0f, 0xeb, 0x36, 0x71, 0xa1, 0xd2, 0x3b, 0xe8,
4497
+	0x1d, 0x0e, 0xea, 0x25, 0x5c, 0x1e, 0x3d, 0x78, 0x78, 0x6f, 0x5c, 0x2f, 0xdf, 0xb8, 0x0d, 0x17,
4498
+	0x5f, 0x9a, 0xcd, 0x2a, 0xfa, 0xf0, 0x80, 0x0e, 0x90, 0xc9, 0x83, 0xda, 0x43, 0x3a, 0x3c, 0x3e,
4499
+	0x38, 0x1a, 0xd4, 0x2d, 0x74, 0x7c, 0x31, 0xea, 0xdd, 0x1f, 0xf4, 0xeb, 0x76, 0xb7, 0xfe, 0xec,
4500
+	0xc5, 0x8e, 0xf5, 0xcb, 0x8b, 0x1d, 0xeb, 0x8f, 0x17, 0x3b, 0xd6, 0xf7, 0x7f, 0xee, 0x6c, 0x4c,
4501
+	0xaa, 0xea, 0x6f, 0xe2, 0xc7, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x42, 0x80, 0x11, 0x1b, 0x66,
4502
+	0x0a, 0x00, 0x00,
4494 4503
 }
... ...
@@ -15,7 +15,18 @@ message Op {
15 15
 		SourceOp source = 3;
16 16
 		CopyOp copy = 4;
17 17
 		BuildOp build = 5;
18
-	 }
18
+	}
19
+	Platform platform = 10;
20
+	WorkerConstraints constraints = 11;
21
+}
22
+
23
+// Platform is github.com/opencontainers/image-spec/specs-go/v1.Platform
24
+message Platform {
25
+	string Architecture = 1;
26
+	string OS = 2;
27
+	string Variant = 3;
28
+	string OSVersion = 4; // unused
29
+	repeated string OSFeatures = 5; // unused
19 30
 }
20 31
 
21 32
 // Input represents an input edge for an Op.
... ...
@@ -54,6 +65,7 @@ message Mount {
54 54
 	CacheOpt cacheOpt = 20;
55 55
 }
56 56
 
57
+// MountType defines a type of a mount from a supported set
57 58
 enum MountType {
58 59
 	BIND = 0;
59 60
 	SECRET = 1;
... ...
@@ -62,8 +74,22 @@ enum MountType {
62 62
 	TMPFS = 4;
63 63
 }
64 64
 
65
+// CacheOpt defines options specific to cache mounts
65 66
 message CacheOpt {
67
+	// ID is an optional namespace for the mount
66 68
 	string ID = 1;
69
+	// Sharing is the sharing mode for the mount 
70
+	CacheSharingOpt sharing = 2;
71
+}
72
+
73
+// CacheSharingOpt defines different sharing modes for cache mount
74
+enum CacheSharingOpt {
75
+	// SHARED cache mount can be used concurrently by multiple writers
76
+	SHARED = 0;
77
+	// PRIVATE creates a new mount if there are multiple writers
78
+	PRIVATE = 1;
79
+	// LOCKED pauses second writer until first one releases the mount
80
+	LOCKED = 2;
67 81
 }
68 82
 
69 83
 // CopyOp copies files across Ops.
... ...
@@ -106,8 +132,9 @@ message OpMetadata {
106 106
 	// ignore_cache specifies to ignore the cache for this Op.
107 107
 	bool ignore_cache = 1;
108 108
 	// Description can be used for keeping any text fields that builder doesn't parse
109
-	map<string, string> description = 2;  
110
-	WorkerConstraint worker_constraint = 3;
109
+	map<string, string> description = 2; 
110
+	// index 3 reserved for WorkerConstraint in previous versions
111
+	// WorkerConstraint worker_constraint = 3;
111 112
 	ExportCache export_cache = 4;
112 113
 }
113 114
 
... ...
@@ -122,8 +149,8 @@ message ProxyEnv {
122 122
 	string no_proxy = 4;
123 123
 }
124 124
 
125
-// WorkerConstraint is experimental and likely to be changed.
126
-message WorkerConstraint {
125
+// WorkerConstraints defines conditions for the worker
126
+message WorkerConstraints {
127 127
 	repeated string filter = 1; // containerd-style filter
128 128
 }
129 129
 
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/containerd/containerd/reference"
9 9
 	"github.com/moby/buildkit/solver/pb"
10 10
 	digest "github.com/opencontainers/go-digest"
11
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
11 12
 	"github.com/pkg/errors"
12 13
 )
13 14
 
... ...
@@ -50,11 +51,20 @@ func FromString(s string) (Identifier, error) {
50 50
 		return nil, errors.Wrapf(errNotFound, "unknown schema %s", parts[0])
51 51
 	}
52 52
 }
53
-func FromLLB(op *pb.Op_Source) (Identifier, error) {
53
+func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) {
54 54
 	id, err := FromString(op.Source.Identifier)
55 55
 	if err != nil {
56 56
 		return nil, err
57 57
 	}
58
+	if id, ok := id.(*ImageIdentifier); ok && platform != nil {
59
+		id.Platform = &specs.Platform{
60
+			OS:           platform.OS,
61
+			Architecture: platform.Architecture,
62
+			Variant:      platform.Variant,
63
+			OSVersion:    platform.OSVersion,
64
+			OSFeatures:   platform.OSFeatures,
65
+		}
66
+	}
58 67
 	if id, ok := id.(*GitIdentifier); ok {
59 68
 		for k, v := range op.Source.Attrs {
60 69
 			switch k {
... ...
@@ -136,6 +146,7 @@ func FromLLB(op *pb.Op_Source) (Identifier, error) {
136 136
 
137 137
 type ImageIdentifier struct {
138 138
 	Reference reference.Spec
139
+	Platform  *specs.Platform
139 140
 }
140 141
 
141 142
 func NewImageIdentifier(str string) (*ImageIdentifier, error) {
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	"github.com/containerd/containerd/reference"
11 11
 	"github.com/containerd/containerd/remotes"
12 12
 	digest "github.com/opencontainers/go-digest"
13
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
13
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
14 14
 	"github.com/pkg/errors"
15 15
 )
16 16
 
... ...
@@ -19,16 +19,18 @@ type IngesterProvider interface {
19 19
 	content.Provider
20 20
 }
21 21
 
22
-func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, platform string) (digest.Digest, []byte, error) {
23
-	if platform == "" {
24
-		platform = platforms.Default()
22
+func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, platform *specs.Platform) (digest.Digest, []byte, error) {
23
+	// TODO: fix containerd to take struct instead of string
24
+	platformStr := platforms.Default()
25
+	if platform != nil {
26
+		platformStr = platforms.Format(*platform)
25 27
 	}
26 28
 	ref, err := reference.Parse(str)
27 29
 	if err != nil {
28 30
 		return "", nil, errors.WithStack(err)
29 31
 	}
30 32
 
31
-	desc := ocispec.Descriptor{
33
+	desc := specs.Descriptor{
32 34
 		Digest: ref.Digest(),
33 35
 	}
34 36
 	if desc.Digest != "" {
... ...
@@ -56,12 +58,12 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
56 56
 
57 57
 	handlers := []images.Handler{
58 58
 		remotes.FetchHandler(ingester, fetcher),
59
-		childrenConfigHandler(ingester, platform),
59
+		childrenConfigHandler(ingester, platformStr),
60 60
 	}
61 61
 	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
62 62
 		return "", nil, err
63 63
 	}
64
-	config, err := images.Config(ctx, ingester, desc, platform)
64
+	config, err := images.Config(ctx, ingester, desc, platformStr)
65 65
 	if err != nil {
66 66
 		return "", nil, err
67 67
 	}
... ...
@@ -75,10 +77,10 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
75 75
 }
76 76
 
77 77
 func childrenConfigHandler(provider content.Provider, platform string) images.HandlerFunc {
78
-	return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
79
-		var descs []ocispec.Descriptor
78
+	return func(ctx context.Context, desc specs.Descriptor) ([]specs.Descriptor, error) {
79
+		var descs []specs.Descriptor
80 80
 		switch desc.MediaType {
81
-		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
81
+		case images.MediaTypeDockerSchema2Manifest, specs.MediaTypeImageManifest:
82 82
 			p, err := content.ReadBlob(ctx, provider, desc)
83 83
 			if err != nil {
84 84
 				return nil, err
... ...
@@ -86,19 +88,19 @@ func childrenConfigHandler(provider content.Provider, platform string) images.Ha
86 86
 
87 87
 			// TODO(stevvooe): We just assume oci manifest, for now. There may be
88 88
 			// subtle differences from the docker version.
89
-			var manifest ocispec.Manifest
89
+			var manifest specs.Manifest
90 90
 			if err := json.Unmarshal(p, &manifest); err != nil {
91 91
 				return nil, err
92 92
 			}
93 93
 
94 94
 			descs = append(descs, manifest.Config)
95
-		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
95
+		case images.MediaTypeDockerSchema2ManifestList, specs.MediaTypeImageIndex:
96 96
 			p, err := content.ReadBlob(ctx, provider, desc)
97 97
 			if err != nil {
98 98
 				return nil, err
99 99
 			}
100 100
 
101
-			var index ocispec.Index
101
+			var index specs.Index
102 102
 			if err := json.Unmarshal(p, &index); err != nil {
103 103
 				return nil, err
104 104
 			}
... ...
@@ -118,7 +120,7 @@ func childrenConfigHandler(provider content.Provider, platform string) images.Ha
118 118
 			} else {
119 119
 				descs = append(descs, index.Manifests...)
120 120
 			}
121
-		case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
121
+		case images.MediaTypeDockerSchema2Config, specs.MediaTypeImageConfig:
122 122
 			// childless data types.
123 123
 			return nil, nil
124 124
 		default:
... ...
@@ -129,7 +131,7 @@ func childrenConfigHandler(provider content.Provider, platform string) images.Ha
129 129
 	}
130 130
 }
131 131
 
132
-// ocispec.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
132
+// specs.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
133 133
 func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
134 134
 	// TODO: schema1
135 135
 
... ...
@@ -6,7 +6,7 @@ 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 63522d9eaa5a0443d225642c4b6f4f5fdedf932b
9
+github.com/containerd/containerd 08f7ee9828af1783dc98cc5cc1739e915697c667
10 10
 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
11 11
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
12 12
 github.com/sirupsen/logrus v1.0.0
... ...
@@ -11,16 +11,18 @@ import (
11 11
 	"github.com/moby/buildkit/frontend"
12 12
 	"github.com/moby/buildkit/solver"
13 13
 	digest "github.com/opencontainers/go-digest"
14
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
14 15
 )
15 16
 
16 17
 type Worker interface {
17 18
 	// ID needs to be unique in the cluster
18 19
 	ID() string
19 20
 	Labels() map[string]string
21
+	Platforms() []specs.Platform
20 22
 	LoadRef(id string) (cache.ImmutableRef, error)
21 23
 	// ResolveOp resolves Vertex.Sys() to Op implementation.
22 24
 	ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solver.Op, error)
23
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
25
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
24 26
 	// Exec is similar to executor.Exec but without []mount.Mount
25 27
 	Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
26 28
 	DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error)
... ...
@@ -33,8 +35,6 @@ type Worker interface {
33 33
 // Pre-defined label keys
34 34
 const (
35 35
 	labelPrefix      = "org.mobyproject.buildkit.worker."
36
-	LabelOS          = labelPrefix + "os"          // GOOS
37
-	LabelArch        = labelPrefix + "arch"        // GOARCH
38 36
 	LabelExecutor    = labelPrefix + "executor"    // "oci" or "containerd"
39 37
 	LabelSnapshotter = labelPrefix + "snapshotter" // containerd snapshotter name ("overlay", "native", ...)
40 38
 	LabelHostname    = labelPrefix + "hostname"