use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=scripts/auto-setup-hooks.sh");
println!("cargo:rerun-if-changed=.git/hooks/pre-commit");
if should_skip_hooks_setup() {
return;
}
if !is_git_repository() {
return;
}
if hooks_already_installed() {
if let Some(marker) = get_marker_file() {
if !marker.exists() {
create_marker_file(&marker);
}
}
return;
}
if let Some(marker) = get_marker_file() {
install_git_hooks(&marker);
}
}
fn should_skip_hooks_setup() -> bool {
let is_ci = env::var("CI").is_ok()
|| env::var("GITHUB_ACTIONS").is_ok()
|| env::var("GITLAB_CI").is_ok()
|| env::var("CIRCLECI").is_ok()
|| env::var("TRAVIS").is_ok();
if is_ci {
return true;
}
if let Ok(profile) = env::var("PROFILE") {
if profile == "release" {
return true;
}
}
if env::var("SKIP_GIT_HOOKS_SETUP").is_ok() {
return true;
}
false
}
fn is_git_repository() -> bool {
Path::new(".git").exists()
}
fn get_marker_file() -> Option<PathBuf> {
let target_dir = Path::new("target");
if !target_dir.exists() {
if let Err(e) = fs::create_dir_all(target_dir) {
eprintln!("cargo:warning=Could not create target directory: {}", e);
return None;
}
}
Some(target_dir.join(".git-hooks-installed"))
}
fn hooks_already_installed() -> bool {
let hook_path = Path::new(".git/hooks/pre-commit");
if !hook_path.exists() {
return false;
}
match fs::read_to_string(hook_path) {
Ok(content) => content.contains("cargo fmt"),
Err(_) => false,
}
}
fn create_marker_file(marker_path: &Path) {
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
let content = format!(
"Git hooks installed by build.rs\nTimestamp: {}\n",
timestamp
);
if let Err(e) = fs::write(marker_path, content) {
eprintln!("cargo:warning=Could not create marker file: {}", e);
}
}
fn install_git_hooks(marker_path: &Path) {
let setup_script = Path::new("scripts/auto-setup-hooks.sh");
if !setup_script.exists() {
eprintln!(
"cargo:warning=Setup script not found: {}",
setup_script.display()
);
return;
}
println!("cargo:warning=🔧 Setting up git pre-commit hooks for auto-formatting...");
let bash_cmd = find_bash_command();
match Command::new(&bash_cmd)
.arg(setup_script)
.current_dir(".")
.output()
{
Ok(output) => {
if output.status.success() {
create_marker_file(marker_path);
println!("cargo:warning=✅ Git hooks configured! Commits will be auto-formatted.");
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!(
"cargo:warning=⚠️ Hook installation failed: {}",
stderr.trim()
);
eprintln!(
"cargo:warning=Run ./scripts/setup-git-hooks.sh manually to install hooks."
);
}
},
Err(e) => {
eprintln!("cargo:warning=⚠️ Could not execute setup script: {}", e);
eprintln!("cargo:warning=Bash may not be available on your system.");
eprintln!("cargo:warning=Run ./scripts/setup-git-hooks.sh manually to install hooks.");
},
}
}
fn find_bash_command() -> String {
let bash_candidates = vec![
"bash", "/bin/bash", "/usr/bin/bash", "sh", ];
for bash in bash_candidates {
if Command::new(bash).arg("--version").output().is_ok() {
return bash.to_string();
}
}
"bash".to_string()
}