{"thread":{"id":"42537","subject":"[BUG?] trailer command with multiple keys","startedAt":"2016-06-06T12:27:52Z","lastAt":"2016-06-06T17:07:37Z","messageCount":2,"participants":["Michael J Gruber","Christian Couder"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"288424","messageId":"b94e1666-2f89-619b-112c-023f72002d9d@drmicha.warpmail.net","threadId":"42537","inReplyTo":null,"subject":"[BUG?] trailer command with multiple keys","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2016-06-06T12:27:52Z","receivedAt":"2016-06-06T12:27:52Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"The command\n\nprintf \"body\\n\\ntest: foo\\ntest: froz\\n\" | git -c\ntrailer.test.key=tested -c trailer.test.command=\"echo by \\$ARG\"\ninterpret-trailers\n\ngives:\n\nbody\n\ntested: foo\ntested: froz\ntested: by froz\n\nI expected the command to be run on each \"test\" key, resulting in the\noutput:\n\nbody:\n\ntested: by foo\ntested: by froz\n\n(In a real life scenario, I would use ifexists replace.)[*]\n\nMaybe my expectation is wrong? The code breaks out of the loop after the\nfirst matching in_tok, apparently intentionally so. But I'm not sure -\nthe key is replaced for both instances.\n\nSimply replacing that \"return 1\" by a \"ret = 1\" etc. runs into problems\nwith the way the freeing of in_tok and arg_tok is arranged there :|\n\nBasically, I expected the trailer command to work \"grep/sed-like\" on all\nkey value pairs that have matching keys, passing the value to the\ncommand, and using the (each) command's output as the new value for each\nof these pairs.\n\nMichael\n\n[*] My prime use case: fill in reported-by etc. with short author names,\ncompleted the same way we complete --author=jun using a trailer command\n(interpret-trailers in the commit-msg hook):\n\n$ git help author\n`git author' is aliased to `!f() { a=$(git log -1 --all -i --format=\"%aN\n<%aE>\" --author \"$1\"); echo ${a:-$1}; }; f'\n\n$ cat .git/hooks/commit-msg\n#!/bin/sh\ngit interpret-trailers --in-place \"$1\"\n\n$ git config --get-regexp trailer\ntrailer.report.key Reported-by\ntrailer.report.command git author '$ARG'\ntrailer.report.ifexists replace\ntrailer.report.ifmissing doNothing\n"},{"id":"288460","messageId":"CAP8UFD3ZE3XooL02DNEvDO85uBK_+FpTiqb+cx5hZ83tWassNg@mail.gmail.com","threadId":"42537","inReplyTo":"b94e1666-2f89-619b-112c-023f72002d9d@drmicha.warpmail.net","subject":"Re: [BUG?] trailer command with multiple keys","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2016-06-06T17:07:37Z","receivedAt":"2016-06-06T17:07:37Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Mon, Jun 6, 2016 at 2:27 PM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n> The command\n>\n> printf \"body\\n\\ntest: foo\\ntest: froz\\n\" | git -c\n> trailer.test.key=tested -c trailer.test.command=\"echo by \\$ARG\"\n> interpret-trailers\n>\n> gives:\n>\n> body\n>\n> tested: foo\n> tested: froz\n> tested: by froz\n>\n> I expected the command to be run on each \"test\" key, resulting in the\n> output:\n>\n> body:\n>\n> tested: by foo\n> tested: by froz\n>\n> (In a real life scenario, I would use ifexists replace.)[*]\n>\n> Maybe my expectation is wrong?\n\nI wouldn't say that it is wrong, but for now trailer configuration\napplies mostly to trailer passed as argument to `git\ninterpret-trailers`.\n\nSo you could perhaps get something close to what you want with:\n\n--------\n$ printf \"body\\n\\n\" | git -c trailer.test.key=tested -c\ntrailer.test.command=\"/home/christian/git/test/interpret-trailers/trailer-script.sh\n\\$ARG\"  interpret-trailers --trim-empty --trailer='test: foo'\n--trailer='test: frotz'\nbody\n\ntested: by foo\ntested: by frotz\n--------\n\nand:\n\n--------\n$ cat /home/christian/git/test/interpret-trailers/trailer-script.sh\n#!/bin/sh\ntest -n \"$1\" && echo \"by $1\"\n:\n--------\n\n> The code breaks out of the loop after the\n> first matching in_tok, apparently intentionally so. But I'm not sure -\n> the key is replaced for both instances.\n>\n> Simply replacing that \"return 1\" by a \"ret = 1\" etc. runs into problems\n> with the way the freeing of in_tok and arg_tok is arranged there :|\n>\n> Basically, I expected the trailer command to work \"grep/sed-like\" on all\n> key value pairs that have matching keys, passing the value to the\n> command, and using the (each) command's output as the new value for each\n> of these pairs.\n\nYeah, it could have been designed like that.\n\nThe problem is that something like:\n\n               $ git config trailer.sign.key \"Signed-off-by: \"\n               $ git config trailer.sign.ifmissing add\n               $ git config trailer.sign.ifexists doNothing\n               $ git config trailer.sign.command 'echo \"$(git config\nuser.name) <$(git config user.email)>\"'\n\nand piping any commit message into \"git interpret-trailers\" should work too.\n\nIn short it's not very natural to have both of the following by default:\n\n- a configured command should run once to get a chance to add a new\ntrailer, even it doesn't exist in the input file\n- a configured command should run once per trailer in the input file\n\n(especially because as I said above for now configuration applies\nmostly to trailers on the command line).\n\nOne solution could be to add support for a new\ntrailer.<token>.commandMode config option that could take values like\n\"onceAnyway\", \"oncePerMatchingTrailerInInputFile\",\n\"oncePerMatchingTrailerOnCommandLine\" and it should be possible to use\none or more of those modes, like for example:\n\ntrailer.stuff.commandMode=onceAnyway,oncePerMatchingTrailerInInputFile\n\n> [*] My prime use case: fill in reported-by etc. with short author names,\n> completed the same way we complete --author=jun using a trailer command\n> (interpret-trailers in the commit-msg hook):\n>\n> $ git help author\n> `git author' is aliased to `!f() { a=$(git log -1 --all -i --format=\"%aN\n> <%aE>\" --author \"$1\"); echo ${a:-$1}; }; f'\n>\n> $ cat .git/hooks/commit-msg\n> #!/bin/sh\n> git interpret-trailers --in-place \"$1\"\n>\n> $ git config --get-regexp trailer\n> trailer.report.key Reported-by\n> trailer.report.command git author '$ARG'\n> trailer.report.ifexists replace\n> trailer.report.ifmissing doNothing\n\nYeah, it would be nice to be able to have things like that.\n"}]}