@@ -2,6 +2,7 @@ package commands
22
33import (
44 "crypto/sha256"
5+ "errors"
56 "fmt"
67 "io"
78 "log/slog"
@@ -28,14 +29,14 @@ func calculateFileChecksum(path string) (string, error) {
2829 f , err := os .Open (path ) //#nosec G304
2930 if err != nil {
3031 slog .Error ("Failed to open file" , "path" , path , "err" , err )
31- return "" , err
32+ return "" , fmt . Errorf ( "cannot open %s: %w" , path , err )
3233 }
3334 defer handling .Close (f )
3435
3536 h := sha256 .New ()
3637 if _ , err := io .Copy (h , f ); err != nil {
3738 slog .Error ("Failed to copy file content" , "path" , path , "err" , err )
38- return "" , err
39+ return "" , fmt . Errorf ( "cannot read %s for checksum: %w" , path , err )
3940 }
4041
4142 return fmt .Sprintf ("%x" , h .Sum (nil )), nil
@@ -48,14 +49,14 @@ func downloadImage(path, url string) error {
4849 out , err := os .Create (path ) //#nosec G304
4950 if err != nil {
5051 slog .Error ("Cannot create image file" , "path" , path , "err" , err )
51- return err
52+ return fmt . Errorf ( "cannot create %s: %w" , path , err )
5253 }
5354 defer handling .Close (out )
5455
5556 resp , err := http .Get (url ) //#nosec G107
5657 if err != nil {
5758 slog .Error ("Cannot download image file" , "url" , url , "err" , err )
58- return err
59+ return fmt . Errorf ( "cannot download %s: %w" , url , err )
5960 }
6061 if resp == nil {
6162 return fmt .Errorf ("received nil response" )
@@ -64,7 +65,7 @@ func downloadImage(path, url string) error {
6465
6566 if resp .StatusCode != http .StatusOK {
6667 slog .Error ("Cannot download image file: bad status" , "status" , resp .Status )
67- return err
68+ return fmt . Errorf ( "cannot download %s: status %s" , url , resp . Status )
6869 }
6970
7071 bar := progressbar .DefaultBytes (
@@ -75,7 +76,7 @@ func downloadImage(path, url string) error {
7576 _ , err = io .Copy (io .MultiWriter (out , bar ), resp .Body )
7677 if err != nil {
7778 slog .Error ("Cannot write image file" , "path" , path , "err" , err )
78- return err
79+ return fmt . Errorf ( "cannot write %s: %w" , path , err )
7980 }
8081
8182 slog .Info ("Download successful" )
@@ -85,18 +86,19 @@ func downloadImage(path, url string) error {
8586func validateChecksum (localPath , checksum string ) error {
8687 newChecksum , err := calculateFileChecksum (localPath )
8788 if err != nil {
88- return err
89+ slog .Error ("Failed to calculate checksum for downloaded image" , "path" , localPath , "err" , err )
90+ return fmt .Errorf ("failed to calculate checksum for %s: %w" , localPath , err )
8991 }
9092
9193 if newChecksum != checksum {
92- err := os .Remove (localPath )
93- if err != nil {
94- slog .Error ("Downloaded image has bad checksum and cannot be removed" , "path" , localPath , "expected" , checksum , "actual" , newChecksum , "err" , err )
95- os . Exit ( 1 )
94+ removeErr := os .Remove (localPath )
95+ if removeErr != nil {
96+ slog .Error ("Downloaded image has bad checksum and cannot be removed" , "path" , localPath , "expected" , checksum , "actual" , newChecksum , "err" , removeErr )
97+ return fmt . Errorf ( "failed to remove image with bad checksum (expected %s, actual %s): %w" , checksum , newChecksum , removeErr )
9698 }
9799
98100 slog .Error ("Downloaded image has bad checksum and was removed" , "path" , localPath , "expected" , checksum , "actual" , newChecksum )
99- os . Exit ( 1 )
101+ return fmt . Errorf ( "detected bad checksum for downloaded image: expected %s, actual %s" , checksum , newChecksum )
100102 }
101103
102104 slog .Info ("Checksum validated successfully" )
@@ -105,47 +107,77 @@ func validateChecksum(localPath, checksum string) error {
105107
106108// Run is the function for the get command.
107109func (c * GetCommand ) Run (s * options.Options ) error {
108- image := images .GetImageDetails (s .Type )
109- info := image .GetDownloadInfo (true )
110+ image , err := images .GetImageDetails (s .Type )
111+ if err != nil {
112+ slog .Error ("Failed to get image details for get command" , "type" , s .Type , "err" , err )
113+ return fmt .Errorf ("cannot resolve image details for %q: %w" , s .Type , err )
114+ }
115+ info , err := image .GetDownloadInfo (true )
116+ if err != nil {
117+ slog .Error ("Failed to get download info for image" , "image" , image .DisplayName , "err" , err )
118+ return fmt .Errorf ("cannot fetch download info for %s: %w" , image .DisplayName , err )
119+ }
110120 if info == nil {
121+ slog .Error ("Download info is nil" , "image" , image .DisplayName )
111122 return fmt .Errorf ("failed to get download information" )
112123 }
113124
114125 slog .Info ("Found image to download" , "filename" , info .Filename , "checksum" , info .Checksum )
115126
116- localPath := image .GetLocalPath (info .Version )
127+ localPath , err := image .GetLocalPath (info .Version )
128+ if err != nil {
129+ slog .Error ("Failed to resolve local image path" , "image" , image .DisplayName , "version" , info .Version , "err" , err )
130+ return fmt .Errorf ("cannot resolve local path for %s %s: %w" , image .DisplayName , info .Version , err )
131+ }
117132
118- // https://stackoverflow.com/a/12518877
119- if _ , err := os .Stat (localPath ); err == nil {
120- // The image already exists.
133+ skipDownload , err := c .shouldSkipDownload (localPath , image , info )
134+ if err != nil {
135+ slog .Error ("Failed to determine if download should be skipped" , "path" , localPath , "err" , err )
136+ return fmt .Errorf ("cannot decide whether to download %s: %w" , localPath , err )
137+ }
138+ if skipDownload {
139+ return nil
140+ }
141+
142+ err = downloadImage (localPath , image .ArchiveURL + "/" + info .Filename )
143+ if err != nil {
144+ slog .Error ("Failed to download image" , "path" , localPath , "url" , image .ArchiveURL + "/" + info .Filename , "err" , err )
145+ return fmt .Errorf ("cannot download image %s/%s: %w" , image .ArchiveURL , info .Filename , err )
146+ }
121147
148+ err = validateChecksum (localPath , info .Checksum )
149+ if err != nil {
150+ slog .Error ("Checksum validation failed" , "path" , localPath , "err" , err )
151+ return fmt .Errorf ("failed to validate checksum for %s: %w" , localPath , err )
152+ }
153+
154+ slog .Info ("When using SELinux, label the image with the fix command before proceeding" )
155+
156+ return nil
157+ }
158+
159+ func (c * GetCommand ) shouldSkipDownload (localPath string , image images.Image , info * images.DownloadInfo ) (bool , error ) {
160+ // https://stackoverflow.com/a/12518877
161+ _ , err := os .Stat (localPath )
162+ if err == nil {
122163 if ! c .Update && ! c .Force {
123164 slog .Info ("An image is already installed; use --update to refresh" )
124- return nil
165+ return true , nil
125166 }
126167
127168 localVersion := image .FileVersion (localPath )
128169
129170 if ! c .Force && image .VersionComparer .Eq (info .Version , localVersion ) {
130171 slog .Info ("Latest image is already installed; use --force to overwrite" )
131- return nil
172+ return true , nil
132173 }
133- } else if ! os .IsNotExist (err ) {
134- slog .Error ("Unable to get file information" , "path" , localPath , "err" , err )
135- os .Exit (1 )
174+ return false , nil
136175 }
137176
138- err := downloadImage (localPath , image .ArchiveURL + "/" + info .Filename )
139- if err != nil {
140- return err
177+ if errors .Is (err , os .ErrNotExist ) {
178+ return false , nil
141179 }
142180
143- err = validateChecksum (localPath , info .Checksum )
144- if err != nil {
145- return err
146- }
147-
148- slog .Info ("When using SELinux, label the image with the fix command before proceeding" )
149-
150- return nil
181+ slog .Error ("Unable to get file information" , "path" , localPath , "err" , err )
182+ return false , fmt .Errorf ("cannot stat %s: %w" , localPath , err )
151183}
0 commit comments