Lines
96.81 %
Functions
100 %
Branches
use sha2::{Digest, Sha256};
use std::env;
use std::fs;
use std::io::{self, Read};
use std::process::Command;
fn checksum(file_path: &str) -> io::Result<String> {
let mut file = fs::File::open(file_path)?;
let mut hasher = Sha256::new();
let mut buffer = [0; 1024];
loop {
let bytes_read = file.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
hasher.update(&buffer[..bytes_read]);
let hash = hasher.finalize();
Ok(hash.iter().fold(String::new(), |mut acc, b| {
use std::fmt::Write;
write!(acc, "{b:02x}").unwrap();
acc
}))
/// Regenerate `doc/versions.org` from git history with git-cliff. It is a
/// build artifact (gitignored), `#+include`d by `disdoc.org`, so the disdoc
/// export below fails if it is missing. The pre-commit hook regenerates it the
/// same way before staging README; doing it here keeps a plain `cargo build`
/// self-contained (one build, no out-of-band step) instead of depending on a
/// hook having run.
fn regenerate_changelog() {
let root = format!("{}/..", env::var("CARGO_MANIFEST_DIR").unwrap());
let status = Command::new("git-cliff")
.current_dir(&root)
.args(["-o", "doc/versions.org"])
.status()
.expect(
"failed to spawn git-cliff for doc/versions.org. cargo build requires \
git-cliff on PATH (same as emacs); `cargo install git-cliff`",
);
assert!(status.success(), "git-cliff changelog generation failed");
fn main() {
// `versions.org` is regenerated from every commit, so re-run when HEAD moves.
println!("cargo:rerun-if-changed=../.git/HEAD");
regenerate_changelog();
println!("cargo:rerun-if-changed=../doc/disdoc.org");
let status = Command::new("emacs")
.args([
"-q",
"--batch",
"--eval",
"(progn (require 'ob-emacs-lisp) (require 'ob-shell) (setq org-confirm-babel-evaluate nil create-lockfiles nil))",
"../doc/disdoc.org",
"-l",
"ox-md",
"(org-md-export-to-markdown)",
"-f",
"save-buffer",
"kill-emacs",
])
.expect("Failed to export doc");
assert!(status.success(), "Building finance doc failed");
fs::copy("../doc/disdoc.md", "../target/nomisync.md").expect("Can't update finance doc file");
println!(
"cargo:rustc-env=CARGO_TARGET_DIR={}/../",
env::var("CARGO_MANIFEST_DIR").unwrap()
println!("cargo:rerun-if-changed=../doc/nomisync.org");
"../doc/nomisync.org",
"(org-babel-do-load-languages 'org-babel-load-languages '((sql . t)))",
"(setq org-confirm-babel-evaluate nil create-lockfiles nil)",
"(org-babel-tangle)",
.expect("Failed to export SQL");
assert!(status.success(), "Building SQL from org failed");
sync_migration("../doc/nomisync.sql", "../migrations/0002_nomisync.sql");
sync_migration(
"../doc/0004_tags_canonical.sql",
"../migrations/0004_tags_canonical.sql",
println!("cargo:rerun-if-changed=../migrations");
fn sync_migration(tangled: &str, migration: &str) {
if fs::metadata(tangled).is_err() {
return;
let status = Command::new("sqlfluff")
.args(["fix", "--dialect", "postgres", tangled, "--force"])
.expect("Failed to format SQL");
assert!(status.success(), "Formatting tangled migration failed");
let needs_copy = match fs::metadata(migration) {
Ok(_) => checksum(tangled).unwrap() != checksum(migration).unwrap(),
Err(_) => true,
};
if needs_copy {
fs::copy(tangled, migration).expect("Can't update migration file");
} else {
fs::remove_file(tangled).unwrap();