From 767feacf72a012023962c73b5b40cb43cf59aea0 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:47:27 +0200 Subject: [PATCH] Require replace: true for file.export_session_text to overwrite Fixes #929 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/cmd/file.rs | 21 ++++++++++++++++++++- crates/engine/src/io.rs | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index 87bba997..f6931f91 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -110,9 +110,10 @@ pub fn specs() -> Vec { crate::io::write_file(&path, &bytes)?; Ok(json!({"path": path, "bytes": bytes.len()})) }), - cmd!(noundo "file.export_session_text", "Session Info as Text...", ["File", "Export"], None, "{path?}", always, |e, p| { + cmd!(noundo "file.export_session_text", "Session Info as Text...", ["File", "Export"], None, "{path?, replace?: false}", always, |e, p| { let text = crate::inspect::session_text(e); if let Some(path) = str_param(p, "path") { + refuse_replacing(e, "file.export_session_text", std::path::Path::new(path), p)?; crate::io::write_file(path, text.as_bytes())?; } Ok(json!({"text": text})) @@ -350,6 +351,24 @@ mod tests { path.to_string_lossy().into_owned() } + #[test] + fn export_session_text_needs_replace_to_overwrite() { + let dir = std::env::temp_dir().join(format!("sc-export-text-replace-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join("info.txt"); + let path_str = path.to_string_lossy().into_owned(); + let mut e = Engine::default(); + e.execute("file.export_session_text", &json!({"path": path_str})).unwrap(); + std::fs::write(&path, "keep me").unwrap(); + let err = e.execute("file.export_session_text", &json!({"path": path_str})).unwrap_err(); + assert!(err.to_string().contains("replace: true"), "{err}"); + assert_eq!(std::fs::read_to_string(&path).unwrap(), "keep me"); + e.execute("file.export_session_text", &json!({"path": path_str, "replace": true})).unwrap(); + assert_ne!(std::fs::read_to_string(&path).unwrap(), "keep me"); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn import_audio_honours_new_tracks() { let dir = std::env::temp_dir().join(format!("sc-import-new-tracks-{}", std::process::id())); diff --git a/crates/engine/src/io.rs b/crates/engine/src/io.rs index eff105ec..341287d3 100644 --- a/crates/engine/src/io.rs +++ b/crates/engine/src/io.rs @@ -1109,7 +1109,7 @@ pub fn replaces(e: &Engine, command: &str, file: &Path) -> bool { "session.save" | "session.save_as" | "session.save_copy" => { file.exists() && !e.path.as_deref().is_some_and(|own| same_path(Path::new(own), file)) } - "session.save_template" | "file.export_selected_tracks_as_session" => file.exists(), + "session.save_template" | "file.export_selected_tracks_as_session" | "file.export_session_text" => file.exists(), _ => false, } }