Skip to content

Commit

Permalink
chore: Merge branch 'lib-support'
Browse files Browse the repository at this point in the history
  • Loading branch information
Dustin Blackman committed Jan 1, 2024
2 parents 4c5c49a + fd60a88 commit c21ce48
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 61 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/target
/.bin
/.tmp
.gha/
*.profraw
lcov.info
17 changes: 15 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ description = "Build, cache, and run binaries scoped in Cargo.toml rather than i
[[bin]]
name = "cargo-bin"
path = "src/main.rs"
required-features = ["cli"]

[features]
default = ["cli"]
cli = ["dep:clap", "dep:owo-colors"]

[dependencies]
anyhow = "=1.0.40"
cfg-if = "=1.0.0"
clap = "=4.3.19"
owo-colors = "=3.5.0"
clap = { version = "=4.3.19", optional = true }
owo-colors = { version = "=3.5.0", optional = true }
serde = { version = "=1.0.149", features = ["derive"] }
toml = "=0.5.9"
toml_edit = "=0.19.14"
Expand All @@ -47,6 +52,10 @@ git-cliff = { version = "1.3.1" }
# Just added for testing
dustinblackman-hello-world = { version = "0.2.1", git = "https://github.com/dustinblackman/rust-hello-world", bins = ["hello-world-first", "hello-world-second"] }

[package.metadata.docs.rs]
all-features = false
features = []

[package.metadata.gha]
targets = ["aarch64-apple-darwin"]

Expand Down Expand Up @@ -110,19 +119,23 @@ release = '''set -e
'''

test-coverage = '''set -e
rm -rf .tmp
cargo build
cargo llvm-cov nextest --ignore-filename-regex='_test.rs'
'''
test-coverage-html = '''set -e
rm -rf .tmp
cargo build
cargo llvm-cov nextest --open --ignore-filename-regex='_test.rs'
'''
test-coverage-lcov = '''set -e
rm -rf .tmp
cargo build
rm -f lcov.info
cargo llvm-cov nextest --lcov --output-path lcov.info --ignore-filename-regex='_test.rs'
'''
test = '''set -e
rm -rf .tmp
cargo build
cargo nextest run
'''
Expand Down
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ 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.0", default-features = false }
```

## Usage

`cargo-run-bin` keeps track of the binaries and their versions from within `Cargo.toml` under the `[package.metadata.bin]`.
Expand Down Expand Up @@ -87,6 +94,61 @@ will create aliases for any `cargo-*` crate, allowing you to execute commands su
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.
32 changes: 8 additions & 24 deletions src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use which::which;

use crate::cargo_config;
use crate::metadata;
use crate::shims;

/// INTERNAL: Install binary with cargo install.
pub fn cargo_install(
binary_package: metadata::BinaryPackage,
cache_path: path::PathBuf,
Expand Down Expand Up @@ -68,6 +70,7 @@ pub fn cargo_install(
return Ok(());
}

/// INTERNAL: Install binary with binstall
pub fn binstall(binary_package: metadata::BinaryPackage, cache_path: path::PathBuf) -> Result<()> {
let mut cmd_prefix = process::Command::new("cargo");

Expand Down Expand Up @@ -103,6 +106,7 @@ pub fn binstall(binary_package: metadata::BinaryPackage, cache_path: path::PathB
return Ok(());
}

/// Install the provided binary package if it has not been built already.
pub fn install(binary_package: metadata::BinaryPackage) -> Result<String> {
let mut rust_version = "unknown".to_string();
if let Some(res) = rustc::triple() {
Expand Down Expand Up @@ -153,6 +157,8 @@ pub fn install(binary_package: metadata::BinaryPackage) -> Result<String> {
return Ok(cache_bin_path.to_str().unwrap().to_string());
}

/// Executes provided binary and arguments, adding shims to PATH so any
/// other run-bin configured binaries are available.
pub fn run(bin_path: String, args: Vec<String>) -> Result<()> {
// Silly hack to make cargo commands parse arguments correctly.
let mut final_args = args.clone();
Expand All @@ -169,30 +175,8 @@ pub fn run(bin_path: String, args: Vec<String>) -> Result<()> {
final_args.append(&mut args.clone());
}

let mut system_shell_paths = env::var("PATH")
.unwrap_or("".to_string())
.split(':')
.map(|e| return e.to_string())
.collect::<Vec<String>>();

let project_root = metadata::get_project_root()?;
let mut shell_paths = vec![];

let runbin = project_root
.join(".bin/.shims")
.to_string_lossy()
.to_string();
if !system_shell_paths.contains(&runbin) {
shell_paths.push(runbin);
}

// https://github.com/dustinblackman/cargo-gha
let gha = project_root.join(".gha/.shims");
if gha.exists() && !system_shell_paths.contains(&gha.to_string_lossy().to_string()) {
shell_paths.push(gha.to_string_lossy().to_string());
}

shell_paths.append(&mut system_shell_paths);
let mut shell_paths = shims::get_shim_paths()?;
shell_paths.push(env::var("PATH").unwrap_or("".to_string()));

let spawn = process::Command::new(bin_path.clone())
.stdout(process::Stdio::inherit())
Expand Down
2 changes: 2 additions & 0 deletions src/cargo_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use toml_edit::Document;

use crate::metadata;

/// Updates alias' in .cargo/config.toml with all configured cargo extensions.
pub fn sync_aliases() -> Result<()> {
let mut toml_str = "".to_string();
let config_path = metadata::get_project_root()?.join(".cargo/config.toml");
Expand Down Expand Up @@ -57,6 +58,7 @@ pub fn sync_aliases() -> Result<()> {
return Ok(());
}

/// Verifies in cargo-binstall is available in alias'.
pub fn binstall_alias_exists() -> Result<bool> {
let config_path = metadata::get_project_root()?.join(".cargo/config.toml");
if !config_path.exists() {
Expand Down
71 changes: 71 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,79 @@
//! 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`, 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!
//!
//! ## Usage
//!
//! For command line usage, see the [GitHub repo](https://github.com/dustinblackman/cargo-run-bin).
//!
//! `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(());
//! }
//! ```
#![deny(clippy::implicit_return)]
#![allow(clippy::needless_return)]

