github.com/kastenhq/syft@v0.0.0-20230821225854-0710af25cdbe/syft/internal/fileresolver/excluding_file.go (about)

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