-
Notifications
You must be signed in to change notification settings - Fork 325
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@natecook1000 can we take this opportunity to make the indentation 2 spaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
AsyncParsableCommand
type that sports anrun() async
method, allowing for asynchronous code in a command line tool.Detailed Design
This includes the new
AsyncParsableCommand
protocol, which provides astatic func main() async
entry 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
@main
on anAsyncParsableCommand
root 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 toAsyncMainProtocol
and add the@main
attribute to that type. For example:AsyncMainProtocol
is deprecated for Swift 5.6.Documentation Plan
There's a new example included (
count-lines
) that usesAsyncParsableCommand
to 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