diff --git a/build.rs b/build.rs index d379b5c..f306021 100644 --- a/build.rs +++ b/build.rs @@ -6,27 +6,39 @@ //! git is unavailable or the directory is not a git repo. //! - `GIT_DIRTY`: "true" if the working tree has uncommitted changes, //! "false" otherwise. +//! +//! Build systems that know the revision but cannot run git can supply either +//! value directly as `AIRLOCK_GIT_HASH` / `AIRLOCK_GIT_DIRTY`. The Nix build +//! does: its sandbox has no git and builds from a store copy with no `.git`. +use std::env; use std::process::Command; fn main() { // Re-run if the git HEAD changes (new commit, checkout, etc.). println!("cargo:rerun-if-changed=.git/HEAD"); println!("cargo:rerun-if-changed=.git/index"); + println!("cargo:rerun-if-env-changed=AIRLOCK_GIT_HASH"); + println!("cargo:rerun-if-env-changed=AIRLOCK_GIT_DIRTY"); - let hash = Command::new("git") - .args(["rev-parse", "--short", "HEAD"]) - .output() - .ok() - .filter(|o| o.status.success()) - .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()) - .unwrap_or_else(|| "unknown".to_string()); + let hash = env::var("AIRLOCK_GIT_HASH").unwrap_or_else(|_| { + Command::new("git") + .args(["rev-parse", "--short", "HEAD"]) + .output() + .ok() + .filter(|o| o.status.success()) + .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()) + .unwrap_or_else(|| "unknown".to_string()) + }); - let dirty = Command::new("git") - .args(["diff", "--quiet", "HEAD"]) - .status() - .map(|s| if s.success() { "false" } else { "true" }) - .unwrap_or("false"); + let dirty = env::var("AIRLOCK_GIT_DIRTY").unwrap_or_else(|_| { + Command::new("git") + .args(["diff", "--quiet", "HEAD"]) + .status() + .map(|s| if s.success() { "false" } else { "true" }) + .unwrap_or("false") + .to_string() + }); println!("cargo:rustc-env=GIT_HASH={hash}"); println!("cargo:rustc-env=GIT_DIRTY={dirty}"); diff --git a/flake.nix b/flake.nix index e3e5ea7..8e6edbf 100644 --- a/flake.nix +++ b/flake.nix @@ -34,12 +34,20 @@ pname = "airlock"; version = (nixpkgs.lib.importTOML ./Cargo.toml).package.version; - # No git in the build environment, so build.rs takes its fallback and - # `airlock --version` reports " (unknown)". src = self; cargoLock.lockFile = ./Cargo.lock; + # build.rs shells out to git, which this build cannot do: no git in + # the sandbox, and `src` is a store copy with no .git. Hand it the + # revision the flake was evaluated from instead. `shortRev` exists + # only for a clean checkout; a dirty tree gives `dirtyShortRev`, + # which carries a "-dirty" suffix that GIT_DIRTY already conveys. + AIRLOCK_GIT_HASH = nixpkgs.lib.removeSuffix "-dirty" ( + self.shortRev or self.dirtyShortRev or "unknown" + ); + AIRLOCK_GIT_DIRTY = if self ? dirtyRev then "true" else "false"; + # Only the unit tests: the suites under tests/ start a daemon and nest # an OS sandbox inside the Nix build sandbox, which is unavailable there. cargoTestFlags = [ "--lib" ];