From 6ce151665dbb67e8ffc88fb461797d7af5cd7823 Mon Sep 17 00:00:00 2001 From: Andrew Roan Date: Fri, 23 Feb 2024 15:12:13 -0600 Subject: [PATCH 1/4] Increase minimum Swift version to 5.9, increase minimum platform versions to iOS v15, add visionOS platform feature/system-FilePath --- .devcontainer/devcontainer.json | 2 +- Package.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a010156..d88370d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "PathKit", - "image": "swift:5.8", + "image": "swift:5.9", "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installZsh": "false", diff --git a/Package.swift b/Package.swift index da1f812..25a633a 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,9 @@ -// swift-tools-version:5.8 +// swift-tools-version:5.9 import PackageDescription let package = Package( name: "PathKit", - platforms: [.iOS(.v12), .macOS(.v10_13), .watchOS(.v4), .tvOS(.v12), .macCatalyst(.v13)], + platforms: [.iOS(.v15), .macOS(.v12), .watchOS(.v8), .tvOS(.v15), .macCatalyst(.v15), .visionOS(.v1)], products: [ .library(name: "PathKit", targets: ["PathKit"]), ], From ce0a53f42ecb205ba8b4c9e24b7c458de4bbe776 Mon Sep 17 00:00:00 2001 From: Andrew Roan Date: Fri, 23 Feb 2024 15:13:35 -0600 Subject: [PATCH 2/4] Conditionally use SystemPackage when System is not available (Linux, Windows, etc) feature/system-FilePath --- Package.resolved | 14 ++++++++++++++ Package.swift | 9 +++++++++ 2 files changed, 23 insertions(+) create mode 100644 Package.resolved diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..868d9cf --- /dev/null +++ b/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", + "version" : "1.2.1" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index 25a633a..9cb0e62 100644 --- a/Package.swift +++ b/Package.swift @@ -22,6 +22,15 @@ let package = Package( ] ) +#if !canImport(System) + package.dependencies += [.package(url: "https://github.com/apple/swift-system.git", from: "1.2.1")] + for target in package.targets { + if target.name == "PathKit" { + target.dependencies += [Target.Dependency.product(name: "SystemPackage", package: "swift-system")] + } + } +#endif + extension [SwiftSetting] { static let swiftSix: [SwiftSetting] = [ .enableUpcomingFeature("BareSlashRegexLiterals"), From 2a0754c35f6dc1285010357b5786fb13357f8b75 Mon Sep 17 00:00:00 2001 From: Andrew Roan Date: Fri, 23 Feb 2024 15:14:18 -0600 Subject: [PATCH 3/4] Update Path to use System.FilePath as underlying type instead of String feature/system-FilePath --- .../PathKit/Internal/Array+FullSlice.swift | 18 -------- Sources/PathKit/Operators.swift | 8 ++-- Sources/PathKit/Path+Components.swift | 17 ++++---- Sources/PathKit/Path+FileInfo.swift | 2 +- Sources/PathKit/Path+PathInfo.swift | 4 +- Sources/PathKit/Path.swift | 42 ++++++++++++++----- 6 files changed, 47 insertions(+), 44 deletions(-) delete mode 100644 Sources/PathKit/Internal/Array+FullSlice.swift diff --git a/Sources/PathKit/Internal/Array+FullSlice.swift b/Sources/PathKit/Internal/Array+FullSlice.swift deleted file mode 100644 index 98fa962..0000000 --- a/Sources/PathKit/Internal/Array+FullSlice.swift +++ /dev/null @@ -1,18 +0,0 @@ -// Array+FullSlice.swift -// PathKit -// -// Copyright (c) 2014, Kyle Fuller -// All rights reserved. -// Version 1.0.1 -// -// Copyright © 2024 MFB Technologies, Inc. All rights reserved. -// After Version 1.0.1 -// -// This source code is licensed under the BSD-2-Clause License found in the -// LICENSE file in the root directory of this source tree. - -extension Array { - var fullSlice: ArraySlice { - self[indices.suffix(from: 0)] - } -} diff --git a/Sources/PathKit/Operators.swift b/Sources/PathKit/Operators.swift index efd62e9..bfecd45 100644 --- a/Sources/PathKit/Operators.swift +++ b/Sources/PathKit/Operators.swift @@ -31,8 +31,8 @@ func + (lhs: String, rhs: String) -> Path { // Absolute paths replace relative paths return Path(rhs) } else { - var lSlice = NSString(string: lhs).pathComponents.fullSlice - var rSlice = NSString(string: rhs).pathComponents.fullSlice + var lSlice = ArraySlice(NSString(string: lhs).pathComponents) + var rSlice = ArraySlice(NSString(string: rhs).pathComponents) // Get rid of trailing "/" at the left side if lSlice.count > 1, lSlice.last == Path.separator { @@ -40,8 +40,8 @@ func + (lhs: String, rhs: String) -> Path { } // Advance after the first relevant "." - lSlice = lSlice.filter { $0 != "." }.fullSlice - rSlice = rSlice.filter { $0 != "." }.fullSlice + lSlice = lSlice.filter { $0 != "." } + rSlice = rSlice.filter { $0 != "." } // Eats up trailing components of the left and leading ".." of the right side while lSlice.last != "..", !lSlice.isEmpty, rSlice.first == ".." { diff --git a/Sources/PathKit/Path+Components.swift b/Sources/PathKit/Path+Components.swift index 5cbdc87..d5e7220 100644 --- a/Sources/PathKit/Path+Components.swift +++ b/Sources/PathKit/Path+Components.swift @@ -19,7 +19,7 @@ extension Path { /// - Returns: the last path component /// public var lastComponent: String { - NSString(string: path).lastPathComponent + filePath.lastComponent?.string ?? "" } /// The last path component without file extension @@ -29,7 +29,7 @@ extension Path { /// - Returns: the last path component without file extension /// public var lastComponentWithoutExtension: String { - NSString(string: lastComponent).deletingPathExtension + filePath.stem ?? "" } /// Splits the string representation on the directory separator. @@ -38,7 +38,11 @@ extension Path { /// - Returns: all path components /// public var components: [String] { - NSString(string: path).pathComponents + if let root = filePath.root { + CollectionOfOne(root.string) + filePath.components.map(\.string) + } else { + filePath.components.map(\.string) + } } /// The file extension behind the last dot of the last component. @@ -46,11 +50,6 @@ extension Path { /// - Returns: the file extension /// public var `extension`: String? { - let pathExtension = NSString(string: path).pathExtension - if pathExtension.isEmpty { - return nil - } - - return pathExtension + filePath.extension } } diff --git a/Sources/PathKit/Path+FileInfo.swift b/Sources/PathKit/Path+FileInfo.swift index d2fa8c2..5fc27ad 100644 --- a/Sources/PathKit/Path+FileInfo.swift +++ b/Sources/PathKit/Path+FileInfo.swift @@ -59,7 +59,7 @@ extension Path { /// public var isSymlink: Bool { do { - try Path.fileManager.destinationOfSymbolicLink(atPath: path) + _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) return true } catch { return false diff --git a/Sources/PathKit/Path+PathInfo.swift b/Sources/PathKit/Path+PathInfo.swift index 9cc1b8e..81dc525 100644 --- a/Sources/PathKit/Path+PathInfo.swift +++ b/Sources/PathKit/Path+PathInfo.swift @@ -19,7 +19,7 @@ extension Path { /// - Returns: `true` iff the path begins with a slash /// public var isAbsolute: Bool { - path.hasPrefix(Path.separator) + filePath.isAbsolute } /// Test whether a path is relative. @@ -27,7 +27,7 @@ extension Path { /// - Returns: `true` iff a path is relative (not absolute) /// public var isRelative: Bool { - !isAbsolute + filePath.isRelative } /// Concatenates relative paths to the current directory and derives the normalized path diff --git a/Sources/PathKit/Path.swift b/Sources/PathKit/Path.swift index e66baee..f68e3d7 100644 --- a/Sources/PathKit/Path.swift +++ b/Sources/PathKit/Path.swift @@ -12,14 +12,24 @@ // LICENSE file in the root directory of this source tree. import Foundation +#if canImport(System) + import System +#else + import SystemPackage + + extension FilePath: @unchecked Sendable {} +#endif /// Represents a filesystem path. public struct Path: Sendable { /// The character used by the OS to separate two path elements public static let separator = "/" + /// The underlying `FilePath` representation + public let filePath: FilePath + /// The underlying string representation - let path: String + var path: String { filePath.string } static let fileManager = FileManager.default @@ -27,6 +37,16 @@ public struct Path: Sendable { // MARK: Init + init(filePath: FilePath, fileSystemInfo: any FileSystemInfo) { + self.filePath = filePath + self.fileSystemInfo = fileSystemInfo + } + + /// Create a Path from a `System.FilePath` + public init(filePath: FilePath) { + self.init(filePath: filePath, fileSystemInfo: DefaultFileSystemInfo()) + } + public init() { self.init("") } @@ -37,8 +57,7 @@ public struct Path: Sendable { } init(_ path: String, fileSystemInfo: any FileSystemInfo) { - self.path = path - self.fileSystemInfo = fileSystemInfo + self.init(filePath: FilePath(path), fileSystemInfo: fileSystemInfo) } init(fileSystemInfo: any FileSystemInfo) { @@ -79,24 +98,27 @@ extension Path: ExpressibleByStringLiteral { extension Path: CustomStringConvertible { public var description: String { - path + filePath.description + } +} + +extension Path: CustomDebugStringConvertible { + public var debugDescription: String { + filePath.debugDescription } } extension Path: Equatable { /// Determines if two paths are identical - /// - /// - Note: The comparison is string-based. Be aware that two different paths (foo.txt and - /// ./foo.txt) can refer to the same file. - /// public static func == (lhs: Path, rhs: Path) -> Bool { - lhs.path == rhs.path + lhs.filePath == rhs.filePath } } extension Path: Hashable { public func hash(into hasher: inout Hasher) { - hasher.combine(path.hashValue) + hasher.combine(filePath.hashValue) + hasher.combine(ObjectIdentifier(Self.self)) } } From c6b6590f24dc41ef75dc2eb4b87c9e9c0aa88100 Mon Sep 17 00:00:00 2001 From: Andrew Roan Date: Fri, 23 Feb 2024 15:28:30 -0600 Subject: [PATCH 4/4] Remove Xcode 14.3.1, Swift 5.8.1 CI strategy feature/system-FilePath --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1082912..63cb6fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,8 @@ jobs: environment: default strategy: matrix: - xcode: ['14.3.1', '15.2'] - # Swift: 5.8.1 , 5.9.2 + xcode: ['15.2'] + # Swift: 5.9.2 steps: - uses: actions/checkout@v3 - name: Select Xcode ${{ matrix.xcode }}