8000 Order locations by container layer order by wagoodman · Pull Request #3858 · anchore/syft · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Order locations by container layer order #3858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion internal/cmptest/common_options.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package cmptest

import (
"strings"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"

"github.com/anchore/syft/internal/evidence"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
Expand All @@ -29,9 +32,41 @@ func BuildOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cm
cmpopts.IgnoreFields(pkg.Package{}, "id"), // note: ID is not deterministic for test purposes
cmpopts.SortSlices(pkg.Less),
cmpopts.SortSlices(DefaultRelationshipComparer),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](locationCmp)),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](locationCmp, locationSorter)),
cmp.Comparer(buildSetComparer[pkg.License, pkg.LicenseSet](licenseCmp)),
cmp.Comparer(locationCmp),
cmp.Comparer(licenseCmp),
}
}

// LocationSorter always sorts by evidence annotations first, then by access path, then by real path.
// This intentionally does not consider layer details since some test fixtures have no layer information
// on the left side of the comparison (expected) and does on the right side (actual).
func locationSorter(a, b file.Location) int {
// compare by evidence annotations first...
aEvidence := a.Annotations[evidence.AnnotationKey]
bEvidence := b.Annotations[evidence.AnnotationKey]

if aEvidence != bEvidence {
if aEvidence == evidence.PrimaryAnnotation {
return -1
}
if bEvidence == evidence.PrimaryAnnotation {
return 1
}

if aEvidence > bEvidence {
return -1
}
if bEvidence > aEvidence {
return 1
}
}

// ...then by paths
if a.AccessPath != b.AccessPath {
return strings.Compare(a.AccessPath, b.AccessPath)
}

return strings.Compare(a.RealPath, b.RealPath)
}
4 changes: 2 additions & 2 deletions internal/cmptest/license.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ func DefaultLicenseComparer(x, y pkg.License) bool {
return cmp.Equal(
x, y,
cmp.Comparer(DefaultLocationComparer),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](DefaultLocationComparer)),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](DefaultLocationComparer, locationSorter)),
)
}

func LicenseComparerWithoutLocationLayer(x, y pkg.License) bool {
return cmp.Equal(
x, y,
cmp.Comparer(LocationComparerWithoutLayer),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](LocationComparerWithoutLayer)),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](LocationComparerWithoutLayer, locationSorter)),
)
}
8 changes: 4 additions & 4 deletions internal/cmptest/set.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package cmptest

type slicer[T any] interface {
ToSlice() []T
ToSlice(sorter ...func(a, b T) int) []T
}

func buildSetComparer[T any, S slicer[T]](l func(x, y T) bool) func(x, y S) bool {
func buildSetComparer[T any, S slicer[T]](l func(x, y T) bool, sorters ...func(a, b T) int) func(x, y S) bool {
return func(x, y S) bool {
xs := x.ToSlice()
ys := y.ToSlice()
xs := x.ToSlice(sorters...)
ys := y.ToSlice(sorters...)

if len(xs) != len(ys) {
return false
Expand Down
35 changes: 28 additions & 7 deletions syft/file/coordinate_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,34 @@ func (s CoordinateSet) Paths() []string {
return pathSlice
}

func (s CoordinateSet) ToSlice() []Coordinates {
func (s CoordinateSet) ToSlice(sorters ...func(a, b Coordinates) int) []Coordinates {
coordinates := s.ToUnorderedSlice()

var sorted bool
for _, sorter := range sorters {
if sorter == nil {
continue
}
sort.Slice(coordinates, func(i, j int) bool {
return sorter(coordinates[i], coordinates[j]) < 0
})
sorted = true
break
}

if !sorted {
sort.SliceStable(coordinates, func(i, j int) bool {
if coordinates[i].FileSystemID == coordinates[j].FileSystemID {
return coordinates[i].RealPath < coordinates[j].RealPath
}
return coordinates[i].FileSystemID < coordinates[j].FileSystemID
})
}

return coordinates
}

func (s CoordinateSet) ToUnorderedSlice() []Coordinates {
if s.set == nil {
return nil
}
Expand All @@ -69,12 +96,6 @@ func (s CoordinateSet) ToSlice() []Coordinates {
coordinates[idx] = v
idx++
}
sort.SliceStable(coordinates, func(i, j int) bool {
if coordinates[i].RealPath == coordinates[j].RealPath {
return coordinates[i].FileSystemID < coordinates[j].FileSystemID
}
return coordinates[i].RealPath < coordinates[j].RealPath
})
return coordinates
}

Expand Down
25 changes: 23 additions & 2 deletions syft/file/location_set.go