Cargo Commander:增强 Rust 项目的命令行工具
简介
Cargo Commander 旨在填补 cargo
命令功能的空白,即不能像 npm
运行脚本那样运行命令。但在此过程中,我决定为其添加一些额外的功能。
新增功能:除了在 Commands.toml
、Cargo.toml
或 package.json
中指定的命令外,还在开发类似于 cargo-script
的脚本执行功能。您可以通过运行本地脚本 cargo cmd script.rs
或远程脚本 cargo cmd https://url.to.script
来尝试。目前这处于早期测试阶段,其工作原理是运行 rustc input -o output
,然后执行输出结果,因此目前仅限于使用标准库,且脚本必须包含在单一文件中。更多功能即将推出!
开始使用
您可以在 Cargo.toml
中的 [commands]
或 [package.metadata.commands]
部分创建命令,或者创建一个新的 Commands.toml
文件。它们都使用相同的语法。如果发现 package.json
中的 scripts
部分,Cargo Commander 也会解析它。通常 package.json
中的脚本只允许是字符串,但 Cargo Commander 通过将 json 转换为 toml,意味着您可以在 json 中添加与 toml 中相同的选项。
# 安装 cargo-commander
cargo install cargo-commander
# 运行您的命令
cargo cmd COMMAND
# 'cargo cmd --help' 的输出
cargo-commander 2.0.15
一个强大的工具,用于管理项目命令
用法:
cargo cmd [选项] [命令/URL/文件] [<参数>...]
参数:
COMMAND 要运行的命令名称
URL 下载脚本,编译然后运行
FILE 编译文件然后运行
<参数>... 传递给命令的参数
选项:
-h, --help 打印帮助信息
-f, --file PATH 自定义命令文件的路径
-p, --parallel 强制所有命令并行运行
命令
命令可以是字符串或使用以下字段自定义其行为的命令对象。
cmd = 字符串或数组,数组可以包含字符串命令或其他命令对象
parallel = true/false,仅在命令对象包含数组时有意义,使所有命令并行运行
shell = 字符串,语法仅为 "程序 参数 参数 参数"
env = 数组,格式为 "VAR=SOMETHING" 的字符串数组
args = 数组,格式为 "ARG=默认值" 的字符串数组,如果没有给定默认值,则使用空字符串
working_dir = 字符串,相对于命令文件或当前目录的工作目录路径
cmd
这可以是字符串、命令对象或命令对象数组。
如果 cmd
是多行字符串,则命令的内容将保存到一个临时文件中,程序完成后该文件将被安全删除。然后使用参数替换字符串中的内容,传递给 shell 的唯一参数是临时文件的路径。我们可以将这种行为与 shell
选项结合使用,创建一个文件,其绝对路径作为参数传递给您指定的 shell 程序。请参阅示例了解这可能的外观。
command = "echo Basic usage"
command = ["echo As an array"]
command = { cmd = "echo Hello" }
command = { cmd = ["echo Hello", "echo World"] }
command = { cmd = [{ cmd = "echo And hello again" }] }
command = { cmd = { cmd = "echo Hello again" } }
parallel
布尔值,默认为 false。如果命令对象的 cmd
是数组,所有子命令将同时运行。
command = { cmd = ["echo first", "echo second", "echo third"], parallel = true }
working_dir
字符串。命令应该在其中执行的路径。
command = { cmd = "ls", working_dir = "src" }
command = { cmd = "ls", working_dir = "path/to/folder" }
args
格式为 args=["参数","参数=默认值"]
的字符串数组。如果参数是一个没有设置默认值的字符串,它将被替换为空字符串。
command = { cmd = "echo $name", args = ["name=World"] }
env
格式为 env=["变量=值"]
的字符串数组。在命令中设置环境变量。这与 args
的工作方式类似,但不同之处在于 env
更改环境变量。这个选项通常不是很有用,您可能更想使用 load_dotenv
。
# Unix
command = { cmd = "echo $HELLO", env = ["HELLO=World"] }
# Windows
command = { cmd = "echo %HELLO%", env = ["HELLO=World"] }
load_dotenv
布尔值,默认为 false。允许您从 .env 文件中加载环境变量。.env 文件应该位于包含正在运行命令的文件的同一文件夹中。此选项不受 working_dir
选项的影响。
# 创建一个包含 "HELLO=World" 的 .env 文件
# Unix
command = { cmd = "echo $HELLO", load_dotenv = true }
# Windows
command = { cmd = "echo %HELLO%", load_dotenv = true }
until
整数。哪个状态码被视为成功运行。通常我们不检查命令的状态码,但使用此选项我们可以告诉命令继续重复,直到达到特定的退出码。如果将其设置为 until=0
,则意味着您将继续运行命令,直到达到状态 0 的退出码。使用 until=404
将继续运行,直到达到 404 码。如果您想避免无限循环,您也应该设置 max_repeat
。
command = { cmd = "echo Hello", until = 0 }
repeat
整数。命令至少应该运行的次数。如果您与 until
一起运行此命令,您将始终至少运行这么多次。
command = { cmd = "echo Hello", repeat = 2 }
delay
整数或浮点数。在运行命令之前的睡眠时间。如果您将此与任何基于重复的选项一起使用,此延迟将在每次命令运行之前添加。
command = { cmd = "echo Hello", delay = 2 }
command = { cmd = "echo Hello", delay = 3.7 }
max_repeat
整数。设置命令允许重试的最大次数。这在与 until
一起运行时最有用。
command = { cmd = "echo Hello", repeat = 5, max_repeat = 1 }
command = { cmd = "echo Hello", until = 0, max_repeat = 1000 }
示例
打开文档
我倾向于为我的项目创建多个 mdbook
书籍进行文档化。这非常整洁,但逐个打开它们可能会有点麻烦。因此,我将打开每个文档的命令放在 docs
部分下,然后运行该部分而不是每个单独的页面,使用 -p
标志使该部分并行运行。
# Commands.toml
[docs]
crate_one = { cmd = "mdbook serve --open --port 9001", working_dir = "crates/one/docs" }
crate_two = { cmd = "mdbook serve --open --port 9002", working_dir = "crates/two/docs" }
crate_three = { cmd = "mdbook serve --open --port 9003", working_dir = "crates/three/docs" }
crate_four = { cmd = "mdbook serve --open --port 9004", working_dir = "crates/four/docs" }
现在我们可以使用单个命令打开所有文档!
cargo cmd -p docs
传递自定义参数
假设您想在 Kubernetes pod 中启动一个运行中的 shell,但事先不知道 pod 名称,可能是因为 pod 是由部署或定时任务创建的。您知道一个 kubectl
命令可以让您在 pod 中获得运行中的 shell,但问题是命令非常长而且每次写都很麻烦,每次从其他地方复制命令也很快变得重复。
# Commands.toml
shell = { cmd = "kubectl exec --stdin --tty $pod -- /bin/bash", args = ["pod"] }
现在我们可以通过简单的语法始终获得我们 pod 的 shell。现在,您不必每次都找到您的 pod 名称并将其复制到更长的 kubectl
命令中,您现在可以轻松记住您有一个 shell
命令,它接受 pod
参数。
cargo cmd shell pod=my-pod-123-654
运行脚本
通过结合 shell
选项和我们为多行字符串设置的行为,我们可以实现直接在命令中编写脚本的运行。
# 使用 python -c
hello_py_c = { cmd = "print('Hello')", shell = "python -c" }
# 使用 python 和多行字符串以及参数
hello_py = { cmd = """import os
print("Hello")
print("$name")
""", args = ["name=World"], shell = "python" }
然后您可以按以下方式运行它:
cargo cmd hello_py_c
Hello
# 或多行
cargo cmd hello_py
Hello
World
# ... 带参数
cargo cmd hello_py name=Commander
Hello
Commander
持续重试直到命令成功
有时您运行的程序或编写的脚本可能会失败。没关系,每个人都会遇到。也许它正在尝试到达的网络资源,或者您计算机上的文件。不管出于什么原因,程序有时以成功代码 0
退出,其他时候以代码 404
退出,因为尝试到达的页面未找到。
我们可以使用 until
轻松创建一个简单的重试循环,结合 delay
以便程序不会运行得过于频繁,以及 max_repeat
以便我们不会永远尝试。
command = { cmd = "python script.py", until = 0, delay = 3, max_repeat = 1000 }
运行该命令将使其持续重试,每次重试之间有 3 秒的延迟。它将重试,直到返回 0 状态,或最多 1000 次。
注意事项
环境变量不持久
我尝试过让这按预期工作,但目前我有点放弃了,因为这看起来在实现上要么是不可能的,要么真的非常非常烦人。所以每个命令都将有一套“新鲜”的环境变量,如果一个命令更改了环境变量,另一个命令不会捕获这些更改,它们在不同的 shell 中运行。您可以使用 env
选项,或者您可以在每个命令中运行一个脚本来设置环境变量,或者您可以使用 load_dotenv
从 .env
文件中加载变量。我认为这些选项是足够的,如果您真的希望变量在命令之间持久存在,您将不得不提交一个拉取请求,或者等待我深入研究这个问题。