Optimize and generalize find_version

- Rm the process of collecting into `BTreeMap` in `find_version`.
 - Accept any type that implements trait `Version`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-07-21 19:18:43 +10:00
parent b2d09e2b13
commit e308b275d5
No known key found for this signature in database
GPG key ID: 591C0B03040416D6
2 changed files with 38 additions and 44 deletions

View file

@ -34,22 +34,8 @@ pub async fn fetch_crate_cratesio(
})?; })?;
// Locate matching version // Locate matching version
let version_iter = let version_iter = base_info.versions.iter().filter(|v| !v.yanked);
base_info let (version, version_name) = find_version(version_req, version_iter)?;
.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(),
})?;
debug!("Found information for crate version: '{}'", version.num); debug!("Found information for crate version: '{}'", version.num);

View file

@ -1,48 +1,56 @@
use std::collections::BTreeSet;
use log::debug; use log::debug;
use semver::{Version, VersionReq}; use semver::VersionReq;
use crate::BinstallError; use crate::BinstallError;
pub(super) fn find_version<'a, V: Iterator<Item = &'a String>>( pub(super) trait Version {
/// Return `None` on error.
fn get_version(&self) -> Option<semver::Version>;
}
impl<T: Version> Version for &T {
fn get_version(&self) -> Option<semver::Version> {
(*self).get_version()
}
}
impl Version for crates_io_api::Version {
fn get_version(&self) -> Option<semver::Version> {
// 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<Item: Version, VersionIter: Iterator<Item = Item>>(
requirement: &str, requirement: &str,
version_iter: V, version_iter: VersionIter,
) -> Result<Version, BinstallError> { ) -> Result<(Item, semver::Version), BinstallError> {
// Parse version requirement // Parse version requirement
let version_req = VersionReq::parse(requirement).map_err(|err| BinstallError::VersionReq { let version_req = VersionReq::parse(requirement).map_err(|err| BinstallError::VersionReq {
req: requirement.into(), req: requirement.into(),
err, err,
})?; })?;
version_iter
// Filter for matching versions // Filter for matching versions
let filtered: BTreeSet<_> = version_iter .filter_map(|item| {
.filter_map(|v| { let ver = item.get_version()?;
// 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);
// Filter by version match // Filter by version match
if version_req.matches(&ver) { if version_req.matches(&ver) {
Some(ver) debug!("Version: {:?}", ver);
Some((item, ver))
} else { } else {
None None
} }
}) })
.collect();
debug!("Filtered: {:?}", filtered);
// Return highest version // Return highest version
filtered .max_by_key(|(_item, ver)| ver.clone())
.iter()
.max()
.cloned()
.ok_or(BinstallError::VersionMismatch { req: version_req }) .ok_or(BinstallError::VersionMismatch { req: version_req })
} }