在Swift并发中使用ArgumentParser

pod7payv  于 2023-04-10  发布在  Swift
关注(0)|答案(1)|浏览(163)

我正在使用ArgumentParser包进行命令行解析,并希望将其与Swift并发的async API一起使用:

struct Foo: ParsableCommand {
    @Argument(
        help: "File to be parsed. If not present, parses stdin.",
        transform: URL.init(fileURLWithPath:)
    )
    var file: URL?

    mutating func run() async throws {
        let handle: FileHandle
        if let file {
            handle = try .init(forReadingFrom: file)
        } else {
            handle = .standardInput
        }

        for try await line in handle.bytes.lines {
            // do something with each line
        }

        try handle.close()
    }
}

但是当我这样做的时候,我总是看到“用法”文本:

USAGE: foo [<file>]

ARGUMENTS:
  <file>                  File to be parsed. If not present, parses stdin.

OPTIONS:
  -h, --help              Show help information.

我没有得到编译错误,但无论是否提供参数,我总是看到“USAGE”文本。

bkkx9g8r

bkkx9g8r1#

问题是将ParsableCommandrun() async throws结合使用。
使用AsyncParsableCommand代替。正如它的documentation所说:
要在命令的run()方法实现中使用async/await代码,请执行以下步骤:
1.对于命令行工具中的根命令,声明与AsyncParsableCommand的一致性,无论该命令是否使用异步代码。
1.将@main属性应用于根命令。(注意:如果root命令位于main.Swift文件中,请将该文件重命名为该命令的名称。)
1.对于任何需要使用异步代码的命令,声明与AsyncParsableCommand的一致性,并将run()方法标记为async。对于不使用异步代码的子命令,不需要进行任何更改。
不幸的是,虽然更广泛的documentation偶尔会提到支持async,但您必须深入研究代码示例(特别是count-lines)或浏览整个类库才能偶然发现AsyncParsableCommand
因此,使用AsyncParsableCommandrunasync再现:

import ArgumentParser

@main
struct Foo: AsyncParsableCommand {
    @Argument(
        help: "File to be parsed. If not present, parses stdin.",
        transform: URL.init(fileURLWithPath:)
    )
    var file: URL?

    mutating func run() async throws {
        let handle: FileHandle
        if let file {
            handle = try .init(forReadingFrom: file)
        } else {
            handle = .standardInput
        }

        for try await line in handle.bytes.lines {
            // do something with each line
        }

        try handle.close()
    }
}

但是,不幸的是,如果您不小心将runasync版本与ParsableCommand一起使用,它编译时没有错误,但无论何时运行它都会产生“USAGE”文本,而没有任何关于 * 为什么 * 它不工作的诊断信息。
简而言之,ParsableCommand需要run的非async副本。async副本需要AsyncParsableCommand

相关问题