mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
finish repository + make syft client
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
c231a9d7cb
commit
54e0ee4c47
12
cmd/root.go
12
cmd/root.go
@ -68,7 +68,17 @@ func startWorker(userInput string) <-chan error {
|
||||
}
|
||||
}
|
||||
|
||||
catalog, scope, distro, err := syft.Catalog(userInput, appConfig.ScopeOpt)
|
||||
config := syft.Config{
|
||||
PluginDirectory: appConfig.Plugins.Directory,
|
||||
}
|
||||
|
||||
client, err := syft.NewClient(config)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("could not initialize syft: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
catalog, scope, distro, err := client.Catalog(userInput, appConfig.ScopeOpt)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("failed to catalog input: %+v", err)
|
||||
return
|
||||
|
||||
@ -34,6 +34,7 @@ type Cataloger interface {
|
||||
// TODO: add "IterationNeeded" error to indicate to the driver to continue with another Select/Catalog pass
|
||||
}
|
||||
|
||||
// All returns a slice of all locally defined catalogers (defined in child packages).
|
||||
func BuiltIn() []Cataloger {
|
||||
return []Cataloger{
|
||||
dpkg.New(),
|
||||
@ -46,8 +47,3 @@ func BuiltIn() []Cataloger {
|
||||
javascript.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// All returns a slice of all locally defined catalogers (defined in child packages).
|
||||
func All() []Cataloger {
|
||||
return BuiltIn()
|
||||
}
|
||||
|
||||
@ -10,13 +10,35 @@ import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/plugin"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
PluginDirectory string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
config Config
|
||||
plugins *plugin.Repository
|
||||
}
|
||||
|
||||
func NewClient(config Config) (Client, error) {
|
||||
plugins, err := plugin.NewRepositoryFromDirectory(config.PluginDirectory)
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
return Client{
|
||||
config: config,
|
||||
plugins: plugins,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Catalog the given image from a particular perspective (e.g. squashed scope, all-layers scope). Returns the discovered
|
||||
// set of packages, the identified Linux distribution, and the scope object used to wrap the data source.
|
||||
func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
func (c *Client) Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
log.Info("cataloging image")
|
||||
s, cleanup, err := scope.NewScope(userInput, scoptOpt)
|
||||
defer cleanup()
|
||||
@ -24,9 +46,9 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
d := IdentifyDistro(s)
|
||||
d := c.IdentifyDistro(s)
|
||||
|
||||
catalog, err := CatalogFromScope(s)
|
||||
catalog, err := c.CatalogFromScope(s)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@ -36,7 +58,7 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
|
||||
|
||||
// IdentifyDistro attempts to discover what the underlying Linux distribution may be from the available flat files
|
||||
// provided by the given scope object. If results are inconclusive a "UnknownDistro" Type is returned.
|
||||
func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
func (c *Client) IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
d := distro.Identify(s.Resolver)
|
||||
if d.Type != distro.UnknownDistroType {
|
||||
log.Infof("identified distro: %s", d.String())
|
||||
@ -47,9 +69,15 @@ func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
}
|
||||
|
||||
// Catalog the given scope, which may represent a container image or filesystem. Returns the discovered set of packages.
|
||||
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
func (c *Client) CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
log.Info("building the catalog")
|
||||
return cataloger.Catalog(s.Resolver, cataloger.All()...)
|
||||
pluginCatalogers, deactivatePluginsFn, err := c.plugins.ActivateCatalogers()
|
||||
defer deactivatePluginsFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cataloger.Catalog(s.Resolver, append(pluginCatalogers, cataloger.BuiltIn()...)...)
|
||||
}
|
||||
|
||||
// SetLogger sets the logger object used for all syft logging calls.
|
||||
@ -14,9 +14,7 @@ import (
|
||||
var _ plugin.GRPCPlugin = &CatalogerPlugin{}
|
||||
|
||||
// Cataloger is the interface exposed as a plugin.
|
||||
type Cataloger interface {
|
||||
cataloger.Cataloger
|
||||
}
|
||||
type Cataloger cataloger.Cataloger
|
||||
|
||||
// CatalogerPlugin is the implementation of plugin.Plugin that is served/consumed.
|
||||
type CatalogerPlugin struct {
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
package plugin
|
||||
|
||||
// repository
|
||||
type Collection struct {
|
||||
byType map[Type]Plugin
|
||||
byName map[string]Plugin
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
func Discover(dir string, pluginTypes ...Type) ([]Plugin, error) {
|
||||
var err error
|
||||
|
||||
if len(pluginTypes) == 0 {
|
||||
pluginTypes = AllTypes
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var plugins []Plugin
|
||||
|
||||
for _, pluginType := range pluginTypes {
|
||||
// look into a sub dir named by the plugin type
|
||||
searchDir := filepath.Join(dir, pluginType.String())
|
||||
|
||||
paths, err := filepath.Glob(filepath.Join(searchDir, "*"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
// TODO: should we use a config for some of this?
|
||||
plugins = append(plugins, NewPlugin(Config{
|
||||
// TODO: should the name be org/name instead of just name? this implies changing the dir storage too
|
||||
Name: filepath.Base(path),
|
||||
Type: pluginType,
|
||||
Command: path,
|
||||
Args: nil, // TODO
|
||||
Env: nil, // TODO
|
||||
}))
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
112
syft/plugin/repository.go
Normal file
112
syft/plugin/repository.go
Normal file
@ -0,0 +1,112 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
byType map[Type][]Plugin
|
||||
}
|
||||
|
||||
func NewRepository() *Repository {
|
||||
return &Repository{
|
||||
byType: make(map[Type][]Plugin),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepositoryFromDirectory(dir string) (*Repository, error) {
|
||||
repo := NewRepository()
|
||||
if dir == "" {
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
return repo, repo.AddFromDirectory(dir)
|
||||
}
|
||||
|
||||
func (c *Repository) Add(plugin Plugin) {
|
||||
c.byType[plugin.Config.Type] = append(c.byType[plugin.Config.Type], plugin)
|
||||
}
|
||||
|
||||
func (c *Repository) AddFromDirectory(dir string, pluginTypes ...Type) error {
|
||||
plugins, err := Discover(dir, pluginTypes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, plugin := range plugins {
|
||||
c.Add(plugin)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Repository) Get(pluginType Type) []Plugin {
|
||||
return c.byType[pluginType]
|
||||
}
|
||||
|
||||
func (c *Repository) ActivateCatalogers() ([]cataloger.Cataloger, func(), error) {
|
||||
var result []cataloger.Cataloger
|
||||
var plugins []Plugin
|
||||
var deactivateFn = func() {
|
||||
for _, plugin := range plugins {
|
||||
// TODO: handle error by log
|
||||
plugin.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
for _, plugin := range c.Get(TypeCataloger) {
|
||||
raw, err := plugin.Start()
|
||||
if err != nil {
|
||||
return nil, deactivateFn, err
|
||||
}
|
||||
plugins = append(plugins, plugin)
|
||||
|
||||
theCataloger, ok := raw.(cataloger.Cataloger)
|
||||
if !ok {
|
||||
return nil, deactivateFn, fmt.Errorf("activation of cataloger did not return a cataloger object (name=%s)", plugin.Config.Name)
|
||||
}
|
||||
|
||||
result = append(result, theCataloger)
|
||||
}
|
||||
return result, deactivateFn, nil
|
||||
}
|
||||
|
||||
func Discover(dir string, pluginTypes ...Type) ([]Plugin, error) {
|
||||
var err error
|
||||
|
||||
if len(pluginTypes) == 0 {
|
||||
pluginTypes = AllTypes
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var plugins []Plugin
|
||||
|
||||
for _, pluginType := range pluginTypes {
|
||||
// look into a sub dir named by the plugin type
|
||||
searchDir := filepath.Join(dir, pluginType.String())
|
||||
|
||||
paths, err := filepath.Glob(filepath.Join(searchDir, "*"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
// TODO: should we use a config for some of this?
|
||||
plugins = append(plugins, NewPlugin(Config{
|
||||
// TODO: should the name be org/name instead of just name? this implies changing the dir storage too
|
||||
Name: filepath.Base(path),
|
||||
Type: pluginType,
|
||||
Command: path,
|
||||
Args: nil, // TODO
|
||||
Env: nil, // TODO
|
||||
}))
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user