use crate::version::Version; #[derive(Clone, Debug)] pub enum UserVersion { OnlyMajor(u64), MajorMinor(u64, u64), Full(Version), } impl UserVersion { pub fn to_version<'a, T>( &self, available_versions: T, config: &crate::config::FnmConfig, ) -> Option<&'a Version> where T: IntoIterator, { available_versions .into_iter() .filter(|x| self.matches(x, config)) .max() } pub fn alias_name(&self) -> Option { match self { Self::Full(version) => version.alias_name(), _ => None, } } pub fn matches(&self, version: &Version, config: &crate::config::FnmConfig) -> bool { match (self, version) { (Self::Full(a), b) if a == b => true, (Self::Full(user_version), maybe_alias) => { match (user_version.alias_name(), maybe_alias.find_aliases(&config)) { (None, _) | (_, Err(_)) => false, (Some(user_alias), Ok(aliases)) => aliases .iter() .find(|alias| alias.name() == user_alias) .is_some(), } } (_, Version::Bypassed) => false, (_, Version::Lts(_)) => false, (_, Version::Alias(_)) => false, (Self::OnlyMajor(major), Version::Semver(other)) => *major == other.major, (Self::MajorMinor(major, minor), Version::Semver(other)) => { *major == other.major && *minor == other.minor } } } } fn next_of<'a, T: std::str::FromStr, It: Iterator>(i: &mut It) -> Option { let x = i.next()?; T::from_str(x).ok() } impl std::fmt::Display for UserVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Full(x) => x.fmt(f), Self::OnlyMajor(major) => write!(f, "v{}.x.x", major), Self::MajorMinor(major, minor) => write!(f, "v{}.{}.x", major, minor), } } } impl std::str::FromStr for UserVersion { type Err = semver::SemVerError; fn from_str(s: &str) -> Result { match Version::parse(s) { Ok(v) => Ok(Self::Full(v)), Err(e) => { let mut parts = s.trim().split('.'); match (next_of::(&mut parts), next_of::(&mut parts)) { (Some(major), None) => Ok(Self::OnlyMajor(major)), (Some(major), Some(minor)) => Ok(Self::MajorMinor(major, minor)), _ => Err(e), } } } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_major_to_version() { let expected = Version::parse("6.1.0").unwrap(); let versions = vec![ Version::parse("6.0.0").unwrap(), Version::parse("6.0.1").unwrap(), expected.clone(), Version::parse("7.0.1").unwrap(), ]; let result = UserVersion::OnlyMajor(6).to_version(&versions, &Default::default()); assert_eq!(result, Some(&expected)); } #[test] fn test_major_minor_to_version() { let expected = Version::parse("6.0.1").unwrap(); let versions = vec![ Version::parse("6.0.0").unwrap(), Version::parse("6.1.0").unwrap(), expected.clone(), Version::parse("7.0.1").unwrap(), ]; let result = UserVersion::MajorMinor(6, 0).to_version(&versions, &Default::default()); assert_eq!(result, Some(&expected)); } #[test] fn test_semver_to_version() { let expected = Version::parse("6.0.0").unwrap(); let versions = vec![ expected.clone(), Version::parse("6.1.0").unwrap(), Version::parse("6.0.1").unwrap(), Version::parse("7.0.1").unwrap(), ]; let result = UserVersion::Full(expected.clone()).to_version(&versions, &Default::default()); assert_eq!(result, Some(&expected)); } }