From 4a2f002be8d19e7372aae2c317078dbf919d4487 Mon Sep 17 00:00:00 2001 From: naufalfx805-source Date: Sat, 31 Oct 2026 17:14:29 +0700 Subject: [PATCH 1/2] join: implement last-flag-wins for --check-order/--nocheck-order GNU coreutils uses last-flag-wins semantics when both --check-order and --nocheck-order are specified. Match that behavior by tracking argument indices. Fixes #16004 Co-Authored-By: Claude Opus 4.6 Claude-Session: https://claude.ai/code/session_01Gc3pLfULRGQmfBnqr3oo3D --- src/uu/join/src/join.rs | 18 ++++++++++++------ tests/by-util/test_join.rs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/uu/join/src/join.rs b/src/uu/join/src/join.rs index 0050bf0c32d..9bf136d3a29 100644 --- a/src/uu/join/src/join.rs +++ b/src/uu/join/src/join.rs @@ -849,12 +849,18 @@ fn parse_settings(matches: &clap::ArgMatches, diag_args: Option<&[OsString]>) -> settings.empty = empty.as_bytes().to_vec(); } - if matches.get_flag("nocheck-order") { - settings.check_order = CheckOrder::Disabled; - } - - if matches.get_flag("check-order") { - settings.check_order = CheckOrder::Enabled; + let nocheck_idx = matches + .indices_of("nocheck-order") + .and_then(|mut i| i.next_back()); + let check_idx = matches + .indices_of("check-order") + .and_then(|mut i| i.next_back()); + match (check_idx, nocheck_idx) { + (Some(c), Some(n)) if c > n => settings.check_order = CheckOrder::Enabled, + (Some(c), Some(n)) if n > c => settings.check_order = CheckOrder::Disabled, + (Some(_), None) => settings.check_order = CheckOrder::Enabled, + (None, Some(_)) => settings.check_order = CheckOrder::Disabled, + _ => {} } if matches.get_flag("header") { diff --git a/tests/by-util/test_join.rs b/tests/by-util/test_join.rs index 21334bd6b67..913f4875a42 100644 --- a/tests/by-util/test_join.rs +++ b/tests/by-util/test_join.rs @@ -1038,3 +1038,22 @@ fn test_missing_key_is_empty_key() { .succeeds() .stdout_only("1002 bob\n"); } + +#[test] +fn check_order_nocheck_order_last_wins() { + // --nocheck-order after --check-order: nocheck wins, unsorted input succeeds. + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.write("unsorted.txt", "b\na\n"); + ts.ucmd() + .args(&["--check-order", "--nocheck-order", "unsorted.txt", "unsorted.txt"]) + .succeeds() + .stdout_contains("a") + .stdout_contains("b"); + + // --check-order after --nocheck-order: check wins, unsorted input fails. + ts.ucmd() + .args(&["--nocheck-order", "--check-order", "unsorted.txt", "unsorted.txt"]) + .fails() + .stderr_contains("is not sorted"); +} From fcdb428dbd978088181f9795fd587591745fc0b3 Mon Sep 17 00:00:00 2001 From: naufalfx805-source Date: Sat, 31 Oct 2026 22:54:29 +0700 Subject: [PATCH 2/2] refactor: use clap overrides_with for check-order last-wins Replace manual indices_of() comparison with clap's built-in overrides_with mechanism, as suggested in review. Co-Authored-By: Claude Opus 4.6 Claude-Session: https://claude.ai/code/session_01Gc3pLfULRGQmfBnqr3oo3D --- src/uu/join/src/join.rs | 18 ++++++------------ tests/by-util/test_join.rs | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/uu/join/src/join.rs b/src/uu/join/src/join.rs index 9bf136d3a29..61b972b247f 100644 --- a/src/uu/join/src/join.rs +++ b/src/uu/join/src/join.rs @@ -849,18 +849,10 @@ fn parse_settings(matches: &clap::ArgMatches, diag_args: Option<&[OsString]>) -> settings.empty = empty.as_bytes().to_vec(); } - let nocheck_idx = matches - .indices_of("nocheck-order") - .and_then(|mut i| i.next_back()); - let check_idx = matches - .indices_of("check-order") - .and_then(|mut i| i.next_back()); - match (check_idx, nocheck_idx) { - (Some(c), Some(n)) if c > n => settings.check_order = CheckOrder::Enabled, - (Some(c), Some(n)) if n > c => settings.check_order = CheckOrder::Disabled, - (Some(_), None) => settings.check_order = CheckOrder::Enabled, - (None, Some(_)) => settings.check_order = CheckOrder::Disabled, - _ => {} + if matches.get_flag("check-order") { + settings.check_order = CheckOrder::Enabled; + } else if matches.get_flag("nocheck-order") { + settings.check_order = CheckOrder::Disabled; } if matches.get_flag("header") { @@ -1022,12 +1014,14 @@ pub fn uu_app() -> Command { Arg::new("check-order") .long("check-order") .help(translate!("join-help-check-order")) + .overrides_with("nocheck-order") .action(ArgAction::SetTrue), ) .arg( Arg::new("nocheck-order") .long("nocheck-order") .help(translate!("join-help-nocheck-order")) + .overrides_with("check-order") .action(ArgAction::SetTrue), ) .arg( diff --git a/tests/by-util/test_join.rs b/tests/by-util/test_join.rs index 913f4875a42..b8224a29385 100644 --- a/tests/by-util/test_join.rs +++ b/tests/by-util/test_join.rs @@ -1046,14 +1046,24 @@ fn check_order_nocheck_order_last_wins() { let at = &ts.fixtures; at.write("unsorted.txt", "b\na\n"); ts.ucmd() - .args(&["--check-order", "--nocheck-order", "unsorted.txt", "unsorted.txt"]) + .args(&[ + "--check-order", + "--nocheck-order", + "unsorted.txt", + "unsorted.txt", + ]) .succeeds() .stdout_contains("a") .stdout_contains("b"); // --check-order after --nocheck-order: check wins, unsorted input fails. ts.ucmd() - .args(&["--nocheck-order", "--check-order", "unsorted.txt", "unsorted.txt"]) + .args(&[ + "--nocheck-order", + "--check-order", + "unsorted.txt", + "unsorted.txt", + ]) .fails() .stderr_contains("is not sorted"); }