diff --git a/api/services/control/control.pb.go b/api/services/control/control.pb.go index c0862fcc0..1bdc906b6 100644 --- a/api/services/control/control.pb.go +++ b/api/services/control/control.pb.go @@ -237,6 +237,7 @@ type Vertex struct { Started *time.Time `protobuf:"bytes,5,opt,name=started,stdtime" json:"started,omitempty"` Completed *time.Time `protobuf:"bytes,6,opt,name=completed,stdtime" json:"completed,omitempty"` Error string `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"` + Parent github_com_opencontainers_go_digest.Digest `protobuf:"bytes,8,opt,name=parent,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"parent"` } func (m *Vertex) Reset() { *m = Vertex{} } @@ -983,6 +984,12 @@ func (m *Vertex) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintControl(dAtA, i, uint64(len(m.Error))) i += copy(dAtA[i:], m.Error) } + if len(m.Parent) > 0 { + dAtA[i] = 0x42 + i++ + i = encodeVarintControl(dAtA, i, uint64(len(m.Parent))) + i += copy(dAtA[i:], m.Parent) + } return i, nil } @@ -1301,6 +1308,10 @@ func (m *Vertex) Size() (n int) { if l > 0 { n += 1 + l + sovControl(uint64(l)) } + l = len(m.Parent) + if l > 0 { + n += 1 + l + sovControl(uint64(l)) + } return n } @@ -2465,6 +2476,35 @@ func (m *Vertex) Unmarshal(dAtA []byte) error { } m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parent", 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.Parent = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipControl(dAtA[iNdEx:]) @@ -3105,57 +3145,58 @@ var ( func init() { proto.RegisterFile("control.proto", fileDescriptorControl) } var fileDescriptorControl = []byte{ - // 832 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x55, 0x5f, 0x8f, 0xdb, 0x44, - 0x10, 0xc7, 0x76, 0xce, 0x49, 0xe6, 0x72, 0xd5, 0xb1, 0x42, 0x95, 0x65, 0x44, 0x12, 0xcc, 0x4b, - 0x54, 0xa9, 0xbe, 0x36, 0x80, 0x84, 0x0e, 0x09, 0x41, 0x48, 0x25, 0xee, 0xc4, 0xbd, 0xec, 0xb5, - 0xf0, 0xec, 0x24, 0x73, 0xae, 0x15, 0xc7, 0x1b, 0x76, 0xd7, 0xd1, 0x85, 0x4f, 0x01, 0x9f, 0x85, - 0xcf, 0x80, 0xe8, 0x23, 0xcf, 0x3c, 0x1c, 0xe8, 0x3e, 0x00, 0x9f, 0x01, 0xed, 0x1f, 0xa7, 0xbe, - 0xe6, 0xd2, 0x96, 0xeb, 0x93, 0x67, 0xd6, 0xbf, 0x99, 0x9d, 0xf9, 0xcd, 0x9f, 0x85, 0x83, 0x29, - 0x2b, 0x24, 0x67, 0x79, 0xbc, 0xe4, 0x4c, 0x32, 0x72, 0xb8, 0x60, 0x93, 0x75, 0x3c, 0x29, 0xb3, - 0x7c, 0x36, 0xcf, 0x64, 0xbc, 0x7a, 0x1c, 0x3e, 0x4c, 0x33, 0xf9, 0xbc, 0x9c, 0xc4, 0x53, 0xb6, - 0x38, 0x4a, 0x59, 0xca, 0x8e, 0x34, 0x70, 0x52, 0x5e, 0x68, 0x4d, 0x2b, 0x5a, 0x32, 0x0e, 0xc2, - 0x5e, 0xca, 0x58, 0x9a, 0xe3, 0x4b, 0x94, 0xcc, 0x16, 0x28, 0x64, 0xb2, 0x58, 0x1a, 0x40, 0x44, - 0xe0, 0x70, 0x9c, 0x89, 0xf9, 0x33, 0x91, 0xa4, 0x48, 0xf1, 0xa7, 0x12, 0x85, 0x8c, 0x4e, 0xe1, - 0xfd, 0xda, 0x99, 0x58, 0xb2, 0x42, 0x20, 0xf9, 0x1c, 0x7c, 0x8e, 0x53, 0xc6, 0x67, 0x81, 0xd3, - 0xf7, 0x06, 0xfb, 0xc3, 0x8f, 0xe2, 0x57, 0x63, 0x8b, 0xad, 0x81, 0x02, 0x51, 0x0b, 0x8e, 0x12, - 0xd8, 0xaf, 0x1d, 0x93, 0x7b, 0xe0, 0x9e, 0x8c, 0x03, 0xa7, 0xef, 0x0c, 0xda, 0xd4, 0x3d, 0x19, - 0x93, 0x00, 0x9a, 0x67, 0xa5, 0x4c, 0x26, 0x39, 0x06, 0x6e, 0xdf, 0x19, 0xb4, 0x68, 0xa5, 0x92, - 0x0f, 0x60, 0xef, 0xa4, 0x78, 0x26, 0x30, 0xf0, 0xf4, 0xb9, 0x51, 0x08, 0x81, 0xc6, 0x79, 0xf6, - 0x33, 0x06, 0x8d, 0xbe, 0x33, 0xf0, 0xa8, 0x96, 0xa3, 0x5f, 0x5d, 0xe8, 0x9c, 0xb3, 0x7c, 0x55, - 0xc5, 0x4f, 0x0e, 0xc1, 0xa3, 0x78, 0x61, 0x6f, 0x51, 0x22, 0xe9, 0x02, 0x8c, 0xf1, 0x22, 0x2b, - 0x32, 0x99, 0xb1, 0x22, 0x70, 0xfb, 0xde, 0xa0, 0x43, 0x6b, 0x27, 0x24, 0x84, 0xd6, 0x93, 0xcb, - 0x25, 0xe3, 0x12, 0xb9, 0xbe, 0xaf, 0x4d, 0x37, 0x3a, 0xf9, 0x11, 0x0e, 0x2a, 0xf9, 0x1b, 0x29, - 0xb9, 0x08, 0x1a, 0x3a, 0xff, 0xc7, 0xdb, 0xf9, 0xd7, 0x83, 0x88, 0x6f, 0xd8, 0x3c, 0x29, 0x24, - 0x5f, 0xd3, 0x9b, 0x7e, 0x54, 0xee, 0xe7, 0x28, 0x84, 0x8a, 0x68, 0x4f, 0xdf, 0x59, 0xa9, 0xe1, - 0xd7, 0x40, 0xb6, 0xcd, 0x55, 0x5a, 0x73, 0x5c, 0x57, 0x69, 0xcd, 0x71, 0xad, 0x38, 0x5a, 0x25, - 0x79, 0x69, 0xb8, 0x6b, 0x53, 0xa3, 0x1c, 0xbb, 0x5f, 0x38, 0xd1, 0x97, 0x70, 0x60, 0xa3, 0xb1, - 0xe5, 0x7b, 0x00, 0xde, 0x4a, 0x5e, 0xda, 0xda, 0x05, 0xdb, 0xb1, 0xff, 0x80, 0x5c, 0xe2, 0x25, - 0x55, 0xa0, 0xe8, 0x63, 0x38, 0x38, 0x97, 0x89, 0x2c, 0xc5, 0x4e, 0x42, 0xa3, 0xdf, 0x1c, 0xb8, - 0x57, 0x61, 0xec, 0x0d, 0x9f, 0x41, 0x6b, 0xa5, 0x9d, 0xa0, 0x78, 0xe3, 0x35, 0x1b, 0x24, 0x39, - 0x86, 0x96, 0xd0, 0x7e, 0x50, 0xe8, 0xba, 0xec, 0x0f, 0xbb, 0xbb, 0xac, 0xec, 0x7d, 0x1b, 0x3c, - 0x39, 0x82, 0x46, 0xce, 0x52, 0x11, 0x78, 0xda, 0xee, 0xc3, 0x5d, 0x76, 0xdf, 0xb3, 0x94, 0x6a, - 0x60, 0x74, 0xe5, 0x82, 0x6f, 0xce, 0xc8, 0x29, 0xf8, 0xb3, 0x2c, 0x45, 0x21, 0x4d, 0x56, 0xa3, - 0xe1, 0x8b, 0xab, 0xde, 0x7b, 0x7f, 0x5d, 0xf5, 0x1e, 0xd4, 0xe6, 0x8b, 0x2d, 0xb1, 0x50, 0xf3, - 0x98, 0x64, 0x05, 0x72, 0x71, 0x94, 0xb2, 0x87, 0xc6, 0x24, 0x1e, 0xeb, 0x0f, 0xb5, 0x1e, 0x94, - 0xaf, 0xac, 0x58, 0x96, 0xd2, 0x64, 0x70, 0x47, 0x5f, 0xc6, 0x83, 0x6a, 0xf0, 0x22, 0x59, 0xa0, - 0xed, 0x42, 0x2d, 0x93, 0xfb, 0xe0, 0x4f, 0x93, 0xe9, 0x73, 0x9c, 0xe9, 0xb6, 0x6f, 0x51, 0xab, - 0x91, 0x63, 0x68, 0x0a, 0x99, 0x70, 0x89, 0x33, 0xdd, 0x40, 0xfb, 0xc3, 0x30, 0x36, 0xe3, 0x1e, - 0x57, 0xe3, 0x1e, 0x3f, 0xad, 0xc6, 0x7d, 0xd4, 0xf8, 0xe5, 0xef, 0x9e, 0x43, 0x2b, 0x03, 0xf2, - 0x15, 0xb4, 0xa7, 0x6c, 0xb1, 0xcc, 0x51, 0x59, 0xfb, 0x6f, 0x69, 0xfd, 0xd2, 0x44, 0xb5, 0x1e, - 0x72, 0xce, 0x78, 0xd0, 0x34, 0xad, 0xa7, 0x95, 0xe8, 0x5f, 0x17, 0x3a, 0xf5, 0x62, 0x6d, 0xcd, - 0xfb, 0x29, 0xf8, 0xa6, 0xf4, 0xa6, 0x65, 0xef, 0x46, 0x95, 0xf1, 0x70, 0x2b, 0x55, 0x01, 0x34, - 0xa7, 0x25, 0xe7, 0x58, 0x48, 0xbb, 0x22, 0x2a, 0x55, 0x05, 0x2c, 0x99, 0x4c, 0x72, 0x4d, 0x95, - 0x47, 0x8d, 0x42, 0x46, 0xd0, 0xde, 0x6c, 0xc4, 0xb7, 0xa0, 0xa1, 0xa5, 0xc2, 0x35, 0x54, 0x6c, - 0xcc, 0xea, 0x65, 0x68, 0xbe, 0x53, 0x19, 0x5a, 0xff, 0xbb, 0x0c, 0xd1, 0xef, 0x0e, 0xb4, 0x37, - 0x5d, 0x5e, 0x63, 0xd7, 0x79, 0x67, 0x76, 0x6f, 0x30, 0xe3, 0xde, 0x8d, 0x99, 0xfb, 0xe0, 0x0b, - 0xc9, 0x31, 0x59, 0xe8, 0x1a, 0x79, 0xd4, 0x6a, 0x6a, 0x9f, 0x2c, 0x44, 0xaa, 0x2b, 0xd4, 0xa1, - 0x4a, 0x8c, 0x22, 0xe8, 0x8c, 0xd6, 0x12, 0xc5, 0x19, 0x0a, 0xf5, 0x5a, 0xa8, 0xda, 0xce, 0x12, - 0x99, 0xe8, 0x3c, 0x3a, 0x54, 0xcb, 0xc3, 0x3f, 0x5c, 0x68, 0x7e, 0x6b, 0x9e, 0x47, 0xf2, 0x14, - 0xda, 0x9b, 0x27, 0x8a, 0x44, 0xdb, 0x93, 0xff, 0xea, 0x9b, 0x16, 0x7e, 0xf2, 0x5a, 0x8c, 0x5d, - 0x61, 0xdf, 0xc1, 0x9e, 0xde, 0x9a, 0xa4, 0xfb, 0xfa, 0xe5, 0x1e, 0xf6, 0x76, 0xfe, 0xb7, 0x9e, - 0xce, 0xc0, 0xb7, 0x13, 0x70, 0x1b, 0xb4, 0xbe, 0x5c, 0xc3, 0xfe, 0x6e, 0x80, 0x71, 0xf6, 0xc8, - 0x21, 0x67, 0x9b, 0xa7, 0xe2, 0xb6, 0xd0, 0xea, 0xcc, 0x85, 0x6f, 0xf8, 0x3f, 0x70, 0x1e, 0x39, - 0xa3, 0xce, 0x8b, 0xeb, 0xae, 0xf3, 0xe7, 0x75, 0xd7, 0xf9, 0xe7, 0xba, 0xeb, 0x4c, 0x7c, 0x5d, - 0xce, 0x4f, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xc9, 0xc1, 0x1a, 0x81, 0x7c, 0x08, 0x00, 0x00, + // 844 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x55, 0xdd, 0x8e, 0xdb, 0x44, + 0x14, 0x66, 0xec, 0xac, 0x93, 0x9c, 0xcd, 0x56, 0xcb, 0x08, 0x55, 0x96, 0x11, 0x49, 0x30, 0x37, + 0x51, 0xa5, 0x7a, 0xdb, 0x00, 0x12, 0x5a, 0x24, 0x04, 0x21, 0x95, 0xd8, 0x15, 0x7b, 0x33, 0xdb, + 0xc2, 0xb5, 0x93, 0x9c, 0x75, 0xad, 0x75, 0x3c, 0x61, 0x66, 0x1c, 0x6d, 0x78, 0x0a, 0x78, 0x0d, + 0x6e, 0x79, 0x06, 0x44, 0x2f, 0xb9, 0xe6, 0xa2, 0xa0, 0x7d, 0x00, 0x9e, 0x01, 0xcd, 0x8c, 0x9d, + 0x7a, 0x9b, 0x4d, 0x7f, 0xd2, 0x2b, 0xcf, 0x19, 0x7f, 0xe7, 0xef, 0x3b, 0x3f, 0x03, 0x07, 0x53, + 0x9e, 0x2b, 0xc1, 0xb3, 0x68, 0x21, 0xb8, 0xe2, 0xf4, 0x70, 0xce, 0x27, 0xab, 0x68, 0x52, 0xa4, + 0xd9, 0xec, 0x32, 0x55, 0xd1, 0xf2, 0x61, 0x70, 0x3f, 0x49, 0xd5, 0xd3, 0x62, 0x12, 0x4d, 0xf9, + 0xfc, 0x28, 0xe1, 0x09, 0x3f, 0x32, 0xc0, 0x49, 0x71, 0x61, 0x24, 0x23, 0x98, 0x93, 0x35, 0x10, + 0xf4, 0x12, 0xce, 0x93, 0x0c, 0x5f, 0xa0, 0x54, 0x3a, 0x47, 0xa9, 0xe2, 0xf9, 0xc2, 0x02, 0x42, + 0x0a, 0x87, 0xe3, 0x54, 0x5e, 0x3e, 0x91, 0x71, 0x82, 0x0c, 0x7f, 0x2a, 0x50, 0xaa, 0xf0, 0x14, + 0xde, 0xaf, 0xdd, 0xc9, 0x05, 0xcf, 0x25, 0xd2, 0xcf, 0xc1, 0x13, 0x38, 0xe5, 0x62, 0xe6, 0x93, + 0xbe, 0x3b, 0xd8, 0x1f, 0x7e, 0x14, 0xbd, 0x1c, 0x5b, 0x54, 0x2a, 0x68, 0x10, 0x2b, 0xc1, 0x61, + 0x0c, 0xfb, 0xb5, 0x6b, 0x7a, 0x07, 0x9c, 0x93, 0xb1, 0x4f, 0xfa, 0x64, 0xd0, 0x66, 0xce, 0xc9, + 0x98, 0xfa, 0xd0, 0x3c, 0x2b, 0x54, 0x3c, 0xc9, 0xd0, 0x77, 0xfa, 0x64, 0xd0, 0x62, 0x95, 0x48, + 0x3f, 0x80, 0xbd, 0x93, 0xfc, 0x89, 0x44, 0xdf, 0x35, 0xf7, 0x56, 0xa0, 0x14, 0x1a, 0xe7, 0xe9, + 0xcf, 0xe8, 0x37, 0xfa, 0x64, 0xe0, 0x32, 0x73, 0x0e, 0x7f, 0x75, 0xa0, 0x73, 0xce, 0xb3, 0x65, + 0x15, 0x3f, 0x3d, 0x04, 0x97, 0xe1, 0x45, 0xe9, 0x45, 0x1f, 0x69, 0x17, 0x60, 0x8c, 0x17, 0x69, + 0x9e, 0xaa, 0x94, 0xe7, 0xbe, 0xd3, 0x77, 0x07, 0x1d, 0x56, 0xbb, 0xa1, 0x01, 0xb4, 0x1e, 0x5d, + 0x2d, 0xb8, 0x50, 0x28, 0x8c, 0xbf, 0x36, 0x5b, 0xcb, 0xf4, 0x47, 0x38, 0xa8, 0xce, 0xdf, 0x28, + 0x25, 0xa4, 0xdf, 0x30, 0xf9, 0x3f, 0xdc, 0xcc, 0xbf, 0x1e, 0x44, 0x74, 0x43, 0xe7, 0x51, 0xae, + 0xc4, 0x8a, 0xdd, 0xb4, 0xa3, 0x73, 0x3f, 0x47, 0x29, 0x75, 0x44, 0x7b, 0xc6, 0x67, 0x25, 0x06, + 0x5f, 0x03, 0xdd, 0x54, 0xd7, 0x69, 0x5d, 0xe2, 0xaa, 0x4a, 0xeb, 0x12, 0x57, 0x9a, 0xa3, 0x65, + 0x9c, 0x15, 0x96, 0xbb, 0x36, 0xb3, 0xc2, 0xb1, 0xf3, 0x05, 0x09, 0xbf, 0x84, 0x83, 0x32, 0x9a, + 0xb2, 0x7c, 0xf7, 0xc0, 0x5d, 0xaa, 0xab, 0xb2, 0x76, 0xfe, 0x66, 0xec, 0x3f, 0xa0, 0x50, 0x78, + 0xc5, 0x34, 0x28, 0xfc, 0x18, 0x0e, 0xce, 0x55, 0xac, 0x0a, 0xb9, 0x95, 0xd0, 0xf0, 0x77, 0x02, + 0x77, 0x2a, 0x4c, 0xe9, 0xe1, 0x33, 0x68, 0x2d, 0x8d, 0x11, 0x94, 0xaf, 0x75, 0xb3, 0x46, 0xd2, + 0x63, 0x68, 0x49, 0x63, 0x07, 0xa5, 0xa9, 0xcb, 0xfe, 0xb0, 0xbb, 0x4d, 0xab, 0xf4, 0xb7, 0xc6, + 0xd3, 0x23, 0x68, 0x64, 0x3c, 0x91, 0xbe, 0x6b, 0xf4, 0x3e, 0xdc, 0xa6, 0xf7, 0x3d, 0x4f, 0x98, + 0x01, 0x86, 0xbf, 0xb9, 0xe0, 0xd9, 0x3b, 0x7a, 0x0a, 0xde, 0x2c, 0x4d, 0x50, 0x2a, 0x9b, 0xd5, + 0x68, 0xf8, 0xec, 0x79, 0xef, 0xbd, 0xbf, 0x9f, 0xf7, 0xee, 0xd5, 0xe6, 0x8b, 0x2f, 0x30, 0xd7, + 0xf3, 0x18, 0xa7, 0x39, 0x0a, 0x79, 0x94, 0xf0, 0xfb, 0x56, 0x25, 0x1a, 0x9b, 0x0f, 0x2b, 0x2d, + 0x68, 0x5b, 0x69, 0xbe, 0x28, 0x94, 0xcd, 0x60, 0x47, 0x5b, 0xd6, 0x82, 0x6e, 0xf0, 0x3c, 0x9e, + 0x63, 0xd9, 0x85, 0xe6, 0x4c, 0xef, 0x82, 0x37, 0x8d, 0xa7, 0x4f, 0x71, 0x66, 0xda, 0xbe, 0xc5, + 0x4a, 0x89, 0x1e, 0x43, 0x53, 0xaa, 0x58, 0x28, 0x9c, 0x99, 0x06, 0xda, 0x1f, 0x06, 0x91, 0x1d, + 0xf7, 0xa8, 0x1a, 0xf7, 0xe8, 0x71, 0x35, 0xee, 0xa3, 0xc6, 0x2f, 0xff, 0xf4, 0x08, 0xab, 0x14, + 0xe8, 0x57, 0xd0, 0x9e, 0xf2, 0xf9, 0x22, 0x43, 0xad, 0xed, 0xbd, 0xa1, 0xf6, 0x0b, 0x15, 0xdd, + 0x7a, 0x28, 0x04, 0x17, 0x7e, 0xd3, 0xb6, 0x9e, 0x11, 0x34, 0x13, 0x8b, 0x58, 0x60, 0xae, 0xfc, + 0xd6, 0xee, 0xac, 0x5a, 0x0b, 0xe1, 0x7f, 0x0e, 0x74, 0xea, 0x85, 0xdf, 0xd8, 0x1d, 0xa7, 0xe0, + 0xd9, 0x36, 0xb2, 0xed, 0xbf, 0x9b, 0x33, 0x6b, 0xe1, 0x56, 0xda, 0x7d, 0x68, 0x4e, 0x0b, 0x61, + 0xb2, 0xb1, 0xeb, 0xa6, 0x12, 0x75, 0xf2, 0x8a, 0xab, 0x38, 0x33, 0xb4, 0xbb, 0xcc, 0x0a, 0x74, + 0x04, 0xed, 0xf5, 0x76, 0x7d, 0x03, 0x4a, 0x5b, 0x3a, 0x5c, 0x4b, 0xeb, 0x5a, 0xad, 0x5e, 0xd2, + 0xe6, 0x3b, 0x95, 0xb4, 0xf5, 0xd6, 0x25, 0x0d, 0xff, 0x20, 0xd0, 0x5e, 0x4f, 0x4c, 0x8d, 0x5d, + 0xf2, 0xce, 0xec, 0xde, 0x60, 0xc6, 0xd9, 0x8d, 0x99, 0xbb, 0xe0, 0x49, 0x25, 0x30, 0x9e, 0x9b, + 0x1a, 0xb9, 0xac, 0x94, 0xf4, 0x6e, 0x9a, 0xcb, 0xc4, 0x54, 0xa8, 0xc3, 0xf4, 0x31, 0x0c, 0xa1, + 0x33, 0x5a, 0x29, 0x94, 0x67, 0x28, 0xf5, 0xcb, 0xa3, 0x6b, 0x3b, 0x8b, 0x55, 0x6c, 0xf2, 0xe8, + 0x30, 0x73, 0x1e, 0xfe, 0xe9, 0x40, 0xf3, 0x5b, 0xfb, 0xd4, 0xd2, 0xc7, 0xd0, 0x5e, 0x3f, 0x77, + 0x34, 0xdc, 0xdc, 0x22, 0x2f, 0xbf, 0x8f, 0xc1, 0x27, 0xaf, 0xc4, 0x94, 0xeb, 0xf0, 0x3b, 0xd8, + 0x33, 0x1b, 0x98, 0x76, 0x5f, 0xfd, 0x50, 0x04, 0xbd, 0xad, 0xff, 0x4b, 0x4b, 0x67, 0xe0, 0x95, + 0x13, 0x70, 0x1b, 0xb4, 0xbe, 0xa8, 0x83, 0xfe, 0x76, 0x80, 0x35, 0xf6, 0x80, 0xd0, 0xb3, 0xf5, + 0xb3, 0x73, 0x5b, 0x68, 0x75, 0xe6, 0x82, 0xd7, 0xfc, 0x1f, 0x90, 0x07, 0x64, 0xd4, 0x79, 0x76, + 0xdd, 0x25, 0x7f, 0x5d, 0x77, 0xc9, 0xbf, 0xd7, 0x5d, 0x32, 0xf1, 0x4c, 0x39, 0x3f, 0xfd, 0x3f, + 0x00, 0x00, 0xff, 0xff, 0x03, 0x3d, 0x42, 0x9c, 0xc8, 0x08, 0x00, 0x00, } diff --git a/api/services/control/control.proto b/api/services/control/control.proto index 4a4af389b..0c3021e60 100644 --- a/api/services/control/control.proto +++ b/api/services/control/control.proto @@ -60,6 +60,7 @@ message Vertex { google.protobuf.Timestamp started = 5 [(gogoproto.stdtime) = true ]; google.protobuf.Timestamp completed = 6 [(gogoproto.stdtime) = true ]; string error = 7; // typed errors? + string parent = 8 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false]; } message VertexStatus { diff --git a/client/graph.go b/client/graph.go index 2cad31401..d9fcd0656 100644 --- a/client/graph.go +++ b/client/graph.go @@ -14,6 +14,7 @@ type Vertex struct { Completed *time.Time Cached bool Error string + Parent digest.Digest } type VertexStatus struct { diff --git a/client/llb/llbbuild/llbbuild.go b/client/llb/llbbuild/llbbuild.go new file mode 100644 index 000000000..ed1643bf6 --- /dev/null +++ b/client/llb/llbbuild/llbbuild.go @@ -0,0 +1,92 @@ +package llbbuild + +import ( + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/solver/pb" + digest "github.com/opencontainers/go-digest" +) + +func Build(opt ...BuildOption) llb.StateOption { + return func(s llb.State) llb.State { + return s.WithOutput(NewBuildOp(s.Output(), opt...).Output()) + } +} + +func NewBuildOp(source llb.Output, opt ...BuildOption) llb.Vertex { + info := &BuildInfo{} + for _, o := range opt { + o(info) + } + return &build{source: source, info: info} +} + +type build struct { + source llb.Output + info *BuildInfo +} + +func (b *build) ToInput() (*pb.Input, error) { + dt, err := b.Marshal() + if err != nil { + return nil, err + } + dgst := digest.FromBytes(dt) + return &pb.Input{Digest: dgst, Index: pb.OutputIndex(0)}, nil +} + +func (b *build) Vertex() llb.Vertex { + return b +} + +func (b *build) Validate() error { + return nil +} + +func (b *build) Marshal() ([]byte, error) { + pbo := &pb.BuildOp{ + Builder: pb.LLBBuilder, + Inputs: map[string]*pb.BuildInput{ + pb.LLBDefinitionInput: {pb.InputIndex(0)}}, + } + + pbo.Attrs = map[string]string{} + + if b.info.DefinitionFilename != "" { + pbo.Attrs[pb.AttrLLBDefinitionFilename] = b.info.DefinitionFilename + } + + pop := &pb.Op{ + Op: &pb.Op_Build{ + Build: pbo, + }, + } + + inp, err := b.source.ToInput() + if err != nil { + return nil, err + } + + pop.Inputs = append(pop.Inputs, inp) + + return pop.Marshal() +} + +func (b *build) Output() llb.Output { + return b +} + +func (b *build) Inputs() []llb.Output { + return []llb.Output{b.source} +} + +type BuildInfo struct { + DefinitionFilename string +} + +type BuildOption func(*BuildInfo) + +func WithFilename(fn string) BuildOption { + return func(b *BuildInfo) { + b.DefinitionFilename = fn + } +} diff --git a/client/llb/llbbuild/llbbuild_test.go b/client/llb/llbbuild/llbbuild_test.go new file mode 100644 index 000000000..9b7a3d743 --- /dev/null +++ b/client/llb/llbbuild/llbbuild_test.go @@ -0,0 +1,49 @@ +package llbbuild + +import ( + "testing" + + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/solver/pb" + digest "github.com/opencontainers/go-digest" + "github.com/stretchr/testify/require" +) + +func TestMarshal(t *testing.T) { + b := NewBuildOp(newDummyOutput("foobar"), WithFilename("myfilename")) + dt, err := b.Marshal() + require.NoError(t, err) + + var op pb.Op + err = op.Unmarshal(dt) + require.NoError(t, err) + + buildop := op.GetBuild() + require.NotEqual(t, buildop, nil) + + require.Equal(t, len(op.Inputs), 1) + require.Equal(t, buildop.Builder, pb.LLBBuilder) + require.Equal(t, len(buildop.Inputs), 1) + require.Equal(t, buildop.Inputs[pb.LLBDefinitionInput], &pb.BuildInput{pb.InputIndex(0)}) + + require.Equal(t, buildop.Attrs[pb.AttrLLBDefinitionFilename], "myfilename") +} + +func newDummyOutput(key string) llb.Output { + dgst := digest.FromBytes([]byte(key)) + return &dummyOutput{dgst: dgst} +} + +type dummyOutput struct { + dgst digest.Digest +} + +func (d *dummyOutput) ToInput() (*pb.Input, error) { + return &pb.Input{ + Digest: d.dgst, + Index: pb.OutputIndex(7), // random constant + }, nil +} +func (d *dummyOutput) Vertex() llb.Vertex { + return nil +} diff --git a/client/solve.go b/client/solve.go index a2500e4d9..f1e9b0bdb 100644 --- a/client/solve.go +++ b/client/solve.go @@ -116,6 +116,7 @@ func (c *Client) Solve(ctx context.Context, r io.Reader, opt SolveOpt, statusCha Completed: v.Completed, Error: v.Error, Cached: v.Cached, + Parent: v.Parent, }) } for _, v := range resp.Statuses { diff --git a/cmd/buildctl/debug/dumpllb.go b/cmd/buildctl/debug/dumpllb.go index 275f75cf9..bb437c838 100644 --- a/cmd/buildctl/debug/dumpllb.go +++ b/cmd/buildctl/debug/dumpllb.go @@ -106,6 +106,8 @@ func attr(dgst digest.Digest, op pb.Op) (string, string) { return op.Source.Identifier, "ellipse" case *pb.Op_Exec: return strings.Join(op.Exec.Meta.Args, " "), "box" + case *pb.Op_Build: + return "build", "box3d" default: return dgst.String(), "plaintext" } diff --git a/control/control.go b/control/control.go index 95e214db9..691163c8a 100644 --- a/control/control.go +++ b/control/control.go @@ -122,6 +122,7 @@ func (c *Controller) Status(req *controlapi.StatusRequest, stream controlapi.Con Completed: v.Completed, Error: v.Error, Cached: v.Cached, + Parent: v.Parent, }) } for _, v := range ss.Statuses { diff --git a/examples/nested-llb/main.go b/examples/nested-llb/main.go new file mode 100644 index 000000000..7617e234c --- /dev/null +++ b/examples/nested-llb/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "os" + + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/llbbuild" + "github.com/moby/buildkit/util/system" +) + +const url = "https://gist.githubusercontent.com/tonistiigi/03b4049f8cc3de059bd2a1a1d8643714/raw/b5960995d570d8c6d94db527e805edc6d5854268/buildprs.go" + +func main() { + build := goBuildBase(). + Run(llb.Shlex("apk add --no-cache curl")). + Run(llb.Shlexf("curl -o /buildprs.go \"%s\"", url)) + + buildkitRepo := "github.com/moby/buildkit" + + build = build.Run(llb.Shlex("sh -c \"go run /buildprs.go > /out/buildkit.llb.definition\"")) + build.AddMount("/go/src/"+buildkitRepo, llb.Git(buildkitRepo, "master")) + pb := build.AddMount("/out", llb.Scratch()) + + built := pb.With(llbbuild.Build()) + + dt, err := llb.Image("docker.io/library/alpine:latest").Run(llb.Shlex("ls -l /out"), llb.AddMount("/out", built, llb.Readonly)).Marshal() + if err != nil { + panic(err) + } + llb.WriteTo(dt, os.Stdout) +} + +func goBuildBase() llb.State { + goAlpine := llb.Image("docker.io/library/golang:1.8-alpine") + return goAlpine. + AddEnv("PATH", "/usr/local/go/bin:"+system.DefaultPathEnv). + AddEnv("GOPATH", "/go"). + Run(llb.Shlex("apk add --no-cache g++ linux-headers make")).Root() +} diff --git a/solver/build.go b/solver/build.go new file mode 100644 index 000000000..9459345b1 --- /dev/null +++ b/solver/build.go @@ -0,0 +1,141 @@ +package solver + +import ( + "encoding/json" + "os" + "path/filepath" + + "github.com/docker/docker/pkg/symlink" + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/progress" + digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" + "golang.org/x/net/context" +) + +type buildOp struct { + op *pb.BuildOp + s *Solver + v Vertex +} + +func newBuildOp(v Vertex, op *pb.Op_Build, s *Solver) (Op, error) { + return &buildOp{ + op: op.Build, + s: s, + v: v, + }, nil +} + +func (b *buildOp) CacheKey(ctx context.Context, inputs []string) (string, int, error) { + dt, err := json.Marshal(struct { + Inputs []string + Exec *pb.BuildOp + }{ + Inputs: inputs, + Exec: b.op, + }) + if err != nil { + return "", 0, err + } + return digest.FromBytes(dt).String(), 1, nil // TODO: other builders should support many outputs +} + +func (b *buildOp) Run(ctx context.Context, inputs []Reference) (outputs []Reference, retErr error) { + if b.op.Builder != pb.LLBBuilder { + return nil, errors.Errorf("only llb builder is currently allowed") + } + + builderInputs := b.op.Inputs + llbDef, ok := builderInputs[pb.LLBDefinitionInput] + if !ok { + return nil, errors.Errorf("no llb definition input %s found", pb.LLBDefinitionInput) + } + + i := int(llbDef.Input) + if i >= len(inputs) { + return nil, errors.Errorf("invalid index %v", i) // TODO: this should be validated before + } + inp := inputs[i] + + ref, ok := toImmutableRef(inp) + if !ok { + return nil, errors.Errorf("invalid reference for build %T", inp) + } + + mount, err := ref.Mount(ctx, false) + if err != nil { + return nil, err + } + + lm := snapshot.LocalMounter(mount) + + root, err := lm.Mount() + if err != nil { + return nil, err + } + + defer func() { + if retErr != nil && lm != nil { + lm.Unmount() + } + }() + + fn := pb.LLBDefaultDefinitionFile + if override, ok := b.op.Attrs[pb.AttrLLBDefinitionFilename]; ok { + fn = override + } + + newfn, err := symlink.FollowSymlinkInScope(filepath.Join(root, fn), root) + if err != nil { + return nil, errors.Wrapf(err, "working dir %s points to invalid target", fn) + } + + f, err := os.Open(newfn) + if err != nil { + return nil, errors.Wrapf(err, "failed to open %s", newfn) + } + + def, err := llb.ReadFrom(f) + if err != nil { + f.Close() + return nil, err + } + + f.Close() + lm.Unmount() + lm = nil + + v, err := LoadLLB(def) + if err != nil { + return nil, err + } + + if len(v.Inputs()) == 0 { + return nil, errors.New("required vertex needs to have inputs") + } + + index := v.Inputs()[0].Index + v = v.Inputs()[0].Vertex + + vv := toInternalVertex(v) + + pw, _, ctx := progress.FromContext(ctx, progress.WithMetadata("parentVertex", b.v.Digest())) + defer pw.Close() + + refs, err := b.s.getRefs(ctx, vv) + + // filer out only the required ref + var out Reference + for i, r := range refs { + if i == index { + out = r + } else { + go r.Release(context.TODO()) + } + } + + return []Reference{out}, err +} diff --git a/solver/exec.go b/solver/exec.go index 962798370..86de977b8 100644 --- a/solver/exec.go +++ b/solver/exec.go @@ -19,7 +19,7 @@ type execOp struct { w worker.Worker } -func newExecOp(op *pb.Op_Exec, cm cache.Manager, w worker.Worker) (Op, error) { +func newExecOp(_ Vertex, op *pb.Op_Exec, cm cache.Manager, w worker.Worker) (Op, error) { return &execOp{ op: op.Exec, cm: cm, diff --git a/solver/jobs.go b/solver/jobs.go index c3fec8442..28ac001f1 100644 --- a/solver/jobs.go +++ b/solver/jobs.go @@ -13,6 +13,10 @@ import ( "github.com/pkg/errors" ) +type jobKeyT string + +var jobKey = jobKeyT("buildkit/solver/job") + type jobList struct { mu sync.RWMutex refs map[string]*job @@ -27,12 +31,12 @@ func newJobList() *jobList { return jl } -func (jl *jobList) new(ctx context.Context, id string, g *vertex, pr progress.Reader) (*job, error) { +func (jl *jobList) new(ctx context.Context, id string, g *vertex, pr progress.Reader) (context.Context, *job, error) { jl.mu.Lock() defer jl.mu.Unlock() if _, ok := jl.refs[id]; ok { - return nil, errors.Errorf("id %s exists", id) + return nil, nil, errors.Errorf("id %s exists", id) } j := &job{g: g, pr: progress.NewMultiReader(pr)} jl.refs[id] = j @@ -44,7 +48,7 @@ func (jl *jobList) new(ctx context.Context, id string, g *vertex, pr progress.Re delete(jl.refs, id) }() - return jl.refs[id], nil + return context.WithValue(ctx, jobKey, jl.refs[id]), jl.refs[id], nil } func (jl *jobList) get(id string) (*job, error) { @@ -104,6 +108,10 @@ func (j *job) pipe(ctx context.Context, ch chan *client.SolveStatus) error { for _, p := range p { switch v := p.Sys.(type) { case client.Vertex: + vtx, ok := p.Meta("parentVertex") + if ok { + v.Parent = vtx.(digest.Digest) + } ss.Vertexes = append(ss.Vertexes, &v) case progress.Status: diff --git a/solver/load.go b/solver/load.go index ae6ae23a0..77e26a213 100644 --- a/solver/load.go +++ b/solver/load.go @@ -83,6 +83,8 @@ func llbOpName(op *pb.Op) string { return op.Source.Identifier case *pb.Op_Exec: return strings.Join(op.Exec.Meta.Args, " ") + case *pb.Op_Build: + return "build" default: return "unknown" } diff --git a/solver/pb/attr.go b/solver/pb/attr.go index 0e84fe6a4..bcb447c13 100644 --- a/solver/pb/attr.go +++ b/solver/pb/attr.go @@ -2,3 +2,4 @@ package pb const AttrKeepGitDir = "git.keepgitdir" const AttrLocalSessionID = "local.session" +const AttrLLBDefinitionFilename = "llbbuild.filename" diff --git a/solver/pb/const.go b/solver/pb/const.go index 7bfdf43bd..2cb995108 100644 --- a/solver/pb/const.go +++ b/solver/pb/const.go @@ -6,3 +6,7 @@ type OutputIndex int64 const RootMount = "/" const SkipOutput OutputIndex = -1 const Empty InputIndex = -1 +const LLBBuilder InputIndex = -1 + +const LLBDefinitionInput = "buildkit.llb.definition" +const LLBDefaultDefinitionFile = LLBDefinitionInput diff --git a/solver/pb/ops.pb.go b/solver/pb/ops.pb.go index 9c986215d..ddd1530ce 100644 --- a/solver/pb/ops.pb.go +++ b/solver/pb/ops.pb.go @@ -17,6 +17,8 @@ CopyOp CopySource SourceOp + BuildOp + BuildInput */ package pb @@ -27,6 +29,8 @@ import _ "github.com/gogo/protobuf/gogoproto" import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" +import errors "errors" + import io "io" // Reference imports to suppress errors if they are not otherwise used. @@ -40,6 +44,7 @@ type Op struct { // *Op_Exec // *Op_Source // *Op_Copy + // *Op_Build Op isOp_Op `protobuf_oneof:"op"` } @@ -62,10 +67,14 @@ type Op_Source struct { type Op_Copy struct { Copy *CopyOp `protobuf:"bytes,4,opt,name=copy,oneof"` } +type Op_Build struct { + Build *BuildOp `protobuf:"bytes,5,opt,name=build,oneof"` +} func (*Op_Exec) isOp_Op() {} func (*Op_Source) isOp_Op() {} func (*Op_Copy) isOp_Op() {} +func (*Op_Build) isOp_Op() {} func (m *Op) GetOp() isOp_Op { if m != nil { @@ -102,12 +111,20 @@ func (m *Op) GetCopy() *CopyOp { return nil } +func (m *Op) GetBuild() *BuildOp { + if x, ok := m.GetOp().(*Op_Build); ok { + return x.Build + } + return nil +} + // XXX_OneofFuncs is for the internal use of the proto package. func (*Op) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), []interface{}) { return _Op_OneofMarshaler, _Op_OneofUnmarshaler, []interface{}{ (*Op_Exec)(nil), (*Op_Source)(nil), (*Op_Copy)(nil), + (*Op_Build)(nil), } } @@ -130,6 +147,11 @@ func _Op_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { if err := b.EncodeMessage(x.Copy); err != nil { return err } + case *Op_Build: + _ = b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Build); err != nil { + return err + } case nil: default: return fmt.Errorf("Op.Op has unexpected type %T", x) @@ -164,6 +186,14 @@ func _Op_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bo err := b.DecodeMessage(msg) m.Op = &Op_Copy{msg} return true, err + case 5: // op.build + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(BuildOp) + err := b.DecodeMessage(msg) + m.Op = &Op_Build{msg} + return true, err default: return false, nil } @@ -265,6 +295,39 @@ func (m *SourceOp) GetAttrs() map[string]string { return nil } +type BuildOp struct { + Builder InputIndex `protobuf:"varint,1,opt,name=builder,proto3,customtype=InputIndex" json:"builder"` + Inputs map[string]*BuildInput `protobuf:"bytes,2,rep,name=inputs" json:"inputs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` + Def [][]byte `protobuf:"bytes,3,rep,name=def" json:"def,omitempty"` + Attrs map[string]string `protobuf:"bytes,4,rep,name=attrs" json:"attrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (m *BuildOp) Reset() { *m = BuildOp{} } +func (m *BuildOp) String() string { return proto.CompactTextString(m) } +func (*BuildOp) ProtoMessage() {} + +func (m *BuildOp) GetInputs() map[string]*BuildInput { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *BuildOp) GetAttrs() map[string]string { + if m != nil { + return m.Attrs + } + return nil +} + +type BuildInput struct { + Input InputIndex `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"` +} + +func (m *BuildInput) Reset() { *m = BuildInput{} } +func (m *BuildInput) String() string { return proto.CompactTextString(m) } +func (*BuildInput) ProtoMessage() {} + func init() { proto.RegisterType((*Op)(nil), "pb.Op") proto.RegisterType((*Input)(nil), "pb.Input") @@ -274,6 +337,8 @@ func init() { proto.RegisterType((*CopyOp)(nil), "pb.CopyOp") proto.RegisterType((*CopySource)(nil), "pb.CopySource") proto.RegisterType((*SourceOp)(nil), "pb.SourceOp") + proto.RegisterType((*BuildOp)(nil), "pb.BuildOp") + proto.RegisterType((*BuildInput)(nil), "pb.BuildInput") } func (m *Op) Marshal() (data []byte, err error) { size := m.Size() @@ -354,6 +419,20 @@ func (m *Op_Copy) MarshalTo(data []byte) (int, error) { } return i, nil } +func (m *Op_Build) MarshalTo(data []byte) (int, error) { + i := 0 + if m.Build != nil { + data[i] = 0x2a + i++ + i = encodeVarintOps(data, i, uint64(m.Build.Size())) + n5, err := m.Build.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n5 + } + return i, nil +} func (m *Input) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -402,11 +481,11 @@ func (m *ExecOp) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintOps(data, i, uint64(m.Meta.Size())) - n5, err := m.Meta.MarshalTo(data[i:]) + n6, err := m.Meta.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n5 + i += n6 } if len(m.Mounts) > 0 { for _, msg := range m.Mounts { @@ -633,6 +712,102 @@ func (m *SourceOp) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *BuildOp) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *BuildOp) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Builder != 0 { + data[i] = 0x8 + i++ + i = encodeVarintOps(data, i, uint64(m.Builder)) + } + if len(m.Inputs) > 0 { + for k, _ := range m.Inputs { + data[i] = 0x12 + i++ + v := m.Inputs[k] + if v == nil { + return 0, errors.New("proto: map has nil element") + } + msgSize := v.Size() + mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + msgSize + sovOps(uint64(msgSize)) + i = encodeVarintOps(data, i, uint64(mapSize)) + data[i] = 0xa + i++ + i = encodeVarintOps(data, i, uint64(len(k))) + i += copy(data[i:], k) + data[i] = 0x12 + i++ + i = encodeVarintOps(data, i, uint64(v.Size())) + n7, err := v.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n7 + } + } + if len(m.Def) > 0 { + for _, b := range m.Def { + data[i] = 0x1a + i++ + i = encodeVarintOps(data, i, uint64(len(b))) + i += copy(data[i:], b) + } + } + if len(m.Attrs) > 0 { + for k, _ := range m.Attrs { + data[i] = 0x22 + i++ + v := m.Attrs[k] + mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + len(v) + sovOps(uint64(len(v))) + i = encodeVarintOps(data, i, uint64(mapSize)) + data[i] = 0xa + i++ + i = encodeVarintOps(data, i, uint64(len(k))) + i += copy(data[i:], k) + data[i] = 0x12 + i++ + i = encodeVarintOps(data, i, uint64(len(v))) + i += copy(data[i:], v) + } + } + return i, nil +} + +func (m *BuildInput) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *BuildInput) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Input != 0 { + data[i] = 0x8 + i++ + i = encodeVarintOps(data, i, uint64(m.Input)) + } + return i, nil +} + func encodeFixed64Ops(data []byte, offset int, v uint64) int { data[offset] = uint8(v) data[offset+1] = uint8(v >> 8) @@ -702,6 +877,15 @@ func (m *Op_Copy) Size() (n int) { } return n } +func (m *Op_Build) Size() (n int) { + var l int + _ = l + if m.Build != nil { + l = m.Build.Size() + n += 1 + l + sovOps(uint64(l)) + } + return n +} func (m *Input) Size() (n int) { var l int _ = l @@ -823,6 +1007,50 @@ func (m *SourceOp) Size() (n int) { return n } +func (m *BuildOp) Size() (n int) { + var l int + _ = l + if m.Builder != 0 { + n += 1 + sovOps(uint64(m.Builder)) + } + if len(m.Inputs) > 0 { + for k, v := range m.Inputs { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + } + mapEntrySize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + l + sovOps(uint64(l)) + n += mapEntrySize + 1 + sovOps(uint64(mapEntrySize)) + } + } + if len(m.Def) > 0 { + for _, b := range m.Def { + l = len(b) + n += 1 + l + sovOps(uint64(l)) + } + } + if len(m.Attrs) > 0 { + for k, v := range m.Attrs { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + len(v) + sovOps(uint64(len(v))) + n += mapEntrySize + 1 + sovOps(uint64(mapEntrySize)) + } + } + return n +} + +func (m *BuildInput) Size() (n int) { + var l int + _ = l + if m.Input != 0 { + n += 1 + sovOps(uint64(m.Input)) + } + return n +} + func sovOps(x uint64) (n int) { for { n++ @@ -992,6 +1220,38 @@ func (m *Op) Unmarshal(data []byte) error { } m.Op = &Op_Copy{v} iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Build", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOps + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &BuildOp{} + if err := v.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + m.Op = &Op_Build{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipOps(data[iNdEx:]) @@ -1926,6 +2186,400 @@ func (m *SourceOp) Unmarshal(data []byte) error { } return nil } +func (m *BuildOp) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BuildOp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BuildOp: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Builder", wireType) + } + m.Builder = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.Builder |= (InputIndex(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Inputs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOps + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + 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 ErrIntOverflowOps + } + 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 ErrInvalidLengthOps + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(data[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + mapmsglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthOps + } + postmsgIndex := iNdEx + mapmsglen + if mapmsglen < 0 { + return ErrInvalidLengthOps + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue := &BuildInput{} + if err := mapvalue.Unmarshal(data[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + if m.Inputs == nil { + m.Inputs = make(map[string]*BuildInput) + } + m.Inputs[mapkey] = mapvalue + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Def", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthOps + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Def = append(m.Def, make([]byte, postIndex-iNdEx)) + copy(m.Def[len(m.Def)-1], data[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Attrs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOps + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + 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 ErrIntOverflowOps + } + 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 ErrInvalidLengthOps + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(data[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + 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 ErrIntOverflowOps + } + 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 ErrInvalidLengthOps + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(data[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + if m.Attrs == nil { + m.Attrs = make(map[string]string) + } + m.Attrs[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOps(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthOps + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BuildInput) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BuildInput: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BuildInput: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Input", wireType) + } + m.Input = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.Input |= (InputIndex(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipOps(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthOps + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipOps(data []byte) (n int, err error) { l := len(data) iNdEx := 0 diff --git a/solver/pb/ops.proto b/solver/pb/ops.proto index 7bbc46bc3..f30c59da3 100644 --- a/solver/pb/ops.proto +++ b/solver/pb/ops.proto @@ -10,6 +10,7 @@ message Op { ExecOp exec = 2; SourceOp source = 3; CopyOp copy = 4; + BuildOp build = 5; } } @@ -52,3 +53,15 @@ message SourceOp { string identifier = 1; map attrs = 2; } + +message BuildOp { + int64 builder = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; + map inputs = 2; + repeated bytes def = 3; + map attrs = 4; + // outputs +} + +message BuildInput { + int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/solver/solver.go b/solver/solver.go index 9c0e3e59a..0f077e7f7 100644 --- a/solver/solver.go +++ b/solver/solver.go @@ -24,16 +24,20 @@ type LLBOpt struct { } func NewLLBSolver(opt LLBOpt) *Solver { - return New(func(v Vertex) (Op, error) { + var s *Solver + s = New(func(v Vertex) (Op, error) { switch op := v.Sys().(type) { case *pb.Op_Source: - return newSourceOp(op, opt.SourceManager) + return newSourceOp(v, op, opt.SourceManager) case *pb.Op_Exec: - return newExecOp(op, opt.CacheManager, opt.Worker) + return newExecOp(v, op, opt.CacheManager, opt.Worker) + case *pb.Op_Build: + return newBuildOp(v, op, s) default: return nil, errors.Errorf("invalid op type %T", op) } }, opt.InstructionCache) + return s } // ResolveOpFunc finds an Op implementation for a vertex @@ -76,10 +80,13 @@ func (s *Solver) Solve(ctx context.Context, id string, v Vertex, exp exporter.Ex defer closeProgressWriter() - if len(v.Inputs()) > 0 { // TODO: detect op_return better - v = v.Inputs()[0].Vertex + if len(v.Inputs()) == 0 { + return errors.New("required vertex needs to have inputs") } + index := v.Inputs()[0].Index + v = v.Inputs()[0].Vertex + vv := toInternalVertex(v) solveVertex := vv @@ -89,12 +96,12 @@ func (s *Solver) Solve(ctx context.Context, id string, v Vertex, exp exporter.Ex vv.initClientVertex() } - j, err := s.jobs.new(ctx, id, vv, pr) + ctx, j, err := s.jobs.new(ctx, id, vv, pr) if err != nil { return err } - refs, err := s.getRefs(ctx, j, solveVertex) + refs, err := s.getRefs(ctx, solveVertex) s.activeState.cancel(j) if err != nil { return err @@ -117,9 +124,10 @@ func (s *Solver) Solve(ctx context.Context, id string, v Vertex, exp exporter.Ex } if exp != nil { - immutable, ok := toImmutableRef(refs[0]) + r := refs[int(index)] + immutable, ok := toImmutableRef(r) if !ok { - return errors.Errorf("invalid reference for exporting: %T", refs[0]) + return errors.Errorf("invalid reference for exporting: %T", r) } vv.notifyStarted(ctx) pw, _, ctx := progress.FromContext(ctx, progress.WithMetadata("vertex", vv.Digest())) @@ -142,8 +150,8 @@ func (s *Solver) Status(ctx context.Context, id string, statusChan chan *client. return j.pipe(ctx, statusChan) } -func (s *Solver) getCacheKey(ctx context.Context, j *job, g *vertex) (cacheKey string, numRefs int, retErr error) { - state, err := s.activeState.vertexState(j, g.digest, func() (Op, error) { +func (s *Solver) getCacheKey(ctx context.Context, g *vertex) (cacheKey string, numRefs int, retErr error) { + state, err := s.activeState.vertexState(ctx, g.digest, func() (Op, error) { return s.resolve(g) }) if err != nil { @@ -156,7 +164,7 @@ func (s *Solver) getCacheKey(ctx context.Context, j *job, g *vertex) (cacheKey s for i, in := range g.inputs { func(i int, in *vertex, index int) { eg.Go(func() error { - k, _, err := s.getCacheKey(ctx, j, in) + k, _, err := s.getCacheKey(ctx, in) if err != nil { return err } @@ -185,8 +193,8 @@ func (s *Solver) getCacheKey(ctx context.Context, j *job, g *vertex) (cacheKey s }) } -func (s *Solver) getRefs(ctx context.Context, j *job, g *vertex) (retRef []Reference, retErr error) { - state, err := s.activeState.vertexState(j, g.digest, func() (Op, error) { +func (s *Solver) getRefs(ctx context.Context, g *vertex) (retRef []Reference, retErr error) { + state, err := s.activeState.vertexState(ctx, g.digest, func() (Op, error) { return s.resolve(g) }) if err != nil { @@ -197,7 +205,7 @@ func (s *Solver) getRefs(ctx context.Context, j *job, g *vertex) (retRef []Refer if s.cache != nil { var err error var numRefs int - cacheKey, numRefs, err = s.getCacheKey(ctx, j, g) + cacheKey, numRefs, err = s.getCacheKey(ctx, g) if err != nil { return nil, err } @@ -230,7 +238,7 @@ func (s *Solver) getRefs(ctx context.Context, j *job, g *vertex) (retRef []Refer func(i int, in *vertex, index int) { eg.Go(func() error { if s.cache != nil { - k, numRefs, err := s.getCacheKey(ctx, j, in) + k, numRefs, err := s.getCacheKey(ctx, in) if err != nil { return err } @@ -249,7 +257,7 @@ func (s *Solver) getRefs(ctx context.Context, j *job, g *vertex) (retRef []Refer } // execute input vertex - r, err := s.getRefs(ctx, j, in) + r, err := s.getRefs(ctx, in) if err != nil { return err } diff --git a/solver/source.go b/solver/source.go index 52d90adfc..6180a9c7c 100644 --- a/solver/source.go +++ b/solver/source.go @@ -15,7 +15,7 @@ type sourceOp struct { src source.SourceInstance } -func newSourceOp(op *pb.Op_Source, sm *source.Manager) (Op, error) { +func newSourceOp(_ Vertex, op *pb.Op_Source, sm *source.Manager) (Op, error) { return &sourceOp{ op: op, sm: sm, diff --git a/solver/state.go b/solver/state.go index b1368481a..5adae6840 100644 --- a/solver/state.go +++ b/solver/state.go @@ -7,6 +7,7 @@ import ( "github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/progress" digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" "golang.org/x/net/context" ) @@ -31,7 +32,13 @@ type state struct { cacheCtx context.Context } -func (s *activeState) vertexState(j *job, key digest.Digest, cb func() (Op, error)) (*state, error) { +func (s *activeState) vertexState(ctx context.Context, key digest.Digest, cb func() (Op, error)) (*state, error) { + jv := ctx.Value(jobKey) + if jv == nil { + return nil, errors.Errorf("can't get vertex state without active job") + } + j := jv.(*job) + s.mu.Lock() defer s.mu.Unlock() diff --git a/source/git/gitsource.go b/source/git/gitsource.go index abcd686d7..76bd7cd1a 100644 --- a/source/git/gitsource.go +++ b/source/git/gitsource.go @@ -226,6 +226,8 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context) (out cache.ImmutableRe return gs.cache.Get(ctx, sis[0].ID()) } + gs.locker.Lock(gs.src.Remote) + defer gs.locker.Unlock(gs.src.Remote) gitDir, unmountGitDir, err := gs.mountRemote(ctx, gs.src.Remote) if err != nil { return nil, err diff --git a/util/progress/progress.go b/util/progress/progress.go index ab2d121b0..330923a72 100644 --- a/util/progress/progress.go +++ b/util/progress/progress.go @@ -192,7 +192,19 @@ func (pw *progressWriter) Write(id string, v interface{}) error { } func (pw *progressWriter) WriteRawProgress(p *Progress) error { - p.meta = pw.meta + meta := p.meta + if len(pw.meta) > 0 { + meta = map[string]interface{}{} + for k, v := range p.meta { + meta[k] = v + } + for k, v := range pw.meta { + if _, ok := meta[k]; !ok { + meta[k] = v + } + } + } + p.meta = meta return pw.writeRawProgress(p) } diff --git a/util/progress/progressui/display.go b/util/progress/progressui/display.go index df154d986..cc176d108 100644 --- a/util/progress/progressui/display.go +++ b/util/progress/progressui/display.go @@ -80,6 +80,7 @@ type vertex struct { statuses []*status byID map[string]*status logs []*client.VertexLog + indent string } type status struct { @@ -99,6 +100,10 @@ func (t *trace) update(s *client.SolveStatus) { t.byDigest[v.Digest] = &vertex{ byID: make(map[string]*status), } + } else { + if prev.Parent != v.Parent { // skip vertexes already in list for other parents + continue + } } if v.Started != nil && (prev == nil || prev.Started == nil) { if t.localTimeDiff == 0 { @@ -107,6 +112,9 @@ func (t *trace) update(s *client.SolveStatus) { t.vertexes = append(t.vertexes, t.byDigest[v.Digest]) } t.byDigest[v.Digest].Vertex = v + if v.Parent != "" { + t.byDigest[v.Digest].indent = t.byDigest[v.Parent].indent + "=> " + } } for _, s := range s.Statuses { v, ok := t.byDigest[s.Vertex] @@ -179,12 +187,13 @@ func (t *trace) displayInfo() (d displayInfo) { if v.Cached { j.name = "CACHED " + j.name } + j.name = v.indent + j.name d.jobs = append(d.jobs, j) for _, s := range v.statuses { j := job{ startTime: addTime(s.Started, t.localTimeDiff), completedTime: addTime(s.Completed, t.localTimeDiff), - name: "=> " + s.ID, + name: v.indent + "=> " + s.ID, } if s.Total != 0 { j.status = units.HumanSize(float64(s.Current)) + " / " + units.HumanSize(float64(s.Total))