-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
118 lines (108 loc) · 4.56 KB
/
Copy pathbuild.rs
File metadata and controls
118 lines (108 loc) · 4.56 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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Build script — bakes the product version slug + (on Windows)
//! embeds the application icon into the `window` binary.
//!
//! ## Version slug
//!
//! Mirrors C# `VersionInfo.Display`, which reads
//! `AssemblyInformationalVersionAttribute` filled in from
//! `git describe --tags --always --dirty` via
//! `Directory.Build.targets`. We do the same here: at build time
//! we shell out to git, drop the leading `v`, and expose the
//! result as the `CODESCOPE_VERSION_DISPLAY` env var so the
//! caption row can read it via `env!`.
//!
//! Override order:
//!
//! 1. `CODESCOPE_VERSION` env var — packaging pipelines set this
//! explicitly when they don't want git-derived strings (or
//! when git isn't available).
//! 2. `git describe --tags --always --dirty` — normal dev /
//! release builds. Leading `v` / `V` is stripped so the chrome
//! can prefix its own `V` consistently.
//! 3. `0.0-unknown` — last-resort fallback so the slug is
//! obviously a placeholder rather than masquerading as a real
//! version (`CARGO_PKG_VERSION` would print `0.0.1`, which
//! would look like a product release).
//!
//! ## Icon
//!
//! Mirrors `<ApplicationIcon>assets\codescope.ico</ApplicationIcon>`
//! from the C# build's `CodeScope.App.csproj`. The resource script
//! at `assets/codescope.rc` references `codescope.ico` under
//! resource ID `1`, which is what Windows looks up when it needs
//! "the" icon for an executable. No-op on non-Windows hosts.
use std::path::PathBuf;
use std::process::Command;
fn main() {
bake_version_slug();
#[cfg(windows)]
embed_resource::compile("assets/codescope.rc", embed_resource::NONE)
.manifest_optional()
.expect("compile codescope.rc");
}
fn bake_version_slug() {
// Always honour the env-var override first so packaging
// pipelines can pin the slug regardless of what's checked out.
println!("cargo:rerun-if-env-changed=CODESCOPE_VERSION");
if let Ok(explicit) = std::env::var("CODESCOPE_VERSION") {
let v = strip_v_prefix(explicit.trim());
println!("cargo:rustc-env=CODESCOPE_VERSION_DISPLAY={v}");
return;
}
let display = git_describe().unwrap_or_else(|| "0.0-unknown".into());
println!("cargo:rustc-env=CODESCOPE_VERSION_DISPLAY={display}");
// `rerun-if-changed` for the *real* git refs so a fresh commit
// or tag updates the slug without a `cargo clean`. The naive
// `../.git/HEAD` form misses two important shapes:
//
// * `.git` is a **file** inside a linked worktree (`git
// worktree add` writes a `gitdir:` pointer to the canonical
// workdir under `<repo>/.git/worktrees/<name>`).
// * Branch-tracked HEAD updates `refs/heads/<branch>` (and
// `packed-refs` after a gc), not `HEAD` itself.
//
// Resolving via `git rev-parse --git-path` handles both.
// Failures (no git, not a repo, …) just skip the trigger — the
// env-var / fallback path above still produces a usable slug.
for relative in ["HEAD", "packed-refs", "index", "refs/tags"] {
if let Some(p) = git_path(relative)
&& p.exists() {
println!("cargo:rerun-if-changed={}", p.display());
}
}
// The current branch's actual ref file. Resolves even when
// packed (in which case the file may not exist; we already
// watch `packed-refs` above).
if let Some(symref) = run_git(&["symbolic-ref", "--quiet", "HEAD"])
&& let Some(p) = git_path(&symref)
&& p.exists() {
println!("cargo:rerun-if-changed={}", p.display());
}
}
fn strip_v_prefix(s: &str) -> String {
s.strip_prefix('v').or_else(|| s.strip_prefix('V')).unwrap_or(s).to_owned()
}
fn run_git(args: &[&str]) -> Option<String> {
let output = Command::new("git")
.args(args)
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.ok()?;
if !output.status.success() {
return None;
}
let s = String::from_utf8_lossy(&output.stdout).trim().to_owned();
if s.is_empty() { None } else { Some(s) }
}
fn git_path(relative: &str) -> Option<PathBuf> {
let raw = run_git(&["rev-parse", "--git-path", relative])?;
Some(PathBuf::from(raw))
}
fn git_describe() -> Option<String> {
// Release tags are `vX.Y.Z` (or `vX.Y.Z-rc.N`). Historical C#
// `v0.2.X` tags resolve here too on a checkout of that legacy
// history; stamping the binary with the historical version is
// correct for that checkout.
let raw = run_git(&["describe", "--tags", "--always", "--dirty", "--match", "v*"])?;
Some(strip_v_prefix(&raw))
}