mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-20 20:48:43 +00:00
Refactor: Extract new mod binstall/install.rs
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
5e35604012
commit
2490cd5a84
2 changed files with 180 additions and 175 deletions
179
src/binstall.rs
179
src/binstall.rs
|
@ -1,185 +1,14 @@
|
|||
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::{bins, fetchers::Fetcher, *};
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod resolve;
|
||||
pub use resolve::*;
|
||||
|
||||
mod install;
|
||||
pub use install::*;
|
||||
|
||||
pub struct Options {
|
||||
pub no_symlinks: bool,
|
||||
pub dry_run: bool,
|
||||
pub version: Option<String>,
|
||||
pub manifest_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub async fn install(
|
||||
resolution: Resolution,
|
||||
opts: Arc<Options>,
|
||||
desired_targets: DesiredTargets,
|
||||
jobserver_client: jobserver::Client,
|
||||
) -> 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");
|
||||
let mut c1 = metafiles::v1::CratesToml::load().unwrap_or_default();
|
||||
c1.insert(cvs.clone(), bins.clone());
|
||||
c1.write()?;
|
||||
}
|
||||
|
||||
{
|
||||
debug!("Writing .crates2.json");
|
||||
let mut c2 = metafiles::v2::Crates2Json::load().unwrap_or_default();
|
||||
c2.insert(
|
||||
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()
|
||||
},
|
||||
);
|
||||
c2.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_from_source(
|
||||
package: Package<Meta>,
|
||||
target: &str,
|
||||
jobserver_client: jobserver::Client,
|
||||
) -> Result<()> {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
|
|
176
src/binstall/install.rs
Normal file
176
src/binstall/install.rs
Normal file
|
@ -0,0 +1,176 @@
|
|||
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: jobserver::Client,
|
||||
) -> 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");
|
||||
let mut c1 = metafiles::v1::CratesToml::load().unwrap_or_default();
|
||||
c1.insert(cvs.clone(), bins.clone());
|
||||
c1.write()?;
|
||||
}
|
||||
|
||||
{
|
||||
debug!("Writing .crates2.json");
|
||||
let mut c2 = metafiles::v2::Crates2Json::load().unwrap_or_default();
|
||||
c2.insert(
|
||||
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()
|
||||
},
|
||||
);
|
||||
c2.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_from_source(
|
||||
package: Package<Meta>,
|
||||
target: &str,
|
||||
jobserver_client: jobserver::Client,
|
||||
) -> Result<()> {
|
||||
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"))
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue