#script #cargo #script-file #cargo-subcommand #cargo-manifest #filter #command-line

build cargo-script

一个Cargo子命令,旨在让人们快速轻松地运行Rust "脚本",这些脚本可以利用Cargo的包生态系统

11个版本

使用旧的Rust 2015

0.2.8 2017年10月29日
0.2.7 2017年9月17日
0.2.3 2017年8月27日
0.2.0 2017年7月27日
0.1.3 2015年10月21日

#182 in 构建工具

Download history 85/week @ 2024-03-13 70/week @ 2024-03-20 75/week @ 2024-03-27 79/week @ 2024-04-03 88/week @ 2024-04-10 63/week @ 2024-04-17 76/week @ 2024-04-24 116/week @ 2024-05-01 60/week @ 2024-05-08 121/week @ 2024-05-15 101/week @ 2024-05-22 109/week @ 2024-05-29 118/week @ 2024-06-05 120/week @ 2024-06-12 94/week @ 2024-06-19 96/week @ 2024-06-26

每月446次下载

MIT/Apache

150KB
3K SLoC

cargo-script

cargo-script 是一个Cargo子命令,旨在让人们快速轻松地运行Rust "脚本",这些脚本可以利用Cargo的包生态系统。它还可以评估表达式和运行过滤器。

一些 cargo-script 的特性包括

  • 读取嵌入在Rust脚本中的Cargo清单。
  • 缓存编译后的工件(包括依赖项)以减少构建时间。
  • 通过UNIX hashbangs和Windows文件关联支持可执行Rust脚本。
  • 在命令行中评估表达式。
  • 使用表达式作为流过滤器(即用于命令管道)。
  • 从脚本中运行单元测试和基准测试。
  • 为命令行表达式和过滤器自定义模板。

注意:当Cargo被指示使用与默认宿主架构不同的目标架构时,cargo-script 无法 工作。

目录

安装

安装 cargo-script 的推荐方法是使用Cargo的 install 子命令

cargo install cargo-script

如果您已经安装了 cargo-script,您可以使用以下命令更新到最新版本:

cargo install --force cargo-script

从旧版本迁移

cargo-script 支持从旧版本迁移数据。这不是强制性的,但可能更受欢迎。使用 cargo script --migrate-data dry-run 进行“干运行”,通知您任何适用的迁移。使用 for-real 选项将实际执行迁移。以下迁移可能适用

  • 0.1 → 0.2:在非Windows平台上,并且当定义了 CARGO_HOME 时,将缓存数据的存储位置从 $CARGO_HOME/.cargo 移动到 $CARGO_HOME

Cargo 功能

以下功能已定义

  • suppress-cargo-output(默认):如果构建脚本少于2秒并且成功,cargo-script 将抑制Cargo的输出。请注意,这将在Windows上禁用彩色Cargo输出。

手动编译和安装

cargo-script 需要 Rust 1.11 或更高版本进行构建。在版本0.2之前支持Rust 1.4+。

构建完成后,您应该将生成的可执行文件放在您的 PATH 上的某个位置。到那时,您应该能够通过使用 cargo script 来调用它。请注意,您可以直接运行可执行文件,但第一个参数必须为 script

如果您想从UNIX的hashbang或Windows的文件关联中运行 cargo script,则还应在 PATH 上安装 run-cargo-script 程序。

自执行脚本

在UNIX系统上,您可以使用 #!/usr/bin/env run-cargo-script 作为Rust脚本中的hashbang行。如果脚本文件是可执行的,这将允许您直接执行脚本文件。

如果您使用的是Windows,则可以将 .crs 扩展名(它只是重命名的 .rs 文件)与 run-cargo-script 相关联。这样,您就可以像其他可执行文件或脚本一样执行Rust脚本。

这可以使用 cargo-script file-association 命令完成(注意 cargo-script 中的连字符)。此命令还可以删除文件关联。如果您将 --amend-pathext 传递给 file-assocation install 命令,则还可以允许您在不指定文件扩展名的情况下执行 .crs 脚本,就像 .exe.bat 文件一样使用。

