pull in temp dir generator from stereoscope

Signed-off-by: Alex Goodman <wagoodman@gmail.com>
This commit is contained in:
Alex Goodman 2021-06-26 23:29:25 -04:00
parent c5390264b0
commit aac0dac0de
13 changed files with 77 additions and 42 deletions

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"os" "os"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui" "github.com/anchore/syft/internal/ui"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
@ -50,10 +51,12 @@ func eventLoop(workerErrs <-chan error, signals <-chan os.Signal, subscription *
} }
} }
case <-signals: case <-signals:
if err := subscription.Unsubscribe(); err != nil { // ignore further results from any event source and exit ASAP, but ensure that all cache is cleaned up.
log.Warnf("unable to unsubscribe from the event bus: %+v", err) // we ignore further errors since cleaning up the tmp directories will affect running catalogers that are
events = nil // reading/writing from/to their nested temp dirs. This is acceptable since we are bailing without result.
} events = nil
workerErrs = nil
syft.Cleanup()
} }
} }

View File

@ -6,10 +6,6 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/anchore/syft/syft/presenter/packages"
"github.com/spf13/viper"
"github.com/anchore/syft/internal" "github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/anchore" "github.com/anchore/syft/internal/anchore"
"github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/bus"
@ -19,10 +15,12 @@ import (
"github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/event" "github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/presenter/packages"
"github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source"
"github.com/pkg/profile" "github.com/pkg/profile"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/wagoodman/go-partybus" "github.com/wagoodman/go-partybus"
) )
@ -206,7 +204,11 @@ func packagesExecWorker(userInput string) <-chan error {
errs <- fmt.Errorf("failed to determine image source: %+v", err) errs <- fmt.Errorf("failed to determine image source: %+v", err)
return return
} }
defer cleanup() defer func() {
if err := cleanup(); err != nil {
log.Warnf("unable to cleanup source temp dir: %+v", err)
}
}()
catalog, d, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt) catalog, d, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt)
if err != nil { if err != nil {

View File

@ -5,8 +5,8 @@ import (
"sync" "sync"
"github.com/anchore/syft/internal" "github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/presenter/poweruser" "github.com/anchore/syft/internal/presenter/poweruser"
"github.com/anchore/syft/internal/ui" "github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/syft/event" "github.com/anchore/syft/syft/event"
@ -89,7 +89,11 @@ func powerUserExecWorker(userInput string) <-chan error {
errs <- err errs <- err
return return
} }
defer cleanup() defer func() {
if err := cleanup(); err != nil {
log.Warnf("unable to cleanup source temp dir: %+v", err)
}
}()
if src.Metadata.Scheme != source.ImageScheme { if src.Metadata.Scheme != source.ImageScheme {
errs <- fmt.Errorf("the power-user subcommand only allows for 'image' schemes, given %q", src.Metadata.Scheme) errs <- fmt.Errorf("the power-user subcommand only allows for 'image' schemes, given %q", src.Metadata.Scheme)

2
go.mod
View File

@ -46,3 +46,5 @@ require (
golang.org/x/mod v0.3.0 golang.org/x/mod v0.3.0
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.3.0
) )
replace github.com/anchore/stereoscope => ../stereoscope

2
go.sum
View File

@ -115,8 +115,6 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods= github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E= github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/stereoscope v0.0.0-20210524175238-3b7662f3a66f h1:bFadyOLOkzME3BrZFZ5m8cf/b2hsn3aMSS9s+SKubRk=
github.com/anchore/stereoscope v0.0.0-20210524175238-3b7662f3a66f/go.mod h1:vhh1M99rfWx5ejMvz1lkQiFZUrC5wu32V12R4JXH+ZI=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=

View File

@ -0,0 +1,5 @@
package internal
import "github.com/anchore/stereoscope/pkg/file"
var RootTempDirGenerator = file.NewTempDirGenerator(ApplicationName)

View File

@ -19,6 +19,9 @@ package syft
import ( import (
"fmt" "fmt"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/distro"
@ -76,3 +79,11 @@ func SetLogger(logger logger.Logger) {
func SetBus(b *partybus.Bus) { func SetBus(b *partybus.Bus) {
bus.SetPublisher(b) bus.SetPublisher(b)
} }
func Cleanup() {
stereoscope.Cleanup()
if err := internal.RootTempDirGenerator.Cleanup(); err != nil {
log.Errorf("failed to cleanup temp directories: %w", err)
}
}

View File

@ -36,7 +36,11 @@ type archiveParser struct {
func parseJavaArchive(virtualPath string, reader io.Reader) ([]pkg.Package, error) { func parseJavaArchive(virtualPath string, reader io.Reader) ([]pkg.Package, error) {
parser, cleanupFn, err := newJavaArchiveParser(virtualPath, reader, true) parser, cleanupFn, err := newJavaArchiveParser(virtualPath, reader, true)
// note: even on error, we should always run cleanup functions // note: even on error, we should always run cleanup functions
defer cleanupFn() defer func() {
if err := cleanupFn(); err != nil {
log.Warnf("unable to clean up java archive temp dir: %+v", err)
}
}()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -53,7 +57,7 @@ func uniquePkgKey(p *pkg.Package) string {
// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover // newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
// and parse nested archives or ignore them. // and parse nested archives or ignore them.
func newJavaArchiveParser(virtualPath string, reader io.Reader, detectNested bool) (*archiveParser, func(), error) { func newJavaArchiveParser(virtualPath string, reader io.Reader, detectNested bool) (*archiveParser, func() error, error) {
contentPath, archivePath, cleanupFn, err := saveArchiveToTmp(reader) contentPath, archivePath, cleanupFn, err := saveArchiveToTmp(reader)
if err != nil { if err != nil {
return nil, cleanupFn, fmt.Errorf("unable to process java archive: %w", err) return nil, cleanupFn, fmt.Errorf("unable to process java archive: %w", err)

View File

@ -226,7 +226,9 @@ func TestParseJar(t *testing.T) {
} }
parser, cleanupFn, err := newJavaArchiveParser(fixture.Name(), fixture, false) parser, cleanupFn, err := newJavaArchiveParser(fixture.Name(), fixture, false)
defer cleanupFn() t.Cleanup(func() {
assert.NoError(t, cleanupFn())
})
if err != nil { if err != nil {
t.Fatalf("should not have filed... %+v", err) t.Fatalf("should not have filed... %+v", err)
} }
@ -845,9 +847,11 @@ func TestPackagesFromPomProperties(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// make the parser // make the parser
parser, cleanup, err := newJavaArchiveParser(virtualPath, nop, false) parser, cleanupFn, err := newJavaArchiveParser(virtualPath, nop, false)
assert.NoError(t, err) assert.NoError(t, err)
t.Cleanup(cleanup) t.Cleanup(func() {
assert.NoError(t, cleanupFn())
})
// get the test data // get the test data
actualPackage := parser.newPackageFromPomProperties(*test.props, test.parent) actualPackage := parser.newPackageFromPomProperties(*test.props, test.parent)

View File

@ -3,25 +3,19 @@ package java
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal"
) )
func saveArchiveToTmp(reader io.Reader) (string, string, func(), error) { func saveArchiveToTmp(reader io.Reader) (string, string, func() error, error) {
tempDir, err := ioutil.TempDir("", "syft-jar-contents-") generator := internal.RootTempDirGenerator.NewGenerator()
tempDir, err := generator.NewDirectory("java-cataloger-content-cache")
if err != nil { if err != nil {
return "", "", func() {}, fmt.Errorf("unable to create tempdir for jar processing: %w", err) return "", "", func() error { return nil }, fmt.Errorf("unable to create tempdir for jar processing: %w", err)
}
cleanupFn := func() {
err = os.RemoveAll(tempDir)
if err != nil {
log.Errorf("unable to cleanup jar tempdir: %+v", err)
}
} }
cleanupFn := generator.Cleanup
archivePath := filepath.Join(tempDir, "archive") archivePath := filepath.Join(tempDir, "archive")
contentDir := filepath.Join(tempDir, "contents") contentDir := filepath.Join(tempDir, "contents")

View File

@ -23,33 +23,33 @@ type Source struct {
type sourceDetector func(string) (image.Source, string, error) type sourceDetector func(string) (image.Source, string, error)
// New produces a Source based on userInput like dir: or image:tag // New produces a Source based on userInput like dir: or image:tag
func New(userInput string, registryOptions *image.RegistryOptions) (Source, func(), error) { func New(userInput string, registryOptions *image.RegistryOptions) (Source, func() error, error) {
fs := afero.NewOsFs() fs := afero.NewOsFs()
noCleanupFn := func() error { return nil }
parsedScheme, imageSource, location, err := detectScheme(fs, image.DetectSource, userInput) parsedScheme, imageSource, location, err := detectScheme(fs, image.DetectSource, userInput)
if err != nil { if err != nil {
return Source{}, func() {}, fmt.Errorf("unable to parse input=%q: %w", userInput, err) return Source{}, noCleanupFn, fmt.Errorf("unable to parse input=%q: %w", userInput, err)
} }
switch parsedScheme { switch parsedScheme {
case DirectoryScheme: case DirectoryScheme:
fileMeta, err := fs.Stat(location) fileMeta, err := fs.Stat(location)
if err != nil { if err != nil {
return Source{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err) return Source{}, noCleanupFn, fmt.Errorf("unable to stat dir=%q: %w", location, err)
} }
if !fileMeta.IsDir() { if !fileMeta.IsDir() {
return Source{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err) return Source{}, noCleanupFn, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
} }
s, err := NewFromDirectory(location) s, err := NewFromDirectory(location)
if err != nil { if err != nil {
return Source{}, func() {}, fmt.Errorf("could not populate source from path=%q: %w", location, err) return Source{}, noCleanupFn, fmt.Errorf("could not populate source from path=%q: %w", location, err)
} }
return s, func() {}, nil return s, noCleanupFn, nil
case ImageScheme: case ImageScheme:
img, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions) img, cleanup, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions)
cleanup := stereoscope.Cleanup
if err != nil || img == nil { if err != nil || img == nil {
return Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err) return Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
@ -62,7 +62,7 @@ func New(userInput string, registryOptions *image.RegistryOptions) (Source, func
return s, cleanup, nil return s, cleanup, nil
} }
return Source{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput) return Source{}, noCleanupFn, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
} }
// NewFromDirectory creates a new source object tailored to catalog a given filesystem directory recursively. // NewFromDirectory creates a new source object tailored to catalog a given filesystem directory recursively.

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/distro"
@ -24,7 +25,9 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
for _, c := range cataloger.ImageCatalogers() { for _, c := range cataloger.ImageCatalogers() {
// in case of future alteration where state is persisted, assume no dependency is safe to reuse // in case of future alteration where state is persisted, assume no dependency is safe to reuse
theSource, cleanupSource, err := source.New("docker-archive:"+tarPath, nil) theSource, cleanupSource, err := source.New("docker-archive:"+tarPath, nil)
b.Cleanup(cleanupSource) b.Cleanup(func() {
assert.NoError(b, cleanupSource())
})
if err != nil { if err != nil {
b.Fatalf("unable to get source: %+v", err) b.Fatalf("unable to get source: %+v", err)
} }

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/anchore/stereoscope/pkg/imagetest" "github.com/anchore/stereoscope/pkg/imagetest"
@ -15,7 +16,9 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string) (*pkg.Catalog, *
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
theSource, cleanupSource, err := source.New("docker-archive:"+tarPath, nil) theSource, cleanupSource, err := source.New("docker-archive:"+tarPath, nil)
t.Cleanup(cleanupSource) t.Cleanup(func() {
assert.NoError(t, cleanupSource())
})
if err != nil { if err != nil {
t.Fatalf("unable to get source: %+v", err) t.Fatalf("unable to get source: %+v", err)
} }
@ -30,7 +33,9 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string) (*pkg.Catalog, *
func catalogDirectory(t *testing.T, dir string) (*pkg.Catalog, *distro.Distro, source.Source) { func catalogDirectory(t *testing.T, dir string) (*pkg.Catalog, *distro.Distro, source.Source) {
theSource, cleanupSource, err := source.New("dir:"+dir, nil) theSource, cleanupSource, err := source.New("dir:"+dir, nil)
t.Cleanup(cleanupSource) t.Cleanup(func() {
assert.NoError(t, cleanupSource())
})
if err != nil { if err != nil {
t.Fatalf("unable to get source: %+v", err) t.Fatalf("unable to get source: %+v", err)
} }