ckb_build_info/
lib.rs

1//! The crate `ckb-build-info` generates CKB version from the build environment.
2
3/// CKB version
4#[derive(Debug, Default, Clone)]
5pub struct Version {
6    /// The major version.
7    ///
8    /// It is the x in `x.y.z`.
9    pub major: u8,
10    /// The minor version.
11    ///
12    /// It is the y in `x.y.z`.
13    pub minor: u8,
14    /// The patch version.
15    ///
16    /// It is the z in `x.y.z`.
17    pub patch: u16,
18    /// The pre-release version.
19    ///
20    /// It is the part starting with `-`.
21    ///
22    /// ## Examples
23    ///
24    /// * `v1.2.3`: `dash_pre` is ""
25    /// * `v1.2.3-rc1`: `dash_pre` is "-rc1"
26    pub dash_pre: String,
27    /// A nickname of the version.
28    pub code_name: Option<String>,
29    /// The SHA of the last Git commit.
30    ///
31    /// See [`get_commit_describe`] how to get it.
32    ///
33    /// [`get_commit_describe`]: fn.get_commit_describe.html
34    pub commit_describe: Option<String>,
35    /// The commit date of the last Git commit.
36    ///
37    /// See [`get_commit_date`] how to get it.
38    ///
39    /// [`get_commit_date`]: fn.get_commit_date.html
40    pub commit_date: Option<String>,
41}
42
43impl Version {
44    /// Returns short representation of the version.
45    ///
46    /// It returns version in format like `x.y.z` or `x.y.z-pre`.
47    pub fn short(&self) -> String {
48        format!(
49            "{}.{}.{}{}",
50            self.major, self.minor, self.patch, self.dash_pre
51        )
52    }
53
54    /// Returns full representation of the version.
55    ///
56    /// It adds extra information after the short version in parenthesis, for example:
57    ///
58    /// `0.36.0 (7692751 2020-09-21)`
59    pub fn long(&self) -> String {
60        self.to_string()
61    }
62
63    /// Tells whether this is a pre-release version.
64    pub fn is_pre(&self) -> bool {
65        !self.dash_pre.is_empty()
66    }
67
68    /// Tells whether this version is build from a dirty git working directory.
69    ///
70    /// The dirty version is built from the source code which has uncommitted changes.
71    pub fn is_dirty(&self) -> bool {
72        if let Some(describe) = &self.commit_describe {
73            describe.ends_with("-dirty")
74        } else {
75            false
76        }
77    }
78}
79
80impl std::fmt::Display for Version {
81    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        write!(
83            f,
84            "{}.{}.{}{}",
85            self.major, self.minor, self.patch, self.dash_pre
86        )?;
87
88        let extra_parts: Vec<_> = self
89            .code_name
90            .iter()
91            .chain(self.commit_describe.iter())
92            .chain(self.commit_date.iter())
93            .map(String::as_str)
94            .collect();
95        if !extra_parts.is_empty() {
96            write!(f, " ({})", extra_parts.as_slice().join(" "))?;
97        }
98
99        Ok(())
100    }
101}
102
103/// Gets the field [`commit_describe`] via Git.
104///
105/// [`commit_describe`]: struct.Version.html#structfield.commit_describe
106pub fn get_commit_describe() -> Option<String> {
107    std::process::Command::new("git")
108        .args([
109            "describe",
110            "--dirty",
111            "--always",
112            "--match",
113            "__EXCLUDE__",
114            "--abbrev=7",
115        ])
116        .output()
117        .ok()
118        .filter(|output| output.status.success())
119        .and_then(|r| {
120            String::from_utf8(r.stdout)
121                .ok()
122                .map(|s| s.trim().to_string())
123        })
124}
125
126/// Gets the field [`commit_date`] via Git.
127///
128/// [`commit_date`]: struct.Version.html#structfield.commit_date
129pub fn get_commit_date() -> Option<String> {
130    std::process::Command::new("git")
131        .env("TZ", "UTC")
132        .args(["log", "-1", "--date=iso", "--pretty=format:%cd"])
133        .output()
134        .ok()
135        .filter(|output| output.status.success())
136        .and_then(|r| {
137            String::from_utf8(r.stdout)
138                .ok()
139                .map(|s| s.trim()[..10].to_string())
140        })
141}