Update java generic cataloger (#1329)

* remove centralize pURL generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* port java cataloger to new generic cataloger pattern

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove common.GenericCataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update format test fixtures to reflect ID updates

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix package sort instability for encode-decode-encode cycles

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2022-11-09 14:55:54 +00:00
committed by GitHub
parent f3528132a7
commit d7a51a69dd
51 changed files with 1871 additions and 894 deletions
+42 -21
View File
@@ -6,6 +6,7 @@ package pkg
import (
"fmt"
"sort"
"strings"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
@@ -21,11 +22,11 @@ type Package struct {
FoundBy string `hash:"ignore" cyclonedx:"foundBy"` // the specific cataloger that discovered this package
Locations source.LocationSet // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
Licenses []string // licenses discovered with the package metadata
Language Language `cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
Type Type `cyclonedx:"type"` // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
CPEs []CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
PURL string `hash:"ignore"` // the Package URL (see https://github.com/package-url/purl-spec)
MetadataType MetadataType `cyclonedx:"metadataType"` // the shape of the additional data in the "metadata" field
Language Language `hash:"ignore" cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
Type Type `cyclonedx:"type"` // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
CPEs []CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
PURL string `hash:"ignore"` // the Package URL (see https://github.com/package-url/purl-spec)
MetadataType MetadataType `cyclonedx:"metadataType"` // the shape of the additional data in the "metadata" field
Metadata interface{} // additional data found while parsing the package source
}
@@ -82,23 +83,43 @@ func IsValid(p *Package) bool {
return p != nil && p.Name != ""
}
//nolint:gocognit
func Less(i, j Package) bool {
if i.Name == j.Name {
if i.Version == j.Version {
iLocations := i.Locations.ToSlice()
jLocations := j.Locations.ToSlice()
if i.Type == j.Type {
maxLen := len(iLocations)
if len(jLocations) > maxLen {
maxLen = len(jLocations)
}
for l := 0; l < maxLen; l++ {
if len(iLocations) < l+1 || len(jLocations) < l+1 {
if len(iLocations) == len(jLocations) {
break
}
return len(iLocations) < len(jLocations)
}
if iLocations[l].RealPath == jLocations[l].RealPath {
continue
}
return iLocations[l].RealPath < jLocations[l].RealPath
}
// compare remaining metadata as a final fallback
// note: we cannot guarantee that IDs (which digests the metadata) are stable enough to sort on
// when there are potentially missing elements there is too much reduction in the dimensions to
// lean on ID comparison. The best fallback is to look at the string representation of the metadata.
return strings.Compare(fmt.Sprintf("%#v", i.Metadata), fmt.Sprintf("%#v", j.Metadata)) < 0
}
return i.Type < j.Type
}
return i.Version < j.Version
}
return i.Name < j.Name
}
func Sort(pkgs []Package) {
sort.SliceStable(pkgs, func(i, j int) bool {
if pkgs[i].Name == pkgs[j].Name {
if pkgs[i].Version == pkgs[j].Version {
iLocations := pkgs[i].Locations.ToSlice()
jLocations := pkgs[j].Locations.ToSlice()
if pkgs[i].Type == pkgs[j].Type && len(iLocations) > 0 && len(jLocations) > 0 {
if iLocations[0].String() == jLocations[0].String() {
// compare IDs as a final fallback
return pkgs[i].ID() < pkgs[j].ID()
}
return iLocations[0].String() < jLocations[0].String()
}
return pkgs[i].Type < pkgs[j].Type
}
return pkgs[i].Version < pkgs[j].Version
}
return pkgs[i].Name < pkgs[j].Name
return Less(pkgs[i], pkgs[j])
})
}