arcature-cli 2026.1.1

Developer lifecycle CLI for Arcature applications.
Documentation
//! File-writing helper for the `arc make` generators.
//!
//! Centralizes the write-or-fail behavior: create parent directories, refuse
//! to overwrite existing files, write content. Each generator produces a
//! `GeneratedFile` and this module handles the filesystem mechanics.
//!
//! This is the **per-file** writer: one file, refuse-overwrite, no
//! rollback. Multi-file generators (`mail`, `test`, `arc stubs publish`) use
//! the transactional [`super::plan`] instead — plan → conflict-detect →
//! dry-run → stage → validate → rollback-on-failure (PROGRAM.md AP2.1-11).
//! The per-file writer remains the default for the single-file generators
//! (`module`, `controller`, …) and is unchanged from A13.

use std::path::Path;

/// A file to be written by a generator: its destination path and content.
pub(crate) struct GeneratedFile {
    pub path: std::path::PathBuf,
    pub content: String,
}

/// Write a generated file, refusing to overwrite an existing file. Creates
/// parent directories as needed. Returns a short status message.
pub(crate) fn write_file(file: &GeneratedFile) -> Result<String, String> {
    super::naming::ensure_missing(&file.path)?;
    if let Some(parent) = file.path.parent() {
        std::fs::create_dir_all(parent)
            .map_err(|e| format!("cannot create directory {}: {e}", parent.display()))?;
    }
    std::fs::write(&file.path, &file.content)
        .map_err(|e| format!("cannot write {}: {e}", file.path.display()))?;
    Ok(format!("created {}", file.path.display()))
}

/// The module directory's `mod.rs` path for a given module name. `src_root`
/// is the application source root (ADR-0008: `backend_src_dir`).
pub(crate) fn module_mod_rs(src_root: &Path, module: &str) -> std::path::PathBuf {
    src_root.join(module).join("mod.rs")
}