github.com/anchore/syft@v1.38.2/syft/file/locations.go (about) 1 package file 2 3 import ( 4 "strings" 5 6 "github.com/anchore/syft/internal/evidence" 7 ) 8 9 var locationSorterWithoutLayers = LocationSorter(nil) 10 11 // Locations is a sortable slice of Location values. 12 type Locations []Location 13 14 func (l Locations) Len() int { 15 return len(l) 16 } 17 18 func (l Locations) Less(i, j int) bool { 19 return locationSorterWithoutLayers(l[i], l[j]) < 0 20 } 21 22 func (l Locations) Swap(i, j int) { 23 l[i], l[j] = l[j], l[i] 24 } 25 26 // LocationSorter creates a comparison function (slices.SortFunc) for Location objects based on layer order 27 func LocationSorter(layers []string) func(a, b Location) int { //nolint:gocognit 28 var layerOrderByDigest map[string]int 29 if len(layers) > 0 { 30 layerOrderByDigest = make(map[string]int) 31 for i, digest := range layers { 32 layerOrderByDigest[digest] = i 33 } 34 } 35 36 return func(a, b Location) int { 37 // compare by evidence annotations first... 38 aEvidence := a.Annotations[evidence.AnnotationKey] 39 bEvidence := b.Annotations[evidence.AnnotationKey] 40 41 if aEvidence != bEvidence { 42 if aEvidence == evidence.PrimaryAnnotation { 43 return -1 44 } 45 if bEvidence == evidence.PrimaryAnnotation { 46 return 1 47 } 48 49 if aEvidence > bEvidence { 50 return -1 51 } 52 if bEvidence > aEvidence { 53 return 1 54 } 55 } 56 57 // ...then by layer order 58 if layerOrderByDigest != nil { 59 // we're given layer order details 60 aLayerIdx, aExists := layerOrderByDigest[a.FileSystemID] 61 bLayerIdx, bExists := layerOrderByDigest[b.FileSystemID] 62 63 if aLayerIdx != bLayerIdx { 64 if !aExists && !bExists { 65 return strings.Compare(a.FileSystemID, b.FileSystemID) 66 } 67 if !aExists { 68 return 1 69 } 70 if !bExists { 71 return -1 72 } 73 74 return aLayerIdx - bLayerIdx 75 } 76 } else if a.FileSystemID != b.FileSystemID { 77 // no layer info given, legacy behavior is to sort lexicographically 78 return strings.Compare(a.FileSystemID, b.FileSystemID) 79 } 80 81 // ...then by paths 82 if a.AccessPath != b.AccessPath { 83 return strings.Compare(a.AccessPath, b.AccessPath) 84 } 85 86 return strings.Compare(a.RealPath, b.RealPath) 87 } 88 } 89 90 // CoordinatesSorter creates a comparison function (slices.SortFunc) for Coordinate objects based on layer order 91 func CoordinatesSorter(layers []string) func(a, b Coordinates) int { 92 var layerOrderByDigest map[string]int 93 if len(layers) > 0 { 94 layerOrderByDigest = make(map[string]int) 95 for i, digest := range layers { 96 layerOrderByDigest[digest] = i 97 } 98 } 99 100 return func(a, b Coordinates) int { 101 // ...then by layer order 102 if layerOrderByDigest != nil { 103 aLayerIdx, aExists := layerOrderByDigest[a.FileSystemID] 104 bLayerIdx, bExists := layerOrderByDigest[b.FileSystemID] 105 106 if aLayerIdx != bLayerIdx { 107 if !aExists && !bExists { 108 return strings.Compare(a.FileSystemID, b.FileSystemID) 109 } 110 if !aExists { 111 return 1 112 } 113 if !bExists { 114 return -1 115 } 116 117 return aLayerIdx - bLayerIdx 118 } 119 } 120 121 return strings.Compare(a.RealPath, b.RealPath) 122 } 123 }