diff --git a/src/drivers/crates_io.rs b/src/drivers/crates_io.rs index b7e96086..5d297d40 100644 --- a/src/drivers/crates_io.rs +++ b/src/drivers/crates_io.rs @@ -34,22 +34,8 @@ pub async fn fetch_crate_cratesio( })?; // Locate matching version - let version_iter = - base_info - .versions - .iter() - .filter_map(|v| if !v.yanked { Some(&v.num) } else { None }); - let version_name = find_version(version_req, version_iter)?; - - // Fetch information for the filtered version - let version = base_info - .versions - .iter() - .find(|v| v.num == version_name.to_string()) - .ok_or_else(|| BinstallError::VersionUnavailable { - crate_name: name.into(), - v: version_name.clone(), - })?; + let version_iter = base_info.versions.iter().filter(|v| !v.yanked); + let (version, version_name) = find_version(version_req, version_iter)?; debug!("Found information for crate version: '{}'", version.num); diff --git a/src/drivers/version.rs b/src/drivers/version.rs index 7d5f4a74..6ef364d5 100644 --- a/src/drivers/version.rs +++ b/src/drivers/version.rs @@ -1,48 +1,56 @@ -use std::collections::BTreeSet; - use log::debug; -use semver::{Version, VersionReq}; +use semver::VersionReq; use crate::BinstallError; -pub(super) fn find_version<'a, V: Iterator>( +pub(super) trait Version { + /// Return `None` on error. + fn get_version(&self) -> Option; +} + +impl Version for &T { + fn get_version(&self) -> Option { + (*self).get_version() + } +} + +impl Version for crates_io_api::Version { + fn get_version(&self) -> Option { + // Remove leading `v` for git tags + let ver_str = match self.num.strip_prefix('s') { + Some(v) => v, + None => &self.num, + }; + + // Parse out version + semver::Version::parse(ver_str).ok() + } +} + +pub(super) fn find_version>( requirement: &str, - version_iter: V, -) -> Result { + version_iter: VersionIter, +) -> Result<(Item, semver::Version), BinstallError> { // Parse version requirement let version_req = VersionReq::parse(requirement).map_err(|err| BinstallError::VersionReq { req: requirement.into(), err, })?; - // Filter for matching versions - let filtered: BTreeSet<_> = version_iter - .filter_map(|v| { - // Remove leading `v` for git tags - let ver_str = match v.strip_prefix('s') { - Some(v) => v, - None => v, - }; - - // Parse out version - let ver = Version::parse(ver_str).ok()?; - debug!("Version: {:?}", ver); + version_iter + // Filter for matching versions + .filter_map(|item| { + let ver = item.get_version()?; // Filter by version match if version_req.matches(&ver) { - Some(ver) + debug!("Version: {:?}", ver); + Some((item, ver)) } else { None } }) - .collect(); - - debug!("Filtered: {:?}", filtered); - - // Return highest version - filtered - .iter() - .max() - .cloned() + // Return highest version + .max_by_key(|(_item, ver)| ver.clone()) .ok_or(BinstallError::VersionMismatch { req: version_req }) }