263 个版本

0.37.15 2024 年 7 月 29 日
0.37.12 2024 年 5 月 4 日
0.37.10 2024 年 2 月 23 日
0.37.5 2023 年 12 月 15 日
0.3.39 2017 年 7 月 28 日

#3Cargo 插件

Download history 9965/week @ 2024-05-03 10001/week @ 2024-05-10 10218/week @ 2024-05-17 8783/week @ 2024-05-24 10087/week @ 2024-05-31 10506/week @ 2024-06-07 7213/week @ 2024-06-14 7718/week @ 2024-06-21 8432/week @ 2024-06-28 10896/week @ 2024-07-05 10766/week @ 2024-07-12 10027/week @ 2024-07-19 10799/week @ 2024-07-26 10959/week @ 2024-08-02 9652/week @ 2024-08-09 13245/week @ 2024-08-16

46,014 次每月下载
11 个 crate(10 个直接) 中使用

Apache-2.0

2MB
34K SLoC

包含(WOFF 字体,400KB) NanumBarunGothic-00000000f861df9d.ttf.woff2,(WOFF 字体,135KB) FiraSans-Medium-0000000066e2bc86.woff2,(WOFF 字体,130KB) FiraSans-Regular-0000000084b1ad12.woff2,(WOFF 字体,82KB) SourceSerif4-Bold-00000000ad926a49.ttf.woff2,(WOFF 字体,77KB) SourceSerif4-Regular-0000000007da4a04.ttf.woff2,(WOFF 字体,45KB) SourceCodePro-It-00000000668aca82.ttf.woff2 以及 3 个其他字体 等。

cargo-make

crates.io CI codecov license Crates.io GitHub All Releases Built with cargo-make

Rust 任务运行器和构建工具。

概览

cargo-make 任务运行器允许定义和配置任务集,并将它们作为一个流程运行。
任务是一个命令、脚本、Rust 代码或其他子任务以执行。
任务可以有依赖项,这些依赖项也是将在任务本身之前执行的子任务。
使用简单的基于 toml 的配置文件,您可以定义一个多平台构建脚本,可以运行构建、测试、生成文档、运行基准测试、运行安全验证等,通过运行单个命令即可执行。

安装

为了安装,只需运行以下命令

cargo install --force cargo-make

这将 cargo-make 安装到您的 ~/.cargo/bin
请确保将 ~/.cargo/bin 目录添加到您的 PATH 变量中。

您将有两个可执行文件可用: cargo-makemakers

  • cargo-make - 这是通过使用 cargo make ... 调用的 cargo 插件
  • makers - 一个独立的可执行文件,它提供了与 cargo-make 相同的功能和 CLI 参数,但直接调用,而不是作为 cargo 插件。

有关完整 CLI 指令,请参阅 CLI 选项 部分。

为了以最小功能安装(例如,无 TLS 支持),请运行以下命令

cargo install --no-default-features --force cargo-make

Arch Linux

sudo pacman -S cargo-make

二进制发布

二进制发布可在 github 发布页面 上找到。
以下二进制文件在每个版本中都可用

  • x86_64-unknown-linux-gnu
  • x86_64-unknown-linux-musl
  • x86_64-apple-darwin
  • x86_64-pc-windows-msvc
  • aarch64-apple-darwin

使用

使用 cargo-make 时,所有任务都通过 toml 文件定义和配置。
以下是一些快速入门的简单说明。

简单示例

为了运行一组任务,您首先必须在 toml 文件中定义它们。
例如,如果我们想有一个脚本

  • 格式化代码
  • 清理旧的目标目录
  • 运行构建
  • 运行测试

默认情况下,如果存在,cargo-make 从 Makefile.toml 读取任务。

我们将创建一个 Makefile.toml 文件,如下所示

[tasks.format]
install_crate = "rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]

[tasks.clean]
command = "cargo"
args = ["clean"]

[tasks.build]
command = "cargo"
args = ["build"]
dependencies = ["clean"]

[tasks.test]
command = "cargo"
args = ["test"]
dependencies = ["clean"]

[tasks.my-flow]
dependencies = [
    "format",
    "build",
    "test"
]

我们将使用以下命令执行流程

cargo make my-flow

