snm_core/version/
dist_version.rs1use std::{fmt::Display, fs::read_dir};
2
3use console::style;
4use semver::Version;
5use serde::Deserialize;
6
7use crate::{
8 fetcher::{Lts, Release},
9 types::ReleaseDir,
10 SnmRes,
11};
12
13use super::{ParseVersion, UserVersion};
14
15#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct DistVersion(pub(super) Version);
18
19impl ParseVersion for DistVersion {
20 type Item = Self;
21 fn parse(v: &str) -> SnmRes<Self::Item> {
22 Ok(DistVersion(Version::parse(v)?))
23 }
24}
25
26impl<'de> Deserialize<'de> for DistVersion {
27 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28 where
29 D: serde::Deserializer<'de>,
30 {
31 let v: String = String::deserialize(deserializer)?;
32
33 Self::parse(v.trim_start_matches('v')).map_err(serde::de::Error::custom)
34 }
35}
36
37impl Display for DistVersion {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 self.0.fmt(f)
40 }
41}
42
43impl AsRef<Version> for DistVersion {
44 fn as_ref(&self) -> &Version {
45 &self.0
46 }
47}
48
49impl DistVersion {
50 pub fn list_versions(release_dir: &ReleaseDir) -> SnmRes<Vec<Self>> {
52 let mut versions: Vec<Self> = vec![];
53
54 let entries = read_dir(release_dir.as_ref())?;
55
56 for entry in entries {
57 let entry = entry?.path();
58 let entry = entry.strip_prefix(release_dir.as_ref())?;
59
60 if let Some(e) = entry.to_str() {
61 let dist_ver = Self::parse(e)?;
62
63 versions.push(dist_ver);
64 }
65 }
66
67 Ok(versions)
68 }
69
70 pub fn match_versions(r_dir: &ReleaseDir, version: &UserVersion) -> SnmRes<Vec<Self>> {
72 let mut versions: Vec<Self> = vec![];
73
74 let entries = read_dir(r_dir.as_ref())?;
75
76 for entry in entries {
77 let entry = entry?.path();
78 let entry = entry.strip_prefix(r_dir.as_ref())?;
79
80 if let Some(e) = entry.to_str() {
81 let dist_ver = Self::parse(e)?;
82
83 let release = Release {
84 version: dist_ver,
85 lts: Lts::No,
86 };
87
88 let is_match = version.match_release(&release);
89
90 if is_match {
91 versions.push(release.version);
92 }
93 }
94 }
95
96 versions.sort_by(|a, b| b.cmp(a));
98
99 Ok(versions)
100 }
101
102 pub fn match_version(r_dir: &ReleaseDir, version: &UserVersion) -> SnmRes<Self> {
104 let versions = Self::match_versions(r_dir, version)?;
105
106 let max = versions.into_iter().next().ok_or_else(|| {
108 anyhow::anyhow!("Version {} not found locally", style(version).bold())
109 })?;
110
111 Ok(max)
112 }
113}