diff --git a/archive/tar.go b/archive/tar.go index 5007c410a..0c44e123e 100644 --- a/archive/tar.go +++ b/archive/tar.go @@ -30,6 +30,7 @@ import ( "time" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/pkg/userns" "github.com/containerd/continuity/fs" ) @@ -80,6 +81,10 @@ func WriteDiff(ctx context.Context, w io.Writer, a, b string, opts ...WriteDiffO return fmt.Errorf("failed to apply option: %w", err) } } + if tm := epoch.FromContext(ctx); tm != nil && options.SourceDateEpoch == nil { + options.SourceDateEpoch = tm + } + if options.writeDiffFunc == nil { options.writeDiffFunc = writeDiffNaive } diff --git a/cmd/ctr/commands/client.go b/cmd/ctr/commands/client.go index c6bdc390c..24639483a 100644 --- a/cmd/ctr/commands/client.go +++ b/cmd/ctr/commands/client.go @@ -20,7 +20,9 @@ import ( gocontext "context" "github.com/containerd/containerd" + "github.com/containerd/containerd/log" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/epoch" "github.com/urfave/cli" ) @@ -42,6 +44,12 @@ func AppContext(context *cli.Context) (gocontext.Context, gocontext.CancelFunc) } else { ctx, cancel = gocontext.WithCancel(ctx) } + if tm, err := epoch.SourceDateEpoch(); err != nil { + log.L.WithError(err).Warn("Failed to read SOURCE_DATE_EPOCH") + } else if tm != nil { + log.L.Debugf("Using SOURCE_DATE_EPOCH: %v", tm) + ctx = epoch.WithSourceDateEpoch(ctx, tm) + } return ctx, cancel } diff --git a/cmd/ctr/commands/snapshots/snapshots.go b/cmd/ctr/commands/snapshots/snapshots.go index 057e063fa..d3653c509 100644 --- a/cmd/ctr/commands/snapshots/snapshots.go +++ b/cmd/ctr/commands/snapshots/snapshots.go @@ -31,7 +31,6 @@ 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,14 +141,7 @@ var diffCommand = cli.Command{ diff.WithReference(context.String("ref")), diff.WithLabels(labels), } - - ep, err := epoch.SourceDateEpoch() - if err != nil { - return err - } - if ep != nil { - opts = append(opts, diff.WithSourceDateEpoch(ep)) - } + // SOURCE_DATE_EPOCH is propagated via the ctx, so no need to specify diff.WithSourceDateEpoch here if idB == "" { desc, err = rootfs.CreateDiff(ctx, idA, snapshotter, client.DiffService(), opts...) diff --git a/diff.go b/diff.go index 3ae3f66d7..dea8af9c3 100644 --- a/diff.go +++ b/diff.go @@ -24,6 +24,7 @@ import ( "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/protobuf" ptypes "github.com/containerd/containerd/protobuf/types" "github.com/opencontainers/go-digest" @@ -81,6 +82,9 @@ func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...di return ocispec.Descriptor{}, err } } + if tm := epoch.FromContext(ctx); tm != nil && config.SourceDateEpoch == nil { + config.SourceDateEpoch = tm + } var sourceDateEpoch *timestamppb.Timestamp if config.SourceDateEpoch != nil { sourceDateEpoch = timestamppb.New(*config.SourceDateEpoch) diff --git a/diff/walking/differ.go b/diff/walking/differ.go index 0ac514406..0fd75c6f2 100644 --- a/diff/walking/differ.go +++ b/diff/walking/differ.go @@ -32,6 +32,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/epoch" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -64,6 +65,9 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o return emptyDesc, err } } + if tm := epoch.FromContext(ctx); tm != nil && config.SourceDateEpoch == nil { + config.SourceDateEpoch = tm + } var writeDiffOpts []archive.WriteDiffOpt if config.SourceDateEpoch != nil { diff --git a/diff/windows/windows.go b/diff/windows/windows.go index 904e27a4a..8efe2da4c 100644 --- a/diff/windows/windows.go +++ b/diff/windows/windows.go @@ -36,6 +36,7 @@ import ( "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/opencontainers/go-digest" @@ -177,6 +178,9 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op return emptyDesc, err } } + if tm := epoch.FromContext(ctx); tm != nil && config.SourceDateEpoch == nil { + config.SourceDateEpoch = tm + } layers, err := mountPairToLayerStack(lower, upper) if err != nil { diff --git a/pkg/epoch/context.go b/pkg/epoch/context.go new file mode 100644 index 000000000..fd16f9519 --- /dev/null +++ b/pkg/epoch/context.go @@ -0,0 +1,41 @@ +/* + 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 ( + "context" + "time" +) + +type ( + epochKey struct{} +) + +// WithSourceDateEpoch associates the context with the epoch. +func WithSourceDateEpoch(ctx context.Context, tm *time.Time) context.Context { + return context.WithValue(ctx, epochKey{}, tm) +} + +// FromContext returns the epoch associated with the context. +// FromContext does not fall back to read the SOURCE_DATE_EPOCH env var. +func FromContext(ctx context.Context) *time.Time { + v := ctx.Value(epochKey{}) + if v == nil { + return nil + } + return v.(*time.Time) +}