hglib/commands/
version.rs1use regex::bytes::Regex;
6
7use crate::client::{Client, HglibError, Runner};
8use crate::{runcommand, MkArg};
9
10pub struct Arg {}
11
12impl Default for Arg {
13 fn default() -> Self {
14 Self {}
15 }
16}
17
18impl Arg {
19 fn run(&self, client: &mut Client) -> Result<(Vec<u8>, i32), HglibError> {
20 runcommand!(client, "version", &[""], "-q", true)
21 }
22}
23
24#[derive(Debug, PartialEq, Eq)]
25pub struct Version {
26 pub major: u32,
27 pub minor: u32,
28 pub micro: Option<u32>,
29 pub build_info: Option<String>,
30}
31
32impl Ord for Version {
33 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
34 for c in &[self.major.cmp(&other.major), self.minor.cmp(&other.minor)] {
35 if c != &std::cmp::Ordering::Equal {
36 return *c;
37 }
38 }
39
40 match (self.micro, other.micro) {
41 (None, None) => std::cmp::Ordering::Equal,
42 (Some(x), None) => x.cmp(&0),
43 (None, Some(y)) => 0.cmp(&y),
44 (Some(x), Some(y)) => x.cmp(&y),
45 }
46 }
47}
48
49impl PartialOrd for Version {
50 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
51 Some(self.cmp(other))
52 }
53}
54
55impl Version {
56 pub fn from_tuple(v: &(u32, u32, Option<u32>)) -> Version {
57 Version {
58 major: v.0,
59 minor: v.1,
60 micro: v.2,
61 build_info: None,
62 }
63 }
64}
65
66impl PartialEq<(u32, u32, Option<u32>)> for Version {
67 fn eq(&self, other: &(u32, u32, Option<u32>)) -> bool {
68 self == &Version::from_tuple(other)
69 }
70}
71
72impl PartialOrd<(u32, u32, Option<u32>)> for Version {
73 fn partial_cmp(&self, other: &(u32, u32, Option<u32>)) -> Option<std::cmp::Ordering> {
74 Some(self.cmp(&Version::from_tuple(other)))
75 }
76}
77
78impl Client {
79 pub fn version(&mut self, x: Arg) -> Result<Version, HglibError> {
80 let (data, _) = x.run(self)?;
81 let pat = Regex::new(r".*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?").unwrap();
82 let cap = pat.captures_iter(&data).next().unwrap();
83
84 let micro = if let Some(buf) = cap.get(3) {
85 Some(
86 buf.as_bytes()
87 .iter()
88 .fold(0, |r, x| r * 10 + u32::from(*x - b'0')),
89 )
90 } else {
91 None
92 };
93
94 let build_info = if let Some(buf) = cap.get(4) {
95 Some(String::from_utf8(buf.as_bytes().to_vec())?)
96 } else {
97 None
98 };
99
100 Ok(Version {
101 major: cap[1].iter().fold(0, |r, x| r * 10 + u32::from(*x - b'0')),
102 minor: cap[2].iter().fold(0, |r, x| r * 10 + u32::from(*x - b'0')),
103 micro,
104 build_info,
105 })
106 }
107}