@@ -7,13 +7,15 @@ import (
77 "fmt"
88 "net/http"
99 "strings"
10+ "time"
1011
1112 "github.com/containers/podman/v6/libpod"
1213 "github.com/containers/podman/v6/pkg/api/handlers"
1314 "github.com/containers/podman/v6/pkg/api/handlers/utils/apiutil"
1415 api "github.com/containers/podman/v6/pkg/api/types"
1516 "github.com/containers/podman/v6/pkg/errorhandling"
1617 "github.com/docker/distribution/registry/api/errcode"
18+ "github.com/docker/go-units"
1719 "github.com/moby/moby/api/types/jsonstream"
1820 "github.com/sirupsen/logrus"
1921 "go.podman.io/common/libimage"
@@ -125,6 +127,68 @@ type pullResult struct {
125127 err error
126128}
127129
130+ // This function is inherited from moby/moby and licensed as Apache-2.0.
131+ // It is used to keep backward compatibility with older docker clients.
132+ func jsonProgressToString (p * jsonstream.Progress ) string {
133+ var (
134+ pbBox string
135+ numbersBox string
136+ )
137+ if p .Current <= 0 && p .Total <= 0 {
138+ return ""
139+ }
140+ if p .Total <= 0 {
141+ switch p .Units {
142+ case "" :
143+ return fmt .Sprintf ("%8v" , units .HumanSize (float64 (p .Current )))
144+ default :
145+ return fmt .Sprintf ("%d %s" , p .Current , p .Units )
146+ }
147+ }
148+
149+ percentage := int (float64 (p .Current )/ float64 (p .Total )* 100 ) / 2
150+ if percentage > 50 {
151+ percentage = 50
152+ }
153+
154+ numSpaces := 0
155+ if 50 - percentage > 0 {
156+ numSpaces = 50 - percentage
157+ }
158+ pbBox = fmt .Sprintf ("[%s>%s] " , strings .Repeat ("=" , percentage ), strings .Repeat (" " , numSpaces ))
159+
160+ switch {
161+ case p .HideCounts :
162+ case p .Units == "" : // no units, use bytes
163+ current := units .HumanSize (float64 (p .Current ))
164+ total := units .HumanSize (float64 (p .Total ))
165+
166+ numbersBox = fmt .Sprintf ("%8v/%v" , current , total )
167+
168+ if p .Current > p .Total {
169+ // remove total display if the reported current is wonky.
170+ numbersBox = fmt .Sprintf ("%8v" , current )
171+ }
172+ default :
173+ numbersBox = fmt .Sprintf ("%d/%d %s" , p .Current , p .Total , p .Units )
174+
175+ if p .Current > p .Total {
176+ // remove total display if the reported current is wonky.
177+ numbersBox = fmt .Sprintf ("%d %s" , p .Current , p .Units )
178+ }
179+ }
180+
181+ // Show approximation of remaining time if there's enough width.
182+ var timeLeftBox string
183+ if p .Current > 0 && p .Start > 0 && percentage < 50 {
184+ fromStart := time .Now ().UTC ().Sub (time .Unix (p .Start , 0 ))
185+ perEntry := fromStart / time .Duration (p .Current )
186+ left := time .Duration (p .Total - p .Current ) * perEntry
187+ timeLeftBox = " " + left .Round (time .Second ).String ()
188+ }
189+ return pbBox + numbersBox + timeLeftBox
190+ }
191+
128192func CompatPull (r * http.Request , w http.ResponseWriter , runtime * libpod.Runtime , reference string , pullPolicy config.PullPolicy , pullOptions * libimage.PullOptions ) {
129193 ctx := r .Context ()
130194 progress := make (chan types.ProgressProperties )
@@ -173,14 +237,7 @@ loop: // break out of for/select infinite loop
173237 report .Progress .Total = e .Artifact .Size
174238 // Deprecated field, but because consumers might still read it keep it.
175239 if _ , err := apiutil .SupportedVersion (r , "<1.52.0" ); err == nil {
176- b , err := json .Marshal (& jsonstream.Message {
177- Status : report .Status ,
178- Progress : report .Progress ,
179- ID : report .ID ,
180- })
181- if err == nil {
182- report .ProgressMessage = string (b )
183- }
240+ report .ProgressMessage = jsonProgressToString (report .Progress )
184241 }
185242 case types .ProgressEventSkipped :
186243 report .Status = "Already exists"
0 commit comments