@@ -71,10 +71,20 @@ struct Install: SwiftlyCommand {
71
71
) )
72
72
var postInstallFile : FilePath ?
73
73
74
+ @Option (
75
+ help: ArgumentHelp (
76
+ " A file path where progress information will be written in JSONL format " ,
77
+ discussion: """
78
+ Progress information will be appended to this file as JSON objects, one per line.
79
+ Each progress entry contains timestamp, progress percentage, and a descriptive message.
80
+ """
81
+ ) )
82
+ var progressFile : FilePath ?
83
+
74
84
@OptionGroup var root : GlobalOptions
75
85
76
86
private enum CodingKeys : String , CodingKey {
77
- case version, use, verify, postInstallFile, root
87
+ case version, use, verify, postInstallFile, root, progressFile
78
88
}
79
89
80
90
mutating func run( ) async throws {
@@ -93,7 +103,9 @@ struct Install: SwiftlyCommand {
93
103
try await validateLinked ( ctx)
94
104
95
105
var config = try await Config . load ( ctx)
96
- let toolchainVersion = try await Self . determineToolchainVersion ( ctx, version: self . version, config: & config)
106
+ let toolchainVersion = try await Self . determineToolchainVersion (
107
+ ctx, version: self . version, config: & config
108
+ )
97
109
98
110
let ( postInstallScript, pathChanged) = try await Self . execute (
99
111
ctx,
@@ -102,7 +114,8 @@ struct Install: SwiftlyCommand {
102
114
useInstalledToolchain: self . use,
103
115
verifySignature: self . verify,
104
116
verbose: self . root. verbose,
105
- assumeYes: self . root. assumeYes
117
+ assumeYes: self . root. assumeYes,
118
+ progressFile: self . progressFile
106
119
)
107
120
108
121
let shell =
@@ -192,8 +205,9 @@ struct Install: SwiftlyCommand {
192
205
await ctx. message ( " Setting up toolchain proxies... " )
193
206
}
194
207
195
- let proxiesToCreate = Set ( toolchainBinDirContents) . subtracting ( swiftlyBinDirContents) . union (
196
- overwrite)
208
+ let proxiesToCreate = Set ( toolchainBinDirContents) . subtracting ( swiftlyBinDirContents)
209
+ . union (
210
+ overwrite)
197
211
198
212
for p in proxiesToCreate {
199
213
let proxy = Swiftly . currentPlatform. swiftlyBinDir ( ctx) / p
@@ -248,7 +262,8 @@ struct Install: SwiftlyCommand {
248
262
useInstalledToolchain: Bool,
249
263
verifySignature: Bool,
250
264
verbose: Bool,
251
- assumeYes: Bool
265
+ assumeYes: Bool,
266
+ progressFile: FilePath? = nil
252
267
) async throws -> ( postInstall: String? , pathChanged: Bool) {
253
268
guard !config. installedToolchains. contains ( version) else {
254
269
await ctx. message ( " \( version) is already installed. " )
@@ -258,10 +273,11 @@ struct Install: SwiftlyCommand {
258
273
// Ensure the system is set up correctly before downloading it. Problems that prevent installation
259
274
// will throw, while problems that prevent use of the toolchain will be written out as a post install
260
275
// script for the user to run afterwards.
261
- let postInstallScript = try await Swiftly . currentPlatform. verifySystemPrerequisitesForInstall (
262
- ctx, platformName: config. platform. name, version: version,
263
- requireSignatureValidation: verifySignature
264
- )
276
+ let postInstallScript = try await Swiftly . currentPlatform
277
+ . verifySystemPrerequisitesForInstall (
278
+ ctx, platformName: config. platform. name, version: version,
279
+ requireSignatureValidation: verifySignature
280
+ )
265
281
266
282
await ctx. message ( " Installing \( version) " )
267
283
@@ -296,10 +312,13 @@ struct Install: SwiftlyCommand {
296
312
}
297
313
}
298
314
299
- let animation = PercentProgressAnimation (
300
- stream: stdoutStream,
301
- header: " Downloading \( version) "
302
- )
315
+ let animation : ProgressAnimationProtocol =
316
+ progressFile != nil
317
+ ? JsonFileProgressReporter ( filePath: progressFile!)
318
+ : PercentProgressAnimation (
319
+ stream: stdoutStream,
320
+ header: " Downloading \( version) "
321
+ )
303
322
304
323
var lastUpdate = Date ( )
305
324
@@ -315,7 +334,9 @@ struct Install: SwiftlyCommand {
315
334
reportProgress: { progress in
316
335
let now = Date ( )
317
336
318
- guard lastUpdate. distance ( to: now) > 0.25 || progress. receivedBytes == progress. totalBytes
337
+ guard
338
+ lastUpdate. distance ( to: now) > 0.25
339
+ || progress. receivedBytes == progress. totalBytes
319
340
else {
320
341
return
321
342
}
@@ -334,7 +355,8 @@ struct Install: SwiftlyCommand {
334
355
}
335
356
)
336
357
} catch let notFound as DownloadNotFoundError {
337
- throw SwiftlyError ( message: " \( version) does not exist at URL \( notFound. url) , exiting " )
358
+ throw SwiftlyError (
359
+ message: " \( version) does not exist at URL \( notFound. url) , exiting " )
338
360
} catch {
339
361
animation. complete ( success: false )
340
362
throw error
@@ -401,7 +423,9 @@ struct Install: SwiftlyCommand {
401
423
}
402
424
403
425
/// Utilize the swift.org API along with the provided selector to select a toolchain for install.
404
- public static func resolve( _ ctx: SwiftlyCoreContext, config: Config, selector: ToolchainSelector)
426
+ public static func resolve(
427
+ _ ctx: SwiftlyCoreContext, config: Config, selector: ToolchainSelector
428
+ )
405
429
async throws -> ToolchainVersion
406
430
{
407
431
switch selector {
@@ -426,7 +450,8 @@ struct Install: SwiftlyCommand {
426
450
}
427
451
428
452
if let patch {
429
- return . stable( ToolchainVersion . StableRelease ( major: major, minor: minor, patch: patch) )
453
+ return . stable(
454
+ ToolchainVersion . StableRelease ( major: major, minor: minor, patch: patch) )
430
455
}
431
456
432
457
await ctx. message ( " Fetching the latest stable Swift \( major) . \( minor) release... " )
0 commit comments