@@ -18,6 +18,7 @@ import (
18
18
"github.com/containers/image/v5/types"
19
19
"github.com/containers/podman/v5/libpod"
20
20
api "github.com/containers/podman/v5/pkg/api/types"
21
+ entities "github.com/containers/podman/v5/pkg/domain/entities/types"
21
22
"github.com/containers/podman/v5/pkg/errorhandling"
22
23
"github.com/containers/storage"
23
24
"github.com/docker/distribution/registry/api/errcode"
@@ -124,6 +125,100 @@ type pullResult struct {
124
125
err error
125
126
}
126
127
128
+ func PullProgress (ctx context.Context , w http.ResponseWriter , runtime * libpod.Runtime , reference string , pullPolicy config.PullPolicy , pullOptions * libimage.PullOptions ) {
129
+ progress := make (chan types.ProgressProperties )
130
+ pullOptions .Progress = progress
131
+
132
+ pullResChan := make (chan pullResult )
133
+ go func () {
134
+ pulledImages , err := runtime .LibimageRuntime ().Pull (ctx , reference , pullPolicy , pullOptions )
135
+ pullResChan <- pullResult {images : pulledImages , err : err }
136
+ }()
137
+
138
+ enc := json .NewEncoder (w )
139
+ enc .SetEscapeHTML (true )
140
+
141
+ flush := func () {
142
+ if flusher , ok := w .(http.Flusher ); ok {
143
+ flusher .Flush ()
144
+ }
145
+ }
146
+
147
+ statusWritten := false
148
+ writeStatusCode := func (code int ) {
149
+ if ! statusWritten {
150
+ w .WriteHeader (code )
151
+ w .Header ().Set ("Content-Type" , "application/json" )
152
+ flush ()
153
+ statusWritten = true
154
+ }
155
+ }
156
+
157
+ report := entities.ImagePullReportV2 {}
158
+ report .Status = "pulling"
159
+ report .Stream = "Pulling image"
160
+
161
+ writeStatusCode (http .StatusOK )
162
+ if err := enc .Encode (report ); err != nil {
163
+ logrus .Errorf ("Error encoding pull report: %v" , err )
164
+ return
165
+ }
166
+ flush ()
167
+
168
+ for {
169
+ select {
170
+ case e := <- progress :
171
+ report .Status = "pulling"
172
+ switch e .Event {
173
+ case types .ProgressEventNewArtifact :
174
+ report .Stream = "Pulling fs layer"
175
+ case types .ProgressEventRead :
176
+ report .Stream = "Downloading"
177
+ report .Progress = & entities.ImagePullProgress {
178
+ Current : e .Offset ,
179
+ Total : e .Artifact .Size ,
180
+ }
181
+ case types .ProgressEventSkipped :
182
+ report .Stream = "Layer already exists"
183
+ case types .ProgressEventDone :
184
+ report .Stream = "Pull complete"
185
+ }
186
+ if err := enc .Encode (report ); err != nil {
187
+ logrus .Errorf ("Error encoding pull report: %v" , err )
188
+ return
189
+ }
190
+ flush ()
191
+
192
+ case result := <- pullResChan :
193
+ if result .err != nil {
194
+ report .Status = "error"
195
+ report .Stream = result .err .Error ()
196
+ writeStatusCode (http .StatusInternalServerError )
197
+ if err := enc .Encode (report ); err != nil {
198
+ logrus .Errorf ("Error encoding pull report: %v" , err )
199
+ }
200
+ flush ()
201
+ return
202
+ }
203
+
204
+ report .Status = "success"
205
+ report .Stream = "Pull complete"
206
+ images := []string {}
207
+ for _ , img := range result .images {
208
+ images = append (images , img .ID ())
209
+ }
210
+
211
+ report .Images = images
212
+ if err := enc .Encode (report ); err != nil {
213
+ logrus .Errorf ("Error encoding pull report: %v" , err )
214
+ return
215
+ }
216
+ flush ()
217
+ return
218
+ }
219
+ }
220
+ }
221
+
127
222
func CompatPull (ctx context.Context , w http.ResponseWriter , runtime * libpod.Runtime , reference string , pullPolicy config.PullPolicy , pullOptions * libimage.PullOptions ) {
128
223
progress := make (chan types.ProgressProperties )
129
224
pullOptions .Progress = progress
0 commit comments