@@ -21,10 +21,10 @@ import WinSDK
2121@_spi ( Internal)
2222public struct FileIterator : Sequence , IteratorProtocol {
2323
24- /// Name of the suppression file to look for.
24+ /// Name of the ignore file to look for.
2525 /// The presence of this file in a directory will cause the formatter
2626 /// 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 "
2828
2929 /// List of file and directory URLs to iterate over.
3030 private let urls : [ URL ]
@@ -62,7 +62,7 @@ public struct FileIterator: Sequence, IteratorProtocol {
6262 /// - workingDirectory: `URL` that indicates the current working directory. Used for testing.
6363 public init ( urls: [ URL ] , followSymlinks: Bool , workingDirectory: URL = URL ( fileURLWithPath: " . " ) ) {
6464 self . workingDirectory = workingDirectory
65- self . urls = urls
65+ self . urls = urls. filter ( inputShouldBeProcessed ( at : ) )
6666 self . urlIterator = self . urls. makeIterator ( )
6767 self . followSymlinks = followSymlinks
6868 }
@@ -97,8 +97,8 @@ public struct FileIterator: Sequence, IteratorProtocol {
9797 fallthrough
9898
9999 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) {
102102 continue
103103 }
104104
@@ -189,3 +189,37 @@ private func fileType(at url: URL) -> FileAttributeType? {
189189 // Linux.
190190 return try ? FileManager . default. attributesOfItem ( atPath: url. path) [ . type] as? FileAttributeType
191191}
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