1#![deny(clippy::pedantic)]
2
3pub mod envs;
30
31use std::env;
32use std::path::Path;
33use std::process::Command;
34
35use crate::envs::{FEDIMINT_BUILD_CODE_VERSION_ENV, FORCE_GIT_HASH_ENV};
36
37fn set_code_version_inner() -> Result<(), String> {
38 println!("cargo:rerun-if-env-changed={FORCE_GIT_HASH_ENV}");
39
40 if let Ok(hash) = env::var(FORCE_GIT_HASH_ENV) {
41 eprintln!("Forced hash via {FORCE_GIT_HASH_ENV} to {hash}");
42 println!("cargo:rustc-env={FEDIMINT_BUILD_CODE_VERSION_ENV}={hash}");
43 return Ok(());
44 }
45
46 if let Ok(file) = std::fs::File::open("./.cargo_vcs_info.json") {
49 let info: serde_json::Value = serde_json::from_reader(file)
50 .map_err(|e| format!("Failed to parse .cargo_vcs_info.json: {e}"))?;
51 let hash = info["git"]["sha1"].as_str().ok_or_else(|| {
52 format!("Failed to parse .cargo_vcs_info.json: no `.git.sha` field: {info:?}")
53 })?;
54 println!("cargo:rustc-env={FEDIMINT_BUILD_CODE_VERSION_ENV}={hash}");
55 return Ok(());
56 }
57
58 for base in [
65 ".",
68 "..",
69 "../..",
70 "../../..",
71 "../../../..",
72 "../../../../..",
73 ] {
74 let p = &format!("{base}/.git/HEAD");
75 if Path::new(&p).exists() {
76 println!("cargo:rerun-if-changed={p}");
77 }
78 let p = &format!("{base}/HEAD");
80 if Path::new(&p).exists() {
81 println!("cargo:rerun-if-changed={p}");
82 }
83 }
84
85 let hash = call_cmd("git", &["rev-parse", "HEAD"])?;
86
87 let dirty = !call_cmd("git", &["status", "--porcelain"])?.is_empty();
88
89 let hash = if dirty {
90 format!("{}00000000{}", &hash[0..16], &hash[(40 - 16)..40])
95 } else {
96 hash
97 };
98
99 println!("cargo:rustc-env={FEDIMINT_BUILD_CODE_VERSION_ENV}={hash}");
100
101 Ok(())
102}
103
104fn call_cmd(cmd: &str, args: &[&str]) -> Result<String, String> {
105 let output = match Command::new(cmd).args(args).output() {
106 Ok(output) => output,
107 Err(e) => {
108 return Err(format!("Failed to execute `git` command: {e}"));
109 }
110 };
111
112 if !output.status.success() {
113 return Err(format!(
114 "`git` command failed: stderr: {}; stdout: {}",
115 String::from_utf8_lossy(&output.stderr),
116 String::from_utf8_lossy(&output.stdout)
117 ));
118 }
119
120 match String::from_utf8(output.stdout) {
121 Ok(o) => Ok(o.trim().to_string()),
122 Err(e) => Err(format!("Invalid UTF-8 sequence detected: {e}")),
123 }
124}
125
126pub fn set_code_version() {
129 if let Err(e) = set_code_version_inner() {
130 eprintln!(
131 "Failed to detect git hash version: {e}. Set {FORCE_GIT_HASH_ENV} to enforce the version and skip auto-detection."
132 );
133 println!(
134 "cargo:rustc-env={FEDIMINT_BUILD_CODE_VERSION_ENV}=0000000000000000000000000000000000000000"
135 );
136 }
137}