miden_node_utils/version/
mod.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
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#[cfg(feature = "vergen")]
pub use vergen::vergen;

/// Contains build metadata which can be formatted into a pretty --version
/// output using its Display implementation.
///
/// The build metadata can be embedded at compile time using the `vergen` function
/// available from the `vergen` feature. See that functions description for a list
/// of the environment variables emitted which map nicely to [`LongVersion`].
///
/// Unfortunately these values must be transferred manually by the end user since the
/// env variables are only available once the caller's build script has run - which is
/// after this crate is compiled.
pub struct LongVersion {
    pub version: &'static str,
    pub sha: &'static str,
    pub branch: &'static str,
    pub dirty: &'static str,
    pub features: &'static str,
    pub rust_version: &'static str,
    pub host: &'static str,
    pub target: &'static str,
    pub opt_level: &'static str,
    pub debug: &'static str,
}

impl std::fmt::Display for LongVersion {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self {
            version,
            mut sha,
            mut branch,
            dirty,
            features,
            rust_version,
            host,
            target,
            opt_level,
            debug,
        } = self;

        let dirty = match *dirty {
            "true" => "-dirty",
            _ => "",
        };

        // This is the default value set by `vergen` when these values are missing.
        // The git values can be missing for a published crate, and while we do attempt
        // to set default values in the build.rs, its still possible for these to be skipped
        // e.g. when cargo publish --allow-dirty is used.
        if branch == "VERGEN_IDEMPOTENT_OUTPUT" {
            branch = "";
        }
        if sha == "VERGEN_IDEMPOTENT_OUTPUT" {
            sha = "";
        }

        f.write_fmt(format_args!(
            "{version}

SHA:          {sha}{dirty}
branch:       {branch}
features:     {features}
rust version: {rust_version}
target arch:  {target}
host arch:    {host}
opt-level:    {opt_level}
debug:        {debug}
"
        ))
    }
}

#[cfg(feature = "vergen")]
mod vergen {
    use std::path::PathBuf;

    use anyhow::{Context, Result};

    /// Emits environment variables for build metadata intended for extended version information.
    ///
    /// The following environment variables are emitted:
    ///
    ///   - `VERGEN_GIT_BRANCH`
    ///   - `VERGEN_GIT_SHA`
    ///   - `VERGEN_GIT_DIRTY`
    ///   - `VERGEN_RUSTC_SEMVER`
    ///   - `VERGEN_RUSTC_HOST_TRIPLE`
    ///   - `VERGEN_CARGO_TARGET_TRIPLE`
    ///   - `VERGEN_CARGO_FEATURES`
    ///   - `VERGEN_CARGO_OPT_LEVEL`
    ///   - `VERGEN_CARGO_DEBUG`
    pub fn vergen() -> Result<()> {
        if let Some(sha) = published_git_sha().context("Checking for published vcs info")? {
            // git data is not available if in a published state, so we set them manually.
            println!("cargo::rustc-env=VERGEN_GIT_SHA={sha}");
            println!("cargo::rustc-env=VERGEN_GIT_BRANCH=NA (published)");
            println!("cargo::rustc-env=VERGEN_GIT_DIRTY=");

            vergen_gitcl::Emitter::new()
        } else {
            // In a non-published state so we can expect git instructions to work.
            let mut emitter = vergen_gitcl::Emitter::new();
            emitter
                .add_instructions(&git_instructions()?)
                .context("Adding git instructions")?;

            emitter
        }
        .add_instructions(&cargo_instructions()?)
        .context("Adding cargo instructions")?
        .add_instructions(&rustc_instructions()?)
        .context("Adding rustc instructions")?
        .emit()
    }

    /// Normal git info is lost on `cargo publish`, which instead adds a file containing the SHA1
    /// hash.
    ///
    /// This function returns the short SHA value. If present, this indicates this we're in a
    /// published state.
    fn published_git_sha() -> Result<Option<String>> {
        let cargo_vcs_info = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".cargo_vcs_info.json");
        if cargo_vcs_info.exists() {
            // The file is small so reading to string is acceptable.
            let contents = std::fs::read_to_string(cargo_vcs_info).context("Reading vcs info")?;

            // File format:
            // {
            //   "git": {
            //     "sha1": "9d48046e9654d93a86212e77d6c92f14c95de44b"
            //   },
            //   "path_in_vcs": "bin/node"
            // }
            let offset = contents.find(r#""sha1""#).context("Searching for sha1 property")?
                + r#""sha1""#.len();

            let sha1 = contents[offset + 1..]
            .chars()
            // Find and skip opening quote.
            .skip_while(|&c| c != '"')
            .skip(1)
            // Take until closing quote.
            .take_while(|&c| c != '"')
            // Short SHA format is 7 digits.
            .take(7)
            .collect();

            Ok(Some(sha1))
        } else {
            Ok(None)
        }
    }

    fn git_instructions() -> Result<vergen_gitcl::Gitcl> {
        const INCLUDE_UNTRACKED: bool = true;
        const SHORT_SHA: bool = true;

        vergen_gitcl::GitclBuilder::default()
            .branch(true)
            .dirty(INCLUDE_UNTRACKED)
            .sha(SHORT_SHA)
            .build()
            .context("Building git instructions")
    }

    fn cargo_instructions() -> Result<vergen::Cargo> {
        vergen_gitcl::CargoBuilder::default()
            .debug(true)
            .features(true)
            .target_triple(true)
            .opt_level(true)
            .build()
            .context("Building git instructions")
    }

    fn rustc_instructions() -> Result<vergen::Rustc> {
        vergen_gitcl::RustcBuilder::default()
            .semver(true)
            .host_triple(true)
            .build()
            .context("Building rustc instructions")
    }
}