github.com/anchore/syft@v1.38.2/syft/get_source.go (about) 1 package syft 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os" 8 "strings" 9 10 "github.com/anchore/syft/syft/source" 11 ) 12 13 // GetSource uses all of Syft's known source providers to attempt to resolve the user input to a usable source.Source 14 func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (source.Source, error) { 15 if cfg == nil { 16 cfg = DefaultGetSourceConfig() 17 } 18 19 providers, err := cfg.getProviders(userInput) 20 if err != nil { 21 return nil, err 22 } 23 24 var errs []error 25 var fileNotFoundProviders []string 26 27 // call each source provider until we find a valid source 28 for _, p := range providers { 29 src, err := p.Provide(ctx) 30 if err != nil { 31 if errors.Is(err, os.ErrNotExist) { 32 fileNotFoundProviders = append(fileNotFoundProviders, p.Name()) 33 } else { 34 errs = append(errs, fmt.Errorf("%s: %w", p.Name(), err)) 35 } 36 } 37 if err := validateSourcePlatform(src, cfg); err != nil { 38 return nil, err 39 } 40 if src != nil { 41 return src, nil 42 } 43 } 44 45 if len(errs) == 0 { 46 return nil, fmt.Errorf("no source providers were able to resolve the input %q", userInput) 47 } 48 49 if len(fileNotFoundProviders) > 0 { 50 errs = append(errs, fmt.Errorf("additionally, the following providers failed with %w: %s", os.ErrNotExist, strings.Join(fileNotFoundProviders, ", "))) 51 } 52 53 return nil, sourceError(userInput, errs...) 54 } 55 56 func validateSourcePlatform(src source.Source, cfg *GetSourceConfig) error { 57 if src == nil { 58 return nil 59 } 60 if cfg == nil || cfg.SourceProviderConfig == nil || cfg.SourceProviderConfig.Platform == nil { 61 return nil 62 } 63 64 meta := src.Describe().Metadata 65 switch meta.(type) { 66 case *source.ImageMetadata, source.ImageMetadata: 67 return nil 68 case *source.SnapMetadata, source.SnapMetadata: 69 return nil 70 default: 71 return fmt.Errorf("platform is not supported for this source type") 72 } 73 } 74 75 func sourceError(userInput string, errs ...error) error { 76 switch len(errs) { 77 case 0: 78 return nil 79 case 1: 80 return fmt.Errorf("an error occurred attempting to resolve '%s': %w", userInput, errs[0]) 81 } 82 errorTexts := "" 83 for _, e := range errs { 84 errorTexts += fmt.Sprintf("\n - %s", e) 85 } 86 return fmt.Errorf("errors occurred attempting to resolve '%s':%s", userInput, errorTexts) 87 }