fix(install): match a quoted fish path, spaces included - #439
Conversation
rc_lists_dir field-split fish_add_path arguments on whitespace. Since #434 started writing fish_add_path "$PREFIX", a prefix containing spaces became two fields, matched neither, and the installer appended a SECOND block directly beneath an existing line naming the same directory -- while reporting that it had added a PATH entry that was already there. The read path now parses quotes like the ownership reader further up the file already does: a quoted argument is one path, spaces included, while an unquoted line still splits so several bare paths on one line keep working. Single quotes are handled too, which the old code also missed. Verified in both directions: the two new harness cases fail against the current installer (29 passed / 2 failed) and pass with this change (31 passed / 0 failed). Found by Bugbot on the develop->staging promotion (cli#438).
|
bugbot run |
|
👋 Heads-up — Code review queue is at 34 / 30 Above the WIP limit. The team convention is to review existing PRs before opening new work. Open PRs currently in Code review (oldest first):
Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.) |
shujaatTracebloc
left a comment
There was a problem hiding this comment.
Reviewed and verified locally.
Diagnosis is correct. rc_lists_dir's fish branch field-split fish_add_path arguments on whitespace, while since #434 we write fish_add_path "$PREFIX". A prefix with spaces arrived as two fields, matched nothing, and the installer appended a duplicate block while reporting it had added the entry — the write path quoted, the read path split.
Fix is sound. The quote-aware parse (double + single quotes as one path, unquoted still whitespace-split, leading flags skipped) now agrees with the space-safe sibling reader in strip_tb_path_block. Downstream, candidates still get quotes/parens stripped and trailing slashes normalized, so the #433 component-match guarantee is preserved.
Verified in both directions myself:
- With the fix:
install-verify: 31 passed, 0 failed. - Reverted to the old field-split one-liner:
29 passed, 2 failed, and the failure output is exactly the bug — a secondfish_add_pathblock appended below an existing line for the same directory. So the two new cases genuinely exercise the regression. - Ran an extra adversarial matrix directly against the awk (14 cases): quoted/unquoted, single/double,
-gand--pathflags, trailing-slash normalization on both sides, leading indent, plus negatives (/opt/tbvs/opt/tb2substring, comment line, bare mention) — all correct.
CI green across the board; Cursor Bugbot completed with no findings on 95cb01d. LGTM.
A greedy /^.*fish_add_path/ strips through the LAST occurrence on the line, so an inline comment mentioning fish_add_path left the comment text as the path and missed the real argument -- reintroducing the exact bug this branch fixes. index() takes the first occurrence instead. Also restores the leading-whitespace strip that the greedy regex used to consume: without it substr() left ' "/path"', so the quote check saw a space and fell back to field-splitting, breaking the spaced-path fix. Caught by re-running the whole case set rather than only the new one. Bugbot, cli#439.
A greedy /^.*fish_add_path/ strips through the LAST occurrence on the line, so an inline comment mentioning fish_add_path left the comment text as the path and missed the real argument -- reintroducing the exact bug this branch fixes. index() takes the first occurrence instead. Also restores the leading-whitespace strip that the greedy regex used to consume: without it substr() left ' "/path"', so the quote check saw a space and fell back to field-splitting, breaking the spaced-path fix. Caught by re-running the whole case set rather than only the new one. Bugbot, cli#439.
|
Correct — fixed, and it caught a second problem on the way. The greedy The second problem, which my own re-test caught: Worth naming: I only found that because I re-ran the whole case set rather than just the new case. Fixing one edge case and re-testing only that edge case would have shipped a PR that no longer did its own job. Verified in both directions again: Plus all twelve direct variants green — the comment case, both quote styles with spaces, multi-path lines,
bugbot run |
Replaces three rounds of patching with one quote-aware tokenizer, because
each patch fixed its own case and broke or missed another:
* greedy .* strip lost the real argument to an inline comment
* index() alone dropped the leading space, so the quote check failed
and spaced paths regressed
* taking only the first quoted argument missed the prefix when
fish_add_path lists several directories
The loop now walks the argument list: quoted tokens are one path (spaces
included), bare tokens split on whitespace, flags are skipped, and a
trailing # comment ends parsing. 18 direct variants and 33 harness cases
green.
Bugbot, cli#439.
Replaces three rounds of patching with one quote-aware tokenizer, because
each patch fixed its own case and broke or missed another:
* greedy .* strip lost the real argument to an inline comment
* index() alone dropped the leading space, so the quote check failed
and spaced paths regressed
* taking only the first quoted argument missed the prefix when
fish_add_path lists several directories
The loop now walks the argument list: quoted tokens are one path (spaces
included), bare tokens split on whitespace, flags are skipped, and a
trailing # comment ends parsing. 18 direct variants and 33 harness cases
green.
Bugbot, cli#439.
|
Right again — and I've stopped patching and written the thing properly. You're correct that That's three rounds on one small function, and each patch fixed its own case while breaking or missing another:
So it is now a single tokenizer rather than accumulated special cases: walk the argument list; a quoted token is one path (spaces included) and parsing continues past its closing quote; bare tokens split on whitespace; flags are skipped; a trailing Verified: 18 direct variants (both quote styles, multi-arg quoted/bare/mixed, flags mid-list, inline comments, unterminated quote, trailing-slash normalisation, and four negatives including "a flag must never be a candidate") plus the harness, checked in both directions: The lesson I should have applied two rounds ago: when a parser keeps failing on new input shapes, the input needs parsing, not another regex. Three review rounds is the cost of not doing that first. bugbot run |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c73e366. Configure here.
|
/fr-pass |
Closes the last open Bugbot finding from today's staging promotion (cli#438). It's a regression introduced by #434, so worth fixing before it reaches a customer.
The bug
rc_lists_dirfield-splitfish_add_patharguments on whitespace:#434 started writing
fish_add_path "$PREFIX". So a prefix containing spaces arrived here as two fields —"/opt/myandtools/bin"— matched neither, and the installer appended a second block directly beneath a line already naming that exact directory, while printing that it had added a PATH entry. Self-inconsistent within one change: the write path quotes, the read path splits.Notably the ownership reader further up the same file (the
^[[:space:]]*fish_add_path[[:space:]]branch) already keeps the remainder intact and is space-safe — so one reader was right and the other wasn't.The fix
The fish branch now parses quotes rather than field-splitting:
fish_add_path /opt/a /opt/bkeeps working-g,-p, …) are still skippedVerified in both directions
The two new harness cases fail against the current installer and pass with the change — I checked that rather than assuming they cover it:
The pre-fix failure output shows the bug exactly: the installer's own block appended immediately below an existing
fish_add_pathfor the same directory.Also exercised directly across ten variants (quoted/unquoted, single/double, spaces, multiple paths,
-gflag, comment lines, trailing-slash normalisation, and negative cases) — all correct, with the two space cases flipping from unmatched to matched and nothing else changing.sh -n,dash -n,bash -nandshellcheck --shell=shall clean.Note
Low Risk
Scoped to installer awk PATH detection for fish shells; behavior change only affects idempotent rc writes and messaging, with targeted harness coverage.
Overview
Fixes a #434 regression where the installer writes
fish_add_path "$PREFIX"butrc_lists_dirsplit arguments on whitespace, so prefixes with spaces were not seen as already listed and a duplicate PATH block could be appended.rc_lists_dirininstall.shnow tokenizesfish_add_patharguments with a small quote-aware parser (firstfish_add_pathviaindex(), not a greedy strip; double/single quotes; multiple paths per line; flags skipped; stops at#comments), aligned with the ownership reader above it.install-verify.shadds cases 16–18: spaced prefixes in double/single quotes, inline comments mentioningfish_add_path, and the install prefix as the second quoted argument on a multi-path line.Reviewed by Cursor Bugbot for commit c73e366. Bugbot is set up for automated code reviews on this repo. Configure here.