github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/file/location_set.go (about)

     1  package file
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/mitchellh/hashstructure/v2"
     7  
     8  	"github.com/anchore/syft/internal/log"
     9  )
    10  
    11  type LocationSet struct {
    12  	set map[LocationData]LocationMetadata
    13  }
    14  
    15  func NewLocationSet(locations ...Location) (s LocationSet) {
    16  	for _, l := range locations {
    17  		s.Add(l)
    18  	}
    19  
    20  	return s
    21  }
    22  
    23  func (s *LocationSet) Add(locations ...Location) {
    24  	if s.set == nil {
    25  		s.set = make(map[LocationData]LocationMetadata)
    26  	}
    27  	for _, l := range locations {
    28  		if m, ok := s.set[l.LocationData]; ok {
    29  			err := m.merge(l.LocationMetadata)
    30  			if err != nil {
    31  				log.Debugf("partial merge of location metadata: %+v", err)
    32  			}
    33  			s.set[l.LocationData] = m
    34  		} else {
    35  			s.set[l.LocationData] = l.LocationMetadata
    36  		}
    37  	}
    38  }
    39  
    40  func (s LocationSet) Remove(locations ...Location) {
    41  	if s.set == nil {
    42  		return
    43  	}
    44  	for _, l := range locations {
    45  		delete(s.set, l.LocationData)
    46  	}
    47  }
    48  
    49  func (s LocationSet) Contains(l Location) bool {
    50  	if s.set == nil {
    51  		return false
    52  	}
    53  	_, ok := s.set[l.LocationData]
    54  	return ok
    55  }
    56  
    57  func (s LocationSet) ToSlice() []Location {
    58  	if s.set == nil {
    59  		return nil
    60  	}
    61  	locations := make([]Location, len(s.set))
    62  	idx := 0
    63  	for dir := range s.set {
    64  		locations[idx] = Location{
    65  			LocationData:     dir,
    66  			LocationMetadata: s.set[dir],
    67  		}
    68  		idx++
    69  	}
    70  	sort.Sort(Locations(locations))
    71  	return locations
    72  }
    73  
    74  func (s *LocationSet) CoordinateSet() CoordinateSet {
    75  	if s.set == nil {
    76  		return NewCoordinateSet()
    77  	}
    78  	set := NewCoordinateSet()
    79  	for l := range s.set {
    80  		set.Add(l.Coordinates)
    81  	}
    82  	return set
    83  }
    84  
    85  func (s *LocationSet) Empty() bool {
    86  	if s.set == nil {
    87  		return true
    88  	}
    89  	return len(s.set) == 0
    90  }
    91  
    92  func (s LocationSet) Hash() (uint64, error) {
    93  	// access paths and filesystem IDs are not considered when hashing a location set, only the real paths
    94  	return hashstructure.Hash(s.CoordinateSet().Paths(), hashstructure.FormatV2, &hashstructure.HashOptions{
    95  		ZeroNil:      true,
    96  		SlicesAsSets: true,
    97  	})
    98  }