输出将类似于以下内容

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: my-flow
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: format
[cargo-make] INFO - Execute Command: "cargo" "fmt" "--" "--emit=files"
[cargo-make] INFO - Running Task: clean
[cargo-make] INFO - Execute Command: "cargo" "clean"
[cargo-make] INFO - Running Task: build
[cargo-make] INFO - Execute Command: "cargo" "build"
   Compiling bitflags v0.9.1
   Compiling unicode-width v0.1.4
   Compiling quote v0.3.15
   Compiling unicode-segmentation v1.1.0
   Compiling strsim v0.6.0
   Compiling libc v0.2.24
   Compiling serde v1.0.8
   Compiling vec_map v0.8.0
   Compiling ansi_term v0.9.0
   Compiling unicode-xid v0.0.4
   Compiling synom v0.11.3
   Compiling rand v0.3.15
   Compiling term_size v0.3.0
   Compiling atty v0.2.2
   Compiling syn v0.11.11
   Compiling textwrap v0.6.0
   Compiling clap v2.25.0
   Compiling serde_derive_internals v0.15.1
   Compiling toml v0.4.2
   Compiling serde_derive v1.0.8
   Compiling cargo-make v0.1.2 (file:///home/ubuntu/workspace)
    Finished dev [unoptimized + debuginfo] target(s) in 79.75 secs
[cargo-make] INFO - Running Task: test
[cargo-make] INFO - Execute Command: "cargo" "test"
   Compiling cargo-make v0.1.2 (file:///home/ubuntu/workspace)
    Finished dev [unoptimized + debuginfo] target(s) in 5.1 secs
     Running target/debug/deps/cargo_make-d5f8d30d73043ede

running 10 tests
test log::tests::create_info ... ok
test log::tests::get_level_error ... ok
test log::tests::create_verbose ... ok
test log::tests::get_level_info ... ok
test log::tests::get_level_other ... ok
test log::tests::get_level_verbose ... ok
test installer::tests::is_crate_installed_false ... ok
test installer::tests::is_crate_installed_true ... ok
test command::tests::validate_exit_code_error ... ok
test log::tests::create_error ... ok

test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

[cargo-make] INFO - Running Task: my-flow
[cargo-make] INFO - Build done in 72 seconds.

我们现在创建了一个可以在任何平台上运行的构建脚本。

任务可以存储在任何 toml 文件中。使用 --makefile other-filename.toml 调用 cargo-make 以使用 other-filename.toml 开始处理。

可以通过cargo make命令以cargo插件的形式调用cargo-make,或者通过makers命令作为一个独立的可执行文件。

重要提示:如果您在这个cargo工作区中运行此示例,您需要将以下内容添加到文件顶部

[env]
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true

有关工作区支持的更多内容,请参阅本文档的相关部分。

任务、依赖和别名

在许多情况下,某些任务依赖于其他任务。
例如,您希望在运行构建之前格式化代码,在运行测试之前运行构建。
这样的流程可以定义如下

[tasks.format]
install_crate = "rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]

[tasks.build]
command = "cargo"
args = ["build"]
dependencies = ["format"]

[tasks.test]
command = "cargo"
args = ["test"]
dependencies = ["build"]

当您运行

cargo make --makefile ./my_build.toml test

它将尝试运行测试,看到它有依赖项,这些依赖项又有其他依赖项。
因此,它将根据任务及其依赖项创建一个任务执行计划。
在我们的例子中,它将调用format -> build -> test。

相同的任务永远不会被执行两次。所以,如果我们有,例如

[tasks.A]
dependencies = ["B", "C"]

[tasks.B]
dependencies = ["D"]

[tasks.C]
dependencies = ["D"]

[tasks.D]
script = "echo hello"

在这个例子中,A依赖于B和C,B和C都依赖于D。
然而,任务D不会调用两次。
执行输出将类似于以下内容

[cargo-make] INFO - Task: A
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: D
[cargo-make] INFO - Execute Command: "sh" "/tmp/cargo-make/CNuU47tIix.sh"
hello
[cargo-make] INFO - Running Task: B
[cargo-make] INFO - Running Task: C
[cargo-make] INFO - Running Task: A

如您所见,'hello'由任务D打印了一次,因为它只被调用了一次。
但如果我们想运行D两次呢?
简单的答案是将任务D复制,让B依赖于D,让C依赖于D2,D2是D的一个副本。
但复制可能会导致错误和非常大的makefile,所以我们为此提供了别名。
别名任务有自己的名称,并指向另一个任务。
别名任务的全部定义都被忽略。
因此,现在,如果我们想让D执行两次,我们可以这样做

[tasks.A]
dependencies = ["B", "C"]

[tasks.B]
dependencies = ["D"]

[tasks.C]
dependencies = ["D2"]

[tasks.D]
script = "echo hello"

[tasks.D2]
alias="D"

现在C依赖于D2,而D2是D的别名。
这种make文件的执行输出如下

[cargo-make] INFO - Task: A
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: D
[cargo-make] INFO - Execute Command: "sh" "/tmp/cargo-make/HP0UD7pgoX.sh"
hello
[cargo-make] INFO - Running Task: B
[cargo-make] INFO - Running Task: D2
[cargo-make] INFO - Execute Command: "sh" "/tmp/cargo-make/TuuZJkqCE2.sh"
hello
[cargo-make] INFO - Running Task: C
[cargo-make] INFO - Running Task: A

现在您可以看到'hello'被打印了两次。

任务也可能依赖于其他文件中的任务。为此,指定依赖项的对象格式,提供路径。cargo-make将使用此路径,就像使用任何其他命令行提供的路径一样:如果提供了文件名,它将搜索该文件。否则,它将搜索该路径上的默认Makefile.toml

[tasks.install]
command = "mv"
args = ["src/B/out", "src/C/static"]
dependencies = [
  { name = "compile", path = "src/B" },
  { name = "clean", path = "src/C/tasks.toml" },
]

run_task属性会指示任务在新执行计划中调用另一个任务。这将导致依赖项被多次调用。

也可以定义特定于平台的别名,例如

[tasks.my_task]
linux_alias = "linux_my_task"
windows_alias = "windows_my_task"
mac_alias = "mac_my_task"

[tasks.linux_my_task]

[tasks.mac_my_task]

[tasks.windows_my_task]

如果找到特定于平台的别名并与当前平台匹配,则它将优先于非平台别名定义。
例如

[tasks.my_task]
linux_alias = "run"
alias = "do_nothing"

[tasks.run]
script = "echo hello"

[tasks.do_nothing]

如果您在Windows或mac上运行任务my_task,它将调用任务do_nothing
然而,如果是在linux平台上执行,它将调用任务run

作为旁注,cargo-make将尝试按照定义的顺序调用任务依赖项,除非它们也被定义为子依赖项。

命令、脚本和子任务

任务实际调用的操作可以通过三种方式定义。
以下将解释每一种

  • run_task - 调用此属性中定义的名称的任务。与在当前任务之前调用的依赖项不同,run_task中定义的任务在当前任务之后调用。
  • command - 命令属性定义要调用的可执行文件。您可以使用args属性来定义作为命令一部分提供的命令行参数。
  • script - 调用脚本。您可以使用script_runner属性更改用于调用脚本的可执行文件。如果没有定义,则使用默认的平台运行器(Windows上为cmd,其他平台为sh)。

只使用其中一个定义。
如果定义了多个属性(例如命令和脚本),则任务在调用时将失败。

脚本属性可以包含非操作系统脚本,例如需要编译和执行 rust 代码。
要使用非操作系统脚本运行器,您必须使用带 @ 前缀的 script_runner 特殊属性。
以下是目前支持的运行器

  • @duckscript - 执行定义的 duckscript 代码。参见 示例
  • @rust - 编译并执行定义的 rust 代码。参见 示例
  • @shell - 对于 Windows 平台,它将尝试将 shell 命令转换为 Windows 批处理命令(仅支持基本脚本)并执行脚本;对于其他平台,脚本将按原样执行。参见 示例

以下是每种操作类型的基本示例。

子任务

在此示例中,如果我们执行 flow 任务,它将调用在 run_task 属性中定义的 echo 任务。

[tasks.echo]
script = "echo hello world"

[tasks.flow]
run_task = "echo"

下面的更复杂示例演示了定义多个任务名称及其附加条件的能力。
对于满足条件(或者如果没有定义任何条件)的第一个任务,将执行。
如果没有任务条件满足,则不会调用任何子任务。
有关条件的更多信息,请参阅 条件部分

[tasks.test1]
command = "echo"
args = ["running test1"]

[tasks.test2]
command = "echo"
args = ["running test2"]

[tasks.test3]
command = "echo"
args = ["running test3"]

[tasks.test-default]
command = "echo"
args = ["running test-default"]

[tasks.test-routing]
run_task = [
    { name = "test1", condition = { platforms = ["windows", "linux"], channels = ["beta", "stable"] } },
    { name = "test2", condition = { platforms = ["mac"], rust_version = { min = "1.20.0", max = "1.30.0" } } },
    { name = "test3", condition_script = [ "somecommand" ] },
    { name = "test-default" }
]

您还可以使用 fork 属性将子任务作为分叉子进程运行。
这可以防止子任务中进行的任何环境更改影响父进程中的其余流程。
以下是一个在分叉子进程中调用子任务的示例

[tasks.echo]
command = "echo"
args = ["hello world"]

[tasks.fork-example]
run_task = { name = "echo", fork = true }

name 属性可以包含单个任务名称或任务列表。
如果是一个列表,则任务将按顺序依次执行。
例如,以下 simple-multirouting-multi 都展示了通过 run_task 定义多任务调用的不同方法

[tasks.echo1]
command = "echo"
args = ["1"]

[tasks.echo2]
command = "echo"
args = ["2"]

[tasks.simple-multi]
run_task = { name = ["echo1", "echo2"] }

[tasks.routing-multi]
run_task = [
    { name = ["echo1", "echo2"] },
]

您还可以设置一个 cleanup 任务,以便在子任务之后运行,即使子任务失败也是如此。
这仅与 fork=true 属性组合使用。
例如

[tasks.echo1]
command = "echo"
args = ["1"]

[tasks.echo2]
command = "echo"
args = ["2"]

[tasks.fail]
script =  "exit 1"

[tasks.cleanup]
command = "echo"
args = ["cleanup"]

[tasks.cleanup-example]
run_task = { name = ["echo1", "echo2", "fail"], fork = true, cleanup_task = "cleanup" }

要并行运行多个任务,请向 run_task 对象添加 parallel = true
例如

[tasks.echo1]
command = "echo"
args = ["1"]

[tasks.echo2]
command = "echo"
args = ["2"]

[tasks.parallel-multi]
run_task = { name = ["echo1", "echo2"], parallel = true }

这允许并行运行独立任务并提高流程的整体性能。
请注意,如果使用以下功能,并行调用任务可能会导致问题

  • 通过 cwd 属性设置任务的当前工作目录将导致所有并行任务受到影响。
  • 请避免使用 CARGO_MAKE_CURRENT_TASK_ 类型环境变量,因为这些可能包含不正确的值。

此外,在某些情况下,子进程可能被留下作为僵尸进程。
您可能需要设置一个手动清理任务来解决这个问题。

命令

在运行命令时,您还可以定义命令行参数,如下面的示例所示,用插件名称作为命令行参数调用 cargo 命令

[tasks.build-with-verbose]
command = "cargo"
args = ["build", "--verbose", "--all-features"]

您还可以提供环境变量作为命令和参数的一部分,在运行时用实际值替换,例如

[env]
SIMPLE = "SIMPLE VALUE"
ECHO_CMD = "echo"

[tasks.expand]
command = "${ECHO_CMD}"
args = [
    "VALUE: ${SIMPLE}"
]

cargo-make CLI 还支持其他参数,这些参数将可用于所有任务。
以下示例打印了附加参数

[tasks.varargs]
command = "echo"
args = [
    "args are:", "${@}"
]

对于本地脚本,使用该本地脚本语法。
对于 shell,可以使用 ${0},对于 Windows:%*

使用附加参数调用 cargo-make 将产生以下结果

> cargo make varargs arg1 arg2 arg3

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: varargs
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: varargs
[cargo-make] INFO - Execute Command: "echo" "args are:" "arg1" "arg2" "arg3"
args are: arg1 arg2 arg3
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

不添加任何额外参数调用 cargo-make 会产生以下结果

> cargo make varargs

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: varargs
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: varargs
[cargo-make] INFO - Execute Command: "echo" "args are:"
args are:
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

这也可以用于模板化,例如

[tasks.varargs]
command = "echo"
args = [
    "args are:", "-o=${@}"
]

将会输出

> cargo make varargs arg1 arg2 arg3

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: varargs
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: varargs
[cargo-make] INFO - Execute Command: "echo" "args are:" "arg1" "arg2" "arg3"
args are: -o=arg1 -o=arg2 -o=arg3
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

命令行参数也可以包含 内置函数(见下文)。

脚本

以下是一个简单的脚本,用于打印“Hello World”。

[tasks.hello-world]
script = [
    "echo start...",
    "echo \"Hello World From Script\"",
    "echo end..."
]

您可以使用多行 toml 字符串来使脚本更易于阅读,如下所示

[tasks.hello-world]
script = '''
echo start...
echo "Hello World From Script"
echo end...
'''

cargo-make CLI 还支持其他参数,这些参数将可用于所有任务。
以下示例打印了附加参数

[tasks.cli-args]
script = "echo args are: ${@}"

使用附加参数调用 cargo-make 将产生以下结果

> cargo make cli-args arg1 arg2 arg3

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: cli-args
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: cli-args
+ cd /projects/rust/cargo-make/examples
+ echo args are: arg1 arg2 arg3
args are: arg1 arg2 arg3
[cargo-make] INFO - Running Task: end

不添加任何额外参数调用 cargo-make 会产生以下结果

> cargo make cli-args

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: Makefile.toml
[cargo-make] INFO - Task: cli-args
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: cli-args
+ cd /projects/rust/cargo-make/examples
+ echo args are:
args are:
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

也可以通过使用 file 属性指向现有的脚本(而不是在 makefile 中包含脚本文本)

[tasks.hello-world-from-script-file]
script = { file = "script.sh" }

脚本文件路径始终相对于当前工作目录,除非通过 absolute_path 属性指定。例如

[tasks.hello-world-from-script-file-absolute-path]
script = { file = "${CARGO_MAKE_WORKING_DIRECTORY}/script.sh", absolute_path = true }

文件路径支持环境变量替换。

优先使用命令而不是脚本,因为命令支持更多功能,如 自动依赖安装参数函数等...

为了在多个任务之间共享常见的脚本内容,您可以使用脚本 pre/main/post 形式,如下所示

[tasks.base-script]
script.pre = "echo start"
script.main = "echo old"
script.post = "echo end"

[tasks.extended-script]
extend = "base-script"
script.main = "echo new"

运行扩展脚本任务会打印

start
new
end

Duckscript

Duckscript 是一种非常简单的类似 shell 的语言,它提供了跨平台的 shell 脚本功能。
Duckscript 内置于 cargo-make,因此与其他脚本解决方案或命令不同,Duckscript 可以在脚本内部更改 cargo-make 环境变量。
此外,您还可以在 duckscript 脚本中运行 cargo-make 任务。
这允许与 cargo-make 实现真正强大的双向集成。

[tasks.duckscript-example]
script_runner = "@duckscript"
script = '''
task_name = get_env CARGO_MAKE_CURRENT_TASK_NAME
echo The currently running cargo make task is: ${task_name}

# since all env vars are auto loaded as duckscript variables by cargo-make
# you can access them directly
echo The currently running cargo make task is: ${CARGO_MAKE_CURRENT_TASK_NAME}

cd .. # this changes cargo-make current working directory (cargo-make will revert to original directory after script execution)
pwd
set_env CARGO_MAKE_CURRENT_TASK_NAME tricking_cargo_make
'''

以下示例展示了如何在 duckscript 中调用 cargo-make 任务

[tasks.run-task-from-duckscript]
script_runner = "@duckscript"
script = '''
echo first invocation of echo1 task:
cm_run_task echo1
echo second invocation of echo1 task:
cm_run_task echo1

echo running task: echo2:
cm_run_task echo2
'''

[tasks.echo1]
command = "echo"
args = ["1"]

[tasks.echo2]
command = "echo"
args = ["2"]

与 OS 脚本相同,@duckscript 运行器也支持 cargo-make CLI 参数访问。
此外,所有环境变量都作为 duckscript 变量预先加载,可以直接从脚本中读取。(不需要调用 get_env 命令!)

Rust 代码

在这个示例中,当调用 rust 任务时,script 内容将被编译并执行。您可以在代码中看到如何以 Cargo.toml 格式定义依赖关系。

[tasks.rust]
script_runner = "@rust"
script = '''
//! ```cargo
//! [dependencies]
//! envmnt = "*"
//! ```
fn main() {
    let value = envmnt::get_or("PATH", "NO PATH VAR DEFINED");
    println!("Path Value: {}", &value);
}
'''

与 OS 脚本相同,@rust 运行器也支持 cargo-make CLI 参数访问。
目前有几种不同的 rust 脚本运行器可用

默认情况下使用 rust-script,但可以通过环境变量 CARGO_MAKE_RUST_SCRIPT_PROVIDER 更改它,该变量应包含包名。
这可以通过在特定任务的 env 块中设置来为每个任务定义不同的运行器。
例如

[tasks.rust-script]
env = { "CARGO_MAKE_RUST_SCRIPT_PROVIDER" = "rust-script" }
script_runner = "@rust"
script = '''
fn main() {
    println!("test");
}
'''

[tasks.cargo-script]
env = { "CARGO_MAKE_RUST_SCRIPT_PROVIDER" = "cargo-script" }
script_runner = "@rust"
script = '''
fn main() {
    println!("test");
}
'''

[tasks.cargo-play]
env = { "CARGO_MAKE_RUST_SCRIPT_PROVIDER" = "cargo-play" }
script_runner = "@rust"
script = '''
fn main() {
    println!("test");
}
'''

请注意,不同运行器使用的 rust 脚本依赖关系定义不同。
请参阅特定包的文档以获取更多信息。

跨平台 Shell

在这个示例中,当调用 shell 任务时,script 内容将自动转换为 Windows 批处理命令(在 Windows 平台上运行时)并执行。

[tasks.shell]
script_runner = "@shell"
script = '''
rm ./myfile.txt
'''

与 OS 脚本相同,@shell 运行器也支持 cargo-make CLI 参数访问。

有关完整功能集,请参阅 shell2batch 项目。

其他编程语言

cargo-make 还可以运行用各种脚本语言编写的脚本,例如 Python、Perl、Ruby、JavaScript 等...
任何形式为 command file(例如 python ./program.py)的运行器都受支持。

以下是一些示例

[tasks.python]
script_runner = "python"
script_extension = "py"
script = '''
print("Hello, World!")
'''

[tasks.perl]
script_runner = "perl"
script_extension = "pl"
script = '''
print "Hello, World!\n";
'''

[tasks.javascript]
script_runner = "node"
script_extension = "js"
script = '''
console.log('Hello, World!');
'''

[tasks.php]
script_runner = "php"
script_extension = "php"
script = '''
<?php
echo "Hello, World!\n";
'''

[tasks.powershell]
script_runner = "powershell"
script_extension = "ps1"
script = '''
Write-Host "Hello, World!"
'''

如果您需要在脚本文件之前提供脚本运行器参数,可以使用 script_runner_args 属性。
例如

[tasks.php-with-args]
script_runner = "php"
script_runner_args = ["-f"]
script_extension = "php"
script = '''
<?php
echo "Hello, World!\n";
'''

script_runner_args 需要定义 script_extension。

Shebang 支持

除了通过 script_runner 属性定义自定义运行器之外,还可以在脚本 shebang 行中定义它。

在Windows系统中,请确保不要使用没有将 # 字符定义为注释的运行器(例如,cmd.exe 不可以!),这会导致错误。

使用bash的示例任务

[tasks.shebang-sh]
script = '''
#!/usr/bin/env bash
echo hello
'''

输出

> cargo make --cwd ./examples --makefile ./shebang.toml shebang-sh
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: ./shebang.toml
[cargo-make] INFO - Task: shebang-sh
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: shebang-sh
[cargo-make] INFO - Execute Command: "/usr/bin/env" "bash" "/tmp/cargo-make/cJf6XEXrL9.sh"
hello
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

使用Python的示例任务

[tasks.shebang-python]
script = '''
#!/usr/bin/env python3
print("Hello, World!")
'''

输出

> cargo make --cwd ./examples --makefile ./shebang.toml shebang-python
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: ./shebang.toml
[cargo-make] INFO - Task: shebang-python
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: shebang-python
[cargo-make] INFO - Execute Command: "/usr/bin/env" "python3" "/tmp/cargo-make/Wy3QMJiQaS.sh"
Hello, World!
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

你可以使用shebang的另一个技巧,如下定义特殊运行器之一,例如@duckscript:

[tasks.duckscript-shebang-example]
script = '''
#!@duckscript
echo Running duckscript without runner attribute.
'''

然而,该语言必须支持以 # 字符开始的注释。

默认任务和扩展

实际上没有必要定义前面示例中显示的一些基本 构建测试 等任务。
cargo-make附带一个内置的toml文件,它将作为每次执行的基文件。
在运行cargo-make时提供的 可选 外部toml文件将仅扩展和添加或覆盖在 默认makefile 中定义的任务。

让我们以默认toml中定义的内置 构建 任务为例

[tasks.build]
description = "Runs the rust compiler."
category = "Build"
command = "cargo"
args = ["build", "--all-features"]

例如,如果您想向其中添加详细输出并移除 --all-features 标志,您只需更改参数并添加 --verbose 如下所示

[tasks.build]
args = ["build", "--verbose"]

如果您想禁用某些现有任务(也将禁用其依赖项),您可以这样做:

[tasks.build]
disabled = true

不需要重新定义现有任务的属性,只需要添加或覆盖所需的内容。
默认toml文件已经内置了许多步骤和流程,所以首先检查它是值得的。

如果您确实想删除您扩展任务中的所有原始任务属性,您可以使用 clear 属性如下所示

[tasks.sometask]
clear = true
command = "echo"
args = [
    "extended task"
]

您还可以通过使用 extend 属性从您的外部makefile扩展其他外部文件,例如

extend = "my_common_makefile.toml"

extend 属性中的文件路径始终相对于您正在使用的当前toml文件,而不是工作目录。

当您有一个包含所有常见自定义任务的 Makefile.toml 的工作空间时,extend属性非常有用,并且在每个项目中都可以有一个简单的 Makefile.toml,它仅包含指向工作空间makefile的extend属性。

扩展外部 Makefile

为了使makefile能够使用extend属性从外部文件扩展额外的外部文件,例如

extend = "my_common_makefile.toml"

在extend属性中的文件路径始终相对于您正在使用的当前toml文件,而不是工作目录。
在extend属性中指向的makefile必须存在,否则构建将失败。

为了定义可选的扩展makefile,您需要除了路径外还要传递可选标志,如下所示

extend = { path = "does_not_exist_makefile.toml", optional = true }

您还可以定义要扩展的makefile列表。
它们将以您定义的顺序加载。
例如

extend = [ { path = "must_have_makefile.toml" }, { path = "optional_makefile.toml", optional = true }, { path = "another_must_have_makefile.toml" } ]

自动扩展 Workspace Makefile

当运行cargo make对属于工作空间的部分进行模块时,您可以自动使成员crates的makefile(即使它不存在)扩展工作空间级别的makefile。

工作空间级别的makefile env 部分必须包含以下环境变量(您也可以通过CLI设置它)。

[env]
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true

这允许您维护整个工作空间的单个makefile,但又能访问每个成员crate中的自定义任务。
这仅适用于在工作空间根触发的工作空间构建。
直接在工作空间crates中开始的流程必须手动使用extend关键字扩展工作空间级别的makefile。

加载脚本

在更复杂的场景中,您可能希望多个不相关的项目共享一些常见的自定义任务。例如,您可能希望通知某个内部公司服务器构建状态。
而不是在每个项目中重新定义这些任务,您可以创建一个包含这些定义的单个toml文件,并让所有项目扩展该文件。
然而,这个“扩展”功能只知道在本地文件系统中查找这样的文件。因此,为了从远程服务器拉取一些常见的 toml 文件(使用 httpgit clone 等),你可以使用加载脚本。

加载脚本使用 load_script 属性在配置部分中定义,并在评估扩展属性之前调用。
这允许你首先从远程服务器拉取 toml 文件,并将其放置在扩展属性定义的位置。

以下是一个加载脚本的示例,它使用 HTTP 从远程服务器下载常见的 toml 文件

[config]
load_script = "wget -O /home/myuser/common.toml companyserver.com/common.toml"

以下是一个从某些 git 仓库拉取常见 toml 文件的示例

[config]
load_script = "git clone git@mygitserver:user/project.git /home/myuser/common"

你可以运行任何命令或命令组。因此,你可以构建一个更复杂的流程,确定如何以及从哪里获取常见的 toml 文件,并将其放置在哪里。
如果需要,你可以使用 linux_load_scriptwindows_load_scriptmac_load_script 属性按平台覆盖加载脚本。

预定义 Makefile

虽然 cargo-make 内置了许多任务,这些任务定义在 默认 makefiles 中,但它们并不总是适用于每个项目。
cargo-make-tasks 仓库包含一些额外的 makefiles,可以加载并提供内置 cargo-make 任务的替换任务。
例如,cmake.toml 为使用 cmake 的项目提供了 cmake 相关任务。

有关更多信息和使用示例,请参阅 cargo-make-tasks 仓库。

默认任务

在没有指定任务名称的情况下调用 cargo make 命令时,将调用默认任务。
默认任务实际上是一个别名,指向以下定义的另一个任务

[tasks.default]
alias = "dev-test-flow"

定义默认任务的不同方法有很多,例如

  • 在自定义 makefile 中将别名指向另一个任务
[tasks.default]
alias = "my-custom-task"
  • 清除别名并定义任务操作
[tasks.default]
clear = true # clears the alias
command = "echo"
args = ["custom!!!"]

扩展任务

有多种方式可以扩展相同或从扩展 makefile 中的任务。

任务覆盖

cargo-make 内置了许多预定义的任务和流程,可以在不重新定义项目中的情况下使用。
然而,在某些情况下,你可能想要进行一些修改以适应你的需求,而不必重写整个任务。
build 任务为例,它是在 cargo-make 内部预定义的,如下所示

[tasks.build]
description = "Runs the rust compiler."
category = "Build"
command = "cargo"
args = ["build", "--all-features"]

如果你不想使用 --all-features 模式,你只需修改任务在外的 Makefile.toml 中的参数如下

[tasks.build]
args = ["build"]

cargo-make 启动时,它将加载外部 Makefile.toml 和内部 makefile 定义,并将它们合并。
由于外部文件覆盖了内部定义,因此仅重新定义的 build 任务参数将覆盖内部定义的参数,实际结果将是

[tasks.build]
description = "Runs the rust compiler."
category = "Build"
command = "cargo"
args = ["build"]

扩展外部 makefile 部分使用扩展关键字加载的其他 makefile 中的任务覆盖过程相同。

平台覆盖

如果你想要为特定平台覆盖任务(或任务中的特定属性),你可以在特定任务的下方定义一个带有平台名称(目前是 Linux、Windows 和 macOS)的覆盖任务。
例如

[tasks.hello-world]
script = '''
echo "Hello World From Unknown"
'''

[tasks.hello-world.linux]
script = '''
echo "Hello World From Linux"
'''

如果你在 Linux 上以任务 'hello-world' 运行 cargo make,它将重定向到 hello-world.linux,而在其他平台上将执行原始的 hello-world。
在 Linux 上的输出将是

[cargo-make] INFO - Task: hello-world
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: hello-world
[cargo-make] INFO - Execute Command: "sh" "/tmp/cargo-make/kOUJfw8Vfc.sh"
Hello World From Linux
[cargo-make] INFO - Build done in 0 seconds.

在其他平台上,它会输出以下内容

[cargo-make] INFO - Task: hello-world
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: hello-world
[cargo-make] INFO - Execute Command: "sh" "/tmp/cargo-make/2gYnulOJLP.sh"
Hello World From Unknown
[cargo-make] INFO - Build done in 0 seconds.

在覆盖任务中,您可以定义任何属性来覆盖父任务的属性,而未定义的属性将使用父任务中的值,不会进行修改。
如果您需要从父任务中删除属性(例如,在父任务中定义了一个命令,但您想在覆盖任务中定义一个脚本),则必须在覆盖任务中使用以下clear属性清除父任务

[tasks.hello-world.linux]
clear = true
script = '''
echo "Hello World From Linux"
'''

这意味着,然而,您将不得不重新定义覆盖任务中所有您希望从父任务中携带的属性。
重要提示:别名在检查覆盖任务之前优先,所以如果父任务有一个别名,它将被重定向到该任务而不是覆盖。
要为每个平台使用别名重定向,请使用linux_alias、windows_alias、mac_alias属性。
此外,平台覆盖任务中不能定义别名,只能在父任务中定义。

扩展属性

到目前为止,覆盖功能允许覆盖来自不同makefile或不同平台的同名任务。
然而,extend关键字也适用于任务级别,并允许您通过名称覆盖任何任务。
让我们看以下示例

[tasks.1]
category = "1"
description = "1"
command = "echo"
args = ["1"]

[tasks.2]
extend = "1"
category = "2"
args = ["2"]

[tasks.3]
extend = "2"
args = ["3"]

当加载任务3时,它会加载任务2,而任务2会加载任务1
最终的任务3定义如下

[tasks.3]
extend = "2"
category = "2"
description = "1"
command = "echo"
args = ["3"]

运行任务3的输出会是

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: task_extend.toml
[cargo-make] INFO - Task: 3
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: 3
[cargo-make] INFO - Execute Command: "echo" "3"
3
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

环境变量

cargo-make允许以多种方式定义环境变量,这些变量可以在任务执行期间访问。

由于环境变量在cargo-make中起着重要作用,因此它提供了多种声明性方法在不同粒度级别提供它们。

声明

有多种方法可以声明环境变量,所有这些方法都适合特定的场景。

简单

最普通的方法是定义一个简单的KEY=Value对,这让人想起了像dotenvbash脚本这样的工具。值可以使用其他变量作为值,这些变量在运行时使用${variable}语法进行插值。

STRING = "value"
RUST_BACKTRACE = 1
BOOL_VALUE = true
COMPOSITE = "${BOOL_VALUE} ${RUST_BACKTRACE}"
列表

cargo-make也支持列表,这些列表在运行时使用;进行连接。

LIST_VALUE = [ "VALUE1", "VALUE2", "VALUE3" ]
脚本

cargo-make支持使用简单的脚本。该脚本的输出将决定环境变量的值。

脚本对象有两个额外的参数:multilinedepends_on。如果multiple设置为true,提供的脚本将被评估为多行脚本。如果未设置depends_on,则该脚本依赖于的环境变量列表,在重新排序时将被考虑。如果未设置,cargo-make将尝试猜测在重新排序期间使用的变量。

注意:这使用默认的操作系统命令执行程序(Windows上的cmd,UNIX系统上的sh),不支持其他执行程序,如duckscriptrust等。

EVALUATED_VAR = { script = ["echo SOME VALUE"] }
解码映射

cargo-make 支持使用映射,其中将 source 与可能的 mapping 字典进行匹配,其中 mapping 的每个键与评估后的 source 值进行比较。如果键和 source 相同,则对应的值将是环境变量的值。如果没有匹配到键,如果提供了 default_value,则使用它。否则,将默认为空字符串。

LIBRARY_EXTENSION = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "unknown", mapping = {"linux" = "so", "macos" = "dylib", "windows" = "dll", "openbsd" = "so" } }
路径

cargo-make 支持使用 glob 语法在给定目录中查找所有文件和目录。在执行期间,文件列表将使用 ; 连接。

PATH_GLOB = { glob = "./src/**/mod.rs", include_files = true, include_dirs = false, ignore_type = "git" }
条件

cargo-make 支持条件变量,如果 condition 评估为 true,则将其设置为指定的 value。有关条件的更多信息,请参阅本节

未设置

可以取消设置变量。

VARIABLE = {unset = true}

全局配置

可以使用顶级 [env] 键全局设置环境变量,并提供多个配置文件,可以在执行 cargo make 时使用 --profile <name> 来选择。

在全局 [env]和默认的 Makefile.toml 中设置的环境变量将在运行任何任务之前设置。

示例
[env]
RUST_BACKTRACE = 1
EVALUATED_VAR = { script = ["echo SOME VALUE"] }
TEST1 = "value1"
TEST2 = "value2"
BOOL_VALUE = true
DEV = false
PROD = false
COMPOSITE = "${TEST1} ${TEST2}"
MULTI_LINE_SCRIPT = { script = ["echo 1\necho 2"], multi_line = true }
CONDITIONAL_SCRIPT = { script = ["echo conditional_script"], condition = { env_not_set = ["CONDITIONAL_SCRIPT"] } }
LIBRARY_EXTENSION = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "unknown", mapping = {"linux" = "so", "macos" = "dylib", "windows" = "dll", "openbsd" = "so" } }
TO_UNSET = { unset = true }
PREFER_EXISTING = { value = "new", condition = { env_not_set = ["PREFER_EXISTING"] } }
OVERWRITE_EXISTING = { value = "new", condition = { env_set = ["OVERWRITE_EXISTING"] } }
ENV_FROM_LIST = ["ARG1", "${SIMPLE}", "simple value: ${SIMPLE} script value: ${SCRIPT}"]
PATH_GLOB = { glob = "./src/**/mod.rs", include_files = true, include_dirs = false, ignore_type = "git" }

