Skip to content

Commit 1215b5d

Browse files
committed
Widespread improvements in Result handling; more concise, more readable
1 parent f407ab7 commit 1215b5d

27 files changed

+870
-813
lines changed

Sources/swift-bundler/Bundler/DarwinAppBundleStructure.swift

+5-16
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,11 @@ struct DarwinAppBundleStructure {
4646
contentsDirectory, resourcesDirectory, librariesDirectory, executableDirectory,
4747
]
4848

49-
for directory in directories {
50-
guard !FileManager.default.itemExists(at: directory, withType: .directory) else {
51-
continue
52-
}
53-
do {
54-
try FileManager.default.createDirectory(
55-
at: directory,
56-
withIntermediateDirectories: true
57-
)
58-
} catch {
59-
return .failure(
60-
.failedToCreateAppBundleDirectoryStructure(error)
61-
)
62-
}
49+
return directories.filter { directory in
50+
!FileManager.default.itemExists(at: directory, withType: .directory)
51+
}.tryForEach { directory in
52+
FileManager.default.createDirectory(at: directory)
53+
.mapError(DarwinBundlerError.failedToCreateAppBundleDirectoryStructure)
6354
}
64-
65-
return .success()
6655
}
6756
}

Sources/swift-bundler/Bundler/DarwinBundler.swift

