diff --git a/zebrad/build.rs b/zebrad/build.rs index 34c707c3..b4ae359f 100644 --- a/zebrad/build.rs +++ b/zebrad/build.rs @@ -1,13 +1,107 @@ -extern crate vergen; +#![allow(clippy::try_err)] + +use std::{env, fs, fs::File, io::Read, path::PathBuf}; use vergen::{generate_cargo_keys, ConstantsFlags}; fn main() { - // Setup the flags, toggling off the 'SEMVER_FROM_CARGO_PKG' flag let mut flags = ConstantsFlags::empty(); flags.toggle(ConstantsFlags::SHA_SHORT); - flags.toggle(ConstantsFlags::REBUILD_ON_HEAD_CHANGE); + + // We want to use REBUILD_ON_HEAD_CHANGE here, but vergen assumes that the + // git directory is in the crate directory, and Zebra uses a workspace. + // See rustyhorde/vergen#15 and rustyhorde/vergen#21 for details. + let result = generate_rebuild_key(); + if let Err(err) = result { + eprintln!("Error generating 'cargo:rerun-if-changed': {:?}", err); + } // Generate the 'cargo:' key output generate_cargo_keys(flags).expect("Unable to generate the cargo keys!"); } + +/// Generate the `cargo:` rebuild keys output +/// +/// The keys that can be generated include: +/// * `cargo:rustc-rerun-if-changed=/HEAD` +/// * `cargo:rustc-rerun-if-changed=` +fn generate_rebuild_key() -> Result<(), Box> { + // Look for .git and ../.git + // We should really use the `git2` crate here, see rustyhorde/vergen#15 + let mut git_dir_or_file = env::current_dir()?.join(".git"); + let mut metadata = fs::metadata(&git_dir_or_file); + // git searches all the ancestors of the current directory, but Zebra's + // crates are direct children of the workspace directory, so we only + // need to look at the parent directory + if metadata.is_err() { + git_dir_or_file = env::current_dir()? + .parent() + .ok_or("finding crate's parent directory")? + .to_path_buf() + .join(".git"); + metadata = fs::metadata(&git_dir_or_file); + } + + // Modified from vergen's REBUILD_ON_HEAD_CHANGE implementation: + // https://github.com/rustyhorde/vergen/blob/master/src/output/envvar.rs#L46 + if let Ok(metadata) = metadata { + if metadata.is_dir() { + // Echo the HEAD path + let git_head_path = git_dir_or_file.join("HEAD"); + println!("cargo:rerun-if-changed={}", git_head_path.display()); + + // Determine where HEAD points and echo that path also. + let mut f = File::open(&git_head_path)?; + let mut git_head_contents = String::new(); + let _ = f.read_to_string(&mut git_head_contents)?; + eprintln!("HEAD contents: {}", git_head_contents); + let ref_vec: Vec<&str> = git_head_contents.split(": ").collect(); + + if ref_vec.len() == 2 { + let current_head_file = ref_vec[1].trim(); + let git_refs_path = git_dir_or_file.join(current_head_file); + println!("cargo:rerun-if-changed={}", git_refs_path.display()); + } else { + eprintln!("You are most likely in a detached HEAD state"); + } + } else if metadata.is_file() { + // We are in a worktree, so find out where the actual worktrees//HEAD file is. + let mut git_file = File::open(&git_dir_or_file)?; + let mut git_contents = String::new(); + let _ = git_file.read_to_string(&mut git_contents)?; + let dir_vec: Vec<&str> = git_contents.split(": ").collect(); + eprintln!(".git contents: {}", git_contents); + let git_path = dir_vec[1].trim(); + + // Echo the HEAD path + let git_head_path = PathBuf::from(git_path).join("HEAD"); + println!("cargo:rerun-if-changed={}", git_head_path.display()); + + // Find out what the full path to the .git dir is. + let mut actual_git_dir = PathBuf::from(git_path); + actual_git_dir.pop(); + actual_git_dir.pop(); + + // Determine where HEAD points and echo that path also. + let mut f = File::open(&git_head_path)?; + let mut git_head_contents = String::new(); + let _ = f.read_to_string(&mut git_head_contents)?; + eprintln!("HEAD contents: {}", git_head_contents); + let ref_vec: Vec<&str> = git_head_contents.split(": ").collect(); + + if ref_vec.len() == 2 { + let current_head_file = ref_vec[1].trim(); + let git_refs_path = actual_git_dir.join(current_head_file); + println!("cargo:rerun-if-changed={}", git_refs_path.display()); + } else { + eprintln!("You are most likely in a detached HEAD state"); + } + } else { + Err("Invalid .git format (Not a directory or a file)")?; + }; + } else { + Err(".git directory or file not found in crate dir or parent dir")?; + }; + + Ok(()) +}