github.com/anchore/syft@v1.38.2/syft/internal/fileresolver/excluding_file.go (about) 1 package fileresolver 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/anchore/syft/syft/file" 9 ) 10 11 type excludeFn func(string) bool 12 13 // excluding decorates a resolver with an exclusion function that is used to 14 // filter out entries in the delegate resolver 15 type excluding struct { 16 delegate file.Resolver 17 excludeFn excludeFn 18 } 19 20 // NewExcludingDecorator create a new resolver which wraps the provided delegate and excludes 21 // entries based on a provided path exclusion function 22 func NewExcludingDecorator(delegate file.Resolver, excludeFn excludeFn) file.Resolver { 23 return &excluding{ 24 delegate, 25 excludeFn, 26 } 27 } 28 29 func (r *excluding) FileContentsByLocation(location file.Location) (io.ReadCloser, error) { 30 if locationMatches(&location, r.excludeFn) { 31 return nil, fmt.Errorf("no such location: %+v", location.RealPath) 32 } 33 return r.delegate.FileContentsByLocation(location) 34 } 35 36 func (r *excluding) FileMetadataByLocation(location file.Location) (file.Metadata, error) { 37 if locationMatches(&location, r.excludeFn) { 38 return file.Metadata{}, fmt.Errorf("no such location: %+v", location.RealPath) 39 } 40 return r.delegate.FileMetadataByLocation(location) 41 } 42 43 func (r *excluding) HasPath(path string) bool { 44 if r.excludeFn(path) { 45 return false 46 } 47 return r.delegate.HasPath(path) 48 } 49 50 func (r *excluding) FilesByPath(paths ...string) ([]file.Location, error) { 51 locations, err := r.delegate.FilesByPath(paths...) 52 return filterLocations(locations, err, r.excludeFn) 53 } 54 55 func (r *excluding) FilesByGlob(patterns ...string) ([]file.Location, error) { 56 locations, err := r.delegate.FilesByGlob(patterns...) 57 return filterLocations(locations, err, r.excludeFn) 58 } 59 60 func (r *excluding) FilesByMIMEType(types ...string) ([]file.Location, error) { 61 locations, err := r.delegate.FilesByMIMEType(types...) 62 return filterLocations(locations, err, r.excludeFn) 63 } 64 65 func (r *excluding) RelativeFileByPath(location file.Location, path string) *file.Location { 66 l := r.delegate.RelativeFileByPath(location, path) 67 if l != nil && locationMatches(l, r.excludeFn) { 68 return nil 69 } 70 return l 71 } 72 73 func (r *excluding) AllLocations(ctx context.Context) <-chan file.Location { 74 c := make(chan file.Location) 75 go func() { 76 defer close(c) 77 for location := range r.delegate.AllLocations(ctx) { 78 if !locationMatches(&location, r.excludeFn) { 79 select { 80 case <-ctx.Done(): 81 return 82 case c <- location: 83 continue 84 } 85 } 86 } 87 }() 88 return c 89 } 90 91 func locationMatches(location *file.Location, exclusionFn excludeFn) bool { 92 return exclusionFn(location.RealPath) || exclusionFn(location.AccessPath) 93 } 94 95 func filterLocations(locations []file.Location, err error, exclusionFn excludeFn) ([]file.Location, error) { 96 if err != nil { 97 return nil, err 98 } 99 if exclusionFn != nil { 100 for i := 0; i < len(locations); i++ { 101 location := &locations[i] 102 if locationMatches(location, exclusionFn) { 103 locations = append(locations[:i], locations[i+1:]...) 104 i-- 105 } 106 } 107 } 108 return locations, nil 109 }