add VirtualPath to source.Location

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2021-01-05 21:16:42 -05:00
parent 06641cfda2
commit 6a49717314
22 changed files with 55 additions and 48 deletions
+2 -4
View File
@@ -114,8 +114,7 @@ func (r *AllLayersResolver) FilesByPath(paths ...string) ([]Location, error) {
return nil, err
}
for _, result := range results {
// we always prefer the REAL path (not the user given path which may have symlinks)
uniqueLocations = append(uniqueLocations, NewLocationFromImage(string(result.RealPath), result, r.img))
uniqueLocations = append(uniqueLocations, NewLocationFromImage(path, result, r.img))
}
}
}
@@ -154,8 +153,7 @@ func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]Location, error)
return nil, err
}
for _, refResult := range refResults {
// we always prefer the REAL path (not the user given path which may have symlinks)
uniqueLocations = append(uniqueLocations, NewLocationFromImage(string(refResult.RealPath), refResult, r.img))
uniqueLocations = append(uniqueLocations, NewLocationFromImage(string(result.MatchPath), refResult, r.img))
}
}
}
+2 -2
View File
@@ -117,7 +117,7 @@ func TestAllLayersResolver_FilesByPath(t *testing.T) {
t.Errorf("bad resolve path: '%s'!='%s'", string(actual.ref.RealPath), expected.path)
}
if expected.path != "" && string(actual.ref.RealPath) != actual.Path {
if expected.path != "" && string(actual.ref.RealPath) != actual.RealPath {
t.Errorf("we should always prefer real paths over ones with links")
}
@@ -225,7 +225,7 @@ func TestAllLayersResolver_FilesByGlob(t *testing.T) {
t.Errorf("bad resolve path: '%s'!='%s'", string(actual.ref.RealPath), expected.path)
}
if expected.path != "" && string(actual.ref.RealPath) != actual.Path {
if expected.path != "" && string(actual.ref.RealPath) != actual.RealPath {
t.Errorf("we should always prefer real paths over ones with links")
}
+4 -4
View File
@@ -54,20 +54,20 @@ func TestContentRequester(t *testing.T) {
}
for _, entry := range data {
if expected, ok := test.expectedContents[entry.Location.Path]; ok {
if expected, ok := test.expectedContents[entry.Location.RealPath]; ok {
actualBytes, err := ioutil.ReadAll(entry.Contents)
if err != nil {
t.Fatalf("could not read %q: %+v", entry.Location.Path, err)
t.Fatalf("could not read %q: %+v", entry.Location.RealPath, err)
}
for expected != string(actualBytes) {
t.Errorf("mismatched contents for %q", entry.Location.Path)
t.Errorf("mismatched contents for %q", entry.Location.RealPath)
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(expected, string(actualBytes), true)
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
}
continue
}
t.Errorf("could not find %q", entry.Location.Path)
t.Errorf("could not find %q", entry.Location.RealPath)
}
})
}
+2 -2
View File
@@ -110,7 +110,7 @@ func (r *DirectoryResolver) RelativeFileByPath(_ Location, path string) *Locatio
func (r DirectoryResolver) MultipleFileContentsByLocation(locations []Location) (map[Location]io.ReadCloser, error) {
refContents := make(map[Location]io.ReadCloser)
for _, location := range locations {
refContents[location] = file.NewDeferredReadCloser(location.Path)
refContents[location] = file.NewDeferredReadCloser(location.RealPath)
}
return refContents, nil
}
@@ -118,5 +118,5 @@ func (r DirectoryResolver) MultipleFileContentsByLocation(locations []Location)
// FileContentsByLocation fetches file contents for a single file reference relative to a directory.
// If the path does not exist an error is returned.
func (r DirectoryResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) {
return file.NewDeferredReadCloser(location.Path), nil
return file.NewDeferredReadCloser(location.RealPath), nil
}
+2 -2
View File
@@ -80,8 +80,8 @@ func TestDirectoryResolver_FilesByPath(t *testing.T) {
}
for _, actual := range refs {
if actual.Path != c.expected {
t.Errorf("bad resolve path: '%s'!='%s'", actual.Path, c.expected)
if actual.RealPath != c.expected {
t.Errorf("bad resolve path: '%s'!='%s'", actual.RealPath, c.expected)
}
}
})
+1 -2
View File
@@ -66,8 +66,7 @@ func (r *ImageSquashResolver) FilesByPath(paths ...string) ([]Location, error) {
if resolvedRef != nil && !uniqueFileIDs.Contains(*resolvedRef) {
uniqueFileIDs.Add(*resolvedRef)
// we always prefer the REAL path (not the user given path which may have symlinks)
uniqueLocations = append(uniqueLocations, NewLocationFromImage(string(resolvedRef.RealPath), *resolvedRef, r.img))
uniqueLocations = append(uniqueLocations, NewLocationFromImage(path, *resolvedRef, r.img))
}
}
+2 -2
View File
@@ -106,7 +106,7 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) {
t.Errorf("bad resolve path: '%s'!='%s'", string(actual.ref.RealPath), c.resolvePath)
}
if c.resolvePath != "" && string(actual.ref.RealPath) != actual.Path {
if c.resolvePath != "" && string(actual.ref.RealPath) != actual.RealPath {
t.Errorf("we should always prefer real paths over ones with links")
}
@@ -212,7 +212,7 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) {
t.Errorf("bad resolve path: '%s'!='%s'", string(actual.ref.RealPath), c.resolvePath)
}
if c.resolvePath != "" && string(actual.ref.RealPath) != actual.Path {
if c.resolvePath != "" && string(actual.ref.RealPath) != actual.RealPath {
t.Errorf("we should always prefer real paths over ones with links")
}
+11 -7
View File
@@ -7,9 +7,11 @@ import (
"github.com/anchore/stereoscope/pkg/image"
)
// Location represents a path relative to a particular filesystem.
// Location represents a path relative to a particular filesystem resolved to a specific file.Reference. This struct is used as a key
// in content fetching to uniquely identify a file relative to a request (the VirtualPath).
type Location struct {
Path string `json:"path"` // The string path of the location (e.g. /etc/hosts)
RealPath string `json:"path"` // The path where all path ancestors have no hardlinks / symlinks
VirtualPath string `json:"-"` // The path to the file which may or may not have hardlinks / symlinks
FileSystemID string `json:"layerID,omitempty"` // An ID representing the filesystem. For container images this is a layer digest, directories or root filesystem this is blank.
ref file.Reference // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
}
@@ -17,23 +19,25 @@ type Location struct {
// NewLocation creates a new Location representing a path without denoting a filesystem or FileCatalog reference.
func NewLocation(path string) Location {
return Location{
Path: path,
RealPath: path,
}
}
// NewLocationFromImage creates a new Location representing the given path (extracted from the ref) relative to the given image.
func NewLocationFromImage(path string, ref file.Reference, img *image.Image) Location {
func NewLocationFromImage(virtualPath string, ref file.Reference, img *image.Image) Location {
entry, err := img.FileCatalog.Get(ref)
if err != nil {
log.Warnf("unable to find file catalog entry for ref=%+v", ref)
return Location{
Path: path,
ref: ref,
VirtualPath: virtualPath,
RealPath: string(ref.RealPath),
ref: ref,
}
}
return Location{
Path: path,
VirtualPath: virtualPath,
RealPath: string(ref.RealPath),
FileSystemID: entry.Layer.Metadata.Digest,
ref: ref,
}
+5 -5
View File
@@ -31,7 +31,7 @@ func NewMockResolverForPaths(paths ...string) *MockResolver {
// HasPath indicates if the given path exists in the underlying source.
func (r MockResolver) HasPath(path string) bool {
for _, l := range r.Locations {
if l.Path == path {
if l.RealPath == path {
return true
}
}
@@ -40,7 +40,7 @@ func (r MockResolver) HasPath(path string) bool {
// String returns the string representation of the MockResolver.
func (r MockResolver) String() string {
return fmt.Sprintf("mock:(%s,...)", r.Locations[0].Path)
return fmt.Sprintf("mock:(%s,...)", r.Locations[0].RealPath)
}
// FileContentsByLocation fetches file contents for a single location. If the
@@ -48,7 +48,7 @@ func (r MockResolver) String() string {
func (r MockResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) {
for _, l := range r.Locations {
if l == location {
return os.Open(location.Path)
return os.Open(location.RealPath)
}
}
@@ -74,7 +74,7 @@ func (r MockResolver) FilesByPath(paths ...string) ([]Location, error) {
var results []Location
for _, p := range paths {
for _, location := range r.Locations {
if p == location.Path {
if p == location.RealPath {
results = append(results, NewLocation(p))
}
}
@@ -88,7 +88,7 @@ func (r MockResolver) FilesByGlob(patterns ...string) ([]Location, error) {
var results []Location
for _, pattern := range patterns {
for _, location := range r.Locations {
if file.GlobMatch(pattern, location.Path) {
if file.GlobMatch(pattern, location.RealPath) {
results = append(results, location)
}
}
+1 -1
View File
@@ -16,8 +16,8 @@ type Resolver interface {
// ContentResolver knows how to get file content for given file.References
type ContentResolver interface {
FileContentsByLocation(Location) (io.ReadCloser, error)
// TODO: it is possible to be given duplicate locations that will be overridden in the map (key), a subtle problem that coule easily be misued.
MultipleFileContentsByLocation([]Location) (map[Location]io.ReadCloser, error)
// TODO: we should consider refactoring to return a set of io.Readers or file.Openers instead of the full contents themselves (allow for optional buffering).
}
// FileResolver knows how to get a Location for given string paths and globs