Build and run
Recipe | Crates | Categories |
---|---|---|
cargo make | ||
Use devx | ||
Write cross-platform bash -like scripts in Rust with xshell |
cargo make
[
][cat-development-tools::testing]
cargo make
is a Rust task runner and build tool. The cargo-make
⮳ task runner enables to define and configure sets of tasks and run them as a flow. A task is a command, script, rust code, or other sub tasks to execute. Tasks can have dependencies which are also tasks that will be executed before the task itself.
With a simple toml based configuration file, you can define a multi platform build script that can run build, test, generate documentation, run bench tests, run security validations and more, executed by running a single command.
Install with
cargo install --force cargo-make
cargo make --version
automating-your-rust-workflows-with-cargo-make⮳.
cargo xtask
cargo-xtask⮳ adds free-form automation to a Rust project, a-la make
, npm run
or bespoke bash scripts.
The two distinguishing features of xtask
⮳ are the following:
- It doesn't require any other binaries besides
cargo
⮳ andrustc
⮳, it fully bootstraps from them. - Unlike
bash
, it can more easily be cross platform, as it doesn't use the shell.
Use devx
devx
⮳ is a collection of utilities for writing your own dev scripts in Rust. The project is inspired by and intended for seamless usage with cargo-xtask
⮳ idioms.
devx-cmd
⮳ provides primitives for spawning child processes that are easier than std::process targeted
when used in development scripts. devx-pre-commit
⮳ creates git pre-commit hooks that enforce good practices.
Write cross-platform bash
-like scripts in Rust with xshell
"xshell
⮳ is a swiss-army knife for writing cross-platform 'bash' scripts in Rust.
It doesn't use the shell directly, but rather re-implements parts of its scripting environment in Rust. The intended use-case is various bits of glue code, which could be written in bash
or python
. The original motivation is xtask
development" (docs.rs).
The following example executes shell commands and interacts with the file system. It showcases:
- Basic command execution,
- Handling command arguments,
- Working directory manipulation,
- Using pipes,
- Checking command status,
- Conditional execution,
- Capturing
stderr
, - Environment variable manipulation,
- Path manipulations,
- File removal.
// ANCHOR: example //! This example demonstrates the usage of the `xshell` crate for shell //! scripting in Rust. //! //! `xshell` provides a convenient way to execute shell commands, manipulate the //! file system, and manage environment variables within a Rust program. use xshell::Shell; use xshell::cmd; fn main() -> anyhow::Result<()> { // Create a new Shell instance. // // This provides the environment for running commands. It maintains a // logical working directory and an environment map. They are // independent from the current process's `std::env::current_dir` and // `std::env::var`, and only affect paths and commands passed to the // `Shell`. let sh = Shell::new()?; // Basic command execution: // The `cmd!` macro provides a convenient syntax // for creating a command (a `Cmd` struct). // `read` runs the command and return its `stdout` as a string. // You can also use `run`. let output = cmd!(sh, "echo Hello, xshell!").read()?; println!("Output: {}", output); // Run a command with arguments: // You don't have to worry about escaping the arguments. let file_paths = ["test.txt"]; let temp_dir = "temp"; cmd!( sh, "echo We will create {file_paths...} in the {temp_dir} directory." ) .run()?; // Note how the so-called splat syntax `...` is used to interpolate an // iterable of arguments. This is a convenient way to pass multiple // or optional arguments to a command. // Working directory manipulation: let current_dir = sh.current_dir(); println!("Current directory: {}", current_dir.display()); // Temporarily changes the working directory of this Shell. // // Returns a RAII guard which reverts the working directory to the old value // when dropped. let guard = sh.push_dir(temp_dir); let cwd = sh.current_dir(); println!("New current directory: {}", cwd.display()); // Write to a file. Paths are relative to the current directory of the // Shell. Creates the file and all intermediate directories // if they don't exist. sh.write_file("test.txt", "Some Content")?; // Conditional execution of a commmand: if cmd!(sh, "test -f test.txt").quiet().run().is_ok() { println!("'test.txt' exists"); } else { println!("'test.txt' does not exist"); } // `quiet()` prevents echoing the command itself to `stderr`. // This is useful when you don't want to see the command in the output. // Path manipulation. let file_path = sh.current_dir().join("text.txt"); println!("File path: {}", file_path.display()); // Check existence of the file. if sh.path_exists(&file_path) { // Read the entire contents of a file into a string. if let Ok(file_content) = sh.read_file(&file_path) { println!("File content: {}", file_content); } // Remove the file. sh.remove_path(file_path)?; } // Reverts the working directory to its old value when the guard is dropped. drop(guard); // Checking command status: let status = cmd!(sh, "true").run(); println!("Command status: {:?}", status); let failed_status = cmd!(sh, "false").run(); println!("Failed command status: {:?}", failed_status); // Capture `stderr` with `read_stderr`: let err_result = cmd!(sh, "cat nonexistent_file").read_stderr(); println!("Standard error: {}", err_result.unwrap_err()); // Environment variables: // `xshell` maintains its own environment map, independent of the system's. sh.set_var("MY_VAR", "my_value"); println!("Set MY_VAR to {}", sh.var("MY_VAR")?); let env_var = cmd!(sh, "echo $MY_VAR").read()?; println!("MY_VAR environment variable: {}", env_var); // Change the working directory permanently: let temp_dir = tempfile::tempdir()?; let temp_path = temp_dir.path(); sh.change_dir(temp_path); Ok(()) } // ANCHOR_END: example #[test] fn test() -> anyhow::Result<()> { main()?; Ok(()) } // TODO echo $MY_VAR does not work?
Related Topics
Topic | Rust Crates |
---|---|
General Build Tools | cargo build (built-in) compiles your project. cargo check checks your code for errors without compiling. |
Cross-Compilation | cross ⮳ simplifies cross-compilation. |
Packaging, Distribution | cargo-deb ⮳ creates Debian packages. cargo-rpm ⮳ creates RPM packages. create-dmg creates macOS disk images. |
Build Script Helpers | cc ⮳ helps with compiling C/C++ code in build scripts. pkg-config ⮳ finds system libraries. |
Code Generation | Use build scripts. |
Link-Time Optimization (LTO) Configuration | Configured in Cargo.toml |
Incremental Compilation Management | Handled by cargo directly. |