@@ -17,6 +17,7 @@ import (
1717 "fmt"
1818 "os"
1919 "path/filepath"
20+ "time"
2021
2122 "github.com/containers/buildah/define"
2223 "github.com/containers/buildah/imagebuildah"
@@ -65,61 +66,106 @@ func NewPrometheus(root, graphDriverName string, maxParallelDownloads uint) (*Pr
6566 }, nil
6667}
6768
68- /* PullImage pulls an image from a remote registry and stores it in the
69- * Prometheus store. It returns the manifest of the pulled image and an
70- * error if any. Note that the 'docker://' prefix is automatically added
71- * to the imageName to make it compatible with the alltransports.ParseImageName
72- * method. */
73- func (p * Prometheus ) PullImage (imageName string , dstName string ) (* OciManifest , error ) {
74- srcRef , err := alltransports .ParseImageName (fmt .Sprintf ("docker://%s" , imageName ))
69+ // PullImage pulls an image from a remote registry and stores it in the
70+ // Prometheus store. It returns the manifest of the pulled image and an
71+ // error if any. Note that the 'docker://' prefix is automatically added
72+ // to the imageName to make it compatible with the alltransports.ParseImageName
73+ // method.
74+ func (p * Prometheus ) PullImage (imageName , dstName string ) (* OciManifest , error ) {
75+ progressCh := make (chan types.ProgressProperties )
76+ manifestCh := make (chan OciManifest )
77+
78+ defer close (progressCh )
79+ defer close (manifestCh )
80+
81+ err := p .pullImage (imageName , dstName , progressCh , manifestCh )
7582 if err != nil {
7683 return nil , err
7784 }
85+ for {
86+ select {
87+ case report := <- progressCh :
88+ fmt .Printf ("%s: %v/%v\n " , report .Artifact .Digest .Encoded ()[:12 ], report .Offset , report .Artifact .Size )
89+ case manifest := <- manifestCh :
90+ return & manifest , nil
91+ }
92+ }
93+ }
94+
95+ // PullImageAsync does the same thing as PullImage, but returns right
96+ // after starting the pull process. The user can track progress in the
97+ // background by reading from the `progressCh` channel, which contains
98+ // information about the current blob and its progress. When the pull
99+ // process is done, the image's manifest will be sent via the `manifestCh`
100+ // channel, which indicates the process is done.
101+ //
102+ // NOTE: The user is responsible for closing both channels once the operation
103+ // completes.
104+ func (p * Prometheus ) PullImageAsync (imageName , dstName string , progressCh chan types.ProgressProperties , manifestCh chan OciManifest ) error {
105+ err := p .pullImage (imageName , dstName , progressCh , manifestCh )
106+ return err
107+ }
108+
109+ func (p * Prometheus ) pullImage (imageName , dstName string , progressCh chan types.ProgressProperties , manifestCh chan OciManifest ) error {
110+ srcRef , err := alltransports .ParseImageName (fmt .Sprintf ("docker://%s" , imageName ))
111+ if err != nil {
112+ return err
113+ }
78114
79115 destRef , err := storage .Transport .ParseStoreReference (p .Store , dstName )
80116 if err != nil {
81- return nil , err
117+ return err
82118 }
83119
84120 systemCtx := & types.SystemContext {}
85121 policy , err := signature .DefaultPolicy (systemCtx )
86122 if err != nil {
87- return nil , err
123+ return err
88124 }
89125
90126 policyCtx , err := signature .NewPolicyContext (policy )
91127 if err != nil {
92- return nil , err
128+ return err
93129 }
94130
95- pulledManifestBytes , err := copy .Image (
96- context .Background (),
97- policyCtx ,
98- destRef ,
99- srcRef ,
100- & copy.Options {
101- ReportWriter : os .Stdout ,
102- MaxParallelDownloads : p .Config .MaxParallelDownloads ,
103- },
104- )
131+ duration , err := time .ParseDuration ("100ms" )
105132 if err != nil {
106- return nil , err
107- }
133+ return err
134+ }
135+
136+ go func () {
137+ pulledManifestBytes , err := copy .Image (
138+ context .Background (),
139+ policyCtx ,
140+ destRef ,
141+ srcRef ,
142+ & copy.Options {
143+ MaxParallelDownloads : p .Config .MaxParallelDownloads ,
144+ ProgressInterval : duration ,
145+ Progress : progressCh ,
146+ },
147+ )
148+ if err != nil {
149+ return
150+ }
108151
109- var manifest OciManifest
110- err = json .Unmarshal (pulledManifestBytes , & manifest )
111- if err != nil {
112- return nil , err
113- }
152+ var manifest OciManifest
153+ err = json .Unmarshal (pulledManifestBytes , & manifest )
154+ if err != nil {
155+ return
156+ }
114157
115- // here we remove the 'sha256:' prefix from the digest, so we don't have
116- // to deal with it later
117- manifest .Config .Digest = manifest .Config .Digest [7 :]
118- for i := range manifest .Layers {
119- manifest .Layers [i ].Digest = manifest .Layers [i ].Digest [7 :]
120- }
158+ // here we remove the 'sha256:' prefix from the digest, so we don't have
159+ // to deal with it later
160+ manifest .Config .Digest = manifest .Config .Digest [7 :]
161+ for i := range manifest .Layers {
162+ manifest .Layers [i ].Digest = manifest .Layers [i ].Digest [7 :]
163+ }
164+
165+ manifestCh <- manifest
166+ }()
121167
122- return & manifest , nil
168+ return nil
123169}
124170
125171/* GetImageByDigest returns an image from the Prometheus store by its digest. */
@@ -185,8 +231,8 @@ func (p *Prometheus) BuildContainerFile(dockerfilePath string, imageName string)
185231 context .Background (),
186232 p .Store ,
187233 define.BuildOptions {
188- Output : imageName ,
189- },
234+ Output : imageName ,
235+ },
190236 dockerfilePath ,
191237 )
192238 if err != nil {
0 commit comments