diff --git a/crates/nu-command/src/commands/filesystem/save.rs b/crates/nu-command/src/commands/filesystem/save.rs index 0212da6810..f8f0f9538b 100644 --- a/crates/nu-command/src/commands/filesystem/save.rs +++ b/crates/nu-command/src/commands/filesystem/save.rs @@ -142,6 +142,7 @@ impl WholeStreamCommand for Save { "treat values as-is rather than auto-converting based on file extension", Some('r'), ) + .switch("append", "append values rather than overriding", Some('a')) } fn usage(&self) -> &str { @@ -165,6 +166,7 @@ fn save(args: CommandArgs) -> Result { let path: Option> = args.opt(0)?; let save_raw = args.has_flag("raw"); + let append = args.has_flag("append"); let input: Vec = args.input.collect(); if path.is_none() { @@ -231,7 +233,7 @@ fn save(args: CommandArgs) -> Result { }; }; - shell_manager.save(&full_path, &content?, name.span) + shell_manager.save(&full_path, &content?, name.span, append) } fn string_from(input: &[Value]) -> String { diff --git a/crates/nu-engine/src/filesystem/filesystem_shell.rs b/crates/nu-engine/src/filesystem/filesystem_shell.rs index 6b736de734..afc9cd74f0 100644 --- a/crates/nu-engine/src/filesystem/filesystem_shell.rs +++ b/crates/nu-engine/src/filesystem/filesystem_shell.rs @@ -14,7 +14,8 @@ use nu_protocol::{CommandAction, ConfigPath, TaggedDictBuilder, Value}; use nu_source::{Span, Tag}; use nu_stream::{ActionStream, Interruptible, IntoActionStream, OutputStream}; use std::collections::VecDeque; -use std::io::ErrorKind; +use std::fs::OpenOptions; +use std::io::{ErrorKind, Write}; use std::path::{Path, PathBuf}; use std::sync::atomic::AtomicBool; use std::sync::Arc; @@ -873,8 +874,19 @@ impl Shell for FilesystemShell { full_path: &Path, save_data: &[u8], name: Span, + append: bool, ) -> Result { - match std::fs::write(full_path, save_data) { + let mut options = OpenOptions::new(); + if append { + options.append(true) + } else { + options.write(true).create(true).truncate(true) + }; + + match options + .open(full_path) + .and_then(|ref mut file| file.write_all(save_data)) + { Ok(_) => Ok(OutputStream::empty()), Err(e) => Err(ShellError::labeled_error( e.to_string(), diff --git a/crates/nu-engine/src/shell/mod.rs b/crates/nu-engine/src/shell/mod.rs index 5d0859fb11..fce62a7c89 100644 --- a/crates/nu-engine/src/shell/mod.rs +++ b/crates/nu-engine/src/shell/mod.rs @@ -49,5 +49,6 @@ pub trait Shell: std::fmt::Debug { path: &Path, contents: &[u8], name: Span, + append: bool, ) -> Result; } diff --git a/crates/nu-engine/src/shell/shell_manager.rs b/crates/nu-engine/src/shell/shell_manager.rs index d985f18339..90b080bb5f 100644 --- a/crates/nu-engine/src/shell/shell_manager.rs +++ b/crates/nu-engine/src/shell/shell_manager.rs @@ -105,8 +105,9 @@ impl ShellManager { full_path: &Path, save_data: &[u8], name: Span, + append: bool, ) -> Result { - self.shells.lock()[self.current_shell()].save(full_path, save_data, name) + self.shells.lock()[self.current_shell()].save(full_path, save_data, name, append) } pub fn next(&self) { diff --git a/crates/nu-engine/src/shell/value_shell.rs b/crates/nu-engine/src/shell/value_shell.rs index 186ec41f9f..5efc45a352 100644 --- a/crates/nu-engine/src/shell/value_shell.rs +++ b/crates/nu-engine/src/shell/value_shell.rs @@ -248,6 +248,7 @@ impl Shell for ValueShell { _path: &Path, _contents: &[u8], _name: Span, + _append: bool, ) -> Result { Err(ShellError::unimplemented( "save on help shell is not supported",