syft/syft/file/location_set.go
Alex Goodman a77d24e379
Improve struct and field comments and incorporate into json schema (#4252)
* improve struct and field comments and incorporate into json schema

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* address review feedback

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-10-03 17:01:56 +00:00

121 lines
2.3 KiB
Go

package file
import (
"slices"
"sort"
"github.com/gohugoio/hashstructure"
"github.com/anchore/syft/internal/log"
)
// LocationSet provides a unique collection of Locations with metadata and set operations.
type LocationSet struct {
set map[LocationData]LocationMetadata
}
func NewLocationSet(locations ...Location) (s LocationSet) {
for _, l := range locations {
s.Add(l)
}
return s
}
func (s *LocationSet) Add(locations ...Location) {
if s.set == nil {
s.set = make(map[LocationData]LocationMetadata)
}
for _, l := range locations {
if m, ok := s.set[l.LocationData]; ok {
err := m.merge(l.LocationMetadata)
if err != nil {
log.Debugf("partial merge of location metadata: %+v", err)
}
s.set[l.LocationData] = m
} else {
s.set[l.LocationData] = l.LocationMetadata
}
}
}
func (s LocationSet) Remove(locations ...Location) {
if s.set == nil {
return
}
for _, l := range locations {
delete(s.set, l.LocationData)
}
}
func (s LocationSet) Contains(l Location) bool {
if s.set == nil {
return false
}
_, ok := s.set[l.LocationData]
return ok
}
func (s LocationSet) ToSlice(sorters ...func(a, b Location) int) []Location {
locations := s.ToUnorderedSlice()
var sorted bool
for _, sorter := range sorters {
if sorter == nil {
continue
}
slices.SortFunc(locations, sorter)
sorted = true
break
}
if !sorted {
// though no sorter was passed, we need to guarantee a stable ordering between calls
sort.Sort(Locations(locations))
}
return locations
}
func (s LocationSet) ToUnorderedSlice() []Location {
if s.set == nil {
return nil
}
locations := make([]Location, len(s.set))
idx := 0
for dir := range s.set {
locations[idx] = Location{
LocationData: dir,
LocationMetadata: s.set[dir],
}
idx++
}
return locations
}
func (s *LocationSet) CoordinateSet() CoordinateSet {
if s.set == nil {
return NewCoordinateSet()
}
set := NewCoordinateSet()
for l := range s.set {
set.Add(l.Coordinates)
}
return set
}
func (s *LocationSet) Empty() bool {
if s.set == nil {
return true
}
return len(s.set) == 0
}
func (s LocationSet) Hash() (uint64, error) {
// access paths and filesystem IDs are not considered when hashing a location set, only the real paths
return hashstructure.Hash(s.CoordinateSet().Paths(), &hashstructure.HashOptions{
ZeroNil: true,
SlicesAsSets: true,
})
}