1
use sha2::{Digest, Sha256};
2
use std::env;
3
use std::fs;
4
use std::io::{self, Read};
5
use std::process::Command;
6

            
7
16
fn checksum(file_path: &str) -> io::Result<String> {
8
16
    let mut file = fs::File::open(file_path)?;
9
16
    let mut hasher = Sha256::new();
10
16
    let mut buffer = [0; 1024];
11

            
12
    loop {
13
104
        let bytes_read = file.read(&mut buffer)?;
14
104
        if bytes_read == 0 {
15
16
            break;
16
88
        }
17
88
        hasher.update(&buffer[..bytes_read]);
18
    }
19

            
20
16
    let hash = hasher.finalize();
21
512
    Ok(hash.iter().fold(String::new(), |mut acc, b| {
22
        use std::fmt::Write;
23
512
        write!(acc, "{b:02x}").unwrap();
24
512
        acc
25
512
    }))
26
16
}
27

            
28
4
fn main() {
29
4
    println!("cargo:rerun-if-changed=../doc/disdoc.org");
30
4
    let status = Command::new("emacs")
31
4
        .args([
32
4
            "-q",
33
4
            "--batch",
34
4
            "--eval",
35
4
            "(progn (require 'ob-emacs-lisp) (require 'ob-shell) (setq org-confirm-babel-evaluate nil))",
36
4
            "../doc/disdoc.org",
37
4
            "-l",
38
4
            "ox-md",
39
4
            "--eval",
40
4
            "(org-md-export-to-markdown)",
41
4
            "-f",
42
4
            "save-buffer",
43
4
            "-f",
44
4
            "kill-emacs",
45
4
        ])
46
4
        .status()
47
4
        .expect("Failed to export doc");
48

            
49
4
    assert!(status.success(), "Building finance doc failed");
50

            
51
4
    fs::copy("../doc/disdoc.md", "../target/nomisync.md").expect("Can't update finance doc file");
52

            
53
4
    println!(
54
        "cargo:rustc-env=CARGO_TARGET_DIR={}/../",
55
4
        env::var("CARGO_MANIFEST_DIR").unwrap()
56
    );
57

            
58
4
    println!("cargo:rerun-if-changed=../doc/nomisync.org");
59
4
    let status = Command::new("emacs")
60
4
        .args([
61
4
            "-q",
62
4
            "--batch",
63
4
            "../doc/nomisync.org",
64
4
            "--eval",
65
4
            "(org-babel-do-load-languages 'org-babel-load-languages '((sql . t)))",
66
4
            "--eval",
67
4
            "(setq org-confirm-babel-evaluate nil)",
68
4
            "--eval",
69
4
            "(org-babel-tangle)",
70
4
            "-f",
71
4
            "kill-emacs",
72
4
        ])
73
4
        .status()
74
4
        .expect("Failed to export SQL");
75

            
76
4
    assert!(status.success(), "Building SQL from org failed");
77

            
78
4
    sync_migration("../doc/nomisync.sql", "../migrations/0002_nomisync.sql");
79
4
    sync_migration(
80
4
        "../doc/0004_tags_canonical.sql",
81
4
        "../migrations/0004_tags_canonical.sql",
82
    );
83

            
84
4
    println!("cargo:rerun-if-changed=../migrations");
85
4
}
86

            
87
8
fn sync_migration(tangled: &str, migration: &str) {
88
8
    if fs::metadata(tangled).is_err() {
89
        return;
90
8
    }
91

            
92
8
    let status = Command::new("sqlfluff")
93
8
        .args(["fix", "--dialect", "postgres", tangled, "--force"])
94
8
        .status()
95
8
        .expect("Failed to format SQL");
96

            
97
8
    assert!(status.success(), "Formatting tangled migration failed");
98

            
99
8
    let needs_copy = match fs::metadata(migration) {
100
8
        Ok(_) => checksum(tangled).unwrap() != checksum(migration).unwrap(),
101
        Err(_) => true,
102
    };
103

            
104
8
    if needs_copy {
105
        fs::copy(tangled, migration).expect("Can't update migration file");
106
8
    } else {
107
8
        fs::remove_file(tangled).unwrap();
108
8
    }
109
8
}