Support an async entry point for commands#404
Conversation
Adds a new `AsyncParsableCommand` protocol, which provides a `static func main() async` entry point and can call through to the root command's or a subcommand's asynchronous `run()` method. For this asynchronous execution, the root command must conform to `AsyncParsableCommand`, but its subcommands can be a mix of asynchronous and synchronous commands. Due to an issue in Swift 5.5, you can only use `@main` on an `AsyncParsableCommand` root command starting in Swift 5.6. This change also includes a workaround for clients that are using Swift 5.5. Declare a separate type that conforms to `AsyncMainProtocol` and add the `@main` attribute to that type. ``` @main enum Main: AsyncMain { typealias Command = <#command#> } ```
|
@swift-ci Please test |
|
@swift-ci Please test |
| @@ -1,4 +1,4 @@ | |||
| // swift-tools-version:5.2 | |||
There was a problem hiding this comment.
If this PR ends up changing the minimum supported Swift version from 5.2 to 5.5, that will be a breaking change for any consumers who support compiling with Swift < 5.5. Is the intention to ship this as part of a 2.0 release or is breaking Swift version support not considered a semver breaking change?
There was a problem hiding this comment.
Good question, @jpsim! The plan is to ship this change as part of the 1.1.0 release. My understanding is that this isn't a source breaking change, since clients using older versions of Swift will just continue to get version 1.0.3. That said, I do have the wrong platform setting below — will update that. Thanks!
There was a problem hiding this comment.
Is there a reason why we don't wrap the new stuff in #if swift(>=5.5), and in turn keep support for older Swift versions?
There was a problem hiding this comment.
@ffried Not to say that you shouldn't, what are your use cases where you need to support older swift versions like 5.2?
There was a problem hiding this comment.
@rauhul I don't have any myself. I was just wondering in case this is considered a breaking change.
There was a problem hiding this comment.
Usage of older Swift versions like 5.1/5.2 is higher than you might think (15% of this survey's respondents).
That might be a convincing enough reason to upgrade. IMO we (the community + apple package owners) should come up with some guidelines for version support. I think NIO announced they will support only the latest 2 swift versions. (Though I might be mis-remembering).
@Lukasa what is swift-nio's policy for swift version support and do you consider dropping support for a swift version a breaking change?
There was a problem hiding this comment.
We are proposing to support the latest Swift version and the two versions prior. We do not consider dropping Swift versions to be a breaking change, because as @natecook1000 says, SwiftPM takes the tools version into account when resolving what version of a package will be used. Users silently get the last version that supported their Swift version.
There was a problem hiding this comment.
SwiftPM takes the tools version into account when resolving what version of a package will be used. Users silently get the last version that supported their Swift version
This is a big surprise to me since it means SwiftPM needs to check out multiple versions of a dependency in order to identify which on is the last to be compatible with the current swift version. Until today I thought SwiftPM just looked at the git tags to determine which version of a dependency to resolve.
If this is the case, then I have no objections to versioning this with 1.1.0.
@rauhul it'd be great if there were guidelines for Swift version support for Swift library authors.
There was a problem hiding this comment.
@jpsim This seems like a good conversation to start on the swift forums, I'm 100% certain people have opinions... (for better or worse)
There was a problem hiding this comment.
A fun irony here is that we discussed the tools version change, but I missed that this also added a platforms stanza, and while changing the tools version isn't breaking, changing the platforms stanza very much is.
|
@swift-ci Please test |
|
@swift-ci Please test |
|
@swift-ci Please test |
|
@swift-ci Please test macOS platform |
| @@ -14,6 +14,7 @@ import PackageDescription | |||
|
|
|||
| var package = Package( | |||
There was a problem hiding this comment.
@natecook1000 can we take this opportunity to make the indentation 2 spaces?
There was a problem hiding this comment.
Oh sure. It should be 4 in code samples and example code and 2 everywhere else.
|
@swift-ci please test |
|
@swift-ci Please test macOS platform |
1 similar comment
|
@swift-ci Please test macOS platform |
|
Shifted our test platform to 5.6 for our async version. Wanted to let you know that we've been able to considerably simplify our code around swift-argument-parser. This is looking good, Nate. |
|
@swift-ci Please test |
|
I refactored my App Store Connect API tool with using the async branch and integrating async/await using the async branch of the argument parser was sooooo satisfying. Good job everyone 👍🏼 hope this makes it in the official release soon. It is soo soo great :) For the interested of you here are some links: twitter.com/Blackjacxxx/status/1411730725393555456 |
|
@swift-ci Please test |
This fixes the build with CMake after apple#404.
* 'main' of github.com:apple/swift-argument-parser: (114 commits) Fix `AsyncParseableCommand` hierarchy (apple#436) Add experimental manual page generation (apple#332) Improving edit distance string extension (apple#446) List valid options in error messages for enum array argument (apple#445) Remove LinuxMain.swift (apple#367) Hide hidden subcommands from completions (apple#443) Update changelog for 1.1.2 release (apple#441) Fix error message for @option array without values (apple#435) Fix Repeat's endless printing (apple#437) build: statically link ArgumentParserToolInfo always (apple#424) Update changelog for the 1.1.1 release (apple#428) build: complete the changes from apple#423 (apple#425) Remove platform requirement from Package.swift (apple#427) build: repair the build after apple#404 (apple#423) Fix broken links/incorrect variance calculation (apple#422) Update changelog for the 1.1.0 release (apple#421) Update documentation (apple#420) Make `@OptionGroup(visibility:)` a public API (apple#419) Support an `async` entry point for commands (apple#404) Fix a typo and template links (apple#418) ...
Description
Adds an
AsyncParsableCommandtype that sports anrun() asyncmethod, allowing for asynchronous code in a command line tool.Detailed Design
This includes the new
AsyncParsableCommandprotocol, which provides astatic func main() asyncentry point and can call through to the root command's or a subcommand's asynchronousrun()method. For this asynchronous execution, the root command must conform toAsyncParsableCommand, but its subcommands can be a mix of asynchronous and synchronous commands.Due to an issue in Swift 5.5, you can only use
@mainon anAsyncParsableCommandroot command starting in Swift 5.6. This PR also includes a workaround for clients that are using Swift 5.5. Declare a separate type that conforms toAsyncMainProtocoland add the@mainattribute to that type. For example:AsyncMainProtocolis deprecated for Swift 5.6.Documentation Plan
There's a new example included (
count-lines) that usesAsyncParsableCommandto read lines asynchronously, demonstrating the feature. A new guide for creating asynchronous commands is still TK.Test Plan
As an entry point, this feature is tested by invoking the built executable via a new test in
ArgumentParserExampleTests.Source Impact
This change requires an upgrade in Swift versions to 5.5, but is otherwise source compatible.
Checklist