mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 06:26:30 +01:00
rename to syft
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
// TODO: add reader methods (by type, id, fuzzy search, etc)
|
||||
|
||||
var nextPackageID int64
|
||||
|
||||
type Catalog struct {
|
||||
byID map[ID]*Package
|
||||
byType map[Type][]*Package
|
||||
byFile map[file.Reference][]*Package
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewCatalog() *Catalog {
|
||||
return &Catalog{
|
||||
byID: make(map[ID]*Package),
|
||||
byType: make(map[Type][]*Package),
|
||||
byFile: make(map[file.Reference][]*Package),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Catalog) PackageCount() int {
|
||||
return len(c.byID)
|
||||
}
|
||||
|
||||
func (c *Catalog) Package(id ID) *Package {
|
||||
return c.byID[id]
|
||||
}
|
||||
|
||||
func (c *Catalog) PackagesByFile(ref file.Reference) []*Package {
|
||||
return c.byFile[ref]
|
||||
}
|
||||
|
||||
func (c *Catalog) Add(p Package) {
|
||||
if p.id != 0 {
|
||||
log.Errorf("package already added to catalog: %s", p)
|
||||
return
|
||||
}
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
p.id = ID(nextPackageID)
|
||||
nextPackageID++
|
||||
|
||||
// store by package ID
|
||||
c.byID[p.id] = &p
|
||||
|
||||
// store by package type
|
||||
_, ok := c.byType[p.Type]
|
||||
if !ok {
|
||||
c.byType[p.Type] = make([]*Package, 0)
|
||||
}
|
||||
c.byType[p.Type] = append(c.byType[p.Type], &p)
|
||||
|
||||
// store by file references
|
||||
for _, s := range p.Source {
|
||||
_, ok := c.byFile[s]
|
||||
if !ok {
|
||||
c.byFile[s] = make([]*Package, 0)
|
||||
}
|
||||
c.byFile[s] = append(c.byFile[s], &p)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Catalog) Enumerate(types ...Type) <-chan *Package {
|
||||
channel := make(chan *Package)
|
||||
go func() {
|
||||
defer close(channel)
|
||||
for ty, packages := range c.byType {
|
||||
if len(types) != 0 {
|
||||
found := false
|
||||
typeCheck:
|
||||
for _, t := range types {
|
||||
if t == ty {
|
||||
found = true
|
||||
break typeCheck
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, p := range packages {
|
||||
channel <- p
|
||||
}
|
||||
}
|
||||
}()
|
||||
return channel
|
||||
}
|
||||
|
||||
func (c *Catalog) Sorted(types ...Type) []*Package {
|
||||
pkgs := make([]*Package, 0)
|
||||
for p := range c.Enumerate(types...) {
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
|
||||
sort.SliceStable(pkgs, func(i, j int) bool {
|
||||
if pkgs[i].Name == pkgs[j].Name {
|
||||
return pkgs[i].Version < pkgs[j].Version
|
||||
}
|
||||
return pkgs[i].Name < pkgs[j].Name
|
||||
})
|
||||
|
||||
return pkgs
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package pkg
|
||||
|
||||
const (
|
||||
UnknownLanguage Language = iota
|
||||
Java
|
||||
JavaScript
|
||||
Python
|
||||
Ruby
|
||||
Go
|
||||
)
|
||||
|
||||
type Language uint
|
||||
|
||||
var languageStr = []string{
|
||||
"UnknownLanguage",
|
||||
"java",
|
||||
"javascript",
|
||||
"python",
|
||||
"ruby",
|
||||
"go",
|
||||
}
|
||||
|
||||
var AllLanguages = []Language{
|
||||
Java,
|
||||
JavaScript,
|
||||
Python,
|
||||
Ruby,
|
||||
Go,
|
||||
}
|
||||
|
||||
func (t Language) String() string {
|
||||
if int(t) >= len(languageStr) {
|
||||
return languageStr[0]
|
||||
}
|
||||
return languageStr[t]
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package pkg
|
||||
|
||||
// TODO: consider keeping the remaining values as an embedded map
|
||||
// Available fields are described at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html
|
||||
// in the --showformat section
|
||||
type DpkgMetadata struct {
|
||||
Package string `mapstructure:"Package"`
|
||||
Source string `mapstructure:"Source"`
|
||||
Version string `mapstructure:"Version"`
|
||||
}
|
||||
|
||||
type RpmMetadata struct {
|
||||
Epoch int `mapstructure:"Epoch"`
|
||||
Arch string `mapstructure:"Arch"`
|
||||
Release string `mapstructure:"Release"`
|
||||
}
|
||||
|
||||
type JavaManifest struct {
|
||||
Name string `mapstructure:"Name"`
|
||||
ManifestVersion string `mapstructure:"Manifest-Version"`
|
||||
SpecTitle string `mapstructure:"Specification-Title"`
|
||||
SpecVersion string `mapstructure:"Specification-Version"`
|
||||
SpecVendor string `mapstructure:"Specification-Vendor"`
|
||||
ImplTitle string `mapstructure:"Implementation-Title"`
|
||||
ImplVersion string `mapstructure:"Implementation-Version"`
|
||||
ImplVendor string `mapstructure:"Implementation-Vendor"`
|
||||
Extra map[string]string `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type PomProperties struct {
|
||||
Path string
|
||||
Name string `mapstructure:"name"`
|
||||
GroupID string `mapstructure:"groupId"`
|
||||
ArtifactID string `mapstructure:"artifactId"`
|
||||
Version string `mapstructure:"version"`
|
||||
Extra map[string]string `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type JavaMetadata struct {
|
||||
Manifest *JavaManifest `mapstructure:"Manifest"`
|
||||
PomProperties *PomProperties `mapstructure:"PomProperties"`
|
||||
Parent *Package
|
||||
}
|
||||
|
||||
// source: https://wiki.alpinelinux.org/wiki/Apk_spec
|
||||
type ApkMetadata struct {
|
||||
Package string `mapstructure:"P"`
|
||||
OriginPackage string `mapstructure:"o"`
|
||||
Maintainer string `mapstructure:"m"`
|
||||
Version string `mapstructure:"V"`
|
||||
License string `mapstructure:"L"`
|
||||
Architecture string `mapstructure:"A"`
|
||||
URL string `mapstructure:"U"`
|
||||
Description string `mapstructure:"T"`
|
||||
Size int `mapstructure:"S"`
|
||||
InstalledSize int `mapstructure:"I"`
|
||||
PullDependencies string `mapstructure:"D"`
|
||||
PullChecksum string `mapstructure:"C"`
|
||||
GitCommitOfAport string `mapstructure:"c"`
|
||||
Files []string
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
type ID int64
|
||||
|
||||
// TODO: add field to trace which cataloger detected this
|
||||
|
||||
// Package represents an application or library that has been bundled into a distributable format
|
||||
type Package struct {
|
||||
id ID // this is set when a package is added to the catalog
|
||||
Name string
|
||||
Version string
|
||||
FoundBy string
|
||||
Source []file.Reference
|
||||
Licenses []string
|
||||
Language Language // TODO: should this support multiple languages as a slice?
|
||||
Type Type
|
||||
Metadata interface{}
|
||||
}
|
||||
|
||||
func (p Package) ID() ID {
|
||||
return p.id
|
||||
}
|
||||
|
||||
func (p Package) String() string {
|
||||
return fmt.Sprintf("Pkg(type=%s, name=%s, version=%s)", p.Type, p.Name, p.Version)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package pkg
|
||||
|
||||
const (
|
||||
UnknownPkg Type = iota
|
||||
ApkPkg
|
||||
BundlerPkg
|
||||
DebPkg
|
||||
EggPkg
|
||||
//PacmanPkg
|
||||
RpmPkg
|
||||
WheelPkg
|
||||
NpmPkg
|
||||
PythonRequirementsPkg
|
||||
JavaPkg
|
||||
JenkinsPluginPkg
|
||||
GoModulePkg
|
||||
)
|
||||
|
||||
type Type uint
|
||||
|
||||
var typeStr = []string{
|
||||
"UnknownPackage",
|
||||
"apk",
|
||||
"bundle",
|
||||
"deb",
|
||||
"egg",
|
||||
//"pacman",
|
||||
"rpm",
|
||||
"wheel",
|
||||
"npm",
|
||||
"python-requirements",
|
||||
"java-archive",
|
||||
"jenkins-plugin",
|
||||
"go-module",
|
||||
}
|
||||
|
||||
var AllPkgs = []Type{
|
||||
ApkPkg,
|
||||
BundlerPkg,
|
||||
DebPkg,
|
||||
EggPkg,
|
||||
//PacmanPkg,
|
||||
RpmPkg,
|
||||
WheelPkg,
|
||||
NpmPkg,
|
||||
PythonRequirementsPkg,
|
||||
JavaPkg,
|
||||
JenkinsPluginPkg,
|
||||
GoModulePkg,
|
||||
}
|
||||
|
||||
func (t Type) String() string {
|
||||
if int(t) >= len(typeStr) {
|
||||
return typeStr[0]
|
||||
}
|
||||
return typeStr[t]
|
||||
}
|
||||
Reference in New Issue
Block a user