Skip to content

Commit

Permalink
Introduce FileManager.uniqueFile to generate file with unique name
Browse files Browse the repository at this point in the history
  • Loading branch information
Alkenso committed Dec 19, 2024
1 parent 3f349ba commit 37e8395
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,31 @@ extension FileManager {
}
}

extension FileManager {
public func uniqueFile(in directory: URL, _ nameGenerator: (Int) -> String) -> URL {
for attempt in 0..<Int.max {
let name = nameGenerator(attempt)
let location = directory.appendingPathComponent(name)
guard FileManager.default.fileExists(at: location) else { return location }
}

// Should be impossible case.
return directory.appendingPathComponent(nameGenerator(-1) + ".invalid")
}

public func uniqueFile(_ name: String, in directory: URL) -> URL {
let pathExtension = name.pathExtension
return uniqueFile(in: directory) { attempt in
guard attempt > 0 else { return name }
var nextName = "\(name.deletingPathExtension)_\(attempt)"
if !pathExtension.isEmpty {
nextName += ".\(pathExtension)"
}
return nextName
}
}
}

extension stat {
public var fileType: URLFileResourceType {
URLFileResourceType(mode: st_mode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,31 @@ class FileManagerExtensionsTests: XCTestCase {
try FileManager.default.removeXattr(at: file, name: "xa1")
XCTAssertEqual(try FileManager.default.listXattr(at: file), ["xa2"])
}

func test_uniqueFile() {
let fm = FileManager.default
func createFile(_ name: String) -> Bool {
fm.createFile(atPath: tempDir.location.appendingPathComponent(name).path, contents: .random(20))
}

XCTAssertEqual(fm.uniqueFile("test.foo", in: tempDir.location).lastPathComponent, "test.foo")
// Ensure it is not created.
XCTAssertEqual(fm.uniqueFile("test.foo", in: tempDir.location).lastPathComponent, "test.foo")

XCTAssertTrue(createFile("test.foo"))
XCTAssertEqual(fm.uniqueFile("test.foo", in: tempDir.location).lastPathComponent, "test_1.foo")

XCTAssertTrue(createFile("test.foo.bar"))
XCTAssertEqual(fm.uniqueFile("test.foo.bar", in: tempDir.location).lastPathComponent, "test.foo_1.bar")

XCTAssertEqual(fm.uniqueFile("test", in: tempDir.location).lastPathComponent, "test")
XCTAssertTrue(createFile("test"))
XCTAssertTrue(createFile("test_1"))
XCTAssertTrue(createFile("test_3"))
XCTAssertEqual(fm.uniqueFile("test", in: tempDir.location).lastPathComponent, "test_2")

XCTAssertEqual(fm.uniqueFile("dir/", in: tempDir.location).lastPathComponent, "dir")
XCTAssertTrue(createFile("dir"))
XCTAssertEqual(fm.uniqueFile("dir/", in: tempDir.location).lastPathComponent, "dir_1")
}
}

0 comments on commit 37e8395

Please sign in to comment.