@@ -19,10 +19,13 @@ package registry
1919import (
2020 "context"
2121 "fmt"
22+ "io"
2223 "os"
2324 "path/filepath"
2425 "strings"
2526
27+ stereoscopeimage "github.com/anchore/stereoscope/pkg/image"
28+ "github.com/anchore/syft/syft/source"
2629 "github.com/atomist-skills/go-skill"
2730 "github.com/docker/cli/cli/command"
2831 "github.com/docker/index-cli-plugin/internal"
@@ -70,18 +73,22 @@ type ImageCache struct {
7073 Tags []string
7174
7275 Image * v1.Image
76+ Source * source.Source
7377 ImagePath string
7478 Ref * name.Reference
7579
76- copy bool
77- cli command.Cli
80+ remote bool
81+ copy bool
82+ cli command.Cli
83+ sourceCleanup func ()
7884}
7985
8086func (c * ImageCache ) StoreImage () error {
8187 if ! c .copy {
8288 return nil
8389 }
8490 skill .Log .Debugf ("Copying image to %s" , c .ImagePath )
91+ var imageSource stereoscopeimage.Source
8592
8693 if format := os .Getenv ("ATOMIST_CACHE_FORMAT" ); format == "" || format == "oci" {
8794 spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
@@ -96,53 +103,113 @@ func (c *ImageCache) StoreImage() error {
96103 if err = p .AppendImage (* c .Image ); err != nil {
97104 return err
98105 }
106+
107+ imageSource = stereoscopeimage .OciDirectorySource
108+
99109 spinner .Stop ()
100- skill .Log .Infof ("Copied image" )
101- return nil
102110 } else if format == "tar" {
103- u := make (chan v1.Update , 0 )
104- errchan := make (chan error )
105- go func () {
106- if err := tarball .WriteToFile (c .ImagePath , * c .Ref , * c .Image , tarball .WithProgress (u )); err != nil {
107- errchan <- errors .Wrapf (err , "failed to write tmp image archive" )
108- }
109- errchan <- nil
110- }()
111+ if c .remote {
112+ u := make (chan v1.Update , 0 )
113+ errchan := make (chan error )
114+ go func () {
115+ if err := tarball .WriteToFile (c .ImagePath , * c .Ref , * c .Image , tarball .WithProgress (u )); err != nil {
116+ errchan <- errors .Wrapf (err , "failed to write tmp image archive" )
117+ }
118+ errchan <- nil
119+ }()
111120
112- var update v1.Update
113- var err error
114- var pp int64
115- spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
116- defer spinner .Stop ()
117- for {
118- select {
119- case update = <- u :
120- if update .Total > 0 {
121- p := 100 * update .Complete / update .Total
122- if pp != p {
123- spinner .WithFields (internal.Fields {
124- "event" : "progress" ,
125- "total" : update .Total ,
126- "complete" : update .Complete ,
127- }).Update (fmt .Sprintf ("Copying image %d%% %s/%s" , p , humanize .Bytes (uint64 (update .Complete )), humanize .Bytes (uint64 (update .Total ))))
128- pp = p
121+ var update v1.Update
122+ var err error
123+ var pp int64
124+ spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
125+ defer spinner .Stop ()
126+ loop := true
127+ for loop {
128+ select {
129+ case update = <- u :
130+ if update .Total > 0 {
131+ p := 100 * update .Complete / update .Total
132+ if pp != p {
133+ spinner .WithFields (internal.Fields {
134+ "event" : "progress" ,
135+ "total" : update .Total ,
136+ "complete" : update .Complete ,
137+ }).Update (fmt .Sprintf ("Copying image %d%% %s/%s" , p , humanize .Bytes (uint64 (update .Complete )), humanize .Bytes (uint64 (update .Total ))))
138+ pp = p
139+ }
140+ }
141+ case err = <- errchan :
142+ if err != nil {
143+ return err
144+ } else {
145+ spinner .Stop ()
146+ skill .Log .Infof ("Copied image" )
147+ loop = false
129148 }
130149 }
131- case err = <- errchan :
150+ }
151+
152+ } else {
153+ spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
154+ defer spinner .Stop ()
155+ tempTarFile , err := os .Create (c .ImagePath )
156+ if err != nil {
157+ return errors .Wrap (err , "unable to create temp file for image" )
158+ }
159+ defer func () {
160+ err := tempTarFile .Close ()
161+ if err != nil {
162+ skill .Log .Errorf ("unable to close temp file (%s): %w" , tempTarFile .Name (), err )
163+ }
164+ }()
165+
166+ readCloser , err := c .cli .Client ().ImageSave (context .Background (), []string {c .Id })
167+ if err != nil {
168+ return errors .Wrap (err , "unable to save image tar" )
169+ }
170+ defer func () {
171+ err := readCloser .Close ()
132172 if err != nil {
133- return err
134- } else {
135- spinner .Stop ()
136- skill .Log .Infof ("Copied image" )
137- return nil
173+ skill .Log .Errorf ("unable to close temp file (%s): %w" , tempTarFile .Name (), err )
138174 }
175+ }()
176+
177+ nBytes , err := io .Copy (tempTarFile , readCloser )
178+ if err != nil {
179+ return fmt .Errorf ("unable to save image to tar: %w" , err )
180+ }
181+ if nBytes == 0 {
182+ return errors .New ("cannot provide an empty image" )
139183 }
184+ spinner .Stop ()
140185 }
186+
187+ imageSource = stereoscopeimage .DockerTarballSource
141188 }
189+
190+ skill .Log .Debugf ("Parsing image" )
191+ input := source.Input {
192+ Scheme : source .ImageScheme ,
193+ ImageSource : imageSource ,
194+ Location : c .ImagePath ,
195+ }
196+ src , cleanup , err := source .New (input , nil , nil )
197+ if err != nil {
198+ return errors .Wrap (err , "failed to create new image source" )
199+ }
200+ c .Source = src
201+ c .sourceCleanup = cleanup
202+
203+ skill .Log .Debugf ("Parsed image" )
204+ skill .Log .Infof ("Copied image" )
205+
142206 return nil
143207}
144208
145209func (c * ImageCache ) Cleanup () {
210+ if c .sourceCleanup != nil {
211+ c .sourceCleanup ()
212+ }
146213 if ! c .copy {
147214 return
148215 }
@@ -169,7 +236,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
169236 }
170237 tarPath := filepath .Join (path , "sha256" , digest [7 :])
171238 tarFileName := filepath .Join (tarPath , uuid .NewString ())
172- if os .Getenv ("ATOMIST_CACHE_FORMAT" ) == "tar " {
239+ if os .Getenv ("ATOMIST_CACHE_FORMAT" ) != "oci " {
173240 tarFileName += ".tar"
174241 }
175242
@@ -204,6 +271,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
204271 name = strings .Split (t , ":" )[0 ]
205272 tags = append (tags , strings .Split (t , ":" )[1 ])
206273 }
274+
207275 return & ImageCache {
208276 Id : im .ID ,
209277 Digest : digest ,
@@ -214,6 +282,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
214282 Ref : & ref ,
215283 ImagePath : imagePath ,
216284 copy : true ,
285+ remote : false ,
217286 cli : cli ,
218287 }, nil
219288 }
@@ -250,6 +319,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
250319 Ref : & ref ,
251320 ImagePath : imagePath ,
252321 copy : true ,
322+ remote : true ,
253323 cli : cli ,
254324 }, nil
255325}
0 commit comments