mirror of
https://github.com/anchore/syft.git
synced 2026-11-04 08:26:38 +01:00
add symlink content fetching support
This commit is contained in:
@@ -4,13 +4,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/imgbom/imgbom/pkg"
|
||||
"github.com/anchore/imgbom/imgbom/scope"
|
||||
"github.com/anchore/imgbom/internal/log"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/tree"
|
||||
)
|
||||
|
||||
// TODO: put under test...
|
||||
|
||||
// GenericCataloger implements the Catalog interface and is responsible for dispatching the proper parser function for
|
||||
// a given path or glob pattern. This is intended to be reusable across many package cataloger types.
|
||||
type GenericCataloger struct {
|
||||
@@ -45,25 +43,26 @@ func (a *GenericCataloger) clear() {
|
||||
}
|
||||
|
||||
// SelectFiles takes a set of file trees and resolves and file references of interest for future cataloging
|
||||
func (a *GenericCataloger) SelectFiles(trees []tree.FileTreeReader) []file.Reference {
|
||||
for _, t := range trees {
|
||||
// select by exact path
|
||||
for path, parser := range a.pathParsers {
|
||||
f := t.File(file.Path(path))
|
||||
if f != nil {
|
||||
a.register([]file.Reference{*f}, parser)
|
||||
}
|
||||
func (a *GenericCataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
// select by exact path
|
||||
for path, parser := range a.pathParsers {
|
||||
files, err := resolver.FilesByPath(file.Path(path))
|
||||
if err != nil {
|
||||
log.Errorf("cataloger failed to select files by path: %w", err)
|
||||
}
|
||||
if files != nil {
|
||||
a.register(files, parser)
|
||||
}
|
||||
}
|
||||
|
||||
// select by pattern
|
||||
for globPattern, parser := range a.globParsers {
|
||||
fileMatches, err := t.FilesByGlob(globPattern)
|
||||
if err != nil {
|
||||
log.Errorf("failed to find files by glob: %s", globPattern)
|
||||
}
|
||||
if fileMatches != nil {
|
||||
a.register(fileMatches, parser)
|
||||
}
|
||||
// select by glob pattern
|
||||
for globPattern, parser := range a.globParsers {
|
||||
fileMatches, err := resolver.FilesByGlob(globPattern)
|
||||
if err != nil {
|
||||
log.Errorf("failed to find files by glob: %s", globPattern)
|
||||
}
|
||||
if fileMatches != nil {
|
||||
a.register(fileMatches, parser)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/imgbom/imgbom/pkg"
|
||||
"github.com/anchore/imgbom/internal"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
type testResolver struct {
|
||||
contents map[file.Reference]string
|
||||
}
|
||||
|
||||
func newTestResolver() *testResolver {
|
||||
return &testResolver{
|
||||
contents: make(map[file.Reference]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *testResolver) FilesByPath(paths ...file.Path) ([]file.Reference, error) {
|
||||
results := make([]file.Reference, len(paths))
|
||||
|
||||
for idx, p := range paths {
|
||||
results[idx] = file.NewFileReference(p)
|
||||
r.contents[results[idx]] = fmt.Sprintf("%s file contents!", p)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *testResolver) FilesByGlob(patterns ...string) ([]file.Reference, error) {
|
||||
path := "/a-path.txt"
|
||||
ref := file.NewFileReference(file.Path(path))
|
||||
r.contents[ref] = fmt.Sprintf("%s file contents!", path)
|
||||
return []file.Reference{ref}, nil
|
||||
}
|
||||
|
||||
func parser(reader io.Reader) ([]pkg.Package, error) {
|
||||
contents, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return []pkg.Package{
|
||||
{
|
||||
Name: string(contents),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestGenericCataloger(t *testing.T) {
|
||||
|
||||
globParsers := map[string]ParserFn{
|
||||
"**a-path.txt": parser,
|
||||
}
|
||||
pathParsers := map[string]ParserFn{
|
||||
"/another-path.txt": parser,
|
||||
"/last/path.txt": parser,
|
||||
}
|
||||
|
||||
resolver := newTestResolver()
|
||||
cataloger := NewGenericCataloger(pathParsers, globParsers)
|
||||
|
||||
selected := cataloger.SelectFiles(resolver)
|
||||
|
||||
if len(selected) != 3 {
|
||||
t.Fatalf("unexpected selection length: %d", len(selected))
|
||||
}
|
||||
|
||||
expectedSelection := internal.NewStringSetFromSlice([]string{"/last/path.txt", "/another-path.txt", "/a-path.txt"})
|
||||
selectionByPath := make(map[string]file.Reference)
|
||||
for _, s := range selected {
|
||||
if !expectedSelection.Contains(string(s.Path)) {
|
||||
t.Errorf("unexpected selection path: %+v", s.Path)
|
||||
}
|
||||
selectionByPath[string(s.Path)] = s
|
||||
}
|
||||
|
||||
upstream := "some-other-cataloger"
|
||||
expectedPkgs := make(map[file.Reference]pkg.Package)
|
||||
for path, ref := range selectionByPath {
|
||||
expectedPkgs[ref] = pkg.Package{
|
||||
FoundBy: upstream,
|
||||
Source: []file.Reference{ref},
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
}
|
||||
}
|
||||
|
||||
actualPkgs, err := cataloger.Catalog(resolver.contents, upstream)
|
||||
if err != nil {
|
||||
t.Fatalf("cataloger catalog action failed: %+v", err)
|
||||
}
|
||||
|
||||
if len(actualPkgs) != len(expectedPkgs) {
|
||||
t.Fatalf("unexpected packages len: %d", len(actualPkgs))
|
||||
}
|
||||
|
||||
for _, p := range actualPkgs {
|
||||
ref := p.Source[0]
|
||||
exP, ok := expectedPkgs[ref]
|
||||
if !ok {
|
||||
t.Errorf("missing expected pkg: ref=%+v", ref)
|
||||
continue
|
||||
}
|
||||
|
||||
if p.FoundBy != exP.FoundBy {
|
||||
t.Errorf("bad upstream: %s", p.FoundBy)
|
||||
}
|
||||
|
||||
if exP.Name != p.Name {
|
||||
t.Errorf("bad contents mapping: %+v", p.Source)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user