287 - Add retry for image fetch using user's input (#626)

* add fallback to user input if source hint fails

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* refactor for smaller functions

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
This commit is contained in:
Christopher Angelo Phillips 2021-11-12 17:57:04 -05:00 committed by GitHub
parent e732f419f8
commit fc39710d06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -11,6 +11,7 @@ import (
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/internal/log"
"github.com/spf13/afero"
)
@ -35,55 +36,75 @@ func New(userInput string, registryOptions *image.RegistryOptions) (*Source, fun
switch parsedScheme {
case FileScheme:
fileMeta, err := fs.Stat(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err)
}
if fileMeta.IsDir() {
return &Source{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
}
s, err := NewFromFile(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("could not populate source from path=%q: %w", location, err)
}
return &s, func() {}, nil
return generateFileSource(fs, location)
case DirectoryScheme:
fileMeta, err := fs.Stat(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err)
}
if !fileMeta.IsDir() {
return &Source{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
}
s, err := NewFromDirectory(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("could not populate source from path=%q: %w", location, err)
}
return &s, func() {}, nil
return generateDirectorySource(fs, location)
case ImageScheme:
img, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions)
cleanup := stereoscope.Cleanup
if err != nil || img == nil {
return &Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
}
s, err := NewFromImage(img, location)
if err != nil {
return &Source{}, cleanup, fmt.Errorf("could not populate source with image: %w", err)
}
return &s, cleanup, nil
return generateImageSource(location, userInput, imageSource, registryOptions)
}
return &Source{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
}
func generateImageSource(location, userInput string, imageSource image.Source, registryOptions *image.RegistryOptions) (*Source, func(), error) {
img, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions)
if err != nil {
log.Debugf("error parsing location: %s after detecting scheme; pulling image: %s", location, userInput)
// we may have been to aggressive reading the source hint
// try the input as supplied by the user if our initial parse failed
img, err = stereoscope.GetImageFromSource(userInput, imageSource, registryOptions)
}
cleanup := stereoscope.Cleanup
if err != nil || img == nil {
return &Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
}
s, err := NewFromImage(img, location)
if err != nil {
return &Source{}, cleanup, fmt.Errorf("could not populate source with image: %w", err)
}
return &s, cleanup, nil
}
func generateDirectorySource(fs afero.Fs, location string) (*Source, func(), error) {
fileMeta, err := fs.Stat(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err)
}
if !fileMeta.IsDir() {
return &Source{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
}
s, err := NewFromDirectory(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("could not populate source from path=%q: %w", location, err)
}
return &s, func() {}, nil
}
func generateFileSource(fs afero.Fs, location string) (*Source, func(), error) {
fileMeta, err := fs.Stat(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err)
}
if fileMeta.IsDir() {
return &Source{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
}
s, err := NewFromFile(location)
if err != nil {
return &Source{}, func() {}, fmt.Errorf("could not populate source from path=%q: %w", location, err)
}
return &s, func() {}, nil
}
// NewFromDirectory creates a new source object tailored to catalog a given filesystem directory recursively.
func NewFromDirectory(path string) (Source, error) {
return Source{