1#![allow(
12 unexpected_cfgs,
13 reason = "`fbcode_build` is supplied by the internal Buck build"
14)]
15
16pub use detcore_model::build_info::BuildFeatures;
17pub use detcore_model::build_info::BuildInfo;
18
19#[cfg(feature = "buck-release-provenance")]
20const fn is_ascii_hex(byte: u8) -> bool {
21 byte.is_ascii_hexdigit()
22}
23
24#[cfg(feature = "buck-release-provenance")]
25const fn valid_release_sha(value: &str) -> bool {
26 let bytes = value.as_bytes();
27 let valid_length = bytes.len() == 12
28 || (bytes.len() == 18
29 && bytes[12] == b'-'
30 && bytes[13] == b'd'
31 && bytes[14] == b'i'
32 && bytes[15] == b'r'
33 && bytes[16] == b't'
34 && bytes[17] == b'y');
35 if !valid_length {
36 return false;
37 }
38 let mut index = 0;
39 while index < 12 {
40 if !is_ascii_hex(bytes[index]) {
41 return false;
42 }
43 index += 1;
44 }
45 true
46}
47
48#[cfg(feature = "buck-release-provenance")]
49const fn valid_release_date(value: &str) -> bool {
50 let bytes = value.as_bytes();
51 if bytes.len() != 10 || bytes[4] != b'-' || bytes[7] != b'-' {
52 return false;
53 }
54 let mut index = 0;
55 while index < bytes.len() {
56 if index != 4 && index != 7 && !bytes[index].is_ascii_digit() {
57 return false;
58 }
59 index += 1;
60 }
61 true
62}
63
64#[cfg(feature = "buck-release-provenance")]
65const fn valid_release_version(value: &str) -> bool {
66 let bytes = value.as_bytes();
67 if bytes.is_empty()
68 || (bytes.len() == 7
69 && bytes[0] == b'u'
70 && bytes[1] == b'n'
71 && bytes[2] == b'k'
72 && bytes[3] == b'n'
73 && bytes[4] == b'o'
74 && bytes[5] == b'w'
75 && bytes[6] == b'n')
76 {
77 return false;
78 }
79 let mut index = 0;
80 while index < bytes.len() {
81 let byte = bytes[index];
82 if !(byte.is_ascii_alphanumeric() || byte == b'.' || byte == b'-' || byte == b'+') {
83 return false;
84 }
85 index += 1;
86 }
87 true
88}
89
90#[cfg(feature = "buck-release-provenance")]
91const fn valid_reverie_pin(value: &str) -> bool {
92 let bytes = value.as_bytes();
93 if bytes.len() != 40 {
94 return false;
95 }
96 let mut index = 0;
97 while index < bytes.len() {
98 if !is_ascii_hex(bytes[index]) {
99 return false;
100 }
101 index += 1;
102 }
103 true
104}
105
106#[cfg(feature = "buck-release-provenance")]
110const _: () = {
111 assert!(valid_release_version(env!("CARGO_PKG_VERSION")));
112 assert!(valid_release_date(env!("HERMIT_BUILD_DATE")));
113 assert!(valid_release_sha(env!("HERMIT_BUILD_GIT_SHA")));
114 assert!(valid_reverie_pin(env!("HERMIT_REVERIE_PIN")));
115};
116
117pub fn current() -> BuildInfo {
122 #[cfg(fbcode_build)]
123 let (version, build_date, git_sha) = {
124 use build_info::BuildInfo as FbBuildInfo;
125
126 let revision = Some(FbBuildInfo::get_revision().to_owned())
127 .filter(|value| !value.is_empty())
128 .unwrap_or_else(|| "unknown".to_owned());
129 let package = Some(FbBuildInfo::get_package_version().to_owned())
130 .filter(|value| !value.is_empty())
131 .unwrap_or_else(|| "unknown".to_owned());
132 (package, None, revision)
133 };
134
135 #[cfg(not(fbcode_build))]
136 let (version, build_date, git_sha) = (
137 env!("CARGO_PKG_VERSION").to_owned(),
138 Some(env!("HERMIT_BUILD_DATE").to_owned()),
139 env!("HERMIT_BUILD_GIT_SHA").to_owned(),
140 );
141
142 BuildInfo {
143 schema: BuildInfo::SCHEMA,
144 version,
145 build_date,
146 git_sha,
147 features: BuildFeatures {
148 dbt: false,
149 e9patch: false,
150 sabre: false,
151 },
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn current_build_info_round_trips_through_the_closed_schema() {
161 let expected = current();
162 let bytes = serde_json::to_vec(&expected).unwrap();
163 let observed: BuildInfo = serde_json::from_slice(&bytes).unwrap();
164
165 assert_eq!(observed, expected);
166 assert_eq!(observed.schema, BuildInfo::SCHEMA);
167 }
168}