pub mod binary;
pub mod cargo_config;
#[cfg(not(doc))]
#[cfg(feature = "cli")]
pub mod cli;
pub mod metadata;
pub mod shims;
1 change: 1 addition & 0 deletions src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ fn get_metadata_binaries() -> Result<MetadataBins> {
return Ok(metadata_res?);
}

/// Returns all configured binary packages set in Cargo.toml.
pub fn get_binary_packages() -> Result<Vec<BinaryPackage>> {
let metadata = get_metadata_binaries()?;

Expand Down
32 changes: 32 additions & 0 deletions src/shims.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(target_family = "unix")]
use std::env;
use std::fs;
use std::io::Write;
Expand Down Expand Up @@ -58,6 +59,8 @@ cargo bin {binary} %*
return Ok(());
}

/// Creates shims in `.bin/shims` for all non cargo extensions configured in
/// Cargo.toml. This directory is added to PATH For all executes of `cargo bin`.
pub fn sync() -> Result<()> {
let bin_dir = metadata::get_project_root()?.join(".bin/.shims");
if !bin_dir.exists() {
Expand Down Expand Up @@ -90,3 +93,32 @@ pub fn sync() -> Result<()> {

return Ok(());
}

/// Return an array of entries that can be added to PATH to provide shims to
/// other configured run-bin packages. Results be empty if entries already exist
/// in PATH.
pub fn get_shim_paths() -> Result<Vec<String>> {
let mut shim_paths = vec![];
let system_shell_paths = env::var("PATH")
.unwrap_or("".to_string())
.split(':')
.map(|e| return e.to_string())
.collect::<Vec<String>>();

let project_root = metadata::get_project_root()?;
let runbin = project_root
.join(".bin/.shims")
.to_string_lossy()
.to_string();

if !system_shell_paths.contains(&runbin) {
shim_paths.push(runbin);
}

let gha = project_root.join(".gha/.shims");
if gha.exists() && !system_shell_paths.contains(&gha.to_string_lossy().to_string()) {
shim_paths.push(gha.to_string_lossy().to_string());
}

return Ok(shim_paths);
}
Loading

0 comments on commit c21ce48

Please sign in to comment.