use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
println!("cargo:rerun-if-changed=../../.git/HEAD");
println!("cargo:rerun-if-changed=../../.git/refs/heads");
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let workspace_cargo_src = manifest_dir.join("../../Cargo.toml");
let workspace_cargo_dst = out_dir.join("workspace-cargo-toml");
copy_or_fallback(
&workspace_cargo_src,
&workspace_cargo_dst,
"[workspace.package]\nversion = \"unknown\"\n",
);
println!("cargo:rerun-if-changed={}", workspace_cargo_src.display());
let schema_src = manifest_dir.join("../../docs/schemas/handoff-artifact.v1.json");
let schema_dst = out_dir.join("handoff-artifact.v1.json");
copy_or_fallback(
&schema_src,
&schema_dst,
r#"{"schema_version":"codelens-handoff-artifact-v1","fallback":true}"#,
);
println!("cargo:rerun-if-changed={}", schema_src.display());
let git_sha = Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.ok()
.and_then(|out| {
if out.status.success() {
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
} else {
None
}
})
.unwrap_or_else(|| "unknown".to_string());
println!("cargo:rustc-env=CODELENS_BUILD_GIT_SHA={git_sha}");
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
let build_time = format_iso8601_utc(now);
println!("cargo:rustc-env=CODELENS_BUILD_TIME={build_time}");
let dirty = Command::new("git")
.args(["status", "--porcelain"])
.output()
.ok()
.map(|out| !out.stdout.is_empty())
.unwrap_or(false);
println!("cargo:rustc-env=CODELENS_BUILD_GIT_DIRTY={}", dirty);
}
fn copy_or_fallback(src: &PathBuf, dst: &PathBuf, fallback: &str) {
if src.exists() {
fs::copy(src, dst)
.unwrap_or_else(|err| panic!("copy {} -> {}: {err}", src.display(), dst.display()));
} else {
fs::write(dst, fallback)
.unwrap_or_else(|err| panic!("write fallback {}: {err}", dst.display()));
}
}
fn format_iso8601_utc(unix_seconds: u64) -> String {
let days = (unix_seconds / 86_400) as i64;
let secs_in_day = unix_seconds % 86_400;
let hour = secs_in_day / 3600;
let minute = (secs_in_day % 3600) / 60;
let second = secs_in_day % 60;
let z = days + 719_468;
let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
let doe = (z - era * 146_097) as u64; let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146_096) / 365; let y = yoe as i64 + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = doy - (153 * mp + 2) / 5 + 1;
let m = if mp < 10 { mp + 3 } else { mp - 9 };
let year = y + (if m <= 2 { 1 } else { 0 });
format!(
"{year:04}-{m:02}-{d:02}T{hour:02}:{minute:02}:{second:02}Z",
year = year,
m = m,
d = d,
hour = hour,
minute = minute,
second = second,
)
}