From d4687371787844c53bc4c3b2849d0d2530edb127 Mon Sep 17 00:00:00 2001 From: wtcpython <1762993226@qq.com> Date: Thu, 30 Jul 2026 21:50:15 +0800 Subject: [PATCH] sort: defer compress program errors until needed --- src/uu/sort/src/ext_sort/threaded.rs | 24 ++++++++++++++++++------ tests/by-util/test_sort.rs | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/uu/sort/src/ext_sort/threaded.rs b/src/uu/sort/src/ext_sort/threaded.rs index 7dd089d0fe8..fbe1d071325 100644 --- a/src/uu/sort/src/ext_sort/threaded.rs +++ b/src/uu/sort/src/ext_sort/threaded.rs @@ -52,6 +52,8 @@ pub fn ext_sort( // Test if compression program exists and works, disable if not let mut effective_settings = settings.clone(); + // Keep the error until we know compression is actually needed. + let mut compress_prog_error = None; if let Some(ref prog) = settings.compress_prog { // Test the compression program by trying to spawn it match std::process::Command::new(prog) @@ -65,12 +67,7 @@ pub fn ext_sort( let _ = child.kill(); } Err(err) => { - // Print the error and disable compression - let _ = writeln!( - stderr(), - "sort: could not run compress program '{prog}': {}", - strip_errno(&err) - ); + compress_prog_error = Some((prog.clone(), err)); effective_settings.compress_prog = None; } } @@ -80,6 +77,7 @@ pub fn ext_sort( reader_writer::<_, WriteableCompressedTmpFile>( files, &effective_settings, + None, &sorted_receiver, recycled_sender, output, @@ -89,6 +87,7 @@ pub fn ext_sort( reader_writer::<_, WriteablePlainTmpFile>( files, &effective_settings, + compress_prog_error, &sorted_receiver, recycled_sender, output, @@ -103,6 +102,7 @@ fn reader_writer< >( files: F, settings: &GlobalSettings, + compress_prog_error: Option<(String, std::io::Error)>, receiver: &Receiver, sender: SyncSender, output: Output, @@ -125,6 +125,7 @@ fn reader_writer< separator, buffer_size, settings, + compress_prog_error, receiver, sender, )?; @@ -207,12 +208,14 @@ enum ReadResult { WroteChunksToFile { tmp_files: Vec }, } /// The function that is executed on the reader/writer thread. +#[allow(clippy::too_many_arguments)] fn read_write_loop( mut files: impl Iterator>>, tmp_dir: &mut TmpDirWrapper, separator: u8, buffer_size: usize, settings: &GlobalSettings, + compress_prog_error: Option<(String, std::io::Error)>, receiver: &Receiver, sender: SyncSender, ) -> UResult> { @@ -249,6 +252,15 @@ fn read_write_loop( } } + // The input did not fit into the first two in-memory chunks. + if let Some((prog, err)) = compress_prog_error { + let _ = writeln!( + stderr(), + "sort: could not run compress program '{prog}': {}", + strip_errno(&err) + ); + } + let mut sender_option = Some(sender); let mut tmp_files = vec![]; loop { diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 87e7f3308d1..396bc6a90f2 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -1374,7 +1374,7 @@ fn test_compress_fail() { "--compress-program", "nonexistent-program", "-S", - "10", + "1K", ]) .succeeds(); @@ -1394,6 +1394,20 @@ fn test_compress_fail() { assert_eq!(result.stdout_str(), expected); } +#[test] +#[cfg(unix)] +fn test_input_error_before_compression_is_needed() { + let (at, mut ucmd) = at_and_ucmd!(); + at.write("input", "b\na\n"); + at.mkdir("directory"); + + ucmd.args(&["--compress-program=nonexistent", "input", "directory"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Is a directory") + .stderr_does_not_contain("compress program"); +} + #[test] fn test_merge_batches() { new_ucmd!()