@@ -91,7 +91,7 @@ func (b *backend) Push(ctx context.Context, target string, cfg *config.Push) err
9191
9292 return retry .Do (func () error {
9393 logrus .Debugf ("push: processing layer %s" , layer .Digest )
94- if err := pushIfNotExist (gctx , pb , internalpb . NormalizePrompt ( "Copying blob" ), src , dst , layer , repo , tag ); err != nil {
94+ if err := pushIfNotExist (gctx , pb , src , dst , layer , repo , tag ); err != nil {
9595 return err
9696 }
9797 logrus .Debugf ("push: successfully processed layer %s" , layer .Digest )
@@ -106,14 +106,14 @@ func (b *backend) Push(ctx context.Context, target string, cfg *config.Push) err
106106
107107 // copy the config.
108108 if err := retry .Do (func () error {
109- return pushIfNotExist (ctx , pb , internalpb . NormalizePrompt ( "Copying config" ), src , dst , manifest .Config , repo , tag )
109+ return pushIfNotExist (ctx , pb , src , dst , manifest .Config , repo , tag )
110110 }, append (defaultRetryOpts , retry .Context (ctx ))... ); err != nil {
111111 return fmt .Errorf ("failed to push config to remote: %w" , err )
112112 }
113113
114114 // copy the manifest.
115115 if err := retry .Do (func () error {
116- return pushIfNotExist (ctx , pb , internalpb . NormalizePrompt ( "Copying manifest" ), src , dst , ocispec.Descriptor {
116+ return pushIfNotExist (ctx , pb , src , dst , ocispec.Descriptor {
117117 MediaType : manifest .MediaType ,
118118 Size : int64 (len (manifestRaw )),
119119 Digest : godigest .FromBytes (manifestRaw ),
@@ -128,15 +128,22 @@ func (b *backend) Push(ctx context.Context, target string, cfg *config.Push) err
128128}
129129
130130// pushIfNotExist copies the content from the src storage to the dst storage if the content does not exist.
131- func pushIfNotExist (ctx context.Context , pb * internalpb.ProgressBar , prompt string , src storage.Storage , dst * remote.Repository , desc ocispec.Descriptor , repo , tag string ) error {
131+ func pushIfNotExist (ctx context.Context , pb * internalpb.ProgressBar , src storage.Storage , dst * remote.Repository , desc ocispec.Descriptor , repo , tag string ) error {
132+ // Phase 1: show "Checking" during existence check (blob layers only).
133+ // Bar is created with nil reader — shows 0 B / total at 0 speed to indicate waiting state.
134+ if desc .MediaType != ocispec .MediaTypeImageManifest {
135+ pb .Add (internalpb .NormalizePrompt ("Checking blob" ), desc .Digest .String (), desc .Size , nil )
136+ }
137+
132138 // check whether the content exists in the destination storage.
133139 exist , err := dst .Exists (ctx , desc )
134140 if err != nil {
141+ pb .Abort (desc .Digest .String (), err )
135142 return err
136143 }
137144
138145 if exist {
139- pb .Add (prompt , desc .Digest .String (), desc .Size , bytes .NewReader ([]byte {}))
146+ pb .Add (internalpb . NormalizePrompt ( "Skipped blob" ) , desc .Digest .String (), desc .Size , bytes .NewReader ([]byte {}))
140147 // if the descriptor is the manifest, should check the tag existence as well.
141148 if desc .MediaType == ocispec .MediaTypeImageManifest {
142149 _ , _ , err := dst .FetchReference (ctx , tag )
@@ -157,7 +164,7 @@ func pushIfNotExist(ctx context.Context, pb *internalpb.ProgressBar, prompt stri
157164 // push the content to the destination, and wrap the content reader for progress bar,
158165 // manifest should use dst.Manifests().Push, others should use dst.Blobs().Push.
159166 if desc .MediaType == ocispec .MediaTypeImageManifest {
160- reader := pb .Add (prompt , desc .Digest .String (), desc .Size , bytes .NewReader (desc .Data ))
167+ reader := pb .Add (internalpb . NormalizePrompt ( "Copying manifest" ) , desc .Digest .String (), desc .Size , bytes .NewReader (desc .Data ))
161168 if err := dst .Manifests ().Push (ctx , desc , reader ); err != nil {
162169 err = fmt .Errorf ("failed to push manifest %s, err: %w" , desc .Digest .String (), err )
163170 pb .Abort (desc .Digest .String (), err )
@@ -174,10 +181,12 @@ func pushIfNotExist(ctx context.Context, pb *internalpb.ProgressBar, prompt stri
174181 // fetch the content from the source storage.
175182 content , err := src .PullBlob (ctx , repo , desc .Digest .String ())
176183 if err != nil {
184+ pb .Abort (desc .Digest .String (), err )
177185 return err
178186 }
179187
180- reader := pb .Add (prompt , desc .Digest .String (), desc .Size , content )
188+ // Phase 2: reset to "Pushing" for actual upload.
189+ reader := pb .Reset (internalpb .NormalizePrompt ("Pushing blob" ), desc .Digest .String (), desc .Size , content )
181190 // resolve issue: https://github.com/modelpack/modctl/issues/50
182191 // wrap the content to the NopCloser, because the implementation of the distribution will
183192 // always return the error when Close() is called.
0 commit comments