Skip to content

Commit 95f67ad

Browse files
mikethemanclaude
andauthored
Optimize supplement file lookup with direct tree traversal (#80)
Replace O(n) whole-tree iteration with O(1) subtree lookup when finding supplement files (lockfiles) in the same directory as a manifest. Before: tree.Files().ForEach() iterated every file in the repository, then filtered by directory path - O(total files in repo) per manifest. After: tree.Tree(dir) navigates directly to the target directory, then iterates only its direct entries - O(files in directory) per manifest. Performance improvement on a repository with 8619 commits: - Before: 5:20 (320 seconds) - After: 12 seconds - Speedup: ~26x Also fixes a subtle bug where filepath.Dir() was used (platform-dependent path separators) instead of explicit "/" (git's path convention), and removes mutation of the captured `dir` variable inside the ForEach closure. Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 84cfd3c commit 95f67ad

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

internal/analyzer/analyzer.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -578,33 +578,49 @@ func (a *Analyzer) parseSupplementsInDir(tree *object.Tree, dir string) map[supp
578578

579579
hashes := make(map[supplementKey]string)
580580

581-
_ = tree.Files().ForEach(func(f *object.File) error {
582-
fileDir := filepath.Dir(f.Name)
583-
if fileDir == "." {
584-
fileDir = ""
581+
// Get the target directory's tree directly instead of iterating all files
582+
var targetTree *object.Tree
583+
if dir == "" || dir == "." {
584+
targetTree = tree
585+
} else {
586+
var err error
587+
targetTree, err = tree.Tree(dir)
588+
if err != nil {
589+
// Directory doesn't exist in this tree
590+
return hashes
585591
}
586-
if dir == "." {
587-
dir = ""
592+
}
593+
594+
// Iterate only direct entries in this directory (not recursive)
595+
for _, entry := range targetTree.Entries {
596+
// Skip subdirectories and non-regular files
597+
if !entry.Mode.IsFile() {
598+
continue
588599
}
589-
if fileDir != dir {
590-
return nil
600+
601+
// Build the full path for identification
602+
var fullPath string
603+
if dir == "" || dir == "." {
604+
fullPath = entry.Name
605+
} else {
606+
fullPath = dir + "/" + entry.Name
591607
}
592-
if !isSupplementFile(f.Name) {
593-
return nil
608+
609+
if !isSupplementFile(fullPath) {
610+
continue
594611
}
595612

596-
result, err := a.parseManifestInTree(tree, f.Name)
613+
result, err := a.parseManifestInTree(tree, fullPath)
597614
if err != nil || result == nil {
598-
return nil
615+
continue
599616
}
600617

601618
for _, dep := range result.Dependencies {
602619
if dep.Integrity != "" {
603620
hashes[supplementKey{dep.Name, dep.Version}] = dep.Integrity
604621
}
605622
}
606-
return nil
607-
})
623+
}
608624

609625
return hashes
610626
}

0 commit comments

Comments
 (0)