From bc3dc98b347ff6b5ab552734ceb0e32b04df9fcd Mon Sep 17 00:00:00 2001 From: WindSoilder Date: Thu, 1 Dec 2022 20:26:17 +0800 Subject: [PATCH] add -f, --force for save command (#7262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Closes: #6920 # User-Facing Changes ``` ❯ "asdf" | save dump.rdb Error: × Destination file already exists ╭─[entry #21:1:1] 1 │ "asdf" | save dump.rdb · ────┬─── · ╰── Destination file '/tmp/dump.rdb' already exists ╰──── help: you can use -f, --force to force overwriting the destination ``` # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --- crates/nu-command/src/filesystem/save.rs | 18 +++++++++++++- crates/nu-command/tests/commands/save.rs | 30 +++++++++++++++++++++++- crates/nu-engine/src/eval.rs | 10 +++++++- 3 files changed, 55 insertions(+), 3 deletions(-) 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,