saluki_metadata/lib.rs
1use serde::{Serialize, Serializer};
2
3#[allow(dead_code)]
4mod details {
5 include!(concat!(env!("OUT_DIR"), "/details.rs"));
6}
7
8static VERSION_DETAILS: AppDetails = AppDetails {
9 full_name: details::DETECTED_APP_FULL_NAME,
10 short_name: details::DETECTED_APP_SHORT_NAME,
11 identifier: details::DETECTED_APP_IDENTIFIER,
12 git_hash: details::DETECTED_GIT_HASH,
13 version: Version::new(
14 details::DETECTED_APP_VERSION,
15 details::DETECTED_APP_VERSION_MAJOR,
16 details::DETECTED_APP_VERSION_MINOR,
17 details::DETECTED_APP_VERSION_PATCH,
18 ),
19 build_time: details::DETECTED_APP_BUILD_TIME,
20 dev_build: details::DETECTED_APP_DEV_BUILD,
21 target_arch: details::DETECTED_TARGET_ARCH,
22};
23
24/// Gets the detected details for this application.
25///
26/// This includes basic information like the application name and semantic version, and information that might otherwise
27/// fall under the general umbrella of "build metadata."
28pub fn get_app_details() -> &'static AppDetails {
29 &VERSION_DETAILS
30}
31
32/// Application details.
33///
34/// # Configuration
35///
36/// This struct is generated at build time and contains information about the detected application name and version
37/// based on detected environment variables. The following environment variables are used:
38///
39/// - `APP_FULL_NAME`: Application's full name. If this isn't set, the default value is `"unknown"`.
40/// - `APP_SHORT_NAME`: Application's short name. If this isn't set, the default value is `"unknown"`.
41/// - `APP_IDENTIFIER`: Application's identifier. If this isn't set, the default value is `"unknown"`.
42/// - `APP_VERSION`: Version of the application. If this isn't set, the default value is `"0.0.0"`.
43/// - `APP_GIT_HASH`: Git hash of the application. If this isn't set, the default value is `"unknown"`.
44/// - `APP_BUILD_TIME`: Build time of the application. If this isn't set, the default value is `"0000-00-00 00:00:00"`.
45/// - `APP_DEV_BUILD`: Whether the application is a development build. If this isn't set, the default value is `true`.
46/// - `TARGET`: Target architecture of the application. If this isn't set, the default value is `"unknown-arch"`.
47///
48/// Environment variables prefixed with `APP_` are expected to be set by the build script/tooling, while others are
49/// provided automatically by Cargo.
50///
51/// The version string will be treated as a semantic version, and will be split on periods to extract the major, minor,
52/// and patch numbers. Additionally, the patch number will be split on hyphens to remove any pre-release or build
53/// metadata.
54#[derive(Serialize)]
55pub struct AppDetails {
56 full_name: &'static str,
57 short_name: &'static str,
58 identifier: &'static str,
59 git_hash: &'static str,
60 version: Version,
61 build_time: &'static str,
62 dev_build: bool,
63 target_arch: &'static str,
64}
65
66impl AppDetails {
67 /// Returns the application's full name.
68 ///
69 /// This is typically a human-friendly/"pretty" name of the binary/executable, such as `"Agent Data Plane"`.
70 ///
71 /// If the full name couldn't be detected, this will return `"unknown"`.
72 pub fn full_name(&self) -> &'static str {
73 self.full_name
74 }
75
76 /// Returns the application's short name.
77 ///
78 /// This is typically a shorter version of the name of the binary/executable, such as `"Data Plane"` or `"DATAPLANE"`.
79 ///
80 /// If the short name couldn't be detected, this will return `"unknown"`.
81 pub fn short_name(&self) -> &'static str {
82 self.short_name
83 }
84
85 /// Returns the application's identifier.
86 ///
87 /// This is typically a very condensed form of the name of the binary/executable, like an acronym, such as `"adp"`
88 /// or `"ADP"`.
89 ///
90 /// If the identifier couldn't be detected, this will return `"unknown"`.
91 pub fn identifier(&self) -> &'static str {
92 self.identifier
93 }
94
95 /// Returns the Git hash used to build the application.
96 ///
97 /// If the Git hash couldn't be detected, this will return `"unknown"`.
98 pub fn git_hash(&self) -> &'static str {
99 self.git_hash
100 }
101
102 /// Returns the application's version.
103 ///
104 /// If the version couldn't be detected, this will return a version equivalent to `"0.0.0"`.
105 pub fn version(&self) -> &Version {
106 &self.version
107 }
108
109 /// Returns the build time of the application.
110 ///
111 /// If the build time couldn't be detected, this will return `"0000-00-00 00:00:00"`.
112 pub fn build_time(&self) -> &'static str {
113 self.build_time
114 }
115
116 /// Returns `true` if this application is a development build.
117 ///
118 /// Development builds generally encompass all local builds, and any CI builds which aren't related to versioned
119 /// artifacts intended for public release.
120 ///
121 /// If the development build flag couldn't be detected, this will return `true`.
122 pub fn is_dev_build(&self) -> bool {
123 self.dev_build
124 }
125
126 /// Returns the target architecture of the application.
127 ///
128 /// This returns a _target triple_, which is a string that generally has _four_ components: the processor
129 /// architecture (x86-64, ARM64, etc), vendor (`"apple"`, `"pc"`, etc), operating system (`"linux"`, `"windows"`,
130 /// `"darwin"`, etc) and environment/ABI (`"gnu"`, `"musl"`, etc).
131 ///
132 /// The environment/ABI component can sometimes be omitted in scenarios where there are no meaningful distinctions
133 /// for the given operating system.
134 ///
135 /// If the target architecture couldn't be detected, this will return `"unknown-arch"`.
136 pub fn target_arch(&self) -> &'static str {
137 self.target_arch
138 }
139}
140
141/// A simple representation of a semantic version.
142pub struct Version {
143 raw: &'static str,
144 major: u32,
145 minor: u32,
146 patch: u32,
147}
148
149impl Version {
150 const fn new(raw: &'static str, major: u32, minor: u32, patch: u32) -> Self {
151 Self {
152 raw,
153 major,
154 minor,
155 patch,
156 }
157 }
158
159 /// Returns the raw version string.
160 pub fn raw(&self) -> &'static str {
161 self.raw
162 }
163
164 /// Returns the major version number.
165 ///
166 /// If the major version number isn't present in the version string, this will return `0`.
167 pub fn major(&self) -> u32 {
168 self.major
169 }
170
171 /// Returns the minor version number.
172 ///
173 /// If the minor version number isn't present in the version string, this will return `0`.
174 pub fn minor(&self) -> u32 {
175 self.minor
176 }
177
178 /// Returns the patch version number.
179 ///
180 /// If the patch version number isn't present in the version string, this will return `0`.
181 pub fn patch(&self) -> u32 {
182 self.patch
183 }
184}
185
186impl Serialize for Version {
187 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
188 where
189 S: Serializer,
190 {
191 // Redirect serialization entirely to the 'raw' string slice
192 serializer.serialize_str(self.raw)
193 }
194}