perf: add single-walk file filter that prunes ignored directories - #661
perf: add single-walk file filter that prunes ignored directories#661apzuk3 wants to merge 1 commit into
Conversation
Add GetFilteredFilesSingleWalk, which traverses the directory tree once instead of twice (GetAllFiles + GetFilteredFiles) and prunes wholly- excluded directories such as node_modules and .git rather than globbing every file beneath them — where almost all the time on real projects was spent. A directory is pruned only when a rule excludes the directory itself (node_modules, /node_modules/, **/dist), never when a rule excludes only its contents (src/*, obj/**) or when the directory contains its own ignore file, since those may be re-included by a ! negation. Per-file emission still uses the full rule set, so output is identical to the original pipeline. Includes equivalence, negation-edge-case, and pruning tests plus a benchmark against the old pipeline.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
PR Reviewer Guide 🔍
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a8bac65. Configure here.
| if path != fw.path && | ||
| dirMatcher.MatchesPath(path) && | ||
| !fw.dirContainsRuleFile(path, ruleFileSet) { | ||
| return fs.SkipDir |
There was a problem hiding this comment.
Pruning skips same-file negations
High Severity
Directory pruning via fs.SkipDir drops entire subtrees before the final per-file pass, but dirExclusionGlob still treats many ignore lines (including trailing-slash directory rules like node_modules/ and plain node_modules) as safe whole-directory exclusions. Negated re-includes in the same .gitignore only apply to paths still visited by the old pipeline, so those files can be omitted from the scan output entirely.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a8bac65. Configure here.
| // applies in this directory and any subdirectory | ||
| glob = filepath.ToSlash(filepath.Join(base, "**", r)) | ||
| } | ||
| glob = escapeSpecialGlobChars(glob) |
There was a problem hiding this comment.
Dir globs omit base quoting
Medium Severity
dirExclusionGlob builds pruning globs from an unquoted baseDir, while parseIgnoreRuleToGlobs applies regexp.QuoteMeta to the ignore file’s directory before compiling file rules. On project paths containing regex metacharacters (parentheses, plus, braces, etc.), dirMatcher can disagree with the final fileMatcher and prune the wrong subtree or skip pruning incorrectly.
Reviewed by Cursor Bugbot for commit a8bac65. Configure here.


Description
Adds
GetFilteredFilesSingleWalk, which traverses the directory tree once (instead of the two-passGetAllFiles+GetFilteredFilespipeline) and prunes wholly-excluded directories such asnode_modulesand.gitrather than globbing every file beneath them — where almost all the traversal time on real projects was being spent.A directory is pruned only when a rule excludes the directory itself (
node_modules,/node_modules/,**/dist), never when a rule excludes only its contents (src/*,obj/**) or when the directory contains its own ignore file, since those may be re-included by a!negation. Per-file emission still uses the full rule set, so output is identical to the original pipeline.Includes equivalence, negation-edge-case, and pruning tests plus a benchmark against the old pipeline.
This is a re-open of #657 (originally authored by @z4ce) from a branch on the snyk org so CI runs with the proper context. Related ticket: COIN-2536.
Needed by snyk/code-client-go#164, which will pin this once merged.
Checklist
make test, incl.-race)make lint)go build ./...cleanNote
Medium Risk
Changes which files are scanned if pruning or negation edge cases are wrong, but behavior is heavily regression-tested against the existing pipeline and real-repo edge cases.
Overview
Adds
GetFilteredFilesSingleWalkas a faster alternative to the two-passGetAllFiles→GetRules→GetFilteredFilesflow: one tree walk, ignore rules folded in as.gitignore/.dcignore/.snykare encountered, andfs.SkipDirused to skip wholly excluded dirs (e.g.node_modules,**/dist) instead of glob-matching every file under them.buildGlobsis refactored throughglobsForIgnoreFileso ignore parsing is shared. Pruning uses a separatedirMatcherbuilt only from whole-directory rules (notsrc/*/obj/**), skips dirs that contain their own rule files, and does not treat.snykas a source of prune rules. Final inclusion still uses the full accumulated glob set inemitCandidates(parallelized like the old path) so results stay aligned with the legacy pipeline.New tests assert equivalence with the old pipeline, negation / content-only-ignore edge cases, and
node_modulespruning; a benchmark compares old vs single-walk on a large ignored tree.Reviewed by Cursor Bugbot for commit a8bac65. Bugbot is set up for automated code reviews on this repo. Configure here.