Skip to main content

elph_agent/init/
mod.rs

1mod progress;
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use anyhow::Result;
7use serde::Serialize;
8
9pub use progress::InitProgress;
10
11/// Create every directory in `dirs`, including parents.
12pub fn ensure_dirs(dirs: &[PathBuf]) -> Result<()> {
13    for dir in dirs {
14        fs::create_dir_all(dir)?;
15    }
16    Ok(())
17}
18
19/// Write a pretty-printed JSON file with mode `0600` on Unix.
20pub fn write_json_file<T: Serialize>(path: &Path, value: &T) -> Result<()> {
21    if let Some(parent) = path.parent() {
22        fs::create_dir_all(parent)?;
23    }
24
25    let mut payload = serde_json::to_string_pretty(value)?;
26    payload.push('\n');
27
28    write_private_file(path, payload.as_bytes())
29}
30
31/// Write a private file with mode `0600` on Unix.
32pub fn write_private_file(path: &Path, contents: &[u8]) -> Result<()> {
33    #[cfg(unix)]
34    {
35        use std::fs::OpenOptions;
36        use std::io::Write;
37        use std::os::unix::fs::OpenOptionsExt;
38
39        let mut file = OpenOptions::new().write(true).create_new(true).mode(0o600).open(path)?;
40        file.write_all(contents)?;
41        return Ok(());
42    }
43
44    #[cfg(not(unix))]
45    {
46        fs::write(path, contents)?;
47        Ok(())
48    }
49}
50
51/// Write a file only when it does not already exist.
52pub fn write_file_if_missing(path: &Path, contents: &[u8]) -> Result<()> {
53    if path.exists() {
54        return Ok(());
55    }
56
57    if let Some(parent) = path.parent() {
58        fs::create_dir_all(parent)?;
59    }
60
61    fs::write(path, contents)?;
62    Ok(())
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn write_file_if_missing_is_idempotent() {
71        let tmp = tempfile::tempdir().expect("tempdir");
72        let path = tmp.path().join("marker.txt");
73
74        write_file_if_missing(&path, b"first").expect("first write");
75        write_file_if_missing(&path, b"second").expect("second write");
76
77        assert_eq!(fs::read_to_string(path).expect("read marker"), "first");
78    }
79}