+7-8
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,13 @@ enum DarwinBundler: Bundler {
207207
/// - Returns: If an error occurs, a failure is returned.
208208
private static func createPkgInfoFile(at pkgInfoFile: URL) -> Result<Void, DarwinBundlerError> {
209209
log.info("Creating 'PkgInfo'")
210-
do {
211-
var pkgInfoBytes: [UInt8] = [0x41, 0x50, 0x50, 0x4c, 0x3f, 0x3f, 0x3f, 0x3f]
212-
let pkgInfoData = Data(bytes: &pkgInfoBytes, count: pkgInfoBytes.count)
213-
try pkgInfoData.write(to: pkgInfoFile)
214-
return .success()
215-
} catch {
216-
return .failure(.failedToCreatePkgInfo(file: pkgInfoFile, error))
217-
}
210+
211+
let pkgInfoBytes: [UInt8] = [0x41, 0x50, 0x50, 0x4c, 0x3f, 0x3f, 0x3f, 0x3f]
212+
let pkgInfoData = Data(bytes: pkgInfoBytes, count: pkgInfoBytes.count)
213+
return pkgInfoData.write(to: pkgInfoFile)
214+
.mapError { error in
215+
.failedToCreatePkgInfo(file: pkgInfoFile, error)
216+
}
218217
}
219218

220219
/// Creates an app's `Info.plist` file.

Sources/swift-bundler/Bundler/GenericLinuxBundler.swift

+9-18
Original file line numberDiff line numberDiff line change
@@ -134,18 +134,12 @@ enum GenericLinuxBundler: Bundler {
134134
/// Creates all directories (including intermediate directories) required to
135135
/// create this bundle structure.
136136
func createDirectories() -> Result<Void, GenericLinuxBundlerError> {
137-
for directory in directories {
138-
do {
139-
try FileManager.default.createDirectory(
140-
at: directory,
141-
withIntermediateDirectories: true
142-
)
143-
} catch {
144-
return .failure(.failedToCreateDirectory(directory, error))
145-
}
137+
directories.tryForEach { directory in
138+
FileManager.default.createDirectory(
139+
at: directory,
140+
onError: GenericLinuxBundlerError.failedToCreateDirectory
141+
)
146142
}
147-
148-
return .success()
149143
}
150144

151145
/// Computes the `.desktop` file name to use for the given app name.
@@ -417,12 +411,9 @@ enum GenericLinuxBundler: Bundler {
417411
return .failure(.failedToCreateDesktopFile(desktopFile, nil))
418412
}
419413

420-
do {
421-
try data.write(to: desktopFile)
422-
} catch {
423-
return .failure(.failedToCreateDesktopFile(desktopFile, error))
424-
}
425-
426-
return .success()
414+
return data.write(to: desktopFile)
415+
.mapError { error in
416+
.failedToCreateDesktopFile(desktopFile, error)
417+
}
427418
}
428419
}

Sources/swift-bundler/Bundler/IconSetCreator.swift

+27-32
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,37 @@ enum IconSetCreator {
1717

1818
let temporaryDirectory = FileManager.default.temporaryDirectory
1919
let iconSet = temporaryDirectory.appendingPathComponent("AppIcon.iconset")
20-
do {
21-
try FileManager.default.createDirectory(at: iconSet)
22-
} catch {
23-
return .failure(.failedToCreateIconSetDirectory(iconSet, error))
24-
}
25-
2620
let sizes = [16, 32, 128, 256, 512]
27-
for size in sizes {
28-
let regularScale = iconSet.appendingPathComponent("icon_\(size)x\(size).png")
29-
let doubleScale = iconSet.appendingPathComponent("icon_\(size)x\(size)@2x.png")
3021

31-
var result = createScaledIcon(icon, dimension: size, output: regularScale)
32-
if case .failure = result {
33-
return result
34-
}
35-
result = createScaledIcon(icon, dimension: size * 2, output: doubleScale)
36-
if case .failure = result {
37-
return result
22+
return FileManager.default.createDirectory(at: iconSet)
23+
.mapError { error in
24+
.failedToCreateIconSetDirectory(iconSet, error)
3825
}
39-
}
26+
.andThen { _ in
27+
sizes.tryForEach { size in
28+
let regularScale = iconSet.appendingPathComponent("icon_\(size)x\(size).png")
29+
let doubleScale = iconSet.appendingPathComponent("icon_\(size)x\(size)@2x.png")
4030

41-
let process = Process.create(
42-
"/usr/bin/iconutil",
43-
arguments: ["--convert", "icns", "--output", outputFile.path, iconSet.path]
44-
)
45-
if case let .failure(error) = process.runAndWait() {
46-
return .failure(.failedToConvertToICNS(error))
47-
}
48-
49-
do {
50-
try FileManager.default.removeItem(at: iconSet)
51-
} catch {
52-
return .failure(.failedToRemoveIconSetDirectory(iconSet, error))
53-
}
54-
55-
return .success()
31+
return createScaledIcon(icon, dimension: size, output: regularScale)
32+
.andThen { _ in
33+
createScaledIcon(icon, dimension: size * 2, output: doubleScale)
34+
}
35+
}
36+
}
37+
.andThen { _ in
38+
Process.create(
39+
"/usr/bin/iconutil",
40+
arguments: ["--convert", "icns", "--output", outputFile.path, iconSet.path]
41+
).runAndWait().mapError { error in
42+
.failedToConvertToICNS(error)
43+
}
44+
}
45+
.andThen { _ in
46+
FileManager.default.removeItem(
47+
at: iconSet,
48+
onError: IconSetCreatorError.failedToRemoveIconSetDirectory
49+
)
50+
}
5651
}
5752

5853
/// Creates a scaled copy of an icon.

Sources/swift-bundler/Bundler/MetalCompiler.swift

+36-50
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,15 @@ enum MetalCompiler {
3838
to: directory,
3939
for: platform,
4040
platformVersion: platformVersion
41-
).flatMap { _ in
42-
if keepSources {
43-
return .success()
44-
}
45-
46-
for source in shaderSources {
47-
do {
48-
try FileManager.default.removeItem(at: source)
49-
} catch {
50-
return .failure(.failedToDeleteShaderSource(source, error))
51-
}
41+
)
42+
.replacingSuccessValue(with: ())
43+
.andThen(if: !keepSources) { _ in
44+
shaderSources.tryForEach { source in
45+
FileManager.default.removeItem(at: source)
46+
.mapError { error in
47+
.failedToDeleteShaderSource(source, error)
48+
}
5249
}
53-
54-
return .success()
5550
}
5651
}
5752

@@ -61,7 +56,8 @@ enum MetalCompiler {
6156
/// - destination: The directory to output `default.metallib` to.
6257
/// - platform: The platform to compile for.
6358
/// - platformVersion: The platform version to target during compilation.
64-
/// - Returns: Returns the location of the resulting `metallib`. If an error occurs, a failure is returned.
59+
/// - Returns: Returns the location of the resulting `metallib`. If an error
60+
/// occurs, a failure is returned.
6561
static func compileMetalShaders(
6662
_ sources: [URL],
6763
to destination: URL,
@@ -71,47 +67,37 @@ enum MetalCompiler {
7167
// Create a temporary directory for compilation
7268
let tempDirectory = FileManager.default.temporaryDirectory
7369
.appendingPathComponent("metal_compilation-\(UUID().uuidString)")
74-
do {
75-
try FileManager.default.createDirectory(at: tempDirectory)
76-
} catch {
77-
return .failure(.failedToCreateTemporaryCompilationDirectory(tempDirectory, error))
78-
}
70+
let archive = tempDirectory.appendingPathComponent("default.metal-ar")
7971

80-
// Compile the shaders into `.air` files
81-
var airFiles: [URL] = []
82-
for shaderSource in sources {
83-
let outputFileName = shaderSource.deletingPathExtension().appendingPathExtension("air")
84-
.lastPathComponent
85-
let outputFile = tempDirectory.appendingPathComponent(outputFileName)
86-
87-
let compilationResult = compileShader(
88-
shaderSource,
89-
to: outputFile,
90-
for: platform,
91-
platformVersion: platformVersion
92-
)
93-
94-
if case let .failure(error) = compilationResult {
95-
return .failure(error)
72+
return FileManager.default.createDirectory(
73+
at: tempDirectory,
74+
onError: MetalCompilerError.failedToCreateTemporaryCompilationDirectory
75+
)
76+
.andThen { _ in
77+
// Compile the shaders into `.air` files
78+
sources.tryMap { shaderSource in
79+
let outputFileName = shaderSource.deletingPathExtension()
80+
.appendingPathExtension("air").lastPathComponent
81+
let outputFile = tempDirectory.appendingPathComponent(outputFileName)
82+
83+
return compileShader(
84+
shaderSource,
85+
to: outputFile,
86+
for: platform,
87+
platformVersion: platformVersion
88+
).replacingSuccessValue(with: outputFile)
9689
}
97-
airFiles.append(outputFile)
9890
}
99-
100-
// Combine the compiled shaders into a `.metal-ar` archive
101-
let archive = tempDirectory.appendingPathComponent("default.metal-ar")
102-
let archiveResult = createArchive(at: archive, from: airFiles, for: platform)
103-
if case let .failure(error) = archiveResult {
104-
return .failure(error)
91+
.andThen { airFiles in
92+
// Combine the compiled shaders into a `.metal-ar` archive
93+
createArchive(at: archive, from: airFiles, for: platform)
10594
}
106-
107-
// Convert the `metal-ar` archive into a `metallib` library
108-
let library = destination.appendingPathComponent("default.metallib")
109-
let libraryResult = createLibrary(at: library, from: archive, for: platform)
110-
if case let .failure(error) = libraryResult {
111-
return .failure(error)
95+
.andThen { _ in
96+
// Convert the `metal-ar` archive into a `metallib` library
97+
let library = destination.appendingPathComponent("default.metallib")
98+
return createLibrary(at: library, from: archive, for: platform)
99+
.replacingSuccessValue(with: library)
112100
}
113-
114-
return .success(library)
115101
}
116102

117103
/// Compiles a metal shader file into an `air` file.

Sources/swift-bundler/Bundler/PlistCreator.swift

+20-20
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ enum PlistCreator {
99
/// - appName: The name of the app.
1010
/// - configuration: The app's configuration.
1111
/// - platform: The platform the app is for.
12-
/// - platformVersion: The minimum platform version that the app should run on.
12+
/// - platformVersion: The minimum platform version that the app should
13+
/// run on.
1314
/// - Returns: If an error occurs, a failure is returned.
1415
static func createAppInfoPlist(
1516
at file: URL,
@@ -23,23 +24,23 @@ enum PlistCreator {
2324
configuration: configuration,
2425
platform: platform,
2526
platformVersion: platformVersion
26-
).flatMap { contents in
27-
do {
28-
try contents.write(to: file)
29-
return .success()
30-
} catch {
31-
return .failure(.failedToWriteAppInfoPlist(file: file, error))
32-
}
27+
).andThen { contents in
28+
contents.write(to: file)
29+
.mapError { error in
30+
.failedToWriteAppInfoPlist(file: file, error)
31+
}
3332
}
3433
}
3534

3635
/// Creates the `Info.plist` file for a resource bundle.
3736
/// - Parameters:
3837
/// - file: The URL of the file to create.
3938
/// - bundleName: The bundle's name.
40-
/// - minimumOSVersion: The minimum OS version that the resource bundle should work on.
39+
/// - minimumOSVersion: The minimum OS version that the resource bundle
40+
/// should work on.
4141
/// - platform: The platform the bundle is for.
42-
/// - platformVersion: The minimum platform version that the app should run on.
42+
/// - platformVersion: The minimum platform version that the app should
43+
/// run on.
4344
/// - Returns: If an error occurs, a failure is returned.
4445
static func createResourceBundleInfoPlist(
4546
at file: URL,
@@ -51,14 +52,11 @@ enum PlistCreator {
5152
bundleName: bundleName,
5253
platform: platform,
5354
platformVersion: platformVersion
54-
).flatMap { contents in
55-
do {
56-
try contents.write(to: file)
57-
return .success()
58-
} catch {
59-
return .failure(
60-
.failedToWriteResourceBundleInfoPlist(bundle: bundleName, file: file, error))
61-
}
55+
).andThen { contents in
56+
contents.write(to: file)
57+
.mapError { error in
58+
.failedToWriteResourceBundleInfoPlist(bundle: bundleName, file: file, error)
59+
}
6260
}
6361
}
6462

@@ -67,8 +65,10 @@ enum PlistCreator {
6765
/// - appName: The app's name.
6866
/// - configuration: The app's configuration.
6967
/// - platform: The platform the app is for.
70-
/// - platformVersion: The minimum platform version that the app should run on.
71-
/// - Returns: The generated contents for the `Info.plist` file. If an error occurs, a failure is returned.
68+
/// - platformVersion: The minimum platform version that the app should
69+
/// run on.
70+
/// - Returns: The generated contents for the `Info.plist` file. If an error
71+
/// occurs, a failure is returned.
7272
static func createAppInfoPlistContents(
7373
appName: String,
7474
configuration: AppConfiguration,

0 commit comments

Comments
 (0)