use std::path::{Path, PathBuf}; use std::process::Command; #[derive(Debug, Eq, PartialEq)] pub struct BuildGitMetadata { pub rerun_paths: Vec, pub short_sha: String, } pub fn collect_from(package_dir: &Path) -> BuildGitMetadata { let mut rerun_paths = Vec::new(); if let Some(head_path) = git_output(package_dir, ["rev-parse", "--git-path", "HEAD"]) { rerun_paths.push(PathBuf::from(head_path)); } if let Some(head_ref) = git_output(package_dir, ["symbolic-ref", "-q", "HEAD"]) { if let Some(ref_path) = git_output(package_dir, ["rev-parse", "--git-path", &head_ref]) { rerun_paths.push(PathBuf::from(ref_path)); } } let short_sha = git_output(package_dir, ["rev-list", "-1", "HEAD"]) .map(|sha| { if sha.len() >= 7 { sha[..7].to_string() } else { sha } }) .unwrap_or_default(); BuildGitMetadata { rerun_paths, short_sha, } } #[expect( clippy::disallowed_methods, reason = "Build scripts read Cargo-provided PROFILE outside application runtime configuration." )] pub fn cargo_profile() -> String { std::env::var("PROFILE").unwrap_or_default() } #[expect( clippy::disallowed_methods, reason = "Build scripts run outside Tokio and need synchronous git probes for embedded build metadata." )] fn git_output(package_dir: &Path, args: [&str; N]) -> Option { Command::new("git") .current_dir(package_dir) .args(args) .output() .ok() .and_then(|output| { if output.status.success() { String::from_utf8(output.stdout) .ok() .map(|output| output.trim().to_string()) } else { None } }) .filter(|output| !output.is_empty()) }