-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
New Issue Checklist
- Updated SwiftLint to the latest version
- I searched for existing GitHub issues
Describe the bug
I noticed that our SwiftLint build phase was taking a really long time to run in our project, even when no code had changed. Digging further, on my machine with our project, it was taking 30s to run without any changes. What is even stranger is that it was only taking 10s more to run without any cache at all.
Using the time profiler in instruments, I found that most of that time was taken up looking for excluded files in Glob.expandGlobstar. It appears that every excluded pattern causes SwiftLint to retrieve a recursive list of subpaths. The documentation for FileManager.subpathsOfDirectory(atPath:) calls this out as a potential performance issue.
Complete output when running SwiftLint, including the stack trace and command used
$ swiftlint lint --quietEnvironment
- SwiftLint version: 0.52.2 (also tested latest master)
- Installation method used: mint (also tested from source and running the command directly)
- Paste your configuration file:
Here is an abbreviated list of our excluded patterns:
- ManualFrameworks
- vendor
- fastlane
- SourceryOutput
- Generated
- templates
- "**/.build"
- "**/*.generated.swift"
- "**/LocalizedStrings.swift"- Are you using nested configurations? No
- Which Xcode version are you using (check
xcodebuild -version)? 14.3.1 and 15.0 beta 8
I have a proof of concept that matches files based on regular expressions (converted from the glob syntax) and uses a directory enumerator to test for matches. This has a few advantages: First, the directory hierarchy can be scanned once regardless of how many include and exclude patterns are used. Second, if a directly is excluded (or not included) it can be skipped entirely no need to even scan the directory contents. We can also re-use the attributes from the enumerator to test if it is a file or folder and avoid calling fileExists(atPath:,isDirectory:).
With this change, I'm seeing the fully cached time go from 30s to 10s.
This seems to be a fairly common technique. Some scripting languages even have the glob to regex converter built in. It also appears to be what SwiftFormat does.
Before I clean this up and submit a PR, I wanted to make sure I wasn't missing anything.