[英]Include git commit hash as string into Rust program
我在 git 存儲庫中托管了一個 Rust 項目,我想讓它在某些命令上打印版本。 如何將版本包含在程序中? 我認為構建腳本可以設置可以在編譯項目本身時使用的環境變量,但它不起作用:
構建.rs :
use std::env;
fn get_git_hash() -> Option<String> {
use std::process::Command;
let branch = Command::new("git")
.arg("rev-parse")
.arg("--abbrev-ref")
.arg("HEAD")
.output();
if let Ok(branch_output) = branch {
let branch_string = String::from_utf8_lossy(&branch_output.stdout);
let commit = Command::new("git")
.arg("rev-parse")
.arg("--verify")
.arg("HEAD")
.output();
if let Ok(commit_output) = commit {
let commit_string = String::from_utf8_lossy(&commit_output.stdout);
return Some(format!("{}, {}",
branch_string.lines().next().unwrap_or(""),
commit_string.lines().next().unwrap_or("")))
} else {
panic!("Can not get git commit: {}", commit_output.unwrap_err());
}
} else {
panic!("Can not get git branch: {}", branch.unwrap_err());
}
None
}
fn main() {
if let Some(git) = get_git_hash() {
env::set_var("GIT_HASH", git);
}
}
src/main.rs:
pub const GIT_HASH: &'static str = env!("GIT_HASH");
fm main() {
println!("Git hash: {}", GIT_HASH);
}
錯誤信息:
error: environment variable `GIT_HASH` not defined
--> src/main.rs:10:25
|
10 | pub const GIT_HASH: &'static str = env!("GIT_HASH");
|
^^^^^^^^^^^^^^^^
有沒有辦法在編譯時傳遞這些數據? 如果不使用環境變量,如何在構建腳本和源代碼之間進行通信? 我只能考慮將數據寫入某個文件,但我認為這對於這種情況來說太過分了。
從 Rust 1.19 (cargo 0.20.0) 開始,感謝https://github.com/rust-lang/cargo/pull/3929 ,您現在可以為rustc
定義一個編譯時環境變量( env!(…)
)和rustdoc
通過:
println!("cargo:rustc-env=KEY=value");
所以OP的程序可以寫成:
// build.rs
use std::process::Command;
fn main() {
// note: add error checking yourself.
let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}
// main.rs
fn main() {
println!("{}", env!("GIT_HASH"));
// output something like:
// 7480b50f3c75eeed88323ec6a718d7baac76290d
}
請注意,如果您仍想支持 1.18 或更低版本,則仍然無法使用它。
已經有一個現有的 crate vergen
可以計算構建腳本中的 git commit。 正如vergen
的回答所述,構建腳本無法在 Rust 1.19 之前修改環境變量,因此vergen
仍然可以通過將結果寫入 OUT_DIR 來工作(即vergen
仍然無法解決 OP 的問題,但它應該更易於使用)。
用法:
# Cargo.toml
...
[build-dependencies]
vergen = "0.1"
// build.rs
extern crate vergen;
use vergen::*;
fn main() {
vergen(SHORT_SHA | COMMIT_DATE).unwrap();
}
mod version {
include!(concat!(env!("OUT_DIR"), "/version.rs"));
}
fn main() {
println!("commit: {} {}", version::commit_date(), version::short_sha());
// output something like:
// commit: 2017-05-03 a29c7e5
}
呃。 (我不建議在生產或測試或公共代碼甚至私有代碼中使用它,但我的意思是,它有點工作?)
const REF: &str = include_str!("../.git/HEAD");
const REF_MASTER: &str = include_str!("../.git/refs/heads/master");
// (elsewhere)
if REF == "ref: refs/heads/master" { REF_MASTER } else { REF }
(除非您正在制作某種代碼高爾夫,否則不要使用它。請注意,這是 100% 未經測試的。)
有一種簡單的方法可以做到這一點,而無需任何build.rs邏輯或自定義板條箱。 您只需將當前的 git hash 作為環境變量直接傳遞給構建命令,並在您的程序中使用option_env!("PROJECT_VERSION")
讀取它,並使用env!("CARGO_PKG_VERSION")
回退。 這些宏在構建期間讀取環境變量。
下面的示例構建了這個最小的src/main.rs :
fn main() {
let version = option_env!("PROJECT_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
println!("This binary was built from {}", version);
}
當您構建程序並想要准確的 git 哈希值時,例如在您的 CI/CD 配置中,您可以在貨物命令前加上PROJECT_VERSION=$(git rev-parse --short HEAD)
前綴。 像這樣的cargo run
(但也適用於cargo build
和其他):
% PROJECT_VERSION=$(git rev-parse --short HEAD) cargo run
This binary was built from 6ca63b2
我個人更喜歡$(git describe)
不是$(git rev-parse)
因為前者更具描述性(現在使用cargo build
作為示例只是為了變化):
% PROJECT_VERSION=$(git describe) cargo build
% ./target/debug/your-program
This binary was built from v0.3.0-15-g6ca63b2 # or just 'v0.3.0' if current commit is tagged with that
由於您有一個CARGO_PKG_VERSION
回退,您的 IDE 仍然可以為您即時構建文件。 同樣,對於開發,您可以跳過傳遞PROJECT_VERSION
。 在這種情況下,將使用Cargo.toml
的版本:
% cargo run
This binary was built from 0.3.0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.