Fix directory resolver to consider CWD and root path input correctly (#1840)

* [wip] put in initial fix

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* capture expected behavior of dir resolver in tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update tests + comments to reflect current dir resolver behavior

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add additional test cases

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix additional tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix bad merge conflict resolution

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2023-05-25 13:41:18 +00:00
committed by GitHub
parent 07e76907f6
commit 6afbffce28
13 changed files with 1177 additions and 29 deletions
@@ -8,6 +8,7 @@ import (
"path"
"path/filepath"
"runtime"
"strings"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
@@ -119,6 +120,22 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil
}
shouldIndexFullTree, err := isRealPath(root)
if err != nil {
return nil, err
}
if !shouldIndexFullTree {
newRoots, err := r.indexBranch(root, stager)
if err != nil {
return nil, fmt.Errorf("unable to index branch=%q: %w", root, err)
}
roots = append(roots, newRoots...)
return roots, nil
}
err = filepath.Walk(root,
func(path string, info os.FileInfo, err error) error {
stager.Current = path
@@ -143,6 +160,85 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil
}
func isRealPath(root string) (bool, error) {
rootParent := filepath.Clean(filepath.Dir(root))
realRootParent, err := filepath.EvalSymlinks(rootParent)
if err != nil {
return false, err
}
realRootParent = filepath.Clean(realRootParent)
return rootParent == realRootParent, nil
}
func (r *directoryIndexer) indexBranch(root string, stager *progress.Stage) ([]string, error) {
rootRealPath, err := filepath.EvalSymlinks(root)
if err != nil {
return nil, err
}
// there is a symlink within the path to the root, we need to index the real root parent first
// then capture the symlinks to the root path
roots, err := r.indexTree(rootRealPath, stager)
if err != nil {
return nil, fmt.Errorf("unable to index real root=%q: %w", rootRealPath, err)
}
// walk down all ancestor paths and shallow-add non-existing elements to the tree
for idx, p := range allContainedPaths(root) {
var targetPath string
if idx != 0 {
parent := path.Dir(p)
cleanParent, err := filepath.EvalSymlinks(parent)
if err != nil {
return nil, fmt.Errorf("unable to evaluate symlink for contained path parent=%q: %w", parent, err)
}
targetPath = filepath.Join(cleanParent, filepath.Base(p))
} else {
targetPath = p
}
stager.Current = targetPath
lstat, err := os.Lstat(targetPath)
newRoot, err := r.indexPath(targetPath, lstat, err)
if err != nil && !errors.Is(err, ErrSkipPath) && !errors.Is(err, fs.SkipDir) {
return nil, fmt.Errorf("unable to index ancestor path=%q: %w", targetPath, err)
}
if newRoot != "" {
roots = append(roots, newRoot)
}
}
return roots, nil
}
func allContainedPaths(p string) []string {
var all []string
var currentPath string
cleanPath := strings.TrimSpace(p)
if cleanPath == "" {
return nil
}
// iterate through all parts of the path, replacing path elements with link resolutions where possible.
for idx, part := range strings.Split(filepath.Clean(cleanPath), file.DirSeparator) {
if idx == 0 && part == "" {
currentPath = file.DirSeparator
continue
}
// cumulatively gather where we are currently at and provide a rich object
currentPath = path.Join(currentPath, part)
all = append(all, currentPath)
}
return all
}
func (r *directoryIndexer) indexPath(path string, info os.FileInfo, err error) (string, error) {
// ignore any path which a filter function returns true
for _, filterFn := range r.pathIndexVisitors {