|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|