如果您想跨平台使用脚本,建议您同时使用hashbang行并为文件提供 .crs 文件扩展名。

用法

通常,您会想通过以下方式调用cargo-scriptcargo script(注意没有连字符)。这样做与使用cargo-script script相同。cargo-script支持其他几个子命令,可以通过直接运行cargo-script来访问。您还可以使用--help标志来获取可用选项的概述。

脚本

cargo-script的主要用途是运行Rust源文件作为脚本。例如

$ echo 'fn main() { println!("Hello, World!"); }' > hello.rs
$ cargo script hello.rs
Hello, World!
$ cargo script hello # you can leave off the file extension
Hello, World!

Cargo的输出将不会显示,除非编译失败,或者需要几秒钟以上。

cargo-script还会在脚本中查找嵌入式依赖项和清单信息。例如,以下所有内容都是等效的

  • now.crs(代码块清单,包含UNIX hashbang和.crs扩展名)

    #!/usr/bin/env run-cargo-script
    //! This is a regular crate doc comment, but it also contains a partial
    //! Cargo manifest.  Note the use of a *fenced* code block, and the
    //! `cargo` "language".
    //!
    //! ```cargo
    //! [dependencies]
    //! time = "0.1.25"
    //! ```
    extern crate time;
    fn main() {
        println!("{}", time::now().rfc822z());
    }
    
  • now.rs(仅依赖项,简写清单)

    // cargo-deps: time="0.1.25"
    // You can also leave off the version number, in which case, it's assumed
    // to be "*".  Also, the `cargo-deps` comment *must* be a single-line
    // comment, and it *must* be the first thing in the file, after the
    // hashbang.
    extern crate time;
    fn main() {
        println!("{}", time::now().rfc822z());
    }
    

    注意:您可以通过逗号分隔来写入多个依赖项。例如:time="0.1.25", libc="0.2.5"

运行其中任何一个,cargo-script将生成一个Cargo包,构建它,并运行结果。输出可能看起来像这样

