Skip to main content

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}