#![forbid(unsafe_code)]
use std::path::{Path, PathBuf};
use std::{env, process::Command};
const BUILD_SCRIPT: &str = "build.rs";
const DESCRIPTOR_TEXT_FILE: &str = "git_description.txt";
const DESCRIPTOR_ENV: &str = "ZINGOLIB_DESCRIPTOR";
const DESCRIPTOR_SOURCE_FILE: &str = "git_description.rs";
fn register_rerun_watches() {
println!("cargo:rerun-if-changed={BUILD_SCRIPT}");
if let Some(git_dir) = git_path_query("--git-dir") {
println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display());
}
if let Some(common_dir) = git_path_query("--git-common-dir") {
let packed_refs = common_dir.join("packed-refs");
if packed_refs.exists() {
println!("cargo:rerun-if-changed={}", packed_refs.display());
}
println!(
"cargo:rerun-if-changed={}",
common_dir.join("refs").display()
);
}
}
fn git_path_query(flag: &str) -> Option<PathBuf> {
let output = Command::new("git")
.args(["rev-parse", flag])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let path = String::from_utf8(output.stdout)
.ok()?
.trim_end()
.to_string();
if path.is_empty() {
return None;
}
Some(PathBuf::from(path))
}
fn git_stdout(args: &[&str]) -> Option<String> {
Command::new("git")
.args(args)
.output()
.ok()
.filter(|output| output.status.success())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|stdout| stdout.trim_end().to_string())
.filter(|stdout| !stdout.is_empty())
}
fn tag_at_head() -> Option<String> {
git_stdout(&[
"tag",
"--points-at",
"HEAD",
"--list",
"zingolib_v*",
"--sort=-version:refname",
])
.and_then(|tags| tags.lines().next().map(str::to_string))
}
fn dirty() -> bool {
Command::new("git")
.args(["diff-index", "--quiet", "HEAD", "--"])
.status()
.map(|status| !status.success())
.unwrap_or(false)
}
fn hash5() -> Option<String> {
git_stdout(&["rev-parse", "HEAD"]).map(|hash| hash.chars().take(5).collect())
}
fn descriptor(tag: Option<&str>, crate_version: &str, hash5: Option<&str>, dirty: bool) -> String {
let formatted = match (tag, hash5) {
(Some(tag), _) => format!("zl_{}", tag.strip_prefix("zingolib_v").unwrap_or(tag)),
(None, Some(hash5)) => format!("zl_{crate_version}_{hash5}"),
(None, None) => format!("zl_{crate_version}"),
};
if dirty {
format!("{formatted}_dirty")
} else {
formatted
}
}
fn git_description() {
let crate_version = env::var("CARGO_PKG_VERSION").unwrap_or_default();
let description = descriptor(
tag_at_head().as_deref(),
&crate_version,
hash5().as_deref(),
dirty(),
);
println!("cargo:rustc-env={DESCRIPTOR_ENV}={description}");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
std::fs::write(out_dir.join(DESCRIPTOR_TEXT_FILE), &description).unwrap();
std::fs::write(
out_dir.join(DESCRIPTOR_SOURCE_FILE),
format!(
"pub fn git_description() -> &'static str {{\n \
include_str!(concat!(env!(\"OUT_DIR\"), \"/{DESCRIPTOR_TEXT_FILE}\"))\n\
}}\n"
),
)
.unwrap();
}
fn get_zcash_params() {
println!("Checking if params are available...");
let params_path = match zcash_proofs::download_sapling_parameters(Some(400)) {
Ok(p) => {
println!("Params downloaded!");
println!("Spend path: {}", p.spend.to_str().unwrap());
println!("Output path: {}", p.output.to_str().unwrap());
p
}
Err(e) => {
println!("Error downloading params: {e}");
panic!();
}
};
publish_param_path("SAPLING_SPEND_PARAMS", ¶ms_path.spend);
publish_param_path("SAPLING_OUTPUT_PARAMS", ¶ms_path.output);
}
fn publish_param_path(variable: &str, path: &Path) {
let path = path.display();
println!("cargo:rustc-env={variable}={path}");
println!("cargo:rerun-if-changed={path}");
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
register_rerun_watches();
get_zcash_params();
git_description();
Ok(())
}