mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-20 20:48:43 +00:00
170 lines
4.9 KiB
Rust
170 lines
4.9 KiB
Rust
use std::{collections::BTreeSet, path::PathBuf, process, sync::Arc};
|
|
|
|
use cargo_toml::Package;
|
|
use log::{debug, error, info};
|
|
use miette::{miette, IntoDiagnostic, Result, WrapErr};
|
|
use tokio::{process::Command, task::block_in_place};
|
|
|
|
use super::{Options, Resolution};
|
|
use crate::{bins, fetchers::Fetcher, *};
|
|
|
|
pub async fn install(
|
|
resolution: Resolution,
|
|
opts: Arc<Options>,
|
|
desired_targets: DesiredTargets,
|
|
jobserver_client: LazyJobserverClient,
|
|
) -> Result<()> {
|
|
match resolution {
|
|
Resolution::Fetch {
|
|
fetcher,
|
|
package,
|
|
name,
|
|
version,
|
|
bin_path,
|
|
bin_files,
|
|
} => {
|
|
let cvs = metafiles::CrateVersionSource {
|
|
name,
|
|
version: package.version.parse().into_diagnostic()?,
|
|
source: metafiles::Source::cratesio_registry(),
|
|
};
|
|
|
|
install_from_package(fetcher, opts, cvs, version, bin_path, bin_files).await
|
|
}
|
|
Resolution::InstallFromSource { package } => {
|
|
let desired_targets = desired_targets.get().await;
|
|
let target = desired_targets
|
|
.first()
|
|
.ok_or_else(|| miette!("No viable targets found, try with `--targets`"))?;
|
|
|
|
if !opts.dry_run {
|
|
install_from_source(package, target, jobserver_client).await
|
|
} else {
|
|
info!(
|
|
"Dry-run: running `cargo install {} --version {} --target {target}`",
|
|
package.name, package.version
|
|
);
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn install_from_package(
|
|
fetcher: Arc<dyn Fetcher>,
|
|
opts: Arc<Options>,
|
|
cvs: metafiles::CrateVersionSource,
|
|
version: String,
|
|
bin_path: PathBuf,
|
|
bin_files: Vec<bins::BinFile>,
|
|
) -> Result<()> {
|
|
// Download package
|
|
if opts.dry_run {
|
|
info!("Dry run, not downloading package");
|
|
} else {
|
|
fetcher.fetch_and_extract(&bin_path).await?;
|
|
}
|
|
|
|
#[cfg(incomplete)]
|
|
{
|
|
// Fetch and check package signature if available
|
|
if let Some(pub_key) = meta.as_ref().map(|m| m.pub_key.clone()).flatten() {
|
|
debug!("Found public key: {pub_key}");
|
|
|
|
// Generate signature file URL
|
|
let mut sig_ctx = ctx.clone();
|
|
sig_ctx.format = "sig".to_string();
|
|
let sig_url = sig_ctx.render(&pkg_url)?;
|
|
|
|
debug!("Fetching signature file: {sig_url}");
|
|
|
|
// Download signature file
|
|
let sig_path = temp_dir.join(format!("{pkg_name}.sig"));
|
|
download(&sig_url, &sig_path).await?;
|
|
|
|
// TODO: do the signature check
|
|
unimplemented!()
|
|
} else {
|
|
warn!("No public key found, package signature could not be validated");
|
|
}
|
|
}
|
|
|
|
if opts.dry_run {
|
|
info!("Dry run, not proceeding");
|
|
return Ok(());
|
|
}
|
|
|
|
info!("Installing binaries...");
|
|
block_in_place(|| {
|
|
for file in &bin_files {
|
|
file.install_bin()?;
|
|
}
|
|
|
|
// Generate symlinks
|
|
if !opts.no_symlinks {
|
|
for file in &bin_files {
|
|
file.install_link()?;
|
|
}
|
|
}
|
|
|
|
let bins: BTreeSet<String> = bin_files.into_iter().map(|bin| bin.base_name).collect();
|
|
|
|
debug!("Writing .crates.toml");
|
|
metafiles::v1::CratesToml::append(&cvs, bins.clone())?;
|
|
|
|
debug!("Writing .crates2.json");
|
|
metafiles::v2::Crates2Json::append(
|
|
&cvs,
|
|
metafiles::v2::CrateInfo {
|
|
version_req: Some(version),
|
|
bins,
|
|
profile: "release".into(),
|
|
target: fetcher.target().to_string(),
|
|
rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
|
|
..Default::default()
|
|
},
|
|
)?;
|
|
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
async fn install_from_source(
|
|
package: Package<Meta>,
|
|
target: &str,
|
|
lazy_jobserver_client: LazyJobserverClient,
|
|
) -> Result<()> {
|
|
let jobserver_client = lazy_jobserver_client.get().await?;
|
|
|
|
debug!(
|
|
"Running `cargo install {} --version {} --target {target}`",
|
|
package.name, package.version
|
|
);
|
|
let mut command = process::Command::new("cargo");
|
|
jobserver_client.configure(&mut command);
|
|
|
|
let mut child = Command::from(command)
|
|
.arg("install")
|
|
.arg(package.name)
|
|
.arg("--version")
|
|
.arg(package.version)
|
|
.arg("--target")
|
|
.arg(&*target)
|
|
.spawn()
|
|
.into_diagnostic()
|
|
.wrap_err("Spawning cargo install failed.")?;
|
|
debug!("Spawned command pid={:?}", child.id());
|
|
|
|
let status = child
|
|
.wait()
|
|
.await
|
|
.into_diagnostic()
|
|
.wrap_err("Running cargo install failed.")?;
|
|
if status.success() {
|
|
info!("Cargo finished successfully");
|
|
Ok(())
|
|
} else {
|
|
error!("Cargo errored! {status:?}");
|
|
Err(miette!("Cargo install error"))
|
|
}
|
|
}
|