一个优雅的纯 Swift 库,用于构建命令行应用程序。
swift build
dependencies: [
.Package(url: "https://github.com/surfandneptune/CommandCougar.git", from: "1.0.0")
]
CommandCougar 支持主命令以及子命令。这非常类似于 swift package manager 的接口。
命令是一个 struct
,用于概述命令行界面的结构。它可以有一个子命令列表或一个(.required
| .optional
) 参数列表。
var helloCommand = Command(
name: "hello",
overview: "Say Hello",
callback: { print($0.options, $0.parameters) },
options: [
Option(flag: .short("v"), overview: "Increase verbosity"),
Option(flag: .short("w"), overview: "Wave hello")
],
parameters:[.optional("Name")])
一旦创建了一个命令,就可以针对一系列参数对其进行评估,通常这些参数来自 CommandLine.arguments。 evaluate 函数创建并返回一个 CommandEvaluation
。
let arguments = ["hello", "-v", "Mr.Rogers"]
let helloEvaluation = helloCommand.evaluate(arguments: arguments)
通常,参数的输入将由 CommandLine.arguments 提供。请注意,CommandCougar 会自动删除第一个参数。
let helloEvaluation = helloCommand.evaluate(arguments: CommandLine.arguments)
CommandEvaluation
是一个 struct
,用于表示针对参数列表评估 Command
的结果。
helloCommand.options // ['-v', '-w']
helloEvaluation.options // ['-v']
helloEvaluation.parameters // ['Mr.Rogers']
请注意,评估仅包括参数列表中看到的选项。
回调将 CommandEvaluation
作为输入传递给在评估之前在 Command
中设置的函数。
try helloEvaluation.performCallbacks()
帮助菜单是自动生成的,并且该选项已添加到命令选项集中。
$ hello --help
OVERVIEW: Say Hello
USAGE: hello [option] <command>
COMMANDS:
OPTIONS:
-h, --help The help menu
-v Increase verbosity
-w Wave hello
选项可以有一个短标志(例如 -v
)或一个长标志(例如 --verbose
)。 选项允许有一个可选的参数。 标志和参数必须用 =
连接,例如 --path=/tmp
。
// will match -v
Option(flag: .short("v"), overview: "verbose")
// will match -v | --verbose
Option(flag: .both(short: "v", long: "verbose"), overview: "verbose")
// will match --path=/etc
Option(flag: .long("path"), overview: "File path", parameterName: "/etc")
许多命令行界面,如 git 或 swift package manager 允许使用子命令。 CommandCougar 也允许表达这一点。 一个需要注意的规则是,具有子命令的命令不允许也具有参数。
swift package -v update --repin
swift
是主命令。
package
是 swift
命令的子命令,带有 -v
选项。
update
是 package
命令的子命令,带有 --repin
选项。
表达此参数列表的命令如下所示
/// Used for callback
func echo(evaluation: Command.Evaluation) throws {
print(
"\(evaluation.name) evaluated with " +
"options: \(evaluation.options) " +
"and parameters \(evaluation.parameters)"
)
}
let swiftCommand =
Command(
name: "swift",
overview: "Swift Program",
callback: echo,
options: [],
subCommands: [
Command(
name: "package",
overview: "Perform operations on Swift packages",
callback: echo,
options: [
Option(
flag: .both(short: "v", long: "verbose"),
overview: "Increase verbosity of informational output"),
Option(
flag: .long("enable-prefetching"),
overview: "Increase verbosity of informational output")
],
subCommands: [
Command(
name: "update",
overview: "Update package dependencies",
callback: echo,
options: [
Option(
flag: .long("repin"),
overview: "Update without applying pins and repin the updated versions.")
],
subCommands: [])
])
])
当评估根命令时,所有子命令也将被评估,并且它们的回调将被触发。
do {
// normally CommandLine.arguments
let args = ["swift", "package", "-v", "update", "--repin"]
let evaluation: Command.Evaluation = try swiftCommand.evaluate(arguments: args)
try evaluation.performCallbacks()
} catch {
print(error)
}
// Output
// swift evaluated with options: [] and parameters []
// package evaluated with options: [-v] and parameters []
// update evaluated with options: [--repin] and parameters []
直接访问返回的 CommandEvaluation
的值
evaluation["package"]?.name // results in "package"
evaluation["package"]?.options["v"] // results in Option.Evaluation
evaluation["package"]?.options["v"]?.flag.shortName // results in "v"
evaluation["package"]?.options["enable-prefetching"] // results in nil
evaluation["package"]?["update"]?.options["repin"]?.flag.longName // results in "repin"
要通过索引访问参数,您可以使用 parameter(at: Int) throws -> String
。 如果该参数不存在,将抛出 parameterAccessError
。
这将变成
func callback(evaluation: CommandEvaluation) throws {
guard let first = evaluation.parameters.first else {
throw CommandCougar.Errors.parameterAccessError("Parameter not found.")
}
}
变成
func callback(evaluation: CommandEvaluation) throws {
let first = try evaluation.parameter(at: 0)
}
也会为子命令生成帮助
$ swift package --help
OVERVIEW: Perform operations on Swift packages
USAGE: swift package [option] <command>
COMMANDS:
update Update package dependencies
OPTIONS:
-v, --verbose Increase verbosity of informational output
--enable-prefetching Enable prefetching in resolver
-h, --help The help menu
CommandCougar 支持的语言的 EBNF 如下所示
<command> ::= <word> {<option>} ([<command>] | {<parameter>})
<option> ::= <single> | <double>
<single> ::= -<letter>=[<parameter>]
<double> ::= --<word>=[<parameter>]
<parameter> ::= <word>
<word> ::= <letter>+
<letter> ::= a | b | c | d | e...
代码行数分解,以显示项目的总体大小
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Swift 11 133 411 451
-------------------------------------------------------------------------------
SUM: 11 133 411 451
-------------------------------------------------------------------------------
CommandCougar 是在 MIT 许可证下发布的。 有关详细信息,请参见 LICENSE。