-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
66 lines (60 loc) · 2.81 KB
/
Copy pathbuild.rs
File metadata and controls
66 lines (60 loc) · 2.81 KB
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
//! Stamps the checkout's identity into the binary.
//!
//! `kuma --version` reporting only `0.2.0` would answer the least useful
//! question. Twice now a change has looked broken because the installed
//! binary predated it: the niri portal fix appeared not to work, and a
//! wallpaper swap would have silently baked the old asset. Both times the
//! binary looked fine and said nothing. The commit it was built from, and
//! whether the tree was clean at the time, is the thing worth carrying.
//!
//! Both values degrade to "unknown" rather than failing the build. A
//! release tarball has no `.git`, and a build from one is still valid.
use std::path::Path;
use std::process::Command;
fn main() {
// Emitting any rerun-if-changed opts out of cargo's default, which is
// to rerun on any file in the package. So the git internals AND the
// sources have to be named: HEAD and the ref catch a commit or a
// branch switch, the sources catch the edits that make a tree dirty.
// Miss the first group and a fresh commit keeps the old sha; miss the
// second and "-dirty" outlives the edit that earned it.
println!("cargo:rerun-if-changed=.git/HEAD");
println!("cargo:rerun-if-changed=.git/index");
if let Some(head_ref) = git(&["rev-parse", "--symbolic-full-name", "HEAD"]) {
let path = format!(".git/{head_ref}");
if Path::new(&path).exists() {
println!("cargo:rerun-if-changed={path}");
}
}
for path in ["src", "assets", "Cargo.toml", "Cargo.lock"] {
println!("cargo:rerun-if-changed={path}");
}
let sha = match git(&["rev-parse", "--short=7", "HEAD"]) {
Some(sha) if dirty() => format!("{sha}-dirty"),
Some(sha) => sha,
None => "unknown".to_string(),
};
// The commit's own date, not the build's: two builds of one commit
// describe the same code, and saying otherwise invites the belief
// that a rebuild changed something.
let date = git(&["log", "-1", "--format=%cd", "--date=short"])
.unwrap_or_else(|| "unknown".to_string());
println!("cargo:rustc-env=KUMA_BUILD_SHA={sha}");
println!("cargo:rustc-env=KUMA_BUILD_DATE={date}");
}
/// Trimmed stdout of a successful `git`, or None if git is missing, this
/// is not a repository, or the command failed.
fn git(args: &[&str]) -> Option<String> {
let out = Command::new("git").args(args).output().ok()?;
if !out.status.success() {
return None;
}
let text = String::from_utf8(out.stdout).ok()?.trim().to_string();
(!text.is_empty()).then_some(text)
}
/// Whether the working tree has changes the sha does not describe.
/// Untracked files count: an asset that exists only locally is baked into
/// the binary exactly like a tracked one.
fn dirty() -> bool {
git(&["status", "--porcelain"]).is_some_and(|s| !s.is_empty())
}