Skip to main content

tuwunel_core/info/
version.rs

1//! one true function for returning the application version with the necessary
2//! TUWUNEL_VERSION_EXTRA env variables used if specified
3//!
4//! Set the environment variable `TUWUNEL_VERSION_EXTRA` to any UTF-8 string
5//! to include it in parenthesis after the SemVer version. A common value are
6//! git commit hashes.
7
8use std::sync::OnceLock;
9
10static BRANDING: &str = "Tuwunel";
11static SEMANTIC: &str = env!("CARGO_PKG_VERSION");
12tuwunel_macros::git_commit! {}
13tuwunel_macros::git_semantic! {}
14
15static VERSION: OnceLock<String> = OnceLock::new();
16static USER_AGENT: OnceLock<String> = OnceLock::new();
17
18#[inline]
19#[must_use]
20/// Returns the compiled product branding.
21///
22/// The value is fixed at build time and remains valid for the process lifetime.
23/// It is used wherever a human-readable server name is required.
24pub fn name() -> &'static str { BRANDING }
25
26#[inline]
27/// Returns the detailed compiled version string.
28///
29/// Initialization occurs once on first access. Development builds may include
30/// source-control revision detail in addition to the semantic version.
31pub fn version() -> &'static str { VERSION.get_or_init(init_version) }
32
33#[inline]
34/// Returns the HTTP user-agent value for this build.
35///
36/// Initialization occurs once on first access. The value combines product and
37/// version information into the process-wide client identifier.
38pub fn user_agent() -> &'static str { USER_AGENT.get_or_init(init_user_agent) }
39
40fn init_user_agent() -> String { format!("{}/{}", name(), semantic()) }
41
42fn init_version() -> String {
43	option_env!("TUWUNEL_VERSION_EXTRA")
44		.or(option_env!("CONDUWUIT_VERSION_EXTRA"))
45		.or(option_env!("CONDUIT_VERSION_EXTRA"))
46		.map_or_else(detailed, |extra| {
47			extra
48				.is_empty()
49				.then(detailed)
50				.unwrap_or_else(|| format!("{} ({extra})", detailed()))
51		})
52}
53
54fn detailed() -> String {
55	let tag_dirty = semantic()
56		.rsplit_once('-')
57		.is_some_and(|(_, s)| !s.is_empty());
58
59	if !GIT_COMMIT.is_empty() && tag_dirty {
60		format!("{} ({})", semantic(), GIT_COMMIT)
61	} else {
62		semantic().to_owned()
63	}
64}
65
66fn semantic() -> &'static str {
67	if !GIT_SEMANTIC.is_empty() {
68		GIT_SEMANTIC
69	} else {
70		SEMANTIC
71	}
72}