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}