refactoring archive indexing

Signed-off-by: Kudryavcev Nikolay <kydry.nikolau@gmail.com>
This commit is contained in:
Kudryavcev Nikolay
2025-06-29 19:39:00 +03:00
parent 40df2d0d91
commit c8fbd613eb
3 changed files with 47 additions and 37 deletions
+27 -23
View File
@@ -16,8 +16,8 @@ import (
type archiveAccessPath struct { type archiveAccessPath struct {
realPath string realPath string
accessPath string accessPath string
archiveDepth int
archiveRealPath string archiveRealPath string
archiveDepth int
} }
const ( const (
@@ -100,7 +100,11 @@ func (r *Directory) buildIndex() error {
func (r *Directory) buildArchiveIndex(archiveTempDir string, archives []string, maxArchiveIndexDepth int) error { func (r *Directory) buildArchiveIndex(archiveTempDir string, archives []string, maxArchiveIndexDepth int) error {
archivesToIndex := make([]archiveAccessPath, len(archives)) archivesToIndex := make([]archiveAccessPath, len(archives))
for i, archive := range archives { for i, archive := range archives {
archivesToIndex[i] = archiveAccessPath{realPath: archive, accessPath: archive, archiveRealPath: archive} archivesToIndex[i] = archiveAccessPath{
realPath: archive,
accessPath: archive,
archiveRealPath: archive,
}
} }
loop: loop:
@@ -119,59 +123,59 @@ loop:
continue continue
} }
archivePath, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern) envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath)
if err != nil {
return fmt.Errorf("could not determine archive envelope type: %w", err)
}
unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver)
if !ok {
return fmt.Errorf("unarchiver %T is not an archiver", envelopedUnarchiver)
}
archiveDestinationTempDir, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern)
if err != nil { if err != nil {
return fmt.Errorf("unable to create tempdir for archive processing: %w", err) return fmt.Errorf("unable to create tempdir for archive processing: %w", err)
} }
archiveRealPath, err := filepath.EvalSymlinks(archivePath) archiveDestinationPath, err := filepath.EvalSymlinks(archiveDestinationTempDir)
if err != nil { if err != nil {
var pathErr *os.PathError var pathErr *os.PathError
if errors.As(err, &pathErr) { if errors.As(err, &pathErr) {
// we can't index the path, but we shouldn't consider this to be fatal // we can't index the path, but we shouldn't consider this to be fatal
// TODO: known-unknowns // TODO: known-unknowns
log.WithFields("archivePath", archivePath, "error", err).Trace("unable to evaluate symlink while indexing branch") log.WithFields("archivePath", archiveDestinationTempDir, "error", err).Trace("unable to evaluate symlink while indexing branch")
return nil continue
} }
return err return err
} }
envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath) if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveDestinationPath); err != nil {
if err != nil { return fmt.Errorf("unable to unarchive nested file: %w", err)
return err
} }
unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver) d, err := newFromDirectoryWithoutIndex(archiveDestinationPath, "")
if !ok {
return ErrSkipPath
}
if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveRealPath); err != nil {
return err
}
d, err := newFromDirectoryWithoutIndex(archiveRealPath, "")
if err != nil { if err != nil {
return err return err
} }
if err = d.buildIndex(); err != nil { if err = d.buildIndex(); err != nil {
return err return fmt.Errorf("unable to build index of archive: %w", err)
} }
for _, archive := range d.indexer.archivePaths { for _, archive := range d.indexer.archivePaths {
archivesToIndex = append(archivesToIndex, archiveAccessPath{ archivesToIndex = append(archivesToIndex, archiveAccessPath{
realPath: currentArchivePath.realPath, realPath: currentArchivePath.realPath,
accessPath: strings.Replace(archive, archiveRealPath, currentArchivePath.accessPath, 1), accessPath: strings.Replace(archive, archiveDestinationPath, currentArchivePath.accessPath, 1),
archiveDepth: currentArchivePath.archiveDepth + 1,
archiveRealPath: archive, archiveRealPath: archive,
archiveDepth: currentArchivePath.archiveDepth + 1,
}) })
} }
d.chroot = r.chroot d.chroot = r.chroot
d.realPath = currentArchivePath.realPath d.realPath = currentArchivePath.realPath
d.accessPath = currentArchivePath.accessPath d.accessPath = currentArchivePath.accessPath
d.tempDir = archiveRealPath d.archiveRealPath = archiveDestinationPath
r.archives = append(r.archives, &d.filetreeResolver) r.archives = append(r.archives, &d.filetreeResolver)
} }
+18 -10
View File
@@ -21,10 +21,10 @@ type filetreeResolver struct {
index filetree.IndexReader index filetree.IndexReader
searchContext filetree.Searcher searchContext filetree.Searcher
realPath string realPath string
accessPath string accessPath string
tempDir string archiveRealPath string
archives []*filetreeResolver archives []*filetreeResolver
} }
func (r *filetreeResolver) requestPath(userPath string) (string, error) { func (r *filetreeResolver) requestPath(userPath string) (string, error) {
@@ -33,8 +33,8 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) {
return "", err return "", err
} }
if r.accessPath != "" && r.tempDir != "" { if r.accessPath != "" && r.archiveRealPath != "" {
return strings.Replace(requestPath, r.accessPath, r.tempDir, 1), nil return strings.Replace(requestPath, r.accessPath, r.archiveRealPath, 1), nil
} }
return requestPath, nil return requestPath, nil
@@ -42,15 +42,19 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) {
// responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the file resolver. // responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the file resolver.
func (r filetreeResolver) responsePath(path string) string { func (r filetreeResolver) responsePath(path string) string {
if r.tempDir != "" && strings.HasPrefix(path, r.tempDir) { if r.archiveRealPath != "" && strings.HasPrefix(path, r.archiveRealPath) {
path = r.realPath path = r.realPath
} }
return r.chroot.ToChrootPath(path) return r.chroot.ToChrootPath(path)
} }
func (r filetreeResolver) responseAccessPath(path string) string { func (r filetreeResolver) responseAccessPath(path string) string {
responsePath := strings.Replace(path, r.tempDir, r.accessPath, 1) if r.accessPath != "" && r.archiveRealPath != "" {
return r.chroot.ToChrootPath(responsePath) path = strings.Replace(path, r.archiveRealPath, r.accessPath, 1)
}
return r.chroot.ToChrootPath(path)
} }
// HasPath indicates if the given path exists in the underlying source. // HasPath indicates if the given path exists in the underlying source.
@@ -138,7 +142,11 @@ func (r filetreeResolver) requestGlob(pattern string) (string, error) {
return "", err return "", err
} }
return strings.Replace(nativeGlob, r.accessPath, r.tempDir, 1), nil if r.accessPath != "" && r.archiveRealPath != "" {
return strings.Replace(nativeGlob, r.accessPath, r.archiveRealPath, 1), nil
}
return nativeGlob, nil
} }
// FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image. // FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image.
@@ -1664,6 +1664,7 @@ func TestFileResolver_AllLocations_errorOnDirRequest(t *testing.T) {
} }
func TestFileResolver_AllLocations(t *testing.T) { func TestFileResolver_AllLocations(t *testing.T) {
defer goleak.VerifyNone(t)
// Verify both the parent and the file itself are indexed // Verify both the parent and the file itself are indexed
filePath := "./test-fixtures/system_paths/target/home/place" filePath := "./test-fixtures/system_paths/target/home/place"
parentPath, err := absoluteSymlinkFreePathToParent(filePath) parentPath, err := absoluteSymlinkFreePathToParent(filePath)
@@ -1685,11 +1686,10 @@ func TestFileResolver_AllLocations(t *testing.T) {
sort.Strings(pathsList) sort.Strings(pathsList)
assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List())) assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List()))
goleak.VerifyNone(t)
} }
func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) { func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) {
defer goleak.VerifyNone(t)
filePath := "./test-fixtures/system_paths/target/home/place" filePath := "./test-fixtures/system_paths/target/home/place"
parentPath, err := absoluteSymlinkFreePathToParent(filePath) parentPath, err := absoluteSymlinkFreePathToParent(filePath)
require.NoError(t, err) require.NoError(t, err)
@@ -1703,6 +1703,4 @@ func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) {
break break
} }
cancel() cancel()
goleak.VerifyNone(t)
} }