Skip to content

Commit fb8b06f

Browse files
committed
Filter urls to remove ignored ones.
1 parent 7b22d51 commit fb8b06f

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

Sources/SwiftFormat/Utilities/FileIterator.swift

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import WinSDK
2121
@_spi(Internal)
2222
public 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

Comments
 (0)