@@ -17,10 +17,10 @@ import Foundation
1717@_spi ( Internal)
1818public struct FileIterator : Sequence , IteratorProtocol {
1919
20- /// Name of the suppression file to look for.
20+ /// Name of the ignore file to look for.
2121 /// The presence of this file in a directory will cause the formatter
2222 /// 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 "
2424
2525 /// List of file and directory URLs to iterate over.
2626 private let urls : [ URL ]
@@ -53,7 +53,7 @@ public struct FileIterator: Sequence, IteratorProtocol {
5353 /// The given URLs may be files or directories. If they are directories, the iterator will recurse
5454 /// into them.
5555 public init ( urls: [ URL ] , followSymlinks: Bool ) {
56- self . urls = urls
56+ self . urls = urls. filter ( inputShouldBeProcessed ( at : ) )
5757 self . urlIterator = self . urls. makeIterator ( )
5858 self . followSymlinks = followSymlinks
5959 }
@@ -88,8 +88,8 @@ public struct FileIterator: Sequence, IteratorProtocol {
8888 fallthrough
8989
9090 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) {
9393 continue
9494 }
9595
@@ -179,3 +179,37 @@ private func fileType(at url: URL) -> FileAttributeType? {
179179 // Linux.
180180 return try ? FileManager . default. attributesOfItem ( atPath: url. path) [ . type] as? FileAttributeType
181181}
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