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  }