Pass addon arguments through verbatim, as documented - #2699
Conversation
… flags The pre-cmdargs required-value check used the union of every subcommand's required-value flags, and scanned past --, so a flag belonging to some other command was rejected with "needs a value" instead of being left for cmdargs or passed on to an addon. Now the check is given the flag set relevant to the identified command (its mode's flags for a builtin, hledger's general flags for an addon), and stops at the first --, as cmdargs does. [plaintextaccounting#2696] AI usage: claude-fable-5, ~35k output tokens
The addon argument list was rebuilt with filter (/="--"), removing every --, including ones the addon itself was meant to receive. Rebuild it from the individual argument sources instead, so that only the -- separating addon args from hledger's own is consumed, as documented. The separator is still added to the args cmdargs parses, so unknown addon flags are still accepted there. [plaintextaccounting#2696] AI usage: claude-opus-5, ~14k output tokens
dropCliSpecificOpts removed -n/--no-conf/--conf VAL from the whole addon argument list, so an addon could not be given those even by escaping them with --. Apply it only to the args preceding the first --; pass the rest through verbatim. Without a --, they keep their current meaning as hledger's own options, which the manual now states. [plaintextaccounting#2696] AI usage: claude-opus-5, ~14k output tokens
Addon arguments were joined into a shell command with quoteForCommandLine, which returns the empty string unquoted, so an empty argument disappeared before the addon saw it, and other quoting hazards applied. Run the addon with rawSystem instead, passing the arguments through untouched. Windows still goes through the shell, which is what runs .bat and other script addons there. [plaintextaccounting#2696] AI usage: claude-opus-5, ~14k output tokens
f6862ac to
6bd6c66
Compare
|
Thanks @kfkonrad. This seems not to satisfy the first-time contributor rule in the https://hledger.org/PULLREQUESTS.html I mentioned. That rule was added to screen out drive-by and policy-ignoring contributors. You're clearly not one of those (right ? :) so I might change this rule. On the other hand, complicating the rule and requiring maintainer judgement every time defeats the purpose a little bit. Is there any other small PR you'd like to submit manually to become a non-first-time contributor ? |
|
Also, the rule's wording has some ambiguity.
|
|
The changes look reasonable to my eye.. though when I've done similar fixups like adding a It would be good to test this also in |
|
I'm not a first time contributor, I hand-wrote this PR (and noted how I used AI in it, which was for a local review only): #2679 I can see if I can find another small PR to file manually if you'd like to see another one before getting partially AI-generated PRs from me. Ultimately the judgement is yours, regardless of what exactly the policy states |
|
I'll do some additional manual testing either way. If I find any interesting test cases I'll add them to the test cases in code too |
|
Ah, sorry! I wonder why github is saying so. never mind then
|
|
Somehow GH didn't register your #2679 and is still showing the first-time badge.. but this one will probably fix it. Please excuse my short memory :) I'll do some here testing too. I got this earlier - you may have seen similar but I'm sharing it in case it's useful. A few of these look worth fixing up, or if you prefer I could do it. https://claude.ai/code/session_019zkbChUyusi3ndEy45t8ar |
|
I see we were literally chatting yesterday. Now I have the nicks wired up. These changes look good. I'll give it a little time for us to use it and possible polish. |
Commit 4 of plaintextaccounting#2699 replaces system with rawSystem off Windows. A script with no shebang runs under a shell either way, but under rawSystem only because execvp falls back to sh on ENOEXEC. Checking that holds on linux and windows, not just macos. AI usage: Claude Opus 5, ~3k output tokens
Not for merging. This is plaintextaccounting#2699 with the addon tests enabled in CI and one case added, to find out what linux does. Commit 4 of plaintextaccounting#2699 replaces system with rawSystem off Windows. A script with no shebang line runs under a shell either way; under rawSystem it runs only if exec falls back to sh on ENOEXEC. GHC's rawSystem uses posix_spawnp, which does not do that, though apple's libc appears to. Probing that mechanism directly: darwin ExitSuccess, "noshebang ran" ubuntu-24.04 FAILED: posix_spawnp: invalid argument (Exec format error) Case 14 exercises it through hledger itself. It passes on macos with both main and plaintextaccounting#2699. This run is to see linux. AI usage: Claude Opus 5, ~7k output tokens
hledger treats the first "--" as its own separator and does not pass it to
the addon. This branch does that for command line args only; a "--" written
in the addon's config file section is passed on. main stripped every "--",
so it never was.
[addon]
alpha -- beta
$ hledger --conf CONF addon gamma
main args: alpha beta gamma
this branch args: alpha -- beta gamma
with this fix args: alpha beta gamma
One asymmetry remains: hledger's own options (--conf, --no-conf, -n) are
still stripped from config args written after a "--", but not from command
line args after one. That matches main, so this leaves it alone.
Test 14 in addons.test covers it.
Applies on top of plaintextaccounting#2699, which introduced this.
AI usage: Claude Opus 5, ~8k output tokens
|
I hope you two don't mind if I crash the party, but this was an interesting looking problem that gave me a good excuse to learn our ci system and the various ways to invoke hledger and pass it arguments. Summary: I opened a pull request against this branch to fix the -- processing. I had one other finding that I think we shouldn't fix. I opened a few unrelated pr's as a result of what I observed while working through this. Sequencing would be for @kfkonrad to merge kfkonrad#1 before merging this pr into main. PR #2699 review — hledger addon argument passing (#2696) Method: built Action items
I reviewed Simon's claude session log. Everything else I've done her is either verification that the PR does what it says, or defects that predate it and are handled elsewhere (see below). Reported cases
|
hledger ui "Trader Joe's" |
result |
|---|---|
| main | argument not delivered; the command fails |
| this PR | runs |
Covered with test (in pr I opened against @kfkonrad's branch see Action 2 section below):
# ** 17. An argument containing an apostrophe is preserved.
$ PATH=$PATH:addons hledger argvdump "Sam's Diner"
argv: [Sam's Diner]
Action 1 — a shebang-less addon script no longer runs on linux
6bd6c66ba replaces system with rawSystem on every platform except Windows. A script with no #! line no longer runs.
| main | this PR | |
|---|---|---|
| macOS | runs | runs |
| linux | runs | produces nothing |
Confirmed on ubuntu-24.04 in a real CI run of this branch, with the addon tests enabled: cases 1-13 [OK], the shebang-less case [Failed] with empty stdout and empty stderr — https://github.com/acinader/hledger/actions/runs/33284617328
It fails silently, so the command appears to do nothing at all. The same mechanism, probed directly:
darwin ExitSuccess
ubuntu-24.04 FAILED: posix_spawnp: invalid argument (Exec format error)
run and repl are not affected — they still dispatch through the shell, so only the direct hledger ADDON path breaks.
Shebang-less scripts are unusual but legal. Probably better to not fix, see if it causes anyone an issue, and then try to better understand why this behavior is needed.
Action 2 — the -- in a config file section or alias (session finding 1)
I tried the fix sketched in Simon's session: break the whole concatenation once, then dropCliSpecificOpts the part before the separator, which is not a complete solution. The sources are joined as conf <> alias <> cli, so a -- from a config section or alias falls before the command line args and moves them all into the "after" partition, where hledger's own options are deliberately not stripped:
[argvdump] section containing "alpha -- beta", run as: hledger --conf CONF argvdump gamma
main argv: [alpha] [beta] [gamma]
this PR argv: [alpha] [--] [beta] [gamma]
sketched argv: [alpha] [beta] [--conf] [CONF] [gamma] <- leaks --conf
per-source argv: [alpha] [beta] [gamma]
Each source has to consume its own first --:
consumeSeparator as = let (bs, cs) = breakAtFirstSeparator as in dropCliSpecificOpts bs <> cs
addonargs = concatMap consumeSeparator
[supportedgenargsfromconf, confcmdargs0, aliasargs, cliargswithoutcmd]Simon observed that -- -n works only from the command line. With a per-source separator it works from a config section and an alias too.
I opened a PR against Konrad's branch with the fix and four test cases — three for the separator, one for the apostrophe above: kfkonrad#1
Bonus: unrelated bugs found along the way
The new addon tests do not run in CI. -x /addons prevents 10 of the 13 new cases from running. just functest does run them locally. The exclusion is vestigial: 1afe5fb (2017) added it when the dummy addons were gitignored and never turned back on. #2710 turns the addon tests back on.
Empty arguments are lost wherever a shell command line is built. see #2711 for details
AI usage: Claude Opus 5, ~50k output tokens
Fixes #2696: pass addon arguments through verbatim, as documented.
As we discussed in chat and in #2696 I split the changes into four commits in the following order:
--, sohledger foo --sortandhledger help --sortfailed with "--sort needs a value". It is now given only the flags relevant to the identified command, and stops at the first--.filter (/="--")removed every--from the addon's arguments. Only the escaping one is consumed now; later ones are passed on.-n/--no-conf/--conf VALwere stripped from the whole addon argument list. They are now stripped only before the first--, sohledger foo -- -ndelivers-n. Without a--they keep their current meaning as hledger's own options; the manual says so now.rawSystemrather than a shell command line, so empty and shell-significant arguments survive.Tests: A total of 12 new cases in hledger/test/cli/addons.test and cli.test, using a new
hledger-argvdumpdummy addon (as demoed in #2696). All tests passed on my machine for each commit.Note that commit 4 only fixes the issue on unix-like systems. For Windows we still shell out to cmd, which presumably swallows empty arguments (
""). I can try to verify this on my Windows machine soon. I'm mostly using a Mac or Linux these days. So no regression on Windows but also presumably no fix. If I can verify that behavior I'll work around that too in a 5th commit.I also noticed that
hledger runmay be subject to similar bugs regarding empty or shell-significant arguments (like"'"). I may file a separate issue if I can confirm that so that heldger and hledger run behave the same when using addons. As I don't use hledger run myself I'm not sure if changing its argument parsing or dispatch might brake existing use cases.AI usage: written with some help from Claude Opus, from a plan created with Claude Fable. Some finer adjustments in the plan were my doing and I made sure to test and review each commit thoroughly. Usage in output token is denoted on each commit. btw: I chose to keep with the existing pattern of only documenting use of one model per commit, which is why the plan's AI usage is included in the first commit and the implementation is divvied up among the rest.