pyrinas_cli/
git.rs

1use git2::{DescribeFormatOptions, DescribeOptions, Repository};
2use pyrinas_shared::ota::OTAPackageVersion;
3use semver::Version;
4// Error handling
5use thiserror::Error;
6
7// Std
8use std::{convert::TryInto, io, num};
9
10#[derive(Debug, Error)]
11pub enum GitError {
12    #[error("filesystem error: {source}")]
13    FileError {
14        #[from]
15        source: io::Error,
16    },
17
18    #[error("git repo not found!")]
19    GitNotFound,
20
21    #[error("git error: {source}")]
22    GitError {
23        #[from]
24        source: git2::Error,
25    },
26
27    #[error("parse error: {source}")]
28    ParseError {
29        #[from]
30        source: num::ParseIntError,
31    },
32
33    #[error("semver error: {source}")]
34    SemVerError {
35        #[from]
36        source: semver::Error,
37    },
38
39    #[error("unable to convert hash")]
40    HashError,
41}
42
43pub fn get_git_describe() -> Result<String, GitError> {
44    let mut path = std::env::current_dir()?;
45
46    let repo: Repository;
47
48    // Recursively go up levels to see if there's a .git folder and then stop
49    loop {
50        repo = match Repository::open(path.clone()) {
51            Ok(repo) => repo,
52            Err(_e) => {
53                if !path.pop() {
54                    return Err(GitError::GitNotFound);
55                }
56
57                continue;
58            }
59        };
60
61        break;
62    }
63
64    // Describe options
65    let mut opts = DescribeOptions::new();
66    let opts = opts.describe_all().describe_tags();
67
68    // Describe format
69    let mut desc_format_opts = DescribeFormatOptions::new();
70    desc_format_opts
71        .always_use_long_format(true)
72        .dirty_suffix("-dirty");
73
74    // Describe string!
75    let des = repo.describe(opts)?.format(Some(&desc_format_opts))?;
76
77    Ok(des)
78}
79
80pub fn get_ota_package_version(ver: &str) -> Result<(OTAPackageVersion, bool), GitError> {
81    // Parse the version
82    let version = Version::parse(ver)?;
83
84    log::info!("ver: {:?}", version);
85
86    // Then convert it to an OTAPackageVersion
87    let dirty = ver.contains("dirty");
88    let pre: Vec<&str> = ver.split('-').collect();
89    let commit: u8 = pre[1].parse()?;
90    let hash: [u8; 8] = get_hash(pre[2].as_bytes().to_vec())?;
91
92    Ok((
93        OTAPackageVersion {
94            major: version.major as u8,
95            minor: version.minor as u8,
96            patch: version.patch as u8,
97            commit,
98            hash,
99        },
100        dirty,
101    ))
102}
103
104fn get_hash(v: Vec<u8>) -> Result<[u8; 8], GitError> {
105    match v.try_into() {
106        Ok(r) => Ok(r),
107        Err(_e) => Err(GitError::HashError),
108    }
109}