MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / safe_write_text_file

Function safe_write_text_file

src/agents/mod.rs:664–710  ·  view source on GitHub ↗

Write text to a file via atomic sibling rename. Mirrors [`safe_write_json_file`] for generated prompt/rule files that are plain text rather than structured JSON. The target is not opened for writing until the final rename, so a failed write leaves the original untouched.

(path: &Path, contents: &str, backup: Option<&Path>)

Source from the content-addressed store, hash-verified

662/// plain text rather than structured JSON. The target is not opened for writing
663/// until the final rename, so a failed write leaves the original untouched.
664pub fn safe_write_text_file(path: &Path, contents: &str, backup: Option<&Path>) -> Result<()> {
665 static TEMP_COUNTER: AtomicU64 = AtomicU64::new(0);
666
667 if let Some(parent) = path.parent() {
668 std::fs::create_dir_all(parent).map_err(|e| TraceDecayError::Config {
669 message: format!("cannot create directory {}: {e}", parent.display()),
670 })?;
671 }
672
673 let file_name = path
674 .file_name()
675 .and_then(|name| name.to_str())
676 .unwrap_or("file");
677 let unique = TEMP_COUNTER.fetch_add(1, Ordering::Relaxed);
678 let new_name = format!(".{file_name}.{}.{}.new", std::process::id(), unique);
679 let new_path = path
680 .parent()
681 .map_or_else(|| PathBuf::from(&new_name), |parent| parent.join(&new_name));
682 if let Err(e) = std::fs::write(&new_path, contents) {
683 std::fs::remove_file(&new_path).ok();
684 return Err(TraceDecayError::Config {
685 message: format!("failed to write new text file {}: {e}", new_path.display()),
686 });
687 }
688
689 if let Err(e) = std::fs::rename(&new_path, path) {
690 std::fs::remove_file(&new_path).ok();
691 let hint = if let Some(b) = backup {
692 format!(
693 "\n Backup is at: {}\n \
694 The original file was NOT modified.",
695 b.display()
696 )
697 } else {
698 "\n The original file was NOT modified.".to_string()
699 };
700 return Err(TraceDecayError::Config {
701 message: format!(
702 "failed to rename {} → {}: {e}{hint}",
703 new_path.display(),
704 path.display()
705 ),
706 });
707 }
708
709 Ok(())
710}
711
712/// Write a JSON value to a file with pretty formatting.
713/// Creates a backup, writes atomically, and restores on failure.

Callers 11

save_digest_targetsFunction · 0.85
export_native_digestFunction · 0.85
export_prompt_digestFunction · 0.85
write_codex_plugin_filesFunction · 0.85
deploy_plugin_bundleFunction · 0.85
write_embedded_pluginFunction · 0.85

Calls 1

writeFunction · 0.85

Tested by

no test coverage detected