-
Notifications
You must be signed in to change notification settings - Fork 641
Expand file tree
/
Copy pathversion.rs
More file actions
119 lines (106 loc) 路 3.69 KB
/
Copy pathversion.rs
File metadata and controls
119 lines (106 loc) 路 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::alias;
use crate::config;
use crate::lts::LtsType;
use crate::system_version;
use std::str::FromStr;
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
pub enum Version {
Semver(node_semver::Version),
Lts(LtsType),
Alias(String),
Latest,
Bypassed,
}
fn first_letter_is_number(s: &str) -> bool {
s.chars().next().is_some_and(|x| x.is_ascii_digit())
}
impl Version {
pub fn parse<S: AsRef<str>>(version_str: S) -> Result<Self, node_semver::SemverError> {
let lowercased = version_str.as_ref().to_lowercase();
if lowercased == system_version::display_name() {
Ok(Self::Bypassed)
} else if lowercased.starts_with("lts-") || lowercased.starts_with("lts/") {
let lts_type = LtsType::from(&lowercased[4..]);
Ok(Self::Lts(lts_type))
} else if first_letter_is_number(lowercased.trim_start_matches('v')) {
let version_plain = lowercased.trim_start_matches('v');
let sver = node_semver::Version::parse(version_plain)?;
Ok(Self::Semver(sver))
} else {
Ok(Self::Alias(lowercased))
}
}
pub fn alias_name(&self) -> Option<String> {
match self {
l @ (Self::Lts(_) | Self::Alias(_)) => Some(l.v_str()),
_ => None,
}
}
pub fn find_aliases(
&self,
config: &config::FnmConfig,
) -> std::io::Result<Vec<alias::StoredAlias>> {
let aliases = alias::list_aliases(config)?
.drain(..)
.filter(|alias| alias.s_ver() == self.v_str())
.collect();
Ok(aliases)
}
pub fn v_str(&self) -> String {
format!("{self}")
}
pub fn installation_path(&self, config: &config::FnmConfig) -> std::path::PathBuf {
match self {
Self::Bypassed => system_version::path(),
v @ (Self::Lts(_) | Self::Alias(_) | Self::Latest) => {
config.aliases_dir().join(v.alias_name().unwrap())
}
v @ Self::Semver(_) => config
.installations_dir()
.join(v.v_str())
.join("installation"),
}
}
pub fn root_path(&self, config: &config::FnmConfig) -> Option<std::path::PathBuf> {
let path = self.installation_path(config);
let mut canon_path = path.canonicalize().ok()?;
canon_path.pop();
Some(canon_path)
}
}
// TODO: add a trait called BinPath that &Path and PathBuf implements
// which adds the `.bin_path()` which works both on windows and unix :)
impl<'de> serde::Deserialize<'de> for Version {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let version_str = String::deserialize(deserializer)?;
Version::parse(version_str).map_err(serde::de::Error::custom)
}
}
impl std::fmt::Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bypassed => write!(f, "{}", system_version::display_name()),
Self::Lts(lts) => write!(f, "lts-{lts}"),
Self::Semver(semver) => write!(f, "v{semver}"),
Self::Alias(alias) => write!(f, "{alias}"),
Self::Latest => write!(f, "latest"),
}
}
}
impl FromStr for Version {
type Err = node_semver::SemverError;
fn from_str(s: &str) -> Result<Version, Self::Err> {
Self::parse(s)
}
}
impl PartialEq<node_semver::Version> for Version {
fn eq(&self, other: &node_semver::Version) -> bool {
match self {
Self::Bypassed | Self::Lts(_) | Self::Alias(_) | Self::Latest => false,
Self::Semver(v) => v == other,
}
}
}