Skip to main content

agent_rules_tool/
io.rs

1//! Atomic file writes used by migrate output.
2
3use crate::error::Error;
4use std::path::Path;
5use tokio::fs;
6
7/// Write `content` to `path`, creating parent directories as needed.
8///
9/// When the file already exists and `force` is false, returns
10/// [`WriteOutcome::Skipped`] without modifying the file.
11pub async fn write_file_atomic(
12    path: &Path,
13    content: &str,
14    force: bool,
15) -> Result<WriteOutcome, Error> {
16    if path.exists() && !force {
17        return Ok(WriteOutcome::Skipped);
18    }
19
20    if let Some(parent) = path.parent() {
21        fs::create_dir_all(parent).await?;
22    }
23
24    let temp_path = path.with_extension("tmp");
25    fs::write(&temp_path, content).await?;
26    fs::rename(&temp_path, path).await?;
27    Ok(WriteOutcome::Written)
28}
29
30/// Result of [`write_file_atomic`].
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum WriteOutcome {
33    /// File was written (or overwritten when `force` is true).
34    Written,
35    /// File already existed and `force` was false.
36    Skipped,
37}