|
| 1 | +// This file is Copyright its original authors, visible in version control |
| 2 | +// history. |
| 3 | +// |
| 4 | +// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE |
| 5 | +// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 6 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. |
| 7 | +// You may not use this file except in accordance with one or both of these |
| 8 | +// licenses. |
| 9 | + |
| 10 | +use std::env; |
| 11 | +use std::path::Path; |
| 12 | +use std::process::Command; |
| 13 | + |
| 14 | +fn main() { |
| 15 | + println!("cargo:rerun-if-changed=build.rs"); |
| 16 | + println!("cargo:rerun-if-env-changed=GIT_HASH"); |
| 17 | + |
| 18 | + // Re-run the build script whenever the checked-out commit changes so the |
| 19 | + // embedded hash never goes stale. HEAD lives in the (possibly worktree-local) |
| 20 | + // git dir, while branch refs and packed-refs live in the common git dir. |
| 21 | + if let Some(git_dir) = git_output(&["rev-parse", "--git-dir"]) { |
| 22 | + watch_path(&Path::new(&git_dir).join("HEAD")); |
| 23 | + } |
| 24 | + if let Some(common_dir) = git_output(&["rev-parse", "--git-common-dir"]) { |
| 25 | + let common_dir = Path::new(&common_dir); |
| 26 | + watch_path(&common_dir.join("packed-refs")); |
| 27 | + // If HEAD points at a ref, watch that ref file too (it changes on commit). |
| 28 | + // Watch it even when it does not exist yet: packed refs become loose |
| 29 | + // files on the next commit, and Cargo can detect that creation. |
| 30 | + if let Some(ref_path) = git_output(&["symbolic-ref", "-q", "HEAD"]) { |
| 31 | + watch_path(&common_dir.join(ref_path)); |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + let git_hash = git_output(&["rev-parse", "HEAD"]) |
| 36 | + .or_else(|| env::var("GIT_HASH").ok()) |
| 37 | + .unwrap_or_else(|| "unknown".to_string()); |
| 38 | + println!("cargo:rustc-env=GIT_HASH={git_hash}"); |
| 39 | +} |
| 40 | + |
| 41 | +/// Runs `git` with the given args, returning the trimmed stdout on success or |
| 42 | +/// `None` if git is unavailable, exits non-zero, or produces no output. |
| 43 | +fn git_output(args: &[&str]) -> Option<String> { |
| 44 | + let output = Command::new("git").args(args).output().ok()?; |
| 45 | + if !output.status.success() { |
| 46 | + return None; |
| 47 | + } |
| 48 | + let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string(); |
| 49 | + if stdout.is_empty() { |
| 50 | + None |
| 51 | + } else { |
| 52 | + Some(stdout) |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +fn watch_path(path: &Path) { |
| 57 | + println!("cargo:rerun-if-changed={}", path.display()); |
| 58 | +} |
0 commit comments