@@ -112,6 +112,25 @@ type CopyGraphOptions struct {
112
112
// source storage to fetch large blobs.
113
113
// If FindSuccessors is nil, content.Successors will be used.
114
114
FindSuccessors func (ctx context.Context , fetcher content.Fetcher , desc ocispec.Descriptor ) ([]ocispec.Descriptor , error )
115
+
116
+ // UpdateChannel is an optional channel to receive progress updates.
117
+ // Each update will include the number of bytes copied for a particular blob
118
+ // or manifest, the expected total size, and the descriptor of the blob or
119
+ // manifest. It is up to the consumer of the channel to differentiate
120
+ // between updates among different blobs and manifests; no mechanism is
121
+ // provided for distinguishing between them, other than the descriptor
122
+ // passed with each update. The total size of downloads of all blobs and
123
+ // manifests is not provided, as it is not known. You can calculate the
124
+ // percentage downloaded for a particular blob in an individual update
125
+ // based on the total size of that blob, which is provided in the
126
+ // descriptor, and the number of bytes copied, which is provided in the
127
+ // update.
128
+ // Updates are sent each time a block is copied. The number of bytes copied
129
+ // depends upon whatever calls the io.ReadCloser of the source Target.
130
+ // This may be io.Copy, which, by default, is 32KB, or it may be some other
131
+ // implementation.
132
+ // The caller is responsible for closing the channel.
133
+ UpdateChannel chan <- CopyUpdate
115
134
}
116
135
117
136
// Copy copies a rooted directed acyclic graph (DAG) with the tagged root node
@@ -266,11 +285,17 @@ func copyGraph(ctx context.Context, src content.ReadOnlyStorage, dst content.Sto
266
285
}
267
286
268
287
// doCopyNode copies a single content from the source CAS to the destination CAS.
269
- func doCopyNode (ctx context.Context , src content.ReadOnlyStorage , dst content.Storage , desc ocispec.Descriptor ) error {
288
+ func doCopyNode (ctx context.Context , src content.ReadOnlyStorage , dst content.Storage , desc ocispec.Descriptor , ch chan <- CopyUpdate ) error {
270
289
rc , err := src .Fetch (ctx , desc )
271
290
if err != nil {
272
291
return err
273
292
}
293
+ if ch != nil {
294
+ rc = & progressReader {
295
+ c : ch ,
296
+ r : rc ,
297
+ }
298
+ }
274
299
defer rc .Close ()
275
300
err = dst .Push (ctx , desc , rc )
276
301
if err != nil && ! errors .Is (err , errdef .ErrAlreadyExists ) {
@@ -291,7 +316,7 @@ func copyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.Stor
291
316
}
292
317
}
293
318
294
- if err := doCopyNode (ctx , src , dst , desc ); err != nil {
319
+ if err := doCopyNode (ctx , src , dst , desc , opts . UpdateChannel ); err != nil {
295
320
return err
296
321
}
297
322
0 commit comments