Skip to content

Commit ef4f15f

Browse files
authored
Improve output when validation fails (#744)
With backtrace support built into command-line Swift, calling `fatalError` for configuration/validation errors isn't very effective, since the error messages get hidden by the backtrace. This switches to simply printing the validation message to stderr and exiting with a failing error code, which possibly should have always been the behavior. This also revamps the file structure for validators.
1 parent be711ca commit ef4f15f

15 files changed

+471
-425
lines changed

Sources/ArgumentParser/CMakeLists.txt

+7-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ add_library(ArgumentParser
2121
"Parsable Types/EnumerableFlag.swift"
2222
"Parsable Types/ExpressibleByArgument.swift"
2323
"Parsable Types/ParsableArguments.swift"
24-
"Parsable Types/ParsableArgumentsValidation.swift"
2524
"Parsable Types/ParsableCommand.swift"
2625

2726
Parsing/ArgumentDecoder.swift
@@ -47,7 +46,13 @@ add_library(ArgumentParser
4746
Utilities/Platform.swift
4847
Utilities/SequenceExtensions.swift
4948
Utilities/StringExtensions.swift
50-
Utilities/Tree.swift)
49+
Utilities/Tree.swift
50+
51+
Validators/CodingKeyValidator.swift
52+
Validators/NonsenseFlagsValidator.swift
53+
Validators/ParsableArgumentsValidation.swift
54+
Validators/PositionalArgumentsValidator.swift
55+
Validators/UniqueNamesValidator.swift)
5156
# NOTE: workaround for CMake not setting up include flags yet
5257
set_target_properties(ArgumentParser PROPERTIES
5358
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})

Sources/ArgumentParser/Parsable Properties/Argument.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public struct Argument<Value>:
8282
case .value(let v):
8383
return v
8484
case .definition:
85-
fatalError(directlyInitializedError)
85+
configurationFailure(directlyInitializedError)
8686
}
8787
}
8888
set {

Sources/ArgumentParser/Parsable Properties/Flag.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public struct Flag<Value>: Decodable, ParsedWrapper {
107107
case .value(let v):
108108
return v
109109
case .definition:
110-
fatalError(directlyInitializedError)
110+
configurationFailure(directlyInitializedError)
111111
}
112112
}
113113
set {

Sources/ArgumentParser/Parsable Properties/Option.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public struct Option<Value>: Decodable, ParsedWrapper {
8787
case .value(let v):
8888
return v
8989
case .definition:
90-
fatalError(directlyInitializedError)
90+
configurationFailure(directlyInitializedError)
9191
}
9292
}
9393
set {

Sources/ArgumentParser/Parsable Properties/OptionGroup.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public struct OptionGroup<Value: ParsableArguments>: Decodable, ParsedWrapper {
101101
case .value(let v):
102102
return v
103103
case .definition:
104-
fatalError(directlyInitializedError)
104+
configurationFailure(directlyInitializedError)
105105
}
106106
}
107107
set {

Sources/ArgumentParser/Parsable Types/ParsableArguments.swift

+15-5
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ extension ArgumentSet {
290290
do {
291291
try type._validate(parent: parent)
292292
} catch {
293-
assertionFailure("\(error)")
293+
configurationFailure("\(error)")
294294
}
295295
#endif
296296

@@ -321,11 +321,23 @@ extension ArgumentSet {
321321
}
322322
}
323323

324+
/// Prints the given message to standard error and exits with a failure code.
325+
///
326+
/// - Parameter message: The message to print to standard error. `message`
327+
/// should be pre-wrapped, if desired.
328+
func configurationFailure(_ message: String) -> Never {
329+
var errorOut = Platform.standardError
330+
print("\n", to: &errorOut)
331+
print(String(repeating: "-", count: 70), to: &errorOut)
332+
print(message, to: &errorOut)
333+
print(String(repeating: "-", count: 70), to: &errorOut)
334+
print("\n", to: &errorOut)
335+
Platform.exit(Platform.exitCodeFailure)
336+
}
337+
324338
/// The fatal error message to display when someone accesses a
325339
/// `ParsableArguments` type after initializing it directly.
326340
internal let directlyInitializedError = """
327-
328-
--------------------------------------------------------------------
329341
Can't read a value from a parsable argument definition.
330342
331343
This error indicates that a property declared with an `@Argument`,
@@ -335,6 +347,4 @@ internal let directlyInitializedError = """
335347
To get a valid value, either call one of the static parsing methods
336348
(`parse`, `parseAsRoot`, or `main`) or define an initializer that
337349
initializes _every_ property of your parsable type.
338-
--------------------------------------------------------------------
339-
340350
"""

0 commit comments

Comments
 (0)