@@ -21,10 +21,10 @@ import WinSDK
21
21
@_spi ( Internal)
22
22
public struct FileIterator : Sequence , IteratorProtocol {
23
23
24
- /// Name of the suppression file to look for.
24
+ /// Name of the ignore file to look for.
25
25
/// The presence of this file in a directory will cause the formatter
26
26
/// to skip formatting files in that directory and its subdirectories.
27
- private static let suppressionFileName = " .swift-format-ignore "
27
+ fileprivate static let ignoreFileName = " .swift-format-ignore "
28
28
29
29
/// List of file and directory URLs to iterate over.
30
30
private let urls : [ URL ]
@@ -62,7 +62,7 @@ public struct FileIterator: Sequence, IteratorProtocol {
62
62
/// - workingDirectory: `URL` that indicates the current working directory. Used for testing.
63
63
public init ( urls: [ URL ] , followSymlinks: Bool , workingDirectory: URL = URL ( fileURLWithPath: " . " ) ) {
64
64
self . workingDirectory = workingDirectory
65
- self . urls = urls
65
+ self . urls = urls. filter ( inputShouldBeProcessed ( at : ) )
66
66
self . urlIterator = self . urls. makeIterator ( )
67
67
self . followSymlinks = followSymlinks
68
68
}
@@ -97,8 +97,8 @@ public struct FileIterator: Sequence, IteratorProtocol {
97
97
fallthrough
98
98
99
99
case . typeDirectory:
100
- let suppressionFile = next. appendingPathComponent ( Self . suppressionFileName )
101
- if FileManager . default. fileExists ( atPath: suppressionFile . path) {
100
+ let ignoreFile = next. appendingPathComponent ( Self . ignoreFileName )
101
+ if FileManager . default. fileExists ( atPath: ignoreFile . path) {
102
102
continue
103
103
}
104
104
@@ -189,3 +189,37 @@ private func fileType(at url: URL) -> FileAttributeType? {
189
189
// Linux.
190
190
return try ? FileManager . default. attributesOfItem ( atPath: url. path) [ . type] as? FileAttributeType
191
191
}
192
+
193
+ /// Returns true if the file should be processed.
194
+ /// Directories are always processed.
195
+ /// Other files are processed if there is not a
196
+ /// ignore file in the containing directory or any of its parents.
197
+ private func inputShouldBeProcessed( at url: URL ) -> Bool {
198
+ guard fileType ( at: url) != . typeDirectory else {
199
+ return true
200
+ }
201
+
202
+ var containingDirectory = url. absoluteURL. standardized. deletingLastPathComponent ( )
203
+ repeat {
204
+ containingDirectory. deleteLastPathComponent ( )
205
+ let candidateFile = containingDirectory. appendingPathComponent ( FileIterator . ignoreFileName)
206
+ if FileManager . default. isReadableFile ( atPath: candidateFile. path) {
207
+ return false
208
+ }
209
+ } while !containingDirectory. isRoot
210
+ return true
211
+ }
212
+
213
+ fileprivate extension URL {
214
+ var isRoot : Bool {
215
+ #if os(Windows)
216
+ // FIXME: We should call into Windows' native check to check if this path is a root once https://github.com/swiftlang/swift-foundation/issues/976 is fixed.
217
+ // https://github.com/swiftlang/swift-format/issues/844
218
+ return self . pathComponents. count <= 1
219
+ #else
220
+ // On Linux, we may end up with an string for the path due to https://github.com/swiftlang/swift-foundation/issues/980
221
+ // TODO: Remove the check for "" once https://github.com/swiftlang/swift-foundation/issues/980 is fixed.
222
+ return self . path == " / " || self . path == " "
223
+ #endif
224
+ }
225
+ }
0 commit comments