Skip to content

Commit 3b8cebe

Browse files
committed
Merge branch 'main' of https://github.com/swiftlang/swiftly into macos_install_force_local
2 parents 4be12e6 + 726ea90 commit 3b8cebe

21 files changed

+179
-101
lines changed

Package.resolved

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"originHash" : "b623c5be535be5b61f96545e9a4aaa177e3f131cfbd5a4270c6abdce87419cc3",
2+
"originHash" : "72da781871f930cedf16c67b076b7afb527340732a76dfddaa4bd3a74126f376",
33
"pins" : [
44
{
55
"identity" : "async-http-client",
@@ -96,8 +96,8 @@
9696
"kind" : "remoteSourceControl",
9797
"location" : "https://github.com/apple/swift-nio.git",
9898
"state" : {
99-
"revision" : "ba72f31e11275fc5bf060c966cf6c1f36842a291",
100-
"version" : "2.79.0"
99+
"revision" : "c51907a839e63ebf0ba2076bba73dd96436bd1b9",
100+
"version" : "2.81.0"
101101
}
102102
},
103103
{

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.0"),
1818
.package(url: "https://github.com/swift-server/async-http-client", from: "1.24.0"),
1919
.package(url: "https://github.com/swift-server/swift-openapi-async-http-client", from: "1.1.0"),
20-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.79.0"),
20+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"),
2121
.package(url: "https://github.com/apple/swift-tools-support-core.git", from: "0.7.2"),
2222
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
2323
.package(url: "https://github.com/apple/swift-openapi-generator", from: "1.6.0"),

Sources/LinuxPlatform/Linux.swift

+13-19
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ var swiftGPGKeysRefreshed = false
77
/// This implementation can be reused for any supported Linux platform.
88
/// TODO: replace dummy implementations
99
public struct Linux: Platform {
10-
let linuxPlatforms = [
11-
PlatformDefinition.ubuntu2404,
12-
PlatformDefinition.ubuntu2204,
13-
PlatformDefinition.ubuntu2004,
14-
PlatformDefinition.ubuntu1804,
15-
PlatformDefinition.fedora39,
16-
PlatformDefinition.rhel9,
17-
PlatformDefinition.amazonlinux2,
18-
PlatformDefinition.debian12,
10+
let linuxPlatforms: [PlatformDefinition] = [
11+
.ubuntu2404,
12+
.ubuntu2204,
13+
.ubuntu2004,
14+
.ubuntu1804,
15+
.fedora39,
16+
.rhel9,
17+
.amazonlinux2,
18+
.debian12,
1919
]
2020

2121
public init() {}
@@ -376,19 +376,13 @@ public struct Linux: Platform {
376376
try self.runProgram(tmpDir.appendingPathComponent("swiftly").path, "init")
377377
}
378378

379-
public func uninstall(_ toolchain: ToolchainVersion) throws {
379+
public func uninstall(_ toolchain: ToolchainVersion, verbose _: Bool) throws {
380380
let toolchainDir = self.swiftlyToolchainsDir.appendingPathComponent(toolchain.name)
381381
try FileManager.default.removeItem(at: toolchainDir)
382382
}
383383

384384
public func getExecutableName() -> String {
385-
#if arch(x86_64)
386-
let arch = "x86_64"
387-
#elseif arch(arm64)
388-
let arch = "aarch64"
389-
#else
390-
fatalError("Unsupported processor architecture")
391-
#endif
385+
let arch = cpuArch
392386

393387
return "swiftly-\(arch)-unknown-linux-gnu"
394388
}
@@ -516,7 +510,7 @@ public struct Linux: Platform {
516510
return await self.manualSelectPlatform(platformPretty)
517511
}
518512

519-
return PlatformDefinition.amazonlinux2
513+
return .amazonlinux2
520514
} else if (id + (idlike ?? "")).contains("rhel") {
521515
guard versionID.hasPrefix("9") else {
522516
let message = "Unsupported version of RHEL"
@@ -528,7 +522,7 @@ public struct Linux: Platform {
528522
return await self.manualSelectPlatform(platformPretty)
529523
}
530524

531-
return PlatformDefinition.rhel9
525+
return .rhel9
532526
} else if let pd = [PlatformDefinition.ubuntu1804, .ubuntu2004, .ubuntu2204, .ubuntu2404, .debian12, .fedora39].first(where: { $0.name == id + versionID }) {
533527
return pd
534528
}

Sources/MacOSPlatform/MacOS.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -120,25 +120,25 @@ public struct MacOS: Platform {
120120
try self.runProgram(homeDir.appendingPathComponent("usr/local/bin/swiftly").path, "init")
121121
}
122122

123-
public func uninstall(_ toolchain: ToolchainVersion) throws {
123+
public func uninstall(_ toolchain: ToolchainVersion, verbose: Bool) throws {
124124
SwiftlyCore.print("Uninstalling package in user home directory...")
125125

126126
let toolchainDir = self.swiftlyToolchainsDir.appendingPathComponent("\(toolchain.identifier).xctoolchain", isDirectory: true)
127127

128128
let decoder = PropertyListDecoder()
129129
let infoPlist = toolchainDir.appendingPathComponent("Info.plist")
130130
guard let data = try? Data(contentsOf: infoPlist) else {
131-
throw SwiftlyError(message: "could not open \(infoPlist)")
131+
throw SwiftlyError(message: "could not open \(infoPlist.path)")
132132
}
133133

134134
guard let pkgInfo = try? decoder.decode(SwiftPkgInfo.self, from: data) else {
135-
throw SwiftlyError(message: "could not decode plist at \(infoPlist)")
135+
throw SwiftlyError(message: "could not decode plist at \(infoPlist.path)")
136136
}
137137

138138
try FileManager.default.removeItem(at: toolchainDir)
139139

140140
let homedir = ProcessInfo.processInfo.environment["HOME"]!
141-
try? runProgram("pkgutil", "--volume", homedir, "--forget", pkgInfo.CFBundleIdentifier)
141+
try? runProgram("pkgutil", "--volume", homedir, "--forget", pkgInfo.CFBundleIdentifier, quiet: !verbose)
142142
}
143143

144144
public func getExecutableName() -> String {
@@ -156,7 +156,7 @@ public struct MacOS: Platform {
156156

157157
public func detectPlatform(disableConfirmation _: Bool, platform _: String?) async -> PlatformDefinition {
158158
// No special detection required on macOS platform
159-
PlatformDefinition.macOS
159+
.macOS
160160
}
161161

162162
public func getShell() async throws -> String {

Sources/Swiftly/Init.swift

+8
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,18 @@ internal struct Init: SwiftlyCommand {
4242
if var config, !overwrite &&
4343
(
4444
config.version == SwiftlyVersion(major: 0, minor: 4, patch: 0, suffix: "dev") ||
45+
<<<<<<< HEAD
4546
config.version == SwiftlyVersion(major: 0, minor: 4, patch: 0)
4647
)
4748
{
4849
// This is a simple upgrade from the 0.4.0-dev pre-release, or 0.4.0 release
50+
=======
51+
config.version == SwiftlyVersion(major: 0, minor: 4, patch: 0) ||
52+
(config.version?.major == 1 && config.version?.minor == 0)
53+
)
54+
{
55+
// This is a simple upgrade from the 0.4.0 pre-releases, or 1.x
56+
>>>>>>> 726ea90b9c304068d9649abc8718f8752169ce7b
4957

5058
// Move our executable over to the correct place
5159
try Swiftly.currentPlatform.installSwiftlyBin()

Sources/Swiftly/Install.swift

+9-2
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,18 @@ struct Install: SwiftlyCommand {
297297

298298
// If this is the first installed toolchain, mark it as in-use regardless of whether the
299299
// --use argument was provided.
300-
if useInstalledToolchain || config.inUse == nil {
301-
// TODO: consider adding the global default option to this commands flags
300+
if useInstalledToolchain {
302301
try await Use.execute(version, globalDefault: false, &config)
303302
}
304303

304+
// We always update the global default toolchain if there is none set. This could
305+
// be the only toolchain that is installed, which makes it the only choice.
306+
if config.inUse == nil {
307+
config.inUse = version
308+
try config.save()
309+
SwiftlyCore.print("The global default toolchain has been set to `\(version)`")
310+
}
311+
305312
SwiftlyCore.print("\(version) installed successfully!")
306313
return (postInstallScript, pathChanged)
307314
}

Sources/Swiftly/Proxy.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public enum Proxy {
5353
}
5454

5555
guard let toolchain = toolchain else {
56-
throw SwiftlyError(message: "No swift toolchain could be selected from either from a .swift-version file, or the default. You can try using `swiftly install <toolchain version>` to install one.")
56+
throw SwiftlyError(message: "No installed swift toolchain is selected from either from a .swift-version file, or the default. You can try using one that's already installed with `swiftly use <toolchain version>` or install a new toolchain to use with `swiftly install --use <toolchain version>`.")
5757
}
5858

5959
// Prevent circularities with a memento environment variable

Sources/Swiftly/Run.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ internal struct Run: SwiftlyCommand {
8686
}
8787

8888
guard let toolchain = toolchain else {
89-
throw SwiftlyError(message: "No swift toolchain could be selected from either from a .swift-version file, or the default. You can try using `swiftly install <toolchain version>` to install one.")
89+
throw SwiftlyError(message: "No installed swift toolchain is selected from either from a .swift-version file, or the default. You can try using one that's already installed with `swiftly use <toolchain version>` or install a new toolchain to use with `swiftly install --use <toolchain version>`.")
9090
}
9191

9292
do {

Sources/Swiftly/Uninstall.swift

+14-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ struct Uninstall: SwiftlyCommand {
5656
}
5757
} else {
5858
let selector = try ToolchainSelector(parsing: self.toolchain)
59-
toolchains = startingConfig.listInstalledToolchains(selector: selector)
59+
var installedToolchains = startingConfig.listInstalledToolchains(selector: selector)
60+
// This is in the unusual case that the inUse toolchain is not listed in the installed toolchains
61+
if let inUse = startingConfig.inUse, selector.matches(toolchain: inUse) && !startingConfig.installedToolchains.contains(inUse) {
62+
installedToolchains.append(inUse)
63+
}
64+
toolchains = installedToolchains
6065
}
6166

6267
guard !toolchains.isEmpty else {
@@ -108,18 +113,23 @@ struct Uninstall: SwiftlyCommand {
108113
}
109114
}
110115

111-
try await Self.execute(toolchain, &config)
116+
try await Self.execute(toolchain, &config, verbose: self.root.verbose)
112117
}
113118

114119
SwiftlyCore.print()
115120
SwiftlyCore.print("\(toolchains.count) toolchain(s) successfully uninstalled")
116121
}
117122

118-
static func execute(_ toolchain: ToolchainVersion, _ config: inout Config) async throws {
123+
static func execute(_ toolchain: ToolchainVersion, _ config: inout Config, verbose: Bool) async throws {
119124
SwiftlyCore.print("Uninstalling \(toolchain)...", terminator: "")
120-
try Swiftly.currentPlatform.uninstall(toolchain)
121125
config.installedToolchains.remove(toolchain)
126+
// This is here to prevent the inUse from referencing a toolchain that is not installed
127+
if config.inUse == toolchain {
128+
config.inUse = nil
129+
}
122130
try config.save()
131+
132+
try Swiftly.currentPlatform.uninstall(toolchain, verbose: verbose)
123133
SwiftlyCore.print("done")
124134
}
125135
}

Sources/Swiftly/Update.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct Update: SwiftlyCommand {
8181
try validateSwiftly()
8282
var config = try Config.load()
8383

84-
guard let parameters = try self.resolveUpdateParameters(config) else {
84+
guard let parameters = try await self.resolveUpdateParameters(&config) else {
8585
if let toolchain = self.toolchain {
8686
SwiftlyCore.print("No installed toolchain matched \"\(toolchain)\"")
8787
} else {
@@ -101,7 +101,7 @@ struct Update: SwiftlyCommand {
101101
}
102102

103103
if !self.root.assumeYes {
104-
SwiftlyCore.print("Update \(parameters.oldToolchain) \(newToolchain)?")
104+
SwiftlyCore.print("Update \(parameters.oldToolchain) -> \(newToolchain)?")
105105
guard SwiftlyCore.promptForConfirmation(defaultBehavior: true) else {
106106
SwiftlyCore.print("Aborting")
107107
return
@@ -117,7 +117,7 @@ struct Update: SwiftlyCommand {
117117
assumeYes: self.root.assumeYes
118118
)
119119

120-
try await Uninstall.execute(parameters.oldToolchain, &config)
120+
try await Uninstall.execute(parameters.oldToolchain, &config, verbose: self.root.verbose)
121121
SwiftlyCore.print("Successfully updated \(parameters.oldToolchain)\(newToolchain)")
122122

123123
if let postInstallScript = postInstallScript {
@@ -152,7 +152,7 @@ struct Update: SwiftlyCommand {
152152
/// If the selector does not match an installed toolchain, this returns nil.
153153
/// If no selector is provided, the currently in-use toolchain will be used as the basis for the returned
154154
/// parameters.
155-
private func resolveUpdateParameters(_ config: Config) throws -> UpdateParameters? {
155+
private func resolveUpdateParameters(_ config: inout Config) async throws -> UpdateParameters? {
156156
let selector = try self.toolchain.map { try ToolchainSelector(parsing: $0) }
157157

158158
let oldToolchain: ToolchainVersion?
@@ -163,7 +163,7 @@ struct Update: SwiftlyCommand {
163163
// 5.5.1 and 5.5.2 are installed (5.5.2 will be updated).
164164
oldToolchain = toolchains.max()
165165
} else {
166-
oldToolchain = config.inUse
166+
(oldToolchain, _) = try await selectToolchain(config: &config)
167167
}
168168

169169
guard let oldToolchain else {

Sources/Swiftly/Use.swift

+12-5
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ internal struct Use: SwiftlyCommand {
116116
// We don't care in this case if there were any problems with the swift version files, just overwrite it with the new value
117117
try toolchain.name.write(to: versionFile, atomically: true, encoding: .utf8)
118118

119-
message = "The file `\(versionFile)` has been set to `\(toolchain)`"
119+
message = "The file `\(versionFile.path)` has been set to `\(toolchain)`"
120120
} else if let newVersionFile = findNewVersionFile(), !globalDefault {
121121
if !assumeYes {
122122
SwiftlyCore.print("A new file `\(newVersionFile)` will be created to set the new in-use toolchain for this project. Alternatively, you can set your default globally with the `--global-default` flag. Proceed with creating this file?")
@@ -129,11 +129,11 @@ internal struct Use: SwiftlyCommand {
129129

130130
try toolchain.name.write(to: newVersionFile, atomically: true, encoding: .utf8)
131131

132-
message = "The file `\(newVersionFile)` has been set to `\(toolchain)`"
132+
message = "The file `\(newVersionFile.path)` has been set to `\(toolchain)`"
133133
} else {
134134
config.inUse = toolchain
135135
try config.save()
136-
message = "The global default toolchain has set to `\(toolchain)`"
136+
message = "The global default toolchain has been set to `\(toolchain)`"
137137
}
138138

139139
if let selectedVersion = selectedVersion {
@@ -177,7 +177,8 @@ public enum ToolchainSelectionResult {
177177
/// Selection of a toolchain can be accomplished in a number of ways. There is the
178178
/// the configuration's global default 'inUse' setting. This is the fallback selector
179179
/// if there are no other selections. The returned tuple will contain the default toolchain
180-
/// version and the result will be .default.
180+
/// version and the result will be .globalDefault. This will always be the result if
181+
/// the globalDefault parameter is true.
181182
///
182183
/// A toolchain can also be selected from a `.swift-version` file in the current
183184
/// working directory, or an ancestor directory. If it successfully selects a toolchain
@@ -233,5 +234,11 @@ public func selectToolchain(config: inout Config, globalDefault: Bool = false) a
233234
}
234235
}
235236

236-
return (config.inUse, .globalDefault)
237+
// Check to ensure that the global default in use toolchain matches one of the installed toolchains, and return
238+
// no selected toolchain if it doesn't.
239+
guard let defaultInUse = config.inUse, config.installedToolchains.contains(defaultInUse) else {
240+
return (nil, .globalDefault)
241+
}
242+
243+
return (defaultInUse, .globalDefault)
237244
}

Sources/SwiftlyCore/HTTPClient.swift

+2-22
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,7 @@ public struct SwiftlyHTTPClient {
295295
limit: Int? = nil,
296296
filter: ((ToolchainVersion.StableRelease) -> Bool)? = nil
297297
) async throws -> [ToolchainVersion.StableRelease] {
298-
let arch = if a == nil {
299-
#if arch(x86_64)
300-
"x86_64"
301-
#elseif arch(arm64)
302-
"aarch64"
303-
#else
304-
#error("Unsupported processor architecture")
305-
#endif
306-
} else {
307-
a!
308-
}
298+
let arch = a ?? cpuArch
309299

310300
let url = "https://www.swift.org/api/v1/install/releases.json"
311301
let swiftOrgReleases: [SwiftOrgRelease] = try await self.getFromJSON(url: url, type: [SwiftOrgRelease].self)
@@ -359,17 +349,7 @@ public struct SwiftlyHTTPClient {
359349
limit: Int? = nil,
360350
filter: ((ToolchainVersion.Snapshot) -> Bool)? = nil
361351
) async throws -> [ToolchainVersion.Snapshot] {
362-
let arch = if a == nil {
363-
#if arch(x86_64)
364-
"x86_64"
365-
#elseif arch(arm64)
366-
"aarch64"
367-
#else
368-
#error("Unsupported processor architecture")
369-
#endif
370-
} else {
371-
a!
372-
}
352+
let arch = a ?? cpuArch
373353

374354
let platformName = if platform.name == PlatformDefinition.macOS.name {
375355
"macos"

Sources/SwiftlyCore/Platform.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public protocol Platform {
7272

7373
/// Uninstalls a toolchain associated with the given version.
7474
/// If this version is in use, the next latest version will be used afterwards.
75-
func uninstall(_ version: ToolchainVersion) throws
75+
func uninstall(_ version: ToolchainVersion, verbose: Bool) throws
7676

7777
/// Get the name of the swiftly release binary.
7878
func getExecutableName() -> String
@@ -141,6 +141,9 @@ extension Platform {
141141
#if os(macOS) || os(Linux)
142142
internal func proxyEnv(_ toolchain: ToolchainVersion) throws -> [String: String] {
143143
let tcPath = self.findToolchainLocation(toolchain).appendingPathComponent("usr/bin")
144+
guard tcPath.fileExists() else {
145+
throw SwiftlyError(message: "Toolchain \(toolchain) could not be located. You can try `swiftly uninstall \(toolchain)` to uninstall it and then `swiftly install \(toolchain)` to install it again.")
146+
}
144147
var newEnv = ProcessInfo.processInfo.environment
145148

146149
// The toolchain goes to the beginning of the PATH

Sources/SwiftlyCore/SwiftlyCore.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
public let version = SwiftlyVersion(major: 1, minor: 0, patch: 0)
3+
public let version = SwiftlyVersion(major: 1, minor: 1, patch: 0, suffix: "dev")
44

55
/// A separate home directory to use for testing purposes. This overrides swiftly's default
66
/// home directory location logic.
@@ -51,3 +51,11 @@ public func readLine(prompt: String) -> String? {
5151
}
5252
return provider.readLine()
5353
}
54+
55+
#if arch(x86_64)
56+
public let cpuArch = "x86_64"
57+
#elseif arch(arm64)
58+
public let cpuArch = "aarch64"
59+
#else
60+
#error("Unsupported processor architecture")
61+
#endif

0 commit comments

Comments
 (0)