mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
* 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>
121 lines
2.3 KiB
Go
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,
|
|
})
|
|
}
|