@@ -112,6 +112,23 @@ type CopyGraphOptions struct {
112112 // source storage to fetch large blobs.
113113 // If FindSuccessors is nil, content.Successors will be used.
114114 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 io.Copy, which, by default, is 32KB. As of now, this cannot
130+ // be changed. We may provided that capability in a future update.
131+ UpdateChannel chan <- CopyUpdate
115132}
116133
117134// Copy copies a rooted directed acyclic graph (DAG) with the tagged root node
@@ -266,11 +283,17 @@ func copyGraph(ctx context.Context, src content.ReadOnlyStorage, dst content.Sto
266283}
267284
268285// 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 {
286+ func doCopyNode (ctx context.Context , src content.ReadOnlyStorage , dst content.Storage , desc ocispec.Descriptor , ch chan <- CopyUpdate ) error {
270287 rc , err := src .Fetch (ctx , desc )
271288 if err != nil {
272289 return err
273290 }
291+ if ch != nil {
292+ rc = & progressReader {
293+ c : ch ,
294+ r : rc ,
295+ }
296+ }
274297 defer rc .Close ()
275298 err = dst .Push (ctx , desc , rc )
276299 if err != nil && ! errors .Is (err , errdef .ErrAlreadyExists ) {
@@ -291,7 +314,7 @@ func copyNode(ctx context.Context, src content.ReadOnlyStorage, dst content.Stor
291314 }
292315 }
293316
294- if err := doCopyNode (ctx , src , dst , desc ); err != nil {
317+ if err := doCopyNode (ctx , src , dst , desc , opts . UpdateChannel ); err != nil {
295318 return err
296319 }
297320
0 commit comments