Repository navigation
join: support -o field lists supplied as separate arguments - #15245
ozenyunus35 wants to merge 3 commits into
Conversation
GNU join accepts the fields of -o as separate operands, as in `join -o 1.1 1.2 2.2 file1 file2`: when an operand comes on top of two pending ones right after -o, the oldest pending one is taken as more of the field list if it is one. uutils reported an extra operand instead. Do the same, taking only as many operands as needed to leave two files, so `join -o 1.1 1.2 2.2 f1` still tries to open 2.2. This fixes the o-sep-unquoted-spaces, o-sep-unquoted-tabs and o-sep-space-enoent cases of the GNU test tests/join/join.pl.
|
GNU testsuite comparison: |
On Windows the name in the error is quoted ('2.2'), so check the parts
of the message instead of the exact line.
|
@ozenyunus35 Please avoid using "Partially addresses" in the PR description when referencing a tracker issue. Instead, please open a new issue to track the work if one doesn't already exist. |
| let mut specs = vec![]; | ||
| for format in formats { | ||
| let mut operand_formats = operand_formats.into_iter().peekable(); | ||
| let indices = matches.indices_of("o").into_iter().flatten(); |
There was a problem hiding this comment.
do we really need to interleave by clap index? quite a lot of logic for a rare case, please add a test showing the order matters if we keep it
| indices.map(move |index| (index, id)) | ||
| }) | ||
| .collect(); | ||
| let follows_o = |index: usize| { |
There was a problem hiding this comment.
this checks the option before the third operand, not the one before the field list itself.
so join -o 1.1 1.2 -t , a b still says extra operand, and join -t , 1.2 -o 1.1 a b is accepted. could you please check what GNU does and add tests for both?
| let mut formats = vec![]; | ||
| for (index, name) in operands { | ||
| if names.len() == 2 { | ||
| match names[0].to_str().and_then(parse_field_list) { |
There was a problem hiding this comment.
only names[0] is tried here, so join a -o 1.1 1.2 b fails with extra operand. is that expected? please add a test either way
| } | ||
|
|
||
| #[test] | ||
| fn format_list_in_separate_operands() { |
There was a problem hiding this comment.
please prefix it with test_
| translate!("join-error-extra-operand", "operand" => extra.quote()), | ||
| )); | ||
| } | ||
| // Operand errors are reported after option errors, as before. |
There was a problem hiding this comment.
the as_mut/mem::take dance is hard to follow, could parse_settings just take &[...] and we ? the operands afterwards?
and "as before" won't mean anything once this is merged
There was a problem hiding this comment.
"as before" won't mean anything once this is merged
@sylvestre I’ve noticed quite a few similar "as before" comments in code. I wonder if Claude Code tends to treat comments as a way to narrate the diff rather than explain the code itself. Personally, I’d rather AI didn’t write comments at all.
| .args(&["-o", "1.1", "1.2", "2.2", "a"]) | ||
| .fails_with_code(1) | ||
| .no_stdout() | ||
| .stderr_contains("2.2") |
There was a problem hiding this comment.
a bit weak, could you please check the full line, e.g. join: 2.2: No such file or directory?
Follow GNU's add_file_name: an operand that follows a -o field list (or another such operand) might be more of it, and the older pending one is taken when a third operand comes. This also accepts other options in between and keeps the fields in the order GNU adds them.
|
@sylvestre reworked in 645b35e: operands are now taken as field lists the same way GNU's |
Merging this PR will regress 1 benchmark
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Simulation | five_38_bit_primes |
1.7 s | 1.8 s | -6.42% |
| ⚡ | Simulation | three_39_bit_primes |
490.4 ms | 413.9 ms | +18.48% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing ozenyunus35:fix/join-o-separate-operands (645b35e) with main (efca981)2
Footnotes
-
54 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
No successful run was found on
main(d43f2b8) during the generation of this report, so efca981 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩
Closes #15279
Summary
Partially addresses #14705.
GNU
joinsupports specifying the-ooutput field list as separate command-line arguments:Previously, uutils
joininterpreted the additional field specifications as file operands and failed with anextra operanderror.This PR updates operand parsing to support the GNU-compatible behavior.
Changes
-o.Regression Tests
Added tests covering:
-ofield specifications supplied as separate arguments.The new regression test fails on the original implementation and passes with this change.
Validation
test_join: 44/44 passedcargo fmt --check: passedGNU's
tests/join/join.plwas also used as a black-box compatibility test.Before this fix, three
o-sep-*cases failed:o-sep-unquoted-spaceso-sep-unquoted-tabso-sep-space-enoentAll three pass with this change.
The two remaining failures,
ee1andee2, are addressed separately in #15244. Applying both PRs together makes the complete GNUjoin.pltest pass.The changes were also tested together in a temporary worktree and applied without conflicts.
Scope and Compatibility
This PR focuses on
-oargument parsing. Ordinary two-file invocations remain unchanged.GNU's behavior and test expectations were used as compatibility references. No GNU implementation code was copied.
AI Assistance
Claude Code assisted with implementation and testing. The changes were reviewed before submission.