-
Notifications
You must be signed in to change notification settings - Fork 22
/
build.rs
104 lines (95 loc) · 3.03 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use eyre::{bail, eyre, Result, WrapErr as _};
use std::{
env::{var, VarError},
fs,
path::Path,
process::Command,
};
use time::{format_description::well_known::Rfc3339, OffsetDateTime, UtcOffset};
fn main() -> Result<()> {
let commit = rerun_if_git_changes().unwrap_or_else(|e| {
eprintln!("Warning: {}", e);
None
});
println!(
"cargo:rustc-env=COMMIT_SHA={}",
env_or_cmd("COMMIT_SHA", &["git", "rev-parse", "HEAD"]).unwrap_or_else(|e| {
eprintln!("Warning: {}", e);
commit.unwrap_or_else(|| "0000000000000000000000000000000000000000".to_string())
})
);
let build_date = OffsetDateTime::now_utc();
let commit_date = env_or_cmd("COMMIT_DATE", &[
"git",
"log",
"-n1",
"--pretty=format:'%aI'",
])
.and_then(|str| Ok(OffsetDateTime::parse(str.trim_matches('\''), &Rfc3339)?))
.unwrap_or_else(|e| {
eprintln!("Warning: {}", e);
OffsetDateTime::UNIX_EPOCH
});
println!(
"cargo:rustc-env=COMMIT_DATE={}",
commit_date.to_offset(UtcOffset::UTC).date()
);
println!(
"cargo:rustc-env=BUILD_DATE={}",
build_date.to_offset(UtcOffset::UTC).date()
);
println!(
"cargo:rustc-env=TARGET={}",
var("TARGET").wrap_err("Fetching environment variable TARGET")?
);
Ok(())
}
fn env_or_cmd(env: &str, cmd: &[&str]) -> Result<String> {
// Try env first
match var(env) {
Ok(s) => return Ok(s),
Err(VarError::NotPresent) => (),
Err(e) => bail!(e),
};
// Try command
let err = || {
format!(
"Variable {} is unset and command \"{}\" failed",
env,
cmd.join(" ")
)
};
let output = Command::new(cmd[0])
.args(&cmd[1..])
.output()
.with_context(err)?;
if output.status.success() {
Ok(String::from_utf8(output.stdout)?.trim().to_string())
} else {
bail!(err())
}
}
fn rerun_if_git_changes() -> Result<Option<String>> {
let git_head = Path::new(".git/HEAD");
// Skip if not in a git repo
if !git_head.exists() {
eprintln!("No .git/HEAD found, not rerunning on git change");
return Ok(None);
}
// TODO: Worktree support where `.git` is a file
println!("cargo:rerun-if-changed=.git/HEAD");
// If HEAD contains a ref, then echo that path also.
let contents = fs::read_to_string(git_head).wrap_err("Error reading .git/HEAD")?;
let head_ref = contents.split(": ").collect::<Vec<_>>();
let commit = if head_ref.len() == 2 && head_ref[0] == "ref" {
let ref_path = Path::new(".git").join(head_ref[1].trim());
let ref_path_str = ref_path
.to_str()
.ok_or_else(|| eyre!("Could not convert ref path {:?} to string", ref_path))?;
println!("cargo:rerun-if-changed={}", ref_path_str);
fs::read_to_string(&ref_path).with_context(|| format!("Error reading {}", ref_path_str))?
} else {
contents
};
Ok(Some(commit))
}