@@ -29,13 +29,15 @@ import (
2929 "github.com/atomist-skills/go-skill"
3030 "github.com/docker/cli/cli/command"
3131 "github.com/docker/index-cli-plugin/internal"
32+ "github.com/dustin/go-humanize"
3233 "github.com/google/go-containerregistry/pkg/authn"
3334 "github.com/google/go-containerregistry/pkg/name"
3435 v1 "github.com/google/go-containerregistry/pkg/v1"
3536 "github.com/google/go-containerregistry/pkg/v1/daemon"
3637 "github.com/google/go-containerregistry/pkg/v1/empty"
3738 "github.com/google/go-containerregistry/pkg/v1/layout"
3839 "github.com/google/go-containerregistry/pkg/v1/remote"
40+ "github.com/google/go-containerregistry/pkg/v1/tarball"
3941 "github.com/google/uuid"
4042 "github.com/pkg/errors"
4143)
@@ -75,6 +77,7 @@ type ImageCache struct {
7577 ImagePath string
7678 Ref * name.Reference
7779
80+ remote bool
7881 copy bool
7982 cli command.Cli
8083 sourceCleanup func ()
@@ -85,6 +88,7 @@ func (c *ImageCache) StoreImage() error {
8588 return nil
8689 }
8790 skill .Log .Debugf ("Copying image to %s" , c .ImagePath )
91+ var imageSource stereoscopeimage.Source
8892
8993 if format := os .Getenv ("ATOMIST_CACHE_FORMAT" ); format == "" || format == "oci" {
9094 spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
@@ -100,70 +104,105 @@ func (c *ImageCache) StoreImage() error {
100104 return err
101105 }
102106
103- input := source.Input {
104- Scheme : source .ImageScheme ,
105- ImageSource : stereoscopeimage .OciDirectorySource ,
106- Location : c .ImagePath ,
107- }
108- src , cleanup , err := source .New (input , nil , nil )
109- if err != nil {
110- return errors .Wrap (err , "failed to create new source" )
111- }
112- c .Source = src
113- c .sourceCleanup = cleanup
107+ imageSource = stereoscopeimage .OciDirectorySource
114108
115109 spinner .Stop ()
116- skill .Log .Infof ("Copied image" )
117- return nil
118-
119110 } else if format == "tar" {
120- spinner := internal .StartSpinner ("info" , "Copying image" , c .cli .Out ().IsTerminal ())
121- defer spinner .Stop ()
122- tempTarFile , err := os .Create (c .ImagePath )
123- if err != nil {
124- return errors .Wrap (err , "unable to create temp file for image" )
125- }
126- defer func () {
127- err := tempTarFile .Close ()
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+ }()
120+
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
148+ }
149+ }
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 )
128156 if err != nil {
129- skill . Log . Errorf ( "unable to close temp file (%s): %w" , tempTarFile . Name (), err )
157+ return errors . Wrap ( err , "unable to create temp file for image" )
130158 }
131- }()
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+ }()
132165
133- readCloser , err := c .cli .Client ().ImageSave (context .Background (), []string {c .Id })
134- if err != nil {
135- return errors .Wrap (err , "unable to save image tar" )
136- }
137- defer func () {
138- err := readCloser .Close ()
166+ readCloser , err := c .cli .Client ().ImageSave (context .Background (), []string {c .Id })
139167 if err != nil {
140- skill . Log . Errorf ( "unable to close temp file (%s): %w" , tempTarFile . Name (), err )
168+ return errors . Wrap ( err , "unable to save image tar" )
141169 }
142- }()
170+ defer func () {
171+ err := readCloser .Close ()
172+ if err != nil {
173+ skill .Log .Errorf ("unable to close temp file (%s): %w" , tempTarFile .Name (), err )
174+ }
175+ }()
143176
144- nBytes , err := io .Copy (tempTarFile , readCloser )
145- if err != nil {
146- return fmt .Errorf ("unable to save image to tar: %w" , err )
147- }
148- if nBytes == 0 {
149- return errors .New ("cannot provide an empty image" )
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" )
183+ }
184+ spinner .Stop ()
150185 }
151186
152- input := source.Input {
153- Scheme : source .ImageScheme ,
154- ImageSource : stereoscopeimage .DockerTarballSource ,
155- Location : c .ImagePath ,
156- }
157- src , cleanup , err := source .New (input , nil , nil )
158- if err != nil {
159- return errors .Wrap (err , "failed to create new source" )
160- }
161- c .Source = src
162- c .sourceCleanup = cleanup
187+ imageSource = stereoscopeimage .DockerTarballSource
188+ }
163189
164- spinner .Stop ()
165- skill .Log .Infof ("Copied image" )
190+ skill .Log .Debugf ("Parsing image" )
191+ input := source.Input {
192+ Scheme : source .ImageScheme ,
193+ ImageSource : imageSource ,
194+ Location : c .ImagePath ,
166195 }
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+
167206 return nil
168207}
169208
@@ -243,6 +282,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
243282 Ref : & ref ,
244283 ImagePath : imagePath ,
245284 copy : true ,
285+ remote : false ,
246286 cli : cli ,
247287 }, nil
248288 }
@@ -279,6 +319,7 @@ func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
279319 Ref : & ref ,
280320 ImagePath : imagePath ,
281321 copy : true ,
322+ remote : true ,
282323 cli : cli ,
283324 }, nil
284325}
0 commit comments