@@ -17,10 +17,10 @@ import Foundation
17
17
@_spi ( Internal)
18
18
public struct FileIterator : Sequence , IteratorProtocol {
19
19
20
- /// Name of the suppression file to look for.
20
+ /// Name of the ignore file to look for.
21
21
/// The presence of this file in a directory will cause the formatter
22
22
/// to skip formatting files in that directory and its subdirectories.
23
- private static let suppressionFileName = " .swift-format-ignore "
23
+ fileprivate static let ignoreFileName = " .swift-format-ignore "
24
24
25
25
/// List of file and directory URLs to iterate over.
26
26
private let urls : [ URL ]
@@ -53,7 +53,7 @@ public struct FileIterator: Sequence, IteratorProtocol {
53
53
/// The given URLs may be files or directories. If they are directories, the iterator will recurse
54
54
/// into them.
55
55
public init ( urls: [ URL ] , followSymlinks: Bool ) {
56
- self . urls = urls
56
+ self . urls = urls. filter ( inputShouldBeProcessed ( at : ) )
57
57
self . urlIterator = self . urls. makeIterator ( )
58
58
self . followSymlinks = followSymlinks
59
59
}
@@ -88,8 +88,8 @@ public struct FileIterator: Sequence, IteratorProtocol {
88
88
fallthrough
89
89
90
90
case . typeDirectory:
91
- let suppressionFile = next. appendingPathComponent ( Self . suppressionFileName )
92
- if FileManager . default. fileExists ( atPath: suppressionFile . path) {
91
+ let ignoreFile = next. appendingPathComponent ( Self . ignoreFileName )
92
+ if FileManager . default. fileExists ( atPath: ignoreFile . path) {
93
93
continue
94
94
}
95
95
@@ -179,3 +179,37 @@ private func fileType(at url: URL) -> FileAttributeType? {
179
179
// Linux.
180
180
return try ? FileManager . default. attributesOfItem ( atPath: url. path) [ . type] as? FileAttributeType
181
181
}
182
+
183
+ /// Returns true if the file should be processed.
184
+ /// Directories are always processed.
185
+ /// Other files are processed if there is not a
186
+ /// ignore file in the containing directory or any of its parents.
187
+ private func inputShouldBeProcessed( at url: URL ) -> Bool {
188
+ guard fileType ( at: url) != . typeDirectory else {
189
+ return true
190
+ }
191
+
192
+ var containingDirectory = url. absoluteURL. standardized. deletingLastPathComponent ( )
193
+ repeat {
194
+ containingDirectory. deleteLastPathComponent ( )
195
+ let candidateFile = containingDirectory. appendingPathComponent ( FileIterator . ignoreFileName)
196
+ if FileManager . default. isReadableFile ( atPath: candidateFile. path) {
197
+ return false
198
+ }
199
+ } while !containingDirectory. isRoot
200
+ return true
201
+ }
202
+
203
+ fileprivate extension URL {
204
+ var isRoot : Bool {
205
+ #if os(Windows)
206
+ // 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.
207
+ // https://github.com/swiftlang/swift-format/issues/844
208
+ return self . pathComponents. count <= 1
209
+ #else
210
+ // On Linux, we may end up with an string for the path due to https://github.com/swiftlang/swift-foundation/issues/980
211
+ // TODO: Remove the check for "" once https://github.com/swiftlang/swift-foundation/issues/980 is fixed.
212
+ return self . path == " / " || self . path == " "
213
+ #endif
214
+ }
215
+ }
0 commit comments