aboutsummaryrefslogtreecommitdiff
path: root/apps/fparkan-vulkan-smoke/build.rs
blob: 24da219adb85aa472e933c6829b7e434497b5c9b (plain) (blame)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Build-time provenance for native smoke artifacts.

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    println!("cargo:rerun-if-env-changed=TARGET");
    println!("cargo:rerun-if-env-changed=RUSTC");
    println!("cargo:rerun-if-env-changed=RUSTUP_TOOLCHAIN");
    println!("cargo:rerun-if-env-changed=GITHUB_SHA");
    println!("cargo:rerun-if-env-changed=SOURCE_VERSION");
    println!("cargo:rerun-if-env-changed=BUILD_VCS_NUMBER");

    if let Ok(target) = env::var("TARGET") {
        println!("cargo:rustc-env=FPARKAN_BUILD_TARGET_TRIPLE={target}");
    }
    if let Some(toolchain) = rustc_release() {
        println!("cargo:rustc-env=FPARKAN_BUILD_RUST_TOOLCHAIN={toolchain}");
    }

    if let Some(workspace_root) = workspace_root() {
        if let Some(git_dir) = git_dir(&workspace_root) {
            emit_git_rerun_hints(&git_dir);
        }

        if let Some(commit_sha) = env_commit_sha().or_else(|| git_head_commit_sha(&workspace_root))
        {
            println!("cargo:rustc-env=FPARKAN_BUILD_COMMIT_SHA={commit_sha}");
        }
        if let Some(git_dirty) = git_dirty(&workspace_root) {
            println!("cargo:rustc-env=FPARKAN_BUILD_GIT_DIRTY={git_dirty}");
        }
    }
}

fn workspace_root() -> Option<PathBuf> {
    env::var_os("CARGO_MANIFEST_DIR")
        .map(PathBuf::from)
        .map(|manifest_dir| manifest_dir.join("../.."))
}

fn env_commit_sha() -> Option<String> {
    ["GITHUB_SHA", "SOURCE_VERSION", "BUILD_VCS_NUMBER"]
        .into_iter()
        .filter_map(|name| env::var(name).ok())
        .find(|value| is_commit_sha(value))
}

fn git_head_commit_sha(workspace_root: &Path) -> Option<String> {
    let output = Command::new("git")
        .args(["-C"])
        .arg(workspace_root)
        .args(["rev-parse", "HEAD"])
        .output()
        .ok()?;
    if !output.status.success() {
        return None;
    }
    let value = String::from_utf8(output.stdout).ok()?;
    let value = value.trim().to_string();
    is_commit_sha(&value).then_some(value)
}

fn git_dirty(workspace_root: &Path) -> Option<bool> {
    let output = Command::new("git")
        .args(["-C"])
        .arg(workspace_root)
        .args(["status", "--short"])
        .output()
        .ok()?;
    output
        .status
        .success()
        .then(|| !String::from_utf8_lossy(&output.stdout).trim().is_empty())
}

fn git_dir(workspace_root: &Path) -> Option<PathBuf> {
    let output = Command::new("git")
        .args(["-C"])
        .arg(workspace_root)
        .args(["rev-parse", "--git-dir"])
        .output()
        .ok()?;
    if !output.status.success() {
        return None;
    }
    let value = String::from_utf8(output.stdout).ok()?;
    let value = value.trim();
    (!value.is_empty()).then(|| workspace_root.join(value))
}

fn emit_git_rerun_hints(git_dir: &Path) {
    let head = git_dir.join("HEAD");
    println!("cargo:rerun-if-changed={}", head.display());
    println!(
        "cargo:rerun-if-changed={}",
        git_dir.join("packed-refs").display()
    );
    println!("cargo:rerun-if-changed={}", git_dir.join("index").display());
    let Some(reference) = std::fs::read_to_string(&head).ok().and_then(|value| {
        value
            .strip_prefix("ref: ")
            .map(str::trim)
            .map(ToOwned::to_owned)
    }) else {
        return;
    };
    println!(
        "cargo:rerun-if-changed={}",
        git_dir.join(reference).display()
    );
}

fn is_commit_sha(value: &str) -> bool {
    value.len() == 40 && value.chars().all(|ch| ch.is_ascii_hexdigit())
}

fn rustc_release() -> Option<String> {
    let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
    let output = Command::new(rustc).arg("-Vv").output().ok()?;
    if !output.status.success() {
        return None;
    }
    String::from_utf8(output.stdout)
        .ok()?
        .lines()
        .find_map(|line| {
            line.strip_prefix("release: ")
                .map(str::trim)
                .filter(|value| !value.is_empty())
                .map(ToString::to_string)
        })
}