From 39e72625651252345be24d7f86319d6cdff0a17a Mon Sep 17 00:00:00 2001 From: disc0infern0 <007gnail@gmail.com> Date: Sat, 14 Feb 2026 09:48:35 +0000 Subject: [PATCH 1/2] Update deprecated file APIs --- Sources/Files.swift | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Sources/Files.swift b/Sources/Files.swift index aede19e..8ab3882 100644 --- a/Sources/Files.swift +++ b/Sources/Files.swift @@ -79,6 +79,19 @@ public extension Location { return components.dropLast().joined() } + /// Disco: The name of the location, excluding its `extension`. + var baseName: String { + get { + let components = name.split(separator: ".") + guard components.count > 1 else { return name } + return components.dropLast().joined() + } + set { + try? rename(to: newValue, keepExtension: true) + } + } + + /// The file extension of the item at the location. var `extension`: String? { let components = name.split(separator: ".") @@ -406,9 +419,15 @@ public extension File { func append(_ data: Data) throws { do { let handle = try FileHandle(forWritingTo: url) - handle.seekToEndOfFile() - handle.write(data) - handle.closeFile() + if #available(macOS 10.15.4, *) { + _ = try handle.seekToEnd() + try handle.write(contentsOf: data) + try handle.close() + } else { + handle.seekToEndOfFile() + handle.write(data) + handle.closeFile() + } } catch { throw WriteError(path: path, reason: .writeFailed(error)) } @@ -466,7 +485,7 @@ import AppKit public extension File { /// Open the file. func open() { - NSWorkspace.shared.openFile(path) + NSWorkspace.shared.open(url) } } From 3f79836a26372b83d445f71d77398c93f5f41d0a Mon Sep 17 00:00:00 2001 From: disc0infern0 <007gnail@gmail.com> Date: Tue, 17 Feb 2026 18:18:48 +0000 Subject: [PATCH 2/2] Added a storage property to a new FileLocation protocol, and make File comply with it. Test added to verify it works as intended. --- .gitignore | 69 +----------------- .../contents.xcworkspacedata | 7 ++ .../UserInterfaceState.xcuserstate | Bin 0 -> 23841 bytes .../xcschemes/xcschememanagement.plist | 14 ++++ Package.swift | 2 +- Sources/Files.swift | 13 +++- Tests/FilesTests/FilesTests.swift | 8 ++ 7 files changed, 44 insertions(+), 69 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 .swiftpm/xcode/package.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 .swiftpm/xcode/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/.gitignore b/.gitignore index d32735f..a0090b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,67 +1,2 @@ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## Build generated -build/ -DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xcuserstate -*.xcscmblueprint - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -.build/ -.swiftpm/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output +# macOS +.DS_Store diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..8a8324b4a999f3def2c92a1674f4b4cc495e0ac7 GIT binary patch literal 23841 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 literal 0 HcmV?d00001 diff --git a/.swiftpm/xcode/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8b91339 --- /dev/null +++ b/.swiftpm/xcode/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Files.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Package.swift b/Package.swift index cc7dc34..0557dbb 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:6.2 /** * Files diff --git a/Sources/Files.swift b/Sources/Files.swift index 8ab3882..1b94cf2 100644 --- a/Sources/Files.swift +++ b/Sources/Files.swift @@ -47,6 +47,17 @@ public protocol Location: Equatable, CustomStringConvertible { init(storage: Storage) } +/// Protocol adopted by locations that represent files. +public protocol FileLocation: Location {} + +public extension FileLocation { + /// The file size, in bytes. Returns `0` if the size couldn't be determined. + var size: UInt64 { + let number = storage.attributes[.size] as? NSNumber + return number?.uint64Value ?? 0 + } +} + public extension Location { static func ==(lhs: Self, rhs: Self) -> Bool { return lhs.storage.path == rhs.storage.path @@ -377,7 +388,7 @@ private extension Storage where LocationType == Folder { /// Type that represents a file on disk. You can either reference an existing /// file by initializing an instance with a `path`, or you can create new files /// using the various `createFile...` APIs available on `Folder`. -public struct File: Location { +public struct File: Location, FileLocation { public let storage: Storage public init(storage: Storage) { diff --git a/Tests/FilesTests/FilesTests.swift b/Tests/FilesTests/FilesTests.swift index 040f60e..b32ae73 100644 --- a/Tests/FilesTests/FilesTests.swift +++ b/Tests/FilesTests/FilesTests.swift @@ -197,6 +197,14 @@ class FilesTests: XCTestCase { try assert(nonIntFile.readAsInt(), throwsErrorOfType: ReadError.self) } } + + func testFileSize() { + performTest { + let data = Data("Hello".utf8) + let file = try folder.createFile(named: "size.txt", contents: data) + XCTAssertEqual(file.size, UInt64(data.count)) + } + } func testRenamingFile() { performTest {