cargo-xtask is way to add free-form automation to a Rust project, a-la
npm runor bespoke bash scripts.
The two distinguishing features of xtask are:
rustc, it fully bootstraps from them
cargo-xtask is neither an officially recommended workflow, nor a de-facto standard (yet?). It might or might not work for your use case.
cargo-xtask is a polyfill for cargo workflows feature. It is a way to extend stock, stable cargo with custom commands (
xtasks), written in Rust.
This polyfill doesn't need any code, just a particular configuration of a cargo project. This repository serves as a specification of such configuration.
The best way to create an xtask is to do so inside of a Cargo workspace. If you don't have a workspace already, you can create one inside your package by moving the contents into a new directory. Let's say that our package is named "testing." We first move everything into a sub-directory:
$ mkdir testing
then move all of the stuff except your .git directory into the new testing directory:
$ mv src testing $ mv Cargo.toml testing $ mv .gitignore testing $ mv README.md testing
Don't forget anything else your package may have.
Then, add a new package named
$ cargo new --bin xtask
Then, we need to create a
Cargo.tomlfor our workspace:
[workspace] members = [ "testing", "xtask", ]
If you had a workspace previously, you'd add
xtaskto your existing workspace
Then, the alias. This is where the magic happens. Create a
$ mkdir .cargo
and create a file in it named
configwith these contents:
[alias] xtask = "run --package xtask --"
Example directory layout:
/testing .git .cargo/ config Cargo.toml testing/ Cargo.toml .gitignore src/ lib.rs xtask/ Cargo.toml src/ main.rs
xtaskdirectory and the
.cargo/configshould be committed to the version control system.
If you don't want to use a workspace, you can use
run --manifest-path ./xtask/Cargo.toml --for the alias, but this is not recommended.
xtaskbinary should expect at least one positional argument, which is a name of the task to be executed. Tasks are implemented in Rust, and can use arbitrary crates from crates.io. Tasks can execute
cargo(it is advisable to use
CARGOenvironmental variable to get the right
xtaskcrate may or may not be a part of the main workspace. Usually, but not always, the workspace setup is better. If
xtaskis a part of the workspace, you can share dependencies between
xtaskand main crates, and dependencies update process is easier. Additionally, you will be able to use
xtask = "run --package xtask --"as an alias, which works regardless of Cargo's working directory If
xtaskis not a part of the workspace, you can use different feature sets for shared dependencies, and you can cache
xtask/targetmore easily on CI. It is advisable to commit
xtasklockfile to the repository.
It is advisable to minimize the compile time of xtasks.
The current recommendation is to define various task as subcommands of the single
xtaskbinary. An alternative is to use a separate binary and a separate entry in
.cargo/configfor each task.
xtasks do not integrate with Cargo lifecycle. If you need to do custom post-processing after
cargo build, you'll need to define and call
cargo xtask buildtask, which calls
cargo buildinternally. There's no way to intercept stock
It's impossible to use xtasks from dependencies, xtasks are project-local. However, it is possible to share logic for implementing common xtasks as crates.io packages.
xtaskis not a workspace member,
cargo xtaskwill work only from the project's root directory.
cargo xtask task-namecommand to run the task.
cargo xtask deploy
Note that this doesn't require any additional setup besides cloning the repository, and will automatically build the
xtaskbinary on the first run.
xtasks are entirely optional, and you don't have to use them! In particular, if, for your purposes,
cargo testare enough, don't use xtasks. If you prefer to write a short bash script, and don't need to support windows, there's no need to use xtasks either.
The following specifies the names and behaviors of some common xtasks, to help establish common conventions. If you want to tweak behavior of a standard task for your project, you can add custom flags to it. If you feel an important common task is missing, feel free to submit a PR!
cargo xtask --help
When run without argument or with the
xtaskshould print a help message which lists available tasks.
cargo xtask dist
This should package the software and produce a set of distributable artifacts. Artifacts should be placed into
./target/distdirectory. The precise meaning of artifacts is not defined, but, for a CLI tool, you can expect the binary itself (build in release mode and stripped), man pages and shell completion files. The
distcommand should clean the
./target/distdirectory before populating it with artifacts. It is expected that the
cargo build --releaseinternally.
See #3 for additional discussion.
cargo xtask codegen
This command should run code generation, which happens outside of
build.rs. For example, if you are writing a gPRC server, and would like to commit the generated code into the repository (so that the clients don't have to have
protocinstalled), you can implement code generation as
cargo xtask codegen.
cargo xtask ci
This task should run
cargo testand any additional checks that are required on CI, like checking formatting, running
miritest, checking links in the documentation. The CI configuration should generally look like this:
script: - cargo xtask ci
The expectation is that, if
cargo xtask cipasses locally, the CI will be green as well.
You don't need this task if
cargo testis enough for your purposes. Moreover, there are certain tradeoffs associated with using xtasks instead of CI provider's built-in ways to specify CI process. So, we do not recommend to blindly use
.travis.yml, but, if you want to use xtasks for CI, use
cias the name of the task.
See #1 for discussion.
Libraries: - devx: collection of useful utilities (spawning processes, git pre-commit hooks, etc.) - xshell: ergonomic "bash" scripting in Rust - duct: a library for running child processes with support for pipelines and IO redirection
If you write tools or libraries for xtasks, send a PR to this document. Some possible ideas:
To my knowledge, the idea of xtasks was first introduced in this post. In some sense, the present document just specifies some conventions around original idea.
xtaskis chosen so as not to conflict with potential future built-in cargo feature for tasks.