1
+ //===----------------------------------------------------------------------===//
2
+ //
3
+ // This source file is part of the Swift.org open source project
4
+ //
5
+ // Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6
+ // Licensed under Apache License v2.0 with Runtime Library Exception
7
+ //
8
+ // See https://swift.org/LICENSE.txt for license information
9
+ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
+ //
11
+ //===----------------------------------------------------------------------===//
12
+
13
+ import Foundation
14
+
15
+ public class IgnoreFile {
16
+ /// Name of the ignore file to look for.
17
+ /// The presence of this file in a directory will cause the formatter
18
+ /// to skip formatting files in that directory and its subdirectories.
19
+ fileprivate static let fileName = " .swift-format-ignore "
20
+
21
+ /// Errors that can be thrown by the IgnoreFile initializer.
22
+ public enum Error : Swift . Error {
23
+ /// Error thrown when an ignore file has invalid content.
24
+ case invalidContent( URL )
25
+ }
26
+
27
+ /// Create an instance from the contents of the file at the given URL.
28
+ /// Throws an error if the file content can't be read, or is not valid.
29
+ public init ( contentsOf url: URL ) throws {
30
+ let content = try String ( contentsOf: url, encoding: . utf8)
31
+ guard content. trimmingCharacters ( in: . whitespacesAndNewlines) == " * " else {
32
+ throw Error . invalidContent ( url)
33
+ }
34
+ }
35
+
36
+ /// Create an instance for the given directory, if a valid
37
+ /// ignore file with the standard name is found in that directory.
38
+ /// Returns nil if no ignore file is found.
39
+ /// Throws an error if an invalid ignore file is found.
40
+ ///
41
+ /// Note that this initializer does not search parent directories for ignore files.
42
+ public convenience init ? ( forDirectory directory: URL ) throws {
43
+ let url = directory. appendingPathComponent ( IgnoreFile . fileName)
44
+ guard FileManager . default. isReadableFile ( atPath: url. path) else {
45
+ return nil
46
+ }
47
+
48
+ try self . init ( contentsOf: url)
49
+ }
50
+
51
+ /// Create an instance to use for the given URL.
52
+ /// We search for an ignore file starting from the given URL's container,
53
+ /// and moving up the directory tree, until we reach the root directory.
54
+ /// Returns nil if no ignore file is found.
55
+ /// Throws an error if an invalid ignore file is found somewhere
56
+ /// in the directory tree.
57
+ public convenience init ? ( for url: URL ) throws {
58
+ var containingDirectory = url. absoluteURL. standardized
59
+ repeat {
60
+ containingDirectory. deleteLastPathComponent ( )
61
+ let url = containingDirectory. appendingPathComponent ( IgnoreFile . fileName)
62
+ if FileManager . default. isReadableFile ( atPath: url. path) {
63
+ try self . init ( contentsOf: url)
64
+ return
65
+ }
66
+ } while !containingDirectory. isRoot
67
+ return nil
68
+ }
69
+
70
+ /// Should the given URL be processed?
71
+ /// Currently the only valid ignore file content is "*",
72
+ /// which means that all files should be ignored.
73
+ func shouldProcess( _ url: URL ) -> Bool {
74
+ return false
75
+ }
76
+
77
+ /// Returns true if the name of the given URL matches
78
+ /// the standard ignore file name.
79
+ public static func isStandardIgnoreFile( _ url: URL ) -> Bool {
80
+ return url. lastPathComponent == fileName
81
+ }
82
+ }
0 commit comments