Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make AllLocations accept a context #2518

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ require (
go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
willmurphyscode marked this conversation as resolved.
Show resolved Hide resolved
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -841,8 +841,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
Expand Down
12 changes: 10 additions & 2 deletions syft/file/cataloger/filemetadata/cataloger.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package filemetadata

import (
"context"
"fmt"

"github.com/dustin/go-humanize"
Expand All @@ -21,8 +22,10 @@ func NewCataloger() *Cataloger {
func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates]file.Metadata, error) {
results := make(map[file.Coordinates]file.Metadata)
var locations <-chan file.Location
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()
if len(coordinates) == 0 {
locations = resolver.AllLocations()
locations = resolver.AllLocations(ctx)
} else {
locations = func() <-chan file.Location {
ch := make(chan file.Location)
Expand All @@ -35,7 +38,12 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
continue
}
for _, loc := range locs {
ch <- loc
select {
case <-ctx.Done():
return
case ch <- loc:
continue
}
}
}
}()
Expand Down
5 changes: 4 additions & 1 deletion syft/file/cataloger/internal/all_regular_files.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package internal

import (
"context"
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
)

func AllRegularFiles(resolver file.Resolver) (locations []file.Location) {
for location := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for location := range resolver.AllLocations(ctx) {
resolvedLocations, err := resolver.FilesByPath(location.RealPath)
if err != nil {
log.Warnf("unable to resolve %+v: %+v", location, err)
Expand Down
11 changes: 9 additions & 2 deletions syft/file/mock_resolver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package file

import (
"context"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -144,12 +145,18 @@ func (r MockResolver) RelativeFileByPath(_ Location, path string) *Location {
return &paths[0]
}

func (r MockResolver) AllLocations() <-chan Location {
func (r MockResolver) AllLocations(ctx context.Context) <-chan Location {
results := make(chan Location)
go func() {
defer close(results)
for _, l := range r.locations {
results <- l
select {
case <-ctx.Done():
return
case results <- l:
continue
}

}
}()
return results
Expand Down
7 changes: 5 additions & 2 deletions syft/file/resolver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package file

import "io"
import (
"context"
"io"
)

// Resolver is an interface that encompasses how to get specific file references and file contents for a generic data source.
type Resolver interface {
Expand Down Expand Up @@ -53,7 +56,7 @@ type LocationResolver interface {
// The implementation for this may vary, however, generally the following considerations should be made:
// - NO symlink resolution should be performed on results
// - returns locations for any file or directory
AllLocations() <-chan Location
AllLocations(ctx context.Context) <-chan Location
}

type WritableResolver interface {
Expand Down
11 changes: 9 additions & 2 deletions syft/internal/fileresolver/container_image_all_layers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"fmt"
"io"

Expand Down Expand Up @@ -234,14 +235,20 @@ func (r *ContainerImageAllLayers) FilesByMIMEType(types ...string) ([]file.Locat
return uniqueLocations, nil
}

func (r *ContainerImageAllLayers) AllLocations() <-chan file.Location {
func (r *ContainerImageAllLayers) AllLocations(ctx context.Context) <-chan file.Location {
results := make(chan file.Location)
go func() {
defer close(results)
for _, layerIdx := range r.layers {
tree := r.img.Layers[layerIdx].Tree
for _, ref := range tree.AllFiles(stereoscopeFile.AllTypes()...) {
results <- file.NewLocationFromImage(string(ref.RealPath), ref, r.img)
select {
case <-ctx.Done():
return
case results <- file.NewLocationFromImage(string(ref.RealPath), ref, r.img):
continue
}

}
}
}()
Expand Down
9 changes: 7 additions & 2 deletions syft/internal/fileresolver/container_image_all_layers_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"io"
"sort"
"testing"
Expand Down Expand Up @@ -358,7 +359,9 @@ func TestAllLayersImageResolver_FilesContents_errorOnDirRequest(t *testing.T) {
assert.NoError(t, err)

var dirLoc *file.Location
for loc := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for loc := range resolver.AllLocations(ctx) {
entry, err := resolver.img.FileCatalog.Get(loc.Reference())
require.NoError(t, err)
if entry.Metadata.IsDir() {
Expand Down Expand Up @@ -517,7 +520,9 @@ func TestAllLayersResolver_AllLocations(t *testing.T) {
assert.NoError(t, err)

paths := strset.New()
for loc := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for loc := range resolver.AllLocations(ctx) {
paths.Add(loc.RealPath)
}
expected := []string{
Expand Down
10 changes: 8 additions & 2 deletions syft/internal/fileresolver/container_image_squash.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"fmt"
"io"

Expand Down Expand Up @@ -172,12 +173,17 @@ func (r *ContainerImageSquash) FileContentsByLocation(location file.Location) (i
return r.img.OpenReference(location.Reference())
}

func (r *ContainerImageSquash) AllLocations() <-chan file.Location {
func (r *ContainerImageSquash) AllLocations(ctx context.Context) <-chan file.Location {
results := make(chan file.Location)
go func() {
defer close(results)
for _, ref := range r.img.SquashedTree().AllFiles(stereoscopeFile.AllTypes()...) {
results <- file.NewLocationFromImage(string(ref.RealPath), ref, r.img)
select {
case <-ctx.Done():
return
case results <- file.NewLocationFromImage(string(ref.RealPath), ref, r.img):
continue
}
}
}()
return results
Expand Down
9 changes: 7 additions & 2 deletions syft/internal/fileresolver/container_image_squash_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"io"
"sort"
"testing"
Expand Down Expand Up @@ -343,7 +344,9 @@ func TestSquashImageResolver_FilesContents_errorOnDirRequest(t *testing.T) {
assert.NoError(t, err)

var dirLoc *file.Location
for loc := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for loc := range resolver.AllLocations(ctx) {
entry, err := resolver.img.FileCatalog.Get(loc.Reference())
require.NoError(t, err)
if entry.Metadata.IsDir() {
Expand Down Expand Up @@ -533,7 +536,9 @@ func TestSquashResolver_AllLocations(t *testing.T) {
assert.NoError(t, err)

paths := strset.New()
for loc := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for loc := range resolver.AllLocations(ctx) {
paths.Add(loc.RealPath)
}
expected := []string{
Expand Down
5 changes: 3 additions & 2 deletions syft/internal/fileresolver/deferred.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"io"

"github.com/anchore/syft/internal/log"
Expand Down Expand Up @@ -80,13 +81,13 @@ func (d *Deferred) RelativeFileByPath(location file.Location, path string) *file
return r.RelativeFileByPath(location, path)
}

func (d *Deferred) AllLocations() <-chan file.Location {
func (d *Deferred) AllLocations(ctx context.Context) <-chan file.Location {
r, err := d.getResolver()
if err != nil {
log.Debug("unable to get resolver: %v", err)
return nil
}
return r.AllLocations()
return r.AllLocations(ctx)
}

func (d *Deferred) FileMetadataByLocation(location file.Location) (file.Metadata, error) {
Expand Down
15 changes: 10 additions & 5 deletions syft/internal/fileresolver/directory.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package fileresolver

import (
"context"
"errors"
"fmt"
"io"
"os"

stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/filetree"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/windows"
"io"
"os"
)

var unixSystemRuntimePrefixes = []string{
Expand Down Expand Up @@ -229,12 +229,17 @@ func (r Directory) FileContentsByLocation(location file.Location) (io.ReadCloser
return stereoscopeFile.NewLazyReadCloser(filePath), nil
}

func (r *Directory) AllLocations() <-chan file.Location {
func (r *Directory) AllLocations(ctx context.Context) <-chan file.Location {
results := make(chan file.Location)
go func() {
defer close(results)
for _, ref := range r.tree.AllFiles(stereoscopeFile.AllTypes()...) {
results <- file.NewLocationFromDirectory(r.responsePath(string(ref.RealPath)), ref)
select {
case <-ctx.Done():
return
case results <- file.NewLocationFromDirectory(r.responsePath(string(ref.RealPath)), ref):
continue
}
}
}()
return results
Expand Down
22 changes: 19 additions & 3 deletions syft/internal/fileresolver/directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package fileresolver

import (
"context"
"go.uber.org/goleak"
"io"
"io/fs"
"os"
Expand Down Expand Up @@ -1380,7 +1382,7 @@ func TestDirectoryResolver_DoNotAddVirtualPathsToTree(t *testing.T) {
require.NoError(t, err)

var allRealPaths []stereoscopeFile.Path
for l := range resolver.AllLocations() {
for l := range resolver.AllLocations(context.Background()) {
allRealPaths = append(allRealPaths, stereoscopeFile.Path(l.RealPath))
}
pathSet := stereoscopeFile.NewPathSet(allRealPaths...)
Expand All @@ -1398,11 +1400,14 @@ func TestDirectoryResolver_DoNotAddVirtualPathsToTree(t *testing.T) {
}

func TestDirectoryResolver_FilesContents_errorOnDirRequest(t *testing.T) {
defer goleak.VerifyNone(t)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very cool!

resolver, err := NewFromDirectory("./test-fixtures/system_paths", "")
assert.NoError(t, err)

var dirLoc *file.Location
for loc := range resolver.AllLocations() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for loc := range resolver.AllLocations(ctx) {
entry, err := resolver.index.Get(loc.Reference())
require.NoError(t, err)
if entry.Metadata.IsDir() {
Expand All @@ -1423,7 +1428,7 @@ func TestDirectoryResolver_AllLocations(t *testing.T) {
assert.NoError(t, err)

paths := strset.New()
for loc := range resolver.AllLocations() {
for loc := range resolver.AllLocations(context.Background()) {
if strings.HasPrefix(loc.RealPath, "/") {
// ignore outside the fixture root for now
continue
Expand All @@ -1449,3 +1454,14 @@ func TestDirectoryResolver_AllLocations(t *testing.T) {

assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List()))
}

func TestAllLocationsDoesNotLeakGoRoutine(t *testing.T) {
defer goleak.VerifyNone(t)
resolver, err := NewFromDirectory("./test-fixtures/symlinks-from-image-symlinks-fixture", "")
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
for _ = range resolver.AllLocations(ctx) {
break
}
cancel()
}
3 changes: 2 additions & 1 deletion syft/internal/fileresolver/empty.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileresolver

import (
"context"
"io"

"github.com/anchore/syft/syft/file"
Expand Down Expand Up @@ -34,7 +35,7 @@ func (e Empty) RelativeFileByPath(_ file.Location, _ string) *file.Location {
return nil
}

func (e Empty) AllLocations() <-chan file.Location {
func (e Empty) AllLocations(_ context.Context) <-chan file.Location {
return nil
}

Expand Down
Loading
Loading