Skip to content
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
2 changes: 1 addition & 1 deletion syft/formats/common/cyclonedxhelpers/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) {

s := &sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: pkg.NewCatalog(),
PackageCatalog: pkg.NewCollection(),
LinuxDistribution: linuxReleaseFromComponents(*bom.Components),
},
Source: extractComponents(bom.Metadata),
Expand Down
6 changes: 3 additions & 3 deletions syft/formats/common/spdxhelpers/to_format_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ func toSPDXID(identifiable artifact.Identifiable) spdx.ElementID {
return spdx.ElementID(id)
}

// packages populates all Package Information from the package Catalog (see https://spdx.github.io/spdx-spec/3-package-information/)
// packages populates all Package Information from the package Collection (see https://spdx.github.io/spdx-spec/3-package-information/)
//
//nolint:funlen
func toPackages(catalog *pkg.Catalog, sbom sbom.SBOM) (results []*spdx.Package) {
func toPackages(catalog *pkg.Collection, sbom sbom.SBOM) (results []*spdx.Package) {
for _, p := range catalog.Sorted() {
// name should be guaranteed to be unique, but semantically useful and stable
id := toSPDXID(p)
Expand Down Expand Up @@ -516,7 +516,7 @@ func toFileTypes(metadata *source.FileMetadata) (ty []string) {
return ty
}

func toOtherLicenses(catalog *pkg.Catalog) []*spdx.OtherLicense {
func toOtherLicenses(catalog *pkg.Collection) []*spdx.OtherLicense {
licenses := map[string]bool{}
for _, p := range catalog.Sorted() {
for _, license := range parseLicenses(p.Licenses) {
Expand Down
4 changes: 2 additions & 2 deletions syft/formats/common/spdxhelpers/to_format_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ func Test_H1Digest(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
catalog := pkg.NewCatalog(test.pkg)
catalog := pkg.NewCollection(test.pkg)
pkgs := toPackages(catalog, s)
require.Len(t, pkgs, 1)
for _, p := range pkgs {
Expand Down Expand Up @@ -494,7 +494,7 @@ func Test_OtherLicenses(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
catalog := pkg.NewCatalog(test.pkg)
catalog := pkg.NewCollection(test.pkg)
otherLicenses := toOtherLicenses(catalog)
require.Len(t, otherLicenses, len(test.expected))
require.Equal(t, test.expected, otherLicenses)
Expand Down
2 changes: 1 addition & 1 deletion syft/formats/common/spdxhelpers/to_syft_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func ToSyftModel(doc *spdx.Document) (*sbom.SBOM, error) {
s := &sbom.SBOM{
Source: src,
Artifacts: sbom.Artifacts{
PackageCatalog: pkg.NewCatalog(),
PackageCatalog: pkg.NewCollection(),
FileMetadata: map[source.Coordinates]source.FileMetadata{},
FileDigests: map[source.Coordinates][]file.Digest{},
LinuxDistribution: findLinuxReleaseByPURL(doc),
Expand Down
2 changes: 1 addition & 1 deletion syft/formats/github/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func Test_toGithubModel(t *testing.T) {
VersionID: "18.04",
IDLike: []string{"debian"},
},
PackageCatalog: pkg.NewCatalog(),
PackageCatalog: pkg.NewCollection(),
},
}
for _, p := range []pkg.Package{
Expand Down
12 changes: 6 additions & 6 deletions syft/formats/internal/testutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func AssertEncoderAgainstGoldenSnapshot(t *testing.T, format sbom.Format, sbom s

func ImageInput(t testing.TB, testImage string, options ...ImageOption) sbom.SBOM {
t.Helper()
catalog := pkg.NewCatalog()
catalog := pkg.NewCollection()
var cfg imageCfg
var img *image.Image
for _, opt := range options {
Expand Down Expand Up @@ -145,7 +145,7 @@ func carriageRedactor(s []byte) []byte {
return []byte(msg)
}

func populateImageCatalog(catalog *pkg.Catalog, img *image.Image) {
func populateImageCatalog(catalog *pkg.Collection, img *image.Image) {
_, ref1, _ := img.SquashedTree().File("/somefile-1.txt", filetree.FollowBasenameLinks)
_, ref2, _ := img.SquashedTree().File("/somefile-2.txt", filetree.FollowBasenameLinks)

Expand Down Expand Up @@ -252,8 +252,8 @@ func DirectoryInputWithAuthorField(t testing.TB) sbom.SBOM {
}
}

func newDirectoryCatalog() *pkg.Catalog {
catalog := pkg.NewCatalog()
func newDirectoryCatalog() *pkg.Collection {
catalog := pkg.NewCollection()

// populate catalog with test data
catalog.Add(pkg.Package{
Expand Down Expand Up @@ -303,8 +303,8 @@ func newDirectoryCatalog() *pkg.Catalog {
return catalog
}

func newDirectoryCatalogWithAuthorField() *pkg.Catalog {
catalog := pkg.NewCatalog()
func newDirectoryCatalogWithAuthorField() *pkg.Collection {
catalog := pkg.NewCollection()

// populate catalog with test data
catalog.Add(pkg.Package{
Expand Down
2 changes: 1 addition & 1 deletion syft/formats/spdxtagvalue/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestSPDXJSONSPDXIDs(t *testing.T) {
Format(),
sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: pkg.NewCatalog(pkgs...),
PackageCatalog: pkg.NewCollection(pkgs...),
},
Relationships: nil,
Source: source.Metadata{
Expand Down
2 changes: 1 addition & 1 deletion syft/formats/syftjson/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func schemaVersionRedactor(s []byte) []byte {
}

func TestEncodeFullJSONDocument(t *testing.T) {
catalog := pkg.NewCatalog()
catalog := pkg.NewCollection()

p1 := pkg.Package{
Name: "package-1",
Expand Down
2 changes: 1 addition & 1 deletion syft/formats/syftjson/to_format_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func toFileType(ty stereoscopeFile.Type) string {
}
}

func toPackageModels(catalog *pkg.Catalog) []model.Package {
func toPackageModels(catalog *pkg.Collection) []model.Package {
artifacts := make([]model.Package, 0)
if catalog == nil {
return artifacts
Expand Down
6 changes: 3 additions & 3 deletions syft/formats/syftjson/to_syft_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func toSyftLinuxRelease(d model.LinuxRelease) *linux.Release {
}
}

func toSyftRelationships(doc *model.Document, catalog *pkg.Catalog, relationships []model.Relationship, idAliases map[string]string) []artifact.Relationship {
func toSyftRelationships(doc *model.Document, catalog *pkg.Collection, relationships []model.Relationship, idAliases map[string]string) []artifact.Relationship {
idMap := make(map[string]interface{})

for _, p := range catalog.Sorted() {
Expand Down Expand Up @@ -256,8 +256,8 @@ func toSyftSourceData(s model.Source) *source.Metadata {
return nil
}

func toSyftCatalog(pkgs []model.Package, idAliases map[string]string) *pkg.Catalog {
catalog := pkg.NewCatalog()
func toSyftCatalog(pkgs []model.Package, idAliases map[string]string) *pkg.Collection {
catalog := pkg.NewCollection()
for _, p := range pkgs {
catalog.Add(toSyftPackage(p, idAliases))
}
Expand Down
4 changes: 2 additions & 2 deletions syft/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
// CatalogPackages takes an inventory of packages from the given image from a particular perspective
// (e.g. squashed source, all-layers source). Returns the discovered set of packages, the identified Linux
// distribution, and the source object used to wrap the data source.
func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []artifact.Relationship, *linux.Release, error) {
func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Collection, []artifact.Relationship, *linux.Release, error) {
resolver, err := src.FileResolver(cfg.Search.Scope)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to determine resolver while cataloging packages: %w", err)
Expand Down Expand Up @@ -76,7 +76,7 @@ func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []
return catalog, relationships, release, err
}

func newSourceRelationshipsFromCatalog(src *source.Source, c *pkg.Catalog) []artifact.Relationship {
func newSourceRelationshipsFromCatalog(src *source.Source, c *pkg.Collection) []artifact.Relationship {
relationships := make([]artifact.Relationship, 0) // Should we pre-allocate this by giving catalog a Len() method?
for p := range c.Enumerate() {
relationships = append(relationships, artifact.Relationship{
Expand Down
96 changes: 48 additions & 48 deletions syft/pkg/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,18 @@ import (
"github.com/anchore/syft/syft/artifact"
)

type orderedIDSet struct {
slice []artifact.ID
}

func (s *orderedIDSet) add(ids ...artifact.ID) {
loopNewIDs:
for _, newID := range ids {
for _, existingID := range s.slice {
if existingID == newID {
continue loopNewIDs
}
}
s.slice = append(s.slice, newID)
}
}

func (s *orderedIDSet) delete(id artifact.ID) {
for i, existingID := range s.slice {
if existingID == id {
s.slice = append(s.slice[:i], s.slice[i+1:]...)
return
}
}
}

// Catalog represents a collection of Packages.
type Catalog struct {
// Collection represents a collection of Packages.
type Collection struct {
byID map[artifact.ID]Package
idsByName map[string]orderedIDSet
idsByType map[Type]orderedIDSet
idsByPath map[string]orderedIDSet // note: this is real path or virtual path
lock sync.RWMutex
}

// NewCatalog returns a new empty Catalog
func NewCatalog(pkgs ...Package) *Catalog {
catalog := Catalog{
// NewCollection returns a new empty Collection
func NewCollection(pkgs ...Package) *Collection {
catalog := Collection{
byID: make(map[artifact.ID]Package),
idsByName: make(map[string]orderedIDSet),
idsByType: make(map[Type]orderedIDSet),
Expand All @@ -61,12 +36,12 @@ func NewCatalog(pkgs ...Package) *Catalog {
}

// PackageCount returns the total number of packages that have been added.
func (c *Catalog) PackageCount() int {
func (c *Collection) PackageCount() int {
return len(c.byID)
}

// Package returns the package with the given ID.
func (c *Catalog) Package(id artifact.ID) *Package {
func (c *Collection) Package(id artifact.ID) *Package {
v, exists := c.byID[id]
if !exists {
return nil
Expand All @@ -81,17 +56,17 @@ func (c *Catalog) Package(id artifact.ID) *Package {
}

// PackagesByPath returns all packages that were discovered from the given path.
func (c *Catalog) PackagesByPath(path string) []Package {
func (c *Collection) PackagesByPath(path string) []Package {
return c.Packages(c.idsByPath[path].slice)
}

// PackagesByName returns all packages that were discovered with a matching name.
func (c *Catalog) PackagesByName(name string) []Package {
func (c *Collection) PackagesByName(name string) []Package {
return c.Packages(c.idsByName[name].slice)
}

// Packages returns all packages for the given ID.
func (c *Catalog) Packages(ids []artifact.ID) (result []Package) {
func (c *Collection) Packages(ids []artifact.ID) (result []Package) {
for _, i := range ids {
p, exists := c.byID[i]
if exists {
Expand All @@ -102,7 +77,7 @@ func (c *Catalog) Packages(ids []artifact.ID) (result []Package) {
}

// Add n packages to the catalog.
func (c *Catalog) Add(pkgs ...Package) {
func (c *Collection) Add(pkgs ...Package) {
c.lock.Lock()
defer c.lock.Unlock()

Expand All @@ -129,26 +104,26 @@ func (c *Catalog) Add(pkgs ...Package) {
}
}

func (c *Catalog) addToIndex(p Package) {
func (c *Collection) addToIndex(p Package) {
c.byID[p.id] = p
c.addNameToIndex(p)
c.addTypeToIndex(p)
c.addPathsToIndex(p)
}

func (c *Catalog) addNameToIndex(p Package) {
func (c *Collection) addNameToIndex(p Package) {
nameIndex := c.idsByName[p.Name]
nameIndex.add(p.id)
c.idsByName[p.Name] = nameIndex
}

func (c *Catalog) addTypeToIndex(p Package) {
func (c *Collection) addTypeToIndex(p Package) {
typeIndex := c.idsByType[p.Type]
typeIndex.add(p.id)
c.idsByType[p.Type] = typeIndex
}

func (c *Catalog) addPathsToIndex(p Package) {
func (c *Collection) addPathsToIndex(p Package) {
observedPaths := internal.NewStringSet()
for _, l := range p.Locations.ToSlice() {
if l.RealPath != "" && !observedPaths.Contains(l.RealPath) {
Expand All @@ -162,13 +137,13 @@ func (c *Catalog) addPathsToIndex(p Package) {
}
}

func (c *Catalog) addPathToIndex(id artifact.ID, path string) {
func (c *Collection) addPathToIndex(id artifact.ID, path string) {
pathIndex := c.idsByPath[path]
pathIndex.add(id)
c.idsByPath[path] = pathIndex
}

func (c *Catalog) Delete(ids ...artifact.ID) {
func (c *Collection) Delete(ids ...artifact.ID) {
c.lock.Lock()
defer c.lock.Unlock()

Expand All @@ -185,19 +160,19 @@ func (c *Catalog) Delete(ids ...artifact.ID) {
}
}

func (c *Catalog) deleteNameFromIndex(p Package) {
func (c *Collection) deleteNameFromIndex(p Package) {
nameIndex := c.idsByName[p.Name]
nameIndex.delete(p.id)
c.idsByName[p.Name] = nameIndex
}

func (c *Catalog) deleteTypeFromIndex(p Package) {
func (c *Collection) deleteTypeFromIndex(p Package) {
typeIndex := c.idsByType[p.Type]
typeIndex.delete(p.id)
c.idsByType[p.Type] = typeIndex
}

func (c *Catalog) deletePathsFromIndex(p Package) {
func (c *Collection) deletePathsFromIndex(p Package) {
observedPaths := internal.NewStringSet()
for _, l := range p.Locations.ToSlice() {
if l.RealPath != "" && !observedPaths.Contains(l.RealPath) {
Expand All @@ -211,7 +186,7 @@ func (c *Catalog) deletePathsFromIndex(p Package) {
}
}

func (c *Catalog) deletePathFromIndex(id artifact.ID, path string) {
func (c *Collection) deletePathFromIndex(id artifact.ID, path string) {
pathIndex := c.idsByPath[path]
pathIndex.delete(id)
if len(pathIndex.slice) == 0 {
Expand All @@ -222,7 +197,7 @@ func (c *Catalog) deletePathFromIndex(id artifact.ID, path string) {
}

// Enumerate all packages for the given type(s), enumerating all packages if no type is specified.
func (c *Catalog) Enumerate(types ...Type) <-chan Package {
func (c *Collection) Enumerate(types ...Type) <-chan Package {
channel := make(chan Package)
go func() {
defer close(channel)
Expand Down Expand Up @@ -257,7 +232,7 @@ func (c *Catalog) Enumerate(types ...Type) <-chan Package {

// Sorted enumerates all packages for the given types sorted by package name. Enumerates all packages if no type
// is specified.
func (c *Catalog) Sorted(types ...Type) (pkgs []Package) {
func (c *Collection) Sorted(types ...Type) (pkgs []Package) {
for p := range c.Enumerate(types...) {
pkgs = append(pkgs, p)
}
Expand All @@ -266,3 +241,28 @@ func (c *Catalog) Sorted(types ...Type) (pkgs []Package) {

return pkgs
}

type orderedIDSet struct {
slice []artifact.ID
}

func (s *orderedIDSet) add(ids ...artifact.ID) {
loopNewIDs:
for _, newID := range ids {
for _, existingID := range s.slice {
if existingID == newID {
continue loopNewIDs
}
}
s.slice = append(s.slice, newID)
}
}

func (s *orderedIDSet) delete(id artifact.ID) {
for i, existingID := range s.slice {
if existingID == id {
s.slice = append(s.slice[:i], s.slice[i+1:]...)
return
}
}
}
Loading