cargo-run-bin
![cargo-run-bin](.github/banner.png)
[![Build status](https://github.com/dustinblackman/cargo-run-bin/workflows/ci/badge.svg)](https://github.com/dustinblackman/cargo-run-bin/actions)
[![Coverage Status](https://coveralls.io/repos/github/dustinblackman/cargo-run-bin/badge.svg?branch=master)](https://coveralls.io/github/dustinblackman/cargo-run-bin?branch=master)
[![Crates.io](https://img.shields.io/crates/v/cargo-run-bin.svg)](https://crates.io/crates/cargo-run-bin)
> Build, cache, and run CLI tools scoped in `Cargo.toml` rather than installing globally. Stop the version drifts across your team, keep it all in sync within your project!
- [Overview](#overview)
- [Install](#install)
- [Usage](#usage)
- [cargo bin CRATE](#cargo-bin-crate)
- [cargo bin --sync-aliases](#cargo-bin---sync-aliases)
- [cargo bin --install](#cargo-bin---install)
- [Library](#library)
- [License](#license)
## Overview
Installing tooling globally when working in teams or on CI is a silly problem to manage. `cargo-run-bin` builds, caches, and executes binaries from their locked down versions in `Cargo.toml`. This acts similarly to [`npm run`](https://docs.npmjs.com/cli/v7/commands/npm-run-script) and [`gomodrun`](https://github.com/dustinblackman/gomodrun), and allows your teams to always be running the same tooling versions.
For command lines that extend cargo such as `cargo-nextest`, run-bin will create and manage cargo aliases to allow using cargo extensions without any changes to your command line scripts! `cargo-run-bin` gets out of your way, and you'll forget you're even using it!
## Install
Minimum Rust Version: 1.70.0
Run the following to install `cargo-run-bin`, and ignore the cache directory in your project.
```sh
cargo install cargo-run-bin
cd my/rust/project
echo ".bin/" >> .gitignore
```
You can also use it as a library within your existing logic.
```toml
[dependencies]
cargo-run-bin = { version = "1.7.2", default-features = false }
```
### Distro packages
Packaging status
[![Packaging status](https://repology.org/badge/vertical-allrepos/cargo-run-bin.svg)](https://repology.org/project/cargo-run-bin/versions)
If your distribution has packaged `cargo-run-bin`, you can use that package for the installation.
### Arch Linux
You can use [pacman](https://wiki.archlinux.org/title/Pacman) to install from the [extra repository](https://archlinux.org/packages/extra/x86_64/cargo-run-bin/):
```sh
pacman -S cargo-run-bin
```
### Alpine Linux
`cargo-run-bin` is available for [Alpine Edge](https://pkgs.alpinelinux.org/packages?name=cargo-run-bin&branch=edge). It can be installed via [apk](https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper) after enabling the [testing repository](https://wiki.alpinelinux.org/wiki/Repositories).
```sh
apk add cargo-run-bin
```
## Usage
`cargo-run-bin` keeps track of the binaries and their versions from within `Cargo.toml` under the `[package.metadata.bin]`.
table. A quick example taken from this repo:
```toml
[package.metadata.bin]
cargo-binstall = { version = "1.1.2" }
cargo-nextest = { version = "0.9.57", locked = true }
dprint = { version = "0.30.3" }
cargo-mobile2 = { version = "0.5.2", bins = ["cargo-android", "cargo-mobile"], locked = true }
```
Or if you're setting up in a workspace:
```toml
[workspace.metadata.bin]
cargo-binstall = { version = "1.1.2" }
cargo-nextest = { version = "0.9.57", locked = true }
```
| Parameter | Type | Required | Description |
| ---------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| version | `String` | true | Specifies the version of the crate. |
| bins | `Vec` | false | An array of binaries that the crate contains that you wish to build. These can be found in a crates `Cargo.toml` file. See [`cargo-mobile2`](https://github.com/tauri-apps/cargo-mobile2/blob/a5f3783870f48886e3266e43f92a6768fb1eb3d4/Cargo.toml#L18-L28) as an example. |
| locked | `Boolean` | false | A parameter when set to `true` runs `cargo install` with the [`--locked`](https://doc.rust-lang.org/cargo/commands/cargo-install.html#dealing-with-the-lockfile) parameter. |
| features | `Vec` | false | An array of crate features to enable. |
| default-features | `Boolean` | false | When set to `false`, disables all default features. |
| git | String | false | A git URL to install from rather than from crates.io. This will also be used by Binstall to look up Cargo manifist if Binstall is available. |
| branch | String | false | A git branch to install from when `git` is set. This takes priority over `tag` and `rev` |
| tag | String | false | A git tag to install from when `git` is set. `branch` will take priority if set, and takes priority over `rev`. |
| rev | String | false | A git revision to install from when `git` is set. `branch` and `tag` will take priority if set. |
| path | String | false | The path to a local crate to install. |
If you're a fan of prebuilt binaries and fast downloads, run-bin will use [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall) if it's installed globally, or configured within `[package.metadata.bin]`, rather than building tools from source.
### `cargo bin CRATE`
Taking an example of `dprint`, running `cargo bin dprint --help` with install/build and cache the dprint binary with the
specified version in `Cargo.toml`. All future executions will run instantly without an install step, and dprint can be used
as you wish!
### `cargo bin --sync-aliases`
With the power of [cargo aliases](https://doc.rust-lang.org/cargo/reference/config.html#alias), `cargo bin --sync-aliases`
will create aliases for any `cargo-*` crate, allowing you to execute commands such `cargo nextest run` that will use
`cargo bin` under the hood. Check out some of the example from [this repo](.cargo/config.toml).
### `cargo bin --install`
When pulling down a new repo, or adding a step to CI, `cargo bin --install` will install or build all binaries that have not been
cached which are configured in `Cargo.toml`.
### Library
`run-bin` can also be used as a library and paired nicely with your `build.rs` or any other scripts. The following
example demos having `dprint` configured within `[package.metadata.bin]`, and executing `dprint --help`.
```toml
[package.metadata.bin]
dprint = { version = "0.40.2" }
```
```rust
use anyhow::Result;
use cargo_run_bin::{binary, metadata};
fn main() -> Result<()> {
let binary_package = metadata::get_binary_packages()?
.iter()
.find(|e| e.package == "dprint")
.unwrap()
.to_owned();
let bin_path = binary::install(binary_package)?;
binary::run(bin_path, vec!["--help".to_string()])?;
return Ok(());
}
```
Using `binary::run` is optional. You can recreate it and make changes to your liking using `std::process`, with shims included!
```rust
use std::process;
use anyhow::Result;
use cargo_run_bin::{binary, metadata, shims};
fn main() -> Result<()> {
let binary_package = metadata::get_binary_packages()?
.iter()
.find(|e| e.package == "dprint")
.unwrap()
.to_owned();
let bin_path = binary::install(binary_package)?;
let mut shell_paths = shims::get_shim_paths()?;
shell_paths.push(env::var("PATH").unwrap_or("".to_string()));
process::Command::new(bin_path)
.args(["--help"])
.env("PATH", shell_paths.join(":"))
.spawn();
return Ok(());
}
```
## [License](./LICENSE)
MIT.