Skip to content

Commit 32c2355

Browse files
authored
Implement update command (#67)
This also introduces a mocking framework for toolchain downloads, which can be used to speed up test runs.
1 parent 86dff27 commit 32c2355

File tree

15 files changed

+694
-157
lines changed

15 files changed

+694
-157
lines changed

README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Target: x86_64-unknown-linux-gnu
3232

3333
- Installing multiple toolchains, including both stable releases and snapshots
3434
- Switching which installed toolchain is active (i.e. which one is discovered via `$PATH`)
35-
- Updating installed toolchains to the latest available versions of those toolchains (not yet implemented)
35+
- Updating installed toolchains to the latest available versions of those toolchains
3636
- Uninstalling installed toolchains
3737
- Listing the toolchains that are available to install (not yet implemented)
3838

@@ -175,23 +175,27 @@ $ swiftly use main-snapshot
175175

176176
### Updating a toolchain
177177

178-
Update replaces a given toolchain with a later version of that toolchain. For a stable release, this means updating to a later patch version. For snapshots, this means updating to the most recently available snapshot.
178+
Update replaces a given toolchain with a later version of that toolchain. For a stable release, this means updating to a later patch, minor, or major version. For snapshots, this means updating to the most recently available snapshot.
179179

180-
If no version is provided, update will update the currently selected toolchain to its latest version while removing the old version. The newly installed version will be used.
181-
182-
Note that this command isn't implemented yet, but it will be included in a future release.
180+
If no version is provided, update will update the currently selected toolchain to its latest patch release if a release toolchain or the latest available snapshot if a snapshot. The newly installed version will be selected.
183181

184182
```
185183
$ swiftly update
186184
```
187185

188-
To update the latest installed stable version, the “latest” version can be provided:
186+
To update the latest installed release version to the latest available release version, the “latest” version can be provided. Note that this may update the toolchain to the next minor or even major version.
189187

190188
```
191189
swiftly update latest
192190
```
193191

194-
To update to the latest patch release of a given major/minor version, only the major/minor pair need to be provided. This will update the latest installed toolchain associated with that major/minor version to the latest patch release for that major/minor version.
192+
If only a major version is specified, the latest installed toolchain with that major version will be updated to the latest available release of that major version:
193+
194+
```
195+
swiftly update 5
196+
```
197+
198+
If the major and minor version are specified, the latest installed toolchain associated with that major/minor version will be updated to the latest available patch release for that major/minor version.
195199

196200
```
197201
swiftly update 5.3
@@ -215,6 +219,12 @@ You can also update the latest installed main snapshot to the latest available o
215219
swiftly update main-snapshot
216220
```
217221

222+
A specific snapshot toolchain can be updated to the newest available snapshot for that branch by including the date:
223+
224+
```
225+
swiftly update 5.9-snapshot-2023-09-20
226+
```
227+
218228
### Listing toolchains available to install
219229

220230
The `list-available` command can be used to list the latest toolchains that Apple has made available to install.

Sources/Swiftly/Install.swift

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,25 @@ struct Install: SwiftlyCommand {
5353
))
5454
var token: String?
5555

56+
public var httpClient = SwiftlyHTTPClient()
57+
58+
private enum CodingKeys: String, CodingKey {
59+
case version, token
60+
}
61+
5662
mutating func run() async throws {
5763
let selector = try ToolchainSelector(parsing: self.version)
58-
HTTP.githubToken = self.token
64+
self.httpClient.githubToken = self.token
5965
let toolchainVersion = try await self.resolve(selector: selector)
60-
try await Self.execute(version: toolchainVersion)
61-
}
62-
63-
internal static func execute(version: ToolchainVersion) async throws {
6466
var config = try Config.load()
67+
try await Self.execute(version: toolchainVersion, &config, self.httpClient)
68+
}
6569

