diff --git a/crates/bin/src/entry.rs b/crates/bin/src/entry.rs index ce165483..337ae8de 100644 --- a/crates/bin/src/entry.rs +++ b/crates/bin/src/entry.rs @@ -157,7 +157,10 @@ pub fn install_crates( desired_targets, resolvers, cargo_install_fallback, - bins: args.bin, + bins: args.bin.map(|mut bins| { + bins.sort(); + 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 f9eb0827..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::{ @@ -44,6 +45,8 @@ pub struct Options { pub desired_targets: DesiredTargets, pub resolvers: Vec, pub cargo_install_fallback: bool, + + /// If provided, the names are sorted. pub bins: Option>, pub temp_dir: PathBuf, diff --git a/crates/binstalk/src/ops/resolve/resolution.rs b/crates/binstalk/src/ops/resolve/resolution.rs index e8b07784..8770133f 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,19 +88,27 @@ impl ResolutionFetch { current_version: self.new_version, source: self.source, target: self.fetcher.target().to_compact_string(), - bins: opts - .bins - .as_ref() - .map(|bins| bins.iter().cloned().map(Into::into).collect()) - .unwrap_or_else(|| { - 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: &[BinFile], + ) -> 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 + .iter() + .map(|bin| bin.base_name.clone()) + .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; @@ -190,6 +199,10 @@ impl ResolutionSource { cmd.arg("--no-track"); } + if let Some(bins) = &opts.bins { + cmd.args(bins.iter().flat_map(|bin| ["--bin", bin.as_ref()])); + } + debug!("Running `{}`", format_cmd(&cmd)); if !opts.dry_run { diff --git a/e2e-tests/specific-binaries.sh b/e2e-tests/specific-binaries.sh index 36e94186..30568a94 100755 --- a/e2e-tests/specific-binaries.sh +++ b/e2e-tests/specific-binaries.sh @@ -8,8 +8,20 @@ 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 (e.g., ripgrep) -"./$1" binstall --no-confirm ripgrep --bin rg +# Install a specific binary, ensuring we don't fallback to source. +"./$1" binstall --no-confirm taplo-cli --bin taplo --disable-strategies compile + +# 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