From 8d2b46b8bd2a09c061f57705a4fafcd60c505559 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Tue, 10 Jun 2025 04:17:48 -0700 Subject: [PATCH] Add a `--bin` argument to mirror `cargo install --bin`. (#2189) * Add a --bin argument to mirror cargo install --bin. * Update crates/bin/src/args.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Update crates/binstalk/src/ops.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Address feedback, make e2e-test test both source/non-source. * Update crates/bin/src/entry.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Update crates/binstalk/src/ops/resolve/resolution.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Update crates/binstalk/src/ops/resolve/resolution.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Update crates/binstalk/src/ops/resolve/resolution.rs Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Signed-off-by: Matan Lurey * Get everything compiling again. * optimize ResolutionFetch::resolve_bins Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> * fix e2e-test on unix due to ordering Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> * fix specific-binaries.sh: relax no-compile Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> --------- Signed-off-by: Matan Lurey Signed-off-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> --- crates/bin/src/args.rs | 14 ++++++++ crates/bin/src/entry.rs | 4 +++ crates/binstalk/src/ops.rs | 4 +++ crates/binstalk/src/ops/resolve/resolution.rs | 30 ++++++++++++++--- e2e-tests/specific-binaries.sh | 33 +++++++++++++++++++ justfile | 4 ++- 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100755 e2e-tests/specific-binaries.sh diff --git a/crates/bin/src/args.rs b/crates/bin/src/args.rs index b993ed72..055e1e4e 100644 --- a/crates/bin/src/args.rs +++ b/crates/bin/src/args.rs @@ -93,6 +93,20 @@ pub struct Args { )] pub(crate) targets: Option>, + /// Install only the specified binaries. + /// + /// This mirrors the equivalent argument in `cargo install --bin`. + /// + /// If omitted, all binaries are installed. + #[clap( + help_heading = "Package selection", + long, + value_name = "BINARY", + num_args = 1.., + action = clap::ArgAction::Append + )] + pub(crate) bin: Option>, + /// Override Cargo.toml package manifest path. /// /// This skips searching crates.io for a manifest and uses the specified path directly, useful diff --git a/crates/bin/src/entry.rs b/crates/bin/src/entry.rs index 9df479f4..4c4865e4 100644 --- a/crates/bin/src/entry.rs +++ b/crates/bin/src/entry.rs @@ -157,6 +157,10 @@ pub fn install_crates( desired_targets, resolvers, cargo_install_fallback, + bins: args.bin.map(|mut bins| { + bins.sort_unstable(); + bins + }), temp_dir: temp_dir.path().to_owned(), install_path, diff --git a/crates/binstalk/src/ops.rs b/crates/binstalk/src/ops.rs index 8051daaa..88d38fa2 100644 --- a/crates/binstalk/src/ops.rs +++ b/crates/binstalk/src/ops.rs @@ -2,6 +2,7 @@ use std::{path::PathBuf, sync::Arc, time::Duration}; +use compact_str::CompactString; use semver::VersionReq; use crate::{ @@ -45,6 +46,9 @@ pub struct Options { pub resolvers: Vec, pub cargo_install_fallback: bool, + /// If provided, the names are sorted. + pub bins: Option>, + pub temp_dir: PathBuf, pub install_path: PathBuf, pub cargo_root: Option, diff --git a/crates/binstalk/src/ops/resolve/resolution.rs b/crates/binstalk/src/ops/resolve/resolution.rs index 75d4f398..0e53dbc9 100644 --- a/crates/binstalk/src/ops/resolve/resolution.rs +++ b/crates/binstalk/src/ops/resolve/resolution.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, env, ffi::OsStr, fmt, iter, path::Path, sync::Arc}; +use binstalk_bins::BinFile; use command_group::AsyncCommandGroup; use compact_str::{CompactString, ToCompactString}; use either::Either; @@ -87,14 +88,27 @@ impl ResolutionFetch { current_version: self.new_version, source: self.source, target: self.fetcher.target().to_compact_string(), - bins: self - .bin_files - .into_iter() - .map(|bin| bin.base_name) - .collect(), + bins: Self::resolve_bins(&opts.bins, self.bin_files), }) } + fn resolve_bins( + user_specified_bins: &Option>, + crate_bin_files: Vec, + ) -> Vec { + // We need to filter crate_bin_files by user_specified_bins in case the prebuilt doesn't + // have featured-gated (optional) binary (gated behind feature). + crate_bin_files + .into_iter() + .map(|bin| bin.base_name) + .filter(|bin_name| { + user_specified_bins + .as_ref() + .map_or(true, |bins| bins.binary_search(bin_name).is_ok()) + }) + .collect() + } + pub fn print(&self, opts: &Options) { let fetcher = &self.fetcher; let bin_files = &self.bin_files; @@ -185,6 +199,12 @@ impl ResolutionSource { cmd.arg("--no-track"); } + if let Some(bins) = &opts.bins { + for bin in bins { + cmd.arg("--bin").arg(bin); + } + } + debug!("Running `{}`", format_cmd(&cmd)); if !opts.dry_run { diff --git a/e2e-tests/specific-binaries.sh b/e2e-tests/specific-binaries.sh new file mode 100755 index 00000000..bc3d92c8 --- /dev/null +++ b/e2e-tests/specific-binaries.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -euxo pipefail + +unset CARGO_INSTALL_ROOT + +CARGO_HOME=$(mktemp -d 2>/dev/null || mktemp -d -t 'cargo-home') +export CARGO_HOME +export PATH="$CARGO_HOME/bin:$PATH" + +# Install a specific binary, ensuring we don't fallback to source. +"./$1" binstall --no-confirm taplo-cli --bin taplo + +# Verify that the binary was installed and is executable +if ! command -v taplo >/dev/null 2>&1; then + echo "taplo was not installed" + exit 1 +fi + +# Run the binary to check it works +taplo --version + +# Install a specific binary, but always compile from source. +"./$1" binstall --no-confirm ripgrep --bin rg --strategies compile + +# Verify that the binary was installed and is executable +if ! command -v rg >/dev/null 2>&1; then + echo "rg was not installed" + exit 1 +fi + +# Run the binary to check it works +rg --version diff --git a/justfile b/justfile index e9cb9f53..b63c682c 100644 --- a/justfile +++ b/justfile @@ -224,6 +224,7 @@ e2e-test-signing: (e2e-test "signing") e2e-test-continue-on-failure: (e2e-test "continue-on-failure") e2e-test-private-github-repo: (e2e-test "private-github-repo") e2e-test-self-install: (e2e-test "self-install") +e2e-test-specific-binaries: (e2e-test "specific-binaries") # WinTLS (Windows in CI) does not have TLS 1.3 support [windows] @@ -232,7 +233,8 @@ e2e-test-tls: (e2e-test "tls" "1.2") [macos] e2e-test-tls: (e2e-test "tls" "1.2") (e2e-test "tls" "1.3") -e2e-tests: e2e-test-live e2e-test-manifest-path e2e-test-git e2e-test-other-repos e2e-test-strategies e2e-test-version-syntax e2e-test-upgrade e2e-test-tls e2e-test-self-upgrade-no-symlink e2e-test-uninstall e2e-test-subcrate e2e-test-no-track e2e-test-registries e2e-test-signing e2e-test-continue-on-failure e2e-test-private-github-repo e2e-test-self-install +# e2e-test-self-install needs to be the last task to run, as it would consume the cargo-binstall binary +e2e-tests: e2e-test-live e2e-test-manifest-path e2e-test-git e2e-test-other-repos e2e-test-strategies e2e-test-version-syntax e2e-test-upgrade e2e-test-tls e2e-test-self-upgrade-no-symlink e2e-test-uninstall e2e-test-subcrate e2e-test-no-track e2e-test-registries e2e-test-signing e2e-test-continue-on-failure e2e-test-private-github-repo e2e-test-specific-binaries e2e-test-self-install unit-tests: print-env cargo test --no-run --target {{target}}