exporter: add image exporter

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
docker-18.09
Tonis Tiigi 2017-07-10 13:03:38 -07:00
parent d706cd52c4
commit 45bfdd5e42
16 changed files with 629 additions and 68 deletions

View File

@ -117,8 +117,10 @@ func (m *UsageRecord) GetSize_() int64 {
} }
type SolveRequest struct { type SolveRequest struct {
Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"` Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
Definition [][]byte `protobuf:"bytes,2,rep,name=Definition" json:"Definition,omitempty"` Definition [][]byte `protobuf:"bytes,2,rep,name=Definition" json:"Definition,omitempty"`
Exporter string `protobuf:"bytes,3,opt,name=Exporter,proto3" json:"Exporter,omitempty"`
ExporterAttrs map[string]string `protobuf:"bytes,4,rep,name=ExporterAttrs" json:"ExporterAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (m *SolveRequest) Reset() { *m = SolveRequest{} } func (m *SolveRequest) Reset() { *m = SolveRequest{} }
@ -140,6 +142,20 @@ func (m *SolveRequest) GetDefinition() [][]byte {
return nil return nil
} }
func (m *SolveRequest) GetExporter() string {
if m != nil {
return m.Exporter
}
return ""
}
func (m *SolveRequest) GetExporterAttrs() map[string]string {
if m != nil {
return m.ExporterAttrs
}
return nil
}
type SolveResponse struct { type SolveResponse struct {
Vtx []*Vertex `protobuf:"bytes,1,rep,name=vtx" json:"vtx,omitempty"` Vtx []*Vertex `protobuf:"bytes,1,rep,name=vtx" json:"vtx,omitempty"`
} }
@ -658,6 +674,29 @@ func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) {
i += copy(dAtA[i:], b) i += copy(dAtA[i:], b)
} }
} }
if len(m.Exporter) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintControl(dAtA, i, uint64(len(m.Exporter)))
i += copy(dAtA[i:], m.Exporter)
}
if len(m.ExporterAttrs) > 0 {
for k, _ := range m.ExporterAttrs {
dAtA[i] = 0x22
i++
v := m.ExporterAttrs[k]
mapSize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
i = encodeVarintControl(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintControl(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintControl(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil return i, nil
} }
@ -1044,6 +1083,18 @@ func (m *SolveRequest) Size() (n int) {
n += 1 + l + sovControl(uint64(l)) n += 1 + l + sovControl(uint64(l))
} }
} }
l = len(m.Exporter)
if l > 0 {
n += 1 + l + sovControl(uint64(l))
}
if len(m.ExporterAttrs) > 0 {
for k, v := range m.ExporterAttrs {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
}
}
return n return n
} }
@ -1550,6 +1601,151 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error {
m.Definition = append(m.Definition, make([]byte, postIndex-iNdEx)) m.Definition = append(m.Definition, make([]byte, postIndex-iNdEx))
copy(m.Definition[len(m.Definition)-1], dAtA[iNdEx:postIndex]) copy(m.Definition[len(m.Definition)-1], dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Exporter", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthControl
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Exporter = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ExporterAttrs", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthControl
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthControl
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.ExporterAttrs == nil {
m.ExporterAttrs = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthControl
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.ExporterAttrs[mapkey] = mapvalue
} else {
var mapvalue string
m.ExporterAttrs[mapkey] = mapvalue
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipControl(dAtA[iNdEx:]) skippy, err := skipControl(dAtA[iNdEx:])
@ -2664,50 +2860,55 @@ var (
func init() { proto.RegisterFile("control.proto", fileDescriptorControl) } func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
var fileDescriptorControl = []byte{ var fileDescriptorControl = []byte{
// 711 bytes of a gzipped FileDescriptorProto // 785 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x55, 0xcd, 0x6e, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x55, 0x4f, 0x6f, 0xe3, 0x44,
0x10, 0x66, 0xe3, 0xd4, 0x49, 0x26, 0x69, 0x55, 0x56, 0xa8, 0xb2, 0x82, 0x48, 0x8c, 0xb9, 0x44, 0x14, 0x67, 0xec, 0xd4, 0x49, 0x5e, 0x92, 0x55, 0x19, 0xa1, 0x95, 0x65, 0x44, 0x12, 0xcc, 0x25,
0x95, 0xea, 0x40, 0x80, 0x4b, 0x91, 0x10, 0x0a, 0x39, 0xd0, 0x8a, 0x5e, 0xb6, 0x2d, 0x77, 0xc7, 0x5a, 0x69, 0x1d, 0x36, 0x80, 0x84, 0x8a, 0x84, 0x20, 0x64, 0x25, 0x5a, 0xb1, 0x97, 0xe9, 0x16,
0xd9, 0xba, 0x56, 0x6d, 0x6f, 0xf0, 0xae, 0xa3, 0xc2, 0x53, 0xf0, 0x2e, 0x3c, 0x03, 0x52, 0x8f, 0xce, 0x4e, 0x32, 0x75, 0xad, 0xd8, 0x9e, 0x30, 0x33, 0x8e, 0x1a, 0x3e, 0x05, 0xdf, 0x85, 0xcf,
0x9c, 0x39, 0x14, 0xd4, 0x07, 0xe0, 0xcc, 0x11, 0x79, 0x77, 0x9d, 0x9a, 0xb6, 0x81, 0xd2, 0x9e, 0x80, 0xd4, 0x23, 0x67, 0x0e, 0x05, 0xf5, 0x03, 0x70, 0x85, 0x23, 0xf2, 0xcc, 0x38, 0x75, 0x9b,
0xb2, 0xb3, 0xf9, 0xe6, 0xdb, 0x99, 0x6f, 0x7e, 0x0c, 0xcb, 0x3e, 0x4b, 0x44, 0xca, 0x22, 0x77, 0xa6, 0x94, 0xf6, 0x94, 0x79, 0x93, 0xdf, 0xfb, 0xbd, 0x37, 0xbf, 0xf7, 0xc7, 0xd0, 0x99, 0xb1,
0x9a, 0x32, 0xc1, 0xf0, 0x6a, 0xcc, 0xc6, 0x1f, 0xdc, 0x71, 0x16, 0x46, 0x93, 0xa3, 0x50, 0xb8, 0x4c, 0x72, 0x96, 0x04, 0x4b, 0xce, 0x24, 0xc3, 0xfb, 0x29, 0x9b, 0xae, 0x83, 0x69, 0x1e, 0x27,
0xb3, 0x27, 0xed, 0x8d, 0x20, 0x14, 0x87, 0xd9, 0xd8, 0xf5, 0x59, 0xdc, 0x0f, 0x58, 0xc0, 0xfa, 0xf3, 0x45, 0x2c, 0x83, 0xd5, 0x2b, 0xef, 0x65, 0x14, 0xcb, 0xb3, 0x7c, 0x1a, 0xcc, 0x58, 0x3a,
0x12, 0x38, 0xce, 0x0e, 0xa4, 0x25, 0x0d, 0x79, 0x52, 0x04, 0xed, 0x6e, 0xc0, 0x58, 0x10, 0xd1, 0x8c, 0x58, 0xc4, 0x86, 0x0a, 0x38, 0xcd, 0x4f, 0x95, 0xa5, 0x0c, 0x75, 0xd2, 0x04, 0x5e, 0x2f,
0x73, 0x94, 0x08, 0x63, 0xca, 0x85, 0x17, 0x4f, 0x15, 0xc0, 0xc1, 0xb0, 0x3a, 0x0a, 0xf9, 0xd1, 0x62, 0x2c, 0x4a, 0xe8, 0x35, 0x4a, 0xc6, 0x29, 0x15, 0x32, 0x4c, 0x97, 0x1a, 0xe0, 0x63, 0xd8,
0x3e, 0xf7, 0x02, 0x4a, 0xe8, 0xfb, 0x8c, 0x72, 0xe1, 0x6c, 0xc3, 0xdd, 0xd2, 0x1d, 0x9f, 0xb2, 0x9f, 0xc4, 0x62, 0x71, 0x22, 0xc2, 0x88, 0x12, 0xfa, 0x63, 0x4e, 0x85, 0xf4, 0x8f, 0xe0, 0xdd,
0x84, 0x53, 0xfc, 0x1c, 0xcc, 0x94, 0xfa, 0x2c, 0x9d, 0x58, 0xc8, 0x36, 0x7a, 0xcd, 0xc1, 0x03, 0xca, 0x9d, 0x58, 0xb2, 0x4c, 0x50, 0xfc, 0x19, 0x38, 0x9c, 0xce, 0x18, 0x9f, 0xbb, 0xa8, 0x6f,
0xf7, 0x62, 0x6c, 0xae, 0x76, 0xc8, 0x41, 0x44, 0x83, 0x1d, 0x0f, 0x9a, 0xa5, 0x6b, 0xbc, 0x02, 0x0f, 0x5a, 0xa3, 0x0f, 0x82, 0xdb, 0xb9, 0x05, 0xc6, 0xa1, 0x00, 0x11, 0x03, 0xf6, 0x43, 0x68,
0x95, 0xad, 0x91, 0x85, 0x6c, 0xd4, 0x6b, 0x90, 0xca, 0xd6, 0x08, 0x5b, 0x50, 0xdb, 0xc9, 0x84, 0x55, 0xae, 0xf1, 0x33, 0xb0, 0x0e, 0x27, 0x2e, 0xea, 0xa3, 0x41, 0x93, 0x58, 0x87, 0x13, 0xec,
0x37, 0x8e, 0xa8, 0x55, 0xb1, 0x51, 0xaf, 0x4e, 0x0a, 0x13, 0xdf, 0x83, 0xa5, 0xad, 0x64, 0x9f, 0x42, 0xfd, 0x4d, 0x2e, 0xc3, 0x69, 0x42, 0x5d, 0xab, 0x8f, 0x06, 0x0d, 0x52, 0x9a, 0xf8, 0x3d,
0x53, 0xcb, 0x90, 0xf7, 0xca, 0xc0, 0x18, 0xaa, 0xbb, 0xe1, 0x47, 0x6a, 0x55, 0x6d, 0xd4, 0x33, 0xd8, 0x3b, 0xcc, 0x4e, 0x04, 0x75, 0x6d, 0x75, 0xaf, 0x0d, 0x8c, 0xa1, 0x76, 0x1c, 0xff, 0x44,
0x88, 0x3c, 0x3b, 0xaf, 0xa0, 0xb5, 0xcb, 0xa2, 0x59, 0x11, 0x3e, 0x5e, 0x05, 0x83, 0xd0, 0x03, 0xdd, 0x5a, 0x1f, 0x0d, 0x6c, 0xa2, 0xce, 0xfe, 0xdf, 0x08, 0xda, 0xc7, 0x2c, 0x59, 0x95, 0xf9,
0xfd, 0x48, 0x7e, 0xc4, 0x1d, 0x80, 0x11, 0x3d, 0x08, 0x93, 0x50, 0x84, 0x2c, 0xb1, 0x2a, 0xb6, 0xe3, 0x7d, 0xb0, 0x09, 0x3d, 0x35, 0x51, 0x8a, 0x23, 0xee, 0x02, 0x4c, 0xe8, 0x69, 0x9c, 0xc5,
0xd1, 0x6b, 0x91, 0xd2, 0x8d, 0xf3, 0x02, 0x96, 0x35, 0x83, 0x4e, 0x76, 0x1d, 0x8c, 0x99, 0x38, 0x32, 0x66, 0x99, 0x6b, 0xf5, 0xed, 0x41, 0x9b, 0x54, 0x6e, 0xb0, 0x07, 0x8d, 0xd7, 0xe7, 0x4b,
0xd6, 0x99, 0x5a, 0x97, 0x33, 0x7d, 0x47, 0x53, 0x41, 0x8f, 0x49, 0x0e, 0x72, 0x1e, 0xc2, 0xf2, 0xc6, 0x25, 0xe5, 0x2a, 0x5e, 0x93, 0x6c, 0x6c, 0xfc, 0x03, 0x74, 0xca, 0xf3, 0xd7, 0x52, 0x72,
0xae, 0xf0, 0x44, 0xc6, 0x17, 0xbe, 0xef, 0x7c, 0x46, 0xb0, 0x52, 0x60, 0xf4, 0x0b, 0xcf, 0xa0, 0xe1, 0xd6, 0xd4, 0xfb, 0x5f, 0x6d, 0xbf, 0xbf, 0x9a, 0x44, 0x70, 0xc3, 0xe7, 0x75, 0x26, 0xf9,
0x3e, 0x93, 0x24, 0x94, 0xff, 0xf3, 0x99, 0x39, 0x12, 0x6f, 0x42, 0x9d, 0x4b, 0x1e, 0xca, 0x65, 0x9a, 0xdc, 0xe4, 0xf1, 0xbe, 0x02, 0xbc, 0x0d, 0x2a, 0x92, 0x5f, 0xd0, 0x75, 0x99, 0xfc, 0x82,
0x1a, 0xcd, 0x41, 0x67, 0x91, 0x97, 0x7e, 0x6f, 0x8e, 0xc7, 0x7d, 0xa8, 0x46, 0x2c, 0xe0, 0x96, 0xae, 0x0b, 0x25, 0x56, 0x61, 0x92, 0x6b, 0x85, 0x9a, 0x44, 0x1b, 0x07, 0xd6, 0xe7, 0xc8, 0xff,
0x21, 0xfd, 0xee, 0x2f, 0xf2, 0x7b, 0xcb, 0x02, 0x22, 0x81, 0xce, 0x69, 0x05, 0x4c, 0x75, 0x87, 0x02, 0x3a, 0x26, 0xa6, 0x29, 0xd2, 0x0b, 0xb0, 0x57, 0xf2, 0xdc, 0x54, 0xc8, 0xdd, 0xce, 0xf0,
0xb7, 0xc1, 0x9c, 0x84, 0x01, 0xe5, 0x42, 0x65, 0x35, 0x1c, 0x9c, 0x9c, 0x76, 0xef, 0x7c, 0x3b, 0x7b, 0xca, 0x25, 0x3d, 0x27, 0x05, 0xc8, 0xff, 0x10, 0x3a, 0xc7, 0x32, 0x94, 0xb9, 0xd8, 0x29,
0xed, 0xae, 0x97, 0xba, 0x91, 0x4d, 0x69, 0x92, 0x77, 0xaf, 0x17, 0x26, 0x34, 0xe5, 0xfd, 0x80, 0x9b, 0xff, 0x0b, 0x82, 0x67, 0x25, 0xc6, 0x44, 0xf8, 0x14, 0x1a, 0x2b, 0x45, 0x42, 0xc5, 0x7f,
0x6d, 0x28, 0x17, 0x77, 0x24, 0x7f, 0x88, 0x66, 0xc8, 0xb9, 0xc2, 0x64, 0x9a, 0x09, 0x95, 0xc1, 0x86, 0xd9, 0x20, 0xf1, 0x01, 0x34, 0x84, 0xe2, 0xa1, 0x42, 0xa9, 0xdf, 0x1a, 0x75, 0x77, 0x79,
0x0d, 0xb9, 0x14, 0x43, 0xde, 0x0e, 0x89, 0x17, 0xab, 0x1e, 0x69, 0x10, 0x79, 0xc6, 0x6b, 0x60, 0x99, 0x78, 0x1b, 0x3c, 0x1e, 0x42, 0x2d, 0x61, 0x91, 0x70, 0x6d, 0xe5, 0xf7, 0xfe, 0x2e, 0xbf,
0xfa, 0x9e, 0x7f, 0x48, 0x27, 0xb2, 0x49, 0xea, 0x44, 0x5b, 0x78, 0x13, 0x6a, 0x5c, 0x78, 0xa9, 0xef, 0x58, 0x44, 0x14, 0xd0, 0xbf, 0xb4, 0xc0, 0xd1, 0x77, 0xf8, 0x08, 0x9c, 0x79, 0x1c, 0x51,
0xa0, 0x13, 0x6b, 0xc9, 0x46, 0xbd, 0xe6, 0xa0, 0xed, 0xaa, 0xe1, 0x70, 0x8b, 0xe1, 0x70, 0xf7, 0x21, 0xf5, 0xab, 0xc6, 0xa3, 0x8b, 0xcb, 0xde, 0x3b, 0xbf, 0x5f, 0xf6, 0x5e, 0x54, 0xa6, 0x88,
0x8a, 0xe1, 0x18, 0x56, 0x3f, 0x7d, 0xef, 0x22, 0x52, 0x38, 0xe0, 0x97, 0xd0, 0xf0, 0x59, 0x3c, 0x2d, 0x69, 0x56, 0x4c, 0x5d, 0x18, 0x67, 0x94, 0x8b, 0x61, 0xc4, 0x5e, 0x6a, 0x97, 0x60, 0xa2,
0x8d, 0x68, 0xee, 0x6d, 0x5e, 0xd3, 0xfb, 0xdc, 0x25, 0x6f, 0x66, 0x9a, 0xa6, 0x2c, 0xb5, 0x6a, 0x7e, 0x88, 0x61, 0x28, 0xb8, 0xe2, 0x6c, 0x99, 0x4b, 0xfd, 0x82, 0x47, 0x72, 0x69, 0x86, 0xa2,
0x32, 0x50, 0x65, 0x38, 0x3f, 0x2b, 0xd0, 0x2a, 0x17, 0xeb, 0xd2, 0x74, 0x6c, 0x83, 0xa9, 0x4a, 0x8d, 0xb3, 0x30, 0xa5, 0xa6, 0xd7, 0xd4, 0x19, 0x3f, 0x07, 0x67, 0x16, 0xce, 0xce, 0xe8, 0x5c,
0x2f, 0x87, 0xe3, 0x86, 0x52, 0x29, 0x86, 0x2b, 0xa5, 0xb2, 0xa0, 0xe6, 0x67, 0x69, 0x4a, 0x13, 0x35, 0x77, 0x83, 0x18, 0x0b, 0x1f, 0x40, 0x5d, 0xc8, 0x90, 0x4b, 0x3a, 0x77, 0xf7, 0xfa, 0x68,
0xa1, 0x07, 0xaa, 0x30, 0xf3, 0x80, 0x05, 0x13, 0x5e, 0x24, 0xa5, 0x32, 0x88, 0x32, 0xf0, 0x10, 0xd0, 0x1a, 0x79, 0x81, 0x1e, 0xea, 0xa0, 0x1c, 0xea, 0xe0, 0x6d, 0x39, 0xd4, 0xe3, 0xda, 0xcf,
0x1a, 0xf3, 0xfd, 0x71, 0x0d, 0x19, 0xea, 0x79, 0xb8, 0x4a, 0x8a, 0xb9, 0x5b, 0xb9, 0x0c, 0xb5, 0x7f, 0xf4, 0x10, 0x29, 0x1d, 0xf0, 0x97, 0xd0, 0x9c, 0xb1, 0x74, 0x99, 0xd0, 0xc2, 0xdb, 0x79,
0x5b, 0x95, 0xa1, 0xfe, 0xdf, 0x65, 0x70, 0xbe, 0x20, 0x68, 0xcc, 0xbb, 0xbc, 0xa4, 0x2e, 0xba, 0xa0, 0xf7, 0xb5, 0x4b, 0xd1, 0x7a, 0x94, 0x73, 0xc6, 0xdd, 0xba, 0x6e, 0x3d, 0x65, 0xf8, 0x7f,
0xb5, 0xba, 0x7f, 0x28, 0x53, 0xb9, 0x99, 0x32, 0x6b, 0x60, 0x72, 0x91, 0x52, 0x2f, 0x96, 0x35, 0x59, 0xd0, 0xae, 0x16, 0x6b, 0x6b, 0xaa, 0x8f, 0xc0, 0xd1, 0xa5, 0xd7, 0x2d, 0xfb, 0x38, 0xa9,
0x32, 0x88, 0xb6, 0xf2, 0x7d, 0x12, 0xf3, 0x40, 0x56, 0xa8, 0x45, 0xf2, 0xe3, 0xe0, 0x17, 0x82, 0x34, 0xc3, 0x9d, 0x52, 0xb9, 0x50, 0x9f, 0xe5, 0x9c, 0xd3, 0x4c, 0x9a, 0x45, 0x50, 0x9a, 0x45,
0xda, 0x6b, 0xf5, 0xa1, 0xc0, 0x7b, 0xd0, 0x98, 0x2f, 0x6b, 0xec, 0x5c, 0x9e, 0xea, 0x8b, 0xdb, 0xc2, 0x92, 0xc9, 0x30, 0x51, 0x52, 0xd9, 0x44, 0x1b, 0x78, 0x0c, 0xcd, 0xcd, 0xde, 0x7b, 0x80,
0xbd, 0xfd, 0xe8, 0xaf, 0x18, 0xbd, 0x9e, 0xde, 0xc0, 0x92, 0xdc, 0x88, 0xf8, 0x8a, 0xfd, 0x52, 0x0c, 0x8d, 0x22, 0x5d, 0x2d, 0xc5, 0xc6, 0xad, 0x5a, 0x86, 0xfa, 0x93, 0xca, 0xd0, 0xf8, 0xdf,
0x5e, 0xb6, 0xed, 0xee, 0xc2, 0xff, 0x35, 0xd3, 0x0e, 0x98, 0xba, 0xbb, 0xaf, 0x82, 0x96, 0x17, 0x65, 0xf0, 0x7f, 0x45, 0xd0, 0xdc, 0x74, 0x79, 0x45, 0x5d, 0xf4, 0x64, 0x75, 0x6f, 0x28, 0x63,
0x67, 0xdb, 0x5e, 0x0c, 0x50, 0x64, 0x8f, 0xd1, 0xb0, 0x75, 0x72, 0xd6, 0x41, 0x5f, 0xcf, 0x3a, 0x3d, 0x4e, 0x99, 0xe7, 0xe0, 0x08, 0xc9, 0x69, 0x98, 0xaa, 0x1a, 0xd9, 0xc4, 0x58, 0xc5, 0x3e,
0xe8, 0xc7, 0x59, 0x07, 0x8d, 0x4d, 0xa9, 0xed, 0xd3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x49, 0x45, 0xa4, 0x2a, 0xd4, 0x26, 0xc5, 0x71, 0xf4, 0x0f, 0x82, 0xfa, 0x37, 0xfa, 0x03, 0x87,
0x88, 0x4d, 0x15, 0x37, 0x07, 0x00, 0x00, 0xdf, 0x42, 0x73, 0xf3, 0x91, 0xc1, 0xfe, 0xf6, 0x54, 0xdf, 0xfe, 0x2a, 0x79, 0x1f, 0xdd, 0x8b,
0x31, 0xeb, 0xe9, 0x5b, 0xd8, 0x53, 0x1b, 0x11, 0x77, 0xef, 0x5f, 0xcf, 0x5e, 0x6f, 0xe7, 0xff,
0x86, 0xe9, 0x0d, 0x38, 0xa6, 0xbb, 0xef, 0x82, 0x56, 0x17, 0xa7, 0xd7, 0xdf, 0x0d, 0xd0, 0x64,
0x1f, 0xa3, 0x71, 0xfb, 0xe2, 0xaa, 0x8b, 0x7e, 0xbb, 0xea, 0xa2, 0x3f, 0xaf, 0xba, 0x68, 0xea,
0x28, 0x6d, 0x3f, 0xf9, 0x37, 0x00, 0x00, 0xff, 0xff, 0x97, 0xc3, 0x70, 0xc2, 0xef, 0x07, 0x00,
0x00,
} }

View File

@ -32,6 +32,8 @@ message UsageRecord {
message SolveRequest { message SolveRequest {
string Ref = 1; string Ref = 1;
repeated bytes Definition = 2; // TODO: remove repeated repeated bytes Definition = 2; // TODO: remove repeated
string Exporter = 3;
map<string, string> ExporterAttrs = 4;
} }
message SolveResponse { message SolveResponse {

1
cache/manager.go vendored
View File

@ -92,6 +92,7 @@ func (cm *cacheManager) Get(ctx context.Context, id string) (ImmutableRef, error
defer cm.mu.Unlock() defer cm.mu.Unlock()
return cm.get(ctx, id) return cm.get(ctx, id)
} }
func (cm *cacheManager) get(ctx context.Context, id string) (ImmutableRef, error) { func (cm *cacheManager) get(ctx context.Context, id string) (ImmutableRef, error) {
rec, err := cm.load(ctx, id) rec, err := cm.load(ctx, id)
if err != nil { if err != nil {

8
cache/refs.go vendored
View File

@ -16,6 +16,7 @@ type ImmutableRef interface {
ID() string ID() string
Release(context.Context) error Release(context.Context) error
Size(ctx context.Context) (int64, error) Size(ctx context.Context) (int64, error)
Parent() ImmutableRef
// Prepare() / ChainID() / Meta() // Prepare() / ChainID() / Meta()
} }
@ -85,6 +86,13 @@ func (cr *cacheRecord) Size(ctx context.Context) (int64, error) {
return s.(int64), err return s.(int64), err
} }
func (cr *cacheRecord) Parent() ImmutableRef {
if cr.parent == nil {
return nil
}
return cr.parent.(*immutableRef).ref()
}
func (cr *cacheRecord) Mount(ctx context.Context) ([]mount.Mount, error) { func (cr *cacheRecord) Mount(ctx context.Context) ([]mount.Mount, error) {
cr.mu.Lock() cr.mu.Lock()
defer cr.mu.Unlock() defer cr.mu.Unlock()

View File

@ -95,6 +95,6 @@ func testBuildMultiMount(t *testing.T, address string) {
err = llb.WriteTo(dt, buf) err = llb.WriteTo(dt, buf)
assert.Nil(t, err) assert.Nil(t, err)
err = c.Solve(context.TODO(), buf, nil) err = c.Solve(context.TODO(), buf, nil, "", nil)
assert.Nil(t, err) assert.Nil(t, err)
} }

View File

@ -13,7 +13,7 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
func (c *Client) Solve(ctx context.Context, r io.Reader, statusChan chan *SolveStatus) error { func (c *Client) Solve(ctx context.Context, r io.Reader, statusChan chan *SolveStatus, exporter string, exporterAttrs map[string]string) error {
def, err := llb.ReadFrom(r) def, err := llb.ReadFrom(r)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to parse input") return errors.Wrap(err, "failed to parse input")
@ -36,8 +36,10 @@ func (c *Client) Solve(ctx context.Context, r io.Reader, statusChan chan *SolveS
}() }()
}() }()
_, err = c.controlClient().Solve(ctx, &controlapi.SolveRequest{ _, err = c.controlClient().Solve(ctx, &controlapi.SolveRequest{
Ref: ref, Ref: ref,
Definition: def, Definition: def,
Exporter: exporter,
ExporterAttrs: exporterAttrs,
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "failed to solve") return errors.Wrap(err, "failed to solve")

View File

@ -5,11 +5,13 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/util/appcontext" "github.com/moby/buildkit/util/appcontext"
"github.com/moby/buildkit/util/progress/progressui" "github.com/moby/buildkit/util/progress/progressui"
"github.com/pkg/errors"
"github.com/urfave/cli" "github.com/urfave/cli"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@ -18,6 +20,16 @@ var buildCommand = cli.Command{
Name: "build", Name: "build",
Usage: "build", Usage: "build",
Action: build, Action: build,
Flags: []cli.Flag{
cli.StringFlag{
Name: "exporter",
Usage: "Define exporter for build result",
},
cli.StringSliceFlag{
Name: "exporter-opt",
Usage: "Define custom options for exporter",
},
},
} }
func build(clicontext *cli.Context) error { func build(clicontext *cli.Context) error {
@ -39,8 +51,13 @@ func build(clicontext *cli.Context) error {
displayCh := make(chan *client.SolveStatus) displayCh := make(chan *client.SolveStatus)
eg, ctx := errgroup.WithContext(appcontext.Context()) eg, ctx := errgroup.WithContext(appcontext.Context())
exporterAttrs, err := attrMap(clicontext.StringSlice("exporter-opt"))
if err != nil {
return errors.Wrap(err, "invalid exporter-opt")
}
eg.Go(func() error { eg.Go(func() error {
return c.Solve(ctx, os.Stdin, ch) return c.Solve(ctx, os.Stdin, ch, clicontext.String("exporter"), exporterAttrs)
}) })
eg.Go(func() error { eg.Go(func() error {
@ -61,3 +78,15 @@ func build(clicontext *cli.Context) error {
return eg.Wait() return eg.Wait()
} }
func attrMap(sl []string) (map[string]string, error) {
m := map[string]string{}
for _, v := range sl {
parts := strings.SplitN(v, "=", 2)
if len(parts) != 2 {
return nil, errors.Errorf("invalid value %s", v)
}
m[parts[0]] = parts[1]
}
return m, nil
}

View File

@ -5,6 +5,7 @@ import (
controlapi "github.com/moby/buildkit/api/services/control" controlapi "github.com/moby/buildkit/api/services/control"
"github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver"
"github.com/moby/buildkit/source" "github.com/moby/buildkit/source"
"github.com/moby/buildkit/worker" "github.com/moby/buildkit/worker"
@ -20,6 +21,7 @@ type Opt struct {
Worker worker.Worker Worker worker.Worker
SourceManager *source.Manager SourceManager *source.Manager
InstructionCache solver.InstructionCache InstructionCache solver.InstructionCache
Exporters map[string]exporter.Exporter
} }
type Controller struct { // TODO: ControlService type Controller struct { // TODO: ControlService
@ -68,7 +70,20 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to load") return nil, errors.Wrap(err, "failed to load")
} }
if err := c.solver.Solve(ctx, req.Ref, v); err != nil {
var expi exporter.ExporterInstance
if req.Exporter != "" {
exp, ok := c.opt.Exporters[req.Exporter]
if !ok {
return nil, errors.Errorf("exporter %q could not be found", req.Exporter)
}
expi, err = exp.Resolve(ctx, req.ExporterAttrs)
if err != nil {
return nil, err
}
}
if err := c.solver.Solve(ctx, req.Ref, v, expi); err != nil {
return nil, err return nil, err
} }
return &controlapi.SolveResponse{}, nil return &controlapi.SolveResponse{}, nil

View File

@ -44,10 +44,13 @@ func NewContainerd(root, address string) (*Controller, error) {
} }
func newContainerdPullDeps(client *containerd.Client) *pullDeps { func newContainerdPullDeps(client *containerd.Client) *pullDeps {
diff := client.DiffService()
return &pullDeps{ return &pullDeps{
Snapshotter: client.SnapshotService(), Snapshotter: client.SnapshotService(),
ContentStore: client.ContentStore(), ContentStore: client.ContentStore(),
Applier: client.DiffService(), Applier: diff,
Differ: diff,
Images: client.ImageService(),
} }
} }

View File

@ -6,21 +6,28 @@ import (
"path/filepath" "path/filepath"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/rootfs" "github.com/containerd/containerd/rootfs"
ctdsnapshot "github.com/containerd/containerd/snapshot" ctdsnapshot "github.com/containerd/containerd/snapshot"
"github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/instructioncache" "github.com/moby/buildkit/cache/instructioncache"
"github.com/moby/buildkit/cache/metadata" "github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/exporter"
imageexporter "github.com/moby/buildkit/exporter/containerimage"
"github.com/moby/buildkit/snapshot/blobmapping" "github.com/moby/buildkit/snapshot/blobmapping"
"github.com/moby/buildkit/source" "github.com/moby/buildkit/source"
"github.com/moby/buildkit/source/containerimage" "github.com/moby/buildkit/source/containerimage"
"github.com/moby/buildkit/source/git" "github.com/moby/buildkit/source/git"
) )
const keyImageExporter = "image"
type pullDeps struct { type pullDeps struct {
Snapshotter ctdsnapshot.Snapshotter Snapshotter ctdsnapshot.Snapshotter
ContentStore content.Store ContentStore content.Store
Applier rootfs.Applier Applier rootfs.Applier
Differ rootfs.MountDiffer
Images images.Store
} }
func defaultControllerOpts(root string, pd pullDeps) (*Opt, error) { func defaultControllerOpts(root string, pd pullDeps) (*Opt, error) {
@ -78,10 +85,25 @@ func defaultControllerOpts(root string, pd pullDeps) (*Opt, error) {
sm.Register(gs) sm.Register(gs)
exporters := map[string]exporter.Exporter{}
imageExporter, err := imageexporter.New(imageexporter.Opt{
Snapshotter: snapshotter,
ContentStore: pd.ContentStore,
Differ: pd.Differ,
CacheAccessor: cm,
Images: pd.Images,
})
if err != nil {
return nil, err
}
exporters[keyImageExporter] = imageExporter
return &Opt{ return &Opt{
Snapshotter: snapshotter, Snapshotter: snapshotter,
CacheManager: cm, CacheManager: cm,
SourceManager: sm, SourceManager: sm,
InstructionCache: ic, InstructionCache: ic,
Exporters: exporters,
}, nil }, nil
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/containerd/containerd/archive" "github.com/containerd/containerd/archive"
"github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/archive/compression"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/differ"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
ctdsnapshot "github.com/containerd/containerd/snapshot" ctdsnapshot "github.com/containerd/containerd/snapshot"
@ -61,12 +62,16 @@ func newStandalonePullDeps(root string) (*pullDeps, error) {
return nil, err return nil, err
} }
a := &localApplier{root: root, content: c} differ, err := differ.NewBaseDiff(c)
if err != nil {
return nil, err
}
return &pullDeps{ return &pullDeps{
Snapshotter: &nsSnapshotter{s}, Snapshotter: &nsSnapshotter{s},
ContentStore: c, ContentStore: c,
Applier: a, Applier: differ,
Differ: differ,
}, nil }, nil
} }

View File

@ -0,0 +1,228 @@
package containerimage
import (
"bytes"
gocontext "context"
"encoding/json"
"runtime"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/rootfs"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/util/flightcontrol"
"github.com/moby/buildkit/util/system"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/net/context"
"golang.org/x/sync/errgroup"
)
const (
keyImageName = "name"
)
type Opt struct {
Snapshotter snapshot.Snapshotter
ContentStore content.Store
Differ rootfs.MountDiffer
CacheAccessor cache.Accessor
MetadataStore metadata.Store
Images images.Store
}
type imageExporter struct {
blobmap blobmapper
opt Opt
g flightcontrol.Group
}
type diffPair struct {
diffID digest.Digest
blobsum digest.Digest
}
type blobmapper interface {
GetBlob(ctx gocontext.Context, key string) (digest.Digest, error)
SetBlob(ctx gocontext.Context, key string, blob digest.Digest) error
}
func New(opt Opt) (exporter.Exporter, error) {
blobmap, ok := opt.Snapshotter.(blobmapper)
if !ok {
return nil, errors.Errorf("image exporter requires snapshotter with blobs mapping support")
}
im := &imageExporter{opt: opt, blobmap: blobmap}
return im, nil
}
func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
i := &imageExporterInstance{imageExporter: e}
for k, v := range opt {
switch k {
case keyImageName:
i.targetName = v
default:
logrus.Warnf("unknown exporter option %s", k)
}
}
return i, nil
}
func (e *imageExporter) getBlobs(ctx context.Context, ref cache.ImmutableRef) ([]diffPair, error) {
eg, ctx := errgroup.WithContext(ctx)
var diffPairs []diffPair
var currentPair diffPair
parent := ref.Parent()
if parent != nil {
defer parent.Release(context.TODO())
eg.Go(func() error {
dp, err := e.getBlobs(ctx, parent)
if err != nil {
return err
}
diffPairs = dp
return nil
})
}
eg.Go(func() error {
dp, err := e.g.Do(ctx, ref.ID(), func(ctx context.Context) (interface{}, error) {
blob, err := e.blobmap.GetBlob(ctx, ref.ID())
if err != nil {
return nil, err
}
if blob != "" {
diffID, err := digest.Parse(ref.ID())
if err != nil {
diffID = blob
}
return diffPair{diffID: diffID, blobsum: blob}, nil
}
// reference needs to be committed
parent := ref.Parent()
var lower []mount.Mount
if parent != nil {
defer parent.Release(context.TODO())
lower, err = parent.Mount(ctx)
if err != nil {
return nil, err
}
}
upper, err := ref.Mount(ctx)
if err != nil {
return nil, err
}
descr, err := e.opt.Differ.DiffMounts(ctx, lower, upper, ocispec.MediaTypeImageLayer, ref.ID())
if err != nil {
return nil, err
}
if err := e.blobmap.SetBlob(ctx, ref.ID(), descr.Digest); err != nil {
return nil, err
}
return diffPair{diffID: descr.Digest, blobsum: descr.Digest}, nil
})
if err != nil {
return err
}
currentPair = dp.(diffPair)
return nil
})
err := eg.Wait()
if err != nil {
return nil, err
}
return append(diffPairs, currentPair), nil
}
type imageExporterInstance struct {
*imageExporter
targetName string
}
func (e *imageExporterInstance) Export(ctx context.Context, ref cache.ImmutableRef) error {
diffPairs, err := e.getBlobs(ctx, ref)
if err != nil {
return err
}
diffIDs := make([]digest.Digest, 0, len(diffPairs))
for _, dp := range diffPairs {
diffIDs = append(diffIDs, dp.diffID)
}
dt, err := json.Marshal(imageConfig(diffIDs))
if err != nil {
return errors.Wrap(err, "failed to marshal image config")
}
dgst := digest.FromBytes(dt)
if err := content.WriteBlob(ctx, e.opt.ContentStore, dgst.String(), bytes.NewReader(dt), int64(len(dt)), dgst); err != nil {
return errors.Wrap(err, "error writing config blob")
}
mfst := ocispec.Manifest{
Config: ocispec.Descriptor{
Digest: dgst,
Size: int64(len(dt)),
MediaType: ocispec.MediaTypeImageConfig,
},
}
mfst.SchemaVersion = 2
for _, dp := range diffPairs {
info, err := e.opt.ContentStore.Info(ctx, dp.blobsum)
if err != nil {
return errors.Wrapf(err, "could not get blob %s", dp.blobsum)
}
mfst.Layers = append(mfst.Layers, ocispec.Descriptor{
Digest: dp.blobsum,
Size: info.Size,
MediaType: ocispec.MediaTypeImageLayerGzip,
})
}
dt, err = json.Marshal(mfst)
if err != nil {
return errors.Wrap(err, "failed to marshal manifest")
}
dgst = digest.FromBytes(dt)
if err := content.WriteBlob(ctx, e.opt.ContentStore, dgst.String(), bytes.NewReader(dt), int64(len(dt)), dgst); err != nil {
return errors.Wrap(err, "error writing manifest blob")
}
logrus.Debugf("wrote manifest %s", dgst)
if e.opt.Images != nil && e.targetName != "" {
e.opt.Images.Update(ctx, e.targetName, ocispec.Descriptor{
Digest: dgst,
Size: int64(len(dt)),
MediaType: ocispec.MediaTypeImageManifest,
})
logrus.Debugf("updated tag for %s", e.targetName)
}
return err
}
// this is temporary: should move to dockerfile frontend
func imageConfig(diffIDs []digest.Digest) ocispec.Image {
img := ocispec.Image{
Architecture: runtime.GOARCH,
OS: runtime.GOOS,
}
img.RootFS.Type = "layers"
img.RootFS.DiffIDs = diffIDs
img.Config.WorkingDir = "/"
img.Config.Env = []string{"PATH=" + system.DefaultPathEnv}
return img
}

14
exporter/exporter.go Normal file
View File

@ -0,0 +1,14 @@
package exporter
import (
"github.com/moby/buildkit/cache"
"golang.org/x/net/context"
)
type Exporter interface {
Resolve(context.Context, map[string]string) (ExporterInstance, error)
}
type ExporterInstance interface {
Export(context.Context, cache.ImmutableRef) error
}

View File

@ -1,7 +1,7 @@
{ {
"Vendor": true, "Vendor": true,
"Deadline": "8m", "Deadline": "8m",
"Exclude": ["solver/pb/ops.pb.go"], "Exclude": ["solver/pb/ops.pb.go", "api/services/control/control.pb.go"],
"DisableAll": true, "DisableAll": true,
"Enable": [ "Enable": [
"gofmt", "gofmt",

View File

@ -65,13 +65,8 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
return nil, errors.Errorf("missing input %d", m.Input) return nil, errors.Errorf("missing input %d", m.Input)
} }
inp := inputs[int(m.Input)] inp := inputs[int(m.Input)]
if sys, ok := inp.(interface {
Sys() Reference
}); ok {
inp = sys.Sys()
}
var ok bool var ok bool
ref, ok = inp.(cache.ImmutableRef) ref, ok = toImmutableRef(inp)
if !ok { if !ok {
return nil, errors.Errorf("invalid reference for exec %T", inputs[int(m.Input)]) return nil, errors.Errorf("invalid reference for exec %T", inputs[int(m.Input)])
} }

View File

@ -4,6 +4,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/source" "github.com/moby/buildkit/source"
"github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/progress"
@ -63,7 +64,7 @@ func New(resolve ResolveOpFunc, cache InstructionCache) *Solver {
return &Solver{resolve: resolve, jobs: newJobList(), cache: cache} return &Solver{resolve: resolve, jobs: newJobList(), cache: cache}
} }
func (s *Solver) Solve(ctx context.Context, id string, v Vertex) error { func (s *Solver) Solve(ctx context.Context, id string, v Vertex, exp exporter.ExporterInstance) error {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@ -87,10 +88,22 @@ func (s *Solver) Solve(ctx context.Context, id string, v Vertex) error {
return err return err
} }
for _, r := range refs { defer func() {
r.Release(context.TODO()) for _, r := range refs {
r.Release(context.TODO())
}
}()
if exp != nil {
immutable, ok := toImmutableRef(refs[0])
if !ok {
return errors.Errorf("invalid reference for exporting: %T", refs[0])
}
if err := exp.Export(ctx, immutable); err != nil {
return err
}
} }
// TODO: export final vertex state
return err return err
} }
@ -264,3 +277,26 @@ func toAny(in []Reference) []interface{} {
} }
return out return out
} }
func toImmutableRef(ref Reference) (cache.ImmutableRef, bool) {
sysRef := ref
if sys, ok := ref.(interface {
Sys() Reference
}); ok {
sysRef = sys.Sys()
}
immutable, ok := sysRef.(cache.ImmutableRef)
if !ok {
return nil, false
}
return &immutableRef{immutable, ref.Release}, true
}
type immutableRef struct {
cache.ImmutableRef
release func(context.Context) error
}
func (ir *immutableRef) Release(ctx context.Context) error {
return ir.release(ctx)
}