Skip to content

Commit

Permalink
build-info: add dirty and revision detect (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheButlah committed Sep 19, 2024
1 parent cdf1774 commit 832962a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 23 deletions.
90 changes: 70 additions & 20 deletions build-info/helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,38 @@ const ENV_PREFIX: &str = "WORLDCOIN_BUILD_INFO_";
/// Call this from within your build script.
pub fn initialize() -> Result<()> {
color_eyre::install().ok();
let git_head_path = workspace_dir().join(".git").join("HEAD");
println!("cargo:rerun-if-changed={}", git_head_path.display());

let git_describe = read_env("GIT_DESCRIBE").unwrap_or(
std::str::from_utf8(
&Command::new("git")
.arg("describe")
.arg("--always")
.arg("--dirty=-modified")
.output()
.wrap_err("Failed to run `git describe`")
.suggestion("Is `git` installed?")?
.stdout,
)?
.trim_end()
.to_string(),
);
let git_path = workspace_dir().join(".git");
let git_head_path = git_path.join("HEAD");
let git_index_path = git_path.join("index");
for p in [git_head_path, git_index_path] {
println!("cargo:rerun-if-changed={}", p.display());
}

let git_describe = read_env("GIT_DESCRIBE")
.ok_or(())
.or_else(|()| git_describe())
.wrap_err("failed to compute value for GIT_DESCRIBE")?;
set_env("GIT_DESCRIBE", &git_describe);

let git_dirty = read_env("GIT_DIRTY")
.ok_or(())
.map(|s| match s.to_lowercase().as_str() {
"0" => false,
"1" => true,
"true" => true,
"false" => false,
_ => panic!("unexpected value"),
})
.or_else(|()| git_dirty())
.wrap_err("failed to compute value for GIT_DIRTY")?;
set_env("GIT_DIRTY", if git_dirty { "1" } else { "0" });

let git_rev_short = read_env("GIT_REV_SHORT")
.ok_or(())
.or_else(|()| git_current_rev_short())
.wrap_err("failed to compute value for GIT_REV_SHORT")?;
set_env("GIT_REV_SHORT", &git_rev_short);

Ok(())
}

Expand All @@ -49,13 +62,50 @@ fn set_env(var: &str, value: &str) {
// https://stackoverflow.com/a/74942075
fn workspace_dir() -> PathBuf {
let output = std::process::Command::new(env!("CARGO"))
.arg("locate-project")
.arg("--workspace")
.arg("--message-format=plain")
.args(["locate-project", "--workspace", "--message-format=plain"])
.output()
.unwrap()
.stdout;
let workpace_cargo_toml_path =
Path::new(std::str::from_utf8(&output).unwrap().trim());
workpace_cargo_toml_path.parent().unwrap().to_path_buf()
}

fn git_describe() -> Result<String> {
let stdout = Command::new("git")
.args(["describe", "--always", "--dirty=-modified"])
.output()
.wrap_err("Failed to run `git describe --always --dirty=-modified`")
.suggestion("Is `git` installed?")?
.stdout;
let cleaned_stdout = std::str::from_utf8(&stdout)?.trim();

Ok(cleaned_stdout.to_owned())
}

/// Uses git status to determine if the repo is dirty.
fn git_dirty() -> Result<bool> {
let stdout = Command::new("git")
.args(["status", "--porcelain"])
.output()
.wrap_err("failed to run `git status --porcelain`")
.suggestion("Is `git` installed?")?
.stdout;
let cleaned_stdout = std::str::from_utf8(&stdout)?.trim();
let is_dirty = !cleaned_stdout.is_empty();

Ok(is_dirty)
}

/// Uses git rev-parse to get the current git revision.
fn git_current_rev_short() -> Result<String> {
let stdout = Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.wrap_err("failed to run `git rev-parse --short HEAD`")
.suggestion("Is `git` installed?`")?
.stdout;
let cleaned_stdout = std::str::from_utf8(&stdout)?.trim();

Ok(cleaned_stdout.to_owned())
}
48 changes: 47 additions & 1 deletion build-info/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub struct BuildInfo {
pub struct GitInfo {
/// The result of `git describe --always --dirty=-modified`.
pub describe: &'static str,
/// Whether `git status --porcelain` returns anything or not.
pub dirty: bool,
/// The current git revision, via `git rev-parse --short HEAD`
pub rev_short: &'static str,
}

/// Information from cargo.
Expand All @@ -47,17 +51,24 @@ macro_rules! make_build_info {
const TMP: $crate::BuildInfo = $crate::BuildInfo {
git: $crate::GitInfo {
describe: $crate::prefix_env!("GIT_DESCRIBE"),
dirty: $crate::are_strs_equal(
$crate::prefix_env!("GIT_DIRTY"),
"1",
),
rev_short: $crate::prefix_env!("GIT_REV_SHORT"),
},
cargo: $crate::CargoInfo {
pkg_version: env!("CARGO_PKG_VERSION"),
},
version: "", // will be overwritten in a moment
};
const DIRTY_SUFFIX: &str = if TMP.git.dirty { "-modified" } else { "" };
let build_info = $crate::BuildInfo {
version: $crate::const_concat!(
TMP.cargo.pkg_version,
" ",
TMP.git.describe,
TMP.git.rev_short,
DIRTY_SUFFIX
),
..TMP
};
Expand All @@ -66,3 +77,38 @@ macro_rules! make_build_info {
}
};
}

#[doc(hidden)]
pub const fn are_strs_equal(a: &str, b: &str) -> bool {
if a.len() != b.len() {
return false;
}
let a = a.as_bytes();
let b = b.as_bytes();
let mut i = 0;
while i < a.len() {
if a[i] != b[i] {
return false;
}
i += 1;
}

true
}

#[cfg(test)]
mod test {
use crate::are_strs_equal;

#[test]
fn test_str_equal() {
assert!(are_strs_equal("foobar", "foobar"));
assert!(are_strs_equal("a", "a"));
assert!(are_strs_equal("", ""));

assert!(!are_strs_equal("foo", "bar"));
assert!(!are_strs_equal("foo", " foo"));
assert!(!are_strs_equal("foo ", "foo"));
assert!(!are_strs_equal("", " "));
}
}
3 changes: 1 addition & 2 deletions orb-attest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ const HTTP_RETRY_DELAY: std::time::Duration = std::time::Duration::from_secs(3);
pub async fn main() -> eyre::Result<()> {
logging::init();

info!("Version: {}", BUILD_INFO.cargo.pkg_version);
info!("git sha: {}", BUILD_INFO.git.describe);
info!("Version: {}", BUILD_INFO.version);

let orb_id =
std::env::var("ORB_ID").wrap_err("env variable `ORB_ID` should be set")?;
Expand Down

0 comments on commit 832962a

Please sign in to comment.