From a423a4b3dcef7777f66a9d1cec42436e3c71b57e Mon Sep 17 00:00:00 2001 From: Natan Rolnik Date: Wed, 6 Sep 2023 00:10:43 +0300 Subject: [PATCH 1/3] Add failing test for hidden files alongside regular directories --- Tests/PathTests/PathTests+ls().swift | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Tests/PathTests/PathTests+ls().swift b/Tests/PathTests/PathTests+ls().swift index 58072d3..06e19b8 100644 --- a/Tests/PathTests/PathTests+ls().swift +++ b/Tests/PathTests/PathTests+ls().swift @@ -157,6 +157,31 @@ extension PathTests { #endif } } + + func testFindHiddenFileAlongsideDirectory() throws { + try Path.mktemp { tmpdir in + let dotFoo = try tmpdir.join(".foo.txt").touch() + let tmpDotA = try tmpdir.join(".a").mkdir() + let tmpDotAFoo = try tmpdir.join(".a").join("foo.txt").touch() + let tmpB = try tmpdir.b.mkdir() + let tmpBFoo = try tmpB.join("foo.txt").touch() + let dotBar = try tmpB.join(".bar.txt").touch() + let tmpC = try tmpdir.b.c.mkdir() + let bar = try tmpC.join("bar.txt").touch() + + XCTAssertEqual( + Set(tmpdir.find().hidden(true)), + Set([dotFoo,tmpDotA,tmpDotAFoo,tmpB,tmpBFoo,tmpC,dotBar,bar]), + relativeTo: tmpdir) + + #if !os(Linux) || swift(>=5) + XCTAssertEqual( + Set(tmpdir.find().hidden(false)), + Set([tmpB,tmpBFoo,tmpC,bar]), + relativeTo: tmpdir) + #endif + } + } func testFindExtension() throws { try Path.mktemp { tmpdir in From 061cec0b2c72375e03de6e1585d3683efa1219f8 Mon Sep 17 00:00:00 2001 From: Natan Rolnik Date: Wed, 6 Sep 2023 00:12:17 +0300 Subject: [PATCH 2/3] Fix Path.Finder use case when a hidden file and a regular subdirectory are in the same level Also update `isDirectory` usage to be more efficient, by passing `.isDirectoryKey` to `FileManager.DirectoryEnumerator` initialization. --- Sources/Path+ls.swift | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index 0b627a3..c4a6173 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -5,7 +5,7 @@ public extension Path { class Finder { fileprivate init(path: Path) { self.path = path - self.enumerator = FileManager.default.enumerator(atPath: path.string) + self.enumerator = FileManager.default.enumerator(at: path.url, includingPropertiesForKeys: [.isDirectoryKey]) } /// The `path` find operations operate on. @@ -42,8 +42,8 @@ extension Path.Finder: Sequence, IteratorProtocol { guard let enumerator = enumerator else { return nil } - while let relativePath = enumerator.nextObject() as? String { - let path = self.path/relativePath + while let url = enumerator.nextObject() as? URL { + guard let path = Path(url: url) else { continue } #if !os(Linux) || swift(>=5.0) if enumerator.level > depth.upperBound { @@ -55,7 +55,9 @@ extension Path.Finder: Sequence, IteratorProtocol { } if !hidden, path.basename().hasPrefix(".") { - enumerator.skipDescendants() + if url.isDirectory { + enumerator.skipDescendants() + } continue } #endif @@ -217,3 +219,9 @@ public enum ListDirectoryOptions { /// Lists hidden files also case a } + +private extension URL { + var isDirectory: Bool { + (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true + } +} From a9555949a59ecf5903c827561a662390c6edbe80 Mon Sep 17 00:00:00 2001 From: Natan Rolnik Date: Sun, 10 Sep 2023 01:05:13 +0300 Subject: [PATCH 3/3] Fix Swift 5.0 compilation --- Sources/Path+ls.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index c4a6173..6b3bef6 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -222,6 +222,6 @@ public enum ListDirectoryOptions { private extension URL { var isDirectory: Bool { - (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true + return (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true } }