-
Notifications
You must be signed in to change notification settings - Fork 0
Optimize file enumeration to skip build directories during traversal #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,6 +16,11 @@ namespace ProjGraph.Lib.Services.EfAnalysis; | |||||||||||||||||||||||||||||||
| /// </remarks> | ||||||||||||||||||||||||||||||||
| public static class EntityFileDiscovery | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||
| /// Maximum recursion depth when searching for base class files to prevent infinite recursion | ||||||||||||||||||||||||||||||||
| /// and limit search scope to reasonable project structures. | ||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||
| private const int MaxSearchDepth = 10; | ||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||
| /// Discovers the file paths of entity files within the specified search directories. | ||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||
|
|
@@ -173,37 +178,69 @@ public static HashSet<string> ExtractEntityTypeNames(ClassDeclarationSyntax cont | |||||||||||||||||||||||||||||||
| /// For each file, it calls <see cref="ProcessSourceFileAsync"/> to process the file and add matching | ||||||||||||||||||||||||||||||||
| /// entity type names and their file paths to the <paramref name="entityFiles"/> dictionary. | ||||||||||||||||||||||||||||||||
| /// Any access errors encountered during directory traversal are ignored. | ||||||||||||||||||||||||||||||||
| /// Directories like bin, obj, .git, and node_modules are skipped during traversal for performance. | ||||||||||||||||||||||||||||||||
| /// </remarks> | ||||||||||||||||||||||||||||||||
| private static async Task SearchDirectoryForEntitiesAsync( | ||||||||||||||||||||||||||||||||
| string searchDir, | ||||||||||||||||||||||||||||||||
| HashSet<string> entityTypeNames, | ||||||||||||||||||||||||||||||||
| string normalizedContextPath, | ||||||||||||||||||||||||||||||||
| Dictionary<string, string> entityFiles) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
| { | |
| { | |
| // Basic validation to ensure we do not attempt to search with invalid inputs. | |
| if (string.IsNullOrWhiteSpace(searchDir) || | |
| entityTypeNames == null || | |
| entityFiles == null) | |
| { | |
| return; | |
| } | |
| // Avoid starting a recursive search on a directory that does not exist. | |
| if (!System.IO.Directory.Exists(searchDir)) | |
| { | |
| return; | |
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SearchDirectoryRecursiveAsync method lacks depth tracking and maximum depth enforcement, unlike SearchForBaseClassFilesRecursive which has these safeguards. This creates an inconsistency and potential risk of unbounded recursion if the file system contains symbolic links or deeply nested directory structures. Consider adding currentDepth and maxDepth parameters to match the pattern used in SearchForBaseClassFilesRecursive, and add an early return check similar to line 461.
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This foreach loop immediately maps its iteration variable to another variable - consider mapping the sequence explicitly using '.Select(...)'.
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directory name filtering uses pattern matching which is case-sensitive ("bin" or "obj" or ".git" or "node_modules"). On Windows, directory names are case-insensitive, so "Bin", "BIN", "Obj", "OBJ" would not be filtered out. Consider using case-insensitive comparison, similar to how path comparisons are handled elsewhere in the codebase (e.g., line 226 uses StringComparison.OrdinalIgnoreCase). Example: if (dirName.Equals("bin", StringComparison.OrdinalIgnoreCase) || dirName.Equals("obj", StringComparison.OrdinalIgnoreCase) || ...)
| if (dirName is "bin" or "obj" or ".git" or "node_modules") | |
| if (string.Equals(dirName, "bin", System.StringComparison.OrdinalIgnoreCase) | |
| || string.Equals(dirName, "obj", System.StringComparison.OrdinalIgnoreCase) | |
| || string.Equals(dirName, ".git", System.StringComparison.OrdinalIgnoreCase) | |
| || string.Equals(dirName, "node_modules", System.StringComparison.OrdinalIgnoreCase)) |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file WorkspaceTypeDiscovery.cs (lines 61-71) still uses the old pattern of RecurseSubdirectories = true with post-traversal filtering. For consistency and performance, consider applying the same optimization pattern used in this PR to that file as well.
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SearchDirectoryRecursiveAsync should check if all entities have been found and return early, similar to the optimization in SearchForBaseClassFilesRecursive (lines 484-487, 502-505). This would prevent unnecessary traversal once all entity files have been discovered. Consider adding a check after processing files and before recursing into subdirectories: if (entityTypeNames.All(entityFiles.ContainsKey)) return;
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directory name filtering uses pattern matching which is case-sensitive ("bin" or "obj" or ".git" or "node_modules"). On Windows, directory names are case-insensitive, so "Bin", "BIN", "Obj", "OBJ" would not be filtered out. Consider using case-insensitive comparison, similar to how path comparisons are handled elsewhere in the codebase (e.g., line 226 uses StringComparison.OrdinalIgnoreCase). Example: if (dirName.Equals("bin", StringComparison.OrdinalIgnoreCase) || dirName.Equals("obj", StringComparison.OrdinalIgnoreCase) || ...)
| if (dirName is "bin" or "obj" or ".git" or "node_modules") | |
| if (dirName.Equals("bin", System.StringComparison.OrdinalIgnoreCase) | |
| || dirName.Equals("obj", System.StringComparison.OrdinalIgnoreCase) | |
| || dirName.Equals(".git", System.StringComparison.OrdinalIgnoreCase) | |
| || dirName.Equals("node_modules", System.StringComparison.OrdinalIgnoreCase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation for MaxSearchDepth indicates it's only used for "base class files", but this constant should also apply to entity file searching in SearchDirectoryRecursiveAsync to prevent unbounded recursion. Update the documentation to reflect that this constant applies to all recursive file search operations in this class.