Skip to content

Commit 7868345

Browse files
authored
Merge branch 'main' into patch-1
2 parents 7715583 + 5645873 commit 7868345

29 files changed

+1169
-515
lines changed

Package.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.10
1+
// swift-tools-version:6.0
22

33
import PackageDescription
44

@@ -52,11 +52,28 @@ let package = Package(
5252
.target(
5353
name: "SwiftlyCore",
5454
dependencies: [
55+
"SwiftlyDownloadAPI",
56+
"SwiftlyWebsiteAPI",
5557
.product(name: "AsyncHTTPClient", package: "async-http-client"),
5658
.product(name: "NIOFoundationCompat", package: "swift-nio"),
5759
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
5860
.product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"),
5961
],
62+
),
63+
.target(
64+
name: "SwiftlyDownloadAPI",
65+
dependencies: [
66+
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
67+
],
68+
plugins: [
69+
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
70+
]
71+
),
72+
.target(
73+
name: "SwiftlyWebsiteAPI",
74+
dependencies: [
75+
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
76+
],
6077
plugins: [
6178
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
6279
]

Plugins/GenerateDocsReference/GenerateDocsReferenceError.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Foundation
2-
import PackagePlugin
2+
@preconcurrency import PackagePlugin
33

4+
@preconcurrency
45
enum GenerateDocsReferencePluginError: Error {
56
case unknownBuildConfiguration(String)
67
case buildFailed(String)

Sources/LinuxPlatform/Linux.swift

Lines changed: 115 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public struct Linux: Platform {
4242
"tar.gz"
4343
}
4444

45-
private static let skipVerificationMessage: String = "To skip signature verification, specify the --no-verify flag."
45+
private static let skipVerificationMessage: String =
46+
"To skip signature verification, specify the --no-verify flag."
4647

4748
public func verifySwiftlySystemPrerequisites() throws {
4849
// Check if the root CA certificates are installed on this system for NIOSSL to use.
@@ -67,10 +68,15 @@ public struct Linux: Platform {
6768
}
6869
}
6970

70-
public func verifySystemPrerequisitesForInstall(_ ctx: SwiftlyCoreContext, platformName: String, version _: ToolchainVersion, requireSignatureValidation: Bool) async throws -> String? {
71+
public func verifySystemPrerequisitesForInstall(
72+
_ ctx: SwiftlyCoreContext, platformName: String, version _: ToolchainVersion,
73+
requireSignatureValidation: Bool
74+
) async throws -> String? {
7175
// TODO: these are hard-coded until we have a place to query for these based on the toolchain version
7276
// These lists were copied from the dockerfile sources here: https://github.com/apple/swift-docker/tree/ea035798755cce4ec41e0c6dbdd320904cef0421/5.10
73-
let packages: [String] = switch platformName {
77+
let packages: [String] =
78+
switch platformName
79+
{
7480
case "ubuntu1804":
7581
[
7682
"libatomic1",
@@ -221,7 +227,9 @@ public struct Linux: Platform {
221227
[]
222228
}
223229

224-
let manager: String? = switch platformName {
230+
let manager: String? =
231+
switch platformName
232+
{
225233
case "ubuntu1804":
226234
"apt-get"
227235
case "ubuntu2004":
@@ -259,18 +267,19 @@ public struct Linux: Platform {
259267
}
260268

261269
let tmpFile = self.getTempFilePath()
262-
let _ = FileManager.default.createFile(atPath: tmpFile.path, contents: nil, attributes: [.posixPermissions: 0o600])
270+
let _ = FileManager.default.createFile(
271+
atPath: tmpFile.path, contents: nil, attributes: [.posixPermissions: 0o600]
272+
)
263273
defer {
264274
try? FileManager.default.removeItem(at: tmpFile)
265275
}
266276

267-
guard let url = URL(string: "https://www.swift.org/keys/all-keys.asc") else {
268-
throw SwiftlyError(message: "malformed URL to the swift gpg keys")
269-
}
270-
271-
try await ctx.httpClient.downloadFile(url: url, to: tmpFile)
277+
try await ctx.httpClient.getGpgKeys().download(to: tmpFile)
272278
if let mockedHomeDir = ctx.mockedHomeDir {
273-
try self.runProgram("gpg", "--import", tmpFile.path, quiet: true, env: ["GNUPGHOME": mockedHomeDir.appendingPathComponent(".gnupg").path])
279+
try self.runProgram(
280+
"gpg", "--import", tmpFile.path, quiet: true,
281+
env: ["GNUPGHOME": mockedHomeDir.appendingPathComponent(".gnupg").path]
282+
)
274283
} else {
275284
try self.runProgram("gpg", "--import", tmpFile.path, quiet: true)
276285
}
@@ -323,16 +332,20 @@ public struct Linux: Platform {
323332
}
324333
}
325334

326-
public func install(_ ctx: SwiftlyCoreContext, from tmpFile: URL, version: ToolchainVersion, verbose: Bool) throws {
335+
public func install(
336+
_ ctx: SwiftlyCoreContext, from tmpFile: URL, version: ToolchainVersion, verbose: Bool
337+
) async throws {
327338
guard tmpFile.fileExists() else {
328339
throw SwiftlyError(message: "\(tmpFile) doesn't exist")
329340
}
330341

331342
if !self.swiftlyToolchainsDir(ctx).fileExists() {
332-
try FileManager.default.createDirectory(at: self.swiftlyToolchainsDir(ctx), withIntermediateDirectories: false)
343+
try FileManager.default.createDirectory(
344+
at: self.swiftlyToolchainsDir(ctx), withIntermediateDirectories: false
345+
)
333346
}
334347

335-
ctx.print("Extracting toolchain...")
348+
await ctx.print("Extracting toolchain...")
336349
let toolchainDir = self.swiftlyToolchainsDir(ctx).appendingPathComponent(version.name)
337350

338351
if toolchainDir.fileExists() {
@@ -347,15 +360,18 @@ public struct Linux: Platform {
347360
let destination = toolchainDir.appendingPathComponent(String(relativePath))
348361

349362
if verbose {
350-
ctx.print("\(destination.path)")
363+
// To avoid having to make extractArchive async this is a regular print
364+
// to stdout. Note that it is unlikely that the test mocking will require
365+
// capturing this output.
366+
print("\(destination.path)")
351367
}
352368

353369
// prepend /path/to/swiftlyHomeDir/toolchains/<toolchain> to each file name
354370
return destination
355371
}
356372
}
357373

358-
public func extractSwiftlyAndInstall(_ ctx: SwiftlyCoreContext, from archive: URL) throws {
374+
public func extractSwiftlyAndInstall(_ ctx: SwiftlyCoreContext, from archive: URL) async throws {
359375
guard archive.fileExists() else {
360376
throw SwiftlyError(message: "\(archive) doesn't exist")
361377
}
@@ -366,7 +382,7 @@ public struct Linux: Platform {
366382
}
367383
try FileManager.default.createDirectory(atPath: tmpDir.path, withIntermediateDirectories: true)
368384

369-
ctx.print("Extracting new swiftly...")
385+
await ctx.print("Extracting new swiftly...")
370386
try extractArchive(atPath: archive) { name in
371387
// Extract to the temporary directory
372388
tmpDir.appendingPathComponent(String(name))
@@ -375,7 +391,9 @@ public struct Linux: Platform {
375391
try self.runProgram(tmpDir.appendingPathComponent("swiftly").path, "init")
376392
}
377393

378-
public func uninstall(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion, verbose _: Bool) throws {
394+
public func uninstall(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion, verbose _: Bool)
395+
throws
396+
{
379397
let toolchainDir = self.swiftlyToolchainsDir(ctx).appendingPathComponent(toolchain.name)
380398
try FileManager.default.removeItem(at: toolchainDir)
381399
}
@@ -390,9 +408,11 @@ public struct Linux: Platform {
390408
FileManager.default.temporaryDirectory.appendingPathComponent("swiftly-\(UUID())")
391409
}
392410

393-
public func verifySignature(_ ctx: SwiftlyCoreContext, archiveDownloadURL: URL, archive: URL, verbose: Bool) async throws {
411+
public func verifyToolchainSignature(
412+
_ ctx: SwiftlyCoreContext, toolchainFile: ToolchainFile, archive: URL, verbose: Bool
413+
) async throws {
394414
if verbose {
395-
ctx.print("Downloading toolchain signature...")
415+
await ctx.print("Downloading toolchain signature...")
396416
}
397417

398418
let sigFile = self.getTempFilePath()
@@ -401,15 +421,15 @@ public struct Linux: Platform {
401421
try? FileManager.default.removeItem(at: sigFile)
402422
}
403423

404-
try await ctx.httpClient.downloadFile(
405-
url: archiveDownloadURL.appendingPathExtension("sig"),
406-
to: sigFile
407-
)
424+
try await ctx.httpClient.getSwiftToolchainFileSignature(toolchainFile).download(to: sigFile)
408425

409-
ctx.print("Verifying toolchain signature...")
426+
await ctx.print("Verifying toolchain signature...")
410427
do {
411428
if let mockedHomeDir = ctx.mockedHomeDir {
412-
try self.runProgram("gpg", "--verify", sigFile.path, archive.path, quiet: false, env: ["GNUPGHOME": mockedHomeDir.appendingPathComponent(".gnupg").path])
429+
try self.runProgram(
430+
"gpg", "--verify", sigFile.path, archive.path, quiet: false,
431+
env: ["GNUPGHOME": mockedHomeDir.appendingPathComponent(".gnupg").path]
432+
)
413433
} else {
414434
try self.runProgram("gpg", "--verify", sigFile.path, archive.path, quiet: !verbose)
415435
}
@@ -418,23 +438,65 @@ public struct Linux: Platform {
418438
}
419439
}
420440

421-
private func manualSelectPlatform(_ ctx: SwiftlyCoreContext, _ platformPretty: String?) async -> PlatformDefinition {
441+
public func verifySwiftlySignature(
442+
_ ctx: SwiftlyCoreContext, archiveDownloadURL: URL, archive: URL, verbose: Bool
443+
) async throws {
444+
if verbose {
445+
await ctx.print("Downloading swiftly signature...")
446+
}
447+
448+
let sigFile = self.getTempFilePath()
449+
let _ = FileManager.default.createFile(atPath: sigFile.path, contents: nil)
450+
defer {
451+
try? FileManager.default.removeItem(at: sigFile)
452+
}
453+
454+
try await ctx.httpClient.getSwiftlyReleaseSignature(
455+
url: archiveDownloadURL.appendingPathExtension("sig")
456+
).download(to: sigFile)
457+
458+
await ctx.print("Verifying swiftly signature...")
459+
do {
460+
if let mockedHomeDir = ctx.mockedHomeDir {
461+
try self.runProgram(
462+
"gpg", "--verify", sigFile.path, archive.path, quiet: false,
463+
env: ["GNUPGHOME": mockedHomeDir.appendingPathComponent(".gnupg").path]
464+
)
465+
} else {
466+
try self.runProgram("gpg", "--verify", sigFile.path, archive.path, quiet: !verbose)
467+
}
468+
} catch {
469+
throw SwiftlyError(message: "Signature verification failed: \(error).")
470+
}
471+
}
472+
473+
private func manualSelectPlatform(_ ctx: SwiftlyCoreContext, _ platformPretty: String?) async
474+
-> PlatformDefinition
475+
{
422476
if let platformPretty {
423-
print("\(platformPretty) is not an officially supported platform, but the toolchains for another platform may still work on it.")
477+
print(
478+
"\(platformPretty) is not an officially supported platform, but the toolchains for another platform may still work on it."
479+
)
424480
} else {
425-
print("This platform could not be detected, but a toolchain for one of the supported platforms may work on it.")
481+
print(
482+
"This platform could not be detected, but a toolchain for one of the supported platforms may work on it."
483+
)
426484
}
427485

428-
let selections = self.linuxPlatforms.enumerated().map { "\($0 + 1)) \($1.namePretty)" }.joined(separator: "\n")
486+
let selections = self.linuxPlatforms.enumerated().map { "\($0 + 1)) \($1.namePretty)" }.joined(
487+
separator: "\n")
429488

430-
print("""
431-
Please select the platform to use for toolchain downloads:
489+
print(
490+
"""
491+
Please select the platform to use for toolchain downloads:
432492
433-
0) Cancel
434-
\(selections)
435-
""")
493+
0) Cancel
494+
\(selections)
495+
""")
436496

437-
let choice = ctx.readLine(prompt: "Pick one of the available selections [0-\(self.linuxPlatforms.count)] ") ?? "0"
497+
let choice =
498+
await ctx.readLine(prompt: "Pick one of the available selections [0-\(self.linuxPlatforms.count)] ")
499+
?? "0"
438500

439501
guard let choiceNum = Int(choice) else {
440502
fatalError("Installation canceled")
@@ -447,11 +509,15 @@ public struct Linux: Platform {
447509
return self.linuxPlatforms[choiceNum - 1]
448510
}
449511

450-
public func detectPlatform(_ ctx: SwiftlyCoreContext, disableConfirmation: Bool, platform: String?) async throws -> PlatformDefinition {
512+
public func detectPlatform(
513+
_ ctx: SwiftlyCoreContext, disableConfirmation: Bool, platform: String?
514+
) async throws -> PlatformDefinition {
451515
// We've been given a hint to use
452516
if let platform {
453517
guard let pd = linuxPlatforms.first(where: { $0.nameFull == platform }) else {
454-
fatalError("Unrecognized platform \(platform). Recognized values: \(self.linuxPlatforms.map(\.nameFull).joined(separator: ", ")).")
518+
fatalError(
519+
"Unrecognized platform \(platform). Recognized values: \(self.linuxPlatforms.map(\.nameFull).joined(separator: ", "))."
520+
)
455521
}
456522

457523
return pd
@@ -489,9 +555,13 @@ public struct Linux: Platform {
489555
} else if info.hasPrefix("ID_LIKE=") {
490556
idlike = String(info.dropFirst("ID_LIKE=".count)).replacingOccurrences(of: "\"", with: "")
491557
} else if info.hasPrefix("VERSION_ID=") {
492-
versionID = String(info.dropFirst("VERSION_ID=".count)).replacingOccurrences(of: "\"", with: "").replacingOccurrences(of: ".", with: "")
558+
versionID = String(info.dropFirst("VERSION_ID=".count)).replacingOccurrences(
559+
of: "\"", with: ""
560+
).replacingOccurrences(of: ".", with: "")
493561
} else if info.hasPrefix("PRETTY_NAME=") {
494-
platformPretty = String(info.dropFirst("PRETTY_NAME=".count)).replacingOccurrences(of: "\"", with: "")
562+
platformPretty = String(info.dropFirst("PRETTY_NAME=".count)).replacingOccurrences(
563+
of: "\"", with: ""
564+
)
495565
}
496566
}
497567

@@ -529,7 +599,9 @@ public struct Linux: Platform {
529599
}
530600

531601
return .rhel9
532-
} else if let pd = [PlatformDefinition.ubuntu1804, .ubuntu2004, .ubuntu2204, .ubuntu2404, .debian12, .fedora39].first(where: { $0.name == id + versionID }) {
602+
} else if let pd = [
603+
PlatformDefinition.ubuntu1804, .ubuntu2004, .ubuntu2204, .ubuntu2404, .debian12, .fedora39,
604+
].first(where: { $0.name == id + versionID }) {
533605
return pd
534606
}
535607

@@ -559,7 +631,8 @@ public struct Linux: Platform {
559631
return "/bin/bash"
560632
}
561633

562-
public func findToolchainLocation(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion) -> URL {
634+
public func findToolchainLocation(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion) -> URL
635+
{
563636
self.swiftlyToolchainsDir(ctx).appendingPathComponent("\(toolchain.name)")
564637
}
565638

0 commit comments

Comments
 (0)