diff --git a/src/core/info/version.rs b/src/core/info/version.rs index 5350ac34..04f9f47c 100644 --- a/src/core/info/version.rs +++ b/src/core/info/version.rs @@ -9,6 +9,7 @@ use std::sync::OnceLock; static BRANDING: &str = "Tuwunel"; static SEMANTIC: &str = env!("CARGO_PKG_VERSION"); +tuwunel_macros::git_describe!(); static VERSION: OnceLock = OnceLock::new(); static USER_AGENT: OnceLock = OnceLock::new(); diff --git a/src/macros/git.rs b/src/macros/git.rs new file mode 100644 index 00000000..08fa0982 --- /dev/null +++ b/src/macros/git.rs @@ -0,0 +1,64 @@ +use std::process::Command; + +use proc_macro::TokenStream; +use quote::quote; + +pub(super) fn semantic(_args: TokenStream) -> TokenStream { + static ARGS: &[&str] = &["describe", "--tags", "--abbrev=1"]; + + let output = git(ARGS); + let output = output + .strip_prefix('v') + .map(str::to_string) + .unwrap_or(output); + + let output = output + .rsplit_once('-') + .map(|(s, _)| s) + .map(str::to_string) + .unwrap_or(output); + + let ret = quote! { + static GIT_SEMANTIC: &'static str = #output; + }; + + ret.into() +} + +pub(super) fn commit(_args: TokenStream) -> TokenStream { + static ARGS: &[&str] = &["describe", "--always", "--dirty", "--abbrev=10"]; + + let output = git(ARGS); + let ret = quote! { + static GIT_COMMIT: &'static str = #output; + }; + + ret.into() +} + +pub(super) fn describe(_args: TokenStream) -> TokenStream { + static ARGS: &[&str] = + &["describe", "--dirty", "--tags", "--always", "--broken", "--abbrev=10"]; + + let output = git(ARGS); + let ret = quote! { + static GIT_DESCRIBE: &'static str = #output; + }; + + ret.into() +} + +fn git(args: &[&str]) -> String { + Command::new("git") + .args(args) + .output() + .map(|output| { + str::from_utf8(&output.stdout) + .map(str::trim) + .map(String::from) + .ok() + }) + .ok() + .flatten() + .unwrap_or_default() +} diff --git a/src/macros/mod.rs b/src/macros/mod.rs index f93de512..d8a0431f 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -4,6 +4,7 @@ mod admin; mod cargo; mod config; mod debug; +mod git; mod implement; mod refutable; mod rustc; @@ -41,6 +42,9 @@ pub fn recursion_depth(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro] pub fn rustc_flags_capture(args: TokenStream) -> TokenStream { rustc::flags_capture(args) } +#[proc_macro] +pub fn rustc_version(args: TokenStream) -> TokenStream { rustc::version(args) } + #[proc_macro_attribute] pub fn refutable(args: TokenStream, input: TokenStream) -> TokenStream { attribute_macro::(args, input, refutable::refutable) @@ -56,6 +60,15 @@ pub fn config_example_generator(args: TokenStream, input: TokenStream) -> TokenS attribute_macro::(args, input, config::example_generator) } +#[proc_macro] +pub fn git_semantic(args: TokenStream) -> TokenStream { git::semantic(args) } + +#[proc_macro] +pub fn git_commit(args: TokenStream) -> TokenStream { git::commit(args) } + +#[proc_macro] +pub fn git_describe(args: TokenStream) -> TokenStream { git::describe(args) } + fn attribute_macro(args: TokenStream, input: TokenStream, func: F) -> TokenStream where F: Fn(I, &[Meta]) -> Result, diff --git a/src/macros/rustc.rs b/src/macros/rustc.rs index 36082ddd..039aac13 100644 --- a/src/macros/rustc.rs +++ b/src/macros/rustc.rs @@ -1,3 +1,5 @@ +use std::process::Command; + use proc_macro::TokenStream; use quote::quote; @@ -27,3 +29,32 @@ pub(super) fn flags_capture(args: TokenStream) -> TokenStream { ret.into() } + +pub(super) fn version(args: TokenStream) -> TokenStream { + let Some(_) = get_crate_name() else { + return args; + }; + + let rustc_path = std::env::args() + .next() + .expect("Path to rustc executable"); + + let version = Command::new(rustc_path) + .args(["-V"]) + .output() + .map(|output| { + str::from_utf8(&output.stdout) + .map(str::trim) + .map(String::from) + .ok() + }) + .ok() + .flatten() + .unwrap_or_default(); + + let ret = quote! { + static RUSTC_VERSION: &'static str = #version; + }; + + ret.into() +}