You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

167 lines
5.1 KiB

use crate::version::Version;
use std::str::FromStr;
#[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<Item = &'a Version>,
{
available_versions
.into_iter()
.filter(|x| self.matches(x, config))
.max()
}
pub fn alias_name(&self) -> Option<String> {
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().any(|alias| alias.name() == user_alias)
}
}
}
(_, Version::Bypassed | Version::Lts(_) | 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: FromStr, It: Iterator<Item = &'a str>>(i: &mut It) -> Option<T> {
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),
}
}
}
fn skip_first_v(str: &str) -> &str {
str.strip_prefix('v').unwrap_or(str)
}
impl FromStr for UserVersion {
type Err = semver::Error;
fn from_str(s: &str) -> Result<UserVersion, Self::Err> {
match Version::parse(s) {
Ok(v) => Ok(Self::Full(v)),
Err(e) => {
let mut parts = skip_first_v(s.trim()).split('.');
match (next_of::<u64, _>(&mut parts), next_of::<u64, _>(&mut parts)) {
(Some(major), None) => Ok(Self::OnlyMajor(major)),
(Some(major), Some(minor)) => Ok(Self::MajorMinor(major, minor)),
_ => Err(e),
}
}
}
}
}
#[cfg(test)]
impl PartialEq for UserVersion {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::OnlyMajor(a), Self::OnlyMajor(b)) if a == b => true,
(Self::MajorMinor(a1, a2), Self::MajorMinor(b1, b2)) if (a1, a2) == (b1, b2) => true,
(Self::Full(v1), Self::Full(v2)) if v1 == v2 => true,
(_, _) => false,
}
}
}
#[cfg(test)]
mod tests {
use crate::config::FnmConfig;
use super::*;
#[test]
fn test_parsing_only_major() {
let version = UserVersion::from_str("10").ok();
assert_eq!(version, Some(UserVersion::OnlyMajor(10)));
}
#[test]
fn test_parsing_major_minor() {
let version = UserVersion::from_str("10.20").ok();
assert_eq!(version, Some(UserVersion::MajorMinor(10, 20)));
}
#[test]
fn test_parsing_only_major_with_v() {
let version = UserVersion::from_str("v10").ok();
assert_eq!(version, Some(UserVersion::OnlyMajor(10)));
}
#[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, &FnmConfig::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, &FnmConfig::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, &FnmConfig::default());
assert_eq!(result, Some(&expected));
}
}