mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-20 04:28:43 +00:00
Feature: Impl opt-out options (#510)
Fixed #136 * Impl opt-out optioins in binstalk * Replace field `Options::{gh_crate, quickinstall}_fetcher` with `resolver` which can determine order of resolver used. * Add new field `Args::{disable_}strategies` * Add new variant `BinstallError::InvalidStrategies` * Add variant `BinstallError::NoFallbackToCargoInstall` * Add code for supporting strategies in mod entry * Test `--disable-strategies` in `tests.sh` * Test for `--strategies` in `tests.sh` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
89fa5b1769
commit
9e80cf0700
6 changed files with 141 additions and 11 deletions
27
.github/scripts/tests.sh
vendored
27
.github/scripts/tests.sh
vendored
|
@ -77,16 +77,13 @@ cargo binstall --help >/dev/null
|
||||||
"./$1" binstall --no-confirm cargo-binstall@0.12.0 | grep -q 'cargo-binstall v0.12.0 is already installed'
|
"./$1" binstall --no-confirm cargo-binstall@0.12.0 | grep -q 'cargo-binstall v0.12.0 is already installed'
|
||||||
"./$1" binstall --no-confirm cargo-binstall@^0.12.0 | grep -q -v 'cargo-binstall v0.12.0 is already installed'
|
"./$1" binstall --no-confirm cargo-binstall@^0.12.0 | grep -q -v 'cargo-binstall v0.12.0 is already installed'
|
||||||
|
|
||||||
# to force failure if falling back to source
|
|
||||||
# FIXME: remove/replace once #136 lands
|
|
||||||
export PATH="$test_resources/fake-cargo:$PATH"
|
|
||||||
|
|
||||||
# Test default GitLab pkg-url templates
|
# Test default GitLab pkg-url templates
|
||||||
"./$1" binstall \
|
"./$1" binstall \
|
||||||
--force \
|
--force \
|
||||||
--manifest-path "$test_resources/gitlab-test-Cargo.toml" \
|
--manifest-path "$test_resources/gitlab-test-Cargo.toml" \
|
||||||
--log-level debug \
|
--log-level debug \
|
||||||
--no-confirm \
|
--no-confirm \
|
||||||
|
--disable-strategies compile \
|
||||||
cargo-binstall
|
cargo-binstall
|
||||||
|
|
||||||
# Test default BitBucket pkg-url templates
|
# Test default BitBucket pkg-url templates
|
||||||
|
@ -95,6 +92,7 @@ export PATH="$test_resources/fake-cargo:$PATH"
|
||||||
--manifest-path "$test_resources/bitbucket-test-Cargo.toml" \
|
--manifest-path "$test_resources/bitbucket-test-Cargo.toml" \
|
||||||
--log-level debug \
|
--log-level debug \
|
||||||
--no-confirm \
|
--no-confirm \
|
||||||
|
--disable-strategies compile \
|
||||||
cargo-binstall
|
cargo-binstall
|
||||||
|
|
||||||
# Test default Github pkg-url templates,
|
# Test default Github pkg-url templates,
|
||||||
|
@ -104,4 +102,25 @@ export PATH="$test_resources/fake-cargo:$PATH"
|
||||||
--manifest-path "$test_resources/github-test-Cargo2.toml" \
|
--manifest-path "$test_resources/github-test-Cargo2.toml" \
|
||||||
--log-level debug \
|
--log-level debug \
|
||||||
--no-confirm \
|
--no-confirm \
|
||||||
|
--disable-strategies compile \
|
||||||
cargo-binstall
|
cargo-binstall
|
||||||
|
|
||||||
|
## Test --disable-strategies
|
||||||
|
set +e
|
||||||
|
|
||||||
|
"./$1" binstall --no-confirm --disable-strategies quick-install,compile cargo-update
|
||||||
|
exit_code="$?"
|
||||||
|
|
||||||
|
if [ "$exit_code" != 94 ]; then
|
||||||
|
echo "Expected exit code 94, but actual exit code $exit_code"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
## Test --strategies
|
||||||
|
"./$1" binstall --no-confirm --strategies crate-meta-data cargo-update
|
||||||
|
exit_code="$?"
|
||||||
|
|
||||||
|
if [ "$exit_code" != 94 ]; then
|
||||||
|
echo "Expected exit code 94, but actual exit code $exit_code"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
|
@ -129,6 +129,19 @@ pub struct Args {
|
||||||
#[clap(help_heading = "Overrides", long, default_value_t = RateLimit::default())]
|
#[clap(help_heading = "Overrides", long, default_value_t = RateLimit::default())]
|
||||||
pub rate_limit: RateLimit,
|
pub rate_limit: RateLimit,
|
||||||
|
|
||||||
|
/// Specify the strategies to be used,
|
||||||
|
/// binstall will run the strategies specified in order.
|
||||||
|
///
|
||||||
|
/// Default value is "crate-meta-data,quick-install,compile".
|
||||||
|
#[clap(help_heading = "Overrides", long, value_delimiter(','))]
|
||||||
|
pub strategies: Vec<Strategy>,
|
||||||
|
|
||||||
|
/// Disable the strategies specified.
|
||||||
|
/// If a strategy is specified in `--strategies` and `--disable-strategies`,
|
||||||
|
/// then it will be removed.
|
||||||
|
#[clap(help_heading = "Overrides", long, value_delimiter(','))]
|
||||||
|
pub disable_strategies: Vec<Strategy>,
|
||||||
|
|
||||||
/// Disable symlinking / versioned updates.
|
/// Disable symlinking / versioned updates.
|
||||||
///
|
///
|
||||||
/// By default, Binstall will install a binary named `<name>-<version>` in the install path, and
|
/// By default, Binstall will install a binary named `<name>-<version>` in the install path, and
|
||||||
|
@ -282,6 +295,18 @@ impl Default for RateLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strategy for installing the package
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ValueEnum)]
|
||||||
|
pub enum Strategy {
|
||||||
|
/// Attempt to download official pre-built artifacts using
|
||||||
|
/// information provided in `Cargo.toml`.
|
||||||
|
CrateMetaData,
|
||||||
|
/// Query third-party QuickInstall for the crates.
|
||||||
|
QuickInstall,
|
||||||
|
/// Build the crates from source using `cargo-build`.
|
||||||
|
Compile,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse() -> Result<Args, BinstallError> {
|
pub fn parse() -> Result<Args, BinstallError> {
|
||||||
// Filter extraneous arg when invoked by cargo
|
// Filter extraneous arg when invoked by cargo
|
||||||
// `cargo run -- --help` gives ["target/debug/cargo-binstall", "--help"]
|
// `cargo run -- --help` gives ["target/debug/cargo-binstall", "--help"]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::{fs, path::Path, sync::Arc, time::Duration};
|
use std::{fs, mem, path::Path, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use binstalk::{
|
use binstalk::{
|
||||||
errors::BinstallError,
|
errors::BinstallError,
|
||||||
|
fetchers::{Fetcher, GhCrateMeta, QuickInstall},
|
||||||
get_desired_targets,
|
get_desired_targets,
|
||||||
helpers::{jobserver_client::LazyJobserverClient, remote::Client, tasks::AutoAbortJoinHandle},
|
helpers::{jobserver_client::LazyJobserverClient, remote::Client, tasks::AutoAbortJoinHandle},
|
||||||
manifests::{
|
manifests::{
|
||||||
|
@ -16,9 +17,61 @@ use log::{debug, error, info, warn, LevelFilter};
|
||||||
use miette::{miette, Result, WrapErr};
|
use miette::{miette, Result, WrapErr};
|
||||||
use tokio::task::block_in_place;
|
use tokio::task::block_in_place;
|
||||||
|
|
||||||
use crate::{args::Args, install_path, ui::UIThread};
|
use crate::{
|
||||||
|
args::{Args, Strategy},
|
||||||
|
install_path,
|
||||||
|
ui::UIThread,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn install_crates(mut args: Args, jobserver_client: LazyJobserverClient) -> Result<()> {
|
pub async fn install_crates(mut args: Args, jobserver_client: LazyJobserverClient) -> Result<()> {
|
||||||
|
let mut strategies = vec![];
|
||||||
|
|
||||||
|
// Remove duplicate strategies
|
||||||
|
for strategy in mem::take(&mut args.strategies) {
|
||||||
|
if !strategies.contains(&strategy) {
|
||||||
|
strategies.push(strategy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default strategies if empty
|
||||||
|
if strategies.is_empty() {
|
||||||
|
strategies = vec![
|
||||||
|
Strategy::CrateMetaData,
|
||||||
|
Strategy::QuickInstall,
|
||||||
|
Strategy::Compile,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
let disable_strategies = mem::take(&mut args.disable_strategies);
|
||||||
|
|
||||||
|
let mut strategies: Vec<Strategy> = if !disable_strategies.is_empty() {
|
||||||
|
strategies
|
||||||
|
.into_iter()
|
||||||
|
.filter(|strategy| !disable_strategies.contains(strategy))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
strategies
|
||||||
|
};
|
||||||
|
|
||||||
|
if strategies.is_empty() {
|
||||||
|
return Err(BinstallError::InvalidStrategies(&"No strategy is provided").into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let cargo_install_fallback = *strategies.last().unwrap() == Strategy::Compile;
|
||||||
|
|
||||||
|
if cargo_install_fallback {
|
||||||
|
strategies.pop().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolver: Vec<_> = strategies
|
||||||
|
.into_iter()
|
||||||
|
.map(|strategy| match strategy {
|
||||||
|
Strategy::CrateMetaData => GhCrateMeta::new,
|
||||||
|
Strategy::QuickInstall => QuickInstall::new,
|
||||||
|
Strategy::Compile => unreachable!(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let cli_overrides = PkgOverride {
|
let cli_overrides = PkgOverride {
|
||||||
pkg_url: args.pkg_url.take(),
|
pkg_url: args.pkg_url.take(),
|
||||||
pkg_fmt: args.pkg_fmt.take(),
|
pkg_fmt: args.pkg_fmt.take(),
|
||||||
|
@ -138,6 +191,7 @@ pub async fn install_crates(mut args: Args, jobserver_client: LazyJobserverClien
|
||||||
cli_overrides,
|
cli_overrides,
|
||||||
desired_targets,
|
desired_targets,
|
||||||
quiet: args.log_level == LevelFilter::Off,
|
quiet: args.log_level == LevelFilter::Off,
|
||||||
|
resolver,
|
||||||
});
|
});
|
||||||
|
|
||||||
let tasks: Vec<_> = if !args.dry_run && !args.no_confirm {
|
let tasks: Vec<_> = if !args.dry_run && !args.no_confirm {
|
||||||
|
@ -208,7 +262,13 @@ pub async fn install_crates(mut args: Args, jobserver_client: LazyJobserverClien
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
if !cargo_install_fallback
|
||||||
|
&& matches!(resolution, Resolution::InstallFromSource { .. })
|
||||||
|
{
|
||||||
|
Err(BinstallError::NoFallbackToCargoInstall)
|
||||||
|
} else {
|
||||||
ops::install::install(resolution, opts, jobserver_client).await
|
ops::install::install(resolution, opts, jobserver_client).await
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -310,6 +310,22 @@ pub enum BinstallError {
|
||||||
#[diagnostic(severity(error), code(binstall::SourceFilePath))]
|
#[diagnostic(severity(error), code(binstall::SourceFilePath))]
|
||||||
EmptySourceFilePath,
|
EmptySourceFilePath,
|
||||||
|
|
||||||
|
/// Invalid strategies configured.
|
||||||
|
///
|
||||||
|
/// - Code: `binstall::strategies`
|
||||||
|
/// - Exit: 93
|
||||||
|
#[error("Invalid strategies configured: {0}")]
|
||||||
|
#[diagnostic(severity(error), code(binstall::strategies))]
|
||||||
|
InvalidStrategies(&'static &'static str),
|
||||||
|
|
||||||
|
/// Fallback to `cargo-install` is disabled.
|
||||||
|
///
|
||||||
|
/// - Code: `binstall::no_fallback_to_cargo_install`
|
||||||
|
/// - Exit: 94
|
||||||
|
#[error("Fallback to cargo-install is disabled")]
|
||||||
|
#[diagnostic(severity(error), code(binstall::no_fallback_to_cargo_install))]
|
||||||
|
NoFallbackToCargoInstall,
|
||||||
|
|
||||||
/// A wrapped error providing the context of which crate the error is about.
|
/// A wrapped error providing the context of which crate the error is about.
|
||||||
#[error("for crate {crate_name}")]
|
#[error("for crate {crate_name}")]
|
||||||
CrateContext {
|
CrateContext {
|
||||||
|
@ -348,6 +364,8 @@ impl BinstallError {
|
||||||
DuplicateSourceFilePath { .. } => 90,
|
DuplicateSourceFilePath { .. } => 90,
|
||||||
InvalidSourceFilePath { .. } => 91,
|
InvalidSourceFilePath { .. } => 91,
|
||||||
EmptySourceFilePath => 92,
|
EmptySourceFilePath => 92,
|
||||||
|
InvalidStrategies(..) => 93,
|
||||||
|
NoFallbackToCargoInstall => 94,
|
||||||
CrateContext { error, .. } => error.exit_number(),
|
CrateContext { error, .. } => error.exit_number(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
//! Concrete Binstall operations.
|
//! Concrete Binstall operations.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
|
||||||
use crate::{manifests::cargo_toml_binstall::PkgOverride, DesiredTargets};
|
use crate::{
|
||||||
|
fetchers::{Data, Fetcher},
|
||||||
|
helpers::remote::Client,
|
||||||
|
manifests::cargo_toml_binstall::PkgOverride,
|
||||||
|
DesiredTargets,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod install;
|
pub mod install;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
|
|
||||||
|
pub type Resolver = fn(&Client, &Arc<Data>) -> Arc<dyn Fetcher>;
|
||||||
|
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub no_symlinks: bool,
|
pub no_symlinks: bool,
|
||||||
pub dry_run: bool,
|
pub dry_run: bool,
|
||||||
|
@ -18,4 +25,5 @@ pub struct Options {
|
||||||
pub cli_overrides: PkgOverride,
|
pub cli_overrides: PkgOverride,
|
||||||
pub desired_targets: DesiredTargets,
|
pub desired_targets: DesiredTargets,
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
|
pub resolver: Vec<Resolver>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
bins,
|
bins,
|
||||||
drivers::fetch_crate_cratesio,
|
drivers::fetch_crate_cratesio,
|
||||||
errors::BinstallError,
|
errors::BinstallError,
|
||||||
fetchers::{Data, Fetcher, GhCrateMeta, QuickInstall},
|
fetchers::{Data, Fetcher},
|
||||||
helpers::{remote::Client, tasks::AutoAbortJoinHandle},
|
helpers::{remote::Client, tasks::AutoAbortJoinHandle},
|
||||||
manifests::cargo_toml_binstall::{Meta, PkgMeta},
|
manifests::cargo_toml_binstall::{Meta, PkgMeta},
|
||||||
};
|
};
|
||||||
|
@ -211,7 +211,7 @@ async fn resolve_inner(
|
||||||
meta: target_meta,
|
meta: target_meta,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.cartesian_product([GhCrateMeta::new, QuickInstall::new])
|
.cartesian_product(&opts.resolver)
|
||||||
.map(|(fetcher_data, f)| {
|
.map(|(fetcher_data, f)| {
|
||||||
let fetcher = f(&client, &fetcher_data);
|
let fetcher = f(&client, &fetcher_data);
|
||||||
(
|
(
|
||||||
|
|
Loading…
Add table
Reference in a new issue