mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-05-05 11:40:04 +00:00
Properly support multiple targets
This commit is contained in:
parent
fcf5728dde
commit
235bcac300
1 changed files with 90 additions and 44 deletions
130
src/main.rs
130
src/main.rs
|
@ -37,8 +37,23 @@ struct Options {
|
||||||
version: String,
|
version: String,
|
||||||
|
|
||||||
/// Override binary target set. Defaults to a set of targets based on the current platform.
|
/// Override binary target set. Defaults to a set of targets based on the current platform.
|
||||||
#[clap(help_heading = "OVERRIDES", long)]
|
///
|
||||||
target: Option<String>,
|
/// Binstall is able to look for binaries for several targets, installing the first one it finds
|
||||||
|
/// in the order the targets were given. For example, on a 64-bit glibc Linux distribution, the
|
||||||
|
/// default is to look first for a `x86_64-unknown-linux-gnu` binary, then for a
|
||||||
|
/// `x86_64-unknown-linux-musl` binary. However, on a musl system, the gnu version will not be
|
||||||
|
/// considered.
|
||||||
|
///
|
||||||
|
/// This option takes a comma-separated list of target triples, which will be tried in order.
|
||||||
|
///
|
||||||
|
/// If falling back to installing from source, the first target will be used.
|
||||||
|
#[clap(
|
||||||
|
help_heading = "OVERRIDES",
|
||||||
|
alias = "target",
|
||||||
|
long,
|
||||||
|
value_name = "triple"
|
||||||
|
)]
|
||||||
|
targets: Option<String>,
|
||||||
|
|
||||||
/// Override install path for downloaded binary.
|
/// Override install path for downloaded binary.
|
||||||
///
|
///
|
||||||
|
@ -154,7 +169,7 @@ async fn entry() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load options
|
// Load options
|
||||||
let mut opts = Options::parse_from(args.iter());
|
let mut opts = Options::parse_from(args);
|
||||||
let cli_overrides = PkgOverride {
|
let cli_overrides = PkgOverride {
|
||||||
pkg_url: opts.pkg_url.take(),
|
pkg_url: opts.pkg_url.take(),
|
||||||
pkg_fmt: opts.pkg_fmt.take(),
|
pkg_fmt: opts.pkg_fmt.take(),
|
||||||
|
@ -174,6 +189,13 @@ async fn entry() -> Result<()> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Compute install directory
|
||||||
|
let install_path = get_install_path(opts.install_path.as_deref()).ok_or_else(|| {
|
||||||
|
error!("No viable install path found of specified, try `--install-path`");
|
||||||
|
miette!("No install path found or specified")
|
||||||
|
})?;
|
||||||
|
debug!("Using install path: {}", install_path.display());
|
||||||
|
|
||||||
// Create a temporary directory for downloads etc.
|
// Create a temporary directory for downloads etc.
|
||||||
let temp_dir = TempDir::new()
|
let temp_dir = TempDir::new()
|
||||||
.map_err(BinstallError::from)
|
.map_err(BinstallError::from)
|
||||||
|
@ -218,20 +240,58 @@ async fn entry() -> Result<()> {
|
||||||
manifest.bin,
|
manifest.bin,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let desired_targets = {
|
||||||
|
let from_opts = opts
|
||||||
|
.targets
|
||||||
|
.as_ref()
|
||||||
|
.map(|ts| ts.split(',').map(|t| t.to_string()).collect());
|
||||||
|
|
||||||
|
if let Some(ts) = from_opts {
|
||||||
|
ts
|
||||||
|
} else {
|
||||||
|
detect_targets().await
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fetchers = MultiFetcher::default();
|
||||||
|
|
||||||
|
for target in &desired_targets {
|
||||||
|
debug!("Building metadata for target: {target}");
|
||||||
|
let mut target_meta = meta.clone();
|
||||||
|
|
||||||
// Merge any overrides
|
// Merge any overrides
|
||||||
if let Some(o) = meta.overrides.remove(&opts.target) {
|
if let Some(o) = target_meta.overrides.get(target).cloned() {
|
||||||
meta.merge(&o);
|
target_meta.merge(&o);
|
||||||
}
|
}
|
||||||
|
|
||||||
meta.merge(&cli_overrides);
|
target_meta.merge(&cli_overrides);
|
||||||
debug!("Found metadata: {:?}", meta);
|
debug!("Found metadata: {target_meta:?}");
|
||||||
|
|
||||||
// Compute install directory
|
let fetcher_data = Data {
|
||||||
let install_path = get_install_path(opts.install_path.as_deref()).ok_or_else(|| {
|
name: package.name.clone(),
|
||||||
error!("No viable install path found of specified, try `--install-path`");
|
target: target.clone(),
|
||||||
miette!("No install path found or specified")
|
version: package.version.clone(),
|
||||||
})?;
|
repo: package.repository.clone(),
|
||||||
debug!("Using install path: {}", install_path.display());
|
meta: target_meta,
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchers.add(GhCrateMeta::new(&fetcher_data).await);
|
||||||
|
fetchers.add(QuickInstall::new(&fetcher_data).await);
|
||||||
|
}
|
||||||
|
|
||||||
|
match fetchers.first_available().await {
|
||||||
|
Some(fetcher) => {
|
||||||
|
// Build final metadata
|
||||||
|
let fetcher_target = fetcher.target();
|
||||||
|
if let Some(o) = meta.overrides.get(&fetcher_target.to_owned()).cloned() {
|
||||||
|
meta.merge(&o);
|
||||||
|
}
|
||||||
|
meta.merge(&cli_overrides);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Found a binary install source: {} ({fetcher_target})",
|
||||||
|
fetcher.source_name()
|
||||||
|
);
|
||||||
|
|
||||||
// Compute temporary directory for downloads
|
// Compute temporary directory for downloads
|
||||||
let pkg_path = temp_dir
|
let pkg_path = temp_dir
|
||||||
|
@ -239,30 +299,9 @@ async fn entry() -> Result<()> {
|
||||||
.join(format!("pkg-{}.{}", opts.name, meta.pkg_fmt));
|
.join(format!("pkg-{}.{}", opts.name, meta.pkg_fmt));
|
||||||
debug!("Using temporary download path: {}", pkg_path.display());
|
debug!("Using temporary download path: {}", pkg_path.display());
|
||||||
|
|
||||||
let fetcher_data: Vec<_> = detect_targets()
|
|
||||||
.await
|
|
||||||
.into_iter()
|
|
||||||
.map(|target| Data {
|
|
||||||
name: package.name.clone(),
|
|
||||||
target: target.into(),
|
|
||||||
version: package.version.clone(),
|
|
||||||
repo: package.repository.clone(),
|
|
||||||
meta: meta.clone(),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Try github releases, then quickinstall
|
|
||||||
let mut fetchers = MultiFetcher::default();
|
|
||||||
for data in &fetcher_data {
|
|
||||||
fetchers.add(GhCrateMeta::new(data).await);
|
|
||||||
fetchers.add(QuickInstall::new(data).await);
|
|
||||||
}
|
|
||||||
|
|
||||||
match fetchers.first_available().await {
|
|
||||||
Some(fetcher) => {
|
|
||||||
install_from_package(
|
install_from_package(
|
||||||
binaries,
|
binaries,
|
||||||
&*fetcher,
|
fetcher.as_ref(),
|
||||||
install_path,
|
install_path,
|
||||||
meta,
|
meta,
|
||||||
opts,
|
opts,
|
||||||
|
@ -273,10 +312,17 @@ async fn entry() -> Result<()> {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
if !opts.no_cleanup {
|
||||||
temp_dir.close().unwrap_or_else(|err| {
|
temp_dir.close().unwrap_or_else(|err| {
|
||||||
warn!("Failed to clean up some resources: {err}");
|
warn!("Failed to clean up some resources: {err}");
|
||||||
});
|
});
|
||||||
install_from_source(opts, package).await
|
}
|
||||||
|
|
||||||
|
let target = desired_targets
|
||||||
|
.first()
|
||||||
|
.ok_or_else(|| miette!("No viable targets found, try with `--targets`"))?;
|
||||||
|
|
||||||
|
install_from_source(opts, package, target).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +467,7 @@ async fn install_from_package(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn install_from_source(opts: Options, package: Package<Meta>) -> Result<()> {
|
async fn install_from_source(opts: Options, package: Package<Meta>, target: &str) -> Result<()> {
|
||||||
// Prompt user for source install
|
// Prompt user for source install
|
||||||
warn!("The package will be installed from source (with cargo)",);
|
warn!("The package will be installed from source (with cargo)",);
|
||||||
if !opts.no_confirm && !opts.dry_run {
|
if !opts.no_confirm && !opts.dry_run {
|
||||||
|
@ -430,14 +476,14 @@ async fn install_from_source(opts: Options, package: Package<Meta>) -> Result<()
|
||||||
|
|
||||||
if opts.dry_run {
|
if opts.dry_run {
|
||||||
info!(
|
info!(
|
||||||
"Dry-run: running `cargo install {} --version {} --target {}`",
|
"Dry-run: running `cargo install {} --version {} --target {target}`",
|
||||||
package.name, package.version, opts.target
|
package.name, package.version
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
"Running `cargo install {} --version {} --target {}`",
|
"Running `cargo install {} --version {} --target {target}`",
|
||||||
package.name, package.version, opts.target
|
package.name, package.version
|
||||||
);
|
);
|
||||||
let mut child = Command::new("cargo")
|
let mut child = Command::new("cargo")
|
||||||
.arg("install")
|
.arg("install")
|
||||||
|
@ -445,7 +491,7 @@ async fn install_from_source(opts: Options, package: Package<Meta>) -> Result<()
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.arg(package.version)
|
.arg(package.version)
|
||||||
.arg("--target")
|
.arg("--target")
|
||||||
.arg(opts.target)
|
.arg(target)
|
||||||
.spawn()
|
.spawn()
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err("Spawning cargo install failed.")?;
|
.wrap_err("Spawning cargo install failed.")?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue