github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/file/location_set.go (about)

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