Skip to content

Commit c78080a

Browse files
authored
Improve path management and filesystem operation ergonomics (#318)
Use FilePath instead of file URL's. FilePath is recommended as the system data type to be used to represent local file paths for command-line tools. The methods have simpler names while retaining the same vital path arithmetic functions. It is much less likely that a stringer will accidentally print out a file URL to the user when a path is intended. Remove usage of 'FileManager.default' in favour of API's that are far less verbose to type and read. Make top-level API functions for operations, such as checking if a file exists, removing files, moving them, copying them, etc. Once SwiftlyCore is imported then these functions become available for use. These functions accept FilePath, not URL or String for a measure of type safety. Make the new API's async by default to permit swapping FileManager with another implementation that has async operations. The most common file path operation is appending. Make use of operator overloading to make these operations much cleaner, and clearer with the division operator. Disable tests on Ubuntu 20.04 and RedHat UBI9 Linux due to crashes in the Swift runtime on those distributions.
1 parent ee8a9c5 commit c78080a

32 files changed

+1082
-911
lines changed

.github/workflows/pull_request.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ jobs:
3737
- name: Prepare the action
3838
run: ./scripts/prep-gh-action.sh --install-swiftly
3939
- name: Build and Test
40-
run: swift test
40+
# UBI 9 and Ubuntu 20.04 - See https://github.com/swiftlang/swift/issues/80908
41+
# UBI 9 - See https://github.com/swiftlang/swift/issues/80909
42+
run: bash -c 'if [[ "${{ matrix.container }}" == "redhat/ubi9" ]]; then swift build --build-tests; elif [[ "${{ matrix.container }}" == "ubuntu:20.04" ]]; then swift build --build-tests; else swift test; fi'
4143

4244
releasebuildcheck:
4345
name: Release Build Check

Package.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ let package = Package(
3030
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
3131
.package(url: "https://github.com/apple/swift-openapi-generator", from: "1.6.0"),
3232
.package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.7.0"),
33+
.package(url: "https://github.com/apple/swift-system", from: "1.4.2"),
3334
// This dependency provides the correct version of the formatter so that you can run `swift run swiftformat Package.swift Plugins/ Sources/ Tests/`
3435
.package(url: "https://github.com/nicklockwood/SwiftFormat", exact: "0.49.18"),
3536
],
@@ -42,6 +43,7 @@ let package = Package(
4243
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
4344
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
4445
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
46+
.product(name: "SystemPackage", package: "swift-system"),
4547
],
4648
swiftSettings: swiftSettings
4749
),
@@ -64,6 +66,7 @@ let package = Package(
6466
.product(name: "NIOFoundationCompat", package: "swift-nio"),
6567
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
6668
.product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"),
69+
.product(name: "SystemPackage", package: "swift-system"),
6770
],
6871
swiftSettings: swiftSettings
6972
),
@@ -123,6 +126,7 @@ let package = Package(
123126
dependencies: [
124127
"SwiftlyCore",
125128
"CLibArchive",
129+
.product(name: "SystemPackage", package: "swift-system"),
126130
],
127131
swiftSettings: swiftSettings,
128132
linkerSettings: [
@@ -133,6 +137,7 @@ let package = Package(
133137
name: "MacOSPlatform",
134138
dependencies: [
135139
"SwiftlyCore",
140+
.product(name: "SystemPackage", package: "swift-system"),
136141
],
137142
swiftSettings: swiftSettings
138143
),
@@ -145,7 +150,10 @@ let package = Package(
145150
),
146151
.testTarget(
147152
name: "SwiftlyTests",
148-
dependencies: ["Swiftly"],
153+
dependencies: [
154+
"Swiftly",
155+
.product(name: "SystemPackage", package: "swift-system"),
156+
],
149157
resources: [
150158
.embedInCode("mock-signing-key-private.pgp"),
151159
],

Sources/LinuxPlatform/Extract.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import CLibArchive
22
import Foundation
3+
import SystemPackage
34

45
// The code in this file consists mainly of a Swift port of the "Complete Extractor" example included in the libarchive
56
// documentation: https://github.com/libarchive/libarchive/wiki/Examples#a-complete-extractor
@@ -44,7 +45,7 @@ func copyData(readArchive: OpaquePointer?, writeArchive: OpaquePointer?) throws
4445
/// the provided closure which will return the path the file will be written to.
4546
///
4647
/// This uses libarchive under the hood, so a wide variety of archive formats are supported (e.g. .tar.gz).
47-
func extractArchive(atPath archivePath: URL, transform: (String) -> URL) throws {
48+
func extractArchive(atPath archivePath: FilePath, transform: (String) -> FilePath) throws {
4849
var flags = Int32(0)
4950
flags = ARCHIVE_EXTRACT_TIME
5051
flags |= ARCHIVE_EXTRACT_PERM
@@ -66,8 +67,8 @@ func extractArchive(atPath archivePath: URL, transform: (String) -> URL) throws
6667
archive_write_free(ext)
6768
}
6869

69-
if archive_read_open_filename(a, archivePath.path, 10240) != 0 {
70-
throw ExtractError(message: "Failed to open \"\(archivePath.path)\"")
70+
if archive_read_open_filename(a, archivePath.string, 10240) != 0 {
71+
throw ExtractError(message: "Failed to open \"\(archivePath)\"")
7172
}
7273

7374
while true {
@@ -82,7 +83,7 @@ func extractArchive(atPath archivePath: URL, transform: (String) -> URL) throws
8283
}
8384

8485
let currentPath = String(cString: archive_entry_pathname(entry))
85-
archive_entry_set_pathname(entry, transform(currentPath).path)
86+
archive_entry_set_pathname(entry, transform(currentPath).string)
8687
r = archive_write_header(ext, entry)
8788
guard r == ARCHIVE_OK else {
8889
throw ExtractError(archive: ext)

0 commit comments

Comments
 (0)