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 }