use std::env; use std::fs; use std::path::PathBuf; use std::time::Duration; fn main() { let version = resolve_app_version(); println!("cargo:rustc-env=APP_VERSION={version}"); slint_build::compile("ui/app.slint").expect("Slint build failed"); } /// Window / package version shown as `Rcalc-{version}`. /// /// On each `release` build the patch in `Cargo.toml` is incremented once /// (`0.1.0` → `0.1.1` → …). If Cargo restarts the build script right after we /// rewrite `Cargo.toml`, a short mtime guard prevents a double bump. fn resolve_app_version() -> String { let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let pkg = env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "0.0.0".into()); let profile = env::var("PROFILE").unwrap_or_default(); if profile != "release" { return pkg; } let cargo_toml = manifest_dir.join("Cargo.toml"); let guard_path = manifest_dir.join(".rcalc_last_bump"); let already = fs::read_to_string(&guard_path) .map(|s| s.trim().to_string()) .unwrap_or_default(); // Cargo re-invoked us because we just rewrote Cargo.toml — keep version. if already == pkg { if let Ok(meta) = fs::metadata(&cargo_toml) { if let Ok(modified) = meta.modified() { if modified.elapsed().unwrap_or(Duration::MAX) < Duration::from_secs(15) { return pkg; } } } } let Some(next) = bump_patch(&pkg) else { return pkg; }; if let Err(e) = set_cargo_toml_version(&cargo_toml, &next) { println!("cargo:warning=could not bump Cargo.toml version: {e}"); return pkg; } let _ = fs::write(&guard_path, &next); next } fn bump_patch(version: &str) -> Option { let mut parts: Vec<&str> = version.split('.').collect(); if parts.is_empty() { return None; } while parts.len() < 3 { parts.push("0"); } let patch: u64 = parts[2] .split(['-', '+']) .next()? .parse() .ok()?; Some(format!("{}.{}.{}", parts[0], parts[1], patch + 1)) } fn set_cargo_toml_version(path: &PathBuf, version: &str) -> std::io::Result<()> { let raw = fs::read_to_string(path)?; let mut out = String::with_capacity(raw.len() + 8); let mut replaced = false; for line in raw.lines() { if !replaced && line.starts_with("version") && line.contains('=') { out.push_str(&format!("version = \"{version}\"")); out.push('\n'); replaced = true; } else { out.push_str(line); out.push('\n'); } } if !replaced { return Err(std::io::Error::new( std::io::ErrorKind::InvalidData, "version field not found in Cargo.toml", )); } fs::write(path, out) }