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

Add support for async/await where available #326

Closed
sergiocampama opened this issue Jun 11, 2021 · 14 comments · Fixed by #404
Closed

Add support for async/await where available #326

sergiocampama opened this issue Jun 11, 2021 · 14 comments · Fixed by #404

Comments

@sergiocampama
Copy link

async/await is useful for writing clean and concise code for building small CLI tools, especially ones that interact with the network or the file system.

Since @main now supports an async variant, I was able to add such support to a prototype with the following code:

// entry.swift

@available(macOS 12.0, *)
protocol AsyncParsableCommand: ParsableCommand {
    mutating func runAsync() async throws
}

extension ParsableCommand {
    static func main(_ arguments: [String]? = nil) async {
        do {
            var command = try parseAsRoot(arguments)
            if #available(macOS 12.0, *), var asyncCommand = command as? AsyncParsableCommand {
                try await asyncCommand.runAsync()
            } else {
                try command.run()
            }
        } catch {
            exit(withError: error)
        }
    }
}

struct MainCommand: AsyncParsableCommand {
    @Option()
    var name: String = "Anon"

    func runAsync() async throws {
        print("Hello, \(name)")
        // await something...
    }
}

@main
struct MainApp {
    static func main() async {
        await MainCommand.main()
    }
}

Having this be officially supported by swift-argument-parser would be ideal.

@Blackjacx
Copy link

Blackjacx commented Jul 4, 2021

Today 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: https://twitter.com/Blackjacxxx/status/1411730725393555456

@natecook1000 natecook1000 added this to the ArgumentParser 1.0 milestone Aug 25, 2021
@natecook1000 natecook1000 removed this from the ArgumentParser 1.0 milestone Sep 9, 2021
@Jerry-Carter
Copy link

Curious what the roadmap is for async/await support. Hoping to see it added to the main branch; using the async branch meanwhile.

@Frizlab
Copy link
Contributor

Frizlab commented Nov 17, 2021

Same here, eagerly waiting for async support to drop officially.

@andyzaharia
Copy link

Is there any news on this front? Seems like it should at least work on Monterey / Xcode 13.1... are there any blockers before pushing the async to main?

@Jerry-Carter
Copy link

Tried using the async branch in a proof of concept project. Had difficulty with objects in Run() getting deinitialized before the program was done. Not sure whether the error was on my side or intrinsic to the async branch. Either way, dropped back to the main branch and haven't seen any issues.

@Blackjacx
Copy link

@Jerry-Carter you could try https://github.com/Blackjacx/swift-argument-parser. It works for me quite well in my CLI application.

@Jerry-Carter
Copy link

@natecook1000
Looking at the 'More palatable async command support' changes, wouldn't it just be better to have all commands be async? Async main can contain synchronous code without issue whereas synchronous main cannot invoke async code. This would eliminate the

@main enum Main: AsyncMain {
typealias Command = <#command#>
}

ugliness. You might want to conditionally compile a definition of 'run() async' for Swift 5.5 vs. a synchronous definition for previous versions.

@everlof
Copy link

everlof commented Dec 10, 2021

@sergiocampama Does your code work with latests Xcode etc? I just keep getting:
'main' attribute cannot be used in a module that contains top-level code something you've seen?

@Jerry-Carter
Copy link

@everlof As I recall @main cannot be used in a file named 'main.swift'. Ensure that the file is named differently and that there is not, in fact, top-level code present.

@everlof
Copy link

everlof commented Dec 11, 2021

Ah, of course. Thank you! 🙏🏻

@ffried
Copy link

ffried commented Feb 8, 2022

Any news from the team on this? No "official" support for async/await here is the only thing preventing us from migrating our CLI-Tools. I'm aware of the async branch, but this is not an official release and thus doesn't work well with shipping releases in our packages.

Personally, I find the extra type conforming to AsyncMain not really ideal, but if that's what gets us official support, so be it.

@natecook1000 natecook1000 linked a pull request Feb 11, 2022 that will close this issue
4 tasks
@natecook1000
Copy link
Member

@ffried I've opened #404 to land async/await support — it will be a part of the 1.1 release once that's ready.

@ffried
Copy link

ffried commented Feb 11, 2022

@natecook1000 thank you!

@stherold
Copy link

stherold commented Mar 14, 2022

Today 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants