@@ -15,7 +15,7 @@ import Foundation
1515/// A file that describes which files and directories should be ignored by the formatter.
1616/// In the future, this file may contain complex rules for ignoring files, based
1717/// on pattern matching file paths.
18- ///
18+ ///
1919/// Currently, the only valid content for an ignore file is a single asterisk "*",
2020/// optionally surrounded by whitespace.
2121public class IgnoreFile {
@@ -26,18 +26,30 @@ public class IgnoreFile {
2626
2727 /// Errors that can be thrown by the IgnoreFile initializer.
2828 public enum Error : Swift . Error {
29- /// Error thrown when an ignore file has invalid content.
30- case invalidContent( URL )
29+ /// Error thrown when initialising with invalid content.
30+ case invalidContent
31+
32+ /// Error thrown when we fail to initialise with the given URL.
33+ case invalidFile( URL , Swift . Error )
34+ }
35+
36+ /// Create an instance from a string.
37+ /// Returns nil if the content is not valid.
38+ public init ( _ content: String ) throws {
39+ guard content. trimmingCharacters ( in: . whitespacesAndNewlines) == " * " else {
40+ throw Error . invalidContent
41+ }
3142 }
3243
3344 /// Create an instance from the contents of the file at the given URL.
3445 /// Throws an error if the file content can't be read, or is not valid.
35- public init ( contentsOf url: URL ) throws {
36- let content = try String ( contentsOf: url, encoding: . utf8)
37- guard content. trimmingCharacters ( in: . whitespacesAndNewlines) == " * " else {
38- throw Error . invalidContent ( url)
39- }
40- }
46+ public convenience init ( contentsOf url: URL ) throws {
47+ do {
48+ try self . init ( try String ( contentsOf: url, encoding: . utf8) )
49+ } catch {
50+ throw Error . invalidFile ( url, error)
51+ }
52+ }
4153
4254 /// Create an instance for the given directory, if a valid
4355 /// ignore file with the standard name is found in that directory.
@@ -47,35 +59,41 @@ public class IgnoreFile {
4759 /// Note that this initializer does not search parent directories for ignore files.
4860 public convenience init ? ( forDirectory directory: URL ) throws {
4961 let url = directory. appendingPathComponent ( IgnoreFile . fileName)
50- guard FileManager . default. isReadableFile ( atPath: url. path) else {
51- return nil
52- }
5362
54- try self . init ( contentsOf: url)
63+ do {
64+ try self . init ( contentsOf: url)
65+ } catch {
66+ if case let Error . invalidFile( _, underlying) = error, ( underlying as NSError ) . domain == NSCocoaErrorDomain,
67+ ( underlying as NSError ) . code == NSFileReadNoSuchFileError
68+ {
69+ return nil
70+ }
71+ throw error
72+ }
5573 }
5674
5775 /// Create an instance to use for the given URL.
5876 /// We search for an ignore file starting from the given URL's container,
5977 /// and moving up the directory tree, until we reach the root directory.
6078 /// Returns nil if no ignore file is found.
61- /// Throws an error if an invalid ignore file is found somewhere
79+ /// Throws an error if an invalid ignore file is found somewhere
6280 /// in the directory tree.
6381 ///
6482 /// Note that we start the search from the given URL's **container**,
6583 /// not the URL itself; the URL passed in is expected to be for a file.
6684 /// If you pass a directory URL, the search will not include the contents
6785 /// of that directory.
6886 public convenience init ? ( for url: URL ) throws {
69- var containingDirectory = url. absoluteURL. standardized
70- repeat {
71- containingDirectory. deleteLastPathComponent ( )
72- let url = containingDirectory. appendingPathComponent ( IgnoreFile . fileName)
73- if FileManager . default. isReadableFile ( atPath: url. path) {
74- try self . init ( contentsOf: url)
75- return
76- }
77- } while !containingDirectory. isRoot
78- return nil
87+ var containingDirectory = url. absoluteURL. standardized
88+ repeat {
89+ containingDirectory. deleteLastPathComponent ( )
90+ let url = containingDirectory. appendingPathComponent ( IgnoreFile . fileName)
91+ if FileManager . default. isReadableFile ( atPath: url. path) {
92+ try self . init ( contentsOf: url)
93+ return
94+ }
95+ } while !containingDirectory. isRoot
96+ return nil
7997 }
8098
8199 /// Should the given URL be processed?
@@ -85,9 +103,9 @@ public class IgnoreFile {
85103 return false
86104 }
87105
88- /// Returns true if the name of the given URL matches
106+ /// Returns true if the name of the given URL matches
89107 /// the standard ignore file name.
90108 public static func isStandardIgnoreFile( _ url: URL ) -> Bool {
91109 return url. lastPathComponent == fileName
92110 }
93- }
111+ }
0 commit comments