From 67b4c6cb7209b8c64f3e33676a118abada05775d Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:15:25 -0500 Subject: [PATCH 1/3] derive Clone for Config --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 8a52f68d2..eb3906742 100644 --- a/src/config.rs +++ b/src/config.rs @@ -71,7 +71,7 @@ impl<'de> Deserialize<'de> for Delimiter { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Config { pub path: Option, // None implies idx_path: Option, From 0e3b7567ed03c605708d547117a616a349217374 Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:16:18 -0500 Subject: [PATCH 2/3] `fmt`: add `--no-final-newline` option per #1300 comment to strip a trailing newline --- src/cmd/fmt.rs | 70 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/src/cmd/fmt.rs b/src/cmd/fmt.rs index b2688198d..e7dc980b1 100644 --- a/src/cmd/fmt.rs +++ b/src/cmd/fmt.rs @@ -24,6 +24,7 @@ fmt options: --quote-never Never put quotes around any value. --escape The escape character to use. When not specified, quotes are escaped by doubling them. + --no-final-newline Do not write a newline at the end of the output. Common options: -h, --help Display this message @@ -41,16 +42,17 @@ use crate::{ #[derive(Deserialize)] struct Args { - arg_input: Option, - flag_out_delimiter: Option, - flag_crlf: bool, - flag_ascii: bool, - flag_output: Option, - flag_delimiter: Option, - flag_quote: Delimiter, - flag_quote_always: bool, - flag_quote_never: bool, - flag_escape: Option, + arg_input: Option, + flag_out_delimiter: Option, + flag_crlf: bool, + flag_ascii: bool, + flag_output: Option, + flag_delimiter: Option, + flag_quote: Delimiter, + flag_quote_always: bool, + flag_quote_never: bool, + flag_escape: Option, + flag_no_final_newline: bool, } pub fn run(argv: &[&str]) -> CliResult<()> { @@ -81,10 +83,50 @@ pub fn run(argv: &[&str]) -> CliResult<()> { let mut rdr = rconfig.reader()?; let mut wtr = wconfig.writer()?; - let mut r = csv::ByteRecord::new(); - while rdr.read_byte_record(&mut r)? { - wtr.write_byte_record(&r)?; + let mut wsconfig = (wconfig).clone(); + + wsconfig.path = Some( + tempfile::NamedTempFile::new()? + .into_temp_path() + .to_path_buf(), + ); + + let mut temp_writer = wsconfig.writer()?; + let mut current_record = csv::ByteRecord::new(); + let mut next_record = csv::ByteRecord::new(); + let mut is_last_record; + let mut records_exist = rdr.read_byte_record(&mut current_record)?; + while records_exist { + is_last_record = !rdr.read_byte_record(&mut next_record)?; + if is_last_record { + // If it's the last record and the --no-final-newline flag is set, + // write the record to a temporary file, then read the file into a string. + // Remove the last character (the newline) from the string, then write the string to the + // output. + temp_writer.write_record(¤t_record)?; + temp_writer.flush()?; + let mut temp_string = match std::fs::read_to_string( + wsconfig.path.as_ref().ok_or("Temp file path not found")?, + ) { + Ok(s) => s, + Err(e) => return fail_clierror!("Error reading from temp file: {}", e), + }; + if args.flag_no_final_newline { + temp_string.pop(); + } + match wtr.into_inner() { + Ok(mut writer) => writer.write_all(temp_string.as_bytes())?, + Err(e) => return fail_clierror!("Error writing to output: {}", e), + }; + break; + } + wtr.write_record(¤t_record)?; + wtr.write_record(&next_record)?; + records_exist = rdr.read_byte_record(&mut current_record)?; } - wtr.flush()?; + + // we don't flush the writer explicitly + // because it will cause a borrow error + // let's just let it drop and flush itself implicitly Ok(()) } From 369a9262e3026e061d5719985ce8c60fd6550897 Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:16:45 -0500 Subject: [PATCH 3/3] `tests`: add `fmt` tests for `--output` and `--no-final-newline` options --- tests/test_fmt.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_fmt.rs b/tests/test_fmt.rs index 759614c11..397c71a3e 100644 --- a/tests/test_fmt.rs +++ b/tests/test_fmt.rs @@ -61,6 +61,39 @@ mnopqr,stuvwx\r assert_eq!(got, expected.to_string()); } +#[test] +fn fmt_nofinalnewline() { + let (wrk, mut cmd) = setup("fmt_nofinalnewline"); + cmd.arg("--no-final-newline"); + + let got: String = wrk.stdout(&mut cmd); + let expected = r#"h1,h2 +abcdef,ghijkl +mnopqr,stuvwx +"ab""cd""ef","gh,ij,kl""#; + assert_eq!(got, expected.to_string()); +} + +#[test] +fn fmt_output() { + let (wrk, mut cmd) = setup("fmt_output"); + + let output_file = wrk.path("output.csv").to_string_lossy().to_string(); + + cmd.args(["--output", &output_file]); + + wrk.assert_success(&mut cmd); + + let got = wrk.read_to_string(&output_file); + + let expected = r#"h1,h2 +abcdef,ghijkl +mnopqr,stuvwx +"ab""cd""ef","gh,ij,kl" +"#; + assert_eq!(got, expected); +} + #[test] fn fmt_quote_always() { let (wrk, mut cmd) = setup("fmt_quote_always");