mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-20 12:38:43 +00:00

* Optimization: Rm `debug!` in `find_version` printing all version iterated obviously doesn't help much in debugging in the problem but rather just confusing. Also this makes it hard for the compiler to optimize the iterators. * Use let-else in `ManifestVisitor` * Optimize `BinFile::preview_{bin, link}` for zero-copy Return `impl Display` that lazily format instead of allocating a `String` * Optimize `infer_bin_dir_template`: Generate dir lazily * Optimize `find_version`: Lazily clone `version_req` only on err * Refactor `find_version`: Use `bool::then_some` * Add dep either v1.8.0 to binstalk * Optimize `GhCrateMeta::find`: Avoid cloning and `Vec` creation by using `Either` * Optimize `ops::install::install_from_package`: Make it a regular fn instead of async fn since it does not `.await` on any async fn. * Optimize `QuickInstall`: Rm field `target` since `Arc<Data>` already contains that field. * Optimize `Fetcher`s: Extract new struct `TargetData` so that `Data` can be shared by all fetchers, regardless of the target. * Optimize `QuickInstall`: Rm unused field `data` * Optimize `Resolution::print`: Replace branching with conditional move Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
151 lines
3.9 KiB
Rust
151 lines
3.9 KiB
Rust
use std::{borrow::Cow, env, ffi::OsStr, sync::Arc};
|
|
|
|
use compact_str::CompactString;
|
|
use tokio::{process::Command, task::block_in_place};
|
|
use tracing::{debug, error, info, instrument};
|
|
|
|
use super::{resolve::Resolution, Options};
|
|
use crate::{
|
|
bins,
|
|
errors::BinstallError,
|
|
helpers::jobserver_client::LazyJobserverClient,
|
|
manifests::crate_info::{CrateInfo, CrateSource},
|
|
};
|
|
|
|
#[instrument(skip_all)]
|
|
pub async fn install(
|
|
resolution: Resolution,
|
|
opts: Arc<Options>,
|
|
) -> Result<Option<CrateInfo>, BinstallError> {
|
|
match resolution {
|
|
Resolution::AlreadyUpToDate => Ok(None),
|
|
Resolution::Fetch {
|
|
fetcher,
|
|
new_version,
|
|
name,
|
|
version_req,
|
|
bin_files,
|
|
} => {
|
|
let target = fetcher.target().into();
|
|
|
|
install_from_package(opts, bin_files).map(|option| {
|
|
option.map(|bins| CrateInfo {
|
|
name,
|
|
version_req,
|
|
current_version: new_version,
|
|
source: CrateSource::cratesio_registry(),
|
|
target,
|
|
bins,
|
|
})
|
|
})
|
|
}
|
|
Resolution::InstallFromSource { name, version } => {
|
|
let desired_targets = opts.desired_targets.get().await;
|
|
let target = desired_targets
|
|
.first()
|
|
.ok_or(BinstallError::NoViableTargets)?;
|
|
|
|
if !opts.dry_run {
|
|
install_from_source(
|
|
&name,
|
|
&version,
|
|
target,
|
|
&opts.jobserver_client,
|
|
opts.quiet,
|
|
opts.force,
|
|
)
|
|
.await
|
|
.map(|_| None)
|
|
} else {
|
|
info!(
|
|
"Dry-run: running `cargo install {name} --version {version} --target {target}`",
|
|
);
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn install_from_package(
|
|
opts: Arc<Options>,
|
|
bin_files: Vec<bins::BinFile>,
|
|
) -> Result<Option<Vec<CompactString>>, BinstallError> {
|
|
if opts.dry_run {
|
|
info!("Dry run, not proceeding");
|
|
return Ok(None);
|
|
}
|
|
|
|
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()?;
|
|
}
|
|
}
|
|
|
|
Ok(Some(
|
|
bin_files.into_iter().map(|bin| bin.base_name).collect(),
|
|
))
|
|
})
|
|
}
|
|
|
|
async fn install_from_source(
|
|
name: &str,
|
|
version: &str,
|
|
target: &str,
|
|
lazy_jobserver_client: &LazyJobserverClient,
|
|
quiet: bool,
|
|
force: bool,
|
|
) -> Result<(), BinstallError> {
|
|
let jobserver_client = lazy_jobserver_client.get().await?;
|
|
|
|
let cargo = env::var_os("CARGO")
|
|
.map(Cow::Owned)
|
|
.unwrap_or_else(|| Cow::Borrowed(OsStr::new("cargo")));
|
|
|
|
debug!(
|
|
"Running `{} install {name} --version {version} --target {target}`",
|
|
cargo.to_string_lossy(),
|
|
);
|
|
|
|
let mut cmd = Command::new(cargo);
|
|
|
|
cmd.arg("install")
|
|
.arg(name)
|
|
.arg("--version")
|
|
.arg(version)
|
|
.arg("--target")
|
|
.arg(target)
|
|
.kill_on_drop(true);
|
|
|
|
if quiet {
|
|
cmd.arg("--quiet");
|
|
}
|
|
|
|
if force {
|
|
cmd.arg("--force");
|
|
}
|
|
|
|
let command_string = format!("{cmd:?}");
|
|
|
|
let mut child = jobserver_client.configure_and_run(&mut cmd, |cmd| cmd.spawn())?;
|
|
|
|
debug!("Spawned command pid={:?}", child.id());
|
|
|
|
let status = child.wait().await?;
|
|
if status.success() {
|
|
info!("Cargo finished successfully");
|
|
Ok(())
|
|
} else {
|
|
error!("Cargo errored! {status:?}");
|
|
Err(BinstallError::SubProcess {
|
|
command: command_string,
|
|
status,
|
|
})
|
|
}
|
|
}
|