@@ -352,6 +352,45 @@ extension __CommandLineArguments_v0: Codable {
352
352
}
353
353
}
354
354
355
+ extension RandomAccessCollection < String > {
356
+ /// Get the value of the command line argument with the given name.
357
+ ///
358
+ /// - Parameters:
359
+ /// - label: The label or name of the argument, e.g. `"--attachments-path"`.
360
+ /// - index: The index where `label` should be found, or `nil` to search the
361
+ /// entire collection.
362
+ ///
363
+ /// - Returns: The value of the argument named by `label` at `index`. If no
364
+ /// value is available, or if `index` is not `nil` and the argument at
365
+ /// `index` is not named `label`, returns `nil`.
366
+ ///
367
+ /// This function handles arguments of the form `--label value` and
368
+ /// `--label=value`. Other argument syntaxes are not supported.
369
+ fileprivate func argumentValue( forLabel label: String , at index: Index ? = nil ) -> String ? {
370
+ guard let index else {
371
+ return indices. lazy
372
+ . compactMap { argumentValue ( forLabel: label, at: $0) }
373
+ . first
374
+ }
375
+
376
+ let element = self [ index]
377
+ if element == label {
378
+ let nextIndex = self . index ( after: index)
379
+ if nextIndex < endIndex {
380
+ return self [ nextIndex]
381
+ }
382
+ } else {
383
+ // Find an element equal to something like "--foo=bar" and split it.
384
+ let prefix = " \( label) = "
385
+ if element. hasPrefix ( prefix) , let equalsIndex = element. firstIndex ( of: " = " ) {
386
+ return String ( element [ equalsIndex... ] . dropFirst ( ) )
387
+ }
388
+ }
389
+
390
+ return nil
391
+ }
392
+ }
393
+
355
394
/// Initialize this instance given a sequence of command-line arguments passed
356
395
/// from Swift Package Manager.
357
396
///
@@ -366,10 +405,6 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
366
405
// Do not consider the executable path AKA argv[0].
367
406
let args = args. dropFirst ( )
368
407
369
- func isLastArgument( at index: [ String ] . Index) -> Bool {
370
- args. index ( after: index) >= args. endIndex
371
- }
372
-
373
408
#if !SWT_NO_FILE_IO
374
409
#if canImport(Foundation)
375
410
// Configuration for the test run passed in as a JSON file (experimental)
@@ -379,9 +414,7 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
379
414
// NOTE: While the output event stream is opened later, it is necessary to
380
415
// open the configuration file early (here) in order to correctly construct
381
416
// the resulting __CommandLineArguments_v0 instance.
382
- if let configurationIndex = args. firstIndex ( of: " --configuration-path " ) ?? args. firstIndex ( of: " --experimental-configuration-path " ) ,
383
- !isLastArgument( at: configurationIndex) {
384
- let path = args [ args. index ( after: configurationIndex) ]
417
+ if let path = args. argumentValue ( forLabel: " --configuration-path " ) ?? args. argumentValue ( forLabel: " --experimental-configuration-path " ) {
385
418
let file = try FileHandle ( forReadingAtPath: path)
386
419
let configurationJSON = try file. readToEnd ( )
387
420
result = try configurationJSON. withUnsafeBufferPointer { configurationJSON in
@@ -394,24 +427,22 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
394
427
}
395
428
396
429
// Event stream output
397
- if let eventOutputIndex = args. firstIndex ( of: " --event-stream-output-path " ) ?? args. firstIndex ( of: " --experimental-event-stream-output " ) ,
398
- !isLastArgument( at: eventOutputIndex) {
399
- result. eventStreamOutputPath = args [ args. index ( after: eventOutputIndex) ]
430
+ if let path = args. argumentValue ( forLabel: " --event-stream-output-path " ) ?? args. argumentValue ( forLabel: " --experimental-event-stream-output " ) {
431
+ result. eventStreamOutputPath = path
400
432
}
433
+
401
434
// Event stream version
402
435
do {
403
- var eventOutputVersionIndex : Array < String > . Index ?
436
+ var versionString : String ?
404
437
var allowExperimental = false
405
- eventOutputVersionIndex = args. firstIndex ( of : " --event-stream-version " )
406
- if eventOutputVersionIndex == nil {
407
- eventOutputVersionIndex = args. firstIndex ( of : " --experimental-event-stream-version " )
408
- if eventOutputVersionIndex != nil {
438
+ versionString = args. argumentValue ( forLabel : " --event-stream-version " )
439
+ if versionString == nil {
440
+ versionString = args. argumentValue ( forLabel : " --experimental-event-stream-version " )
441
+ if versionString != nil {
409
442
allowExperimental = true
410
443
}
411
444
}
412
- if let eventOutputVersionIndex, !isLastArgument( at: eventOutputVersionIndex) {
413
- let versionString = args [ args. index ( after: eventOutputVersionIndex) ]
414
-
445
+ if let versionString {
415
446
// If the caller specified a version that could not be parsed, treat it as
416
447
// an invalid argument.
417
448
guard let eventStreamVersion = VersionNumber ( versionString) else {
@@ -432,14 +463,13 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
432
463
#endif
433
464
434
465
// XML output
435
- if let xunitOutputIndex = args. firstIndex ( of : " --xunit-output " ) , !isLastArgument ( at : xunitOutputIndex ) {
436
- result. xunitOutput = args [ args . index ( after : xunitOutputIndex ) ]
466
+ if let xunitOutputPath = args. argumentValue ( forLabel : " --xunit-output " ) {
467
+ result. xunitOutput = xunitOutputPath
437
468
}
438
469
439
470
// Attachment output
440
- if let attachmentsPathIndex = args. firstIndex ( of: " --attachments-path " ) ?? args. firstIndex ( of: " --experimental-attachments-path " ) ,
441
- !isLastArgument( at: attachmentsPathIndex) {
442
- result. attachmentsPath = args [ args. index ( after: attachmentsPathIndex) ]
471
+ if let attachmentsPath = args. argumentValue ( forLabel: " --attachments-path " ) ?? args. argumentValue ( forLabel: " --experimental-attachments-path " ) {
472
+ result. attachmentsPath = attachmentsPath
443
473
}
444
474
#endif
445
475
@@ -457,13 +487,12 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
457
487
}
458
488
459
489
// Whether or not to symbolicate backtraces in the event stream.
460
- if let symbolicateBacktracesIndex = args. firstIndex ( of : " --symbolicate-backtraces " ) , !isLastArgument ( at : symbolicateBacktracesIndex ) {
461
- result. symbolicateBacktraces = args [ args . index ( after : symbolicateBacktracesIndex ) ]
490
+ if let symbolicateBacktraces = args. argumentValue ( forLabel : " --symbolicate-backtraces " ) {
491
+ result. symbolicateBacktraces = symbolicateBacktraces
462
492
}
463
493
464
494
// Verbosity
465
- if let verbosityIndex = args. firstIndex ( of: " --verbosity " ) , !isLastArgument( at: verbosityIndex) ,
466
- let verbosity = Int ( args [ args. index ( after: verbosityIndex) ] ) {
495
+ if let verbosity = args. argumentValue ( forLabel: " --verbosity " ) . flatMap ( Int . init) {
467
496
result. verbosity = verbosity
468
497
}
469
498
if args. contains ( " --verbose " ) || args. contains ( " -v " ) {
@@ -478,9 +507,7 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
478
507
479
508
// Filtering
480
509
func filterValues( forArgumentsWithLabel label: String ) -> [ String ] {
481
- args. indices. lazy
482
- . filter { args [ $0] == label && $0 < args. endIndex }
483
- . map { args [ args. index ( after: $0) ] }
510
+ args. indices. compactMap { args. argumentValue ( forLabel: label, at: $0) }
484
511
}
485
512
let filter = filterValues ( forArgumentsWithLabel: " --filter " )
486
513
if !filter. isEmpty {
@@ -492,11 +519,11 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum
492
519
}
493
520
494
521
// Set up the iteration policy for the test run.
495
- if let repetitionsIndex = args. firstIndex ( of : " --repetitions " ) , !isLastArgument ( at : repetitionsIndex ) {
496
- result. repetitions = Int ( args [ args . index ( after : repetitionsIndex ) ] )
522
+ if let repetitions = args. argumentValue ( forLabel : " --repetitions " ) . flatMap ( Int . init ) {
523
+ result. repetitions = repetitions
497
524
}
498
- if let repeatUntilIndex = args. firstIndex ( of : " --repeat-until " ) , !isLastArgument ( at : repeatUntilIndex ) {
499
- result. repeatUntil = args [ args . index ( after : repeatUntilIndex ) ]
525
+ if let repeatUntil = args. argumentValue ( forLabel : " --repeat-until " ) {
526
+ result. repeatUntil = repeatUntil
500
527
}
501
528
502
529
return result
0 commit comments