Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AsyncParseableCommand hierarchy #436

Merged
merged 9 commits into from Jun 13, 2022
Expand Up @@ -73,4 +73,3 @@ extension AsyncMainProtocol {
}
}
}

33 changes: 32 additions & 1 deletion Sources/ArgumentParser/Parsable Types/ParsableCommand.swift
Expand Up @@ -84,7 +84,7 @@ extension ParsableCommand {
public static func helpMessage(
for subcommand: ParsableCommand.Type,
columns: Int? = nil
) -> String {
) -> String {
helpMessage(for: subcommand, includeHidden: false, columns: columns)
}

Expand Down Expand Up @@ -124,6 +124,13 @@ extension ParsableCommand {
/// - Parameter arguments: An array of arguments to use for parsing. If
/// `arguments` is `nil`, this uses the program's command-line arguments.
public static func main(_ arguments: [String]?) {

#if DEBUG
if #available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *) {
checkAsyncHierarchy(self, root: "\(self)")
}
#endif

do {
var command = try parseAsRoot(arguments)
try command.run()
Expand Down Expand Up @@ -164,4 +171,28 @@ extension ParsableCommand {
internal static var defaultIncludesUnconditionalArguments: Bool {
configuration.defaultSubcommand?.includesUnconditionalArguments == true
}

#if DEBUG
@available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *)
internal static func checkAsyncHierarchy(_ command: ParsableCommand.Type, root: String) {
for sub in command.configuration.subcommands {
checkAsyncHierarchy(sub, root: root)

guard sub.configuration.subcommands.isEmpty else { continue }
guard sub is AsyncParsableCommand.Type else { continue }

fatalError("""

--------------------------------------------------------------------
Asynchronous subcommand of a synchronous root.

The asynchronous command `\(sub)` is declared as a subcommand of the synchronous root command `\(root)`.

With this configuration, your asynchronous `run()` method will not be called. To fix this issue, change `\(root)`'s `ParsableCommand` conformance to `AsyncParsableCommand`.
--------------------------------------------------------------------

""".wrapped(to: 70))
}
}
#endif
}