diff --git a/src/binstall/install.rs b/src/binstall/install.rs index 0bf5c0e7..9e57d6c1 100644 --- a/src/binstall/install.rs +++ b/src/binstall/install.rs @@ -15,6 +15,7 @@ pub async fn install( jobserver_client: LazyJobserverClient, ) -> Result> { match resolution { + Resolution::AlreadyUpToDate => Ok(None), Resolution::Fetch { fetcher, package, diff --git a/src/binstall/resolve.rs b/src/binstall/resolve.rs index d17747b4..0869106a 100644 --- a/src/binstall/resolve.rs +++ b/src/binstall/resolve.rs @@ -8,7 +8,7 @@ use compact_str::{CompactString, ToCompactString}; use log::{debug, error, info, warn}; use miette::{miette, Result}; use reqwest::Client; -use semver::VersionReq; +use semver::{Version, VersionReq}; use super::Options; use crate::{ @@ -29,6 +29,7 @@ pub enum Resolution { InstallFromSource { package: Package, }, + AlreadyUpToDate, } impl Resolution { fn print(&self, opts: &Options) { @@ -70,6 +71,7 @@ impl Resolution { Resolution::InstallFromSource { .. } => { warn!("The package will be installed from source (with cargo)",) } + Resolution::AlreadyUpToDate => (), } } } @@ -77,6 +79,7 @@ impl Resolution { pub async fn resolve( opts: Arc, crate_name: CrateName, + curr_version: Option, temp_dir: Arc, install_path: Arc, client: Client, @@ -109,6 +112,19 @@ pub async fn resolve( let package = manifest.package.unwrap(); + if let Some(curr_version) = curr_version { + let new_version = + Version::parse(&package.version).map_err(|err| BinstallError::VersionParse { + v: package.version.clone(), + err, + })?; + + if new_version == curr_version { + info!("package {crate_name} is already up to date {curr_version}"); + return Ok(Resolution::AlreadyUpToDate); + } + } + let (mut meta, binaries) = ( package .metadata diff --git a/src/main.rs b/src/main.rs index 687fc906..55628a22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -354,26 +354,29 @@ async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> { })?; // Remove installed crates - let crate_names = CrateName::dedup(crate_names).filter(|crate_name| { + let crate_names = CrateName::dedup(crate_names).filter_map(|crate_name| { if opts.force { - true + Some((crate_name, None)) } else if let Some(records) = &metadata { - let keep = if let Some(version_req) = &crate_name.version_req { - records - .get(&crate_name.name) - .map(|metadata| !version_req.is_latest_compatible(&metadata.current_version)) - .unwrap_or(true) + if let Some(metadata) = records.get(&crate_name.name) { + if let Some(version_req) = &crate_name.version_req { + if version_req.is_latest_compatible(&metadata.current_version) { + info!( + "package {crate_name} is already installed and cannot be upgraded, use --force to override" + ); + None + } else { + Some((crate_name, Some(metadata.current_version.clone()))) + } + } else { + info!("package {crate_name} is already installed, use --force to override"); + None + } } else { - !records.contains(&crate_name.name) - }; - - if !keep { - info!("package {crate_name} is already installed, use --force to override") + Some((crate_name, None)) } - - keep } else { - true + Some((crate_name, None)) } }); @@ -395,10 +398,11 @@ async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> { // Resolve crates let tasks: Vec<_> = crate_names .into_iter() - .map(|crate_name| { + .map(|(crate_name, current_version)| { AutoAbortJoinHandle::spawn(binstall::resolve( binstall_opts.clone(), crate_name, + current_version, temp_dir_path.clone(), install_path.clone(), client.clone(), @@ -430,7 +434,7 @@ async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> { // Resolve crates and install without confirmation crate_names .into_iter() - .map(|crate_name| { + .map(|(crate_name, current_version)| { let opts = binstall_opts.clone(); let temp_dir_path = temp_dir_path.clone(); let jobserver_client = jobserver_client.clone(); @@ -442,6 +446,7 @@ async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> { let resolution = binstall::resolve( opts.clone(), crate_name, + current_version, temp_dir_path, install_path, client,