@@ -84,31 +84,8 @@ struct Install: SwiftlyCommand {
84
84
try validateSwiftly ( ctx)
85
85
86
86
var config = try Config . load ( ctx)
87
+ let toolchainVersion = try await Self . determineToolchainVersion ( ctx, version: self . version, config: & config)
87
88
88
- var selector : ToolchainSelector
89
-
90
- if let version = self . version {
91
- selector = try ToolchainSelector ( parsing: version)
92
- } else {
93
- if case let ( _, result) = try await selectToolchain ( ctx, config: & config) ,
94
- case let . swiftVersionFile( _, sel, error) = result
95
- {
96
- if let sel = sel {
97
- selector = sel
98
- } else if let error = error {
99
- throw error
100
- } else {
101
- throw SwiftlyError ( message: " Internal error selecting toolchain to install. " )
102
- }
103
- } else {
104
- throw SwiftlyError (
105
- message:
106
- " Swiftly couldn't determine the toolchain version to install. Please set a version like this and try again: `swiftly install latest` "
107
- )
108
- }
109
- }
110
-
111
- let toolchainVersion = try await Self . resolve ( ctx, config: config, selector: selector)
112
89
let ( postInstallScript, pathChanged) = try await Self . execute (
113
90
ctx,
114
91
version: toolchainVersion,
@@ -158,6 +135,101 @@ struct Install: SwiftlyCommand {
158
135
to: URL ( fileURLWithPath: postInstallFile) , options: . atomic
159
136
)
160
137
}
138
+ }
139
+
140
+ public static func setupProxies(
141
+ _ ctx: SwiftlyCoreContext ,
142
+ version: ToolchainVersion ,
143
+ verbose: Bool ,
144
+ assumeYes: Bool
145
+ ) async throws -> Bool {
146
+ var pathChanged = false
147
+
148
+ // Create proxies if we have a location where we can point them
149
+ if let proxyTo = try ? Swiftly . currentPlatform. findSwiftlyBin ( ctx) {
150
+ // Ensure swiftly doesn't overwrite any existing executables without getting confirmation first.
151
+ let swiftlyBinDir = Swiftly . currentPlatform. swiftlyBinDir ( ctx)
152
+ let swiftlyBinDirContents =
153
+ ( try ? FileManager . default. contentsOfDirectory ( atPath: swiftlyBinDir. path) ) ?? [ String] ( )
154
+ let toolchainBinDir = Swiftly . currentPlatform. findToolchainBinDir ( ctx, version)
155
+ let toolchainBinDirContents = try FileManager . default. contentsOfDirectory (
156
+ atPath: toolchainBinDir. path)
157
+
158
+ let existingProxies = swiftlyBinDirContents. filter { bin in
159
+ do {
160
+ let linkTarget = try FileManager . default. destinationOfSymbolicLink (
161
+ atPath: swiftlyBinDir. appendingPathComponent ( bin) . path)
162
+ return linkTarget == proxyTo
163
+ } catch { return false }
164
+ }
165
+
166
+ let overwrite = Set ( toolchainBinDirContents) . subtracting ( existingProxies) . intersection (
167
+ swiftlyBinDirContents)
168
+ if !overwrite. isEmpty && !assumeYes {
169
+ await ctx. print ( " The following existing executables will be overwritten: " )
170
+
171
+ for executable in overwrite {
172
+ await ctx. print ( " \( swiftlyBinDir. appendingPathComponent ( executable) . path) " )
173
+ }
174
+
175
+ guard await ctx. promptForConfirmation ( defaultBehavior: false ) else {
176
+ throw SwiftlyError ( message: " Toolchain installation has been cancelled " )
177
+ }
178
+ }
179
+
180
+ if verbose {
181
+ await ctx. print ( " Setting up toolchain proxies... " )
182
+ }
183
+
184
+ let proxiesToCreate = Set ( toolchainBinDirContents) . subtracting ( swiftlyBinDirContents) . union (
185
+ overwrite)
186
+
187
+ for p in proxiesToCreate {
188
+ let proxy = Swiftly . currentPlatform. swiftlyBinDir ( ctx) . appendingPathComponent ( p)
189
+
190
+ if proxy. fileExists ( ) {
191
+ try FileManager . default. removeItem ( at: proxy)
192
+ }
193
+
194
+ try FileManager . default. createSymbolicLink (
195
+ atPath: proxy. path,
196
+ withDestinationPath: proxyTo
197
+ )
198
+
199
+ pathChanged = true
200
+ }
201
+ }
202
+ return pathChanged
203
+ }
204
+
205
+ static func determineToolchainVersion(
206
+ _ ctx: SwiftlyCoreContext ,
207
+ version: String ? ,
208
+ config: inout Config
209
+ ) async throws -> ToolchainVersion {
210
+ let selector : ToolchainSelector
211
+
212
+ if let version = version {
213
+ selector = try ToolchainSelector ( parsing: version)
214
+ } else {
215
+ if case let ( _, result) = try await selectToolchain ( ctx, config: & config) ,
216
+ case let . swiftVersionFile( _, sel, error) = result {
217
+ if let sel = sel {
218
+ selector = sel
219
+ } else if let error = error {
220
+ throw error
221
+ } else {
222
+ throw SwiftlyError ( message: " Internal error selecting toolchain to install. " )
223
+ }
224
+ } else {
225
+ throw SwiftlyError (
226
+ message:
227
+ " Swiftly couldn't determine the toolchain version to install. Please set a version like this and try again: `swiftly install latest` "
228
+ )
229
+ }
230
+ }
231
+
232
+ return try await Self . resolve ( ctx, config: config, selector: selector)
161
233
}
162
234
163
235
public static func execute(
@@ -274,62 +346,12 @@ struct Install: SwiftlyCommand {
274
346
275
347
try await Swiftly . currentPlatform. install ( ctx, from: tmpFile, version: version, verbose: verbose)
276
348
277
- var pathChanged = false
278
-
279
- // Create proxies if we have a location where we can point them
280
- if let proxyTo = try ? Swiftly . currentPlatform. findSwiftlyBin ( ctx) {
281
- // Ensure swiftly doesn't overwrite any existing executables without getting confirmation first.
282
- let swiftlyBinDir = Swiftly . currentPlatform. swiftlyBinDir ( ctx)
283
- let swiftlyBinDirContents =
284
- ( try ? FileManager . default. contentsOfDirectory ( atPath: swiftlyBinDir. path) ) ?? [ String] ( )
285
- let toolchainBinDir = Swiftly . currentPlatform. findToolchainBinDir ( ctx, version)
286
- let toolchainBinDirContents = try FileManager . default. contentsOfDirectory (
287
- atPath: toolchainBinDir. path)
288
-
289
- let existingProxies = swiftlyBinDirContents. filter { bin in
290
- do {
291
- let linkTarget = try FileManager . default. destinationOfSymbolicLink (
292
- atPath: swiftlyBinDir. appendingPathComponent ( bin) . path)
293
- return linkTarget == proxyTo
294
- } catch { return false }
295
- }
296
-
297
- let overwrite = Set ( toolchainBinDirContents) . subtracting ( existingProxies) . intersection (
298
- swiftlyBinDirContents)
299
- if !overwrite. isEmpty && !assumeYes {
300
- await ctx. print ( " The following existing executables will be overwritten: " )
301
-
302
- for executable in overwrite {
303
- await ctx. print ( " \( swiftlyBinDir. appendingPathComponent ( executable) . path) " )
304
- }
305
-
306
- guard await ctx. promptForConfirmation ( defaultBehavior: false ) else {
307
- throw SwiftlyError ( message: " Toolchain installation has been cancelled " )
308
- }
309
- }
310
-
311
- if verbose {
312
- await ctx. print ( " Setting up toolchain proxies... " )
313
- }
314
-
315
- let proxiesToCreate = Set ( toolchainBinDirContents) . subtracting ( swiftlyBinDirContents) . union (
316
- overwrite)
317
-
318
- for p in proxiesToCreate {
319
- let proxy = Swiftly . currentPlatform. swiftlyBinDir ( ctx) . appendingPathComponent ( p)
320
-
321
- if proxy. fileExists ( ) {
322
- try FileManager . default. removeItem ( at: proxy)
323
- }
324
-
325
- try FileManager . default. createSymbolicLink (
326
- atPath: proxy. path,
327
- withDestinationPath: proxyTo
328
- )
329
-
330
- pathChanged = true
331
- }
332
- }
349
+ let pathChanged = try await Self . setupProxies (
350
+ ctx,
351
+ version: version,
352
+ verbose: verbose,
353
+ assumeYes: assumeYes
354
+ )
333
355
334
356
config. installedToolchains. insert ( version)
335
357
0 commit comments