@@ -22,6 +22,7 @@ import (
2222 "github.com/containers/buildah/define"
2323 "github.com/containers/buildah/imagebuildah"
2424 "github.com/containers/image/v5/copy"
25+ "github.com/containers/image/v5/manifest"
2526 "github.com/containers/image/v5/signature"
2627 "github.com/containers/image/v5/storage"
2728 "github.com/containers/image/v5/transports/alltransports"
@@ -78,14 +79,33 @@ func (p *Prometheus) PullImage(imageName, dstName string) (*OciManifest, error)
7879 defer close (progressCh )
7980 defer close (manifestCh )
8081
81- err := p .pullImage (imageName , dstName , progressCh , manifestCh )
82+ manifest , err := p .PullManifestOnly (imageName )
83+ if err != nil {
84+ return nil , fmt .Errorf ("failed to pull manifest %w" , err )
85+ }
86+
87+ // +1 to account for manifest
88+ layersAll := len (manifest .LayerInfos ()) + 1
89+ layersDone := 0
90+
91+ err = p .pullImage (imageName , dstName , progressCh , manifestCh )
8292 if err != nil {
8393 return nil , err
8494 }
8595 for {
8696 select {
8797 case report := <- progressCh :
88- fmt .Printf ("%s: %v/%v\n " , report .Artifact .Digest .Encoded ()[:12 ], report .Offset , report .Artifact .Size )
98+ digestShort := report .Artifact .Digest .Encoded ()[:12 ]
99+ switch report .Event {
100+ case types .ProgressEventNewArtifact :
101+ fmt .Printf ("[%v/%v] %s: %s\n " , layersDone , layersAll , digestShort , "new" )
102+ case types .ProgressEventDone , types .ProgressEventSkipped :
103+ layersDone += 1
104+ fmt .Printf ("[%v/%v] %s: %s\n " , layersDone , layersAll , digestShort , "done" )
105+ case types .ProgressEventRead :
106+ percentDone := 100 * float64 (report .Offset ) / float64 (report .Artifact .Size )
107+ fmt .Printf ("[%v/%v] %s: %v%%\n " , layersDone , layersAll , digestShort , int (percentDone ))
108+ }
89109 case manifest := <- manifestCh :
90110 return & manifest , nil
91111 }
@@ -246,3 +266,50 @@ func (p *Prometheus) BuildContainerFile(dockerfilePath string, imageName string)
246266
247267 return image , nil
248268}
269+
270+ func (p * Prometheus ) PullManifestOnly (imageName string ) (manifest.Manifest , error ) {
271+ systemCtx := & types.SystemContext {}
272+ ctx := context .Background ()
273+
274+ var outputManifest manifest.Manifest
275+
276+ srcRef , err := alltransports .ParseImageName (fmt .Sprintf ("docker://%s" , imageName ))
277+ if err != nil {
278+ return outputManifest , fmt .Errorf ("failed to parse image name: %w" , err )
279+ }
280+
281+ source , err := srcRef .NewImageSource (ctx , systemCtx )
282+ if err != nil {
283+ return outputManifest , fmt .Errorf ("failed to create image source: %w" , err )
284+ }
285+ defer source .Close ()
286+
287+ manRaw , manMime , err := source .GetManifest (ctx , nil )
288+ if err != nil {
289+ return outputManifest , fmt .Errorf ("failed to fetch manifest: %w" , err )
290+ }
291+
292+ if manMime == manifest .DockerV2ListMediaType || manMime == "application/vnd.oci.image.index.v1+json" {
293+ list , err := manifest .ListFromBlob (manRaw , manMime )
294+ if err != nil {
295+ return outputManifest , fmt .Errorf ("failed to parse manifest list: %w" , err )
296+ }
297+
298+ instanceDigest , err := list .ChooseInstance (systemCtx )
299+ if err != nil {
300+ return outputManifest , fmt .Errorf ("failed to select platform instance: %w" , err )
301+ }
302+
303+ manRaw , manMime , err = source .GetManifest (ctx , & instanceDigest )
304+ if err != nil {
305+ return outputManifest , fmt .Errorf ("failed to fetch platform manifest: %w" , err )
306+ }
307+ }
308+
309+ outputManifest , err = manifest .FromBlob (manRaw , manMime )
310+ if err != nil {
311+ return outputManifest , fmt .Errorf ("failed to parse platform specific manifest: %w" , err )
312+ }
313+
314+ return outputManifest , nil
315+ }
0 commit comments