1#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct BuildInfo {
18 pub version: &'static str,
20 pub sha: &'static str,
22}
23
24pub const DUMMY_BUILD_INFO: BuildInfo = BuildInfo {
29 version: "0.0.0+dummy",
30 sha: "0000000000000000000000000000000000000000",
31};
32
33pub const TARGET_TRIPLE: &str = env!("TARGET_TRIPLE");
35
36impl BuildInfo {
37 pub fn human_version(&self, helm_chart_version: Option<String>) -> String {
39 if let Some(ref helm_chart_version) = helm_chart_version {
40 format!(
41 "v{} ({}, helm chart: {})",
42 self.version,
43 &self.sha[..9],
44 helm_chart_version
45 )
46 } else {
47 format!("v{} ({})", self.version, &self.sha[..9])
48 }
49 }
50
51 #[cfg(feature = "semver")]
61 pub fn semver_version(&self) -> semver::Version {
62 self.version
63 .parse()
64 .expect("build version is not valid semver")
65 }
66
67 #[cfg(feature = "semver")]
70 pub fn semver_version_build(&self) -> Option<semver::Version> {
71 let build_id = buildid::build_id()?;
72 let build_id = hex::encode(build_id);
73 let version = format!("{}+{}", self.version, build_id)
74 .parse()
75 .expect("build version is not valid semver");
76 Some(version)
77 }
78
79 #[cfg(feature = "semver")]
81 pub fn version_num(&self) -> i32 {
82 let semver: semver::Version = self
83 .version
84 .parse()
85 .expect("build version is not a valid semver");
86 let ver_string = format!(
87 "{:0>2}{:0>3}{:0>2}",
88 semver.major, semver.minor, semver.patch
89 );
90 ver_string.parse::<i32>().unwrap()
91 }
92
93 pub fn is_dev(&self) -> bool {
95 self.version.contains("dev")
96 }
97}
98
99#[macro_export]
106macro_rules! build_info {
107 () => {
108 $crate::BuildInfo {
109 version: env!("CARGO_PKG_VERSION"),
110 sha: $crate::__git_sha_internal!(),
111 }
112 };
113}
114
115#[cfg(all(bazel, stamped))]
116#[macro_export]
117macro_rules! __git_sha_internal {
118 () => {
119 $crate::private::bazel_variables::GIT_COMMIT_HASH
120 };
121}
122
123#[cfg(all(bazel, not(stamped)))]
128#[macro_export]
129macro_rules! __git_sha_internal {
130 () => {
131 $crate::private::run_command_str!(
132 "sh",
133 "-c",
134 r#"if [ -f /tmp/mz_git_hash.txt ]; then
135 cat /tmp/mz_git_hash.txt
136 else
137 echo "0000000000000000000000000000000000000000"
138 fi"#
139 )
140 };
141}
142
143#[cfg(not(bazel))]
144#[macro_export]
145macro_rules! __git_sha_internal {
146 () => {
147 $crate::private::run_command_str!(
148 "sh",
149 "-c",
150 r#"if [ -n "$MZ_DEV_BUILD_SHA" ]; then
151 echo "$MZ_DEV_BUILD_SHA"
152 else
153 # Unfortunately we need to suppress error messages from `git`, as
154 # run_command_str will display no error message at all if we print
155 # more than one line of output to stderr.
156 git rev-parse --verify HEAD 2>/dev/null || {
157 printf "error: unable to determine Git SHA; " >&2
158 printf "either build from working Git clone " >&2
159 printf "(see https://materialize.com/docs/install/#build-from-source), " >&2
160 printf "or specify SHA manually by setting MZ_DEV_BUILD_SHA environment variable" >&2
161 printf "If you are using git worktrees, you must be in the primary worktree" >&2
162 printf "for automatic detection to work." >&2
163 exit 1
164 }
165 fi"#
166 )
167 }
168}
169
170#[doc(hidden)]
171pub mod private {
172 pub use compile_time_run::run_command_str;
173
174 #[cfg(all(bazel, stamped))]
178 #[allow(unused)]
179 pub mod bazel_variables {
180 include!(std::env!("BAZEL_GEN_BUILD_INFO"));
181 }
182}
183
184#[cfg(test)]
185mod test {
186 #[test] fn smoketest_build_info() {
188 let build_info = crate::build_info!();
189
190 assert_eq!(build_info.sha.len(), 40);
191 }
192}