# profile based environment override
[env.development]
DEV = true

[env.production]
PROD = true

任务

可以在任务的作用域中设置环境变量,并且在执行该任务时,它们将与全局环境合并。这意味着环境变量的评估发生在所有依赖项运行之后,但在任务本身运行之前。

注意: 不会对任务变量和全局变量进行排序。任务简单地覆盖之前声明的变量。

注意: 执行后不会清理变量,这意味着执行任务后的任务将继承前一个任务设置的变量。

cargo-make 在单个任务级别上支持与全局配置相同的相同功能。

[tasks.test-flow]
env = { "SOME_ENV_VAR" = "value" }
run_task = "actual-task"

[tasks.actual-task]
condition = { env_set = [ "SOME_ENV_VAR" ] }
script = '''
echo var: ${SOME_ENV_VAR}
'''

命令行

可以使用 --env / - 参数在命令行中定义环境变量,如下所示

cargo make --env ENV1=VALUE1 --env ENV2=VALUE2 -e ENV3=VALUE3

环境文件

也可以在 CLI 参数中提供环境文件路径,如下所示

cargo make --env-file=./env/production.env

这允许使用相同的 Makefile.toml,但使用从环境文件加载的不同环境变量集。

环境文件是一个简单的 key=value,类似于 dotenv,但只支持使用 ${} 语法进行变量插值。

#just a comment...
ENV1_TEST=TEST1
ENV2_TEST=TEST2
ENV3_TEST=VALUE OF ENV2 IS: ${ENV2_TEST}

可以在 Makefile.tomlenv_files 键中全局定义环境文件路径,它们将按定义的顺序加载。所有相对路径都是相对于定义它们的 Makefile.toml 所在目录的相对路径。

注意: env_files 也可以在任务级别上使用。请注意,相对路径将相对于 当前工作目录

env_files = [
    "./env1.env",
    "./env2.env"
]

要仅在变量尚未定义时加载环境变量,请使用 defaults_only 属性。

env_files = [
    { path = "./load_only_undefined.env", defaults_only = true },
    { path = "./load_all.env" }
]

使用 profile 属性仅在特定配置文件活动时加载环境变量。

要了解更多关于配置文件的信息,请查看 配置文件部分

env_files = [
    { path = "./profile.env", profile = "development" },
    { path = "./env.env" }
]

环境设置脚本

环境设置脚本在环境文件和 env 块之后调用。它们由 env_scripts 属性全局定义。这些脚本可以在启动流程之前运行任何需要的操作。

对于由嵌入式运行时调用的 duckscript 脚本,可以直接修改 cargo-make 运行时环境变量。

例如

env_scripts = [
'''
#!@duckscript
echo first env script...

composite_env_value = get_env COMPOSITE
echo COMPOSITE = ${composite_env_value}

set_env COMPOSITE_2 ${composite_env_value}
''',
'''
#!@duckscript
echo second env script...

composite_env_value = get_env COMPOSITE_2
echo COMPOSITE_2 = ${composite_env_value}
'''
]

[env]
SIMPLE = "SIMPLE VALUE"
SCRIPT = { script = ["echo SCRIPT VALUE"] }
COMPOSITE = "simple value: ${SIMPLE} script value: ${SCRIPT}"

在这个例子中,由于 env 块在 env 脚本之前调用,所以 duckscript 可以访问 COMPOSITE 环境变量。
这些脚本使用该值创建一个新的环境变量 COMPOSITE_2,并在第二个脚本中打印它。

加载顺序

cargo-make 将按以下顺序加载环境变量

  • 加载命令行提供的环境文件
  • 设置内部环境变量(见 全局 部分)。**不包括任务特定变量**。
  • 加载在 env_files 属性中定义的全局环境文件。
  • 加载命令行提供的全局环境变量。
  • 根据配置文件/附加配置文件加载在 env 块和相关的子 env 块中定义的全局环境变量。
  • 加载在 env.[当前配置文件] 块中定义的全局环境变量。
  • 加载在 env_scripts 属性中定义的全局环境设置脚本。
  • 任务特定
    • 加载在 env_files 属性中定义的环境文件(相对于全局 env_files 处理方式不同)。
    • 设置 任务特定 内部环境变量(见 全局 部分)。
    • 加载在 env 块中定义的环境变量(与全局 env 块的行为相同)。

在每一步中,可以根据需要重新排序变量以确保指定所有依赖关系。环境变量将在每个任务运行之前进行插值。

关于顺序的说明

cargo-make 中环境变量的顺序在定义和评估之间不一定相同。相反,cargo-make 会查看值并根据提到的变量重新排序变量。

这种行为具有许多优点,例如可以自由地引用其他变量或在不同作用域中重新定义它们。

[env]
VAR1="${VAR2}"
VAR2=2

一种简单的实现可能会导致以下结果:VAR1=""VAR2=2,这种行为可能会非常意外,尤其是在扩展环境变量的现有声明时。与 cargo-make 不同,它使用类似于 terraform 这样的工具的方法,它会识别出 VAR1 依赖于 VAR2,这将输出 VAR1=2VAR2=2

[env]
VAR1="${VAR2}"

[env.prod]
VAR2=2

[env.devel]
VAR2=3

这是一个扩展的例子,由于不同的配置文件与环境(基本上是追加)合并,所以简单的实现无法工作。然而,与 cargo-make 不同,它将识别依赖关系并正确解决所有值。

简单实现
--release=test
    VAR1=""
--release=prod
    VAR1=""
    VAR2=2
--release=devel
    VAR1=""
    VAR2=3
cargo-make 实现
--release=test
    VAR1=""
--release=prod
    VAR1="2"
    VAR2=2
--release=devel
    VAR1="3"
    VAR2=3

全局

