github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/internal/licenses/find_licenses.go (about)

     1  package licenses
     2  
     3  import (
     4  	"context"
     5  	"path"
     6  
     7  	"github.com/anchore/syft/internal"
     8  	"github.com/anchore/syft/internal/log"
     9  	"github.com/anchore/syft/syft/file"
    10  	"github.com/anchore/syft/syft/pkg"
    11  )
    12  
    13  // RelativeToPackage searches for licenses in the same directory as primary evidence locations
    14  // on the package and returns the package with licenses set and ID reset if the package has no licenses already
    15  func RelativeToPackage(ctx context.Context, resolver file.Resolver, p pkg.Package) pkg.Package {
    16  	// if licenses were already found, don't search for more
    17  	if !p.Licenses.Empty() {
    18  		return p
    19  	}
    20  	var out []pkg.License
    21  	for _, l := range p.Locations.ToUnorderedSlice() {
    22  		if evidenceType, ok := l.Annotations[pkg.EvidenceAnnotationKey]; ok && evidenceType != pkg.PrimaryEvidenceAnnotation {
    23  			continue
    24  		}
    25  		// search for license files relative to any primary evidence on the package
    26  		out = append(out, FindRelativeToLocations(ctx, resolver, l)...)
    27  	}
    28  	if len(out) > 0 {
    29  		p.Licenses = pkg.NewLicenseSet(out...)
    30  		p.SetID()
    31  	}
    32  	return p
    33  }
    34  
    35  // FindAtLocations creates License objects by reading license files directly the provided locations
    36  func FindAtLocations(ctx context.Context, resolver file.Resolver, locations ...file.Location) []pkg.License {
    37  	var out []pkg.License
    38  	for _, loc := range locations {
    39  		out = append(out, readFromResolver(ctx, resolver, loc)...)
    40  	}
    41  	return out
    42  }
    43  
    44  // FindAtPaths creates License objects by reading license files directly at the provided paths
    45  func FindAtPaths(ctx context.Context, resolver file.Resolver, paths ...string) []pkg.License {
    46  	var out []pkg.License
    47  	for _, p := range paths {
    48  		locs, err := resolver.FilesByPath(p)
    49  		if err != nil {
    50  			log.WithFields("error", err, "path", p).Trace("unable to resolve license path")
    51  			continue
    52  		}
    53  		for _, loc := range locs {
    54  			out = append(out, readFromResolver(ctx, resolver, loc)...)
    55  		}
    56  	}
    57  	return out
    58  }
    59  
    60  // FindInDirs creates License objects by searching for known license files in the provided directories
    61  func FindInDirs(ctx context.Context, resolver file.Resolver, dirs ...string) []pkg.License {
    62  	var out []pkg.License
    63  	for _, dir := range dirs {
    64  		glob := path.Join(dir, "*") // only search in the directory
    65  		out = append(out, FindByGlob(ctx, resolver, glob)...)
    66  	}
    67  	return out
    68  }
    69  
    70  // FindRelativeToLocations creates License objects by searching for known license files relative to the provided locations, in the same directory path
    71  func FindRelativeToLocations(ctx context.Context, resolver file.Resolver, locations ...file.Location) []pkg.License {
    72  	var out []pkg.License
    73  	for _, location := range locations {
    74  		dir := path.Dir(location.AccessPath)
    75  		out = append(out, FindInDirs(ctx, resolver, dir)...)
    76  	}
    77  	return out
    78  }
    79  
    80  // FindByGlob creates License objects by searching for license files with the provided glob.
    81  // only file names which match licenses.LowerFileNames() case-insensitive will be included,
    82  // so a recursive glob search such as: `<path>/**/*` will only attempt to read LICENSE files it finds, for example
    83  func FindByGlob(ctx context.Context, resolver file.Resolver, glob string) []pkg.License {
    84  	locs, err := resolver.FilesByGlob(glob)
    85  	if err != nil {
    86  		log.WithFields("glob", glob, "error", err).Debug("error searching for license files")
    87  		return nil
    88  	}
    89  	var out []pkg.License
    90  	for _, l := range locs {
    91  		fileName := path.Base(l.Path())
    92  		if IsLicenseFile(fileName) {
    93  			out = append(out, readFromResolver(ctx, resolver, l)...)
    94  		}
    95  	}
    96  	return out
    97  }
    98  
    99  func NewFromValues(ctx context.Context, locations []file.Location, values ...string) []pkg.License {
   100  	if len(locations) == 0 {
   101  		return pkg.NewLicensesFromValuesWithContext(ctx, values...)
   102  	}
   103  
   104  	var out []pkg.License
   105  	for _, value := range values {
   106  		if value == "" {
   107  			continue
   108  		}
   109  		out = append(out, pkg.NewLicenseFromLocationsWithContext(ctx, value, locations...))
   110  	}
   111  
   112  	return out
   113  }
   114  
   115  func readFromResolver(ctx context.Context, resolver file.Resolver, location file.Location) []pkg.License {
   116  	metadataContents, err := resolver.FileContentsByLocation(location)
   117  	if err != nil || metadataContents == nil {
   118  		log.WithFields("error", err, "path", location.Path()).Trace("unable to license file contents")
   119  		return nil
   120  	}
   121  	defer internal.CloseAndLogError(metadataContents, location.Path())
   122  	return pkg.NewLicensesFromReadCloserWithContext(ctx, file.NewLocationReadCloser(location, metadataContents))
   123  }