70+
internal static func execute(
71+
version: ToolchainVersion,
72+
_ config: inout Config,
73+
_ httpClient: SwiftlyHTTPClient
74+
) async throws {
6675
guard !config.installedToolchains.contains(version) else {
6776
SwiftlyCore.print("\(version) is already installed, exiting.")
6877
return
@@ -121,7 +130,8 @@ struct Install: SwiftlyCommand {
121130
var lastUpdate = Date()
122131

123132
do {
124-
try await HTTP.downloadToolchain(
133+
try await httpClient.downloadToolchain(
134+
version,
125135
url: url,
126136
to: tmpFile.path,
127137
reportProgress: { progress in
@@ -143,7 +153,7 @@ struct Install: SwiftlyCommand {
143153
)
144154
}
145155
)
146-
} catch _ as HTTP.DownloadNotFoundError {
156+
} catch _ as SwiftlyHTTPClient.DownloadNotFoundError {
147157
SwiftlyCore.print("\(version) does not exist, exiting")
148158
return
149159
} catch {
@@ -160,7 +170,7 @@ struct Install: SwiftlyCommand {
160170

161171
// If this is the first installed toolchain, mark it as in-use.
162172
if config.inUse == nil {
163-
try await Use.execute(version, config: &config)
173+
try await Use.execute(version, &config)
164174
}
165175

166176
SwiftlyCore.print("\(version) installed successfully!")
@@ -173,7 +183,7 @@ struct Install: SwiftlyCommand {
173183
case .latest:
174184
SwiftlyCore.print("Fetching the latest stable Swift release...")
175185

176-
guard let release = try await HTTP.getReleaseToolchains(limit: 1).first else {
186+
guard let release = try await self.httpClient.getReleaseToolchains(limit: 1).first else {
177187
throw Error(message: "couldn't get latest releases")
178188
}
179189
return .stable(release)
@@ -192,7 +202,7 @@ struct Install: SwiftlyCommand {
192202
SwiftlyCore.print("Fetching the latest stable Swift \(major).\(minor) release...")
193203
// If a patch was not provided, perform a lookup to get the latest patch release
194204
// of the provided major/minor version pair.
195-
let toolchain = try await HTTP.getReleaseToolchains(limit: 1) { release in
205+
let toolchain = try await self.httpClient.getReleaseToolchains(limit: 1) { release in
196206
release.major == major && release.minor == minor
197207
}.first
198208

@@ -210,7 +220,7 @@ struct Install: SwiftlyCommand {
210220
SwiftlyCore.print("Fetching the latest \(branch) branch snapshot...")
211221
// If a date was not provided, perform a lookup to find the most recent snapshot
212222
// for the given branch.
213-
let snapshot = try await HTTP.getSnapshotToolchains(limit: 1) { snapshot in
223+
let snapshot = try await self.httpClient.getSnapshotToolchains(limit: 1) { snapshot in
214224
snapshot.branch == branch
215225
}.first
216226

Sources/Swiftly/ListAvailable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ struct ListAvailable: SwiftlyCommand {
3535
))
3636
var toolchainSelector: String?
3737

38+
public var httpClient = SwiftlyHTTPClient()
39+
40+
private enum CodingKeys: String, CodingKey {
41+
case toolchainSelector
42+
}
43+
3844
internal mutating func run() async throws {
3945
let selector = try self.toolchainSelector.map { input in
4046
try ToolchainSelector(parsing: input)
@@ -47,7 +53,7 @@ struct ListAvailable: SwiftlyCommand {
4753
}
4854
}
4955

50-
let toolchains = try await HTTP.getReleaseToolchains()
56+
let toolchains = try await self.httpClient.getReleaseToolchains()
5157
.map(ToolchainVersion.stable)
5258
.filter { selector?.matches(toolchain: $0) ?? true }
5359

Sources/Swiftly/Swiftly.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public struct Swiftly: SwiftlyCommand {
1818
Use.self,
1919
Uninstall.self,
2020
List.self,
21+
Update.self,
2122
]
2223
)
2324

Sources/Swiftly/Uninstall.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ struct Uninstall: SwiftlyCommand {
5959
for toolchain in toolchains {
6060
SwiftlyCore.print(" \(toolchain)")
6161
}
62-
let proceed = SwiftlyCore.readLine(prompt: "Proceed? (y/n)") ?? "n"
6362

64-
guard proceed == "y" else {
63+
guard SwiftlyCore.promptForConfirmation(defaultBehavior: true) else {
6564
SwiftlyCore.print("Aborting uninstall")
6665
return
6766
}
@@ -90,7 +89,7 @@ struct Uninstall: SwiftlyCommand {
9089
?? config.listInstalledToolchains(selector: .latest).filter({ !toolchains.contains($0) }).max()
9190
?? config.installedToolchains.filter({ !toolchains.contains($0) }).max()
9291
{
93-
try await Use.execute(toUse, config: &config)
92+
try await Use.execute(toUse, &config)
9493
} else {
9594
// If there are no more toolchains installed, just unuse the currently active toolchain.
9695
try Swiftly.currentPlatform.unUse(currentToolchain: toolchain)
@@ -99,14 +98,18 @@ struct Uninstall: SwiftlyCommand {
9998
}
10099
}
101100

102-
SwiftlyCore.print("Uninstalling \(toolchain)...", terminator: "")
103-
try Swiftly.currentPlatform.uninstall(toolchain)
104-
config.installedToolchains.remove(toolchain)
105-
try config.save()
106-
SwiftlyCore.print("done")
101+
try await Self.execute(toolchain, &config)
107102
}
108103

109104
SwiftlyCore.print()
110105
SwiftlyCore.print("\(toolchains.count) toolchain(s) successfully uninstalled")
111106
}
107+
108+
static func execute(_ toolchain: ToolchainVersion, _ config: inout Config) async throws {
109+
SwiftlyCore.print("Uninstalling \(toolchain)...", terminator: "")
110+
try Swiftly.currentPlatform.uninstall(toolchain)
111+
config.installedToolchains.remove(toolchain)
112+
try config.save()
113+
SwiftlyCore.print("done")
114+
}
112115
}

0 commit comments

Comments
 (0)