除了手动设置环境变量外,cargo-make 还会自动添加一些环境变量,这在使用任务脚本、命令、条件等时可能很有帮助。

  • CARGO_MAKE - 设置为 "true" 以帮助子进程识别它们正在从 cargo make 运行。
  • CARGO_MAKE_TASK - 存储正在执行的主要任务名称。
  • CARGO_MAKE_TASK_ARGS - 在任务名称之后提供的参数列表,参数之间用分号字符分隔。
  • CARGO_MAKE_CURRENT_TASK_NAME - 存储当前正在执行的任务名称。
  • CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE - 存储最初定义当前正在执行的任务的 makefile 的完整路径(对于内部核心任务不可用)。
  • CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY - 存储包含最初定义当前正在执行的任务的 makefile 的目录的完整路径(对于内部核心任务不可用)。
  • CARGO_MAKE_COMMAND - 调用 cargo-make 的命令(例如:cargo makemakers
  • CARGO_MAKE_WORKING_DIRECTORY - 当前工作目录(可以通过设置 --cwd CLI 选项来定义)
  • CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY - 工作区的原始工作目录。使工作区成员能够访问工作区级别的 CARGO_MAKE_WORKING_DIRECTORY
  • CARGO_MAKE_PROFILE - 当前配置文件名称的小写(不应由全局/任务环境块手动修改)
  • CARGO_MAKE_ADDITIONAL_PROFILES - 额外配置文件名称的小写,用分号字符分隔(不应由全局/任务环境块手动修改)
  • CARGO_MAKE_PROJECT_NAME - 对于独立包,这将与 CARGO_MAKE_CRATE_NAME 相同,对于工作区,它将默认为工作目录的基本名。
  • CARGO_MAKE_PROJECT_VERSION 对于独立包,这将与 CARGO_MAKE_CRATE_VERSION 相同,对于工作区,它将是主包版本(主包由配置部分中的可选 main_project_member 属性定义)。
  • CARGO_MAKE_CARGO_HOME - 根据cargo 文档中描述的路径到 CARGO_HOME
  • CARGO_MAKE_CARGO_PROFILE - 从 CARGO_MAKE_PROFILE 映射的 cargo 配置文件名称(未映射的值将默认为 CARGO_MAKE_PROFILE 的值)
  • CARGO_MAKE_RUST_VERSION - Rust 版本(例如 1.20.0)
  • CARGO_MAKE_RUST_CHANNEL - Rust 频道(稳定版、beta版、nightly版)
  • CARGO_MAKE_RUST_TARGET_ARCH - x86、x86_64、arm 等 ... (参见 rust cfg 功能)
  • CARGO_MAKE_RUST_TARGET_ENV - gnu、msvc 等 ... (参见 rust cfg 功能)
  • CARGO_MAKE_RUST_TARGET_OS - Windows、macOS、iOS、Linux、Android 等 ... (参见 rust cfg 功能)
  • CARGO_MAKE_RUST_TARGET_POINTER_WIDTH - 32, 64
  • CARGO_MAKE_RUST_TARGET_VENDOR - apple、pc、unknown
  • CARGO_MAKE_RUST_TARGET_TRIPLE - x86_64-unknown-linux-gnu、x86_64-apple-darwin、x86_64-pc-windows-msvc 等 ...
  • CARGO_MAKE_CRATE_TARGET_DIRECTORY - 获取 cargo 存储构建输出的目标目录,尊重 ${CARGO_TARGET_DIR}.cargo/config.toml${CARGO_HOME}/config.toml,但不尊重 --target-dir 命令行标志。
  • CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY - 与 CARGO_MAKE_CRATE_TARGET_DIRECTORY 类似,但尊重 .cargo/config.toml 中的 build.target
  • CARGO_MAKE_CRATE_HAS_DEPENDENCIES - 根据在 Cargo.toml 中是否定义了依赖项而持有 true/false(如果没有找到 Cargo.toml,则定义为 false
  • CARGO_MAKE_CRATE_IS_WORKSPACE - 根据是否为 workspace crate 而持有 true/false(即使没有找到 Cargo.toml,也会定义)
  • CARGO_MAKE_CRATE_WORKSPACE_MEMBERS - 持有一个成员路径列表(如果没有找到 Cargo.toml,则定义为空值)
  • CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER - 持有正在构建的当前 workspace 成员的名称(仅当流程从 workspace 级别流程开始时)
  • CARGO_MAKE_CRATE_LOCK_FILE_EXISTS - 如果当前工作目录中存在 Cargo.lock 文件,则持有 true/false(在 workspace 项目中,每个成员都有自己的工作目录)。
  • CARGO_MAKE_CRATE_TARGET_TRIPLE - 获取默认构建的目标三元组,尊重 .cargo/config.toml${CARGO_HOME}/config.toml
  • CARGO_MAKE_WORKSPACE_PACKAGE_NAME - 持有当前工作目录中 Cargo.toml 文件中的 workspace 根包名称。
  • CARGO_MAKE_WORKSPACE_PACKAGE_VERSION - 持有当前工作目录中 Cargo.toml 文件中的 workspace 根包版本。
  • CARGO_MAKE_WORKSPACE_PACKAGE_DESCRIPTION - 持有当前工作目录中 Cargo.toml 文件中的 workspace 根包描述。
  • CARGO_MAKE_WORKSPACE_PACKAGE_LICENSE - 存储工作区根包的许可证,来源于当前工作目录中的 Cargo.toml 文件。
  • CARGO_MAKE_WORKSPACE_PACKAGE_DOCUMENTATION - 存储工作区根包文档链接,来源于当前工作目录中的 Cargo.toml 文件。
  • CARGO_MAKE_WORKSPACE_PACKAGE_HOMEPAGE - 存储工作区根包主页链接,来源于当前工作目录中的 Cargo.toml 文件。
  • CARGO_MAKE_WORKSPACE_PACKAGE_REPOSITORY - 存储工作区根包仓库链接,来源于当前工作目录中的 Cargo.toml 文件。
  • CARGO_MAKE_CI - 如果任务在持续集成系统(如Travis CI)中运行,则存储 true/false
  • CARGO_MAKE_PR - 如果任务在持续集成系统(如Travis CI)中作为拉取请求构建的一部分运行,则存储 true/false(未知情况默认为false)。
  • CARGO_MAKE_CI_BRANCH_NAME - 存储持续集成分支名称(如果可用)。
  • CARGO_MAKE_CI_VENDOR - 存储持续集成供应商名称(如果可用)。
  • CARGO_MAKE_DUCKSCRIPT_VERSION - 嵌入的 duckscript 运行时版本。
  • CARGO_MAKE_DUCKSCRIPT_SDK_VERSION - 嵌入的 duckscript SDK 版本。

以下环境变量将在 Cargo.toml 文件存在且定义了相关值时由 cargo-make 设置

  • CARGO_MAKE_CRATE_NAME - 存储当前工作目录中 Cargo.toml 文件中的 crate 名称。
  • CARGO_MAKE_CRATE_FS_NAME - 与 CARGO_MAKE_CRATE_NAME 相同,但某些字符被替换(例如 '-' 到 '_')。
  • CARGO_MAKE_CRATE_VERSION - 存储当前工作目录中找到的 crate 版本。
  • CARGO_MAKE_CRATE_DESCRIPTION - 存储当前工作目录中 Cargo.toml 文件中的 crate 描述。
  • CARGO_MAKE_CRATE_LICENSE - 存储当前工作目录中 Cargo.toml 文件中的 crate 许可证。
  • CARGO_MAKE_CRATE_DOCUMENTATION - 存储当前工作目录中 Cargo.toml 文件中的 crate 文档链接。
  • CARGO_MAKE_CRATE_HOMEPAGE - 存储当前工作目录中 Cargo.toml 文件中的 crate 主页链接。
  • CARGO_MAKE_CRATE_REPOSITORY - 存储当前工作目录中 Cargo.toml 文件中的 crate 仓库链接。

以下环境变量将在项目是 git 仓库的一部分时由 cargo-make 设置

  • CARGO_MAKE_GIT_BRANCH - 当前分支名称。
  • CARGO_MAKE_GIT_USER_NAME - 从 git 配置的 user.name 键获取的用户名。
  • CARGO_MAKE_GIT_USER_EMAIL - 从 git 配置的 user.email 键获取的用户电子邮件。
  • CARGO_MAKE_GIT_HEAD_LAST_COMMIT_HASH - 最后的 HEAD 提交哈希值。
  • CARGO_MAKE_GIT_HEAD_LAST_COMMIT_HASH_PREFIX - 最后的 HEAD 提交哈希值前缀。

设置工作目录

为了修改特定任务(非整个运行)的当前工作目录,请使用cwd属性。
例如

[tasks.move-dir]
cwd = "./mysubdir/"

忽略错误

在某些情况下,您可能希望将可选任务作为更大流程的一部分运行,但在这些可选任务中发生任何错误时,您不希望破坏整个构建。
对于这些任务,您可以使用具有ignore_errors=true属性的属性。

[tasks.unstable_task]
ignore_errors = true

条件

条件允许您在运行时评估是否运行特定任务。
在任务运行其安装和/或命令之前,会评估这些条件。如果条件不满足,则不会调用任务。
然而,任务依赖不受父任务条件结果的影响。

有两种类型的条件

任务运行器将评估任何定义的条件,并且一个任务定义可能同时包含这两种类型。

标准

条件属性可以定义多个参数进行验证。
所有定义的参数都必须有效,条件作为整体才是真实的,才能启用任务运行。

以下是一个条件定义的示例,该定义检查我们是否在Windows或Linux上运行(但不是macOS),并且是否在beta或nightly上运行(但不是稳定版)

[tasks.test-condition]
condition = { platforms = ["windows", "linux"], channels = ["beta", "nightly"] }
script = '''
echo "condition was met"
'''

以下条件类型可用

  • profile - 有关更多信息,请参阅配置文件
  • os - 操作系统名称列表(Windows、macOS、iOS、Linux、Android等...,如由cfg!(target_os)定义)
  • platforms - 平台名称列表(windows、linux、mac)
  • channels - Rust通道列表(稳定版、beta版、nightly版)
  • env_set - 必须定义的环境变量列表
  • env_not_set - 必须未定义的环境变量列表
  • env_true - 必须定义并设置以下之一(不区分大小写):false、no、0或空字符串的环境变量列表
  • env_false - 必须定义并设置为以下之一(不区分大小写):false、no、0或空字符串的环境变量列表
  • env - 必须定义并等于提供的值的环境变量映射
  • env_contains - 必须定义并包含提供的值的环境变量映射(不区分大小写)
  • rust_version - 可选的min、max和/或特定rust版本定义
  • files_exist - 要检查它们是否存在的绝对路径文件列表。支持环境替换,因此您可以定义相对路径,例如${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml
  • files_not_exist - 要检查它们是否不存在的绝对路径文件列表。支持环境替换,因此您可以定义相对路径,例如${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml
  • files_modified - 输入和输出glob列表。如果任何输入文件比所有输出文件新,则条件满足。支持环境替换,因此您可以定义相对路径,例如${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml

一些示例

[tasks.test-condition]
condition = {
    profiles = ["development", "production"],
    platforms = ["windows", "linux"],
    channels = ["beta", "nightly"],
    env_set = [ "CARGO_MAKE_KCOV_VERSION" ],
    env_not_set = [ "CARGO_MAKE_SKIP_CODECOV" ],
    env = { "CARGO_MAKE_CI" = true, "CARGO_MAKE_RUN_CODECOV" = true },
    rust_version = { min = "1.20.0", max = "1.30.0" },
    files_exist = ["${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml"],
    files_not_exist = ["${CARGO_MAKE_WORKING_DIRECTORY}/Cargo2.toml"],
    files_modified = { input = ["${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "./src/**/*.rs"], output = ["./target/**/myapp*"] }
}

要设置自定义失败消息,请在条件对象内部使用fail_message,例如

[tasks.test-condition-with-message]
condition = { platforms = ["windows"], fail_message = "Condition Failed." }
command = "echo"
args = ["condition was met"]

如果日志级别为详细或配置中的减少输出标志设置为false,则仅打印失败消息

[config]
reduce_output = false

脚本

以下脚本在任务运行其安装和/或命令之前调用,并且如果条件脚本的退出码非零,则不会调用任务。

以下是一个始终返回非零值的条件脚本示例,在这种情况下,该命令永远不会执行

[tasks.never]
condition_script = """
exit 1
"""
command = "cargo"
args = ["build"]

条件脚本可用于确保仅在满足特定条件时调用任务,例如特定第三方已安装。

要设置自定义失败消息,请在条件对象内部使用fail_message,例如

[tasks.test-condition-script-with-message]
condition = { fail_message = "Condition Script Failed." }
condition_script = [
    "exit 1"
]
command = "echo"
args = ["condition was met"]

和/或/分组或

默认情况下,所有条件组和每个组内部的所有条件都将进行评估,并且使用'AND'来验证一切是否按请求进行。
但是,还有其他类型的条件可用

  • 或 - 在每个组内搜索满足单个条件的所有组和所有条件
  • GroupOr - 在每个组中搜索满足单个条件的所有条件,但所有条件组都必须通过。

只需在条件对象中添加任何这些值之一的 condition_type。
例如

[tasks.test-or-condition]
condition = { condition_type = "Or", env_true = [
  "TRUE_ENV",
  "FALSE_ENV",
], env_false = [
  "TRUE_ENV",
  "FALSE_ENV",
] }
script = '''
echo "condition was met"
'''

组合条件和子任务

条件和运行任务结合可以让你定义一个条件子流程。
例如,如果你有一个覆盖流程,它应该只在CI构建的Linux上调用,并且只有当 CARGO_MAKE_RUN_CODECOV 环境变量定义为 "true" 时

[tasks.ci-coverage-flow]
description = "Runs the coverage flow and uploads the results to codecov."
condition = { platforms = ["linux"], env = { "CARGO_MAKE_CI" = true, "CARGO_MAKE_RUN_CODECOV" = true } }
run_task = "codecov-flow"

[tasks.codecov-flow]
description = "Runs the full coverage flow and uploads the results to codecov."
windows_alias = "empty"
dependencies = [
    "coverage-flow",
    "codecov"
]

第一个任务 ci-coverage-flow 定义了检查我们是否在Linux上运行,作为CI构建的一部分,并且 CARGO_MAKE_RUN_CODECOV 环境变量设置为 "true" 的条件。
只有当所有条件都满足时,它才会运行 codecov-flow 任务。
我们无法在 codecov-flow 任务上直接定义条件,因为它将在检查条件之前调用任务依赖项。

仅在源文件更改时运行任务

files_modified 条件允许任务根据文件修改时间戳跳过。
如果未找到任何比输出中的任何文件更新的输入文件,则条件会导致任务跳过。
输入和输出被定义为要检查的文件的 glob 数组(不是正则表达式)。
在下面的例子中,如果目标二进制文件比 Cargo.toml 或 src 目录中的任何 rust 源文件新,它将不会运行 cargo build 命令。

[tasks.compile-if-modified]
condition = { files_modified = { input = ["${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "./src/**/*.rs"], output = ["./target/**/myapp*"] } }
command = "cargo"
args = ["build"]

安装依赖项

某些任务可能需要第三方 crate、rustup 组件或其他本地工具。
cargo-make 提供了多种方式在运行任务之前设置这些依赖项。

Cargo 插件

当任务使用 command 属性调用 cargo 插件时,例如

[tasks.audit]
command = "cargo"
args = ["audit"]

cargo-make 将首先检查命令是否可用。
只有在命令不可用的情况下,它才会尝试通过运行 cargo install cargo- 来安装它
如果 cargo 插件有不同的名称,您可以通过 install_crate 属性手动指定它。
您可以使用 install_crate_args 属性(例如:版本)指定额外的安装参数。

要禁用自动 crate 安装,可以将 install_crate 属性设置为 false,例如

[tasks.test]
command = "cargo"
args = ["test"]
install_crate = false

crates

cargo-make 可以验证第三方 crate 是否已安装,如果提供了相关的安装信息。
首先它会检查 crate 是否已安装,并且只有在不可用的情况下才会尝试安装。
如果提供了组件名称,第三方 crate 的安装首先通过 rustup 完成。
如果 rustup 失败或未提供组件名称,它将转而使用 cargo install 命令。
例如

[tasks.rustfmt]
install_crate = { crate_name = "rustfmt-nightly", rustup_component_name = "rustfmt-preview", binary = "rustfmt", test_arg = "--help" }
command = "rustfmt"

在这个例子中,cargo 将首先测试 rustfmt --help 命令是否正常工作,并且只有在失败的情况下,它才会首先尝试通过 rustup 安装组件 rustfmt-preview,如果失败,它会尝试运行 cargo install 对 crate 名称 rustfmt-nightly

如果需要传递多个参数,test_arg 可以包含一个参数数组。例如

[tasks.doc-upload]
install_crate = { crate_name = "cargo-travis", binary = "cargo", test_arg = ["doc-upload", "--help"] }
command = "cargo"
args = ["doc-upload"]

在这个例子中,cargo-make 将通过运行命令 cargo doc-upload --help 来测试 cargo-travis 的存在,并且只有当此命令失败时才会安装 crate。

Rustup 组件

未作为 crate 或组件部署的 Rustup 组件(纯源代码,没有可执行二进制文件)也可以通过 cargo-make 安装。
以下示例展示了如何安装带有二进制的 rustup 组件

[tasks.install-rls]
install_crate = { rustup_component_name = "rls-preview", binary = "rls", test_arg = "--help" }

在这个例子中,cargo-make 将首先检查 rls 二进制文件是否可用,并且只有在无法执行它的情况下,它才会使用 rustup 安装 rls 组件。

一些rustup组件是纯源码,因此在这种情况下,cargo-make无法验证它们是否已经安装,并且会尝试每次都安装它们。
示例

[tasks.install-rust-src]
install_crate = { rustup_component_name = "rust-src" }

本地依赖

还可以安装原生依赖,但是需要Makefile的作者编写脚本,检查依赖是否存在,如果不存在,则正确安装。
这是通过在任务的install_script属性中设置安装脚本来实现的。
可以使用平台覆盖来为Linux/macOS/Windows平台指定不同的安装脚本。
例如

[tasks.coverage-kcov]
windows_alias = "empty"
install_script = '''
KCOV_INSTALLATION_DIRECTORY=""
KCOV_BINARY_DIRECTORY=""
if [ -n "CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY" ]; then
    mkdir -p ${CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY}
    cd ${CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY}
    KCOV_INSTALLATION_DIRECTORY="$(pwd)/"
    cd -
    echo "Kcov Installation Directory: ${KCOV_INSTALLATION_DIRECTORY}"
    KCOV_BINARY_DIRECTORY="${KCOV_INSTALLATION_DIRECTORY}/build/src/"
    echo "Kcov Binary Directory: ${KCOV_BINARY_DIRECTORY}"
fi

# get help info to fetch all supported command line arguments
KCOV_HELP_INFO=`${KCOV_BINARY_DIRECTORY}kcov --help` || true

# check needed arguments are supported, else install
if [[ $KCOV_HELP_INFO != *"--include-pattern"* ]] || [[ $KCOV_HELP_INFO != *"--exclude-line"* ]] || [[ $KCOV_HELP_INFO != *"--exclude-region"* ]]; then
    # check we are on a supported platform
    if [ "$(grep -Ei 'debian|buntu|mint' /etc/*release)" ]; then
        echo "Installing/Upgrading kcov..."
        sudo apt-get update || true
        sudo apt-get install -y libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc binutils-dev

        mkdir -p ${CARGO_MAKE_KCOV_DOWNLOAD_DIRECTORY}
        cd ${CARGO_MAKE_KCOV_DOWNLOAD_DIRECTORY}
        KCOV_DOWNLOAD_DIRECTORY=$(pwd)

        wget https://github.com/SimonKagstrom/kcov/archive/v${CARGO_MAKE_KCOV_VERSION}.zip
        unzip v${CARGO_MAKE_KCOV_VERSION}.zip
        cd kcov-${CARGO_MAKE_KCOV_VERSION}
        mkdir -p build
        cd ./build
        cmake ..
        make

        # if custom installation directory, leave kcov as local
        if [ -n "CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY" ]; then
            cd ${KCOV_DOWNLOAD_DIRECTORY}/kcov-${CARGO_MAKE_KCOV_VERSION}
            mv ./* ${KCOV_INSTALLATION_DIRECTORY}
        else
            sudo make install
            cd ../..
            rm -rf kcov-${CARGO_MAKE_KCOV_VERSION}
        fi
    fi
fi
'''

该任务检查kcov是否已安装;如果没有,则会安装它及其所需的任何其他依赖项。

定义版本

可以定义所依赖crate的最小版本,例如

[tasks.simple-example]
install_crate = { min_version = "0.0.1" }
command = "cargo"
args = ["make", "--version"]

[tasks.complex-example]
install_crate = { crate_name = "cargo-make", binary = "cargo", test_arg = ["make", "--version"], min_version = "0.0.1" }
command = "cargo"
args = ["make", "--version"]

这确保我们使用的是支持所需构建功能的crate版本。
目前定义min_version时存在一些限制

  • 在任务中指定toolchain或在install_crate结构中指定rustup_component_name,将使cargo-make忽略最小版本值。
  • 如果由于任何错误cargo-make无法检测当前安装的版本,cargo-make将假定版本有效并打印警告。

如果您想确保使用特定版本,可以定义version属性,例如

[tasks.complex-example]
install_crate = { crate_name = "cargo-make", binary = "cargo", test_arg = ["make", "--version"], version = "0.0.1" }
command = "cargo"
args = ["make", "--version"]

全局版本锁定

如果定义了min_version,您可以通过定义CARGO_MAKE_CRATE_INSTALLATION_LOCKED=true环境变量,自动将--locked标志添加到crate安装命令中。如果定义了version而不是min_version,则自动设置为true。

替代 Cargo 安装命令

您可以指定不同的cargo install命令,以便使crate安装使用某些自定义cargo安装器插件。例如,如果您想使用install而不是local-install插件,只需添加包含相关值的install_command属性。
例如

[tasks.alt-command-example1]
install_crate = { install_command = "custom-install" }
command = "cargo"
args = ["somecrate"]

[tasks.alt-command-example2]
install_crate = { crate_name = "somecrate", install_command = "custom-install" }

默认情况下,添加了--force标志。为了删除它,将force=false添加到install_crate定义中,如下所示

[tasks.alt-command-example2]
install_crate = { crate_name = "somecrate", install_command = "custom-install", force = false }

安装优先级

每个任务只会调用一种安装类型。
以下定义了cargo-make使用的安装类型,按优先级排序,以决定调用哪种安装流程

  • install_crate - 允许安装crate和rustup组件。
  • install_script - 可用于安装或运行任务命令所需的任何内容的自定义脚本。
  • 自动cargo插件 - 如果命令是cargo,cargo-make将检查需要自动安装的cargo插件(如果需要)。

如果定义了多个安装类型(例如,install_crate和install_script),则将根据上述优先级列表调用一种安装类型。

多重安装

在某些情况下,任务需要安装多个项目才能正常运行。
例如,您可能需要在同一任务中安装rustup组件rlsrust-src以及cargo插件cargo-xbuild
为了实现这一点,您可以拆分任务为调用任务和安装任务,并将安装任务设置为依赖项。
以下示例定义了两个具有相同依赖项的类似任务的流程:cargo-xbuild crate、rls rustup二进制组件和rust-src rustup源码组件。
您可以拥有两个rustup依赖项作为仅安装的任务,并将它们设置为xbuild任务的依赖项。
由于依赖项只调用一次,这还将确保不会安装两次这些rustup组件。

[tasks.install-rls]
# install rls-preview only if needed
install_crate = { rustup_component_name = "rls-preview", binary = "rls", test_arg = "--help" }

[tasks.install-rust-src]
# always install rust-src via rustup component add
install_crate = { rustup_component_name = "rust-src" }

[tasks.xbuild1]
# run cargo xbuild, if xbuild is not installed, it will be automatically installed for you
command = "cargo"
args = [ "xbuild", "some arg" ]
dependencies = [ "install-rls", "install-rust-src" ]

[tasks.xbuild2]
# run cargo xbuild, if xbuild is not installed, it will be automatically installed for you
command = "cargo"
args = [ "xbuild", "another arg" ]
dependencies = [ "install-rls", "install-rust-src" ]

[tasks.myflow]
dependencies = [ "xbuild1", "xbuild2" ]

工作区支持

如果cargo-make检测到当前工作目录是工作区根目录(一个包含Cargo.toml的目录,该文件定义了工作区及其成员),它将不会在该目录中调用请求的任务。
相反,它将在运行时生成一个任务定义,该定义将遍历每个成员目录并在该成员上调用请求的任务。
例如,如果我们有以下目录结构

workspace
├── Cargo.toml
├── member1
   └── Cargo.toml
└── member2
    └── Cargo.toml

如果我们运行cargo make mytask,它将进入每个工作区成员目录并执行:在当前目录下执行cargo make mytask,其中mytask是在工作区级别请求的原始任务。
成员的顺序由工作区Cargo.toml中的成员属性定义。

这种流程被称为工作区流程,因为它识别工作区并处理对每个工作区成员的请求,而定义工作区结构的根目录被忽略。

我们可以使用这项功能在所有工作区成员crates上运行相同的功能,例如,如果我们想格式化所有crates,我们可以在工作区目录中运行:cargo make format

成员crate的makefile也可以自动扩展工作区目录的makefile。
更多信息请参阅相关部分。

禁用工作区支持

如果您希望在工作区根目录上运行任务而不是在成员上运行(例如生成工作区级别的README文件),请在运行cargo make时使用--no-workspace CLI标志。
例如

cargo make --no-workspace mytask

这使cargo-make忽略该目录是工作区根目录的事实,并且就像这是一个带有makefile的简单目录一样运行简单的流程。

另一种在工作区级别调用任务的方法(而不是针对每个成员)是在工作区Makefile.toml中将该任务定义为具有workspace设置为false,如下所示

[tasks.ignore-members]
workspace = false

将cargo-make命令行请求的任务的workspace=false设置等同于使用--no-workspace标志调用它。
此标志仅针对cargo-make命令行上的任务进行检查,对于所有其他作为流程一部分执行的任务完全忽略。
默认情况下,所有任务的workspac标志都设置为true,但在配置部分可以配置为不同,如下所示

[config]
default_to_workspace = false

在这种情况下,工作区级别支持始终是禁用的,除非任务定义为workspace=true

复合流程

您可以为工作区根目录和成员目录上的任务定义一个复合流程。
这是一个工作区级别Makefile.toml的示例,它启用了这样的流程

[tasks.composite]
dependencies = ["member_flow", "workspace_flow"]

[tasks.member_flow]
# by forking, cargo make starts and by default detects it is a workspace and runs the member_task for each member
run_task = { name = "member_task", fork = true }

[tasks.workspace_flow]
#run some workspace level command or flow

您可以通过以下方式启动此复合流程

cargo make --no-workspace composite

配置文件

您可以通过将CARGO_MAKE_USE_WORKSPACE_PROFILE设置为false来防止配置文件传递到工作区成员

[env]
CARGO_MAKE_USE_WORKSPACE_PROFILE = false

更多关于配置文件的信息请参阅配置文件部分

跳过/包含特定成员

在大多数情况下,您可能希望在所有成员上运行特定的流程,但在极少数情况下,您可能希望跳过特定的成员。

通过将CARGO_MAKE_WORKSPACE_SKIP_MEMBERS环境变量设置为包含要跳过的成员名称的数组,您可以定义是否要那些成员不参与流程。

在下面的示例中,我们将跳过member3和member4(应在工作区级别的Makefile.toml中定义)

[env]
CARGO_MAKE_WORKSPACE_SKIP_MEMBERS = ["member3", "member4"]

您还可以定义glob路径,例如

[env]
CARGO_MAKE_WORKSPACE_SKIP_MEMBERS = "tools/*"

但是,有些情况下您可能只想在有特定条件满足时跳过特定的成员。
例如,如果您想在rust nightly编译器上运行时才构建成员模块。
这是对member3和member4的条件跳过简单示例(应在工作区级别的Makefile.toml中定义)

[tasks.workspace-task]
condition = { channels = ["beta", "stable"] }
env = { "CARGO_MAKE_WORKSPACE_SKIP_MEMBERS" = ["member3", "member4"] }
run_task = { name = "member-task", fork = true }

您必须将其作为复合流程调用

cargo make workspace-task --no-workspace

此外,您还可以声明相反的情况,即通过 CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS 环境变量来指定要包含的成员。
它与 CARGO_MAKE_WORKSPACE_SKIP_MEMBERS 环境变量遵循相同的规则。
如果同时定义了这两个变量,则包含的成员将是未被排除的成员的子集,意味着两个过滤器都将应用。

工作区模拟

工作区模拟允许您为项目创建类似于工作区结构,而无需实际定义 Rust 工作区。
这意味着您可以有一个没有 Cargo.toml 的项目目录,并且有很多子包。
这允许在根项目目录中运行 cargo make,对所有 成员 包进行操作,而无需实际的工作区,这会产生一些副作用(如共享目标文件夹和依赖项)。

为了设置工作区模拟,您需要在您的工作区级别的 Makefile.toml 中定义以下内容

[env]
# this tells cargo-make that this directory acts as a workspace root
CARGO_MAKE_WORKSPACE_EMULATION = true

# a list of crate members. since we do not have a Cargo.toml, we will need to specify this in here.
CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
    "member1",
    "member2"
]

工具链

cargo-make 支持通过设置任务定义中的一部分 toolchain 属性来设置调用命令和安装 Rust 依赖项时要使用的工具链。
以下示例显示了如何打印当前安装的稳定和夜间 rustc 版本

[tasks.rustc-version-stable]
toolchain = "stable"
command = "rustc"
args = [ "--version" ]

[tasks.rustc-version-nightly]
toolchain = "nightly"
command = "rustc"
args = [ "--version" ]

[tasks.rustc-version-flow]
dependencies = [
    "rustc-version-stable",
    "rustc-version-nightly"
]

上述 rustc-version-flow 的示例输出为

[cargo-make] INFO - Task: rustc-version-flow
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: rustc-version-stable
[cargo-make] INFO - Execute Command: "rustup" "run" "stable" "rustc" "--version"
rustc 1.30.1 (1433507eb 2018-11-07)
[cargo-make] INFO - Running Task: rustc-version-nightly
[cargo-make] INFO - Execute Command: "rustup" "run" "nightly" "rustc" "--version"
rustc 1.32.0-nightly (451987d86 2018-11-01)
[cargo-make] INFO - Running Task: rustc-version-flow
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 2 seconds.

当与脚本(而不是命令)一起定义时,CARGO 环境变量将为请求的工具链定义。
以下示例显示了如何打印稳定和夜间 CARGO 二进制路径

[tasks.echo-cargo-stable]
toolchain = "stable"
script = '''
echo ${CARGO}
'''

[tasks.echo-cargo-nightly]
toolchain = "nightly"
script = '''
echo ${CARGO}
'''

[tasks.echo-cargo-all]
dependencies = ["echo-cargo-stable", "echo-cargo-nightly"]

上述 echo-cargo-all 的示例输出为

[cargo-make] INFO - Task: echo-cargo-all
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: legacy-migration
[cargo-make] INFO - Running Task: echo-cargo-stable
/home/someuser/.rustup/toolchains/stable-armv7-unknown-linux-gnueabihf/bin/cargo
[cargo-make] INFO - Running Task: echo-cargo-nightly
/home/someuser/.rustup/toolchains/nightly-armv7-unknown-linux-gnueabihf/bin/cargo
[cargo-make] INFO - Build Done in 4.44 seconds.

您还可以通过通道断言 rustc 的最小所需版本。这有助于记录所需的编译器功能和提醒开发人员升级其安装。

[tasks.requires-stable-edition-2021]
toolchain = { channel = "stable", min_version = "1.56" }
command = "rustc"
args = ["--version"]

如果工具链未安装或现有版本小于指定的 min_version,则任务将失败。

初始化和结束任务

由 cargo-make 执行的每个任务或流程都有额外的 2 个任务。
一个初始化任务,在所有流程的开始时调用,以及一个结束任务,在所有流程的结束时调用。
初始化和结束任务的名字定义在 toml 文件的配置部分中,以下显示默认设置

[config]
init_task = "init"
end_task = "end"

[tasks.init]

[tasks.end]

默认情况下,初始化和结束任务都是空的,可以通过外部 toml 文件进行修改,或者您可以简单地在外部 toml 文件中更改初始化和结束任务的名字,以便指向不同的任务。
这些任务允许在运行任何流程时调用常见操作。

重要的是要注意,初始化和结束任务的调用与其他任务不同。

  • 别名和依赖项将被忽略
  • 如果在执行的流程中定义了相同的任务,则这些任务将被多次调用

因此,不建议在流程中也使用初始化/结束任务。

捕获错误

默认情况下,任何未将 ignore_errors=true 设置为的 task 的错误都将导致整个流程失败。
然而,在某些情况下,您可能希望在流程失败之前进行某种清理。
cargo make 允许您定义一个 on error 任务,该任务仅在流程失败时调用。
为了定义此特殊任务,您必须在 Makefile 的 config 部分中添加 on_error_task 属性,并将其指向您的任务,例如

[config]
on_error_task = "catch"

[tasks.catch]
script = '''
echo "Doing cleanups in catch"
'''

Cargo 别名任务

Cargo 别名命令 可以自动加载为 cargo-make 任务。
为了自动加载它们,必须在 Makefile.toml 的配置部分中定义以下内容

[config]
load_cargo_aliases = true

在 config.toml 中定义的每个别名都将加载为具有与别名相同名称的任务。
如果存在同名的任务,它将被忽略。
任务定义将简单地调用cargo和别名值,因此不会自动安装cargo插件。

配置文件

配置文件是一个有用的工具,用于定义自定义行为。
为了设置执行配置文件,请使用 --profile-p 命令行参数,并指定配置文件名称。
配置文件名称将自动转换为下划线并去除多余空格。
如果没有提供配置文件名称,配置文件将默认为 开发

设置配置文件示例

cargo make --profile production mytask

配置文件提供多项功能

condition = { profiles = ["development", "production"] }
  • 新环境变量 CARGO_MAKE_PROFILE,它包含配置文件名称,可以被条件、脚本和命令使用。

可以使用 additional_profiles 同时激活多个配置文件,但这些支持有限。
默认配置文件(如果没有通过命令行提供)是 "development"
但是,可以通过设置环境变量 CARGO_MAKE_DEFAULT_PROFILE 来覆盖它。

[config]
additional_profiles = ["second_profile", "another_profile"]

额外的配置文件可以用来定义额外的环境块,并将它们定义在新的环境变量 CARGO_MAKE_ADDITIONAL_PROFILES 中。

环境变量

配置文件使您能够定义一个新子集的环境变量,这些变量仅在当前配置文件与env配置文件匹配时在运行时设置。

[env]
RUST_BACKTRACE = "1"
EVALUATED_VAR = { script = ["echo SOME VALUE"] }
TEST1 = "value1"
TEST2 = "value2"
COMPOSITE = "${TEST1} ${TEST2}"

# profile based environment override
[env.development]
DEV = true

[env.production]
PROD = true

例如,给定以下具有2个基于配置文件的环境映射的makefile

[env]
COMMON = "COMMON"
PROFILE_NAME = "${CARGO_MAKE_PROFILE}"

[env.development]
IS_DEV = true
IS_PROD = false

[env.production]
IS_DEV = false
IS_PROD = true

[tasks.echo]
script = [
'''
echo COMMON: ${COMMON}
echo PROFILE_NAME: ${PROFILE_NAME}
echo IS_DEV: ${IS_DEV}
echo IS_PROD: ${IS_PROD}
'''
]

我们使用 生产 配置文件运行 echo 任务如下

cargo make --cwd ./examples --makefile profile.toml --profile production echo

输出

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: profile.toml
[cargo-make] INFO - Task: echo
[cargo-make] INFO - Profile: production
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: echo
+ cd /media/devhdd/projects/rust/cargo-make/examples
+ echo COMMON: COMMON
COMMON: COMMON
+ echo PROFILE_NAME: production
PROFILE_NAME: production
+ echo IS_DEV: FALSE
IS_DEV: FALSE
+ echo IS_PROD: TRUE
IS_PROD: TRUE
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

环境文件也可以根据配置文件使用 profile 属性进行过滤,如下所示

env_files = [
    { path = "./development.env", profile = "development" },
    { path = "./production.env", profile = "production" },
    { path = "./env.env" }
]

在配置部分定义的额外配置文件也将导致额外的环境块/文件被加载,例如

env_files = [
    { path = "./second.env", profile = "second_profile" },
    { path = "./another.env", profile = "another_profile" }
]

[config]
additional_profiles = ["second_profile", "another_profile"]

[env.second_profile]
IS_SECOND_AVAILABLE = true

[env.another_profile]
IS_OTHER_AVAILABLE = true

这可以非常有用,因为它可以在环境变量块中启用/禁用特定的任务。

条件

条件允许您触发/跳过任务。
条件内置了对配置文件的支持,因此您可以根据配置文件名称触发/跳过任务。

示例

[tasks.echo-development]
condition = { profiles = [ "development" ] }
command = "echo"
args = [ "running in development profile" ]

[tasks.echo-production]
condition = { profiles = [ "production" ] }
command = "echo"
args = [ "running in production profile" ]

内置配置文件

cargo-make包含一些内置的配置文件,以快速启用额外的条件任务。

  • ci-coverage-tasks - 将启用所有代码覆盖率任务,并设置rust编译以移除无效代码。
  • none-thread-safe-tests - 将rust测试运行器设置为单线程
  • multi-phase-tests - 允许将测试分成多个阶段(线程安全、多线程、自定义)
  • ci-static-code-analysis-tasks - 将启用所有静态代码分析任务,例如格式检查和clippy,作为CI流程的一部分(关于向下兼容性的特殊说明见下文)。
  • ci-all-build-tasks - 将启用所有额外的编译任务(即基准和示例代码),作为CI流程的一部分(关于向下兼容性的特殊说明见下文)。
  • all-default-tasks - 将在运行默认任务时启用额外的任务(例如toml格式化)。

其中一些配置文件可能会在未来更改,以启用更多任务,这可能会破坏您的构建,并且按定义将永远不会向下兼容。
请谨慎使用。

私有任务

私有任务是仅应由其他任务调用而不是直接从CLI调用的任务。

为了将任务定义为私有,请添加具有值true的 private 属性,如下所示

[tasks.internal-task]
private = true

已弃用任务

可以标记任务为已弃用,以警告用户不应再使用此任务,而应切换到较新/不同的任务。
一旦调用,将显示带有弃用信息的警告消息。
您可以通过将 deprecated 设置为 true 或提供相关消息来定义一个已弃用的任务。
例如

[tasks.legacy]
deprecated = "Please use task OTHER instead"

[tasks.legacy-extended]
extend = "legacy"
deprecated = false

[tasks.legacy2]
deprecated = true

例如,调用 legacy 任务时,输出结果为

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: deprecated.toml
[cargo-make] INFO - Task: legacy
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Running Task: legacy
[cargo-make] WARN - Task: legacy is deprecated - Please use task OTHER instead
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Build Done in 0 seconds.

当列出任务时,已弃用的任务将包含此信息

No Category
----------
default - Empty Task
empty - Empty Task
legacy - No Description. (deprecated - Please use task OTHER instead)
legacy-extended - No Description.
legacy2 - No Description. (deprecated)

监视

通过 cargo-make 触发任务以监视项目中的更改非常简单。
只需为任务添加 watch 属性并将其设置为 true,一旦触发任务,就会在项目中的文件更改时运行。
需要终止进程才能停止监视。

示例

[tasks.watch-example]
command = "echo"
args = [ "Triggered by watch" ]
watch = true

以下为调用任务的示例输出

[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: ./examples/watch.toml
[cargo-make] INFO - Task: watch-example
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: watch-example
[cargo-make] INFO - Running Task: watch-example-watch
[cargo-make] INFO - Execute Command: "cargo" "watch" "-q" "-x" "make --disable-check-for-updates --no-on-error --loglevel=info --makefile=/projects/rust/cargo-make/examples/watch.toml watch-example"
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: /projects/rust/cargo-make/examples/watch.toml
[cargo-make] INFO - Task: watch-example
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: watch-example
[cargo-make] INFO - Execute Command: "echo" "Triggered by watch"
Triggered by watch
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.
^C

您还可以通过以下方式调整监视设置(基于 cargo-watch):

[tasks.watch-args-example]
command = "echo"
args = [ "Triggered by watch" ]
watch = { postpone = true, no_git_ignore = true, ignore_pattern = "examples/files/*", watch = ["./docs/"] }

有关所有可用选项的描述,请参阅 文档

运行多个阻塞监视

在需要运行多个阻塞监视的场景(例如运行编译 + HTTP 服务器)中,您需要将所有此类监视作为并行分叉子任务运行。
为了实现这一点,您需要使用 fork=trueparallel=true 属性。
例如

[tasks.multiple-watches]
run_task = { name = ["build", "http-server", "something-else"], fork = true, parallel = true }

函数

cargo-make 提供内置函数,有助于扩展环境变量所缺少的功能。
函数在 makefile 中并不支持,目前仅在命令参数数组结构中受支持。
为了定义函数调用,使用以下格式:@@FUNCTION_NAME(ARG1,ARG2,ARG3,...)
例如

[tasks.split-example]
command = "echo"
args = ["@@split(ENV_VAR,|)"]

当前支持的功能

拆分

split 函数接受两个参数

  • 环境变量名称
  • 按字符分割

然后返回一个子字符串数组。
这可以用来将环境变量分割成多个命令参数,例如

[env]
MULTIPLE_VALUES="1 2 3 4"

[tasks.split]
command = "echo"
args = ["@@split(MULTIPLE_VALUES, )"]

[tasks.no-split]
command = "echo"
args = ["${MULTIPLE_VALUES}"]
> cargo make --cwd ./examples --makefile functions.toml split
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: split
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: split
[cargo-make] INFO - Execute Command: "echo" "1" "2" "3" "4"
1 2 3 4
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

> cargo make --cwd ./examples --makefile functions.toml no-split
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: no-split
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: no-split
[cargo-make] INFO - Execute Command: "echo" "1 2 3 4"
1 2 3 4
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

split 函数还支持可选的第三个 mode 属性。
如果 mode: remove-empty,则输出将不包括空值。

GetAt

getat 函数接受三个参数

  • 环境变量名称
  • 按字符分割
  • 要返回的项目索引

然后返回一个基于给定索引的单值数组。
这可以用来分割环境变量并提取所需参数,例如

[env]
MULTIPLE_VALUES="1 2 3 4"

[tasks.getat]
command = "echo"
args = ["@@getat(MULTIPLE_VALUES,|,3)"]
> cargo make --cwd ./examples --makefile functions.toml getat
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: getat
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: getat
[cargo-make] INFO - Execute Command: "echo" "4"
4
[cargo-make] INFO - Build Done in 0 seconds.

移除空值

remove empty 函数接受单个参数

  • 环境变量名称

如果环境变量未定义或为空,或者返回实际环境变量值,则将完全删除该命令行参数。

[tasks.remove-empty]
command = "echo"
args = ["1", "@@remove-empty(DOES_NOT_EXIST)", "2"]
> cargo make --cwd ./examples --makefile functions.toml remove-empty
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: remove-empty
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: remove-empty
[cargo-make] INFO - Execute Command: "echo" "1" "2"
1 2
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

修剪

trim 函数接受以下参数

  • 环境变量名称
  • 可选的 trim 类型:start/end(如果未提供,则同时修剪起始和结束部分)

如果环境变量未定义,或者修剪后为空,或者返回实际环境变量值,则将完全删除该命令行参数。

[env]
TRIM_VALUE="   123    "

[tasks.trim]
command = "echo"
args = ["@@trim(TRIM_VALUE)"]
> cargo make --cwd ./examples --makefile functions.toml remove-empty
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: trim
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: trim
[cargo-make] INFO - Execute Command: "echo" "123"
123
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

以下为使用 start/end 属性的示例

[env]
TRIM_VALUE="   123    "

[tasks.trim-start]
command = "echo"
args = ["@@trim(TRIM_VALUE,start)"]

[tasks.trim-end]
command = "echo"
args = ["@@trim(TRIM_VALUE,end)"]
> cargo make --cwd ./examples --makefile functions.toml trim-start
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: trim-start
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: trim-start
[cargo-make] INFO - Execute Command: "echo" "123    "
123
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

> cargo make --cwd ./examples --makefile functions.toml trim-end
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: trim-end
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: init
[cargo-make] INFO - Running Task: trim-end
[cargo-make] INFO - Execute Command: "echo" "   123"
   123
[cargo-make] INFO - Running Task: end
[cargo-make] INFO - Build Done  in 0 seconds.

解码

decode 函数接受以下参数

  • 环境变量名称
  • 可选的映射值列表(源/目标)
  • 可选的默认值

如果输出为空,则将删除该命令行参数。

例如

[tasks.decode]
command = "echo"
args = ["Env:", "${CARGO_MAKE_PROFILE}", "Decoded:", "@@decode(CARGO_MAKE_PROFILE,development,dev,ci,test)"]

我们检查 CARGO_MAKE_PROFILE 环境变量值,并在映射中查找。
如果值是 development,则映射为 dev,而 ci 映射为 test
如果没有找到映射,则返回原始值。
找到映射的示例运行

cargo make --cwd ./examples --makefile functions.toml -e DECODE_ENV_VAR=development decode
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: decode
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Running Task: decode
[cargo-make] INFO - Execute Command: "echo" "Env:" "development" "Decoded:" "dev"
Env: development Decoded: dev
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Build Done in 0 seconds.

未找到映射的示例运行

cargo make --cwd ./examples --makefile functions.toml -e DECODE_ENV_VAR=unmapped decode
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: decode
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Running Task: decode
[cargo-make] INFO - Execute Command: "echo" "Env:" "unmapped" "Decoded:" "unmapped"
Env: unmapped Decoded: unmapped
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Build Done in 0 seconds.

另一个示例

[tasks.decode-with-default]
command = "echo"
args = ["Env:", "${DECODE_ENV_VAR}", "Decoded:", "@@decode(DECODE_ENV_VAR,development,dev,ci,test,unknown)"]

与上一个示例相同,但不同之处在于如果没有找到映射,则返回默认值(最后一个参数)。
示例运行

cargo make --cwd ./examples --makefile functions.toml -e DECODE_ENV_VAR=unmapped decode-with-default
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: decode-with-default
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Running Task: decode-with-default
[cargo-make] INFO - Execute Command: "echo" "Env:" "unmapped" "Decoded:" "unknown"
Env: unmapped Decoded: unknown
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Build Done in 0 seconds.

映射值可以包含环境表达式,例如

[tasks.decode-with-eval]
command = "echo"
args = ["Env:", "${DECODE_ENV_VAR}", "Decoded:", "@@decode(DECODE_ENV_VAR,test,The current profile is: ${CARGO_MAKE_PROFILE})"]

示例运行

cargo make --cwd ./examples --makefile functions.toml -e DECODE_ENV_VAR=test decode-with-eval
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: functions.toml
[cargo-make] INFO - Task: decode-with-eval
[cargo-make] INFO - Profile: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Running Task: decode-with-eval
[cargo-make] INFO - Execute Command: "echo" "Env:" "test" "Decoded:" "The current profile is: development"
Env: test Decoded: The current profile is: development
[cargo-make] INFO - Running Task: empty
[cargo-make] INFO - Build Done in 0 seconds.

持续集成

cargo-make 提供了一个由内部或在线服务(如 travis-ci 和 appveyor)执行的持续集成构建的预定义流程。
建议使用调试标志安装 cargo-make 以加快安装速度。

Github 动作

请将以下内容添加到您的 workflow.yml 文件中

- name: Install cargo-make
  uses: actions-rs/cargo@v1
  with:
    command: install
    args: --debug cargo-make
- name: Run CI
  uses: actions-rs/cargo@v1
  with:
    command: make
    args: ci-flow

这将使用最新的 cargo-make 并包含所有最新功能。

您可以在以下位置查看完整的 yaml 文件: ci.yml

如果您想运行代码覆盖率并将其上传到 codecov,也需要定义以下环境变量

CARGO_MAKE_RUN_CODECOV=true

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下命令

- name: Install cargo-make
  uses: actions-rs/cargo@v1
  with:
    command: install
    args: --debug cargo-make
- name: Run CI
  uses: actions-rs/cargo@v1
  with:
    command: make
    args: --no-workspace workspace-ci-flow

为了在构建过程中加快 cargo-make 的安装,您可以使用 rust-cargo-make GitHub 动作下载预构建的二进制文件。

Travis

请将以下内容添加到 .travis.yml 文件中

script:
  - cargo install --debug cargo-make
  - cargo make ci-flow

这将使用最新的 cargo-make 并包含所有最新功能。
当缓存 cargo

cache: cargo
script:
  - which cargo-make || cargo install cargo-make
  - cargo make ci-flow

注意:在使用缓存时,为了更新 cargo-make,您需要手动清除 travis 缓存

如果您想运行代码覆盖率并将其上传到 codecov,也需要定义以下环境变量

env:
  global:
    - CARGO_MAKE_RUN_CODECOV="true"

注意:如果您使用 kcov 覆盖率,可以通过将环境变量 CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY 设置为 travis 缓存的目录来缓存 kcov 安装。

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下命令

script:
  - cargo install --debug cargo-make
  - cargo make --no-workspace workspace-ci-flow

AppVeyor

请将以下内容添加到 .appveyor.yml 文件中

build: false

test_script:
  - cargo install --debug cargo-make
  - cargo make ci-flow

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下命令

build: false

test_script:
  - cargo install --debug cargo-make
  - cargo make --no-workspace workspace-ci-flow

GitLab CI

请将以下内容添加到您的 .gitlab-ci.yml 文件中

test:cargo:
  script:
  - cargo install --debug cargo-make
  - cargo make ci-flow

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下命令

build: false

test:cargo:
  script:
  - cargo install --debug cargo-make
  - cargo make --no-workspace workspace-ci-flow

为了将您的覆盖率信息上传到 codecov,您需要访问 GitLab 仓库的设置,添加一个包含您的 codecov 令牌的密钥变量

然后您可以在 .gitlab-ci.yml 中添加以下内容以启用覆盖率支持

variables:
  CARGO_MAKE_RUN_CODECOV: "true"

CircleCI

请将以下内容添加到您的 .circleci/config.yml 文件中

- run:
    name: install cargo-make
    command: cargo install --debug cargo-make
- run:
    name: ci flow
    command: cargo make ci-flow

这将使用最新的 cargo-make 并包含所有最新功能。
当缓存 cargo

  - restore_cache:
      key: project-cache
  # ....
  - run:
      name: install cargo-make
      command: which cargo-make || cargo install cargo-make
  - run:
      name: ci flow
      command: cargo make ci-flow
  # ....
  - save_cache:
      key: project-cache
      paths:
        - "~/.cargo"

注意:在使用缓存时,为了更新 cargo-make,您需要手动清除 CircleCI 缓存

注意:如果您使用 kcov 覆盖率,可以通过将环境变量 CARGO_MAKE_KCOV_INSTALLATION_DIRECTORY 设置为 CircleCI 缓存的目录来缓存 kcov 安装。

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下命令

- run:
    name: install cargo-make
    command: cargo install --debug cargo-make
- run:
    name: ci flow
    command: cargo make --no-workspace workspace-ci-flow

Azure Pipelines

请将以下内容添加到您的 .azure-pipelines.yml 文件中

- script: cargo install --debug cargo-make
  displayName: install cargo-make
- script: cargo make ci-flow
  displayName: ci flow

在处理工作区时,为了对每个成员运行 ci-flow 并打包所有覆盖率数据,请使用以下配置

- script: cargo install --debug cargo-make
  displayName: install cargo-make
- script: cargo make --no-workspace workspace-ci-flow
  displayName: ci flow

drone.io

这是一个使用 docker 运行器运行 ci-flow 任务的 .drone.yml 最小示例

pipeline:
  ci-flow:
    image: rust:1.38-slim
    commands:
    - cargo install --debug cargo-make
    - cargo make ci-flow

Cirrus CI

这是一个运行 ci-flow 任务的 .cirrus.yml 最小示例

container:
  image: rust:latest

task:
  name: ci-flow
  install_script: cargo install --debug cargo-make
  flow_script: cargo make ci-flow

预定义流程

默认的 makefiles 文件包含了大量预定义的任务和流程。
以下是一些无需任何外部 Makefile.toml 定义即可使用的流程。

  • default - 可以不添加任务名称执行,只需运行 cargo make 即可。此任务是对 dev-test-flow 的别名。
  • dev-test-flow - 也是默认流程,因此无需编写任何任务名称(只需运行 cargo make)。
    此任务运行格式化、cargo build 和 cargo test,很可能是您在开发和测试 rust 项目时将运行的任务集。
  • watch-flow - 监视任何文件更改,如果检测到更改,它将调用测试流程。
  • ci-flow - 应用于 CI 构建(如 travis/appveyor)中,它以详细级别运行构建和测试。
  • workspace-ci-flow - 应用于 CI 构建(如 travis/appveyor)中的工作区项目。
  • publish-flow - 清理旧的目标目录并发布项目。
  • build-flow - 运行完整的构建、测试、安全检查、依赖项更新验证和文档生成周期。
    此流程可确保您的项目经过全面测试且保持最新。
  • coverage-flow - 从所有单元和集成测试创建覆盖率报告(不支持在Windows上)。默认情况下,cargo-make使用kcov进行代码覆盖率;然而,还定义了其他不支持的实现。
  • codecov-flow - 运行coverage-flow并将覆盖率结果上传到codecov(不支持在Windows上)。

覆盖率

cargo-make内置了对多个覆盖率任务的支持。
通过设置环境变量中的覆盖率提供者名称来在它们之间切换,而无需修改流程

[env]
# can be defined as kcov, tarpaulin, ...
CARGO_MAKE_COVERAGE_PROVIDER = "kcov"

CARGO_MAKE_COVERAGE_PROVIDER 如下所示

[tasks.coverage]
alias = "coverage-some-custom-provider"

如果您有一个自定义覆盖率任务,可以通过更改主覆盖率任务别名将其连接到覆盖率流程

cargo make --list-all-steps | grep "coverage-"

例如

ci-coverage-flow: No Description.
coverage-tarpaulin: Runs coverage using tarpaulin rust crate (linux only)
coverage-flow: Runs the full coverage flow.
coverage-kcov: Installs (if missing) and runs coverage using kcov (not supported on windows)

您可以运行

以查看所有当前支持的提供者。示例输出

cargo make coverage

所有内置覆盖率提供者都由其作者支持,而不是由cargo-make支持。

cargo make --no-workspace workspace-coverage

根据上述说明,要为简单项目生成覆盖率报告,请运行以下命令

为了在工作区项目中运行覆盖率并将所有成员覆盖率报告打包在工作区级别,请运行以下命令

[env]
CARGO_MAKE_KCOV_EXCLUDE_LINE = "unreachable,kcov-ignore"             # your choice of pattern(s)
CARGO_MAKE_KCOV_EXCLUDE_REGION = "kcov-ignore-start:kcov-ignore-end" # your choice of markers

如果您正在使用 kcov,您可以在Makefile.toml中声明以下环境变量以自定义覆盖率任务

[env]
# for example: cargo make filter regex would be cargo_make-[a-z0-9]*$
CARGO_MAKE_TEST_COVERAGE_BINARY_FILTER = "${CARGO_MAKE_CRATE_FS_NAME}-[a-z0-9]*$"

指定要忽略的代码行或代码区域
默认情况下,用于收集覆盖率的二进制文件通过正则表达式进行过滤。如果它不匹配您系统生成的二进制文件,您可以选择以下内容进行覆盖

完整列表

有关grcov支持,请查看以下存储库中的说明

禁用预定义任务/流程

https://github.com/kazuk/cargo-make-coverage-grcov

[config]
skip_core_tasks = true

有关所有预定义任务的全列表,请参阅预定义任务列表(通过 cargo make --list-all-steps生成)

修改预定义任务/流程

要防止加载内部核心任务和流程,只需在您的外部Makefile.toml中添加以下配置属性即可
即使在跳过核心任务的情况下,也会加载一些空任务,以确保cargo-make有一个默认任务定义。

[config.modify_core_tasks]
# if true, all core tasks are set to private (default false)
private = true

# if set to some value, all core tasks are modified to: <namespace>::<name> for example default::build
namespace = "default"

最小版本

您可以修改内部核心任务。
所有修改都定义在 config.modify_core_tasks 部分。

[config]
min_version = "0.37.15"

性能调整

如果您正在使用仅从特定版本才可用的cargo-make功能,您可以确保如果使用较旧的cargo-make版本调用它,构建将失败。
为了指定最小版本,请在配置部分使用 min_version 如下所示

[config]
# Skip loading of all core tasks which saves up a bit on toml parsing and task creation
skip_core_tasks = true
# Skips loading Git related environment variables
skip_git_env_info = true
# Skips loading rust related environment variables
skip_rust_env_info = true
# Skips loading the current crate related environment variables
skip_crate_env_info = true

一些cargo-make功能可以被禁用,这可以提高启动时间。
以下是所有当前功能的列表

当在Rust工作区中运行时,您可以在成员makefiles中禁用一些功能。

命令组(子命令)

例如,如果成员与整个项目位于同一git仓库中,您可以在成员makefiles中添加 skip_git_env_info,它们仍然会从父进程设置环境变量。

对于可以在没有修改输入文件的情况下跳过的任务,请参阅仅当源代码更改时运行任务部分。

您可以通过创建一个顶层任务,该任务将调用其他内部任务来将任务公开为

有两种可能的方法可以做到这一点。

本地任务

  • 使用私有任务(私有不是强制的)更适合简单情况,将一个命令重定向到另一个命令。
  • 这种方法有一些限制

例如,如果您想要具有服务器启动/停止和客户端启动/停止命令,并按以下方式执行它们:

cargo make server start
cargo make server stop
cargo make client start
cargo make client stop

您可以定义两个顶级任务(服务器和客户端),它们将调用内部任务。
示例实现

[tasks.server]
private = false
extend = "subcommand"
env = { "SUBCOMMAND_PREFIX" = "server" }

[tasks.client]
private = false
extend = "subcommand"
env = { "SUBCOMMAND_PREFIX" = "client" }

[tasks.subcommand]
private = true
script = '''
#!@duckscript

cm_run_task ${SUBCOMMAND_PREFIX}_${1}
'''

[tasks.server_start]
private = true
command = "echo"
args = ["starting server..."]

[tasks.server_stop]
private = true
command = "echo"
args = ["stopping server..."]

[tasks.client_start]
private = true
command = "echo"
args = ["starting client..."]

[tasks.client_stop]
private = true
command = "echo"
args = ["stopping client..."]

外部子命令文件

另一种方法是使用不同的配置文件来定义子命令。

这允许在子命令中使用 --list-all-steps,并在子命令文件中设置 [config] 选项。

对于在文件夹中包含子项目的项目,可以为每个子项目创建一个 Makefile.toml 文件,并从主文件夹作为子命令访问。

foo/ 文件夹中具有配置文件的 foo 子命令的示例实现。

[tasks.foo]
description = "Foo subcommands"
category = "Subcommands"
cwd = "foo/"
command = "makers"
args = ["${@}"]

在同一文件夹中具有 Makefile.foo.toml 配置文件的 foo 子命令的示例实现。

[tasks.foo]
description = "Foo subcommands"
category = "Subcommands"
command = "makers"
args = ["--makefile", "Makefile.foo.toml", "${@}"]

差异变更

使用 --diff-steps CLI 命令标志,您可以将正确的覆盖与预构建的内部 makefile 流程进行比较。

示例用法

cargo make --diff-steps --makefile ./examples/override_core.toml post-build
[cargo-make] INFO - cargo make 0.37.15
[cargo-make] INFO - Build File: ./examples/override_core.toml
[cargo-make] INFO - Task: post-build
[cargo-make] INFO - Setting Up Env.
[cargo-make] INFO - Printing diff...
[cargo-make] INFO - Execute Command: "git" "diff" "--no-index" "/tmp/cargo-make/Lz7lFgjj0x.toml" "/tmp/cargo-make/uBpOa9THwD.toml"
diff --git a/tmp/cargo-make/Lz7lFgjj0x.toml b/tmp/cargo-make/uBpOa9THwD.toml
index 5152290..ba0ef1d 100644
--- a/tmp/cargo-make/Lz7lFgjj0x.toml
+++ b/tmp/cargo-make/uBpOa9THwD.toml
@@ -42,7 +42,9 @@
         name: "post-build",
         config: Task {
             clear: None,
-            description: None,
+            description: Some(
+                "Override description"
+            ),
             category: Some(
                 "Build"
             ),
[cargo-make] INFO - Done

需要 Git 可用,因为它用于比较结构并将其输出到控制台,使用标准的 git 颜色方案。

不稳定功能

一些 cargo-make 功能虽然运行良好,但尚未设置为默认行为。
因此,它们通过 unstable_features 属性进行限制。
为了启用此类功能,您需要定义其名称。
例如,xxx 功能可以按以下方式定义:

[config]
unstable_features = ["CTRL_C_HANDLING"]

以下是当前存在的所有不稳定功能的列表

  • CTRL_C_HANDLING - 添加 ctrl-c 处理程序,它将停止当前任务引发的任何正在运行的命令并退出 cargo-make

CLI 选项

以下是运行 cargo-make 时的以下选项:

USAGE:
    [makers | cargo make | cargo-make make] [OPTIONS] [--] [<TASK_CMD>...]

ARGS:
    <TASK_CMD>    The task to execute, potentially including arguments which can be accessed in the task itself.

OPTIONS:
    --help, -h                           Print help information
    --version, -V                        Print version information
    --makefile <FILE>                    The optional toml file containing the tasks definitions
    --task, -t <TASK>                    The task name to execute (can omit the flag if the task name is the last argument) [default: default]
    --profile, -p <PROFILE>              The profile name (will be converted to lower case) [default: development]
    --cwd <DIRECTORY>                    Will set the current working directory. The search for the makefile will be from this directory if defined.
    --no-workspace                       Disable workspace support (tasks are triggered on workspace and not on members)
    --no-on-error                        Disable on error flow even if defined in config sections
    --allow-private                      Allow invocation of private tasks
    --skip-init-end-tasks                If set, init and end tasks are skipped
    --skip-tasks <SKIP_TASK_PATTERNS>    Skip all tasks that match the provided regex (example: pre.*|post.*)
    --env-file <FILE>                    Set environment variables from provided file
    --env, -e <ENV>                      Set environment variables
    --loglevel, -l <LOG LEVEL>           The log level (verbose, info, error, off) [default: info]
    --verbose, -v                        Sets the log level to verbose (shorthand for --loglevel verbose)
    --quiet                              Sets the log level to error (shorthand for --loglevel error)
    --silent                             Sets the log level to off (shorthand for --loglevel off)
    --no-color                           Disables colorful output
    --time-summary                       Print task level time summary at end of flow
    --experimental                       Allows access unsupported experimental predefined tasks.
    --disable-check-for-updates          Disables the update check during startup
    --output-format <OUTPUT FORMAT>      The print/list steps format (some operations do not support all formats) (default, short-description, markdown, markdown-single-page, markdown-sub-section, autocomplete)
    --output-file <OUTPUT_FILE>          The list steps output file name
    --hide-uninteresting                 Hide any minor tasks such as pre/post hooks.
    --print-steps                        Only prints the steps of the build in the order they will be invoked but without invoking them
    --list-all-steps                     Lists all known steps
    --list-category-steps <CATEGORY>     List steps for a given category
    --diff-steps                         Runs diff between custom flow and prebuilt flow (requires git)

插件

插件使用户能够完全控制任务执行。
cargo-make 仍会根据任务及其依赖关系创建执行计划,但会将单个任务执行留给插件代码。

插件基本上是一个包含对任务和流元数据的访问权限的单个 duckscript 代码块,可以调用 cargo-make 特定命令或通用 duckscript 命令。
例如,如果任务定义了一个要执行的命令和参数,而插件只需要调用它们,则可以按照以下方式实现一个简单的插件:

args_string = array_join ${task.args} " " # simple example which doesn't support args that contain spaces in them
exec --fail-on-error ${task.command} %{args_string}

一旦为任务定义了插件,任务执行控制就转移到插件本身。
所有脚本、命令、条件、环境等都将被忽略,应由插件代码本身处理。
所有特定任务环境变量将不会在全局范围内定义(所有 CARGO_MAKE_CURRENT_TASK_ 变量),而是在 json 字符串中的任务环境块中可用。

定义插件

插件在 plugin.impl 前缀下定义,例如

[plugins.impl.command-runner]
script = '''
echo task: ${task.name}

args_string = array_join ${task.args} " " # simple example which doesn't support args that contain spaces in them
exec --fail-on-error ${task.command} %{args_string}
'''

您可以定义所需的任何数量的插件。
还可以提供别名以将新名称映射到现有插件。
例如

[plugins.aliases]
original = "new"
this = "that"

为了使任务将执行控制传递给插件,只需将插件名称放入 plugin 属性中。
例如

[tasks.my-task]
plugin = "my-plugin"
# other attributes as needed...

您可以使用内置的 load scripts 功能创建可重用的插件并加载它们。

插件 SDK

插件 SDK 包含以下内容

  • 通用 Duckscript SDK
  • 元数据变量
    • flow.task.name - 保存触发此任务的流任务(不是当前任务)
    • flow.cli.args - 数组,包含在命令行上提供给 cargo-make 的所有任务参数
    • plugin.impl.name - 当前插件名称(经过别名修改后)
    • task.as_json - 整个任务配置的JSON字符串(可以使用json_parse将其转换为duckscript变量)。
    • task.has_condition - 如果任务有任何条件定义(包括空定义),则为true。
    • task.has_env - 如果任务有任何环境定义(包括空定义),则为true。
    • task.has_install_instructions - 如果任务有安装定义,则为true。
    • task.has_command - 如果任务有命令定义,则为true。
    • task.has_script - 如果任务有脚本定义,则为true。
    • task.has_run_task - 如果任务有run_task定义,则为true。
    • task.has_dependencies - 如果任务有依赖项,则为true。
    • task.has_toolchain_specifier - 如果任务有工具链定义,则为true。
    • task.name - 任务名称
    • task.description - 描述
    • task.category - 类别
    • task.disabled - 根据disabled属性,为true/false。
    • task.private - 根据 private 属性,为true/false。
    • task.deprecated - 根据 deprecated 属性,为true/false。
    • task.workspace - 根据 workspace 属性,为true/false。
    • task.plugin.name - 任务中定义的插件名称(在别名之前)
    • task.watch - 根据 watch 属性,为true/false。
    • task.ignore_errors - 根据 ignore_errors 属性,为true/false。
    • task.cwd - 任务当前工作目录的值
    • task.command - 命令
    • task.args - 所有命令参数的数组
    • task.script_runner - 脚本运行器的值
    • task.script_runner_args - 所有脚本运行器参数的数组
    • task.script_extension - 脚本文件扩展名的值
  • cargo-make任务特定脚本命令
    • cm_run_task [--async] takename - 运行任务及其依赖项。支持异步执行(通过--async标志)。必须获取任务名称以调用。
  • cargo-make插件特定命令
    • cm_plugin_run_task - 运行调用插件的任务(不包括依赖项),包括条件处理、环境、当前工作目录以及cargo-make的所有逻辑。
    • cm_plugin_run_custom_task - 接受一个任务JSON字符串并运行任务定义(不包括依赖项),包括条件处理、环境、当前工作目录以及cargo-make的所有逻辑。
    • cm_plugin_check_task_condition - 如果当前任务条件得到满足,则返回true/false。
    • cm_plugin_force_plugin_set - 将调用当前插件的所有未来任务,无论它们的配置如何。
    • cm_plugin_force_plugin_clear - 取消cm_plugin_force_plugin_set更改,任务将像以前一样运行。

插件示例 - Docker 集成

以下是一个简单的示例,它在一个docker容器中运行任务(以及从该点开始的其余流程)。

[plugins.impl.dockerize]
script = '''
plugin_force_set = get_env PLUGIN_FORCE_SET
plugin_force_set = eq "${plugin_force_set}" 1

if not ${plugin_force_set}
    cm_plugin_force_plugin_set
    set_env PLUGIN_FORCE_SET 1

    dockerfile = set ""
    fn add_docker
        dockerfile = set "${dockerfile}${1}\n"
    end

    taskjson = json_parse ${task.as_json}
    makefile = basename ${taskjson.env.CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE}

    add_docker "FROM debian:stable"
    add_docker "RUN mkdir /workdir/"
    add_docker "RUN mkdir /workdir/project/"
    add_docker "RUN apt-get update"
    add_docker "RUN apt-get install -y curl build-essential libssl-dev pkg-config"
    add_docker "ENV PATH=\"$PATH:$HOME/.cargo/bin\""
    add_docker "RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"
    add_docker "RUN $HOME/.cargo/bin/cargo install cargo-make"
    add_docker "RUN $HOME/.cargo/bin/cargo make --version"
    add_docker "RUN echo \"cd ./workdir/project/ && ls -lsa && $HOME/.cargo/bin/cargo make --makefile ${makefile} --profile ${CARGO_MAKE_PROFILE} ${CARGO_MAKE_TASK}\" > ./run.sh"
    add_docker "RUN chmod 777 ./run.sh"
    add_docker "ADD . /workdir/project/"
    add_docker "CMD [\"sh\", \"./run.sh\"]"

    writefile ./Dockerfile ${dockerfile}
    exec --fail-on-error docker build --tag cmimg:build ./

    exec --fail-on-error docker run cmimg:build
end
'''

[tasks.default]
alias = "docker_flow"

[tasks.docker_flow]
dependencies = ["part1", "part2", "part3"]

[tasks.base-task]
command = "echo"
args = ["task", "${CARGO_MAKE_CURRENT_TASK_NAME}"]

[tasks.part1]
plugin = "dockerize"
extend = "base-task"

[tasks.part2]
extend = "base-task"

[tasks.part3]
extend = "base-task"

运行

cargo make docker_flow

将导致创建一个新的docker容器,它将在其中运行1-3部分。
该示例是有效的。但是,它不支持一些功能,如传递CLI参数等。

插件示例 - 并行运行工作区成员

以下示例展示了如何在工作空间级别的makefile中定义任务以使其能够在并行中调用每个成员。

[plugins.impl.parallel-members]
script = '''
plugin_used = get_env PLUGIN_USED
plugin_used = eq "${plugin_used}" 1

if not ${plugin_used}
    set_env PLUGIN_USED 1
    members = split ${CARGO_MAKE_CRATE_WORKSPACE_MEMBERS} ,

    workspace_dir = pwd
    for member in ${members}
        cd ./${member}
        spawn cargo make --disable-check-for-updates --allow-private --no-on-error ${flow.task.name} %{args}
        cd ${workspace_dir}
    end

    release ${members}
else
    task_definition = json_parse --collection ${task.as_json}
    map_remove ${task_definition} workspace
    task_json = json_encode --collection ${task_definition}
    cm_plugin_run_custom_task ${task_json}
end
'''

[tasks.sometask]
# to make this task serial and not parallel, remove following 2 lines
plugin = "parallel-members"
workspace = false

插件示例 - 从Rust脚本加载环境

以下示例展示了如何使从cargo-make调用的rust脚本更新主cargo-make进程的环境。
它假设任务有脚本行且脚本为rust。它将执行它(为了简单起见,忽略任何rust脚本提供者配置)并将每行输出作为环境键/值对加载。

[plugins.impl.rust-env]
script = '''
# make sure the task has a script
assert ${task.has_script}

taskjson = json_parse ${task.as_json}
script = set ${taskjson.script}
writefile ./target/_tempplugin/main.rs ${script}

out = exec --fail-on-error rust-script ./target/_tempplugin/main.rs

output = trim ${out.stdout}
lines = split ${output} \n
for line in ${lines}
    parts = split ${line} =
    key = array_get ${parts} 0
    value = array_get ${parts} 1
    set_env ${key} ${value}
end
'''

[tasks.default]
alias = "test"

[tasks.test]
dependencies = ["dorust"]
command = "echo"
args = ["${ENV_FROM_RUST1}", "${ENV_FROM_RUST2}"]

[tasks.dorust]
private = true
plugin = "rust-env"
script = '''
fn main() {
    println!("ENV_FROM_RUST1=hello");
    println!("ENV_FROM_RUST2=world");
}
'''

插件示例 - 添加更简单的 Windows PowerShell 支持

在下面的示例中,我们添加了对简单的powershell命令的支持。
此插件将获取现有任务,将其命令设置为powershell并在前面添加-C参数。
此示例还展示了如何在运行时创建新任务并调用它们。

[plugins.impl.powershell]
script = '''
# Adds simpler powershell integration

# make sure we are on windows
windows = is_windows
assert ${windows}

# make sure the task has args
args_empty = array_is_empty ${task.args}
assert_false ${args_empty}

task_definition = json_parse --collection ${task.as_json}

# prepend powershell args to task args
powershell_args = array -C
all_args = array_concat ${powershell_args} ${task.args}
args = map_get ${task_definition} args
release ${args}
map_put ${task_definition} args ${all_args}

# set powershell command
map_put ${task_definition} command pwsh.exe

powershell_task_json = json_encode --collection ${task_definition}

echo Custom Task:\n${powershell_task_json}
cm_plugin_run_custom_task ${powershell_task_json}
'''

[tasks.default]
alias = "test"

[tasks.test]
plugin = "powershell"
args = ["echo hello from windows powershell"]

Shell 完整性

cargo-make 支持Shell自动补全功能,但是为了提供当前目录中可用的确切任务名称,它将运行 --list-all-steps 命令,这可能需要一些时间来完成。

Bash

在您的Shell会话开始时,请在 makers-completion.bash 文件(位于 extra/shell 文件夹中)处运行源代码。这将启用对 makers 可执行文件的自动补全。

zsh

zsh 支持 bash 自动补全。因此,您可以通过运行以下脚本使用现有的 bash 自动补全

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit

# make sure to update the path based on your file system location
source ./extra/shell/makers-completion.bash

它将启用对 makers 可执行文件的自动补全。

Fig / Amazon CodeWhisperer for 命令行

Fig 从 这个PR 开始支持 cargo-make,不需要特殊配置,只需下载 FigAmazon CodeWhisperer for command line 的最新版本即可。

通过运行以下命令来检查是否全局安装了 cargo-make

cargo --list

如果列表中可以看到 make,则 Fig 应该可以工作并自动从 ./Makefile.toml 或您用 --makefile <path> 指定的任何目录加载完成。

全局配置

可以通过位于 cargo-make 目录中的可选全局配置文件 config.toml 来配置一些默认 CLI 值和 cargo-make 的行为。

可以通过 CARGO_MAKE_HOME 环境变量的值来定义 cargo-make 目录的位置。
如果 CARGO_MAKE_HOME 没有被定义,cargo-make 的默认位置是

操作系统 位置
Linux $XDG_CONFIG_HOME 或 $HOME/.config
Windows RoamingAppData
Mac $HOME/Library/Preferences

如果由于任何原因,上述路径对于给定平台无效,则默认为 $HOME/.cargo-make

以下示例 config.toml 展示了所有可能的选项及其默认值

# The default log level if not defined by the `--loglevel` CLI argument
log_level = "info"

# The default configuration whether output coloring is disabled
disable_color = false

# The default task name if no task was provided as part of the cargo-make invocation
default_task_name = "default"

# cargo-make checks for updates during invocation.
# This configuration defines the minimum amount of time which must pass before cargo-make invocations will try to check for updates.
# If the minimum amount of time did not pass, cargo-make will not check for updates (same as --disable-check-for-updates)
# Valid values are: always, daily, weekly, monthly
# If any other value is provided, it will be treated as weekly.
update_check_minimum_interval = "weekly"

# If set to true and cwd was not provided in the command line arguments and the current cwd is not the project root (Cargo.toml not present),
# cargo make will attempt to find the project root by searching the parent directories, until a directory with a Cargo.toml is found.
# cargo make will set the cwd to that directory and will use any Makefile.toml found at that location.
search_project_root = false

Makefile 定义

配置部分

任务

平台覆盖

条件

更多信息可以在 API 文档的 类型 部分找到。

任务命名约定

本节解释了默认任务名称背后的逻辑。
尽管默认名称逻辑可以用作在项目 Makefile.toml 中定义的新任务的约定,但它不是必需的。

默认 makefiles 文件包含几种类型的任务

  • 单个命令或脚本任务(例如 cargo build
  • 在单个命令任务之前或之后运行的任务(钩子)
  • 使用依赖关系定义流程的任务
  • 仅安装某些依赖的任务

单个命令任务根据其命令命名(在大多数情况下),例如运行 cargo build 的任务命名为 build。

[tasks.build]
command = "cargo"
args = ["build"]

这使得可以轻松地理解此任务的作用。

在那些任务之前/之后调用的任务将使用与原始任务相同的方式命名,但带有 pre/post 前缀。
例如,对于 build 任务,默认 toml 还定义了 pre-build 和 post-build 任务。

[tasks.pre-build]

[tasks.post-build]

默认 makefiles 中,所有 pre/post 任务都是空的,并且作为外部 Makefile.toml 的占位符,以便可以轻松地在运行特定任务之前/之后定义自定义功能。

使用流程后缀命名流程。例如,ci-flow

[tasks.ci-flow]
# CI task will run cargo build and cargo test with verbose output
dependencies = [
    "pre-build",
    "build-verbose",
    "post-build",
    "pre-test",
    "test-verbose",
    "post-test"
]

这防止流程任务名称与单个命令任务名称冲突,并快速让用户了解该任务是一个流程定义。

仅安装依赖项而不执行任何命令的任务以 install- 前缀开头,例如

[tasks.install-rust-src]
install_crate = { rustup_component_name = "rust-src" }

错误代码

E001: 检测到环境变量循环

检测到不同环境变量之间的循环;这可能在环境合并期间(在每次加载步骤中)发生。由于重新排序并确保不存在循环引用,因此发出此错误。

您可以通过查看您的 env 配置,并查看在任何点上是否可能发生循环引用来解决此问题。错误消息提到了可能是循环原因的环境变量。

您的最佳选择是尝试通过创建一个新的环境变量或使用静态值多次来打破循环。循环通常是由快速变化的配置、遗忘的未使用环境变量或设计问题引起的,即使没有循环检测或重新排序,这也可能在执行过程中引起隐藏问题,因为 cargo-make 否则需要将实例设置为空值。这样,您可以在它成为意外、隐藏且难以调试的问题之前自行调查和修复它。

注意:脚本有时会导致假阳性。在这种情况下,使用 depends_on 属性,显式告诉 cargo-make 应考虑哪些环境变量作为依赖项,而不是尝试从脚本中猜测。

文章

以下是一些解释 cargo-make 大多数功能的文章列表。

这些文章缺少了一些发布后添加的新功能,例如

等等...

徽章

如果您在项目中使用 cargo-make 并想在项目的 README 或网站上显示它,您可以嵌入 "Built with cargo-make" 徽章。

Built with cargo-make

以下是一些快照

Markdown

[![Built with cargo-make](https://sagiegurari.github.io/cargo-make/assets/badges/cargo-make.svg)](https://sagiegurari.github.io/cargo-make)

HTML

<a href="https://sagiegurari.github.io/cargo-make">
  <img src="https://sagiegurari.github.io/cargo-make/assets/badges/cargo-make.svg" alt="Built with cargo-make">
</a>

路线图

虽然功能丰富,但 cargo-make 仍在积极开发中。
您可以在 github 项目问题 中查看未来开发项列表

编辑器支持

Vim

VSCode

为了调试目的,在 docs/vscode-example 目录中包含一些示例 .vscode 文件

您可能还需要

  • 本地安装的 LLVM(用于 LLDB 调试器)已安装并可在路径上访问
  • VSCode 扩展 - CodeLLDB
  • VSCode 扩展 - "rust-analyser"(不是 "rust" 那个)
  • VSCode 扩展 - "Task Explorer"
  • VSCode 扩展 - "crates"

贡献

请参阅 贡献指南

发布历史

请参阅 变更日志

许可

由 Sagie Gur-Ari 开发并许可为 Apache 2 开源许可证。

依赖关系

~31–45MB
~657K SLoC