Merge pull request #7478 from AkihiroSuda/archive-whiteout-source-date-epoch

archive: add WithSourceDateEpoch() for whiteouts
This commit is contained in:
Phil Estes 2022-10-10 15:45:25 -07:00 committed by GitHub
commit cef99bea26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 390 additions and 104 deletions

View File

@ -2827,6 +2827,7 @@ file {
name: "github.com/containerd/containerd/api/services/diff/v1/diff.proto"
package: "containerd.services.diff.v1"
dependency: "google/protobuf/any.proto"
dependency: "google/protobuf/timestamp.proto"
dependency: "github.com/containerd/containerd/api/types/mount.proto"
dependency: "github.com/containerd/containerd/api/types/descriptor.proto"
message_type {
@ -2928,6 +2929,14 @@ file {
type_name: ".containerd.services.diff.v1.DiffRequest.LabelsEntry"
json_name: "labels"
}
field {
name: "source_date_epoch"
number: 6
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".google.protobuf.Timestamp"
json_name: "sourceDateEpoch"
}
nested_type {
name: "LabelsEntry"
field {

View File

@ -26,6 +26,7 @@ import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@ -171,6 +172,9 @@ type DiffRequest struct {
// Labels are the labels to apply to the generated content
// on content store commit.
Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// SourceDateEpoch specifies the timestamp used for whiteouts to provide control for reproducibility.
// See also https://reproducible-builds.org/docs/source-date-epoch/ .
SourceDateEpoch *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=source_date_epoch,json=sourceDateEpoch,proto3" json:"source_date_epoch,omitempty"`
}
func (x *DiffRequest) Reset() {
@ -240,6 +244,13 @@ func (x *DiffRequest) GetLabels() map[string]string {
return nil
}
func (x *DiffRequest) GetSourceDateEpoch() *timestamppb.Timestamp {
if x != nil {
return x.SourceDateEpoch
}
return nil
}
type DiffResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -298,76 +309,83 @@ var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_rawDes
0x74, 0x6f, 0x12, 0x1b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x1a,
0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0x99, 0x02, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x30, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x1a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x99, 0x02, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70,
0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64,
0x69, 0x66, 0x66, 0x12, 0x2f, 0x0a, 0x06, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x12, 0x53, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66,
0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x08, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e,
0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x0d,
0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a,
0x07, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65,
0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64, 0x69,
0x66, 0x66, 0x12, 0x2f, 0x0a, 0x06, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e,
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x12, 0x53, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66,
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08,
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x0d, 0x41,
0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07,
0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73,
0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x61, 0x70, 0x70,
0x6c, 0x69, 0x65, 0x64, 0x22, 0xa3, 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e,
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6c, 0x65, 0x66,
0x74, 0x12, 0x2d, 0x0a, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74,
0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12,
0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65,
0x66, 0x12, 0x4c, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65,
0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a,
0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x0c, 0x44, 0x69,
0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x69,
0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x32, 0xc3, 0x01, 0x0a,
0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x5e, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x29,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70,
0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x28, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x61, 0x70,
0x70, 0x6c, 0x69, 0x65, 0x64, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64,
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6c, 0x65,
0x66, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68,
0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65,
0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72,
0x65, 0x66, 0x12, 0x4c, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31,
0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62,
0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73,
0x12, 0x46, 0x0a, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f,
0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44,
0x61, 0x74, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65,
0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x0c, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52,
0x04, 0x64, 0x69, 0x66, 0x66, 0x32, 0xc3, 0x01, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x5e,
0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69,
0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x66, 0x66, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x66, 0x66,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31,
0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b,
0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66,
0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44,
0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x66,
0x66, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x66, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
@ -384,15 +402,16 @@ func file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_rawDe
var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_goTypes = []interface{}{
(*ApplyRequest)(nil), // 0: containerd.services.diff.v1.ApplyRequest
(*ApplyResponse)(nil), // 1: containerd.services.diff.v1.ApplyResponse
(*DiffRequest)(nil), // 2: containerd.services.diff.v1.DiffRequest
(*DiffResponse)(nil), // 3: containerd.services.diff.v1.DiffResponse
nil, // 4: containerd.services.diff.v1.ApplyRequest.PayloadsEntry
nil, // 5: containerd.services.diff.v1.DiffRequest.LabelsEntry
(*types.Descriptor)(nil), // 6: containerd.types.Descriptor
(*types.Mount)(nil), // 7: containerd.types.Mount
(*anypb.Any)(nil), // 8: google.protobuf.Any
(*ApplyRequest)(nil), // 0: containerd.services.diff.v1.ApplyRequest
(*ApplyResponse)(nil), // 1: containerd.services.diff.v1.ApplyResponse
(*DiffRequest)(nil), // 2: containerd.services.diff.v1.DiffRequest
(*DiffResponse)(nil), // 3: containerd.services.diff.v1.DiffResponse
nil, // 4: containerd.services.diff.v1.ApplyRequest.PayloadsEntry
nil, // 5: containerd.services.diff.v1.DiffRequest.LabelsEntry
(*types.Descriptor)(nil), // 6: containerd.types.Descriptor
(*types.Mount)(nil), // 7: containerd.types.Mount
(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
(*anypb.Any)(nil), // 9: google.protobuf.Any
}
var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_depIdxs = []int32{
6, // 0: containerd.services.diff.v1.ApplyRequest.diff:type_name -> containerd.types.Descriptor
@ -402,17 +421,18 @@ var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_depIdx
7, // 4: containerd.services.diff.v1.DiffRequest.left:type_name -> containerd.types.Mount
7, // 5: containerd.services.diff.v1.DiffRequest.right:type_name -> containerd.types.Mount
5, // 6: containerd.services.diff.v1.DiffRequest.labels:type_name -> containerd.services.diff.v1.DiffRequest.LabelsEntry
6, // 7: containerd.services.diff.v1.DiffResponse.diff:type_name -> containerd.types.Descriptor
8, // 8: containerd.services.diff.v1.ApplyRequest.PayloadsEntry.value:type_name -> google.protobuf.Any
0, // 9: containerd.services.diff.v1.Diff.Apply:input_type -> containerd.services.diff.v1.ApplyRequest
2, // 10: containerd.services.diff.v1.Diff.Diff:input_type -> containerd.services.diff.v1.DiffRequest
1, // 11: containerd.services.diff.v1.Diff.Apply:output_type -> containerd.services.diff.v1.ApplyResponse
3, // 12: containerd.services.diff.v1.Diff.Diff:output_type -> containerd.services.diff.v1.DiffResponse
11, // [11:13] is the sub-list for method output_type
9, // [9:11] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
8, // 7: containerd.services.diff.v1.DiffRequest.source_date_epoch:type_name -> google.protobuf.Timestamp
6, // 8: containerd.services.diff.v1.DiffResponse.diff:type_name -> containerd.types.Descriptor
9, // 9: containerd.services.diff.v1.ApplyRequest.PayloadsEntry.value:type_name -> google.protobuf.Any
0, // 10: containerd.services.diff.v1.Diff.Apply:input_type -> containerd.services.diff.v1.ApplyRequest
2, // 11: containerd.services.diff.v1.Diff.Diff:input_type -> containerd.services.diff.v1.DiffRequest
1, // 12: containerd.services.diff.v1.Diff.Apply:output_type -> containerd.services.diff.v1.ApplyResponse
3, // 13: containerd.services.diff.v1.Diff.Diff:output_type -> containerd.services.diff.v1.DiffResponse
12, // [12:14] is the sub-list for method output_type
10, // [10:12] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_init() }

View File

@ -19,6 +19,7 @@ syntax = "proto3";
package containerd.services.diff.v1;
import "google/protobuf/any.proto";
import "google/protobuf/timestamp.proto";
import "github.com/containerd/containerd/api/types/mount.proto";
import "github.com/containerd/containerd/api/types/descriptor.proto";
@ -72,6 +73,10 @@ message DiffRequest {
// Labels are the labels to apply to the generated content
// on content store commit.
map<string, string> labels = 5;
// SourceDateEpoch specifies the timestamp used for whiteouts to provide control for reproducibility.
// See also https://reproducible-builds.org/docs/source-date-epoch/ .
google.protobuf.Timestamp source_date_epoch = 6;
}
message DiffResponse {

View File

@ -50,11 +50,11 @@ var errInvalidArchive = errors.New("invalid archive")
// files will be prepended with the prefix ".wh.". This style is
// based off AUFS whiteouts.
// See https://github.com/opencontainers/image-spec/blob/main/layer.md
func Diff(ctx context.Context, a, b string) io.ReadCloser {
func Diff(ctx context.Context, a, b string, opts ...WriteDiffOpt) io.ReadCloser {
r, w := io.Pipe()
go func() {
err := WriteDiff(ctx, w, a, b)
err := WriteDiff(ctx, w, a, b, opts...)
if err != nil {
log.G(ctx).WithError(err).Debugf("write diff failed")
}
@ -94,8 +94,12 @@ func WriteDiff(ctx context.Context, w io.Writer, a, b string, opts ...WriteDiffO
// files will be prepended with the prefix ".wh.". This style is
// based off AUFS whiteouts.
// See https://github.com/opencontainers/image-spec/blob/main/layer.md
func writeDiffNaive(ctx context.Context, w io.Writer, a, b string, _ WriteDiffOptions) error {
cw := NewChangeWriter(w, b)
func writeDiffNaive(ctx context.Context, w io.Writer, a, b string, o WriteDiffOptions) error {
var opts []ChangeWriterOpt
if o.SourceDateEpoch != nil {
opts = append(opts, WithWhiteoutTime(*o.SourceDateEpoch))
}
cw := NewChangeWriter(w, b, opts...)
err := fs.Changes(ctx, a, b, cw.HandleChange)
if err != nil {
return fmt.Errorf("failed to create diff tar stream: %w", err)
@ -497,18 +501,32 @@ type ChangeWriter struct {
addedDirs map[string]struct{}
}
// ChangeWriterOpt can be specified in NewChangeWriter.
type ChangeWriterOpt func(cw *ChangeWriter)
// WithWhiteoutTime sets the whiteout timestamp.
func WithWhiteoutTime(tm time.Time) ChangeWriterOpt {
return func(cw *ChangeWriter) {
cw.whiteoutT = tm
}
}
// NewChangeWriter returns ChangeWriter that writes tar stream of the source directory
// to the privided writer. Change information (add/modify/delete/unmodified) for each
// file needs to be passed through HandleChange method.
func NewChangeWriter(w io.Writer, source string) *ChangeWriter {
return &ChangeWriter{
func NewChangeWriter(w io.Writer, source string, opts ...ChangeWriterOpt) *ChangeWriter {
cw := &ChangeWriter{
tw: tar.NewWriter(w),
source: source,
whiteoutT: time.Now(),
whiteoutT: time.Now(), // can be overridden with WithWhiteoutTime(time.Time) ChangeWriterOpt .
inodeSrc: map[uint64]string{},
inodeRefs: map[uint64][]string{},
addedDirs: map[string]struct{}{},
}
for _, o := range opts {
o(cw)
}
return cw
}
// HandleChange receives filesystem change information and reflect that information to

View File

@ -20,6 +20,7 @@ import (
"archive/tar"
"context"
"io"
"time"
)
// ApplyOptions provides additional options for an Apply operation
@ -89,7 +90,19 @@ type WriteDiffOptions struct {
ParentLayers []string // Windows needs the full list of parent layers
writeDiffFunc func(context.Context, io.Writer, string, string, WriteDiffOptions) error
// SourceDateEpoch specifies the timestamp used for whiteouts to provide control for reproducibility.
// See also https://reproducible-builds.org/docs/source-date-epoch/ .
SourceDateEpoch *time.Time
}
// WriteDiffOpt allows setting mutable archive write properties on creation
type WriteDiffOpt func(options *WriteDiffOptions) error
// WithSourceDateEpoch specifies the SOURCE_DATE_EPOCH without touching the env vars.
func WithSourceDateEpoch(tm *time.Time) WriteDiffOpt {
return func(options *WriteDiffOptions) error {
options.SourceDateEpoch = tm
return nil
}
}

View File

@ -36,6 +36,7 @@ import (
"github.com/containerd/containerd/pkg/testutil"
"github.com/containerd/continuity/fs"
"github.com/containerd/continuity/fs/fstest"
"github.com/stretchr/testify/require"
exec "golang.org/x/sys/execabs"
)
@ -1156,8 +1157,35 @@ func TestDiffTar(t *testing.T) {
}
}
func TestWhiteoutSourceDateEpoch(t *testing.T) {
sourceDateEpoch, err := time.Parse(time.RFC3339, "2022-01-23T12:34:56Z")
require.NoError(t, err)
opts := []WriteDiffOpt{WithSourceDateEpoch(&sourceDateEpoch)}
validators := []tarEntryValidator{
composeValidators(whiteoutEntry("f1"), requireModTime(sourceDateEpoch)),
}
a := fstest.Apply(
fstest.CreateFile("/f1", []byte("content"), 0644),
)
b := fstest.Apply(
fstest.RemoveAll("/f1"),
)
makeDiffTarTest(validators, a, b, opts...)(t)
}
type tarEntryValidator func(*tar.Header, []byte) error
func composeValidators(vv ...tarEntryValidator) tarEntryValidator {
return func(hdr *tar.Header, b []byte) error {
for _, v := range vv {
if err := v(hdr, b); err != nil {
return err
}
}
return nil
}
}
func dirEntry(name string, mode int) tarEntryValidator {
return func(hdr *tar.Header, b []byte) error {
if hdr.Typeflag != tar.TypeDir {
@ -1222,7 +1250,16 @@ func whiteoutEntry(name string) tarEntryValidator {
}
}
func makeDiffTarTest(validators []tarEntryValidator, a, b fstest.Applier) func(*testing.T) {
func requireModTime(expected time.Time) tarEntryValidator {
return func(hdr *tar.Header, b []byte) error {
if !hdr.ModTime.Equal(expected) {
return fmt.Errorf("expected ModTime %v, got %v", expected, hdr.ModTime)
}
return nil
}
}
func makeDiffTarTest(validators []tarEntryValidator, a, b fstest.Applier, opts ...WriteDiffOpt) func(*testing.T) {
return func(t *testing.T) {
ad := t.TempDir()
if err := a.Apply(ad); err != nil {
@ -1237,7 +1274,7 @@ func makeDiffTarTest(validators []tarEntryValidator, a, b fstest.Applier) func(*
t.Fatalf("failed to apply b: %v", err)
}
rc := Diff(context.Background(), ad, bd)
rc := Diff(context.Background(), ad, bd, opts...)
defer rc.Close()
tr := tar.NewReader(rc)

View File

@ -31,6 +31,7 @@ import (
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/pkg/epoch"
"github.com/containerd/containerd/pkg/progress"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/snapshots"
@ -142,6 +143,14 @@ var diffCommand = cli.Command{
diff.WithLabels(labels),
}
ep, err := epoch.SourceDateEpoch()
if err != nil {
return err
}
if ep != nil {
opts = append(opts, diff.WithSourceDateEpoch(ep))
}
if idB == "" {
desc, err = rootfs.CreateDiff(ctx, idA, snapshotter, client.DiffService(), opts...)
if err != nil {

16
diff.go
View File

@ -28,6 +28,7 @@ import (
ptypes "github.com/containerd/containerd/protobuf/types"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"google.golang.org/protobuf/types/known/timestamppb"
)
// DiffService handles the computation and application of diffs
@ -80,12 +81,17 @@ func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...di
return ocispec.Descriptor{}, err
}
}
var sourceDateEpoch *timestamppb.Timestamp
if config.SourceDateEpoch != nil {
sourceDateEpoch = timestamppb.New(*config.SourceDateEpoch)
}
req := &diffapi.DiffRequest{
Left: fromMounts(a),
Right: fromMounts(b),
MediaType: config.MediaType,
Ref: config.Reference,
Labels: config.Labels,
Left: fromMounts(a),
Right: fromMounts(b),
MediaType: config.MediaType,
Ref: config.Reference,
Labels: config.Labels,
SourceDateEpoch: sourceDateEpoch,
}
resp, err := r.client.Diff(ctx, req)
if err != nil {

View File

@ -19,6 +19,7 @@ package diff
import (
"context"
"io"
"time"
"github.com/containerd/containerd/mount"
"github.com/containerd/typeurl"
@ -44,6 +45,9 @@ type Config struct {
// the MediaType of the target diff content to the compressor.
// When using this config, MediaType must be specified as well.
Compressor func(dest io.Writer, mediaType string) (io.WriteCloser, error)
// SourceDateEpoch specifies the SOURCE_DATE_EPOCH without touching the env vars.
SourceDateEpoch *time.Time
}
// Opt is used to configure a diff operation
@ -120,3 +124,12 @@ func WithPayloads(payloads map[string]typeurl.Any) ApplyOpt {
return nil
}
}
// WithSourceDateEpoch specifies the timestamp used for whiteouts to provide control for reproducibility.
// See also https://reproducible-builds.org/docs/source-date-epoch/ .
func WithSourceDateEpoch(tm *time.Time) Opt {
return func(c *Config) error {
c.SourceDateEpoch = tm
return nil
}
}

View File

@ -65,6 +65,11 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
}
}
var writeDiffOpts []archive.WriteDiffOpt
if config.SourceDateEpoch != nil {
writeDiffOpts = append(writeDiffOpts, archive.WithSourceDateEpoch(config.SourceDateEpoch))
}
var isCompressed bool
if config.Compressor != nil {
if config.MediaType == "" {
@ -136,7 +141,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
return fmt.Errorf("failed to get compressed stream: %w", errOpen)
}
}
errOpen = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), lowerRoot, upperRoot)
errOpen = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), lowerRoot, upperRoot, writeDiffOpts...)
compressed.Close()
if errOpen != nil {
return fmt.Errorf("failed to write compressed diff: %w", errOpen)
@ -147,7 +152,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
}
config.Labels[uncompressed] = dgstr.Digest().String()
} else {
if errOpen = archive.WriteDiff(ctx, cw, lowerRoot, upperRoot); errOpen != nil {
if errOpen = archive.WriteDiff(ctx, cw, lowerRoot, upperRoot, writeDiffOpts...); errOpen != nil {
return fmt.Errorf("failed to write diff: %w", errOpen)
}
}

69
pkg/epoch/epoch.go Normal file
View File

@ -0,0 +1,69 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package epoch provides SOURCE_DATE_EPOCH utilities.
package epoch
import (
"fmt"
"os"
"strconv"
"time"
"github.com/sirupsen/logrus"
)
// SourceDateEpochEnv is the SOURCE_DATE_EPOCH env var.
// See https://reproducible-builds.org/docs/source-date-epoch/
const SourceDateEpochEnv = "SOURCE_DATE_EPOCH"
// SourceDateEpoch returns the SOURCE_DATE_EPOCH env var as *time.Time.
// If the env var is not set, SourceDateEpoch returns nil without an error.
func SourceDateEpoch() (*time.Time, error) {
v, ok := os.LookupEnv(SourceDateEpochEnv)
if !ok {
return nil, nil // not an error
}
i64, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid %s value %q: %w", SourceDateEpochEnv, v, err)
}
unix := time.Unix(i64, 0)
return &unix, nil
}
// SourceDateEpochOrNow returns the SOURCE_DATE_EPOCH time if available,
// otherwise returns the current time.
func SourceDateEpochOrNow() time.Time {
epoch, err := SourceDateEpoch()
if err != nil {
logrus.WithError(err).Warnf("Invalid %s", SourceDateEpochEnv)
}
if epoch != nil {
return *epoch
}
return time.Now()
}
// SetSourceDateEpoch sets the SOURCE_DATE_EPOCH env var.
func SetSourceDateEpoch(tm time.Time) {
os.Setenv(SourceDateEpochEnv, fmt.Sprintf("%d", tm.Unix()))
}
// UnsetSourceDateEpoch unsets the SOURCE_DATE_EPOCH env var.
func UnsetSourceDateEpoch() {
os.Unsetenv(SourceDateEpochEnv)
}

78
pkg/epoch/epoch_test.go Normal file
View File

@ -0,0 +1,78 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package epoch
import (
"os"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func rightAfter(t1, t2 time.Time) bool {
if runtime.GOOS == "windows" {
// Low timer resolution on Windows
return (t2.After(t1) && t2.Before(t1.Add(100*time.Millisecond))) || t2.Equal(t1)
}
return t2.After(t1) && t2.Before(t1.Add(10*time.Millisecond))
}
func TestSourceDateEpoch(t *testing.T) {
if s, ok := os.LookupEnv(SourceDateEpochEnv); ok {
t.Logf("%s is already set to %q, unsetting", SourceDateEpochEnv, s)
t.Setenv(SourceDateEpochEnv, "")
}
t.Run("WithoutSourceDateEpoch", func(t *testing.T) {
vp, err := SourceDateEpoch()
require.NoError(t, err)
require.Nil(t, vp)
now := time.Now()
v := SourceDateEpochOrNow()
require.True(t, rightAfter(now, v))
})
t.Run("WithSourceDateEpoch", func(t *testing.T) {
sourceDateEpoch, err := time.Parse(time.RFC3339, "2022-01-23T12:34:56Z")
require.NoError(t, err)
SetSourceDateEpoch(sourceDateEpoch)
t.Cleanup(UnsetSourceDateEpoch)
vp, err := SourceDateEpoch()
require.NoError(t, err)
require.True(t, vp.Equal(sourceDateEpoch))
v := SourceDateEpochOrNow()
require.True(t, v.Equal(sourceDateEpoch))
})
t.Run("WithInvalidSourceDateEpoch", func(t *testing.T) {
t.Setenv(SourceDateEpochEnv, "foo")
vp, err := SourceDateEpoch()
require.ErrorContains(t, err, "invalid SOURCE_DATE_EPOCH value")
require.Nil(t, vp)
now := time.Now()
v := SourceDateEpochOrNow()
require.True(t, rightAfter(now, v))
})
}

View File

@ -145,6 +145,10 @@ func (l *local) Diff(ctx context.Context, dr *diffapi.DiffRequest, _ ...grpc.Cal
if dr.Labels != nil {
opts = append(opts, diff.WithLabels(dr.Labels))
}
if dr.SourceDateEpoch != nil {
tm := dr.SourceDateEpoch.AsTime()
opts = append(opts, diff.WithSourceDateEpoch(&tm))
}
for _, d := range l.differs {
ocidesc, err = d.Compare(ctx, aMounts, bMounts, opts...)