$ cargo script now
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling winapi-build v0.1.1
   Compiling winapi v0.2.8
   Compiling libc v0.2.30
   Compiling kernel32-sys v0.2.2
   Compiling time v0.1.38
   Compiling now v0.1.0 (file:///C:/Users/drk/AppData/Local/Cargo/script-cache/file-now-37cb982cd51cc8b1)
    Finished release [optimized] target(s) in 49.7 secs
Sun, 17 Sep 2017 20:38:58 +1000

如果脚本没有更改,后续运行可能只需直接运行缓存的可执行文件

$ cargo script now
Sun, 17 Sep 2017 20:39:40 +1000

有用的命令行参数

  • --bench:编译并运行基准测试。需要夜间工具链。
  • --debug:构建调试可执行文件,而不是优化版本。
  • --features <features>:构建和运行时传递的Cargo功能。
  • --force:强制脚本重新构建。如果您想强制使用不同的工具链重新编译,则非常有用。
  • --gen-pkg-only:生成Cargo包,但不会编译或运行它。实际上是将脚本“解包”到Cargo包中。
  • --test:编译并运行测试。

表达式

cargo-script还可以直接从命令行运行Rust代码片段。这是通过提供--expr选项来完成的;这将导致cargo-script<script>参数作为源代码而不是作为文件路径来解释。例如,可以通过多种方式从命令行执行代码

  • cargoscript --deptime --expr "extern crate time; time::now().rfc822z().to_string()"
  • cargo script --dep time=0.1.38 --expr "extern crate time; ..." - 使用特定的time版本
  • cargo script -d time -e "extern crate time; ..." - 上面的简写形式
  • cargo script -D time -e "..." - 猜测并注入 extern crate time;仅在依赖项的包和crate名称匹配时才有效。
  • cargo script -d time -x time -e "..." - 注入 extern crate time;当名称不匹配时有效。

给出的代码被嵌入到表达式块中,使用 Debug 格式化程序(即 {:?})评估和打印出来。

有用的命令行参数

  • -d/--dep:将依赖项添加到生成的 Cargo.toml 清单中。
  • -x/--extern:将 extern crate 注入到生成的脚本中。
  • -D/--dep-extern:执行上述两项。
  • -t/--template:为此表达式指定一个自定义模板(参见模板部分)。

流过滤器

您可以使用 cargo-script 来编写一个快速的流过滤器,通过指定一个闭包,该闭包将对从 stdin 读取的每一行调用,如下所示

$ cat now.crs | cargo script --loop \
    "let mut n=0; move |l| {n+=1; println!(\"{:>6}: {}\",n,l.trim_right())}"
   Compiling loop v0.1.0 (file:///C:/Users/drk/AppData/Local/Cargo/script-cache/loop-58079283761aab8433b1)
     1: // cargo-deps: time="0.1.25"
     2: extern crate time;
     3: fn main() {
     4:     println!("{}", time::now().rfc822z());
     5: }

您可以使用 --count 标志实现类似的效果,该标志将行号作为闭包的第二个参数传递

$ cat now.crs | cargo script --count --loop \
    "|l,n| println!(\"{:>6}: {}\", n, l.trim_right())"
   Compiling loop v0.1.0 (file:///C:/Users/drk/AppData/Local/Cargo/script-cache/loop-58079283761aab8433b1)
     1: // cargo-deps: time="0.1.25"
     2: extern crate time;
     3: fn main() {
     4:     println!("{}", time::now().rfc822z());
     5: }

注意,与表达式一样,您可以为流过滤器指定自定义模板。

环境变量

cargo-script 为脚本提供的以下环境变量

  • CARGO_SCRIPT_BASE_PATHcargo-script 用来解析相对依赖路径的基础路径。请注意,这不一定与工作目录或脚本编译的目录相同。

  • CARGO_SCRIPT_PKG_NAME:脚本的生成包名称。

  • CARGO_SCRIPT_SAFE_NAME:正在运行的脚本(不带文件扩展名)的文件名。对于脚本,这是从脚本的文件名派生的。对于这些调用,也可能为 "expr""loop"

  • CARGO_SCRIPT_SCRIPT_PATH:正在运行的脚本的绝对路径,假设存在。对于表达式,设置为空字符串。

模板

您可以使用模板来避免重新指定常见的代码和依赖项。您可以通过运行 cargo-script templates list(注意连字符)来查看模板列表,或者通过运行 cargo-script templates show 来显示它们应存储的文件夹。您可以使用 cargo-script templates dump NAME 来转储模板的内容。

模板是Rust源文件,包含两个占位符:用于自动生成的引言的占位符#{prelude}(应放置在模板顶部),以及用于脚本内容的占位符#{script}

例如,一个添加依赖项并导入一些额外符号的最小表达式模板可能是

// cargo-deps: itertools="0.6.2"
#![allow(unused_imports)]
#{prelude}
extern crate itertools;
use std::io::prelude::*;
use std::mem;
use itertools::Itertools;

fn main() {
    let result = {
        #{script}
    };
    println!("{:?}", result);
}

如果将其存储在模板文件夹中为grabbag.rs,您可以通过传递名称grabbag通过--template选项来使用它

$ cargo script -t grabbag -e "mem::size_of::<Box<Read>>()"
16

此外,还有三个内置模板:exprlooploop-count。它们用于--expr--loop--loop --count调用形式。它们可以通过将具有相同名称的模板放置在模板文件夹中来覆盖。如果您没有覆盖它们,可以使用上述templates dump命令来转储这些内置模板的内容。

已知问题

问题 #50

在Windows上存在一个问题,即当cargo-script询问Cargo获取一个包编译可执行文件的路径时,cargo-script可能会挂起。当前,cargo-script通过使用较旧的启发式方法猜测此路径来解决这个问题。然而,这可能导致cargo-script无法正确定位编译后的可执行文件。

如果这是一个问题,可以通过设置环境变量CARGO_SCRIPT_IGNORE_ISSUE_50为任何非空字符串来指示cargo-script使用准确但存在缺陷的方法。

许可协议

根据您选择的许可

贡献

除非您明确说明,否则您提交的任何有意包含在您的工作中的贡献都应根据上述条款双许可,不附加任何额外条款或条件。

依赖项

~7.5MB
~137K SLoC