diff --git a/crates/nu-command/src/filesystem/save.rs b/crates/nu-command/src/filesystem/save.rs index f5f86cbfc6..bafbefc50c 100644 --- a/crates/nu-command/src/filesystem/save.rs +++ b/crates/nu-command/src/filesystem/save.rs @@ -45,6 +45,7 @@ impl Command for Save { ) .switch("raw", "save file as raw binary", Some('r')) .switch("append", "append input to the end of the file", Some('a')) + .switch("force", "overwrite the destination", Some('f')) .category(Category::FileSystem) } @@ -57,6 +58,7 @@ impl Command for Save { ) -> Result { let raw = call.has_flag("raw"); let append = call.has_flag("append"); + let force = call.has_flag("force"); let span = call.head; @@ -64,7 +66,21 @@ impl Command for Save { let arg_span = path.span; let path = Path::new(&path.item); - let file = match (append, path.exists()) { + let path_exists = path.exists(); + if path_exists && !force && !append { + return Err(ShellError::GenericError( + "Destination file already exists".into(), + format!( + "Destination file '{}' already exists", + path.to_string_lossy() + ), + Some(arg_span), + Some("you can use -f, --force to force overwriting the destination".into()), + Vec::new(), + )); + } + + let file = match (append, path_exists) { (true, true) => std::fs::OpenOptions::new() .write(true) .append(true) diff --git a/crates/nu-command/tests/commands/save.rs b/crates/nu-command/tests/commands/save.rs index b8a9e166de..604d448b8c 100644 --- a/crates/nu-command/tests/commands/save.rs +++ b/crates/nu-command/tests/commands/save.rs @@ -1,4 +1,4 @@ -use nu_test_support::fs::file_contents; +use nu_test_support::fs::{file_contents, Stub}; use nu_test_support::nu; use nu_test_support::playground::Playground; use std::io::Write; @@ -149,3 +149,31 @@ fn save_string_and_stream_as_raw() { ) }) } + +#[test] +fn save_not_override_file_by_default() { + Playground::setup("save_test_8", |dirs, sandbox| { + sandbox.with_files(vec![Stub::EmptyFile("log.txt")]); + + let actual = nu!( + cwd: dirs.root(), + r#""abcd" | save save_test_8/log.txt"# + ); + assert!(actual.err.contains("Destination file already exists")); + }) +} + +#[test] +fn save_override_works() { + Playground::setup("save_test_9", |dirs, sandbox| { + sandbox.with_files(vec![Stub::EmptyFile("log.txt")]); + + let expected_file = dirs.test().join("log.txt"); + nu!( + cwd: dirs.root(), + r#""abcd" | save save_test_9/log.txt -f"# + ); + let actual = file_contents(expected_file); + assert_eq!(actual, "abcd"); + }) +} diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 33f656f272..1d331fa557 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -910,7 +910,15 @@ pub fn eval_element_with_input( Argument::Positional(expr.clone()), Argument::Named(( Spanned { - item: "--raw".into(), + item: "raw".into(), + span: *span, + }, + None, + None, + )), + Argument::Named(( + Spanned { + item: "force".into(), span: *span, }, None,