forked from stacked-git/stgit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.rs
92 lines (87 loc) · 3.53 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
fn main() {
let git_output = std::process::Command::new("git")
.args(["rev-parse", "--git-dir"])
.output()
.ok();
let git_dir = git_output.as_ref().and_then(|output| {
std::str::from_utf8(&output.stdout)
.ok()
.and_then(|s| s.strip_suffix('\n').or_else(|| s.strip_suffix("\r\n")))
});
// Tell cargo to rebuild if the head or any relevant refs change.
if let Some(git_dir) = git_dir {
let git_path = std::path::Path::new(git_dir);
let refs_path = git_path.join("refs");
if git_path.join("HEAD").exists() {
println!("cargo:rerun-if-changed={git_dir}/HEAD");
}
if git_path.join("packed-refs").exists() {
println!("cargo:rerun-if-changed={git_dir}/packed-refs");
}
if refs_path.join("heads").exists() {
println!("cargo:rerun-if-changed={git_dir}/refs/heads");
}
if refs_path.join("tags").exists() {
println!("cargo:rerun-if-changed={git_dir}/refs/tags");
}
}
let git_output = std::process::Command::new("git")
.args([
"describe",
"--match=v*",
"--abbrev=9",
"--long",
"--dirty=*",
])
.output()
.ok();
let git_hash = git_output
.as_ref()
.and_then(|output| std::str::from_utf8(&output.stdout).ok().map(str::trim))
// E.g. "v2.0.0-beta.2-7-g12ab34cd56*"
// ttttttttttttt N hhhhhhhhhhhD
// t => last matching annotated tag
// N => distance (in commits) from tag
// h => git commit id (hash)
// D => work tree dirty flag
//
// N.B. Since the tag may have '-' characters, the description string is parsed
// from right to left.
.and_then(|desc| {
desc.rsplit_once('-').and_then(|(tag_and_distance, hash)| {
let hash = hash
.strip_prefix('g')
.expect("git hash component starts with 'g'");
let dirty = hash.ends_with('*');
tag_and_distance
.rsplit_once('-')
.and_then(|(tag, distance_from_tag)| {
let tag = tag
.strip_prefix('v')
.expect("last annotated tag starts with 'v'");
let distance_from_tag = distance_from_tag
.parse::<usize>()
.expect("distance from tag is usize");
let cargo_pkg_version = env!("CARGO_PKG_VERSION");
if tag != cargo_pkg_version {
println!(
"cargo:warning=\
version from Cargo.toml, \"{cargo_pkg_version}\", \
does not match last annotated tag \"{tag}\""
);
}
if tag == cargo_pkg_version && distance_from_tag == 0 && !dirty {
// Do not use/display hash when the cargo version exactly
// matches the latest annotated tag.
None
} else {
Some(hash)
}
})
})
});
// Make the current git hash available to the build.
if let Some(git_hash) = git_hash {
println!("cargo:rustc-env=STGIT_BUILD_GIT_HASH={git_hash}");
}
}