trailer: change $ARG to environment variable
PATCH 1/1 trailer: change $ARG to environment variable
From: ZheNing Hu <[email protected]>
In the original implementation of trailer.<token>.command, use strbuf_replace to replace $ARG in the <value> of the trailer, but it have a problem:strbuf_replace replace the $ARG in command only once, If the user's trailer command have used more then one $ARG, error will occur.
So pass $ARG as an environment variable to the trailer command, all $ARG in the command will be replaced, which will fix this problem.
---
[GSOC] trailer: change $ARG to environment variable
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG.
The current new solution is to pass $ARG as an environment variable into the command.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Documentation/git-interpret-trailers.txt | 3 ++- t/t7513-interpret-trailers.sh | 17 +++++++++++++++++ trailer.c | 9 ++++++--- 3 files changed, 25 insertions(+), 4 deletions(-)
Documentation/git-interpret-trailers.txt +2 -1
@@ -242,7 +242,8 @@ line, where <value> is taken to be the standard output of the specified command with any leading and trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be +If the command contains the `$ARG` string (`$ARG` is an exported +environment variable), this string will be replaced with the <value> part of an existing trailer with the same <token>, if any, before the command is launched. +
t/t7513-interpret-trailers.sh +17 -0
@@ -1291,6 +1291,23 @@ test_expect_success 'with command using $ARG' ' test_cmp expected actual ' +test_expect_success 'with command using more than one $ARG' ' + git config trailer.fix.ifExists "replace" && + git config trailer.fix.command "test -n $ARG && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG || true" && + FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-EOF && + Fixes: $FIXED + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <[email protected]> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual && + test_cmp expected actual +' + test_expect_success 'with failing command using $ARG' ' git config trailer.fix.ifExists "replace" && git config trailer.fix.command "false \$ARG" &&
trailer.c +6 -3
@@ -44,7 +44,7 @@ static char *separators = ":";static int configured; -#define TRAILER_ARG_STRING "$ARG" +#define TRAILER_ARG_STRING "ARG"static const char *git_generated_prefixes[] = {"Signed-off-by: " ,
@@ -222,13 +222,16 @@ static char *apply_command(const char *command, const char *arg)struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; +const char *const *var;strbuf_addstr (&cmd, command); +for (var = local_repo_env; *var; var++) +strvec_push (&cp.env_array, *var);if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_pushf (&cp.env_array,"%s=%s" ,TRAILER_ARG_STRING , arg);strvec_push (&cp.args, cmd.buf); - cp.env = local_repo_env; + cp.no_stdin =1 ; cp.use_shell =1 ;
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
PATCH v2 1/1 trailer: pass arg as positional parameter
From: ZheNing Hu <[email protected]>
In the original implementation of trailer.<token>.command, use strbuf_replace to replace $ARG in the <value> of the trailer, but it have a problem: strbuf_replace replace the $ARG in command only once, If the user's trailer command have used more than one $ARG, error will occur.
If directly modify the implementation of the original trailer.<token>.command, The user’s previous '$ARG' in trailer command will not be replaced. So now add new config "trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, users can use $1 as trailer's value, to implement original variable replacement.
Original trailer.<token>.command can still be used until git completely abandoned it.
---
[GSOC]trailer: pass arg as positional parameter
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v1:
1: abc5b04d152f ! 1: 185356d6fc90 [GSOC]trailer: change $ARG to environment variable
@@ Metadata
Author: ZheNing Hu <[email protected]>
## Commit message ##
- [GSOC]trailer: change $ARG to environment variable
+ [GSOC]trailer: pass arg as positional parameter
In the original implementation of trailer.<token>.command,
- use strbuf_replace to replace $ARG in the <value> of the trailer,
- but it have a problem:strbuf_replace replace the $ARG in command
- only once, If the user's trailer command have used more then one $ARG,
- error will occur.
+ use strbuf_replace to replace $ARG in the <value> of the
+ trailer, but it have a problem: strbuf_replace replace the
+ $ARG in command only once, If the user's trailer command have
+ used more than one $ARG, error will occur.
- So pass $ARG as an environment variable to the trailer command,
- all $ARG in the command will be replaced, which will fix this problem.
+ If directly modify the implementation of the original
+ trailer.<token>.command, The user’s previous '$ARG' in
+ trailer command will not be replaced. So now add new
+ config "trailer.<token>.cmd", pass trailer's value as
+ positional parameter 1 to the user's command, users can
+ use $1 as trailer's value, to implement original variable
+ replacement.
+
+ Original trailer.<token>.command can still be used until git
+ completely abandoned it.
## Documentation/git-interpret-trailers.txt ##
-@@ Documentation/git-interpret-trailers.txt: line, where <value> is taken to be the standard output of the
- specified command with any leading and trailing whitespace trimmed
- off.
- +
--If the command contains the $ARG string, this string will be
-+If the command contains the $ARG string ($ARG is an exported
-+environment variable), this string will be
- replaced with the <value> part of an existing trailer with the same
- <token>, if any, before the command is launched.
- +
+@@ Documentation/git-interpret-trailers.txt: also be executed for each of these arguments. And the <value> part of
+ these arguments, if any, will be used to replace the $ARG string in
+ the command.
+
++trailer.<token>.cmd::
++ Similar to 'trailer.<token>.command'. But the difference is that
++ $1 is used in the command to replace the value of the trailer
++ instead of the original $ARG, which means that we can quote the
++ trailer value multiple times in the command.
++ E.g. trailer.sign.cmd="test -n \"$1\" && echo \"$1\" || true "
++
+ EXAMPLES
+ --------
+
## t/t7513-interpret-trailers.sh ##
-@@ t/t7513-interpret-trailers.sh: test_expect_success 'with command using $ARG' '
- test_cmp expected actual
+@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
+ git commit -m "Add file a.txt"
'
-+test_expect_success 'with command using more than one $ARG' ' ++test_expect_success 'with cmd using $1' '
++ test_when_finished "git config --unset trailer.fix.cmd" &&
+ git config trailer.fix.ifExists "replace" &&
-+ git config trailer.fix.command "test -n $ARG && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG || true" &&
++ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" \
++ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
+ FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
-+ cat complex_message_body >expected &&
-+ sed -e "s/ Z\$/ /" >>expected <<-EOF &&
++ cat complex_message_body >expected2 &&
++ sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
+ Fixes: $FIXED
+ Acked-by= Z
+ Reviewed-by:
@@ t/t7513-interpret-trailers.sh: test_expect_success 'with command using $ARG' '
+ Signed-off-by: A U Thor <[email protected]>
+ EOF
+ git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \
-+ <complex_message >actual &&
-+ test_cmp expected actual
++ <complex_message >actual2 &&
++ test_cmp expected2 actual2
+'
+
- test_expect_success 'with failing command using $ARG' '
+ test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" &&
- git config trailer.fix.command "false \$ARG" &&
+- git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
++ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
++ --abbrev-commit --abbrev=14 \$ARG" &&
+ FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-EOF &&
## trailer.c ##
-@@ trailer.c: static char *separators = ":";
-
- static int configured;
-
--#define TRAILER_ARG_STRING "$ARG"
-+#define TRAILER_ARG_STRING "ARG"
+@@ trailer.c: struct conf_info {
+ char *name;
+ char *key;
+ char *command;
++ int is_new_cmd;
+ enum trailer_where where;
+ enum trailer_if_exists if_exists;
+ enum trailer_if_missing if_missing;
+@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
+ return 1;
+ }
- static const char *git_generated_prefixes[] = {
- "Signed-off-by: ",
-@@ trailer.c: static char *apply_command(const char *command, const char *arg) +-static char *apply_command(const char *command, const char *arg) ++static char *apply_command(const char *command, int is_new_cmd , const char *arg)
+ {
+ struct strbuf cmd = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
- struct child_process cp = CHILD_PROCESS_INIT;
+@@ trailer.c: static char *apply_command(const char *command, const char *arg)
char *result;
-+ const char *const *var;
strbuf_addstr(&cmd, command);
-+ for (var = local_repo_env; *var; var++)
-+ strvec_push(&cp.env_array, *var);
- if (arg)
+- if (arg)
- strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
-+ strvec_pushf(&cp.env_array, "%s=%s", TRAILER_ARG_STRING, arg);
-
+-
strvec_push(&cp.args, cmd.buf);
-- cp.env = local_repo_env;
-+
++ if (arg) {
++ if (is_new_cmd)
++ strvec_push(&cp.args, arg);
++ else
++ strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
++ }
+ cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
+@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
+ else
+ arg = xstrdup("");
+ }
+- arg_tok->value = apply_command(arg_tok->conf.command, arg);
++ arg_tok->value = apply_command(arg_tok->conf.command, arg_tok->conf.is_new_cmd, arg);
+ free((char *)arg);
+ }
+ }
+@@ trailer.c: static struct arg_item *get_conf_item(const char *name)
+ return item;
+ }
+
+-enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_WHERE,
+- TRAILER_IF_EXISTS, TRAILER_IF_MISSING };
++enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_CMD,
++ TRAILER_WHERE, TRAILER_IF_EXISTS, TRAILER_IF_MISSING };
+ static struct {
+ const char *name;
+@@ trailer.c: static struct {
+ } trailer_config_items[] = {
+ { "key", TRAILER_KEY },
+ { "command", TRAILER_COMMAND },
++ { "cmd", TRAILER_CMD },
+ { "where", TRAILER_WHERE },
+ { "ifexists", TRAILER_IF_EXISTS },
+ { "ifmissing", TRAILER_IF_MISSING }
+@@ trailer.c: static int git_trailer_config(const char *conf_key, const char *value, void *cb)
+ case TRAILER_COMMAND:
+ if (conf->command)
+ warning(_("more than one %s"), conf_key);
++ conf->is_new_cmd = 0;
++ conf->command = xstrdup(value);
++ break;
++ case TRAILER_CMD:
++ if (conf->command)
++ warning(_("more than one %s"), conf_key);
++ conf->is_new_cmd = 1;
+ conf->command = xstrdup(value);
+ break;
+ case TRAILER_WHERE:
Documentation/git-interpret-trailers.txt | 7 +++++++ t/t7513-interpret-trailers.sh | 22 +++++++++++++++++++- trailer.c | 26 +++++++++++++++++------- 3 files changed, 47 insertions(+), 8 deletions(-)
Documentation/git-interpret-trailers.txt +7 -0
@@ -252,6 +252,13 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command. +trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can quote the + trailer value multiple times in the command. + E.g. `trailer.sign.cmd="test -n \"$1\" && echo \"$1\" || true "` + EXAMPLES --------
t/t7513-interpret-trailers.sh +21 -1
@@ -1274,9 +1274,29 @@ test_expect_success 'setup a commit' ' git commit -m "Add file a.txt" ' +test_expect_success 'with cmd using $1' ' + test_when_finished "git config --unset trailer.fix.cmd" && + git config trailer.fix.ifExists "replace" && + git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \"\$1\" || true" && + FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) && + cat complex_message_body >expected2 && + sed -e "s/ Z\$/ /" >>expected2 <<-EOF && + Fixes: $FIXED + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <[email protected]> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual2 && + test_cmp expected2 actual2 +' + test_expect_success 'with command using $ARG' ' git config trailer.fix.ifExists "replace" && - git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \$ARG" && FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) && cat complex_message_body >expected && sed -e "s/ Z\$/ /" >>expected <<-EOF &&
trailer.c +19 -7
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +int is_new_cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -216,7 +217,7 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (const char *command,int is_new_cmd ,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;
@@ -224,10 +225,13 @@ static char *apply_command(const char *command, const char *arg)char *result;strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); -strvec_push (&cp.args, cmd.buf); +if (arg) { +if (is_new_cmd) +strvec_push (&cp.args, arg); +else +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -257,7 +261,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (arg_tok->conf.command, arg_tok->conf.is_new_cmd, arg);free ((char *)arg); } }
@@ -454,8 +458,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +467,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -540,6 +545,13 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)case TRAILER_COMMAND :if (conf->command)warning (_ ("more than one %s" ), conf_key); + conf->is_new_cmd =0 ; + conf->command =xstrdup (value); +break ; +case TRAILER_CMD : +if (conf->command) +warning (_ ("more than one %s" ), conf_key); + conf->is_new_cmd =1 ; conf->command =xstrdup (value);break ;case TRAILER_WHERE :
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
Re: [PATCH v2] [GSOC]trailer: pass arg as positional parameter
Quoted 16 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
In the original implementation of
trailer.<token>.command, usestrbuf_replaceto replace $ARG in the <value> of the trailer, but it have a problem:strbuf_replacereplace the $ARG in command only once, If the user's trailer command have used more than one $ARG, error will occur.If directly modify the implementation of the original
trailer.<token>.command, The user’s previous'$ARG'in trailer command will not be replaced. So now add new config "trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, users can use $1 as trailer's value, to implement original variable replacement.
Quoted 2 lines
Original
trailer.<token>.commandcan still be used until git completely abandoned it.
Sorry, but that's quite an ungrammatical mess X-<.
Quoted 3 lines
1:
abc5b04d152f! 1:185356d6fc90[GSOC]trailer: change $ARG to environment variable
@@ Metadata
Author: ZheNing Hu <[email protected]>
As this is completely a different design and does not share anything with the earlier round, the range-diff is merely distracting and useless.
Quoted 10 lines
Documentation/git-interpret-trailers.txt | 7 +++++++ t/t7513-interpret-trailers.sh | 22 +++++++++++++++++++- trailer.c | 26 +++++++++++++++++------- 3 files changed, 47 insertions(+), 8 deletions(-)Documentation/git-interpret-trailers.txt +0
-0
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 258
Quoted 7 lines
Documentation/git-interpret-trailers.txt +4
-0@@ -252,6 +252,13 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command. +trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can quote the
"quote"?
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 260
Quoted 2 lines
Documentation/git-interpret-trailers.txt +2
-0+ trailer value multiple times in the command. + E.g. `trailer.sign.cmd="test -n \"$1\" && echo \"$1\" || true "`
This needs to explain what happens if the user gives both .cmd and .command to the same token. Is it an error? Is the newly invented .cmd takes precedence? Something else?
Whatever the answer is, the reasoning behind reaching the design must be explained and defended in the proposed log message.
trailer.c struct conf_info { · line 17
Quoted 9 lines
trailer.c +1
-0@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +int is_new_cmd;
Poor naming. The .cmd thing may be "new" right now in your mind, but how would you transition out of it when design flaws are discovered in it and replace it with yet another mechanism?
Add a new "char *cmd" field, and at the using site, define the precedence between the two when both cmd and command members of the structure are populated, perhaps?
Re: [PATCH v2] [GSOC]trailer: pass arg as positional parameter
Quoted 19 lines · Junio C Hamano <[email protected]> 于2021年3月25日周四 上午4:18写道:
Quoted 16 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
In the original implementation of
trailer.<token>.command, usestrbuf_replaceto replace $ARG in the <value> of the trailer, but it have a problem:strbuf_replacereplace the $ARG in command only once, If the user's trailer command have used more than one $ARG, error will occur.If directly modify the implementation of the original
trailer.<token>.command, The user’s previous'$ARG'in trailer command will not be replaced. So now add new config "trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, users can use $1 as trailer's value, to implement original variable replacement.
Quoted 5 lines
Quoted 2 lines
Original
trailer.<token>.commandcan still be used until git completely abandoned it.Sorry, but that's quite an ungrammatical mess X-<.
Somewhat embarrassing. I have tried to fix it...
Quoted 8 lines
Quoted 3 lines
1:
abc5b04d152f! 1:185356d6fc90[GSOC]trailer: change $ARG to environment variable
@@ Metadata
Author: ZheNing Hu <[email protected]>As this is completely a different design and does not share anything with the earlier round, the range-diff is merely distracting and useless.
I thought the designs of the two were very similar.
Quoted 13 lines
Quoted 13 lines
Documentation/git-interpret-trailers.txt | 7 +++++++ t/t7513-interpret-trailers.sh | 22 +++++++++++++++++++- trailer.c | 26 +++++++++++++++++------- 3 files changed, 47 insertions(+), 8 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -252,6 +252,13 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command.
Quoted 7 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 258
Quoted 4 lines
Documentation/git-interpret-trailers.txt +4
-0+trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can quote the"quote"?
parse.
Quoted 7 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 260
Quoted 2 lines
Documentation/git-interpret-trailers.txt +2
-0+ trailer value multiple times in the command. + E.g. `trailer.sign.cmd="test -n \"$1\" && echo \"$1\" || true "`This needs to explain what happens if the user gives both .cmd and .command to the same token. Is it an error? Is the newly invented .cmd takes precedence? Something else?
For the time being, if I make "cmd" and "command" equivalent, it will only trigger a warning.
Quoted 3 lines
Whatever the answer is, the reasoning behind reaching the design must be explained and defended in the proposed log message.
OK.
Quoted 15 lines
trailer.c struct conf_info { · line 17
Quoted 10 lines
trailer.c +1
-0@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +int is_new_cmd;Poor naming. The .cmd thing may be "new" right now in your mind, but how would you transition out of it when design flaws are discovered in it and replace it with yet another mechanism?
I thought if the "command" will need to be replaced in later releases,
"is_new_cmd" will be removed at the same time, now I think "is_new_cmd" may cause misunderstandings.
Quoted 3 lines
Add a new "char *cmd" field, and at the using site, define the precedence between the two when both cmd and command members of the structure are populated, perhaps?
It sounds feasible, I will try.
Thanks.
PATCH v3 1/1 trailer: pass arg as positional parameter
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
Original implementation of trailer.<token>.command use strbuf_replace to replace $ARG in command with the <value> of the trailer, but it have a problem: strbuf_replace replace the $ARG only once, If the user's trailer command have used more than one $ARG, the remaining replacement will fail.
If directly modify the implementation of the original trailer.<token>.command, The user’s previous '$ARG' in trailer command will not be replaced. So now add new config "trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, the user can use $1 as trailer's value, to implement original variable replacement.
If the user has these two configuration: "trailer.<token>.cmd" and "trailer.<token>.command", "cmd" will execute and "command" will not executed.
Original trailer.<token>.command can still be used until git completely abandoned it.
---
[GSOC]trailer: pass arg as positional parameter
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v2:
1: 185356d6fc90 ! 1: b268ecd7b395 [GSOC]trailer: pass arg as positional parameter
@@ Metadata
## Commit message ##
[GSOC]trailer: pass arg as positional parameter
- In the original implementation of `trailer.<token>.command`,
- use `strbuf_replace` to replace $ARG in the <value> of the
- trailer, but it have a problem: `strbuf_replace` replace the
- $ARG in command only once, If the user's trailer command have
- used more than one $ARG, error will occur.
+ Original implementation of `trailer.<token>.command` use
+ `strbuf_replace` to replace $ARG in command with the <value>
+ of the trailer, but it have a problem: `strbuf_replace`
+ replace the $ARG only once, If the user's trailer command
+ have used more than one $ARG, the remaining replacement will
+ fail.
If directly modify the implementation of the original
`trailer.<token>.command`, The user’s previous `'$ARG'` in
- trailer command will not be replaced. So now add new
- config "trailer.<token>.cmd", pass trailer's value as
- positional parameter 1 to the user's command, users can
- use $1 as trailer's value, to implement original variable
- replacement.
+ trailer command will not be replaced. So now add new config
+ "trailer.<token>.cmd", pass trailer's value as positional
+ parameter 1 to the user's command, the user can use $1 as
+ trailer's value, to implement original variable replacement.
+
+ If the user has these two configuration: "trailer.<token>.cmd"
+ and "trailer.<token>.command", "cmd" will execute and "command"
+ will not executed.
Original `trailer.<token>.command` can still be used until git
completely abandoned it.
@@ Documentation/git-interpret-trailers.txt: also be executed for each of these arg
+trailer.<token>.cmd::
+ Similar to 'trailer.<token>.command'. But the difference is that
+ `$1` is used in the command to replace the value of the trailer
-+ instead of the original `$ARG`, which means that we can quote the
++ instead of the original `$ARG`, which means that we can pass the
+ trailer value multiple times in the command.
-+ E.g. `trailer.sign.cmd="test -n \"$1\" && echo \"$1\" || true "`
++ E.g. `git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true "`.
++ If the user has these two configuration: "trailer.<token>.cmd"
++ and "trailer.<token>.command", "cmd" will be executed and "command"
++ will not be executed.
+
EXAMPLES
--------
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'
-+test_expect_success 'with cmd using $1' '
++test_expect_success 'with cmd and $1' '
+ test_when_finished "git config --unset trailer.fix.cmd" &&
+ git config trailer.fix.ifExists "replace" &&
+ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" \
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
+ <complex_message >actual2 &&
+ test_cmp expected2 actual2
+'
++
++test_expect_success 'cmd takes precedence over command' '
++ test_when_finished "git config --unset trailer.fix.cmd" &&
++ git config trailer.fix.ifExists "replace" &&
++ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
++ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
++ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
++ --abbrev-commit --abbrev=14 \$ARG" &&
++ FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
++ cat complex_message_body >expected2 &&
++ sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
++ Fixes: $FIXED
++ Acked-by= Z
++ Reviewed-by:
++ Signed-off-by: Z
++ Signed-off-by: A U Thor <[email protected]>
++ EOF
++ git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \
++ <complex_message >actual2 &&
++ test_cmp expected2 actual2
++'
+
test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" &&
@@ trailer.c: struct conf_info {
char *name;
char *key;
char *command;
-+ int is_new_cmd;
++ char *cmd;
enum trailer_where where;
enum trailer_if_exists if_exists;
enum trailer_if_missing if_missing;
+@@ trailer.c: static void free_arg_item(struct arg_item *item)
+ free(item->conf.name);
+ free(item->conf.key);
+ free(item->conf.command);
++ free(item->conf.cmd);
+ free(item->token);
+ free(item->value);
+ free(item);
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
return 1;
}
-static char *apply_command(const char *command, const char *arg)
-+static char *apply_command(const char *command, int is_new_cmd , const char *arg)
++static char *apply_command(const char *command, const char *cmd_, const char *arg)
{
struct strbuf cmd = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
-@@ trailer.c: static char *apply_command(const char *command, const char *arg)
+ struct child_process cp = CHILD_PROCESS_INIT;
char *result;
- strbuf_addstr(&cmd, command);
+- strbuf_addstr(&cmd, command);
- if (arg)
- strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
-
- strvec_push(&cp.args, cmd.buf);
-+ if (arg) {
-+ if (is_new_cmd)
+- strvec_push(&cp.args, cmd.buf);
++ if (cmd_) {
++ strbuf_addstr(&cmd, cmd_);
++ strvec_push(&cp.args, cmd.buf);
++ if (arg)
+ strvec_push(&cp.args, arg);
-+ else
++ } else if (command) {
++ strbuf_addstr(&cmd, command);
++ strvec_push(&cp.args, cmd.buf);
++ if (arg)
+ strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
+ }
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
+@@ trailer.c: static char *apply_command(const char *command, const char *arg)
+
+ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
+ {
+- if (arg_tok->conf.command) {
++ if (arg_tok->conf.command || arg_tok->conf.cmd) {
+ const char *arg;
+ if (arg_tok->value && arg_tok->value[0]) {
+ arg = arg_tok->value;
@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
else
arg = xstrdup("");
}
- arg_tok->value = apply_command(arg_tok->conf.command, arg);
-+ arg_tok->value = apply_command(arg_tok->conf.command, arg_tok->conf.is_new_cmd, arg);
++ arg_tok->value = apply_command(arg_tok->conf.command, arg_tok->conf.cmd, arg);
free((char *)arg);
}
}
+@@ trailer.c: static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
+ dst->name = xstrdup_or_null(src->name);
+ dst->key = xstrdup_or_null(src->key);
+ dst->command = xstrdup_or_null(src->command);
++ dst->cmd = xstrdup_or_null(src->cmd);
+ }
+
+ static struct arg_item *get_conf_item(const char *name)
@@ trailer.c: static struct arg_item *get_conf_item(const char *name)
return item;
}
@@ trailer.c: static struct {
{ "ifexists", TRAILER_IF_EXISTS },
{ "ifmissing", TRAILER_IF_MISSING }
@@ trailer.c: static int git_trailer_config(const char *conf_key, const char *value, void *cb)
- case TRAILER_COMMAND:
- if (conf->command)
warning(_("more than one %s"), conf_key);
-+ conf->is_new_cmd = 0;
-+ conf->command = xstrdup(value);
-+ break;
-+ case TRAILER_CMD:
-+ if (conf->command)
-+ warning(_("more than one %s"), conf_key);
-+ conf->is_new_cmd = 1;
conf->command = xstrdup(value);
break;
++ case TRAILER_CMD:
++ if (conf->cmd)
++ warning(_("more than one %s"), conf_key);
++ conf->cmd = xstrdup(value);
++ break;
case TRAILER_WHERE:
+ if (trailer_set_where(&conf->where, value))
+ warning(_("unknown value '%s' for key '%s'"), value, conf_key);
+@@ trailer.c: static void process_command_line_args(struct list_head *arg_head,
+ /* Add an arg item for each configured trailer with a command */
+ list_for_each(pos, &conf_head) {
+ item = list_entry(pos, struct arg_item, list);
+- if (item->conf.command)
++ if (item->conf.cmd || item->conf.command)
+ add_arg_item(arg_head,
+ xstrdup(token_from_item(item, NULL)),
+ xstrdup(""),Documentation/git-interpret-trailers.txt | 10 ++++++ t/t7513-interpret-trailers.sh | 43 +++++++++++++++++++++++- trailer.c | 37 ++++++++++++++------ 3 files changed, 78 insertions(+), 12 deletions(-)
Documentation/git-interpret-trailers.txt +10 -0
@@ -252,6 +252,16 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command. +trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can pass the + trailer value multiple times in the command. + E.g. `git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true "`. + If the user has these two configuration: "trailer.<token>.cmd" + and "trailer.<token>.command", "cmd" will be executed and "command" + will not be executed. + EXAMPLES --------
t/t7513-interpret-trailers.sh +42 -1
51 lines not on this page · raw message
trailer.c +26 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (const char *command,const char *cmd_,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (cmd_) { +strbuf_addstr (&cmd, cmd_); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (command) { +strbuf_addstr (&cmd, command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (arg_tok->conf.command, arg_tok->conf.cmd, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
Re: [PATCH v3] [GSOC]trailer: pass arg as positional parameter
Quoted 3 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
Original implementation of
trailer.<token>.commanduse
uses
Quoted 2 lines
strbuf_replaceto replace $ARG in command with the <value> of the trailer, but it have a problem:strbuf_replace
has
Quoted 1 line
replace the $ARG only once, If the user's trailer command
replaces the $ARG only once.
Quoted 2 lines
have used more than one $ARG, the remaining replacement will fail.
"will fail" is quite vague. It is just left unreplaced, and if the user expects all of them to be replaced, then the expectation and reality would not match, but all of that you have already said by "replaces the $ARG only once.", so I think this sentence should be removed.
Quoted 3 lines
If directly modify the implementation of the original
trailer.<token>.command, The user’s previous'$ARG'in trailer command will not be replaced.
That statement does not make much sense. Depending on the way how the implementation is "directly" modified, you can fix the "replaces only once" problem without introducing such a problem. Just look for '$ARG' in the string and replace all of them, not just the first one. It's not too difficult.
This confusion primarily comes from the fact that you forgot to explain the other problem you are fixing, I think. Even though the trailer.<token>.command documentation implies that the user is expected to give a shell script or some sort as the command and the use of $ARG makes it look like a shell variable, the original implementation does not treat it as a shell variable at all. And the textual replacement is done without making sure the value being replaced has characters with special meaning in the shell language.
So existing .command may incorrectly use $ARG inside a single-quote pair and expect it to be replaced to a string inside a single-quote pair. A malformed, or worse, malicious, value would escape out of the single-quote pair (remember, the '; rm -fr .' example?) and execute arbitrary code in an unexpected way. The (ungrammatical) "if directly modify the implementation" refers to a potential way to fix these two problems at the same time by doing the $ARG thing without using textual replacement, namely, exporting the value as an environment variable ARG. If that approach was taken, then, $ARG enclosed in a single-quote pair will no longer be replaced, which makes it a backward incompatible change.
But without describing what solution you are talking about, your three-line description does not make much sense.
Quoted 5 lines
So now add new config
"trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, the user can use $1 as trailer's value, to implement original variable replacement.
Quoted 8 lines
If the user has these two configuration: "trailer.<token>.cmd" and "trailer.<token>.command", "cmd" will execute and "command" will not executed.
Original
trailer.<token>.commandcan still be used until git completely abandoned it.Signed-off-by ZheNing Hu <[email protected]>
Let's rewrite it completely.
The trailer.<token>.command configuration variable specifies a command (run via the shall, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
I tried to cover everything we need to tell the reviewers about this change with the above. Did I miss anything?
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 259
Quoted 5 lines
Documentation/git-interpret-trailers.txt +5
-0+trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can pass the + trailer value multiple times in the command.
We eventually want to deprecate the .command, so we'd prefer not to rely on its description too much (e.g. try to find a way to say what you want to say without "instead of the original $ARG").
The command specified by this configuration variable is run with a single parameter, which is the <value> part of an existing trailer with the same <token>. The output from the command is then used as the value for the <token> in the resulting trailer.
would be the replacement for the part that talks about $ARG in the description of trailer.<token>.command.
The original description for trailer.<token>.command is so jumbled (not your failure at all) that I had a hard time to understand what it is trying to say (e.g. what does "as if a special <token>=<value> argument were added at the beginning of the command line" mean? Is it making a one-shot export of environment variable to run the command???), so the above may need further adjustment. Christian? Care to help out?
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 260
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+ E.g. `git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true "`.
An example is good. There is a whole EXAMPLES section in this manual page, and the one that uses $ARG may be a good candidate to look at and change to use .cmd (instead of .command).
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 263
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+ If the user has these two configuration: "trailer.<token>.cmd" + and "trailer.<token>.command", "cmd" will be executed and "command" + will not be executed.
When both .cmd and .command are given for the same <token>, .cmd is used and .command is ignored.
Quoted 38 lines
trailer.c +4
-6@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (const char *command,const char *cmd_,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (cmd_) {
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 238
Quoted 10 lines
trailer.c +10
-0+strbuf_addstr (&cmd, cmd_); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (command) { +strbuf_addstr (&cmd, command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + }
OK. it is clear cmd_ takes precedence this way.
Later (not as part of this patch, but a few releases down the road), we may want to add a warning() about using a deprecated feature when "else if (command)" block is taken.
Quoted 10 lines
trailer.c +1
-1@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
trailer.c static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg · line 268
Quoted 5 lines
trailer.c +1
-1@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (arg_tok->conf.command, arg_tok->conf.cmd, arg);
It might be cleaner to just pass arg_tok->conf to apply_command() and hide "cmd takes precedence over command" as an implementation detail of that helper function.
The implementation looks as good as the original "command" with that change at this point. Documentation may need a bit more polishing.
Thanks.
Re: [PATCH v3] [GSOC]trailer: pass arg as positional parameter
Quoted 9 lines · Junio C Hamano <[email protected]> 于2021年3月26日周五 上午6:28写道:
Quoted 3 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
Original implementation of
trailer.<token>.commanduseuses
Quoted 9 lines
Quoted 2 lines
strbuf_replaceto replace $ARG in command with the <value> of the trailer, but it have a problem:strbuf_replacehas
Quoted 1 line
replace the $ARG only once, If the user's trailer command
replaces the $ARG only once.
Okay... singular and plural problems.
Quoted 9 lines
Quoted 2 lines
have used more than one $ARG, the remaining replacement will fail.
"will fail" is quite vague. It is just left unreplaced, and if the user expects all of them to be replaced, then the expectation and reality would not match, but all of that you have already said by "replaces the $ARG only once.", so I think this sentence should be removed.
Indeed so.
Quoted 10 lines
Quoted 3 lines
If directly modify the implementation of the original
trailer.<token>.command, The user’s previous'$ARG'in trailer command will not be replaced.That statement does not make much sense. Depending on the way how the implementation is "directly" modified, you can fix the "replaces only once" problem without introducing such a problem. Just look for '$ARG' in the string and replace all of them, not just the first one. It's not too difficult.
Quoted 9 lines
This confusion primarily comes from the fact that you forgot to explain the other problem you are fixing, I think. Even though the trailer.<token>.command documentation implies that the user is expected to give a shell script or some sort as the command and the use of $ARG makes it look like a shell variable, the original implementation does not treat it as a shell variable at all. And the textual replacement is done without making sure the value being replaced has characters with special meaning in the shell language.
Yes! The accidental injection problem caused should have been the focus of my explanation.
Quoted 12 lines
So existing .command may incorrectly use $ARG inside a single-quote pair and expect it to be replaced to a string inside a single-quote pair. A malformed, or worse, malicious, value would escape out of the single-quote pair (remember, the '; rm -fr .' example?) and execute arbitrary code in an unexpected way. The (ungrammatical) "if directly modify the implementation" refers to a potential way to fix these two problems at the same time by doing the $ARG thing without using textual replacement, namely, exporting the value as an environment variable ARG. If that approach was taken, then, $ARG enclosed in a single-quote pair will no longer be replaced, which makes it a backward incompatible change.
Oh, I remeber it: terrible shell injection. Specifically, it looks like this:
$ git config trailer.sign.command "git log --author='\$ARG'" $ git interpret-trailers --trailer "sign = adl' && rm -rf ./repo/'"
now I know that should be "backward incompatible change" as you said.
Quoted 47 lines
But without describing what solution you are talking about, your three-line description does not make much sense.
Quoted 5 lines
So now add new config
"trailer.<token>.cmd", pass trailer's value as positional parameter 1 to the user's command, the user can use $1 as trailer's value, to implement original variable replacement.Quoted 8 lines
If the user has these two configuration: "trailer.<token>.cmd" and "trailer.<token>.command", "cmd" will execute and "command" will not executed.
Original
trailer.<token>.commandcan still be used until git completely abandoned it.Signed-off-by ZheNing Hu <[email protected]>Let's rewrite it completely.
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shall, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to theinterpret-trailercommand for the token. This has two downsides:* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
Quoted 2 lines
I tried to cover everything we need to tell the reviewers about this change with the above. Did I miss anything?
Nothing to blame, feature of the old command, 2 problems, 1 solution, this is what the log should look like.
Quoted 11 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 259
Quoted 6 lines
Documentation/git-interpret-trailers.txt +5
-0+trailer.<token>.cmd:: + Similar to 'trailer.<token>.command'. But the difference is that + `$1` is used in the command to replace the value of the trailer + instead of the original `$ARG`, which means that we can pass the + trailer value multiple times in the command.We eventually want to deprecate the .command, so we'd prefer not to rely on its description too much (e.g. try to find a way to say what you want to say without "instead of the original
$ARG").
Oh! here I can’t rely on the documentation of the old .command, otherwise it’s not easy to delete the old documentation.
Quoted 17 lines
The command specified by this configuration variable is run with a single parameter, which is the <value> part of an existing trailer with the same <token>. The output from the command is then used as the value for the <token> in the resulting trailer.
would be the replacement for the part that talks about $ARG in the description of trailer.<token>.command.
The original description for
trailer.<token>.commandis so jumbled (not your failure at all) that I had a hard time to understand what it is trying to say (e.g. what does "as if a special <token>=<value> argument were added at the beginning of the command line" mean? Is it making a one-shot export of environment variable to run the command???), so the above may need further adjustment. Christian? Care to help out?
Quoted 6 lines
Quoted 1 line
+ E.g.
git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true ".An example is good. There is a whole EXAMPLES section in this manual page, and the one that uses $ARG may be a good candidate to look at and change to use .cmd (instead of .command).
Okay, I will modify the paragraphs containing .command in these examples.
Quoted 58 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 263
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+ If the user has these two configuration: "trailer.<token>.cmd" + and "trailer.<token>.command", "cmd" will be executed and "command" + will not be executed.When both .cmd and .command are given for the same <token>, .cmd is used and .command is ignored.
Quoted 38 lines
trailer.c +4
-6@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (const char *command,const char *cmd_,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (cmd_) {trailer.c static int check_if_different(struct trailer_item *in_tok, · line 238
Quoted 10 lines
trailer.c +10
-0+strbuf_addstr (&cmd, cmd_); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (command) { +strbuf_addstr (&cmd, command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + }OK. it is clear
cmd_takes precedence this way.
Quoted 4 lines
Later (not as part of this patch, but a few releases down the road), we may want to add a
warning()about using a deprecated feature when "else if (command)" block is taken.
Fine, I will keep this version of "cmd priority execution" for now.
Quoted 20 lines
Quoted 10 lines
trailer.c +1
-1@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;trailer.c static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg · line 268
Quoted 5 lines
trailer.c +1
-1@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (arg_tok->conf.command, arg_tok->conf.cmd, arg);It might be cleaner to just pass
arg_tok->conftoapply_command()and hide "cmd takes precedence over command" as an implementation detail of that helper function.
Quoted 3 lines
The implementation looks as good as the original "command" with that change at this point. Documentation may need a bit more polishing.
you're right.
Quoted 1 line
Thanks.
Thanks, Junio.
You and the people in the git community are very enthusiastic, You have patiently explained these small mistakes that I made, and taught me a lot of problems that I didn't notice.
Grateful.
--
ZheNing Hu
PATCH v4 1/1 trailer: pass arg as positional parameter
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
---
[GSOC]trailer: pass arg as positional parameter
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v3:
1: b268ecd7b395 ! 1: e2bbdcb943c2 [GSOC]trailer: pass arg as positional parameter
@@ Metadata
## Commit message ##
[GSOC]trailer: pass arg as positional parameter
- Original implementation of trailer.<token>.command use
- strbuf_replace to replace $ARG in command with the <value>
- of the trailer, but it have a problem: strbuf_replace
- replace the $ARG only once, If the user's trailer command
- have used more than one $ARG, the remaining replacement will
- fail.
+ The trailer.<token>.command configuration variable
+ specifies a command (run via the shell, so it does not have
+ to be a single name of or path to the command, but can be a
+ shell script), and the first occurrence of substring $ARG is
+ replaced with the value given to the interpret-trailer
+ command for the token. This has two downsides:
- If directly modify the implementation of the original
- trailer.<token>.command, The user’s previous '$ARG' in
- trailer command will not be replaced. So now add new config
- "trailer.<token>.cmd", pass trailer's value as positional
- parameter 1 to the user's command, the user can use $1 as
- trailer's value, to implement original variable replacement.
+ * The use of $ARG in the mechanism misleads the users that
+ the value is passed in the shell variable, and tempt them
+ to use $ARG more than once, but that would not work, as
+ the second and subsequent $ARG are not replaced.
- If the user has these two configuration: "trailer.<token>.cmd"
- and "trailer.<token>.command", "cmd" will execute and "command"
- will not executed.
+ * Because $ARG is textually replaced without regard to the
+ shell language syntax, even '$ARG' (inside a single-quote
+ pair), which a user would expect to stay intact, would be
+ replaced, and worse, if the value had an unmatching single
+ quote (imagine a name like "O'Connor", substituted into
+ NAME='$ARG' to make it NAME='O'Connor), it would result in
+ a broken command that is not syntactically correct (or
+ worse).
- Original trailer.<token>.command can still be used until git
- completely abandoned it.
+ Introduce a new trailer.<token>.cmd configuration that
+ takes higher precedence to deprecate and eventually remove
+ trailer.<token>.command, which passes the value as a
+ parameter to the command. Instead of "$ARG", the users will
+ refer to the value as positional argument, $1, in their
+ scripts.
+ Helped-by: Junio C Hamano <[email protected]>
## Documentation/git-interpret-trailers.txt ##
@@ Documentation/git-interpret-trailers.txt: also be executed for each of these arg
the command.
+trailer.<token>.cmd::
-+ Similar to 'trailer.<token>.command'. But the difference is that
-+ $1 is used in the command to replace the value of the trailer
-+ instead of the original $ARG, which means that we can pass the
-+ trailer value multiple times in the command.
-+ E.g. git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true ".
-+ If the user has these two configuration: "trailer.<token>.cmd"
-+ and "trailer.<token>.command", "cmd" will be executed and "command"
-+ will not be executed.
++ The command specified by this configuration variable is run
++ with a single parameter, which is the <value> part of an
++ existing trailer with the same <token>. The output from the
++ command is then used as the value for the <token> in the
++ resulting trailer.
++ The command is expected to replace trailer.<token>.cmd.
++ When both .cmd and .command are given for the same <token>,
++ .cmd is used and .command is ignored.
+
EXAMPLES
--------
+@@ Documentation/git-interpret-trailers.txt: $ git format-patch -1
+ $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Reviewed-by: Bob <[email protected]>' 0001-foo.patch >0001-bar.patch
+ ------------
+
+-* Configure a 'sign' trailer with a command to automatically add a
++* Configure a 'sign' trailer with a cmd to automatically add a
+ 'Signed-off-by: ' with the author information only if there is no
+ 'Signed-off-by: ' already, and show how it works:
+ +
+@@ Documentation/git-interpret-trailers.txt: $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re
+ $ git config trailer.sign.key "Signed-off-by: "
+ $ git config trailer.sign.ifmissing add
+ $ git config trailer.sign.ifexists doNothing
+-$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
++$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
+ $ git interpret-trailers <<EOF
+ > EOF
+
+@@ Documentation/git-interpret-trailers.txt: subject
+ Fix #42
+ ------------
+
+-* Configure a 'see' trailer with a command to show the subject of a
++* Configure a 'see' trailer with a cmd to show the subject of a
+ commit that is related, and show how it works:
+ +
+ ------------
+ $ git config trailer.see.key "See-also: "
+ $ git config trailer.see.ifExists "replace"
+ $ git config trailer.see.ifMissing "doNothing"
+-$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG"
++$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true "
+ $ git interpret-trailers <<EOF
+ > subject
+ >
## t/t7513-interpret-trailers.sh ##
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
}
-static char *apply_command(const char *command, const char *arg)
-+static char *apply_command(const char *command, const char *cmd_, const char *arg) ++static char *apply_command(struct conf_info *conf, const char *arg)
{
struct strbuf cmd = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
- strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
-
- strvec_push(&cp.args, cmd.buf);
-+ if (cmd_) {
-+ strbuf_addstr(&cmd, cmd_);
++ if (conf->cmd) {
++ strbuf_addstr(&cmd, conf->cmd);
+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
+ strvec_push(&cp.args, arg);
-+ } else if (command) {
-+ strbuf_addstr(&cmd, command);
++ } else if (conf->command) {
++ strbuf_addstr(&cmd, conf->command);
+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
+ strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct ar
arg = xstrdup("");
}
- arg_tok->value = apply_command(arg_tok->conf.command, arg);
-+ arg_tok->value = apply_command(arg_tok->conf.command, arg_tok->conf.cmd, arg);
++ arg_tok->value = apply_command(&arg_tok->conf, arg);
free((char *)arg);
}
}
Documentation/git-interpret-trailers.txt | 18 +++++++--- t/t7513-interpret-trailers.sh | 43 +++++++++++++++++++++++- trailer.c | 37 ++++++++++++++------ 3 files changed, 82 insertions(+), 16 deletions(-)
Documentation/git-interpret-trailers.txt +14 -4
@@ -252,6 +252,16 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command. +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. + The command is expected to replace `trailer.<token>.cmd`. + When both .cmd and .command are given for the same <token>, + .cmd is used and .command is ignored. + EXAMPLES --------
@@ -301,7 +311,7 @@ $ git format-patch -1 $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Reviewed-by: Bob <[email protected]>' 0001-foo.patch >0001-bar.patch ------------ -* Configure a 'sign' trailer with a command to automatically add a +* Configure a 'sign' trailer with a cmd to automatically add a 'Signed-off-by: ' with the author information only if there is no 'Signed-off-by: ' already, and show how it works: +
@@ -309,7 +319,7 @@ $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re $ git config trailer.sign.key "Signed-off-by: " $ git config trailer.sign.ifmissing add $ git config trailer.sign.ifexists doNothing -$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"' +$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"' $ git interpret-trailers <<EOF > EOF
@@ -333,14 +343,14 @@ subject Fix #42 ------------ -* Configure a 'see' trailer with a command to show the subject of a +* Configure a 'see' trailer with a cmd to show the subject of a commit that is related, and show how it works: + ------------ $ git config trailer.see.key "See-also: " $ git config trailer.see.ifExists "replace" $ git config trailer.see.ifMissing "doNothing" -$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" +$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true " $ git interpret-trailers <<EOF > subject >
t/t7513-interpret-trailers.sh +42 -1
51 lines not on this page · raw message
trailer.c +26 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 263
Quoted 13 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +9
-0@@ -252,6 +252,16 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command. +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. + The command is expected to replace `trailer.<token>.cmd`. + When both .cmd and .command are given for the same <token>, + .cmd is used and .command is ignored.
Christian, because ".cmd" is trying to eventually replace it, I find it a bit disturbing that the description we give here looks a lot smaller compared to the one for ".command". I am afraid that we may have failed to reproduce something important from the description of the ".command" for the above; care to rend a hand or two here to complete the description?
As I cannot grok what the description for ".command" is trying to say, especially around this part:
When this option is specified, the behavior is as if a special '<token>=<value>' argument were added at the beginning of the command line, where <value> is ...
and
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments.
I cannot quite judge if what we came up with in the above description is sufficient.
Documentation/git-interpret-trailers.txt $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re · line 324
Quoted 13 lines
Documentation/git-interpret-trailers.txt +2
-2-* Configure a 'sign' trailer with a command to automatically add a +* Configure a 'sign' trailer with a cmd to automatically add a 'Signed-off-by: ' with the author information only if there is no 'Signed-off-by: ' already, and show how it works: +@@ -309,7 +319,7 @@ $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re $ git config trailer.sign.key "Signed-off-by: " $ git config trailer.sign.ifmissing add $ git config trailer.sign.ifexists doNothing -$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"' +$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"' $ git interpret-trailers <<EOF > EOF
This change would definitely be needed when the support for ".command" is removed after deprecation period. As it does not take any argument, .cmd and .command should behave identically, so making this change now, without waiting, may make sense.
Quoted 6 lines
Documentation/git-interpret-trailers.txt +1
-1@@ -333,14 +343,14 @@ subject Fix #42 ------------ -* Configure a 'see' trailer with a command to show the subject of a +* Configure a 'see' trailer with a cmd to show the subject of a
Documentation/git-interpret-trailers.txt subject · line 355
Quoted 10 lines
Documentation/git-interpret-trailers.txt +1
-1commit that is related, and show how it works: + ------------ $ git config trailer.see.key "See-also: " $ git config trailer.see.ifExists "replace" $ git config trailer.see.ifMissing "doNothing" -$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" +$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true " $ git interpret-trailers <<EOF > subject
This, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
Besides, the examples given here are not equivalent. The original assumes that ARG is there, or it is OK to default to HEAD; the new one gives no output when $ARG/$1 is not supplied. It would confuse readers to give two too-similar-but-subtly-different examles, as they will be forced to wonder if the difference is something needed to transition from .command to .cmd (and I am guessing that it is not).
Rewriting both to use "--pretty=reference" may be worth doing. As can be seen in these examples:
git show -s --pretty=reference \$1
git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$1
that it makes the result much easier to read.
Thanks. Do not send a reroll prematurely; I want to see area expert's input at this point.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 7 lines · Junio C Hamano
Quoted 4 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +0
-0@@ -252,6 +252,16 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command.
Quoted 7 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 261
Quoted 7 lines
Documentation/git-interpret-trailers.txt +7
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. + The command is expected to replace `trailer.<token>.cmd`.
s/trailer.<token>.cmd/trailer.<token>.command/
Quoted 9 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 263
Quoted 2 lines
Documentation/git-interpret-trailers.txt +2
-0+ When both .cmd and .command are given for the same <token>, + .cmd is used and .command is ignored.Christian, because ".cmd" is trying to eventually replace it, I find it a bit disturbing that the description we give here looks a lot smaller compared to the one for ".command". I am afraid that we may have failed to reproduce something important from the description of the ".command" for the above; care to rend a hand or two here to complete the description?
Yeah, sure. I just saw that you already asked about this in this thread. Sorry for not answering earlier.
Quoted 6 lines
As I cannot grok what the description for ".command" is trying to say, especially around this part:
When this option is specified, the behavior is as if a special '<token>=<value>' argument were added at the beginning of the command line, where <value> is ...
This is because when a number of trailers are passed on the command line, and some other trailers are in the input file, the order in which the different trailers are processed and their priorities can be important. So by saying the above, people can get an idea about at which point and with which priority a trailer coming from such a config option will be processed.
Quoted 5 lines
and
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments.
Yeah, this means that when a 'trailer.foo.command' is configured, it is always executed at least once. The first time it is executed, it is passed nothing ($ARG is replaced with the empty string). Then for each 'foo=<value>' argument passed on the command line, it is executed once more with $ARG replaced by <value>.
The reason it is always executed first with $ARG replaced with the empty string is that this way it makes it possible to set up commands that will always be executed when git interpret-trailers is run. This makes it possible to automatically add some trailers if they are missing for example.
Another way to do it would be to have another config option called trailer.<token>.alwaysRunCmd to tell if the cmd specified by trailer.<token>.cmd should be run even if no '<token>=<value>' argument is passed on the command line. As we are introducing trailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.
This mechanism is the reason why a trick, when setting up a 'trailer.foo.command' trailer, is to also set 'trailer.foo.ifexists' to "replace", so that the first time the command is run (with $ARG replaced with the empty string) it will add a foo trailer with a default value, and if it is run another time, because a 'foo=bar' argument is passed on the command line, then the trailer with the default value will be replaced by the value computed from running the command again with $ARG replaced with "bar".
Another trick is to have the command output nothing when $ARG is the empty string along with using --trim-empty. This way the command will create an empty trailer, when it is run the first time, and if it's not another time, then this empty trailer will be removed because of --trim-empty.
Quoted 2 lines
I cannot quite judge if what we came up with in the above description is sufficient.
I don't think it's sufficient. I think that, while we are at it, a bit more thinking/discussion is required to make sure we want to keep the same design as 'trailer.<token>.command'.
Quoted 10 lines
Quoted 10 lines
Documentation/git-interpret-trailers.txt +1
-2-* Configure a 'sign' trailer with a command to automatically add a +* Configure a 'sign' trailer with a cmd to automatically add a 'Signed-off-by: ' with the author information only if there is no 'Signed-off-by: ' already, and show how it works: +@@ -309,7 +319,7 @@ $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re $ git config trailer.sign.key "Signed-off-by: " $ git config trailer.sign.ifmissing add $ git config trailer.sign.ifexists doNothing -$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
Quoted 8 lines
Documentation/git-interpret-trailers.txt $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re · line 324
Quoted 3 lines
Documentation/git-interpret-trailers.txt +1
-0+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"' $ git interpret-trailers <<EOF > EOFThis change would definitely be needed when the support for ".command" is removed after deprecation period. As it does not take any argument, .cmd and .command should behave identically, so making this change now, without waiting, may make sense.
By the way the above example is an example of why we might want any configured command to be executed at least once, even when no corresponding '<token>=<value>' argument is passed on the command line.
Quoted 21 lines
Quoted 6 lines
Documentation/git-interpret-trailers.txt +1
-1@@ -333,14 +343,14 @@ subject Fix #42 ------------ -* Configure a 'see' trailer with a command to show the subject of a +* Configure a 'see' trailer with a cmd to show the subject of aDocumentation/git-interpret-trailers.txt subject · line 355
Quoted 10 lines
Documentation/git-interpret-trailers.txt +1
-1commit that is related, and show how it works: + ------------ $ git config trailer.see.key "See-also: " $ git config trailer.see.ifExists "replace" $ git config trailer.see.ifMissing "doNothing" -$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" +$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true " $ git interpret-trailers <<EOF > subjectThis, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
Quoted 3 lines
Besides, the examples given here are not equivalent. The original assumes that ARG is there, or it is OK to default to HEAD; the new one gives no output when $ARG/$1 is not supplied.
Yeah, I agree they are not equivalent.
Quoted 5 lines
It would confuse
readers to give two too-similar-but-subtly-different examles, as they will be forced to wonder if the difference is something needed to transition from .command to .cmd (and I am guessing that it is not).
I agree.
Quoted 7 lines
Rewriting both to use "--pretty=reference" may be worth doing. As can be seen in these examples:
git show -s --pretty=reference \$1
git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$1that it makes the result much easier to read.
Yeah, thanks for the good suggestion.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 39 lines · Christian Couder <[email protected]> 于2021年3月28日周日 上午3:53写道:
Quoted 7 lines · Junio C Hamano
Quoted 4 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +0
-0@@ -252,6 +252,16 @@ also be executed for each of these arguments. And the <value> part of these arguments, if any, will be used to replace the `$ARG` string in the command.Quoted 7 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 261
Quoted 7 lines
Documentation/git-interpret-trailers.txt +7
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. + The command is expected to replace `trailer.<token>.cmd`.s/trailer.<token>.cmd/trailer.<token>.command/
Quoted 9 lines
Documentation/git-interpret-trailers.txt also be executed for each of these arguments. And the <value> part of · line 263
Quoted 2 lines
Documentation/git-interpret-trailers.txt +2
-0+ When both .cmd and .command are given for the same <token>, + .cmd is used and .command is ignored.Christian, because ".cmd" is trying to eventually replace it, I find it a bit disturbing that the description we give here looks a lot smaller compared to the one for ".command". I am afraid that we may have failed to reproduce something important from the description of the ".command" for the above; care to rend a hand or two here to complete the description?
Yeah, sure. I just saw that you already asked about this in this thread. Sorry for not answering earlier.
Quoted 6 lines
As I cannot grok what the description for ".command" is trying to say, especially around this part:
When this option is specified, the behavior is as if a special '<token>=<value>' argument were added at the beginning of the command line, where <value> is ...
Quoted 7 lines
This is because when a number of trailers are passed on the command line, and some other trailers are in the input file, the order in which the different trailers are processed and their priorities can be important. So by saying the above, people can get an idea about at which point and with which priority a trailer coming from such a config option will be processed.
This shows that .command itself has the characteristic of alwaysRun:
even if <token> <value> is not specified, the shell in .command will be executed at least once, $ARG is empty by default. This is why I asked log --author=$ARG -1 will show the last commit identity when --trailer
is not used.
Quoted 12 lines
Quoted 5 lines
and
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments.
Yeah, this means that when a 'trailer.foo.command' is configured, it is always executed at least once. The first time it is executed, it is passed nothing ($ARG is replaced with the empty string). Then for each 'foo=<value>' argument passed on the command line, it is executed once more with $ARG replaced by <value>.
Quoted 6 lines
The reason it is always executed first with $ARG replaced with the empty string is that this way it makes it possible to set up commands that will always be executed when
git interpret-trailersis run. This makes it possible to automatically add some trailers if they are missing for example.
Yes, $ARG or $1 are always exist because of:
arg = xstrdup("");so I think maybe we don't even need this judge in apply_command?
+ if (arg)
+ strvec_push(&cp.args, arg);
Quoted 9 lines
Another way to do it would be to have another config option called
trailer.<token>.alwaysRunCmdto tell if the cmd specified bytrailer.<token>.cmdshould be run even if no '<token>=<value>' argument is passed on the command line. As we are introducingtrailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.
In fact, I would prefer this design, because if I don’t add any trailers, the trailer.<token>.command I set will be executed, which may be very distressing sometimes, and alwayRunCmd is the user I hope that "trailers" can be added automatically, and other trailers.<token>.command will not be executed automatically. This allows the user to reasonably configure the commands that need to be executed. This must be a very comfortable thing.
But as you said, to disable the automatic addition in the original .command and use the new .alwaysRunCmd, I’m afraid there are a lot of things to consider. Perhaps future series of patches can be considered to do it.
Quoted 9 lines
This mechanism is the reason why a trick, when setting up a 'trailer.foo.command' trailer, is to also set 'trailer.foo.ifexists' to "replace", so that the first time the command is run (with $ARG replaced with the empty string) it will add a foo trailer with a default value, and if it is run another time, because a 'foo=bar' argument is passed on the command line, then the trailer with the default value will be replaced by the value computed from running the command again with $ARG replaced with "bar".
Quoted 6 lines
Another trick is to have the command output nothing when $ARG is the empty string along with using --trim-empty. This way the command will create an empty trailer, when it is run the first time, and if it's not another time, then this empty trailer will be removed because of --trim-empty.
It looks very practical indeed.
Quoted 6 lines
Quoted 2 lines
I cannot quite judge if what we came up with in the above description is sufficient.
I don't think it's sufficient. I think that, while we are at it, a bit more thinking/discussion is required to make sure we want to keep the same design as 'trailer.<token>.command'.
Sure. I agree that more discussion is needed.
I think if the documents that once belonged to .command are copied to .cmd, will the readers be too burdensome to read them? Will it be better to migrate its documentation until we completely delete .command?
Quoted 20 lines
Quoted 11 lines
Quoted 11 lines
Documentation/git-interpret-trailers.txt +1
-2-* Configure a 'sign' trailer with a command to automatically add a +* Configure a 'sign' trailer with a cmd to automatically add a 'Signed-off-by: ' with the author information only if there is no 'Signed-off-by: ' already, and show how it works: +@@ -309,7 +319,7 @@ $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re $ git config trailer.sign.key "Signed-off-by: " $ git config trailer.sign.ifmissing add $ git config trailer.sign.ifexists doNothing -$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'Quoted 8 lines
Documentation/git-interpret-trailers.txt $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re · line 324
Quoted 3 lines
Documentation/git-interpret-trailers.txt +1
-0+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"' $ git interpret-trailers <<EOF > EOFThis change would definitely be needed when the support for ".command" is removed after deprecation period. As it does not take any argument, .cmd and .command should behave identically, so making this change now, without waiting, may make sense.
Quoted 4 lines
By the way the above example is an example of why we might want any configured command to be executed at least once, even when no corresponding '<token>=<value>' argument is passed on the command line.
Already noticed that.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Documentation/git-interpret-trailers.txt +0
-0@@ -333,14 +343,14 @@ subject Fix #42 ------------
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
Documentation/git-interpret-trailers.txt +1
-1-* Configure a 'see' trailer with a command to show the subject of a +* Configure a 'see' trailer with a cmd to show the subject of a commit that is related, and show how it works: + ------------ $ git config trailer.see.key "See-also: " $ git config trailer.see.ifExists "replace" $ git config trailer.see.ifMissing "doNothing"Quoted 8 lines
Documentation/git-interpret-trailers.txt subject · line 355
Quoted 4 lines
Documentation/git-interpret-trailers.txt +1
-1-$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" +$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true " $ git interpret-trailers <<EOF > subjectThis, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
So the correct solution should be to keep the original .command Examples, and then give the .cmd examples again.
Quoted 7 lines
Quoted 4 lines
Besides, the examples given here are not equivalent. The original assumes that ARG is there, or it is OK to default to HEAD; the new one gives no output when $ARG/$1 is not supplied.
Yeah, I agree they are not equivalent.
Quoted 7 lines
Quoted 5 lines
It would confuse
readers to give two too-similar-but-subtly-different examles, as they will be forced to wonder if the difference is something needed to transition from .command to .cmd (and I am guessing that it is not).I agree.
OK...I will modify it.
Quoted 10 lines
Quoted 8 lines
Rewriting both to use "--pretty=reference" may be worth doing. As can be seen in these examples:
git show -s --pretty=reference \$1
git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$1that it makes the result much easier to read.
Yeah, thanks for the good suggestion.
Yes, --pretty=reference is similar to --format="%h(%s)" and provides better readability.
Thanks,Junio and Christian!
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 19 lines · ZheNing Hu
Quoted 10 lines · Christian Couder <[email protected]> 于2021年3月28日周日 上午3:53写道:
Quoted 6 lines · Junio C Hamano
As I cannot grok what the description for ".command" is trying to say, especially around this part:
When this option is specified, the behavior is as if a special '<token>=<value>' argument were added at the beginning of the command line, where <value> is ...
Quoted 6 lines
This is because when a number of trailers are passed on the command line, and some other trailers are in the input file, the order in which the different trailers are processed and their priorities can be important. So by saying the above, people can get an idea about at which point and with which priority a trailer coming from such a config option will be processed.
Quoted 5 lines
This shows that .command itself has the characteristic of alwaysRun:
even if <token> <value> is not specified, the shell in .command will be executed at least once, $ARG is empty by default. This is why I askedlog --author=$ARG -1will show the last commit identity when--trailer
is not used.
Yeah, that's the reason.
Quoted 23 lines
Quoted 12 lines
Quoted 5 lines
and
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments.
Yeah, this means that when a 'trailer.foo.command' is configured, it is always executed at least once. The first time it is executed, it is passed nothing ($ARG is replaced with the empty string). Then for each 'foo=<value>' argument passed on the command line, it is executed once more with $ARG replaced by <value>.
Quoted 5 lines
The reason it is always executed first with $ARG replaced with the empty string is that this way it makes it possible to set up commands that will always be executed when
git interpret-trailersis run. This makes it possible to automatically add some trailers if they are missing for example.Yes, $ARG or $1 are always exist because of:
arg = xstrdup("");so I think maybe we don't even need this judge in
apply_command?
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 232
Quoted 2 lines
trailer.c +2
-0+if (arg) +strvec_push (&cp.args, arg);
Yeah, I haven't looked at the code, but that might be a good simplification. If you work on this, please submit it in a separate commit.
Quoted 8 lines
Quoted 8 lines
Another way to do it would be to have another config option called
trailer.<token>.alwaysRunCmdto tell if the cmd specified bytrailer.<token>.cmdshould be run even if no '<token>=<value>' argument is passed on the command line. As we are introducingtrailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.
Actually after thinking about it, I think it might be better, instead of trailer.<token>.alwaysRunCmd, to add something like trailer.<token>.runMode that could take multiple values like:
- "beforeCLI": would make it run once, like ".command" does now before any CLI trailer are processed
- "forEachCLIToken": would make it run once for each trailer that has the token, like ".command" also does now, the difference would be that the value for the token would be passed in the $1 argument
- "afterCLI": would make it run once after all the CLI trailers have been processed and it could pass the different values for the token if any in different arguments: $1, $2, $3, ...
This would make it possible to extend later if the need arises for more different times or ways to run configured commands.
Quoted 6 lines
In fact, I would prefer this design, because if I don’t add any trailers, the trailer.<token>.command I set will be executed, which may be very distressing sometimes, and
alwayRunCmdis the user I hope that "trailers" can be added automatically, and other trailers.<token>.command will not be executed automatically. This allows the user to reasonably configure the commands that need to be executed. This must be a very comfortable thing.
I agree that it should be easier and more straightforward, than it is now, to configure this.
Quoted 3 lines
But as you said, to disable the automatic addition in the original .command and use the new .alwaysRunCmd, I’m afraid there are a lot of things to consider. Perhaps future series of patches can be considered to do it.
Yeah, support for trailer.<token>.runMode might be added in different commits at least and possibly later in a different patch series. There are the following issues to resolve, though, if we want to focus only on a new ".cmd" config option:
- how and when should it run by default,
- how to explain that in the doc, and maybe
- how to improve the current description of what happens for ".command"
Quoted 21 lines
Quoted 9 lines
This mechanism is the reason why a trick, when setting up a 'trailer.foo.command' trailer, is to also set 'trailer.foo.ifexists' to "replace", so that the first time the command is run (with $ARG replaced with the empty string) it will add a foo trailer with a default value, and if it is run another time, because a 'foo=bar' argument is passed on the command line, then the trailer with the default value will be replaced by the value computed from running the command again with $ARG replaced with "bar".
Quoted 6 lines
Another trick is to have the command output nothing when $ARG is the empty string along with using --trim-empty. This way the command will create an empty trailer, when it is run the first time, and if it's not another time, then this empty trailer will be removed because of --trim-empty.
It looks very practical indeed.
Quoted 3 lines
Quoted 2 lines
I cannot quite judge if what we came up with in the above description is sufficient.
Quoted 8 lines
Quoted 3 lines
I don't think it's sufficient. I think that, while we are at it, a bit more thinking/discussion is required to make sure we want to keep the same design as 'trailer.<token>.command'.
Sure. I agree that more discussion is needed.
I think if the documents that once belonged to .command are copied to .cmd, will the readers be too burdensome to read them? Will it be better to migrate its documentation until we completely delete .command?
My opinion (if we focus only on adding ".cmd") is that:
- for simplicity for now it should run at the same time as ".command", the only difference being how the argument is passed (using $1 instead of textually replacing $ARG)
- the doc for ".command" should be first improved if possible, and then moved over to ".cmd" saying for ".command" that ".command" is deprecated in favor of ".cmd" but otherwise works as ".cmd" except that instead using $1 the value is passed by textually replacing $ARG which could be a safety and correctness issue.
Another way to work on all this, would be to first work on adding support for trailer.<token>.runMode and on improving existing documentation, and then to add ".cmd", which could then by default use a different ".runMode" than ".command".
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
This, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
So the correct solution should be to keep the original .command Examples, and then give the .cmd examples again.
Maybe we could take advantage of ".cmd" to show other nice possibilities to use all of this. Especially if support for git commit --trailer ... is already merged, we might be able to use it in those examples, or perhaps add some examples to the git commit doc.
Best,
Christian.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 6 lines · Christian Couder <[email protected]> 于2021年3月29日周一 下午5:05写道:
Quoted 6 lines
Yes, $ARG or $1 are always exist because of:
arg = xstrdup("");
Quoted 8 lines
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 232
Quoted 3 lines
so I think maybe we don't even need this judge in
apply_command?trailer.c +2
-0+if (arg) +strvec_push (&cp.args, arg);Yeah, I haven't looked at the code, but that might be a good simplification. If you work on this, please submit it in a separate commit.
Well, if necessary, I'll put it in another commit, maybe I should double check to see if there's anything special going on.
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines
Another way to do it would be to have another config option called
trailer.<token>.alwaysRunCmdto tell if the cmd specified bytrailer.<token>.cmdshould be run even if no '<token>=<value>' argument is passed on the command line. As we are introducingtrailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.
Quoted 4 lines
Actually after thinking about it, I think it might be better, instead of
trailer.<token>.alwaysRunCmd, to add something liketrailer.<token>.runModethat could take multiple values like:
If really can achieve it is certainly better than 'alwaysRunCmd'. The following three small configuration options look delicious. But I think it needs to be discussed in more detail:
Quoted 3 lines
- "beforeCLI": would make it run once, like ".command" does now before any CLI trailer are processed
Does "beforeCLI" handle all trailers? Or is it just doing something to add empty value trailers?
Quoted 4 lines
- "forEachCLIToken": would make it run once for each trailer that has the token, like ".command" also does now, the difference would be that the value for the token would be passed in the $1 argument
This is exactly same as before.
Quoted 4 lines
- "afterCLI": would make it run once after all the CLI trailers have been processed and it could pass the different values for the token if any in different arguments: $1, $2, $3, ...
I might get a little confused here: What's the input for $1,$2,$3? Is users more interested in dealing with trailers value or a line of the trailer?
Quoted 17 lines
This would make it possible to extend later if the need arises for more different times or ways to run configured commands.
Quoted 6 lines
In fact, I would prefer this design, because if I don’t add any trailers, the trailer.<token>.command I set will be executed, which may be very distressing sometimes, and
alwayRunCmdis the user I hope that "trailers" can be added automatically, and other trailers.<token>.command will not be executed automatically. This allows the user to reasonably configure the commands that need to be executed. This must be a very comfortable thing.I agree that it should be easier and more straightforward, than it is now, to configure this.
Quoted 3 lines
But as you said, to disable the automatic addition in the original .command and use the new .alwaysRunCmd, I’m afraid there are a lot of things to consider. Perhaps future series of patches can be considered to do it.
Quoted 6 lines
Yeah, support for
trailer.<token>.runModemight be added in different commits at least and possibly later in a different patch series. There are the following issues to resolve, though, if we want to focus only on a new ".cmd" config option:- how and when should it run by default,
Do you mean that ".cmd" can get rid of the ".command" auto-add problem in this patch series?
This might be a good idea if I can add the three modes you mentioned above in the later patch series.
Quoted 35 lines
- how to explain that in the doc, and maybe
- how to improve the current description of what happens for ".command"Quoted 21 lines
Quoted 9 lines
This mechanism is the reason why a trick, when setting up a 'trailer.foo.command' trailer, is to also set 'trailer.foo.ifexists' to "replace", so that the first time the command is run (with $ARG replaced with the empty string) it will add a foo trailer with a default value, and if it is run another time, because a 'foo=bar' argument is passed on the command line, then the trailer with the default value will be replaced by the value computed from running the command again with $ARG replaced with "bar".
Quoted 6 lines
Another trick is to have the command output nothing when $ARG is the empty string along with using --trim-empty. This way the command will create an empty trailer, when it is run the first time, and if it's not another time, then this empty trailer will be removed because of --trim-empty.
It looks very practical indeed.
Quoted 3 lines
Quoted 2 lines
I cannot quite judge if what we came up with in the above description is sufficient.
Quoted 8 lines
Quoted 3 lines
I don't think it's sufficient. I think that, while we are at it, a bit more thinking/discussion is required to make sure we want to keep the same design as 'trailer.<token>.command'.
Sure. I agree that more discussion is needed.
I think if the documents that once belonged to .command are copied to .cmd, will the readers be too burdensome to read them? Will it be better to migrate its documentation until we completely delete .command?My opinion (if we focus only on adding ".cmd") is that:
Quoted 9 lines
- for simplicity for now it should run at the same time as ".command", the only difference being how the argument is passed (using $1 instead of textually replacing $ARG)
- the doc for ".command" should be first improved if possible, and then moved over to ".cmd" saying for ".command" that ".command" is deprecated in favor of ".cmd" but otherwise works as ".cmd" except that instead using $1 the value is passed by textually replacing $ARG which could be a safety and correctness issue.
I agree with you. There may be need some discretion.
Quoted 5 lines
Another way to work on all this, would be to first work on adding support for
trailer.<token>.runModeand on improving existing documentation, and then to add ".cmd", which could then by default use a different ".runMode" than ".command".
I think the task can be put off until April.
Deal with the easier ".cmd" first.
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
This, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
Quoted 8 lines
Quoted 2 lines
So the correct solution should be to keep the original .command Examples, and then give the .cmd examples again.
Maybe we could take advantage of ".cmd" to show other nice possibilities to use all of this. Especially if support for
git commit --trailer ...is already merged, we might be able to use it in those examples, or perhaps add some examples to the git commit doc.
Oh, the 'commit --trailer' may still be queuing, It may take a while.
Quoted 2 lines
Best,
Christian.
Thanks.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 36 lines · ZheNing Hu
Quoted 6 lines · Christian Couder <[email protected]> 于2021年3月29日周一 下午5:05写道:
Quoted 6 lines
Yes, $ARG or $1 are always exist because of:
arg = xstrdup("");Quoted 7 lines
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 232
Quoted 3 lines
so I think maybe we don't even need this judge in
apply_command?trailer.c +2
-0+if (arg) +strvec_push (&cp.args, arg);Yeah, I haven't looked at the code, but that might be a good simplification. If you work on this, please submit it in a separate commit.
Well, if necessary, I'll put it in another commit, maybe I should double check to see if there's anything special going on.
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines
Another way to do it would be to have another config option called
trailer.<token>.alwaysRunCmdto tell if the cmd specified bytrailer.<token>.cmdshould be run even if no '<token>=<value>' argument is passed on the command line. As we are introducingtrailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.Quoted 3 lines
Actually after thinking about it, I think it might be better, instead of
trailer.<token>.alwaysRunCmd, to add something liketrailer.<token>.runModethat could take multiple values like:If really can achieve it is certainly better than 'alwaysRunCmd'. The following three small configuration options look delicious. But I think it needs to be discussed in more detail:
Quoted 5 lines
Quoted 2 lines
- "beforeCLI": would make it run once, like ".command" does now before any CLI trailer are processed
Does "beforeCLI" handle all trailers? Or is it just doing something to add empty value trailers?
I am not sure what you mean by "handle all trailers". What I mean is that it would just work like ".command" does right now before the "--trailers ..." options are processed.
Let's suppose the "trailer.foo.command" config option is set to "bar". Then the "bar" command will be run just before the "--trailers ..." options are processed and the output of that, let's say "baz" will be used to add a new "foo: baz" trailer to the ouput of git interpret-trailers.
For example:
-------
$ git -c trailer.foo.command='echo baz' interpret-trailers<<EOF EOF
foo: baz
-------
In other words an empty value trailer is just a special case when the command that is run does not output anything. But such commands are expected to output something not trivial at least in some cases.
See also the example in the doc that uses:
$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
Quoted 5 lines
Quoted 3 lines
- "forEachCLIToken": would make it run once for each trailer that has the token, like ".command" also does now, the difference would be that the value for the token would be passed in the $1 argument
This is exactly same as before.
Yeah it is the same as before when the "--trailers ..." options are processed, but not before that.
To get exactly the same as before one would need to configure both "beforeCLI" _and_ "forEachCLIToken", for example like this (note that we use "--add" when adding "forEachCLIToken"):
$ git config trailer.foo.runMode beforeCLI $ git config --add trailer.foo.runMode forEachCLIToken $ git config -l | grep foo trailer.foo.runmode=beforeCLI trailer.foo.runmode=forEachCLIToken
Quoted 5 lines
Quoted 3 lines
- "afterCLI": would make it run once after all the CLI trailers have been processed and it could pass the different values for the token if any in different arguments: $1, $2, $3, ...
I might get a little confused here: What's the input for $1,$2,$3?
The input would be the different values that are used for the token in the "--trailer ..." CLI arguments.
For (an hypothetical) example:
------
$ git config trailer.foo.runMode afterCLI $ git config trailer.foo.cmd 'echo $@' $ git interpret-trailers --trailer foo=a --trailer foo=b --trailer foo=c<<EOF EOF
foo: a b c
$ git interpret-trailers<<EOF EOF
foo:
------
I am not sure "afterCLI" would be useful, but we might not want to implement it right now. It's just an example to show that we could add other modes to run the configured ".cmd" (and maybe ".command" too).
Quoted 2 lines
Is users more interested in dealing with trailers value or a line of the trailer?
I am not sure what you mean here. If "a line of the trailer" means a trailer that is already in the input file that is passed to git interpret-trailers, and if "trailers value" means a "--trailer ..." argument, then I would say that users could be interested in dealing with both.
It's true that right now the command configured by a ".command" is not run when git interpret-trailers processes in input file that contains a trailer with the corresponding token. So new values for ".runMode" could be implemented to make that happen.
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
But as you said, to disable the automatic addition in the original .command and use the new .alwaysRunCmd, I’m afraid there are a lot of things to consider. Perhaps future series of patches can be considered to do it.
Yeah, support for
trailer.<token>.runModemight be added in different commits at least and possibly later in a different patch series. There are the following issues to resolve, though, if we want to focus only on a new ".cmd" config option:
Quoted 4 lines
Quoted 1 line
- how and when should it run by default,
Do you mean that ".cmd" can get rid of the ".command" auto-add problem in this patch series?
I am not sure what you mean with "auto-add". Do you mean that fact that the ".command" runs once before the CLI "--trailer ..." options are processed?
Quoted 2 lines
This might be a good idea if I can add the three modes you mentioned above in the later patch series.
I like that your are interested in improving trailer handling in Git, but I must say that if you intend to apply for the GSoC, you might want to work on your application document first, as it will need to be discussed on the mailing list too and it will take some time. You are also free to work on this too, but that shouldn't be your priority.
By the way if this (or another Git related) subject is more interesting to you than the project ideas we propose on
https://git.github.io/SoC-2021-Ideas/, then you are welcome to write a proposal about working on this (improving trailer handling) rather than on a project idea from that page. You might want to make sure that some people would be willing to (co-)mentor you working on it though.
[...]
Quoted 7 lines
Quoted 4 lines
Another way to work on all this, would be to first work on adding support for
trailer.<token>.runModeand on improving existing documentation, and then to add ".cmd", which could then by default use a different ".runMode" than ".command".I think the task can be put off until April.
Deal with the easier ".cmd" first.
Ok for me, but see above about GSoC application.
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
This, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
So the correct solution should be to keep the original .command Examples, and then give the .cmd examples again.
Quoted 6 lines
Quoted 4 lines
Maybe we could take advantage of ".cmd" to show other nice possibilities to use all of this. Especially if support for
git commit --trailer ...is already merged, we might be able to use it in those examples, or perhaps add some examples to the git commit doc.Oh, the 'commit --trailer' may still be queuing, It may take a while.
You might want to check if it needs another reroll or if there are other reasons (like no reviews) why it's not listed in the last "What's cooking ..." email from Junio. If you think it is ready and has been forgotten, you can ping reviewers (including me), to ask them to review it one more time, or Junio if the last version you sent has already been reviewed.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 63 lines · Christian Couder <[email protected]> 于2021年3月30日周二 下午4:45写道:
Quoted 36 lines · ZheNing Hu
Quoted 6 lines · Christian Couder <[email protected]> 于2021年3月29日周一 下午5:05写道:
Quoted 6 lines
Yes, $ARG or $1 are always exist because of:
arg = xstrdup("");Quoted 7 lines
Review
Quoted 3 lines
so I think maybe we don't even need this judge in
apply_command?(quoted diff) +2
-0+ if (arg) + strvec_push(&cp.args, arg);Yeah, I haven't looked at the code, but that might be a good simplification. If you work on this, please submit it in a separate commit.
Well, if necessary, I'll put it in another commit, maybe I should double check to see if there's anything special going on.
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines
Another way to do it would be to have another config option called
trailer.<token>.alwaysRunCmdto tell if the cmd specified bytrailer.<token>.cmdshould be run even if no '<token>=<value>' argument is passed on the command line. As we are introducingtrailer.<token>.cmd, it's a good time to wonder if this would be a better design. But this issue is quite complex, because of the fact that 'trailer.<token>.ifMissing' and 'trailer.<token>.ifExists' also take a part in deciding if the command will be run.Quoted 3 lines
Actually after thinking about it, I think it might be better, instead of
trailer.<token>.alwaysRunCmd, to add something liketrailer.<token>.runModethat could take multiple values like:If really can achieve it is certainly better than 'alwaysRunCmd'. The following three small configuration options look delicious. But I think it needs to be discussed in more detail:
Quoted 5 lines
Quoted 2 lines
- "beforeCLI": would make it run once, like ".command" does now before any CLI trailer are processed
Does "beforeCLI" handle all trailers? Or is it just doing something to add empty value trailers?
I am not sure what you mean by "handle all trailers". What I mean is that it would just work like ".command" does right now before the "--trailers ..." options are processed.
Let's suppose the "trailer.foo.command" config option is set to "bar". Then the "bar" command will be run just before the "--trailers ..." options are processed and the output of that, let's say "baz" will be used to add a new "foo: baz" trailer to the ouput of
git interpret-trailers.For example:
-------
$ git -c trailer.foo.command='echo baz' interpret-trailers<<EOF EOFfoo: baz
-------
Quoted 9 lines
In other words an empty value trailer is just a special case when the command that is run does not output anything. But such commands are expected to output something not trivial at least in some cases.
See also the example in the doc that uses:
$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
I see what you mean, which is to provide a default value for any trailers that haven't been run command yet.
Quoted 40 lines
Quoted 5 lines
Quoted 3 lines
- "forEachCLIToken": would make it run once for each trailer that has the token, like ".command" also does now, the difference would be that the value for the token would be passed in the $1 argument
This is exactly same as before.
Yeah it is the same as before when the "--trailers ..." options are processed, but not before that.
To get exactly the same as before one would need to configure both "beforeCLI" _and_ "forEachCLIToken", for example like this (note that we use "--add" when adding "forEachCLIToken"):
$ git config trailer.foo.runMode beforeCLI $ git config --add trailer.foo.runMode forEachCLIToken $ git config -l | grep foo trailer.foo.runmode=beforeCLI trailer.foo.runmode=forEachCLITokenQuoted 5 lines
Quoted 3 lines
- "afterCLI": would make it run once after all the CLI trailers have been processed and it could pass the different values for the token if any in different arguments: $1, $2, $3, ...
I might get a little confused here: What's the input for $1,$2,$3?
The input would be the different values that are used for the token in the "--trailer ..." CLI arguments.
For (an hypothetical) example:
------
$ git config trailer.foo.runMode afterCLI $ git config trailer.foo.cmd 'echo $@' $ git interpret-trailers --trailer foo=a --trailer foo=b --trailer foo=c<<EOF EOFfoo: a b c
$ git interpret-trailers<<EOF EOF
Quoted 7 lines
foo:
------I am not sure "afterCLI" would be useful, but we might not want to implement it right now. It's just an example to show that we could add other modes to run the configured ".cmd" (and maybe ".command" too).
Yes, not so useful.
Quoted 9 lines
Quoted 2 lines
Is users more interested in dealing with trailers value or a line of the trailer?
I am not sure what you mean here. If "a line of the trailer" means a trailer that is already in the input file that is passed to
git interpret-trailers, and if "trailers value" means a "--trailer ..." argument, then I would say that users could be interested in dealing with both.
Sorry, I mean after we running those command, a line trailer is "foo: bar" and trailers value will be "bar".
Quoted 5 lines
It's true that right now the command configured by a ".command" is not run when
git interpret-trailersprocesses in input file that contains a trailer with the corresponding token. So new values for ".runMode" could be implemented to make that happen.
Sure.
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
But as you said, to disable the automatic addition in the original .command and use the new .alwaysRunCmd, I’m afraid there are a lot of things to consider. Perhaps future series of patches can be considered to do it.
Yeah, support for
trailer.<token>.runModemight be added in different commits at least and possibly later in a different patch series. There are the following issues to resolve, though, if we want to focus only on a new ".cmd" config option:
Quoted 9 lines
Quoted 4 lines
Quoted 1 line
- how and when should it run by default,
Do you mean that ".cmd" can get rid of the ".command" auto-add problem in this patch series?
I am not sure what you mean with "auto-add". Do you mean that fact that the ".command" runs once before the CLI "--trailer ..." options are processed?
I'm talking about the empty values $ARG passing to the user's command, those command at least run once, You say "how and when should it run by default", I was wondering if I could not run .cmd without passing trailer.
Quoted 9 lines
Quoted 2 lines
This might be a good idea if I can add the three modes you mentioned above in the later patch series.
I like that your are interested in improving trailer handling in Git, but I must say that if you intend to apply for the GSoC, you might want to work on your application document first, as it will need to be discussed on the mailing list too and it will take some time. You are also free to work on this too, but that shouldn't be your priority.
In fact, I had written the proposal carefully.
I have been studying what went wrong with OIga's improvement of cat-file recently.
I may have thought of some ideas, and has been written in Proposal, I will submit it in about two days :)
Quoted 8 lines
By the way if this (or another Git related) subject is more interesting to you than the project ideas we propose on
https://git.github.io/SoC-2021-Ideas/, then you are welcome to write a proposal about working on this (improving trailer handling) rather than on a project idea from that page. You might want to make sure that some people would be willing to (co-)mentor you working on it though.
Aha, for the time being, you are the most suitable mentor,
But I might just take improvement of interpret-tarilers as my interest to do something. I will choice the project of "git cat-file" .
Quoted 25 lines
[...]
Quoted 7 lines
Quoted 4 lines
Another way to work on all this, would be to first work on adding support for
trailer.<token>.runModeand on improving existing documentation, and then to add ".cmd", which could then by default use a different ".runMode" than ".command".I think the task can be put off until April.
Deal with the easier ".cmd" first.Ok for me, but see above about GSoC application.
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
This, too, but until ".command" is removed, wouldn't it be better for readers to keep both variants, as the distinction between $ARG and $1 needs to be illustrated?
So the correct solution should be to keep the original .command Examples, and then give the .cmd examples again.
Maybe we could take advantage of ".cmd" to show other nice possibilities to use all of this. Especially if support for
git commit --trailer ...is already merged, we might be able to use it in those examples, or perhaps add some examples to the git commit doc.
Quoted 8 lines
Quoted 1 line
Oh, the 'commit --trailer' may still be queuing, It may take a while.
You might want to check if it needs another reroll or if there are other reasons (like no reviews) why it's not listed in the last "What's cooking ..." email from Junio. If you think it is ready and has been forgotten, you can ping reviewers (including me), to ask them to review it one more time, or Junio if the last version you sent has already been reviewed.
It should still be in "seen" inheritance, Junio is advancing it. Maybe you think it has something to improve, please feel free to tell me.
In addition, I now found a small bug in ".cmd",
git config -l |grep bug
trailer.bug.key=bug-descibe:
trailer.bug.ifexists=replace
trailer.bug.cmd=echo 123
see what will happen:
git interpret-trailers --trailer="bug:text" <<-EOF `heredocd> EOF
bug-descibe:123 text
"text" seem print to stdout.
I'm looking at what's going on here.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Hi, Junio,
Quoted 10 lines · ZheNing Hu <[email protected]> 于2021年3月30日周二 下午7:22写道:
In addition, I now found a small bug in ".cmd",
git config -l |grep bug
trailer.bug.key=bug-descibe:
trailer.bug.ifexists=replace
trailer.bug.cmd=echo 123see what will happen:
Quoted 9 lines
git interpret-trailers --trailer="bug:text" <<
-EOF`heredocd> EOFbug-descibe:123 text
"text" seem print to stdout.
I'm looking at what's going on here.
Here I may need to think with you whether it is reasonable to pass "$1".
I found that we passed the parameters in the above situation like this:
(gdb) print cp.args.v[0]
$7 = 0x5555558f4e20 "echo \"123\""
(gdb) print cp.args.v[1]
$8 = 0x5555558ee150 "text"
At this time, our idea is base on that v[0] will be the content of the shell, and v[1] will be the $1 of the shell.
But in fact, git handles shell subprocesses in a special way:
The prepare_shell_cmd() in "run-command.c" seem to use "$@" to pass shell args.
Before exec:
(gdb) print argv.v[1]
$22 = 0x5555558edfd0 "/bin/sh"
(gdb) print argv.v[2]
$23 = 0x5555558f4c80 "-c"
(gdb) print argv.v[3]
$24 = 0x5555558ed4b0 "echo \"123\" \"$@\""
(gdb) print argv.v[4]
$25 = 0x5555558f5980 "echo \"123\""
(gdb) print argv.v[5]
$26 = 0x5555558edab0 "abc"
(gdb) print argv.v[6]
$27 = 0x0
Some unexpected things happened here.
Maybe "abc" was wrongly used as the parameter of "echo"? Looking forward to your reply.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 2 lines · ZheNing Hu
The
prepare_shell_cmd()in "run-command.c" seem to use "$@" to pass shell args.
Yes. "$@" is a way to write "$1" "$2" "$3"...
Since you are passing only one,
echo "$@"
and
echo "$1"
would be the equivalent.
I am not sure what program you fed to the gdb (and remote debugging over e-mail is not my forte ;-), but let's see.
Quoted 15 lines
Before exec:
(gdb) print argv.v[1]
$22 =0x5555558edfd0"/bin/sh"
(gdb) print argv.v[2]
$23 =0x5555558f4c80"-c"
(gdb) print argv.v[3]
$24 =0x5555558ed4b0"echo \"123\" \"$@\""
(gdb) print argv.v[4]
$25 =0x5555558f5980"echo \"123\""
(gdb) print argv.v[5]
$26 =0x5555558edab0"abc"
(gdb) print argv.v[6]
$27 =0x0
Quoted 3 lines
Some unexpected things happened here.
Maybe "abc" was wrongly used as the parameter of "echo"? Looking forward to your reply.
Observe
$ sh -c ' echo "\$0 == $0" count=0 for arg in "$@" do count=$(( $count + 1 )) echo "\$$count == $arg" done ' 0 1 2 $0 == 0 $1 == 1 $2 == 2
i.e. the first arg after
argv[1] = "/bin/sh"
argv[2] = "-c"
argv[3] = "script"is used to give the script the name of the program ($0). Are we getting hit by this common confusion?
It is customery to write such an invocation with '-' as the "name of the program" thing, so that ordinary positional parameters are available starting at $1, not $0, like so:
sh -c 'script' - arg1 arg2 ...
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 63 lines · Junio C Hamano <[email protected]> 于2021年3月31日周三 上午1:14写道:
Quoted 2 lines · ZheNing Hu
The
prepare_shell_cmd()in "run-command.c" seem to use "$@" to pass shell args.Yes. "$@" is a way to write "$1" "$2" "$3"...
Since you are passing only one,echo "$@"and
echo "$1"would be the equivalent.
I am not sure what program you fed to the gdb (and remote debugging over e-mail is not my forte ;-), but let's see.
Quoted 15 lines
Before exec:
(gdb) print argv.v[1]
$22 =0x5555558edfd0"/bin/sh"
(gdb) print argv.v[2]
$23 =0x5555558f4c80"-c"
(gdb) print argv.v[3]
$24 =0x5555558ed4b0"echo \"123\" \"$@\""
(gdb) print argv.v[4]
$25 =0x5555558f5980"echo \"123\""
(gdb) print argv.v[5]
$26 =0x5555558edab0"abc"
(gdb) print argv.v[6]
$27 =0x0Quoted 3 lines
Some unexpected things happened here.
Maybe "abc" was wrongly used as the parameter of "echo"? Looking forward to your reply.Observe
$ sh -c ' echo "\$0 == $0" count=0 for arg in "$@" do count=$(( $count + 1 )) echo "\$$count == $arg" done ' 0 1 2 $0 == 0 $1 == 1 $2 == 2i.e. the first arg after
argv[1] = "/bin/sh" argv[2] = "-c" argv[3] = "script"
Quoted 8 lines
is used to give the script the name of the program ($0). Are we getting hit by this common confusion?
It is customery to write such an invocation with '-' as the "name of the program" thing, so that ordinary positional parameters are available starting at $1, not $0, like so:
sh -c 'script' - arg1 arg2 ...
The configuration is like this:
trailer.bug.key=BUG:
trailer.bug.ifexists=add
trailer.bug.cmd=echo "123"
And use:
$ git interpret-trailers --trailer="bug:456" --trailer="bug:789"<<-EOF EOF
BUG: 123 BUG: 123 456 BUG: 123 789
I just want three "BUG: 123", but "456" and "789" appeared...
In fact, I think about this problem like this way:
When we execute a child process that runs the shell,
the functionprepare_shell_cmd() will actively add "$@" to the end of our shell command when we have more than zero args ,
e.g.
"echo \"123\"" "abc"
will turn to
"echo \"123\" \"$@\"" "echo \"123\"" "abc"
Normally, $@ should not cause any problems because it passes arguments to the script what we provide.
But now, what we actually want is take any $1 that appears in the script as an argument, the automatically added $@ causes $1 to be implicitly included. And the original $ARG does not have this problem, Or if we pass environment variables, this kind of problem will not occur.
Or If we want to avoid this problem, should we add one new options in struct child_process , such as: "shell_no_implicit_args" , let git not add
extra "$@" before we run the shell script?
Thanks.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 5 lines · ZheNing Hu
The configuration is like this:
trailer.bug.key=BUG:
trailer.bug.ifexists=add
trailer.bug.cmd=echo "123"
Quoted 8 lines
And use:
$ git interpret-trailers --trailer="bug:456" --trailer="bug:789"<<-EOF EOFBUG: 123 BUG: 123 456 BUG: 123 789
I think that is quite expected. You said the command to run is 'echo 123', and that is not "pick a directory $D on $PATH where there is an executable '$D/echo 123' exists, and run that". It runs the given command with the shell, and in general that is what we want for end-user supplied commands specified in the configuration file [*1*].
So we form a shell command whose beginning is 'echo 123' and tuck the argument after that command line, so it is understandable that "echo 123 456" gets executed for "--trailer=bug:456".
I wasn't following the discussion between you and Christian closely but I recall seeing him saying that the command is executed one extra time without any arg before it is run for actual --trailer requests with the value? I am guessing that is where the first output "BUG: 123" (without anything else) is coming from.
*1* Imagine .editor set to 'emacs -nw' or 'vim -f'; we do not want
Git to find a directory on $PATH that has an executable whose name is 'emacs -nw' and run that file (i.e. give 'emacs -nw' as the first argument to execlp()). Instead, you'd want to behave as if the user typed "emacs -nw", followed by any arguments we want to give to it (in .editor's case, the name of the file to be edited) properly quoted for the shell.
And the way we do so is to form a moral equivalent of
execlp("sh", "-c", "emacs -nw $@", ...);
and put the arguments at the end where I wrote ... (we actually do so with execvp(), but illustrating with execlp() is easier to read and write---hence "a moral equivalent of").
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 31 lines · Junio C Hamano
Quoted 5 lines · ZheNing Hu
The configuration is like this:
trailer.bug.key=BUG:
trailer.bug.ifexists=add
trailer.bug.cmd=echo "123"Quoted 8 lines
And use:
$ git interpret-trailers --trailer="bug:456" --trailer="bug:789"<<-EOF EOFBUG: 123 BUG: 123 456 BUG: 123 789I think that is quite expected. You said the command to run is 'echo 123', and that is not "pick a directory $D on $PATH where there is an executable '$D/echo 123' exists, and run that". It runs the given command with the shell, and in general that is what we want for end-user supplied commands specified in the configuration file [*1*].
...
*1* Imagine .editor set to 'emacs -nw' or 'vim -f'; we do not want
Git to find a directory on $PATH that has an executable whose name is 'emacs -nw' and run that file (i.e. give 'emacs -nw' as the first argument toexeclp()). Instead, you'd want to behave as if the user typed "emacs -nw", followed by any arguments we want to give to it (in .editor's case, the name of the file to be edited) properly quoted for the shell.
Quoted 7 lines
And the way we do so is to form a moral equivalent of
execlp("sh", "-c", "emacs -nw \"$@\"", ...);and put the arguments at the end where I wrote ... (we actually do so with
execvp(), but illustrating withexeclp()is easier to read and write---hence "a moral equivalent of").
So, learning from that .editor example, what you can do when you do not want to take any parameter is to explicitly ignore them.
Let's take the very basic form first. Imagine you wrote a little script and wanted to see three "123", ignoring end-user input after "--trailer=bug:".
.cmd = my-script 123
would run 'my-script "$@"'. What should you write in my-script to cause that happen? Here is an example solution:
#!/bin/sh
echo 123Notice that "$1" is completely ignored, even if the machinery that drives .cmd makes three calls?
sh -c 'my-script 123 "$@"' sh -c 'my-script 123 "$@"' 456 sh -c 'my-script 123 "$@"' 789
The way to do the same without an extra script on disk is for you to use sh-c yourself.
.cmd = sh -c 'echo 123'
And if you do want to use $1, you can do the same. E.g. if you want to double them in the output, you'd probably do something like this:
.cmd = sh -c 'echo "<$1 - $1>"'
You'd need to quote the value appropriately for the config file, though.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 60 lines · Junio C Hamano <[email protected]> 于2021年4月1日周四 上午2:29写道:
Quoted 31 lines · Junio C Hamano
Quoted 5 lines · ZheNing Hu
The configuration is like this:
trailer.bug.key=BUG:
trailer.bug.ifexists=add
trailer.bug.cmd=echo "123"Quoted 8 lines
And use:
$ git interpret-trailers --trailer="bug:456" --trailer="bug:789"<<-EOF EOFBUG: 123 BUG: 123 456 BUG: 123 789I think that is quite expected. You said the command to run is 'echo 123', and that is not "pick a directory $D on $PATH where there is an executable '$D/echo 123' exists, and run that". It runs the given command with the shell, and in general that is what we want for end-user supplied commands specified in the configuration file [*1*].
...
*1* Imagine .editor set to 'emacs -nw' or 'vim -f'; we do not want
Git to find a directory on $PATH that has an executable whose name is 'emacs -nw' and run that file (i.e. give 'emacs -nw' as the first argument toexeclp()). Instead, you'd want to behave as if the user typed "emacs -nw", followed by any arguments we want to give to it (in .editor's case, the name of the file to be edited) properly quoted for the shell.Quoted 7 lines
And the way we do so is to form a moral equivalent of
execlp("sh", "-c", "emacs -nw \"$@\"", ...);and put the arguments at the end where I wrote ... (we actually do so with
execvp(), but illustrating withexeclp()is easier to read and write---hence "a moral equivalent of").So, learning from that .editor example, what you can do when you do not want to take any parameter is to explicitly ignore them.
Let's take the very basic form first. Imagine you wrote a little script and wanted to see three "123", ignoring end-user input after "--trailer=bug:".
.cmd = my-script 123would run 'my-script "$@"'. What should you write in my-script to cause that happen? Here is an example solution:
#!/bin/sh echo 123Notice that "$1" is completely ignored, even if the machinery that drives .cmd makes three calls?
Quoted 9 lines
sh -c 'my-script 123 "$@"' sh -c 'my-script 123 "$@"' 456 sh -c 'my-script 123 "$@"' 789The way to do the same without an extra script on disk is for you to use sh-c yourself.
.cmd = sh -c 'echo 123'
This is indeed a viable solution, But the extra "sh -c" seems to put an unnecessary burden on the user.
Sometimes I wonder, why not recommend using environment variables like $ARG?
Quoted 7 lines
And if you do want to use $1, you can do the same. E.g. if you want to double them in the output, you'd probably do something like this:
.cmd = sh -c 'echo "<$1 - $1>"'You'd need to quote the value appropriately for the config file, though.
In fact, In the following example, trailer <value> contains whitespaces ,
$ git interpret-trailers --trailer="bug:the information manager from hell"
which can make it to work properly (But it's a little bit tedious):
$ git config trailer.bug.cmd "sh -c \"echo \\\"\$1\"\\\"" $ git interpret-trailers --trailer="bug:the information manager from hell"
Bug-from:
Bug-from: the information manager from hell
Is there an easier way?
Or can make the user ignore the details of "sh -c"?
Thanks.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 7 lines · ZheNing Hu
Quoted 4 lines
The way to do the same without an extra script on disk is for you to use sh-c yourself.
.cmd = sh -c 'echo 123'This is indeed a viable solution, But the extra "sh -c" seems to put an unnecessary burden on the user.
Nobody forces you to write long script in the configuration file. In fact, the "find author from history" is so useful that I'd think people have an alias or a script in ~/bin/ already for their own interactive use. E.g.
$ cat ~/bin/git-who
#!/bin/sh
git log -1 --format="%an <%ae>" --author="$1"
$ cat ~/bin/git-one
#!/bin/sh
git show -s --pretty=reference "$1"and with them:
trailer.key.cmd = git who
that is internally wrapped into
sh -c 'git who "$@"'
and fed "gitster@" as the first parameter when "--trailer=key:gitster@" is given would work just fine.
Quoted 2 lines
Sometimes I wonder, why not recommend using environment variables like $ARG?
I am also fine with that; when we discovered the design flaw of .command, I think I suggested either would make a viable choice. The only downside is that it would squat on a good name $ARG and forbids end-users from using the symbol for other purpose, but as long as the application is limited in scope, that would be fine.
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
Quoted 25 lines · Junio C Hamano <[email protected]> 于2021年4月2日周五 上午3:49写道:
Quoted 7 lines · ZheNing Hu
Quoted 4 lines
The way to do the same without an extra script on disk is for you to use sh-c yourself.
.cmd = sh -c 'echo 123'This is indeed a viable solution, But the extra "sh -c" seems to put an unnecessary burden on the user.
Nobody forces you to write long script in the configuration file. In fact, the "find author from history" is so useful that I'd think people have an alias or a script in ~/bin/ already for their own interactive use. E.g.
$ cat ~/bin/git-who #!/bin/sh git log -1 --format="%an <%ae>" --author="$1" $ cat ~/bin/git-one #!/bin/sh git show -s --pretty=reference "$1"and with them:
Quoted 9 lines
trailer.key.cmd = git who
that is internally wrapped into
sh -c 'git who "$@"'and fed "gitster@" as the first parameter when "--trailer=key:gitster@" is given would work just fine.
Okay, now I get it. This allows us to run some common scripts or just use "sh -c". I might need some additional tests to illustrate those changes made by using '.cmd'.
Quoted 8 lines
Quoted 2 lines
Sometimes I wonder, why not recommend using environment variables like $ARG?
I am also fine with that; when we discovered the design flaw of .command, I think I suggested either would make a viable choice. The only downside is that it would squat on a good name $ARG and forbids end-users from using the symbol for other purpose, but as long as the application is limited in scope, that would be fine.
I agree with you. This may indeed be a minor drawback.
Thanks, Junio.
--
ZheNing Hu
Re: [PATCH v4] [GSOC]trailer: pass arg as positional parameter
In reply to Junio C HamanoQuoted 17 lines · Junio C Hamano <[email protected]> 于2021年4月1日周四 上午2:20写道:
Quoted 5 lines · ZheNing Hu
The configuration is like this:
trailer.bug.key=BUG:
trailer.bug.ifexists=add
trailer.bug.cmd=echo "123"Quoted 8 lines
And use:
$ git interpret-trailers --trailer="bug:456" --trailer="bug:789"<<-EOF EOFBUG: 123 BUG: 123 456 BUG: 123 789
Quoted 7 lines
I think that is quite expected. You said the command to run is 'echo 123', and that is not "pick a directory $D on $PATH where there is an executable '$D/echo 123' exists, and run that". It runs the given command with the shell, and in general that is what we want for end-user supplied commands specified in the configuration file [*1*].
I agree that if you want to use execv directly to execute a terminal command, if arg[0] is something like "emacs -nw", error will be reported:"No such file or directory". But by wrapping a layer of "sh" "-c", The program name 'emacs' in 'emacs -nw' can be found and executed normally.
Quoted 10 lines
So we form a shell command whose beginning is 'echo 123' and tuck the argument after that command line, so it is understandable that "echo 123 456" gets executed for "--trailer=bug:456".
I wasn't following the discussion between you and Christian closely but I recall seeing him saying that the command is executed one extra time without any arg before it is run for actual --trailer requests with the value? I am guessing that is where the first output "BUG: 123" (without anything else) is coming from.
Exactly.
Each .command/.cmd willl executes this 'beforeCLI' operation once, I use ifexists='add' here just for seeing the effect, In general, we will use ifexists='replace'.
Quoted 9 lines
*1* Imagine .editor set to 'emacs -nw' or 'vim -f'; we do not want
Git to find a directory on $PATH that has an executable whose name is 'emacs -nw' and run that file (i.e. give 'emacs -nw' as the first argument toexeclp()). Instead, you'd want to behave as if the user typed "emacs -nw", followed by any arguments we want to give to it (in .editor's case, the name of the file to be edited) properly quoted for the shell.
Quoted 7 lines
And the way we do so is to form a moral equivalent of
execlp("sh", "-c", "emacs -nw $@", ...);and put the arguments at the end where I wrote ... (we actually do so with
execvp(), but illustrating withexeclp()is easier to read and write---hence "a moral equivalent of").
I can see the benefits of this.
v5 cover trailer: pass arg as positional parameter
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
ZheNing Hu (2):
[GSOC] run-command: add shell_no_implicit_args option [GSOC]trailer: pass arg as positional parameter
Documentation/git-interpret-trailers.txt | 75 ++++++++++++++++++++---- run-command.c | 8 +-- run-command.h | 1 + t/t7513-interpret-trailers.sh | 61 ++++++++++++++++++- trailer.c | 38 ++++++++---- 5 files changed, 157 insertions(+), 26 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v4:
-: ------------ > 1: 4c59cab53a0d [GSOC] run-command: add shell_no_implicit_args option 1: e2bbdcb943c2 ! 2: 5894d8c4b364 [GSOC]trailer: pass arg as positional parameter
@@ Commit message
scripts.
+ Helped-by: Christian Couder <[email protected]>
## Documentation/git-interpret-trailers.txt ##
-@@ Documentation/git-interpret-trailers.txt: also be executed for each of these arguments. And the <value> part of
- these arguments, if any, will be used to replace the $ARG string in
- the command.
-
+@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
+ be called to automatically add or modify a trailer with the
+ specified <token>.
+ +
+-When this option is specified, the behavior is as if a special
+-'<token>=<value>' argument were added at the beginning of the command
+-line, where <value> is taken to be the standard output of the
+-specified command with any leading and trailing whitespace trimmed
+-off.
++When this option is specified, the first occurrence of substring $ARG is
++replaced with the value given to the interpret-trailer command for the
++same token.
+ +
+-If the command contains the $ARG string, this string will be
+-replaced with the <value> part of an existing trailer with the same
+-<token>, if any, before the command is launched.
++".command" has been deprecated due to the $ARG in the user's command can
++only be replaced once and the original way of replacing $ARG was not safe.
++Now the preferred option is using "trailer.<token>.cmd", which use position
++argument to pass the value.
+++
++When both .cmd and .command are given for the same <token>,
++.cmd is used and .command is ignored.
++
+trailer.<token>.cmd::
+ The command specified by this configuration variable is run
+ with a single parameter, which is the <value> part of an
+ existing trailer with the same <token>. The output from the
+ command is then used as the value for the <token> in the
+ resulting trailer.
-+ The command is expected to replace trailer.<token>.cmd.
-+ When both .cmd and .command are given for the same <token>,
-+ .cmd is used and .command is ignored.
-+
- EXAMPLES
- --------
-
-@@ Documentation/git-interpret-trailers.txt: $ git format-patch -1
- $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Reviewed-by: Bob <[email protected]>' 0001-foo.patch >0001-bar.patch
- ------------
-
--* Configure a 'sign' trailer with a command to automatically add a
-+* Configure a 'sign' trailer with a cmd to automatically add a
- 'Signed-off-by: ' with the author information only if there is no
- 'Signed-off-by: ' already, and show how it works:
+++
++When this option is specified, If there is no trailer with same <token>,
++the behavior is as if a special '<token>=<value>' argument were added at
++the beginning of the command, <value> will be passed to the user's
++command as an empty value.
+
-@@ Documentation/git-interpret-trailers.txt: $ git interpret-trailers --trailer 'Cc: Alice <[email protected]>' --trailer 'Re
- $ git config trailer.sign.key "Signed-off-by: "
- $ git config trailer.sign.ifmissing add
- $ git config trailer.sign.ifexists doNothing
--$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
-+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
- $ git interpret-trailers <<EOF
- > EOF
+ If some '<token>=<value>' arguments are also passed on the command
+ line, when a 'trailer.<token>.command' is configured, the command will
+ also be executed for each of these arguments. And the <value> part of
+-these arguments, if any, will be used to replace the $ARG string in
+-the command.
++these arguments, if any, will be passed to the command as first parameter.
+ EXAMPLES
+ --------
@@ Documentation/git-interpret-trailers.txt: subject
Fix #42
------------
--* Configure a 'see' trailer with a command to show the subject of a
+* Configure a 'see' trailer with a cmd to show the subject of a
++ commit that is related, and show how it works:
+++
++------------
++$ git config trailer.see.key "See-also: "
++$ git config trailer.see.ifExists "replace"
++$ git config trailer.see.ifMissing "doNothing"
++$ git config trailer.see.cmd "git show -s --pretty=reference \"\$1\""
++$ git interpret-trailers <<EOF
++> subject
++>
++> message
++>
++> see: HEAD~2
++> EOF
++subject
++
++message
++
++See-also: fe3187489d69c4 (subject of related commit, 2021-3-20)
++------------
++
++* Configure a 'bug' trailer with a cmd to show when and where
++ was the bug introduced, and show how it works:
+++
++------------
++$ git config trailer.bug.key "Bug-from: "
++$ git config trailer.bug.ifExists "replace"
++$ git config trailer.bug.cmd "git log --grep \"\$1\" -1 --pretty=\"%h %aD\""
++$ git interpret-trailers --trailer="bug:the information manager from hell" <<EOF
++> subject
++>
++> message
++>
++> EOF
++subject
++
++message
++
++Bug-from: 57d84f8d93 Mon, 6 Aug 2012 18:27:09 +0700
++------------
++
+ * Configure a 'see' trailer with a command to show the subject of a
commit that is related, and show how it works:
+
- ------------
- $ git config trailer.see.key "See-also: "
- $ git config trailer.see.ifExists "replace"
- $ git config trailer.see.ifMissing "doNothing"
--$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" -+$ git config trailer.see.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \"\$1\"|| true "
- $ git interpret-trailers <<EOF
- > subject
- >
## t/t7513-interpret-trailers.sh ##
+@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ EOF
+ '
+
++test_expect_success 'with cmd' '
++ test_when_finished "git config --unset trailer.bug.key && \
++ git config --unset trailer.bug.ifExists && \
++ git config --unset trailer.bug.cmd" &&
++ git config trailer.bug.key "Bug-maker: " &&
++ git config trailer.bug.ifExists "add" &&
++ git config trailer.bug.cmd "echo \"\$@\"" &&
++ cat >>expected2 <<-EOF &&
++
++ Bug-maker:
++ Bug-maker: jocker
++ Bug-maker: batman
++ EOF
++ git interpret-trailers --trailer "bug: jocker" --trailer "bug:batman" \
++ >actual2 &&
++ test_cmp expected2 actual2
++'
++
+ test_expect_success 'without config' '
+ sed -e "s/ Z\$/ /" >expected <<-\EOF &&
+
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
-
- strvec_push(&cp.args, cmd.buf);
+ if (conf->cmd) {
++ cp.shell_no_implicit_args = 1;
+ strbuf_addstr(&cmd, conf->cmd);
+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
+- cp.shell_no_implicit_args = 1;
+
+ if (capture_command(&cp, &buf, 1024)) {
+ error(_("running trailer command '%s' failed"), cmd.buf);
@@ trailer.c: static char *apply_command(const char *command, const char *arg)
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
Signature · 1 line
gitgitgadget
PATCH v5 1/2 run-command: add shell_no_implicit_args option
From: ZheNing Hu <[email protected]>
When we use subprocess to run a shell-script, if we have any args, git will add extra $@ to the end of the shell-script, This can pass positional parameters correctly, But if we just want to use some of these passed parameters, git will still add an extra "$@", which contains all positional parameters we passed. This does not meet our expectations.
E.g. our shell-script is:
"echo \"\$1\""
and pass $1 "abc", git will change our script to:
"echo \"\$1\" \"$@\""
The positional parameters we entered will be printed repeatedly. So let add a new shell_no_implicit_args to struct child_process, which can suppress the joining of $@ if shell_no_implicit_args is set to 1, this will allow us to use only few of positional args in multi-parameter shell script, instead of using all of them.
--- run-command.c | 8 ++++---- run-command.h | 1 + trailer.c | 1 + 3 files changed, 6 insertions(+), 4 deletions(-)
run-command.c +4 -4
@@ -264,7 +264,7 @@ int sane_execvp(const char *file, char * const argv[])return -1 ; } -static const char **prepare_shell_cmd (struct strvec *out,const char **argv) +static const char **prepare_shell_cmd (struct strvec *out,const char **argv,int shell_no_implicit_args) {if (!argv[0 ])BUG ("shell command is empty" );
@@ -281,7 +281,7 @@ static const char **prepare_shell_cmd(struct strvec *out, const char **argv)* If we have no extra arguments, we do not even need to * bother with the "$@" magic. */ -if (!argv[1 ]) +if (!argv[1 ] || shell_no_implicit_args)strvec_push (out, argv[0 ]);else strvec_pushf (out,"%s \"$@\"" , argv[0 ]);
@@ -416,7 +416,7 @@ static int prepare_cmd(struct strvec *out, const struct child_process *cmd)if (cmd->git_cmd) {prepare_git_cmd (out, cmd->argv); }else if (cmd->use_shell) { -prepare_shell_cmd (out, cmd->argv); +prepare_shell_cmd (out, cmd->argv, cmd->shell_no_implicit_args); }else {strvec_pushv (out, cmd->argv); }
@@ -929,7 +929,7 @@ int start_command(struct child_process *cmd)if (cmd->git_cmd) cmd->argv =prepare_git_cmd (&nargv, cmd->argv);else if (cmd->use_shell) - cmd->argv =prepare_shell_cmd (&nargv, cmd->argv); + cmd->argv =prepare_shell_cmd (&nargv, cmd->argv, cmd->shell_no_implicit_args); cmd->pid =mingw_spawnvpe (cmd->argv[0 ], cmd->argv, (char **) cmd->env, cmd->dir, fhin, fhout, fherr);
run-command.h +1 -0
@@ -133,6 +133,7 @@ struct child_process {* argv[1], etc, do not need to be shell-quoted. */ unsigned use_shell:1; + unsigned shell_no_implicit_args:1; unsigned stdout_to_stderr:1; unsigned clean_on_exit:1;
trailer.c +1 -0
@@ -231,6 +231,7 @@ static char *apply_command(const char *command, const char *arg) cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ; + cp.shell_no_implicit_args =1 ;if (capture_command (&cp, &buf,1024 )) {error (_ ("running trailer command '%s' failed" ), cmd.buf);
Signature · 1 line
gitgitgadget
Re: [PATCH v5 1/2] [GSOC] run-command: add shell_no_implicit_args option
Quoted 4 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
When we use subprocess to run a shell-script, if we have any
Maybe: s/subprocess/a subprocess/
Quoted 5 lines
args, git will add extra $@ to the end of the shell-script, This can pass positional parameters correctly, But if we just want to use some of these passed parameters, git will still add an extra "$@", which contains all positional parameters we passed. This does not meet our expectations.
I am not sure explaining things using $@ is the best way to make this as clear as possible. I don't have a clear alternative right now though.
Quoted 3 lines
E.g. our shell-script is:
"echo \"\$1\""
and pass $1 "abc",
Maybe: s/pass $1 "abc"/we pass "abc" as $1/
Quoted 2 lines
git will change our script to:
"echo \"\$1\" \"$@\""
Where will "abc" appear then?
Quoted 2 lines
The positional parameters we entered will be printed repeatedly.
If you take us passing "abc" in $1 as an example, then I think it's a good idea to show us the result of that.
Quoted 1 line
So let add a new
shell_no_implicit_args
Maybe: s/shell_no_implicit_args/shell_no_implicit_args flag/
Quoted 5 lines
to
struct child_process, which can suppress the joining of $@ ifshell_no_implicit_argsis set to 1, this will allow us to use only few of positional args in multi-parameter shell script, instead of using all of them.
I think our goal is more to have each argument we pass be passed just once.
Re: [PATCH v5 1/2] [GSOC] run-command: add shell_no_implicit_args option
Quoted 34 lines · Christian Couder <[email protected]> 于2021年4月1日周四 下午3:22写道:
Quoted 4 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
When we use subprocess to run a shell-script, if we have any
Maybe: s/subprocess/a subprocess/
Quoted 5 lines
args, git will add extra $@ to the end of the shell-script, This can pass positional parameters correctly, But if we just want to use some of these passed parameters, git will still add an extra "$@", which contains all positional parameters we passed. This does not meet our expectations.
I am not sure explaining things using $@ is the best way to make this as clear as possible. I don't have a clear alternative right now though.
Quoted 3 lines
E.g. our shell-script is:
"echo \"\$1\""
and pass $1 "abc",Maybe: s/pass $1 "abc"/we pass "abc" as $1/
Quoted 2 lines
git will change our script to:
"echo \"\$1\" \"$@\""Where will "abc" appear then?
Quoted 2 lines
The positional parameters we entered will be printed repeatedly.
Quoted 7 lines
If you take us passing "abc" in $1 as an example, then I think it's a good idea to show us the result of that.
Quoted 1 line
So let add a new
shell_no_implicit_argsMaybe: s/
shell_no_implicit_args/shell_no_implicit_argsflag/
Thanks for these grammar corrections.
Quoted 7 lines
Quoted 5 lines
to
struct child_process, which can suppress the joining of $@ ifshell_no_implicit_argsis set to 1, this will allow us to use only few of positional args in multi-parameter shell script, instead of using all of them.I think our goal is more to have each argument we pass be passed just once.
More accurately, we only want those explicit positional parameters to be replaced.
But Junio probably thinks it's OK to put on a layer of "sh -c" to "absorb" the "$@". I think it works, but it may cause some trouble for users.
--
ZheNing Hu
PATCH v5 2/2 trailer: pass arg as positional parameter
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
--- Documentation/git-interpret-trailers.txt | 75 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 61 ++++++++++++++++++- trailer.c | 39 ++++++++---- 3 files changed, 152 insertions(+), 23 deletions(-)
Documentation/git-interpret-trailers.txt +65 -10
@@ -236,21 +236,34 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command can +only be replaced once and the original way of replacing $ARG was not safe. +Now the preferred option is using "trailer.<token>.cmd", which use position +argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored. + +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. ++ +When this option is specified, If there is no trailer with same <token>, +the behavior is as if a special '<token>=<value>' argument were added at +the beginning of the command, <value> will be passed to the user's +command as an empty value. + If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +these arguments, if any, will be passed to the command as first parameter. EXAMPLES --------
@@ -333,6 +346,48 @@ subject Fix #42 ------------ +* Configure a 'see' trailer with a cmd to show the subject of a + commit that is related, and show how it works: ++ +------------ +$ git config trailer.see.key "See-also: " +$ git config trailer.see.ifExists "replace" +$ git config trailer.see.ifMissing "doNothing" +$ git config trailer.see.cmd "git show -s --pretty=reference \"\$1\"" +$ git interpret-trailers <<EOF +> subject +> +> message +> +> see: HEAD~2 +> EOF +subject + +message + +See-also: fe3187489d69c4 (subject of related commit, 2021-3-20) +------------ + +* Configure a 'bug' trailer with a cmd to show when and where + was the bug introduced, and show how it works: ++ +------------ +$ git config trailer.bug.key "Bug-from: " +$ git config trailer.bug.ifExists "replace" +$ git config trailer.bug.cmd "git log --grep \"\$1\" -1 --pretty=\"%h %aD\"" +$ git interpret-trailers --trailer="bug:the information manager from hell" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Bug-from: 57d84f8d93 Mon, 6 Aug 2012 18:27:09 +0700 +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +60 -1
75 lines not on this page · raw message
trailer.c +27 -12
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,22 +218,28 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { + cp.shell_no_implicit_args =1 ; +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ; - cp.shell_no_implicit_args =1 ;if (capture_command (&cp, &buf,1024 )) {error (_ ("running trailer command '%s' failed" ), cmd.buf);
@@ -248,7 +256,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -258,7 +266,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -431,6 +439,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -455,8 +464,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -464,6 +473,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -543,6 +553,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -709,7 +724,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
Signature · 1 line
gitgitgadget
Re: [PATCH v5 0/2] [GSOC]trailer: pass arg as positional parameter
In reply to ZheNing Hu via GitGitGadgetQuoted 4 lines · ZheNing Hu via GitGitGadget
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG.
It's better to sum up a bit the discussions. It's nice to provide a link to the discussions though.
Quoted 2 lines
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
If this patch series introduces a new trailer.<token>.cmd config option, then I would expect one of the patch in the series to have a subject like "trailer: add new trailer.<token>.cmd config option".
Quoted 3 lines
ZheNing Hu (2):
[GSOC] run-command: addshell_no_implicit_argsoption [GSOC]trailer: pass arg as positional parameter
I guess the "trailer: pass arg as positional parameter" is the one introducing the new trailer.<token>.cmd config option.
Also it seems strange that there is no space between "[GSOC]" and "trailer".
Re: [PATCH v5 0/2] [GSOC]trailer: pass arg as positional parameter
Quoted 18 lines · Christian Couder <[email protected]> 于2021年4月1日周四 下午3:28写道:
Quoted 4 lines · ZheNing Hu via GitGitGadget
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG.It's better to sum up a bit the discussions. It's nice to provide a link to the discussions though.
Quoted 2 lines
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config.
If this patch series introduces a new trailer.<token>.cmd config option, then I would expect one of the patch in the series to have a subject like "trailer: add new trailer.<token>.cmd config option".
Quoted 8 lines
Quoted 3 lines
ZheNing Hu (2):
[GSOC] run-command: addshell_no_implicit_argsoption [GSOC]trailer: pass arg as positional parameterI guess the "trailer: pass arg as positional parameter" is the one introducing the new trailer.<token>.cmd config option.
Also it seems strange that there is no space between "[GSOC]" and "trailer".
Thanks, I'll fix them.
--
ZheNing Hu
PATCH v6 1/1 trailer: add new trailer.<token>.cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
---
[GSOC] trailer: add new trailer..cmd config option
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if user's script have more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v5:
1: 4c59cab53a0d < -: ------------ [GSOC] run-command: add shell_no_implicit_args option
2: 5894d8c4b364 ! 1: 3aed77d077b9 [GSOC]trailer: pass arg as positional parameter
@@ Metadata
Author: ZheNing Hu <[email protected]>
## Commit message ##
- [GSOC]trailer: pass arg as positional parameter
+ [GSOC] trailer: add new trailer.<token>.cmd config option
The `trailer.<token>.command` configuration variable
specifies a command (run via the shell, so it does not have
@@ Documentation/git-interpret-trailers.txt: subject
Fix #42
------------
-+* Configure a 'see' trailer with a cmd to show the subject of a
-+ commit that is related, and show how it works:
++* Configure a 'see' trailer with a cmd use a global script `git-one`
++ to show the subject of a commit that is related, and show how it works:
++
+------------
++$ cat ~/bin/git-one
++#!/bin/sh
++git show -s --pretty=reference "$1"
+$ git config trailer.see.key "See-also: "
+$ git config trailer.see.ifExists "replace"
+$ git config trailer.see.ifMissing "doNothing"
-+$ git config trailer.see.cmd "git show -s --pretty=reference \"\$1\""
++$ git config trailer.see.cmd "~/bin/git-one"
+$ git interpret-trailers <<EOF
+> subject
+>
@@ Documentation/git-interpret-trailers.txt: subject
+
+message
+
-+See-also: fe3187489d69c4 (subject of related commit, 2021-3-20)
++See-also: fe3187e (subject of related commit, 2021-4-2)
+------------
+
-+* Configure a 'bug' trailer with a cmd to show when and where
-+ was the bug introduced, and show how it works:
++* Configure a 'who' trailer with a cmd use a global script `git-who`
++ to find the recent matching "author <mail>" pair in git log and
++ show how it works:
++
+------------
-+$ git config trailer.bug.key "Bug-from: "
-+$ git config trailer.bug.ifExists "replace"
-+$ git config trailer.bug.cmd "git log --grep \"\$1\" -1 --pretty=\"%h %aD\""
-+$ git interpret-trailers --trailer="bug:the information manager from hell" <<EOF
++$ cat ~/bin/git-who
++ #!/bin/sh
++ git log -1 --format="%an <%ae>" --author="$1"
++$ git config trailer.help.key "Helped-by: "
++$ git config trailer.help.ifExists "replace"
++$ git config trailer.help.cmd "~/bin/git-who"
++$ git interpret-trailers --trailer="help:gitster@" <<EOF
+> subject
+>
+> message
@@ Documentation/git-interpret-trailers.txt: subject
+
+message
+
-+Bug-from: 57d84f8d93 Mon, 6 Aug 2012 18:27:09 +0700
++Helped-by: Junio C Hamano <[email protected]>
+------------
+
* Configure a 'see' trailer with a command to show the subject of a
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+test_expect_success 'with cmd' '
+ test_when_finished "git config --unset trailer.bug.key && \
-+ git config --unset trailer.bug.ifExists && \
-+ git config --unset trailer.bug.cmd" &&
++ git config --unset trailer.bug.ifExists && \
++ git config --unset trailer.bug.cmd" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "add" &&
-+ git config trailer.bug.cmd "echo \"\$@\"" &&
-+ cat >>expected2 <<-EOF &&
++ git config trailer.bug.cmd "echo \"maybe is\"" &&
++ cat >expected2 <<-EOF &&
+
-+ Bug-maker:
-+ Bug-maker: jocker
-+ Bug-maker: batman
++ Bug-maker: maybe is
++ Bug-maker: maybe is him
++ Bug-maker: maybe is me
+ EOF
-+ git interpret-trailers --trailer "bug: jocker" --trailer "bug:batman" \
++ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
++ >actual2 &&
++ test_cmp expected2 actual2
++'
++
++test_expect_success 'with cmd and $1' '
++ test_when_finished "git config --unset trailer.bug.key && \
++ git config --unset trailer.bug.ifExists && \
++ git config --unset trailer.bug.cmd" &&
++ git config trailer.bug.key "Bug-maker: " &&
++ git config trailer.bug.ifExists "replace" &&
++ git config trailer.bug.cmd "echo \"\$1\" is" &&
++ cat >expected2 <<-EOF &&
++
++ Bug-maker: me is me
++ EOF
++ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
++ >actual2 &&
++ test_cmp expected2 actual2
++'
++
++test_expect_success 'with cmd and $1 with sh -c' '
++ test_when_finished "git config --unset trailer.bug.key && \
++ git config --unset trailer.bug.ifExists && \
++ git config --unset trailer.bug.cmd" &&
++ git config trailer.bug.key "Bug-maker: " &&
++ git config trailer.bug.ifExists "replace" &&
++ git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" &&
++ cat >expected2 <<-EOF &&
++
++ Bug-maker: who is me
++ EOF
++ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
++ >actual2 &&
++ test_cmp expected2 actual2
++'
++
++test_expect_success 'with cmd and $1 with shell script' '
++ test_when_finished "git config --unset trailer.bug.key && \
++ git config --unset trailer.bug.ifExists && \
++ git config --unset trailer.bug.cmd" &&
++ git config trailer.bug.key "Bug-maker: " &&
++ git config trailer.bug.ifExists "replace" &&
++ git config trailer.bug.cmd "./echoscript" &&
++ cat >expected2 <<-EOF &&
++
++ Bug-maker: who is me
++ EOF
++ cat >echoscript <<-EOF &&
++ #!/bin/sh
++ echo who is "\$1"
++ EOF
++ chmod +x echoscript &&
++ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'
-+test_expect_success 'with cmd and $1' '
-+ test_when_finished "git config --unset trailer.fix.cmd" &&
-+ git config trailer.fix.ifExists "replace" &&
-+ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%s)\" \
-+ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
-+ FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
-+ cat complex_message_body >expected2 &&
-+ sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
-+ Fixes: $FIXED
-+ Acked-by= Z
-+ Reviewed-by:
-+ Signed-off-by: Z
-+ Signed-off-by: A U Thor <[email protected]>
-+ EOF
-+ git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \
-+ <complex_message >actual2 &&
-+ test_cmp expected2 actual2
-+'
-+
+test_expect_success 'cmd takes precedence over command' '
+ test_when_finished "git config --unset trailer.fix.cmd" &&
+ git config trailer.fix.ifExists "replace" &&
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
-
- strvec_push(&cp.args, cmd.buf);
+ if (conf->cmd) {
-+ cp.shell_no_implicit_args = 1;
++ // cp.shell_no_implicit_args = 1;
+ strbuf_addstr(&cmd, conf->cmd);
+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
-- cp.shell_no_implicit_args = 1;
-
- if (capture_command(&cp, &buf, 1024)) {
- error(_("running trailer command '%s' failed"), cmd.buf);
@@ trailer.c: static char *apply_command(const char *command, const char *arg)
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)Documentation/git-interpret-trailers.txt | 82 +++++++++++++++++--- t/t7513-interpret-trailers.sh | 95 +++++++++++++++++++++++- trailer.c | 38 +++++++--- 3 files changed, 193 insertions(+), 22 deletions(-)
Documentation/git-interpret-trailers.txt +72 -10
@@ -236,21 +236,34 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command can +only be replaced once and the original way of replacing $ARG was not safe. +Now the preferred option is using "trailer.<token>.cmd", which use position +argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored. + +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. ++ +When this option is specified, If there is no trailer with same <token>, +the behavior is as if a special '<token>=<value>' argument were added at +the beginning of the command, <value> will be passed to the user's +command as an empty value. + If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +these arguments, if any, will be passed to the command as first parameter. EXAMPLES --------
@@ -333,6 +346,55 @@ subject Fix #42 ------------ +* Configure a 'see' trailer with a cmd use a global script `git-one` + to show the subject of a commit that is related, and show how it works: ++ +------------ +$ cat ~/bin/git-one +#!/bin/sh +git show -s --pretty=reference "$1" +$ git config trailer.see.key "See-also: " +$ git config trailer.see.ifExists "replace" +$ git config trailer.see.ifMissing "doNothing" +$ git config trailer.see.cmd "~/bin/git-one" +$ git interpret-trailers <<EOF +> subject +> +> message +> +> see: HEAD~2 +> EOF +subject + +message + +See-also: fe3187e (subject of related commit, 2021-4-2) +------------ + +* Configure a 'who' trailer with a cmd use a global script `git-who` + to find the recent matching "author <mail>" pair in git log and + show how it works: ++ +------------ +$ cat ~/bin/git-who + #!/bin/sh + git log -1 --format="%an <%ae>" --author="$1" +$ git config trailer.help.key "Helped-by: " +$ git config trailer.help.ifExists "replace" +$ git config trailer.help.cmd "~/bin/git-who" +$ git interpret-trailers --trailer="help:gitster@" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Helped-by: Junio C Hamano <[email protected]> +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +94 -1
109 lines not on this page · raw message
trailer.c +27 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,25 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +// cp.shell_no_implicit_args = 1; +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +strvec_push (&cp.args, cmd.buf); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +256,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +266,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +439,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +464,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +473,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +553,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +724,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 2 lines · ZheNing Hu via GitGitGadget
quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor), it would result in
You inherited a typo from my review comments here. This line should have said
NAME='$ARG' to make it NAME='O'Connor'), it would result in
I will tweak locally while queuing (read: no need to send an update only to fix this line---but please do not forget to change it if you are going to send an update to fix or improve other things).
Quoted 22 lines
Documentation/git-interpret-trailers.txt | 82 +++++++++++++++++--- t/t7513-interpret-trailers.sh | 95 +++++++++++++++++++++++- trailer.c | 38 +++++++--- 3 files changed, 193 insertions(+), 22 deletions(-)Documentation/git-interpret-trailers.txt +3
-5@@ -236,21 +236,34 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. +
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 10 lines
Documentation/git-interpret-trailers.txt +7
-3-If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command can +only be replaced once and the original way of replacing $ARG was not safe. +Now the preferred option is using "trailer.<token>.cmd", which use position +argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored.
Warning about unsafe replacement is a good idea. OK.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 258
Quoted 8 lines
Documentation/git-interpret-trailers.txt +8
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an + existing trailer with the same <token>. The output from the + command is then used as the value for the <token> in the + resulting trailer. ++ +When this option is specified, If there is no trailer with same <token>,
s/If/if/ (downcase).
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 261
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+the behavior is as if a special '<token>=<value>' argument were added at +the beginning of the command, <value> will be passed to the user's +command as an empty value.
Do the two occurrences of the word "command" in the sentence refer to different things? I do not think this is an existing problem inherited from the original, but as we are trying to improve the description, I wonder if we can clarify them a bit.
... as if a '<token>=<value>' argument were added at the beginning of the "git interpret-trailers" command, the command specified by this configuration variable will be called with an empty string as the argument.
is my attempt, but I am not still sure what that "as if" part is trying to say. Does it mean with
[trailer "Foo"] cmd = foo-cmd
and the 'input-file' does not have "Foo: <some existing value>" trailer in it, the command "git interpret-trailers input-file" would behave as if this command was run
$ Foo= git interpret-trailers input-file
(as there is no <value>, I am not sure what <value> is used when <token>=<value> is prefixed to the command)?
Puzzled and confused utterly am I... Help, Christian?
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 265
Quoted 4 lines
Documentation/git-interpret-trailers.txt +0
-0+ If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of
This talks about 'trailer.<token>.command'. Should this be changed to '.cmd'?
Or does everything after "When this option is specified, if there is no trailer with ..." apply to both the old .command and new .cmd? If so, that was not clear at all---we'd need to clarify this part.
Quoted 33 lines
Documentation/git-interpret-trailers.txt +24
-2-these arguments, if any, will be used to replace the `$ARG` string in -the command. +these arguments, if any, will be passed to the command as first parameter. EXAMPLES --------@@ -333,6 +346,55 @@ subject Fix #42 ------------ +* Configure a 'see' trailer with a cmd use a global script `git-one` + to show the subject of a commit that is related, and show how it works: ++ +------------ +$ cat ~/bin/git-one +#!/bin/sh +git show -s --pretty=reference "$1" +$ git config trailer.see.key "See-also: " +$ git config trailer.see.ifExists "replace" +$ git config trailer.see.ifMissing "doNothing" +$ git config trailer.see.cmd "~/bin/git-one" +$ git interpret-trailers <<EOF +> subject +> +> message +> +> see: HEAD~2 +> EOF +subject + +message + +See-also: fe3187e (subject of related commit, 2021-4-2)
Documentation/git-interpret-trailers.txt subject · line 381
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+------------ + +* Configure a 'who' trailer with a cmd use a global script `git-who` + to find the recent matching "author <mail>" pair in git log and + show how it works: ++ +------------ +$ cat ~/bin/git-who + #!/bin/sh + git log -1 --format="%an <%ae>" --author="$1"
Unusual indentation here. But more importantly, I am not sure if having both 'see' and 'help' examples is worth it---they are similar enough that the second one does not teach anything new to those who studied the first one already, aren't they?
Quoted 27 lines
Documentation/git-interpret-trailers.txt +16
-0+$ git config trailer.help.key "Helped-by: " +$ git config trailer.help.ifExists "replace" +$ git config trailer.help.cmd "~/bin/git-who" +$ git interpret-trailers --trailer="help:gitster@" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Helped-by: Junio C Hamano <[email protected]> +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +t/t7513-interpret-trailers.sh +0
-0
t/t7513-interpret-trailers.sh test_expect_success 'setup' ' · line 57
Quoted 7 lines
t/t7513-interpret-trailers.sh +4
-0@@ -51,6 +51,77 @@ test_expect_success 'setup' ' EOF ' +test_expect_success 'with cmd' ' + test_when_finished "git config --unset trailer.bug.key && \ + git config --unset trailer.bug.ifExists && \ + git config --unset trailer.bug.cmd" &&
It is unwise to use && between these three "git config" invocations, I suspect. "git config --unset" exits with non-zero status when you attempt to remove with an non-existent key, but you would remove the .ifExists and .cmd even if .key is not defined. Perhaps
test_when_finished "git config --unset-all trailer.bug.key git config --unset-all trailer.bug.ifExists git config --unset-all trailer.bug.cmd" &&
would be more sensible. Or if we just want to remove everything under the trailer.bug.* section, this might be even better:
test_when_finished "git config --remove-section trailer.bug" &&
as we can add new trailer.bug.* to the system and use them in this test, but removing the entire section would still be a good way to clean after ourselves.
Quoted 9 lines
trailer.c +1
-0+static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 229
Quoted 10 lines
trailer.c +2
-5struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +// cp.shell_no_implicit_args = 1;
Do not add new code that is commented out. Besides we do not use // comment.
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 233
Quoted 4 lines
trailer.c +4
-0+strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg);
Thanks.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 23 lines · Junio C Hamano <[email protected]> 于2021年4月3日周六 上午4:49写道:
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 261
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+the behavior is as if a special '<token>=<value>' argument were added at +the beginning of the command, <value> will be passed to the user's +command as an empty value.Do the two occurrences of the word "command" in the sentence refer to different things? I do not think this is an existing problem inherited from the original, but as we are trying to improve the description, I wonder if we can clarify them a bit.
... as if a '<token>=<value>' argument were added at the beginning of the "git interpret-trailers" command, the command specified by this configuration variable will be called with an empty string as the argument.
is my attempt, but I am not still sure what that "as if" part is trying to say. Does it mean with
[trailer "Foo"] cmd = foo-cmd
and the 'input-file' does not have "Foo: <some existing value>" trailer in it, the command "git interpret-trailers input-file" would behave as if this command was run
Quoted 7 lines
$ Foo= git interpret-trailers input-file(as there is no <value>, I am not sure what <value> is used when <token>=<value> is prefixed to the command)?
Puzzled and confused utterly am I... Help, Christian?
If we don’t want a input-file without any trailers to execute this command,
I’m thinking that we maybe need "trailer.<token>.ifmissing=doNothing"
or something else, otherwise execute this 'alwaysRunCmd' for create a empty trailer like "Signed-off-by" and users can use it to add content.
Quoted 5 lines
Quoted 4 lines
+
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of
Quoted 7 lines
This talks about 'trailer.<token>.command'. Should this be changed to '.cmd'?
Or does everything after "When this option is specified, if there is no trailer with ..." apply to both the old .command and new .cmd? If so, that was not clear at all---we'd need to clarify this part.
Because ".command" will be eliminated, may be only leave those description Information to ".cmd" is better.
Quoted 40 lines
Quoted 40 lines
Documentation/git-interpret-trailers.txt +31
-2-these arguments, if any, will be used to replace the `$ARG` string in -the command. +these arguments, if any, will be passed to the command as first parameter. EXAMPLES --------@@ -333,6 +346,55 @@ subject Fix #42 ------------ +* Configure a 'see' trailer with a cmd use a global script `git-one` + to show the subject of a commit that is related, and show how it works: ++ +------------ +$ cat ~/bin/git-one +#!/bin/sh +git show -s --pretty=reference "$1" +$ git config trailer.see.key "See-also: " +$ git config trailer.see.ifExists "replace" +$ git config trailer.see.ifMissing "doNothing" +$ git config trailer.see.cmd "~/bin/git-one" +$ git interpret-trailers <<EOF +> subject +> +> message +> +> see: HEAD~2 +> EOF +subject + +message + +See-also: fe3187e (subject of related commit, 2021-4-2) +------------ + +* Configure a 'who' trailer with a cmd use a global script `git-who` + to find the recent matching "author <mail>" pair in git log and + show how it works: ++ +------------
Quoted 9 lines
Documentation/git-interpret-trailers.txt subject · line 381
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+$ cat ~/bin/git-who + #!/bin/sh + git log -1 --format="%an <%ae>" --author="$1"Unusual indentation here. But more importantly, I am not sure if having both 'see' and 'help' examples is worth it---they are similar enough that the second one does not teach anything new to those who studied the first one already, aren't they?
Ok, I will think about other examples.
Quoted 44 lines
Quoted 27 lines
Documentation/git-interpret-trailers.txt +16
-0+$ git config trailer.help.key "Helped-by: " +$ git config trailer.help.ifExists "replace" +$ git config trailer.help.cmd "~/bin/git-who" +$ git interpret-trailers --trailer="help:gitster@" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Helped-by: Junio C Hamano <[email protected]> +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +t/t7513-interpret-trailers.sh +0
-0t/t7513-interpret-trailers.sh test_expect_success 'setup' ' · line 57
Quoted 7 lines
t/t7513-interpret-trailers.sh +4
-0@@ -51,6 +51,77 @@ test_expect_success 'setup' ' EOF ' +test_expect_success 'with cmd' ' + test_when_finished "git config --unset trailer.bug.key && \ + git config --unset trailer.bug.ifExists && \ + git config --unset trailer.bug.cmd" &&It is unwise to use && between these three "git config" invocations, I suspect. "git config --unset" exits with non-zero status when you attempt to remove with an non-existent key, but you would remove the .ifExists and .cmd even if .key is not defined. Perhaps
test_when_finished "git config --unset-all trailer.bug.key git config --unset-all trailer.bug.ifExists git config --unset-all trailer.bug.cmd" &&
Quoted 9 lines
would be more sensible. Or if we just want to remove everything under the trailer.bug.* section, this might be even better:
test_when_finished "git config --remove-section trailer.bug" &&as we can add new trailer.bug.* to the system and use them in this test, but removing the entire section would still be a good way to clean after ourselves.
Good idea, This removing is also more efficient.
Quoted 22 lines
Quoted 9 lines
trailer.c +1
-0+static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;trailer.c static int check_if_different(struct trailer_item *in_tok, · line 229
Quoted 10 lines
trailer.c +2
-5struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +// cp.shell_no_implicit_args = 1; Do not add new code that is commented out. Besides we do not use // comment.
Quoted 6 lines
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 233
Quoted 4 lines
trailer.c +4
-0+strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg);Thanks.
Thanks.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 7 lines · ZheNing Hu
Quoted 7 lines
Quoted 3 lines
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of
This talks about 'trailer.<token>.command'. Should this be changed to '.cmd'?
Quoted 7 lines
Quoted 4 lines
Or does everything after "When this option is specified, if there is no trailer with ..." apply to both the old .command and new .cmd? If so, that was not clear at all---we'd need to clarify this part.
Because ".command" will be eliminated, may be only leave those description Information to ".cmd" is better.
Not really.
Until .command goes away, people who want to migrate a config file written in the .command days to .cmd would need to know what rules govern .command variant. Otherwise they would not know what the original they inherited, using .command, wanted to do, and have no way to emulate it with the new .cmd approach. If something is shared between the two, at least you need to mention that it applies to both.
Until .command actually gets removed, that is.
Quoted 7 lines
Quoted 5 lines
Unusual indentation here. But more importantly, I am not sure if having both 'see' and 'help' examples is worth it---they are similar enough that the second one does not teach anything new to those who studied the first one already, aren't they?
Ok, I will think about other examples.
Or just use one, and let somebody else in the future encounter real world example that is different enough to come up with a follow up patch to describe that example.
Quoted 19 lines
Quoted 11 lines
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 229
Quoted 8 lines
trailer.c +2
-1-strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +// cp.shell_no_implicit_args = 1; Do not add new code that is commented out. Besides we do not use // comment.
Quoted 6 lines
trailer.c static int check_if_different(struct trailer_item *in_tok, · line 233
Quoted 4 lines
trailer.c +4
-0+strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg);Thanks.
Thanks.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
In reply to Junio C HamanoQuoted 6 lines · Junio C Hamano
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 253
Quoted 3 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +3
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single parameter, which is the <value> part of an
I prefer "argument" over "parameter". In the next paragraph you use "argument" (in "as if a special '<token>=<value>' argument"), so it would be more consistent and easier to read if "argument" was used here too.
Quoted 1 line
Quoted 1 line
+ existing trailer with the same <token>.
It would be better to say something like "which is the <value> part of a --trailer <token>=<value> on the command line". (Yeah, the existing doc might be bad about this.)
Also it might be better to explicitly say that the command is run once for each --trailer <token>=<value> on the command line with the same <token>.
Quoted 5 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 258
Quoted 5 lines
The output from the
Documentation/git-interpret-trailers.txt +4
-0+ command is then used as the value for the <token> in the + resulting trailer. ++ +When this option is specified, If there is no trailer with same <token>,
As above, it's better to be more explicit and say something like "if there is no --trailer <token>=<value> with the same <token> on the command line". That's because there could already be such trailers in the input file, but those don't trigger the command.
Anyway see below as you might need to change the whole paragraph anyway.
Quoted 5 lines
s/If/if/ (downcase).
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 261
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+the behavior is as if a special '<token>=<value>' argument were added at +the beginning of the command, <value> will be passed to the user's +command as an empty value.
The problem with this is that people could understand that the command will run with an empty argument only if there is no trailer with the same <token>. The current situation though is that the command will run once with an empty argument whether there are --trailer <token>=<value> options with the same <token> passed on the command line or not.
Quoted 11 lines
Do the two occurrences of the word "command" in the sentence refer to different things? I do not think this is an existing problem inherited from the original, but as we are trying to improve the description, I wonder if we can clarify them a bit.
... as if a '<token>=<value>' argument were added at the beginning of the "git interpret-trailers" command, the command specified by this configuration variable will be called with an empty string as the argument.
is my attempt,
It looks better to me.
Quoted 10 lines
but I am not still sure what that "as if" part is
trying to say. Does it mean with[trailer "Foo"] cmd = foo-cmd
and the 'input-file' does not have "Foo: <some existing value>" trailer in it, the command "git interpret-trailers input-file" would behave as if this command was run
$ Foo= git interpret-trailers input-file
I would say it would behave as if:
$ git interpret-trailers --trailer Foo= input-file
Quoted 2 lines
(as there is no <value>, I am not sure what <value> is used when <token>=<value> is prefixed to the command)?
Nothing is done when such things are prefixed to the command.
Quoted 1 line
Puzzled and confused utterly am I... Help, Christian?
I hope the above helps.
Quoted 6 lines
Quoted 3 lines
If some '<token>=<value>' arguments are also passed on the command line, when a 'trailer.<token>.command' is configured, the command will also be executed for each of these arguments. And the <value> part of
This talks about 'trailer.<token>.command'. Should this be changed to '.cmd'?
I think so.
Quoted 3 lines
Or does everything after "When this option is specified, if there is no trailer with ..." apply to both the old .command and new .cmd? If so, that was not clear at all---we'd need to clarify this part.
Yeah, in the doc about ".command" I think we should say that it behaves in a similar way as ".cmd" except for the $ARG vs $1 issue.
Quoted 3 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 266
Quoted 3 lines
Documentation/git-interpret-trailers.txt +1
-2-these arguments, if any, will be used to replace the `$ARG` string in -the command. +these arguments, if any, will be passed to the command as first parameter.
s/as first parameter/as its first argument/
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 20 lines · Christian Couder
Quoted 7 lines · Junio C Hamano
...
... as if a '<token>=<value>' argument were added at the beginning of the "git interpret-trailers" command, the command specified by this configuration variable will be called with an empty string as the argument.is my attempt,
It looks better to me.
Quoted 9 lines
but I am not still sure what that "as if" part is
trying to say. Does it mean with[trailer "Foo"] cmd = foo-cmd
and the 'input-file' does not have "Foo: <some existing value>" trailer in it, the command "git interpret-trailers input-file" would behave as if this command was run
Quoted 5 lines
Quoted 1 line
$ Foo= git interpret-trailers input-fileI would say it would behave as if:
$ git interpret-trailers --trailer Foo= input-file
Hmmm. That means that the descrition in the original is quite misleading, no? If it said
... as if "--trailer" "<token>=<value>" arguments were given to "git interpret-trailers" command near the beginning of its command line
then that may be closer description of the command line you are forming, but as its written (with or without my attempt to clarify above), it was impossible to infer that you are behaving as if another --trailer option (with <token>=<value> as its value) was given.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 23 lines · Junio C Hamano
Quoted 20 lines · Christian Couder
Quoted 7 lines · Junio C Hamano
...
... as if a '<token>=<value>' argument were added at the beginning of the "git interpret-trailers" command, the command specified by this configuration variable will be called with an empty string as the argument.is my attempt,
It looks better to me.
Quoted 9 lines
but I am not still sure what that "as if" part is
trying to say. Does it mean with[trailer "Foo"] cmd = foo-cmd
and the 'input-file' does not have "Foo: <some existing value>" trailer in it, the command "git interpret-trailers input-file" would behave as if this command was run
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
$ Foo= git interpret-trailers input-fileI would say it would behave as if:
$ git interpret-trailers --trailer Foo= input-fileHmmm. That means that the descrition in the original is quite misleading, no?
Yeah, I agree it is misleading and difficult to understand.
Quoted 11 lines
If it said
... as if "--trailer" "<token>=<value>" arguments were given to "git interpret-trailers" command near the beginning of its command line
then that may be closer description of the command line you are forming, but as its written (with or without my attempt to clarify above), it was impossible to infer that you are behaving as if another --trailer option (with <token>=<value> as its value) was given.
I agree.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 20 lines · Christian Couder
Quoted 9 lines · Junio C Hamano
Quoted 3 lines · Christian Couder
I would say it would behave as if:
$ git interpret-trailers --trailer Foo= input-fileHmmm. That means that the descrition in the original is quite misleading, no?
Yeah, I agree it is misleading and difficult to understand.
Quoted 6 lines
If it said
... as if "--trailer" "<token>=<value>" arguments were given to "git interpret-trailers" command near the beginning of its command line
Quoted 7 lines
Quoted 5 lines
then that may be closer description of the command line you are forming, but as its written (with or without my attempt to clarify above), it was impossible to infer that you are behaving as if another --trailer option (with <token>=<value> as its value) was given.
I agree.
By the way it might be better to first have a patch that clarifies the existing documentation of ".command", before the patch that adds ".cmd". This way the first patch that only clarifies the documentation could be backported to maintenance branches of old releases.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Hi, Junio and Christian,
Quoted 29 lines · Christian Couder <[email protected]> 于2021年4月6日周二 上午11:52写道:
Quoted 26 lines · Christian Couder
Quoted 9 lines · Junio C Hamano
Quoted 3 lines · Christian Couder
I would say it would behave as if:
$ git interpret-trailers --trailer Foo= input-fileHmmm. That means that the descrition in the original is quite misleading, no?
Yeah, I agree it is misleading and difficult to understand.
Quoted 11 lines
If it said
... as if "--trailer" "<token>=<value>" arguments were given to "git interpret-trailers" command near the beginning of its command line
then that may be closer description of the command line you are forming, but as its written (with or without my attempt to clarify above), it was impossible to infer that you are behaving as if another --trailer option (with <token>=<value> as its value) was given.
Quoted 6 lines
Quoted 1 line
I agree.
By the way it might be better to first have a patch that clarifies the existing documentation of ".command", before the patch that adds ".cmd". This way the first patch that only clarifies the documentation could be backported to maintenance branches of old releases.
This first patch should explain errors of ".command", and then explain that we will no longer use it, right?
I find in the status update description:
"Seems to break new tests for .command variant in zh/commit-trailer" I have tryed to merge my local branch 1e9a657(trailer-cmd) and 2daae3d(upstream/zh/commit-trailer)
I can't find any tests errors after merging, is there something unexpected happened?
--
ZheNing Hu
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 4 lines · ZheNing Hu
I find in the status update description:
"Seems to break new tests for .command variant in zh/commit-trailer" I have tryed to merge my local branch 1e9a657(trailer-cmd) and 2daae3d(upstream/zh/commit-trailer)
Thanks for noticing---the description is stale. Remember that after I pointed out the breakage, you responded that the conversion for the .command codepath was wrong? What is queued in my tree has a version with fix of that bug, so the comment does not apply.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
In reply to ZheNing HuQuoted 7 lines · ZheNing Hu
Quoted 4 lines
By the way it might be better to first have a patch that clarifies the existing documentation of ".command", before the patch that adds ".cmd". This way the first patch that only clarifies the documentation could be backported to maintenance branches of old releases.
This first patch should explain errors of ".command", and then explain that we will no longer use it, right?
If I am reading what Christian wrote correctly, I think it is not "errors of .command" but to clarify the misleading description (especially around the "as if <token>=<value> were added at the beginning"). As if nothing is planned for its deprecation.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
In reply to Junio C HamanoHi, Junio and Christian,
Quoted 27 lines
Quoted 27 lines
+------------
+$ cat ~/bin/git-oneDocumentation/git-interpret-trailers.txt +25
-0+#!/bin/sh +git show -s --pretty=reference "$1" +$ git config trailer.see.key "See-also: " +$ git config trailer.see.ifExists "replace" +$ git config trailer.see.ifMissing "doNothing" +$ git config trailer.see.cmd "~/bin/git-one" +$ git interpret-trailers <<EOF +> subject +> +> message +> +> see: HEAD~2 +> EOF +subject + +message + +See-also: fe3187e (subject of related commit, 2021-4-2) +------------ + +* Configure a 'who' trailer with a cmd use a global script `git-who` + to find the recent matching "author <mail>" pair in git log and + show how it works: ++ +------------
Quoted 9 lines
Quoted 3 lines
+$ cat ~/bin/git-who
+ #!/bin/sh
+ git log -1 --format="%an <%ae>" --author="$1"Unusual indentation here. But more importantly, I am not sure if having both 'see' and 'help' examples is worth it---they are similar enough that the second one does not teach anything new to those who studied the first one already, aren't they?
This may be an off-topic question:
I wanted to use shortlog -s instead of the document example, But I found a very strange place:
Here we have two shell scripts:
$ cat ~/bin/gcount #!/bin/sh if test "$1" != "" then git log -1 --author="$1" else echo "hello there" fi
cat ~/bin/gcount2
#!/bin/sh
if test "$1" != ""
then
git shortlog -1 --author="$1"
else
echo "hello there"
fi
If I use them in the terminal, there is no problem with them,
$ ~/bin/gcount gitster commit 142430338477d9d1bb25be66267225fb58498d92 (interpret-trailers-command-arg, abc5b) Author: Junio C Hamano <[email protected]> Date: Mon Mar 22 14:00:00 2021 -0700
The second batch
$ ~/bin/gcount2 gitster
Junio C Hamano (1):
The second batchif I use .cmd to run these scripts, the situation is totally different:
$ git config -l | grep trailer trailer.cnt.ifexists=add trailer.cnt.key=Cnt: trailer.cnt.cmd=~/bin/gcount
$ git interpret-trailers --trailer="cnt:gitster" <<EOF EOF
Cnt: hello there
Cnt: commit 142430338477d9d1bb25be66267225fb58498d92
Author: Junio C Hamano <[email protected]>
Date: Mon Mar 22 14:00:00 2021 -0700
The second batch
And if I turn to use gcount2:
$ git config trailer.cnt.cmd "~/bin/gcount2" $ git interpret-trailers --trailer="cnt:gitster" <<EOF EOF
Cnt: hello there
Cnt:
It looks like shortlog does not write to standard output. Note that in short_log.c, log will be output to log->file. Does it make the above behavior different?
Is there a good solution?
Quoted 19 lines
Quoted 19 lines
+$ git config trailer.help.key "Helped-by: "
+$ git config trailer.help.ifExists "replace"
+$ git config trailer.help.cmd "~/bin/git-who" +$ git interpret-trailers --trailer="help:gitster@" <<EOF +> subject
+>
+> message
+>
+> EOFDocumentation/git-interpret-trailers.txt +7
-0+subject + +message + +Helped-by: Junio C Hamano <[email protected]> +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 8 lines · ZheNing Hu
This may be an off-topic question:
I wanted to useshortlog -sinstead of the document example, But I found a very strange place:
Here we have two shell scripts:$ cat ~/bin/gcount #!/bin/sh if test "$1" != ""
It's better to use test -n "$1" instead of test "$1" != "".
Quoted 31 lines
then
git log -1 --author="$1"
else
echo "hello there"
ficat ~/bin/gcount2
#!/bin/sh
if test "$1" != ""
then
git shortlog -1 --author="$1"
else
echo "hello there"
fiIf I use them in the terminal, there is no problem with them,
$ ~/bin/gcount gitster commit 142430338477d9d1bb25be66267225fb58498d92 (interpret-trailers-command-arg, abc5b) Author: Junio C Hamano <[email protected]> Date: Mon Mar 22 14:00:00 2021 -0700The second batch
Signed-off-by Junio C Hamano <[email protected]>$ ~/bin/gcount2 gitster Junio C Hamano (1): The second batch
Quoted 6 lines
if I use .cmd to run these scripts, the situation is totally different:
$ git config -l | grep trailer trailer.cnt.ifexists=add trailer.cnt.key=Cnt: trailer.cnt.cmd=~/bin/gcount
The script/command used in ".cmd" or ".command" should really return a short string with no newline or line feed char in it. Here your script can return multiple lines which could mess things up and be difficult to understand.
Quoted 13 lines
$ git interpret-trailers --trailer="cnt:gitster" <<EOF EOFCnt: hello there
Cnt: commit142430338477d9d1bb25be66267225fb58498d92
Author: Junio C Hamano <[email protected]>
Date: Mon Mar 22 14:00:00 2021 -0700The second batch
Signed-off-by Junio C Hamano <[email protected]>And if I turn to use gcount2:
Quoted 8 lines
$ git config trailer.cnt.cmd "~/bin/gcount2" $ git interpret-trailers --trailer="cnt:gitster" <<EOF EOFCnt: hello there
Cnt:It looks like
shortlogdoes not write to standard output.
In shortlog's doc there is:
"If no revisions are passed on the command line and either standard input is not a terminal or there is no current branch, git shortlog will output a summary of the log read from standard input, without reference to the current repository."
I guess that's what's happening here.
Quoted 3 lines
Note that in
short_log.c, log will be output tolog->file. Does it make the above behavior different?
Is there a good solution?
I would try to pass a revision on the command line.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 52 lines · Christian Couder <[email protected]> 于2021年4月4日周日 下午4:52写道:
Quoted 8 lines · ZheNing Hu
This may be an off-topic question:
I wanted to useshortlog -sinstead of the document example, But I found a very strange place:
Here we have two shell scripts:$ cat ~/bin/gcount #!/bin/sh if test "$1" != ""It's better to use
test -n "$1"instead oftest "$1" != "".Quoted 31 lines
then
git log -1 --author="$1"
else
echo "hello there"
ficat ~/bin/gcount2
#!/bin/sh
if test "$1" != ""
then
git shortlog -1 --author="$1"
else
echo "hello there"
fiIf I use them in the terminal, there is no problem with them,
$ ~/bin/gcount gitster commit 142430338477d9d1bb25be66267225fb58498d92 (interpret-trailers-command-arg, abc5b) Author: Junio C Hamano <[email protected]> Date: Mon Mar 22 14:00:00 2021 -0700The second batch
Signed-off-by Junio C Hamano <[email protected]>$ ~/bin/gcount2 gitster Junio C Hamano (1): The second batchQuoted 6 lines
if I use .cmd to run these scripts, the situation is totally different:
$ git config -l | grep trailer trailer.cnt.ifexists=add trailer.cnt.key=Cnt: trailer.cnt.cmd=~/bin/gcount
Quoted 5 lines
The script/command used in ".cmd" or ".command" should really return a short string with no newline or line feed char in it. Here your script can return multiple lines which could mess things up and be difficult to understand.
Yes, it's just a small test, I want use git shortlog -s --author="$1" to show commit count of one author.
Quoted 22 lines
Quoted 13 lines
$ git interpret-trailers --trailer="cnt:gitster" <<EOF EOFCnt: hello there
Cnt: commit142430338477d9d1bb25be66267225fb58498d92
Author: Junio C Hamano <[email protected]>
Date: Mon Mar 22 14:00:00 2021 -0700The second batch
Signed-off-by Junio C Hamano <[email protected]>And if I turn to use gcount2:
Quoted 8 lines
$ git config trailer.cnt.cmd "~/bin/gcount2" $ git interpret-trailers --trailer="cnt:gitster" <<EOF EOFCnt: hello there
Cnt:It looks like
shortlogdoes not write to standard output.
Quoted 9 lines
In shortlog's doc there is:
"If no revisions are passed on the command line and either standard input is not a terminal or there is no current branch, git shortlog will output a summary of the log read from standard input, without reference to the current repository."
I guess that's what's happening here.
This solved my confusion ;-)
Quoted 5 lines
Quoted 3 lines
Note that in
short_log.c, log will be output tolog->file. Does it make the above behavior different?
Is there a good solution?I would try to pass a revision on the command line.
Thanks, Christian.
--
ZheNing Hu
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
In reply to ZheNing Hu via GitGitGadgetQuoted 10 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to theinterpret-trailercommand for the token. This has two downsides:
...
Quoted 4 lines
Documentation/git-interpret-trailers.txt | 82 +++++++++++++++++--- t/t7513-interpret-trailers.sh | 95 +++++++++++++++++++++++- trailer.c | 38 +++++++--- 3 files changed, 193 insertions(+), 22 deletions(-)
Merging this to anything that has zh/commit-trailer (which extends the tests in t7502) seems to break t7502. Running the test with the "-i -v" option ends like so.
expecting success of 7502.24 'commit --trailer with -c and command':
trailer_commit_base && cat >expected <<-\EOF && hello Signed-off-by: C O Mitter <[email protected]> Signed-off-by: C1 E1 Helped-by: C2 E2 Mentored-by: C4 E4 Reported-by: A U Thor <[email protected]> EOF git -c trailer.report.key="Reported-by: " \ -c trailer.report.ifexists="replace" \ -c trailer.report.command="NAME=\"\$ARG\"; test -n \"\$NAME\" && \ git log --author=\"\$NAME\" -1 --format=\"format:%aN <%aE>\" || true" \ commit --trailer "report = author" --amend && git cat-file commit HEAD >commit.msg && sed -e "1,/^\$/d" commit.msg >actual && test_cmp expected actual
[main 6b1e5e9] hello
Author: A U Thor <[email protected]>
1 file changed, 1 insertion(+) [main 97c7a39] hello Author: A U Thor <[email protected]> Date: Thu Apr 7 15:22:13 2005 -0700 1 file changed, 1 insertion(+)
actual renamed from expected +1 -1
@@ -4,4 +4,4 @@ Signed-off-by: C1 E1 Helped-by: C2 E2 Mentored-by: C4 E4 -Reported-by: A U Thor <[email protected]> +Reported-by:
not ok 24 - commit --trailer with -c and command
#
# trailer_commit_base &&
# cat >expected <<-\EOF &&
# hello
#
# Signed-off-by: C O Mitter <[email protected]>
# Signed-off-by: C1 E1
# Helped-by: C2 E2
# Mentored-by: C4 E4
# Reported-by: A U Thor <[email protected]>
# EOF
# git -c trailer.report.key="Reported-by: " \
# -c trailer.report.ifexists="replace" \
# -c trailer.report.command="NAME=\"\$ARG\"; test -n \"\$NAME\" && \
# git log --author=\"\$NAME\" -1 --format=\"format:%aN <%aE>\" || true" \
# commit --trailer "report = author" --amend &&
# git cat-file commit HEAD >commit.msg &&
# sed -e "1,/^\$/d" commit.msg >actual &&
# test_cmp expected actual
#
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 77 lines · Junio C Hamano <[email protected]> 于2021年4月3日周六 上午7:44写道:
Quoted 10 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to theinterpret-trailercommand for the token. This has two downsides:
...Quoted 4 lines
Documentation/git-interpret-trailers.txt | 82 +++++++++++++++++--- t/t7513-interpret-trailers.sh | 95 +++++++++++++++++++++++- trailer.c | 38 +++++++--- 3 files changed, 193 insertions(+), 22 deletions(-)Merging this to anything that has zh/commit-trailer (which extends the tests in t7502) seems to break t7502. Running the test with the "-i -v" option ends like so.
expecting success of 7502.24 'commit --trailer with -c and command':
trailer_commit_base && cat >expected <<-\EOF && hello Signed-off-by: C O Mitter <[email protected]> Signed-off-by: C1 E1 Helped-by: C2 E2 Mentored-by: C4 E4 Reported-by: A U Thor <[email protected]> EOF git -c trailer.report.key="Reported-by: " \ -c trailer.report.ifexists="replace" \ -c trailer.report.command="NAME=\"\$ARG\"; test -n \"\$NAME\" && \ git log --author=\"\$NAME\" -1 --format=\"format:%aN <%aE>\" || true" \ commit --trailer "report = author" --amend && git cat-file commit HEAD >commit.msg && sed -e "1,/^\$/d" commit.msg >actual && test_cmp expected actual[main 6b1e5e9] hello
Author: A U Thor <[email protected]>1 file changed, 1 insertion(+) [main 97c7a39] hello Author: A U Thor <[email protected]> Date: Thu Apr 7 15:22:13 2005 -0700 1 file changed, 1 insertion(+)actual 2021-04-02 23:43:10.673085111 +0000 renamed from expected 2021-04-02 23:43:10.649082950 +0000 +1
-1@@ -4,4 +4,4 @@ Signed-off-by: C1 E1 Helped-by: C2 E2 Mentored-by: C4 E4 -Reported-by: A U Thor <[email protected]> +Reported-by:not ok 24 - commit --trailer with -c and command
## trailer_commit_base && # cat >expected <<-\EOF && # hello # # Signed-off-by: C O Mitter <[email protected]> # Signed-off-by: C1 E1 # Helped-by: C2 E2 # Mentored-by: C4 E4 # Reported-by: A U Thor <[email protected]> # EOF # git -c trailer.report.key="Reported-by: " \ # -c trailer.report.ifexists="replace" \ # -c trailer.report.command="NAME=\"\$ARG\"; test -n \"\$NAME\" && \ # git log --author=\"\$NAME\" -1 --format=\"format:%aN <%aE>\" || true" \ # commit --trailer "report = author" --amend && # git cat-file commit HEAD >commit.msg && # sed -e "1,/^\$/d" commit.msg >actual && # test_cmp expected actual
Quoted 1 line
#
Little bug, Change it like this will work:
} else if (conf->command) {
strbuf_addstr(&cmd, conf->command);
- strvec_push(&cp.args, cmd.buf);
if (arg)
strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
+ strvec_push(&cp.args, cmd.buf);
}thanks.
--
ZheNing Hu
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Review
Quoted 9 lines · ZheNing Hu
Little bug, Change it like this will work:
} else if (conf->command) { strbuf_addstr(&cmd, conf->command);(quoted diff) +1
-1- strvec_push(&cp.args, cmd.buf); if (arg) strbuf_replace(&cmd, TRAILER_ARG_STRING, arg); + strvec_push(&cp.args, cmd.buf); }
It means the coverage of the test included in this patch was not sufficient, right?
I queued this separately from the "commit --trailer" topic in tonight's pushout, but it may make sense to queue this step immediately on top of the "commit --trailer" patch.
In any case, I suspect we would not hear from Christian right away due to timezone differences, so perhaps let this v6 simmer on the list, and then hopefully update the documentation part with his input.
Thanks.
Re: [PATCH v6] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 13 lines · Junio C Hamano <[email protected]> 于2021年4月3日周六 下午12:31写道:
Review
Quoted 9 lines · ZheNing Hu
Little bug, Change it like this will work:
} else if (conf->command) { strbuf_addstr(&cmd, conf->command);(quoted diff) +1
-1- strvec_push(&cp.args, cmd.buf); if (arg) strbuf_replace(&cmd, TRAILER_ARG_STRING, arg); + strvec_push(&cp.args, cmd.buf); }
Quoted 3 lines
It means the coverage of the test included in this patch was not sufficient, right?
Indeed, I might have to think what tests need to be added to the ".cmd".
Quoted 4 lines
I queued this separately from the "commit --trailer" topic in tonight's pushout, but it may make sense to queue this step immediately on top of the "commit --trailer" patch.
Maybe I can rebase this "trailer .cmd" to "master" which already have include "commit --trailer" later, this will cover "commit --trailer" tests.
Quoted 5 lines
In any case, I suspect we would not hear from Christian right away due to timezone differences, so perhaps let this v6 simmer on the list, and then hopefully update the documentation part with his input.
Yes, it's worth waiting patiently,
Quoted 1 line
Thanks.
Thanks.
PATCH v7 1/1 trailer: add new trailer.<token>.cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will refer to the value as positional argument, $1, in their scripts.
---
[GSOC] trailer: add new trailer..cmd config option
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if user's script have more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
We are now writing documents that are more readable and correct than before.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v7
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v7
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v6:
1: 3aed77d077b9 ! 1: 1e9a6572ac6f [GSOC] trailer: add new trailer.<token>.cmd config option
@@ Commit message
pair), which a user would expect to stay intact, would be
replaced, and worse, if the value had an unmatching single
quote (imagine a name like "O'Connor", substituted into
- NAME='$ARG' to make it NAME='O'Connor), it would result in
+ NAME='$ARG' to make it NAME='O'Connor'), it would result in
a broken command that is not syntactically correct (or
worse).
@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
-off.
+When this option is specified, the first occurrence of substring $ARG is
+replaced with the value given to the `interpret-trailer` command for the
-+same token.
++same token. This option behaves in a similar way as ".cmd", however, it
++passes the value through $ARG.
+
-If the command contains the `$ARG` string, this string will be
-replaced with the <value> part of an existing trailer with the same
@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
+
+trailer.<token>.cmd::
+ The command specified by this configuration variable is run
-+ with a single parameter, which is the <value> part of an
-+ existing trailer with the same <token>. The output from the
-+ command is then used as the value for the <token> in the
-+ resulting trailer.
++ with a single argument, which is the <value> part of a
++ `--trailer <token>=<value>` on the command line. The output
++ from the command is then used as the value for the <token>
++ in the resulting trailer.
++
-+When this option is specified, If there is no trailer with same <token>,
-+the behavior is as if a special '<token>=<value>' argument were added at
-+the beginning of the command, <value> will be passed to the user's
-+command as an empty value.
++When this option is specified, the behavior is as if a '<token>=<value>'
++argument were added at the beginning of the "git interpret-trailers"
++command, the command specified by this configuration variable will be
++called with an empty string as the argument.
+
If some '<token>=<value>' arguments are also passed on the command
- line, when a 'trailer.<token>.command' is configured, the command will
- also be executed for each of these arguments. And the <value> part of
+-line, when a 'trailer.<token>.command' is configured, the command will
+-also be executed for each of these arguments. And the <value> part of
-these arguments, if any, will be used to replace the `$ARG` string in
-the command.
-+these arguments, if any, will be passed to the command as first parameter.
++line, when a 'trailer.<token>.cmd' is configured, the command is run
++once for each `--trailer <token>=<value>` on the command line with the
++same <token>. And the <value> part of these arguments, if any, will be
++passed to the command as its first argument.
EXAMPLES
--------
@@ Documentation/git-interpret-trailers.txt: subject
Fix #42
------------
-+* Configure a 'see' trailer with a cmd use a global script `git-one`
-+ to show the subject of a commit that is related, and show how it works:
++* Configure a 'cnt' trailer with a cmd use a global script `gcount`
++to record commit counts of a specified author and show how it works:
++
+------------
-+$ cat ~/bin/git-one
++$ cat ~/bin/gcount
+#!/bin/sh
-+git show -s --pretty=reference "$1"
-+$ git config trailer.see.key "See-also: "
-+$ git config trailer.see.ifExists "replace"
-+$ git config trailer.see.ifMissing "doNothing"
-+$ git config trailer.see.cmd "~/bin/git-one"
-+$ git interpret-trailers <<EOF
++test -n "$1" && git shortlog -s --author="$1" HEAD || true
++$ git config trailer.cnt.key "Commit-count: "
++$ git config trailer.cnt.ifExists "replace"
++$ git config trailer.cnt.cmd "~/bin/gcount"
++$ git interpret-trailers --trailer="cnt:Junio" <<EOF
+> subject
+>
+> message
+>
-+> see: HEAD~2
+> EOF
+subject
+
+message
+
-+See-also: fe3187e (subject of related commit, 2021-4-2)
++Commit-count: 22484 Junio C Hamano
+------------
+
-+* Configure a 'who' trailer with a cmd use a global script `git-who`
-+ to find the recent matching "author <mail>" pair in git log and
-+ show how it works:
++* Configure a 'ref' trailer with a cmd use a global script `glog-grep`
++ to grep last relevant commit from git log in the git repository
++ and show how it works:
++
+------------
-+$ cat ~/bin/git-who
-+ #!/bin/sh
-+ git log -1 --format="%an <%ae>" --author="$1"
-+$ git config trailer.help.key "Helped-by: "
-+$ git config trailer.help.ifExists "replace"
-+$ git config trailer.help.cmd "~/bin/git-who"
-+$ git interpret-trailers --trailer="help:gitster@" <<EOF
++$ cat ~/bin/glog-grep
++#!/bin/sh
++test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
++$ git config trailer.ref.key "Reference-to: "
++$ git config trailer.ref.ifExists "replace"
++$ git config trailer.ref.cmd "~/bin/glog-grep"
++$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
+> subject
+>
+> message
@@ Documentation/git-interpret-trailers.txt: subject
+
+message
+
-+Helped-by: Junio C Hamano <[email protected]>
++Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
+------------
+
* Configure a 'see' trailer with a command to show the subject of a
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
'
+test_expect_success 'with cmd' '
-+ test_when_finished "git config --unset trailer.bug.key && \
-+ git config --unset trailer.bug.ifExists && \
-+ git config --unset trailer.bug.cmd" &&
++ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "add" &&
+ git config trailer.bug.cmd "echo \"maybe is\"" &&
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+'
+
+test_expect_success 'with cmd and $1' '
-+ test_when_finished "git config --unset trailer.bug.key && \
-+ git config --unset trailer.bug.ifExists && \
-+ git config --unset trailer.bug.cmd" &&
++ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "replace" &&
+ git config trailer.bug.cmd "echo \"\$1\" is" &&
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+'
+
+test_expect_success 'with cmd and $1 with sh -c' '
-+ test_when_finished "git config --unset trailer.bug.key && \
-+ git config --unset trailer.bug.ifExists && \
-+ git config --unset trailer.bug.cmd" &&
++ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "replace" &&
+ git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" &&
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+'
+
+test_expect_success 'with cmd and $1 with shell script' '
-+ test_when_finished "git config --unset trailer.bug.key && \
-+ git config --unset trailer.bug.ifExists && \
-+ git config --unset trailer.bug.cmd" &&
++ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
+ git config trailer.bug.ifExists "replace" &&
+ git config trailer.bug.cmd "./echoscript" &&
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
-
- strvec_push(&cp.args, cmd.buf);
+ if (conf->cmd) {
-+ // cp.shell_no_implicit_args = 1;
+ strbuf_addstr(&cmd, conf->cmd);
+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
+ strvec_push(&cp.args, arg);
+ } else if (conf->command) {
+ strbuf_addstr(&cmd, conf->command);
-+ strvec_push(&cp.args, cmd.buf);
+ if (arg)
+ strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
++ strvec_push(&cp.args, cmd.buf);
+ }
cp.env = local_repo_env;
cp.no_stdin = 1;Documentation/git-interpret-trailers.txt | 86 +++++++++++++++++++---- t/t7513-interpret-trailers.sh | 87 +++++++++++++++++++++++- trailer.c | 37 +++++++--- 3 files changed, 186 insertions(+), 24 deletions(-)
Documentation/git-interpret-trailers.txt +74 -12
@@ -236,21 +236,36 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. This option behaves in a similar way as ".cmd", however, it +passes the value through $ARG. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command can +only be replaced once and the original way of replacing $ARG was not safe. +Now the preferred option is using "trailer.<token>.cmd", which use position +argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored. + +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single argument, which is the <value> part of a + `--trailer <token>=<value>` on the command line. The output + from the command is then used as the value for the <token> + in the resulting trailer. ++ +When this option is specified, the behavior is as if a '<token>=<value>' +argument were added at the beginning of the "git interpret-trailers" +command, the command specified by this configuration variable will be +called with an empty string as the argument. + If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.cmd' is configured, the command is run +once for each `--trailer <token>=<value>` on the command line with the +same <token>. And the <value> part of these arguments, if any, will be +passed to the command as its first argument. EXAMPLES --------
@@ -333,6 +348,53 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +86 -1
101 lines not on this page · raw message
trailer.c +26 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_push (&cp.args, cmd.buf); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Signature · 1 line
gitgitgadget
Re: [PATCH v7] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 15 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to theinterpret-trailercommand for the token. This has two downsides:* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
Quoted 4 lines
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single
s/unmatching/unmatched/
Quoted 4 lines
quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Good explanation of the issues with ".command"!
Quoted 4 lines
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users will
s/a parameter/an argument/
s/the users will/users can/
Quoted 8 lines
refer to the value as positional argument, $1, in their scripts.
Helped-by Junio C Hamano <[email protected]>Helped-by Christian Couder <[email protected]>Signed-off-by ZheNing Hu <[email protected]>---
[GSOC] trailer: add new trailer..cmd config option
Maybe <token> has been removed from "trailer.<token>.cmd" above because it has been interpreted as an HTML or XML tag?
Quoted 5 lines
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG:1. if user's script have more than one $ARG, only the first one will be
s/user's script have/the user's script has/
Quoted 4 lines
replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Yeah, good summary of the issues with ".command"
Quoted 5 lines
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
We are now writing documents that are more readable and correct than before.
Yeah, correcting the doc is a good thing to do. By the way, as I said to Junio, it might be better to make the doc for ".command" more readable and correct in a first patch separate from the patch introducing ".cmd".
If you really want to do both in the same patch you should tell that in the commit message too, not just here after the "---" line.
Quoted 12 lines
Documentation/git-interpret-trailers.txt | 86 +++++++++++++++++++---- t/t7513-interpret-trailers.sh | 87 +++++++++++++++++++++++- trailer.c | 37 +++++++--- 3 files changed, 186 insertions(+), 24 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -236,21 +236,36 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 10 lines
Documentation/git-interpret-trailers.txt +4
-5+ -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. This option behaves in a similar way as ".cmd", however, it +passes the value through $ARG.
Maybe this last sentence could be replaced with "Otherwise this option behaves in the same way as 'trailer.<token>.cmd'."
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 244
Quoted 4 lines
Documentation/git-interpret-trailers.txt +1
-3-If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command can
s/".command"/The 'trailer.<token>.command' option/ s/to the $ARG/to the fact that $ARG/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+only be replaced once and the original way of replacing $ARG was not safe.
s/only be/can only be/
s/and the/and that the/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 246
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+Now the preferred option is using "trailer.<token>.cmd", which use position
s/using//
s/use/uses/
s/position/a positional/
Also please make sure that trailer.<token>.cmd and trailer.<token>.command are always quoted in the same way. I think single quotes are used in the current doc, so please keep using single quotes.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 250
Quoted 4 lines
Documentation/git-interpret-trailers.txt +4
-0+argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored.
Please spell and quote ".cmd" and ".command" consistently, so for example like: 'trailer.<token>.cmd'
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 259
Quoted 8 lines
Documentation/git-interpret-trailers.txt +8
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single argument, which is the <value> part of a + `--trailer <token>=<value>` on the command line. The output + from the command is then used as the value for the <token> + in the resulting trailer. ++ +When this option is specified, the behavior is as if a '<token>=<value>'
s/'<token>=<value>'/--trailer <token>=<value>/ (let's try to be as explicit as possible)
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 260
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+argument were added at the beginning of the "git interpret-trailers"
s/were/was/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 268
Quoted 12 lines
Documentation/git-interpret-trailers.txt +7
-4+command, the command specified by this configuration variable will be +called with an empty string as the argument. + If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.cmd' is configured, the command is run +once for each `--trailer <token>=<value>` on the command line with the +same <token>. And the <value> part of these arguments, if any, will be +passed to the command as its first argument.
Yeah, it's much better than it was, but I think we can do better. I will try to come up with something soon.
Also as I said above and in reply to Junio, I think it might be better to split this in 2 patches.
Quoted 41 lines
Documentation/git-interpret-trailers.txt +35
-0EXAMPLES --------@@ -333,6 +348,53 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
Documentation/git-interpret-trailers.txt subject · line 395
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
The added examples look good!
Quoted 5 lines
Documentation/git-interpret-trailers.txt +5
-0+test_expect_success 'with cmd' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "add" && + git config trailer.bug.cmd "echo \"maybe is\"" &&
Documentation/git-interpret-trailers.txt subject
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ cat >expected2 <<-EOF && + + Bug-maker: maybe is + Bug-maker: maybe is him + Bug-maker: maybe is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'
I guess this shows that the command is called multiple times, the first time with an empty first arg.
Documentation/git-interpret-trailers.txt
Quoted 13 lines
Documentation/git-interpret-trailers.txt +13
-0+test_expect_success 'with cmd and $1' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "echo \"\$1\" is" && + cat >expected2 <<-EOF && + + Bug-maker: me is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'
I guess this shows that the argument is also available as "$1".
Documentation/git-interpret-trailers.txt
Quoted 13 lines
Documentation/git-interpret-trailers.txt +13
-0+test_expect_success 'with cmd and $1 with sh -c' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" && + cat >expected2 <<-EOF && + + Bug-maker: who is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'
Ok, this shows how sh -c ... can be used in ".cmd".
Quoted 8 lines
Documentation/git-interpret-trailers.txt +8
-0+test_expect_success 'with cmd and $1 with shell script' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "./echoscript" && + cat >expected2 <<-EOF && + + Bug-maker: who is me
Documentation/git-interpret-trailers.txt
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ EOF + cat >echoscript <<-EOF && + #!/bin/sh + echo who is "\$1" + EOF + chmod +x echoscript && + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'
Ok.
Quoted 17 lines
test_expect_success'without config' 'sed -e "s/ Z\$/ /" >expected <<-\EOF &&Documentation/git-interpret-trailers.txt +10
-0@@ -1274,9 +1337,31 @@ test_expect_success 'setup a commit' ' git commit -m "Add file a.txt" ' +test_expect_success 'cmd takes precedence over command' ' + test_when_finished "git config --unset trailer.fix.cmd" && + git config trailer.fix.ifExists "replace" && + git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \ + --abbrev-commit --abbrev=14 \"\$1\" || true" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \$ARG" && + FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) && + cat complex_message_body >expected2 && + sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
Documentation/git-interpret-trailers.txt test_expect_success 'setup a commit' ' · line 1359
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ Fixes: $FIXED + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <[email protected]> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual2 && + test_cmp expected2 actual2 +'
Ok.
Documentation/git-interpret-trailers.txt test_expect_success 'setup a commit' ' · line 1363
Quoted 5 lines
Documentation/git-interpret-trailers.txt +2
-1test_expect_success 'with command using $ARG' ' git config trailer.fix.ifExists "replace" && - git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \$ARG" &&
This is just an indent change. I am not sure it's worth doing in this patch. If you think that the file needs better indentation though, then you might do it in a separate preparatory patch at the beginning of the current patch series.
If there is only this place in the file where such an indentation improvement is needed, this might be ok, but please mention in the commit message that while at it you are also doing this small change.
The other parts of the patch look good to me.
Re: [PATCH v7] [GSOC] trailer: add new trailer.<token>.cmd config option
Quoted 23 lines · Christian Couder <[email protected]> 于2021年4月7日周三 上午12:23写道:
Quoted 15 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to theinterpret-trailercommand for the token. This has two downsides:* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
Quoted 4 lines
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatching single
Quoted 9 lines
s/unmatching/unmatched/
Quoted 4 lines
quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Good explanation of the issues with ".command"!
Credit for Junio.
Quoted 11 lines
Quoted 4 lines
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as a parameter to the command. Instead of "$ARG", the users wills/a parameter/an argument/
s/the users will/users can/Quoted 3 lines
refer to the value as positional argument, $1, in their scripts.
Quoted 9 lines
Quoted 5 lines
Helped-by Junio C Hamano <[email protected]>Helped-by Christian Couder <[email protected]>Signed-off-by ZheNing Hu <[email protected]>---
[GSOC] trailer: add new trailer..cmd config optionMaybe <token> has been removed from "trailer.<token>.cmd" above because it has been interpreted as an HTML or XML tag?
Aha, It may well be so.
Maybe change to "[GSOC] trailer add .cmd config option"?
Quoted 21 lines
Quoted 5 lines
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG:1. if user's script have more than one $ARG, only the first one will be
s/user's script have/the user's script has/
Quoted 4 lines
replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.Yeah, good summary of the issues with ".command"
Quoted 5 lines
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
We are now writing documents that are more readable and correct than before.
Quoted 8 lines
Yeah, correcting the doc is a good thing to do. By the way, as I said to Junio, it might be better to make the doc for ".command" more readable and correct in a first patch separate from the patch introducing ".cmd".
If you really want to do both in the same patch you should tell that in the commit message too, not just here after the "---" line.
I actually tried to write it yesterday, but...
(quoted diff) +0 -0
b/Documentation/git-interpret-trailers.txt
index 96ec6499f0..39f742b3dc 100644
Documentation/git-interpret-trailers.txt +11 -11
@@ -237,20 +237,20 @@ trailer.<token>.command:: specified <token>. + When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +'<token>=<value>' argument were added at the beginning of the +"git interpret-trailers" command, where <value> is taken to be the +standard output of the specified command with any leading and +trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +The first occurrence of substring $ARG will be replaced with the +<value> part of an existing trailer with the same <token>, if any, +before the command is launched. + If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.cmd' is configured, the command is run +once for each `--trailer <token>=<value>` on the command line with the +same <token>. And the <value> part of these arguments, if any, will be +used to replace the fist $ARG string in the command.
Since I am based on the document in the second patch, you have also uncovered some points worthy of modification below,
so temporarily what I wrote is not accurate enough.
Quoted 50 lines
Quoted 12 lines
Documentation/git-interpret-trailers.txt | 86 +++++++++++++++++++---- t/t7513-interpret-trailers.sh | 87 +++++++++++++++++++++++- trailer.c | 37 +++++++--- 3 files changed, 186 insertions(+), 24 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -236,21 +236,36 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>.Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 10 lines
Documentation/git-interpret-trailers.txt +4
-5+ -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. This option behaves in a similar way as ".cmd", however, it +passes the value through $ARG.Maybe this last sentence could be replaced with "Otherwise this option behaves in the same way as 'trailer.<token>.cmd'."
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 243
Quoted 4 lines
Documentation/git-interpret-trailers.txt +1
-3-If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +".command" has been deprecated due to the $ARG in the user's command cans/".command"/The 'trailer.<token>.command' option/ s/to the $ARG/to the fact that
$ARG/Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 244
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+only be replaced once and the original way of replacing $ARG was not safe.s/only be/can only be/
s/and the/and that the/Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+Now the preferred option is using "trailer.<token>.cmd", which use positions/using//
s/use/uses/
s/position/a positional/Also please make sure that trailer.<token>.cmd and trailer.<token>.command are always quoted in the same way. I think single quotes are used in the current doc, so please keep using single quotes.
Quoted 8 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 4 lines
Documentation/git-interpret-trailers.txt +4
-0+argument to pass the value. ++ +When both .cmd and .command are given for the same <token>, +.cmd is used and .command is ignored.Please spell and quote ".cmd" and ".command" consistently, so for example like: 'trailer.<token>.cmd'
OK.
Quoted 80 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 257
Quoted 8 lines
Documentation/git-interpret-trailers.txt +8
-0+trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single argument, which is the <value> part of a + `--trailer <token>=<value>` on the command line. The output + from the command is then used as the value for the <token> + in the resulting trailer. ++ +When this option is specified, the behavior is as if a '<token>=<value>'s/'<token>=<value>'/
--trailer <token>=<value>/ (let's try to be as explicit as possible)Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 258
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+argument were added at the beginning of the "git interpret-trailers"s/were/was/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 266
Quoted 12 lines
Documentation/git-interpret-trailers.txt +7
-4+command, the command specified by this configuration variable will be +called with an empty string as the argument. + If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.cmd' is configured, the command is run +once for each `--trailer <token>=<value>` on the command line with the +same <token>. And the <value> part of these arguments, if any, will be +passed to the command as its first argument.Yeah, it's much better than it was, but I think we can do better. I will try to come up with something soon.
Also as I said above and in reply to Junio, I think it might be better to split this in 2 patches.
Quoted 45 lines
Documentation/git-interpret-trailers.txt +39
-0EXAMPLES --------@@ -333,6 +348,53 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +>
Quoted 9 lines
Documentation/git-interpret-trailers.txt subject · line 395
Quoted 6 lines
Documentation/git-interpret-trailers.txt +6
-0+> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)The added examples look good!
Thanks.
Quoted 108 lines
Quoted 5 lines
Documentation/git-interpret-trailers.txt +5
-0+test_expect_success 'with cmd' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "add" && + git config trailer.bug.cmd "echo \"maybe is\"" &&Documentation/git-interpret-trailers.txt subject
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ cat >expected2 <<-EOF && + + Bug-maker: maybe is + Bug-maker: maybe is him + Bug-maker: maybe is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'I guess this shows that the command is called multiple times, the first time with an empty first arg.
Documentation/git-interpret-trailers.txt
Quoted 13 lines
Documentation/git-interpret-trailers.txt +13
-0+test_expect_success 'with cmd and $1' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "echo \"\$1\" is" && + cat >expected2 <<-EOF && + + Bug-maker: me is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'I guess this shows that the argument is also available as "$1".
Documentation/git-interpret-trailers.txt
Quoted 13 lines
Documentation/git-interpret-trailers.txt +13
-0+test_expect_success 'with cmd and $1 with sh -c' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" && + cat >expected2 <<-EOF && + + Bug-maker: who is me + EOF + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'Ok, this shows how
sh -c ...can be used in ".cmd".Quoted 8 lines
Documentation/git-interpret-trailers.txt +8
-0+test_expect_success 'with cmd and $1 with shell script' ' + test_when_finished "git config --remove-section trailer.bug" && + git config trailer.bug.key "Bug-maker: " && + git config trailer.bug.ifExists "replace" && + git config trailer.bug.cmd "./echoscript" && + cat >expected2 <<-EOF && + + Bug-maker: who is meDocumentation/git-interpret-trailers.txt
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ EOF + cat >echoscript <<-EOF && + #!/bin/sh + echo who is "\$1" + EOF + chmod +x echoscript && + git interpret-trailers --trailer "bug: him" --trailer "bug:me" \ + >actual2 && + test_cmp expected2 actual2 +'Ok.
Quoted 17 lines
test_expect_success'without config' 'sed -e "s/ Z\$/ /" >expected <<-\EOF &&Documentation/git-interpret-trailers.txt +10
-0@@ -1274,9 +1337,31 @@ test_expect_success 'setup a commit' ' git commit -m "Add file a.txt" ' +test_expect_success 'cmd takes precedence over command' ' + test_when_finished "git config --unset trailer.fix.cmd" && + git config trailer.fix.ifExists "replace" && + git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \ + --abbrev-commit --abbrev=14 \"\$1\" || true" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \$ARG" && + FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) && + cat complex_message_body >expected2 && + sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&Documentation/git-interpret-trailers.txt test_expect_success 'setup a commit' ' · line 1359
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+ Fixes: $FIXED + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <[email protected]> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual2 && + test_cmp expected2 actual2 +'Ok.
Documentation/git-interpret-trailers.txt test_expect_success 'setup a commit' ' · line 1363
Quoted 5 lines
Documentation/git-interpret-trailers.txt +2
-1test_expect_success 'with command using $ARG' ' git config trailer.fix.ifExists "replace" && - git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \ + --abbrev-commit --abbrev=14 \$ARG" &&
Quoted 9 lines
This is just an indent change. I am not sure it's worth doing in this patch. If you think that the file needs better indentation though, then you might do it in a separate preparatory patch at the beginning of the current patch series.
If there is only this place in the file where such an indentation improvement is needed, this might be ok, but please mention in the commit message that while at it you are also doing this small change.
Well, I may often think that these small changes are irrelevant. Since you said that, I will cancel the modification of this place.
Quoted 1 line
The other parts of the patch look good to me.
Thanks, Christian.
--
ZheNing Hu
v8 cover trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
We are now writing documents that are more readable and correct than before.
ZheNing Hu (2):
[GSOC] docs: correct descript of trailer.<token>.command [GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt | 90 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++ trailer.c | 37 +++++++--- 3 files changed, 187 insertions(+), 24 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v8
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v8
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v7:
-: ------------ > 1: 505903811df8 [GSOC] docs: correct descript of trailer.<token>.command 1: 1e9a6572ac6f ! 2: 3dc8983a4702 [GSOC] trailer: add new trailer.<token>.cmd config option
@@ Metadata
Author: ZheNing Hu <[email protected]>
## Commit message ##
- [GSOC] trailer: add new trailer.<token>.cmd config option
+ [GSOC] trailer: add new .cmd config option
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have
@@ Commit message
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be
- replaced, and worse, if the value had an unmatching single
+ replaced, and worse, if the value had an unmatched single
quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or
@@ Commit message
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove
- trailer.<token>.command, which passes the value as a
- parameter to the command. Instead of "$ARG", the users will
+ trailer.<token>.command, which passes the value as an
+ argument to the command. Instead of "$ARG", users can
refer to the value as positional argument, $1, in their scripts.
@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
specified <token>.
+
-When this option is specified, the behavior is as if a special
--'<token>=<value>' argument were added at the beginning of the command --line, where <value> is taken to be the standard output of the --specified command with any leading and trailing whitespace trimmed --off.
+-'--trailer <token>=<value>' argument was added at the beginning of +-the "git interpret-trailers" command, where <value> is taken to be the +-standard output of the specified command with any leading and trailing +-whitespace trimmed off.
+When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the interpret-trailer command for the
-+same token. This option behaves in a similar way as ".cmd", however, it -+passes the value through $ARG.
- +
--If the command contains the $ARG string, this string will be --replaced with the <value> part of an existing trailer with the same --<token>, if any, before the command is launched.
-+".command" has been deprecated due to the $ARG in the user's command can -+only be replaced once and the original way of replacing $ARG was not safe. -+Now the preferred option is using "trailer.<token>.cmd", which use position -+argument to pass the value.
++same token. It passes the value through $ARG, otherwise this option behaves ++in the same way as 'trailer.<token>.cmd'.
++
-+When both .cmd and .command are given for the same <token>, -+.cmd is used and .command is ignored.
++The 'trailer.<token>.command' option has been deprecated due to the fact ++that $ARG in the user's command can only be replaced once and that the ++original way of replacing $ARG was not safe. Now the preferred option is ++'trailer.<token>.cmd', which uses a positional argument to pass the value.
+ +
+-The first occurrence of substring $ARG will be replaced with the +-<value> part of an existing trailer with the same <token>, if any, +-before the command is launched.
++When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given ++for the same <token>, 'trailer.<token>.cmd' is used and ++'trailer.<token>.command' is ignored.
+
+trailer.<token>.cmd::
+ The command specified by this configuration variable is run
@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
+ from the command is then used as the value for the <token>
+ in the resulting trailer.
++
-+When this option is specified, the behavior is as if a '<token>=<value>' -+argument were added at the beginning of the "git interpret-trailers" -+command, the command specified by this configuration variable will be -+called with an empty string as the argument.
++When this option is specified, the behavior is as if a ++'--trailer <token>=<value>' argument was added at the beginning of ++the "git interpret-trailers" command, the command specified by this ++configuration variable will be called with an empty string as the ++argument.
+
- If some '<token>=<value>' arguments are also passed on the command --line, when a 'trailer.<token>.command' is configured, the command will --also be executed for each of these arguments. And the <value> part of --these arguments, if any, will be used to replace the $ARG string in --the command.
-+line, when a 'trailer.<token>.cmd' is configured, the command is run -+once for each --trailer <token>=<value> on the command line with the -+same <token>. And the <value> part of these arguments, if any, will be -+passed to the command as its first argument.
+-If some '<token>=<value>' arguments are also passed on the command +-line, when a 'trailer.<token>.command' is configured, the command is run +-once for each these arguments with the same <token>. And the <value> +-part of these arguments, if any, will be used to replace the first $ARG +-string in the command.
++If some '--trailer <token>=<value>' arguments are also passed on the ++command line, when a 'trailer.<token>.cmd' is configured, the command ++is run once for each --trailer <token>=<value> on the command line ++with the same <token>. And the <value> part of these arguments, if any, ++will be passed to the command as its first argument.
EXAMPLES
--------
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
+ test_when_finished "git config --unset trailer.fix.cmd" &&
+ git config trailer.fix.ifExists "replace" &&
+ git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
-+ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
++ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
+ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
+ --abbrev-commit --abbrev=14 \$ARG" &&
+ FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup a commit' '
+
test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" &&
-- git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
-+ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
-+ --abbrev-commit --abbrev=14 \$ARG" &&
- FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
- cat complex_message_body >expected &&
- sed -e "s/ Z\$/ /" >>expected <<-EOF &&
+ git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
## trailer.c ##
@@ trailer.c: struct conf_info {
Signature · 1 line
gitgitgadget
PATCH v8 1/2 docs: correct descript of trailer.<token>.command
From: ZheNing Hu <[email protected]>
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
In addition, clarify that $ARG in command can only be replaced once since $ARG is text replacement.
--- Documentation/git-interpret-trailers.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
Documentation/git-interpret-trailers.txt +11 -11
@@ -237,20 +237,20 @@ trailer.<token>.command:: specified <token>. + When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +'--trailer <token>=<value>' argument was added at the beginning of +the "git interpret-trailers" command, where <value> is taken to be the +standard output of the specified command with any leading and trailing +whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +The first occurrence of substring `$ARG` will be replaced with the +<value> part of an existing trailer with the same <token>, if any, +before the command is launched. + If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.command' is configured, the command is run +once for each these arguments with the same <token>. And the <value> +part of these arguments, if any, will be used to replace the first `$ARG` +string in the command. EXAMPLES --------
Signature · 1 line
gitgitgadget
Re: [PATCH v8 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Quoted 9 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
In the original documentation of
trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.In addition, clarify that
$ARGin command can only be replaced once since$ARGis text replacement.
I think you can remove the "since $ARG is text replacement" part. Otherwise this looks fine.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 237
Quoted 11 lines
Signed-off-by ZheNing Hu <[email protected]>--- Documentation/git-interpret-trailers.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -237,20 +237,20 @@ trailer.<token>.command:: specified <token>.
The beginning of the doc for trailer.<token>.command could already be improved. It is:
This option can be used to specify a shell command that will be called to automatically add or modify a trailer with the specified <token>.
Instead we could say for example:
This option can be used to specify a shell command that will be called:
- once to automatically add a trailer with the specified
<token>, and then
- each time a '--trailer <token>=<value>' argument to modify
the <value> of the trailer that this option would produce
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 239
Quoted 1 line
Documentation/git-interpret-trailers.txt +0
-0When this option is specified, the behavior is as if a special
I would rather say:
When the specified command is first called to add a trailer with the specified <token>, the behavior is as if a special
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 7 lines
Documentation/git-interpret-trailers.txt +3
-4-'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +'--trailer <token>=<value>' argument was added at the beginning of +the "git interpret-trailers" command, where <value> is taken to be the +standard output of the specified command with any leading and trailing
Here we can remove "specified" as we now use it at the beginning of the sentence.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 247
Quoted 8 lines
Documentation/git-interpret-trailers.txt +4
-3+whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +The first occurrence of substring `$ARG` will be replaced with the +<value> part of an existing trailer with the same <token>, if any, +before the command is launched.
I think we should not talk about $ARG at this point, let's remove this and see what we can do below in the next paragraph or after it.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 1 line
Documentation/git-interpret-trailers.txt +0
-0If some '<token>=<value>' arguments are also passed on the command
s/'<token>=<value>'/'--trailer <token>=<value>'/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 250
Quoted 5 lines
Documentation/git-interpret-trailers.txt +1
-4-line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.command' is configured, the command is run
s/when a 'trailer.<token>.command' is configured, // s/the command is run/the command is called again/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+once for each these arguments with the same <token>.
s/each these/each of these/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 253
Quoted 3 lines
And the <value>
Documentation/git-interpret-trailers.txt +2
-0+part of these arguments, if any, will be used to replace the first `$ARG` +string in the command.
s/first $ARG string/first occurrence of substring $ARG/
Let's also add something to explain the purpose of this, for example we could add:
"This way the command can produce a <value> computed from the <value> passed in the '--trailer <token>=<value>' argument."
And then let's also explain what happens when the command is called the first time, with for example:
"For consistency, the first occurrence of substring $ARG is also replaced, this time with the empty string, in the command when the command is first called to add a trailer with the specified <token>."
To sum up this would give the following (not properly formatted) description:
-------------------
trailer.<token>.command::
This option can be used to specify a shell command that will be called:
- once to automatically add a trailer with the specified
<token>, and then
- each time a '--trailer <token>=<value>' argument to modify
the <value> of the trailer that this option would produce
When the specified command is first called to add a trailer
with the specified <token>, the behavior is as if a special
'--trailer <token>=<value>' argument was added at the beginning
of the "git interpret-trailers" command, where <value>
is taken to be the standard output of the command with any
leading and trailing whitespace trimmed off.
If some '--trailer <token>=<value>' arguments are also passed
on the command
line, the command is called again once for each of these
arguments with the same <token>.
And the <value> part of these arguments, if any, will be used
to replace the first occurrence
of substring $ARG in the command. This way the command can
produce a <value>
computed from the <value> passed in the '--trailer
<token>=<value>' argument.
For consistency, the first occurrence of substring $ARG is
also replaced, this time with the
empty string, in the command when the command is first called
to add a trailer with the
specified <token>.
-------------------
Thanks!
Re: [PATCH v8 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Quoted 10 lines · Christian Couder <[email protected]> 于2021年4月10日周六 上午3:02写道:
Quoted 7 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
In the original documentation of
trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
Quoted 6 lines
Quoted 2 lines
In addition, clarify that
$ARGin command can only be replaced once since$ARGis text replacement.I think you can remove the "since
$ARGis text replacement" part. Otherwise this looks fine.
Ok.
Quoted 46 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 237
Quoted 11 lines
Signed-off-by ZheNing Hu <[email protected]>--- Documentation/git-interpret-trailers.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -237,20 +237,20 @@ trailer.<token>.command:: specified <token>.The beginning of the doc for trailer.<token>.command could already be improved. It is:
This option can be used to specify a shell command that will be called to automatically add or modify a trailer with the specified <token>.
Instead we could say for example:
This option can be used to specify a shell command that will be called:
- once to automatically add a trailer with the specified
<token>, and then
- each time a '--trailer <token>=<value>' argument to modify
the <value> of the trailer that this option would produceDocumentation/git-interpret-trailers.txt trailer.<token>.command:: · line 239
Quoted 1 line
Documentation/git-interpret-trailers.txt +0
-0When this option is specified, the behavior is as if a specialI would rather say:
When the specified command is first called to add a trailer with the specified <token>, the behavior is as if a special
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 7 lines
Documentation/git-interpret-trailers.txt +3
-4-'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +'--trailer <token>=<value>' argument was added at the beginning of +the "git interpret-trailers" command, where <value> is taken to be the +standard output of the specified command with any leading and trailingHere we can remove "specified" as we now use it at the beginning of the sentence.
Quoted 12 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 247
Quoted 8 lines
Documentation/git-interpret-trailers.txt +4
-3+whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +The first occurrence of substring `$ARG` will be replaced with the +<value> part of an existing trailer with the same <token>, if any, +before the command is launched.I think we should not talk about
$ARGat this point, let's remove this and see what we can do below in the next paragraph or after it.
Here I may want to keep the content similar to the original paragraph. But if you say so, it will be fine.
Quoted 38 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 1 line
Documentation/git-interpret-trailers.txt +0
-0If some '<token>=<value>' arguments are also passed on the commands/'<token>=<value>'/'--trailer <token>=<value>'/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 250
Quoted 5 lines
Documentation/git-interpret-trailers.txt +1
-4-line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +line, when a 'trailer.<token>.command' is configured, the command is runs/when a 'trailer.<token>.command' is configured, // s/the command is run/the command is called again/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 249
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+once for each these arguments with the same <token>.s/each these/each of these/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 253
Quoted 3 lines
And the <value>
Documentation/git-interpret-trailers.txt +2
-0+part of these arguments, if any, will be used to replace the first `$ARG` +string in the command.s/first
$ARGstring/first occurrence of substring$ARG/Let's also add something to explain the purpose of this, for example we could add:
"This way the command can produce a <value> computed from the <value> passed in the '--trailer <token>=<value>' argument."
And then let's also explain what happens when the command is called the first time, with for example:
"For consistency, the first occurrence of substring
$ARGis also replaced, this time with the empty string, in the command when the command is first called to add a trailer with the specified <token>."To sum up this would give the following (not properly formatted) description:
Quoted 8 lines
-------------------
trailer.<token>.command::
This option can be used to specify a shell command that will be called:
- once to automatically add a trailer with the specified
<token>, and then
- each time a '--trailer <token>=<value>' argument to modify
the <value> of the trailer that this option would produce
Maybe I am a little confused: this two "-" meaning? Shouldn't it be the same paragraph?
- This option can be used to specify a shell command that will - be called to automatically add or modify a trailer with the - specified <token>. + This option can be used to specify a shell command that will be called: + - once to automatically add a trailer with the specified
<token>, and then
+ - each time a '--trailer <token>=<value>' argument to modify
the <value> of
+ the trailer that this option would produce.
Wouldn't it be weird?
Quoted 18 lines
When the specified command is first called to add a trailer
with the specified <token>, the behavior is as if a special
'--trailer <token>=<value>' argument was added at the beginning
of the "git interpret-trailers" command, where <value>
is taken to be the standard output of the command with any
leading and trailing whitespace trimmed off.If some '--trailer <token>=<value>' arguments are also passed
on the command
line, the command is called again once for each of these
arguments with the same <token>.
And the <value> part of these arguments, if any, will be used
to replace the first occurrence
of substring$ARGin the command. This way the command can
produce a <value>
computed from the <value> passed in the '--trailer
<token>=<value>' argument.
Quoted 8 lines
For consistency, the first occurrence of substring
$ARGis
also replaced, this time with the
empty string, in the command when the command is first called
to add a trailer with the
specified <token>.
-------------------Thanks!
Thanks a lot!
It looks more professional than what I wrote.
--
ZheNing Hu
PATCH v8 2/2 trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token. This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts.
--- Documentation/git-interpret-trailers.txt | 90 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++ trailer.c | 37 +++++++--- 3 files changed, 187 insertions(+), 24 deletions(-)
Documentation/git-interpret-trailers.txt +77 -13
@@ -236,21 +236,38 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>. + -When this option is specified, the behavior is as if a special -'--trailer <token>=<value>' argument was added at the beginning of -the "git interpret-trailers" command, where <value> is taken to be the -standard output of the specified command with any leading and trailing -whitespace trimmed off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. It passes the value through `$ARG`, otherwise this option behaves +in the same way as 'trailer.<token>.cmd'. ++ +The 'trailer.<token>.command' option has been deprecated due to the fact +that $ARG in the user's command can only be replaced once and that the +original way of replacing $ARG was not safe. Now the preferred option is +'trailer.<token>.cmd', which uses a positional argument to pass the value. + -The first occurrence of substring `$ARG` will be replaced with the -<value> part of an existing trailer with the same <token>, if any, -before the command is launched. +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored. + +trailer.<token>.cmd:: + The command specified by this configuration variable is run + with a single argument, which is the <value> part of a + `--trailer <token>=<value>` on the command line. The output + from the command is then used as the value for the <token> + in the resulting trailer. ++ +When this option is specified, the behavior is as if a +'--trailer <token>=<value>' argument was added at the beginning of +the "git interpret-trailers" command, the command specified by this +configuration variable will be called with an empty string as the +argument. + -If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command is run -once for each these arguments with the same <token>. And the <value> -part of these arguments, if any, will be used to replace the first `$ARG` -string in the command. +If some '--trailer <token>=<value>' arguments are also passed on the +command line, when a 'trailer.<token>.cmd' is configured, the command +is run once for each `--trailer <token>=<value>` on the command line +with the same <token>. And the <value> part of these arguments, if any, +will be passed to the command as its first argument. EXAMPLES --------
@@ -333,6 +350,53 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +84 -0
96 lines not on this page · raw message
trailer.c +26 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_push (&cp.args, cmd.buf); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
Signature · 1 line
gitgitgadget
Re: [PATCH v8 2/2] [GSOC] trailer: add new .cmd config option
Quoted 6 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be a
s/of or/or/
Quoted 3 lines
shell script), and the first occurrence of substring $ARG is replaced with the value given to the
interpret-trailercommand for the token. This has two downsides:
Maybe: s/for the token/for the token in a '--trailer <token>=<value>' argument/
Quoted 14 lines
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Quoted 6 lines
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts.
Good!
Quoted 16 lines
Helped-by Junio C Hamano <[email protected]>Helped-by Christian Couder <[email protected]>Signed-off-by ZheNing Hu <[email protected]>--- Documentation/git-interpret-trailers.txt | 90 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++ trailer.c | 37 +++++++--- 3 files changed, 187 insertions(+), 24 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -236,21 +236,38 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 10 lines
Documentation/git-interpret-trailers.txt +4
-5+ -When this option is specified, the behavior is as if a special -'--trailer <token>=<value>' argument was added at the beginning of -the "git interpret-trailers" command, where <value> is taken to be the -standard output of the specified command with any leading and trailing -whitespace trimmed off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. It passes the value through `$ARG`, otherwise this option behaves +in the same way as 'trailer.<token>.cmd'.
Actually I think that we should say first that this behaves in the same way as the 'trailer.<token>.cmd'.
And this should also replace the first paragraph in the description of 'trailer.<token>.command', not just the second one.
Maybe:
"This option behaves in the same way as 'trailer.<token>.cmd', except that it doesn't pass anything as argument to the specified command. Instead the first occurrence of substring $ARG is replaced by the value that would be passed as argument."
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 244
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+The 'trailer.<token>.command' option has been deprecated due to the fact
s/deprecated/deprecated in favor of 'trailer.<token>.cmd'/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+that $ARG in the user's command can only be replaced once and that the
s/can only be/is only/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+original way of replacing $ARG was not safe.
s/was/is/
Quoted 1 line
Now the preferred option is 'trailer.<token>.cmd', which uses a positional argument to pass the value.
I think we can remove this sentence especially if we say "deprecated in favor of 'trailer.<token>.cmd'" above.
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 251
Quoted 6 lines
Documentation/git-interpret-trailers.txt +3
-3-The first occurrence of substring `$ARG` will be replaced with the -<value> part of an existing trailer with the same <token>, if any, -before the command is launched. +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored.
Ok.
Quoted 1 line
+trailer.<token>.cmd::
I think we should base the description of this option on what I suggest in patch 1/2. So let's agree on patch 1/2 before discussing this.
Re: [PATCH v8 2/2] [GSOC] trailer: add new .cmd config option
Quoted 71 lines · Christian Couder <[email protected]> 于2021年4月10日周六 上午4:19写道:
Quoted 6 lines · ZheNing Hu via GitGitGadget
From: ZheNing Hu <[email protected]>
The
trailer.<token>.commandconfiguration variable specifies a command (run via the shell, so it does not have to be a single name of or path to the command, but can be as/of or/or/
Quoted 3 lines
shell script), and the first occurrence of substring $ARG is replaced with the value given to the
interpret-trailercommand for the token. This has two downsides:Maybe: s/for the token/for the token in a '--trailer <token>=<value>' argument/
Quoted 14 lines
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Quoted 6 lines
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts.Good!
Quoted 16 lines
Helped-by Junio C Hamano <[email protected]>Helped-by Christian Couder <[email protected]>Signed-off-by ZheNing Hu <[email protected]>--- Documentation/git-interpret-trailers.txt | 90 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++ trailer.c | 37 +++++++--- 3 files changed, 187 insertions(+), 24 deletions(-)Documentation/git-interpret-trailers.txt +0
-0@@ -236,21 +236,38 @@ trailer.<token>.command:: be called to automatically add or modify a trailer with the specified <token>.Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 242
Quoted 10 lines
Documentation/git-interpret-trailers.txt +4
-5+ -When this option is specified, the behavior is as if a special -'--trailer <token>=<value>' argument was added at the beginning of -the "git interpret-trailers" command, where <value> is taken to be the -standard output of the specified command with any leading and trailing -whitespace trimmed off. +When this option is specified, the first occurrence of substring $ARG is +replaced with the value given to the `interpret-trailer` command for the +same token. It passes the value through `$ARG`, otherwise this option behaves +in the same way as 'trailer.<token>.cmd'.Actually I think that we should say first that this behaves in the same way as the 'trailer.<token>.cmd'.
Quoted 3 lines
And this should also replace the first paragraph in the description of 'trailer.<token>.command', not just the second one.
Make sence. After all, the primary purpose of this patch is to show that ".command" has been deprecated.
Quoted 15 lines
Maybe:
"This option behaves in the same way as 'trailer.<token>.cmd', except that it doesn't pass anything as argument to the specified command. Instead the first occurrence of substring $ARG is replaced by the value that would be passed as argument."
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 244
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+The 'trailer.<token>.command' option has been deprecated due to the facts/deprecated/deprecated in favor of 'trailer.<token>.cmd'/
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+that $ARG in the user's command can only be replaced once and that thes/can only be/is only/
Quoted 9 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 245
Quoted 1 line
Documentation/git-interpret-trailers.txt +1
-0+original way of replacing $ARG was not safe.s/was/is/
Quoted 1 line
Now the preferred option is 'trailer.<token>.cmd', which uses a positional argument to pass the value.
I think we can remove this sentence especially if we say "deprecated in favor of 'trailer.<token>.cmd'" above.
I agree.
Quoted 9 lines
Documentation/git-interpret-trailers.txt trailer.<token>.command:: · line 251
Quoted 6 lines
Documentation/git-interpret-trailers.txt +3
-3-The first occurrence of substring `$ARG` will be replaced with the -<value> part of an existing trailer with the same <token>, if any, -before the command is launched. +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored.Ok.
Quoted 5 lines
Quoted 1 line
+trailer.<token>.cmd::
I think we should base the description of this option on what I suggest in patch 1/2. So let's agree on patch 1/2 before discussing this.
Yes, The description of the new .cmd is best approximated by the .command in 1/2 .
I should @Junio, I don't know if he has any other opinions.
--
ZheNing Hu
Re: [PATCH v8 0/2] [GSOC] trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetQuoted 7 lines · ZheNing Hu via GitGitGadget
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG:1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
Maybe: s/is incorrected/can be puzzling/
Quoted 1 line
2. $ARG is textually replaced without shell syntax, which may result a
Not sure what "without shell syntax" means here.
Also: s/may result a/may result in a/
Quoted 1 line
broken command when $ARG include some unmatching single quote, very
s/when/if/
s/include/includes/
s/some unmatching/an unmatched/
Quoted 4 lines
unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
I think the important thing here is to explain that we want to introduce a new 'trailer.<token>.cmd' config option, so that we can start deprecating 'trailer.<token>.command' when people have started using the new 'trailer.<token>.cmd' config option. Maybe something like:
"To address these issues, let's introduce a new 'trailer.<token>.cmd' config option that behaves in the same way as 'trailer.<token>.command' except that it passes the trailer value as $1 to the configured command instead of textually replacing the first occurence of '$ARG' in it. This will let us slowly deprecate 'trailer.<token>.command' in favor of 'trailer.<token>.cmd' in the future."
Quoted 1 line
We are now writing documents that are more readable and correct than before.
I would suggest removing this sentence as I don't think it adds much to the above.
Quoted 2 lines
ZheNing Hu (2):
[GSOC] docs: correct descript of trailer.<token>.command
By the way the following title might be a bit better and shorter:
"[GSOC] docs: improve 'trailer.<token>.command' doc"
Quoted 1 line
[GSOC] trailer: add new .cmd config option
Maybe we can afford: s/.cmd/'trailer.<token>.cmd'/
Quoted 2 lines
- [GSOC] trailer: add new trailer.<token>.cmd config option
+ [GSOC] trailer: add new .cmd config option
Was the previous title too long? Or is there an issue with GitGitGadget because it contains <token>?
v9 cover trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above two problems,
We are now writing documents that are more readable and correct than before.
ZheNing Hu (2):
[GSOC] docs: correct descript of trailer.<token>.command [GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt | 96 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 +++++++++++++++++++++ trailer.c | 37 ++++++--- 3 files changed, 190 insertions(+), 27 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v9
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v9
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v8:
1: 505903811df8 ! 1: 8129ef6c476b [GSOC] docs: correct descript of trailer.<token>.command
@@ Commit message
it to increase its readability.
In addition, clarify that $ARG in command can only be
- replaced once since $ARG is text replacement.
+ replaced once.
## Documentation/git-interpret-trailers.txt ##
-@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
- specified <token>.
+@@ Documentation/git-interpret-trailers.txt: trailer.<token>.ifmissing::
+ that option for trailers with the specified <token>.
+
+ trailer.<token>.command::
+- This option can be used to specify a shell command that will
+- be called to automatically add or modify a trailer with the
+- specified <token>.
++ This option can be used to specify a shell command that will be called:
++ once to automatically add a trailer with the specified <token>, and then
++ each time a '--trailer <token>=<value>' argument to modify the <value> of
++ the trailer that this option would produce.
+
- When this option is specified, the behavior is as if a special +-When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off.
-+'--trailer <token>=<value>' argument was added at the beginning of -+the "git interpret-trailers" command, where <value> is taken to be the -+standard output of the specified command with any leading and trailing -+whitespace trimmed off.
++When the specified command is first called to add a trailer ++with the specified <token>, the behavior is as if a special ++'--trailer <token>=<value>' argument was added at the beginning ++of the "git interpret-trailers" command, where <value>
++is taken to be the standard output of the command with any ++leading and trailing whitespace trimmed off.
+
-If the command contains the $ARG string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched.
-+The first occurrence of substring $ARG will be replaced with the -+<value> part of an existing trailer with the same <token>, if any, -+before the command is launched.
++If some '--trailer <token>=<value>' arguments are also passed ++on the command line, the command is called again once for each ++of these arguments with the same <token>. And the <value> part ++of these arguments, if any, will be used to replace the first ++occurrence of substring $ARG in the command. This way the ++command can produce a <value> computed from the <value> passed ++in the '--trailer <token>=<value>' argument.
+
- If some '<token>=<value>' arguments are also passed on the command +-If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the $ARG string in -the command.
-+line, when a 'trailer.<token>.command' is configured, the command is run -+once for each these arguments with the same <token>. And the <value> -+part of these arguments, if any, will be used to replace the first $ARG -+string in the command.
++For consistency, the first occurrence of substring $ARG is ++also replaced, this time with the empty string, in the command ++when the command is first called to add a trailer with the ++specified <token>.
EXAMPLES
--------
2: 3dc8983a4702 ! 2: 7f645ec95f48 [GSOC] trailer: add new .cmd config option
@@ Commit message
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have
- to be a single name of or path to the command, but can be a
+ to be a single name or path to the command, but can be a
shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer
- command for the token. This has two downsides:
+ command for the token in a '--trailer <token>=<value>' argument.
+
+ This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them
@@ Commit message
## Documentation/git-interpret-trailers.txt ##
-@@ Documentation/git-interpret-trailers.txt: trailer.<token>.command::
- be called to automatically add or modify a trailer with the
- specified <token>.
- +
--When this option is specified, the behavior is as if a special --'--trailer <token>=<value>' argument was added at the beginning of
--the "git interpret-trailers" command, where <value> is taken to be the --standard output of the specified command with any leading and trailing --whitespace trimmed off.
-+When this option is specified, the first occurrence of substring $ARG is -+replaced with the value given to the interpret-trailer command for the -+same token. It passes the value through $ARG, otherwise this option behaves -+in the same way as 'trailer.<token>.cmd'.
+@@ Documentation/git-interpret-trailers.txt: trailer.<token>.ifmissing::
+ that option for trailers with the specified <token>.
+
+ trailer.<token>.command::
++ This option behaves in the same way as 'trailer.<token>.cmd', except
++ that it doesn't pass anything as argument to the specified command.
++ Instead the first occurrence of substring $ARG is replaced by the
++ value that would be passed as argument.
+++
++The 'trailer.<token>.command' option has been deprecated in favor of ++'trailer.<token>.cmd' due to the fact that $ARG in the user's command is ++only replaced once and that the original way of replacing $ARG is not safe.
++
-+The 'trailer.<token>.command' option has been deprecated due to the fact -+that $ARG in the user's command can only be replaced once and that the -+original way of replacing $ARG was not safe. Now the preferred option is -+'trailer.<token>.cmd', which uses a positional argument to pass the value.
- +
--The first occurrence of substring $ARG will be replaced with the --<value> part of an existing trailer with the same <token>, if any, --before the command is launched.
+When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored.
+
+trailer.<token>.cmd::
-+ The command specified by this configuration variable is run
-+ with a single argument, which is the <value> part of a
-+ --trailer <token>=<value> on the command line. The output
-+ from the command is then used as the value for the <token>
-+ in the resulting trailer.
-++
-+When this option is specified, the behavior is as if a
-+'--trailer <token>=<value>' argument was added at the beginning of
-+the "git interpret-trailers" command, the command specified by this -+configuration variable will be called with an empty string as the -+argument.
+ This option can be used to specify a shell command that will be called:
+ once to automatically add a trailer with the specified <token>, and then
+ each time a '--trailer <token>=<value>' argument to modify the <value> of
+@@ Documentation/git-interpret-trailers.txt: leading and trailing whitespace trimmed off.
+ If some '--trailer <token>=<value>' arguments are also passed
+ on the command line, the command is called again once for each
+ of these arguments with the same <token>. And the <value> part
+-of these arguments, if any, will be used to replace the first +-occurrence of substring $ARG in the command. This way the
+-command can produce a <value> computed from the <value> passed
+-in the '--trailer <token>=<value>' argument.
++of these arguments, if any, will be passed to the command as its
++first argument. This way the command can produce a <value> computed ++from the <value> passed in the '--trailer <token>=<value>' argument.
+
--If some '<token>=<value>' arguments are also passed on the command --line, when a 'trailer.<token>.command' is configured, the command is run --once for each these arguments with the same <token>. And the <value> --part of these arguments, if any, will be used to replace the first $ARG --string in the command.
-+If some '--trailer <token>=<value>' arguments are also passed on the -+command line, when a 'trailer.<token>.cmd' is configured, the command -+is run once for each --trailer <token>=<value> on the command line -+with the same <token>. And the <value> part of these arguments, if any, -+will be passed to the command as its first argument.
+-For consistency, the first occurrence of substring $ARG is
+-also replaced, this time with the empty string, in the command
+-when the command is first called to add a trailer with the
+-specified <token>.
++For consistency, the $1 is also passed, this time with the empty string, ++in the command when the command is first called to add a trailer with ++the specified <token>.
EXAMPLES
--------
Signature · 1 line
gitgitgadget
PATCH v9 1/2 docs: correct descript of trailer.<token>.command
From: ZheNing Hu <[email protected]>
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
In addition, clarify that $ARG in command can only be replaced once.
--- Documentation/git-interpret-trailers.txt | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-)
Documentation/git-interpret-trailers.txt +21 -16
@@ -232,25 +232,30 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: - This option can be used to specify a shell command that will - be called to automatically add or modify a trailer with the - specified <token>. + This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + -If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>. EXAMPLES --------
Signature · 1 line
gitgitgadget
Re: [PATCH v9 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 245
Quoted 13 lines · ZheNing Hu via GitGitGadget
trailer.<token>.command::
Documentation/git-interpret-trailers.txt +10
-1+ This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off.
So, with
[trailer "foo"] command = "echo $ARG"
in your .git/config
$ git interpret-trailers </dev/null
gives 'foo:'.
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 258
Quoted 12 lines
Documentation/git-interpret-trailers.txt +11
-0+If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>.
And then
$ git interpret-trailers --trailer=foo:F </dev/null
would give you
foo:
foo: F
The above is quite an easy to read explanation of the behaviour.
I somehow wonder if this "run with empty even without anything on the command line" a misfeature, and I'd prefer to iron it out before we add .cmd, because we may not want to inherit it to the new .cmd, just like we avoided '$ARG' that does not properly quote and replaces only once from getting inherited by .cmd mechanism.
The reason why I suspect this may be a misfeature is because I do not see any way to avoid 'foo' trailer once trailer.foo.command is set. Which means I cannot use this mechanism to emulate "commit -s", which would hopefully be something like
[trailer "signoff"] command = "git var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/" ifexists = addIfDifferentNeighbor
And trailer.signoff.ifmissing=donothing would not help in this case, either, I am afraid, as that would not just suppress the automatic empty one, which is fairly useless, but also suppresses the one that is made in response to the option from the command line.
Christian? What's your thought on this?
I can understand that it sometimes may be useful to unconditionally be able to add a trailer without doing anything from the command line, but it feels fairly useless that an empty one is automatically added, that the only way to hide that empty one from the end result is to use ifexists=replace, and that there is no apparent way to remove the empty one.
The --trim-empty option is a bit too crude a band-aid to use, as the existing log message may have an unrelated trailer for which it is perfectly valid not to have any value.
The fix we'd do when introducing .cmd should also get rid of this initial "run with an empty even when not asked"?
Or if the execution without any input from the command line were truly useful sometimes, a configuration variable that disables this behaviour, i.e.
[trailer "signoff"]
command = "git who"
ifexists = addIfDifferentNeighbor
implicitExecution = false
so that
git commit --trailer=signoff:Couder --trailer=signoff:gitster@
would give us two sign-offs without the empty one, perhaps?
In any case, the documentation update in this step looks reasonably well written.
Thanks.
Re: [PATCH v9 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Sorry for the late answer.
Quoted 19 lines · Junio C Hamano
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 245
Quoted 13 lines · ZheNing Hu via GitGitGadget
trailer.<token>.command::
Documentation/git-interpret-trailers.txt +10
-1+ This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off.So, with
Quoted 7 lines
[trailer "foo"] command = "echo $ARG"
in your .git/config
$ git interpret-trailers </dev/nullgives 'foo:'.
Yeah:
------
$ git -c trailer.foo.command='echo $ARG' interpret-trailers </dev/null
foo:
------
Quoted 15 lines
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 258
Quoted 12 lines
Documentation/git-interpret-trailers.txt +11
-0+If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>.And then
Quoted 6 lines
$ git interpret-trailers --trailer=foo:F </dev/nullwould give you
foo:
foo: F
Yeah:
------
git -c trailer.foo.command='echo $ARG' interpret-trailers --trailer=foo:F </dev/null
foo:
foo: F
------
Quoted 7 lines
The above is quite an easy to read explanation of the behaviour.
I somehow wonder if this "run with empty even without anything on the command line" a misfeature, and I'd prefer to iron it out before we add .cmd, because we may not want to inherit it to the new .cmd, just like we avoided '$ARG' that does not properly quote and replaces only once from getting inherited by .cmd mechanism.
I don't think it's a misfeature. I think it can be very useful in some cases like with:
$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
My opinion is that we should have added a trailer.<token>.runMode config option along with trailer.<token>.command. This was not discussed unfortunately when ".command" was implemented, but it seems to be a good idea now.
Quoted 3 lines
The reason why I suspect this may be a misfeature is because I do not see any way to avoid 'foo' trailer once trailer.foo.command is set.
It can be avoided when the --trim-empty CLI option can be used. A hook to remove empty trailers (which might call git interpret-trailers --trim-empty itself) could also be used when --trim-empty cannot be used directly.
Quoted 11 lines
Which means I cannot use this mechanism to emulate "commit -s", which would hopefully be something like
[trailer "signoff"]
command = "git varGIT_COMMITTER_IDENT| sed -e 's/>.*/>/" ifexists = addIfDifferentNeighborAnd trailer.signoff.ifmissing=donothing would not help in this case, either, I am afraid, as that would not just suppress the automatic empty one, which is fairly useless, but also suppresses the one that is made in response to the option from the command line.
I agree that the current mechanism cannot easily emulate "commit -s".
Quoted 9 lines
Christian? What's your thought on this?
I can understand that it sometimes may be useful to unconditionally be able to add a trailer without doing anything from the command line, but it feels fairly useless that an empty one is automatically added, that the only way to hide that empty one from the end result is to use ifexists=replace, and that there is no apparent way to remove the empty one.
Quoted 3 lines
The --trim-empty option is a bit too crude a band-aid to use, as the existing log message may have an unrelated trailer for which it is perfectly valid not to have any value.
I agree that --trim-empty is not usable sometimes. Another idea would be to add 'trailer.<token>.trimEmpty' to be able to do things like:
------
git -c trailer.foo.trimEmpty=true -c trailer.foo.command='echo $ARG' interpret-trailers --trailer=foo:F </dev/null
foo: F
------
It could also be used along with git commit --trailer=foo:F.
Quoted 2 lines
The fix we'd do when introducing .cmd should also get rid of this initial "run with an empty even when not asked"?
I don't think it's a good idea to make ".cmd" behave in a different way as ".command" regarding this. Yes, there could be a short term gain because people could use ".cmd" when they don't want the initial "run with an empty value", but, as some people might still want this initial run, long term it looks like a burden that might:
- make it more difficult to understand how ".cmd" and ".command" both work
- make it more difficult to migrate from ".command" to ".cmd"
- prevent us from deprecating ".command" in favor of ".cmd"
Quoted 9 lines
Or if the execution without any input from the command line were truly useful sometimes, a configuration variable that disables this behaviour, i.e.
[trailer "signoff"]
command = "git who"
ifexists = addIfDifferentNeighbor
implicitExecution = false
Quoted 5 lines
so that
git commit --trailer=signoff:Couder --trailer=signoff:gitster@would give us two sign-offs without the empty one, perhaps?
Yeah, that's basically the same idea that we previously discussed with 'tailer.<token>.runMode' (or 'trailer.<token>.alwaysRunCmd') in:
https://lore.kernel.org/git/CAP8UFD0OMJfkuX_JoDros7h0B20D8sm0ZbtkVpL3dCYRV_M=OA@mail.gmail.com/
Quoted 2 lines
In any case, the documentation update in this step looks reasonably well written.
Thanks!
Re: [PATCH v9 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Quoted 7 lines · Christian Couder
$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'My opinion is that we should have added a
trailer.<token>.runModeconfig option along withtrailer.<token>.command. This was not discussed unfortunately when ".command" was implemented, but it seems to be a good idea now.
Yes, without a knob to diable/enable, the "feature" is pretty much useless.
Quoted 4 lines
It can be avoided when the --trim-empty CLI option can be used. A hook to remove empty trailers (which might call
git interpret-trailers --trim-emptyitself) could also be used when --trim-empty cannot be used directly.
And as you know, --trim-empty that applies to all trailer keys would destroy other trailers and trailer.<token>.trimEmpty, even if it were available, would not work at all to remove it for the case you cited above, to add "user.name <user.email>", which is not an empty string.
Quoted 4 lines
I agree that the current mechanism cannot easily emulate "commit -s".
...
I agree that --trim-empty is not usable sometimes. Another idea would be to add 'trailer.<token>.trimEmpty' to be able to do things like:
"easily"? "sometimes"?
"--trim-empty" is unusable, trailer.<token>.trimEmpty would not work even if it were added because the reason why this is broken is not because it gives an empty value, but because it runs even when it is not asked and there is no way to turn it off.
This shows that even the only plausibly-useful use case we've seen so far is not very well supported, and necessary options/knobs to make it usable have not been invented and implemented.
It is time for us to admit that this is a misfeature that is not well thought out. Recognising that .command is broken is the first step to remedy it with a better alternative in .cmd; otherwise we would inherit the same breakage in the replacement.
The only reasonable way out I would think of is to hide the unconditional execution behind trailer.<token>.runMode, and make the default for runMode to "do not run when --trailer=<token>[:<value>] is not asked from the command line" for .cmd; it is OK for .command not to honor the knob, as we will get rid of it once we see .cmd works well.
Thanks.
PATCH v9 2/2 trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token in a '--trailer <token>=<value>' argument.
This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts.
--- Documentation/git-interpret-trailers.txt | 75 ++++++++++++++++++--- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++++ trailer.c | 37 +++++++---- 3 files changed, 177 insertions(+), 19 deletions(-)
Documentation/git-interpret-trailers.txt +67 -8
@@ -232,6 +232,20 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: + This option behaves in the same way as 'trailer.<token>.cmd', except + that it doesn't pass anything as argument to the specified command. + Instead the first occurrence of substring $ARG is replaced by the + value that would be passed as argument. ++ +The 'trailer.<token>.command' option has been deprecated in favor of +'trailer.<token>.cmd' due to the fact that $ARG in the user's command is +only replaced once and that the original way of replacing $ARG is not safe. ++ +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored. + +trailer.<token>.cmd:: This option can be used to specify a shell command that will be called: once to automatically add a trailer with the specified <token>, and then each time a '--trailer <token>=<value>' argument to modify the <value> of
@@ -247,15 +261,13 @@ leading and trailing whitespace trimmed off. If some '--trailer <token>=<value>' arguments are also passed on the command line, the command is called again once for each of these arguments with the same <token>. And the <value> part -of these arguments, if any, will be used to replace the first -occurrence of substring `$ARG` in the command. This way the -command can produce a <value> computed from the <value> passed -in the '--trailer <token>=<value>' argument. +of these arguments, if any, will be passed to the command as its +first argument. This way the command can produce a <value> computed +from the <value> passed in the '--trailer <token>=<value>' argument. + -For consistency, the first occurrence of substring `$ARG` is -also replaced, this time with the empty string, in the command -when the command is first called to add a trailer with the -specified <token>. +For consistency, the $1 is also passed, this time with the empty string, +in the command when the command is first called to add a trailer with +the specified <token>. EXAMPLES --------
@@ -338,6 +350,53 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +84 -0
96 lines not on this page · raw message
trailer.c +26 -11
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_push (&cp.args, cmd.buf); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
@@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if (item->conf.cmd || item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
Signature · 1 line
gitgitgadget
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt leading and trailing whitespace trimmed off. · line 270
Quoted 3 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +3
-0+For consistency, the $1 is also passed, this time with the empty string, +in the command when the command is first called to add a trailer with +the specified <token>.
I guess the same question as 1/2 applies to this part. I am not sure what "consistency" the behaviour of calling the configured command with no argument is trying to achieve. To me, .cmd doing this may be for consistency with .command but I am not sure why the consistency is even desiable.
Quoted 8 lines
+$ cat ~/bin/gcount
Documentation/git-interpret-trailers.txt +7
-0+#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject
Documentation/git-interpret-trailers.txt subject · line 374
Quoted 10 lines
Documentation/git-interpret-trailers.txt +10
-0+> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +------------
This and the other (omitted) example demonstrates how the initial "empty" invocation is useless by using "replace". Which also means that you cannot add more than one trailer of the same <key> with the mechanism (since the older ones are replaced with the latest).
The code change and the test change are consistent with the design, though.
Thanks.
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 12 lines · Junio C Hamano
Documentation/git-interpret-trailers.txt leading and trailing whitespace trimmed off. · line 270
Quoted 3 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +3
-0+For consistency, the $1 is also passed, this time with the empty string, +in the command when the command is first called to add a trailer with +the specified <token>.I guess the same question as 1/2 applies to this part. I am not sure what "consistency" the behaviour of calling the configured command with no argument is trying to achieve. To me, .cmd doing this may be for consistency with .command but I am not sure why the consistency is even desiable.
It might be desirable to make it easier for people to migrate from ".command" to ".cmd". I agree this is debatable, but I don't see a big downside in it. Maybe, if no argument was passed at all the first time the command is called instead of the empty string, the command could then know that it's called for the first time. I am not sure this would be very helpful in practice though.
Quoted 15 lines
Quoted 15 lines
+$ cat ~/bin/gcount
Documentation/git-interpret-trailers.txt +14
-0+#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +message
Quoted 8 lines
Documentation/git-interpret-trailers.txt subject · line 374
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+ +Commit-count: 22484 Junio C Hamano +------------This and the other (omitted) example demonstrates how the initial "empty" invocation is useless by using "replace". Which also means that you cannot add more than one trailer of the same <key> with the mechanism (since the older ones are replaced with the latest).
You can add more than one trailer with the same key if you don't use "replace" but use "--trim-empty" on the command line, so that an empty trailer added by the initial invocation is removed. And we can later add a trailer.<token>.runMode to remove the initial invocation.
Quoted 2 lines
The code change and the test change are consistent with the design, though.
Yeah, this patch looks good to me now.
Thanks!
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Hi, Christian and Junio,
Quoted 15 lines · Christian Couder <[email protected]> 于2021年4月13日周二 下午3:33写道:
Quoted 12 lines · Junio C Hamano
Documentation/git-interpret-trailers.txt leading and trailing whitespace trimmed off. · line 270
Quoted 3 lines · ZheNing Hu via GitGitGadget
Documentation/git-interpret-trailers.txt +3
-0+For consistency, the $1 is also passed, this time with the empty string, +in the command when the command is first called to add a trailer with +the specified <token>.I guess the same question as 1/2 applies to this part. I am not sure what "consistency" the behaviour of calling the configured command with no argument is trying to achieve. To me, .cmd doing this may be for consistency with .command but I am not sure why the consistency is even desirable.
Quoted 7 lines
It might be desirable to make it easier for people to migrate from ".command" to ".cmd". I agree this is debatable, but I don't see a big downside in it. Maybe, if no argument was passed at all the first time the command is called instead of the empty string, the command could then know that it's called for the first time. I am not sure this would be very helpful in practice though.
If i'm not wrong, Christan meant that this command must run so it's "consistency", and Junio thinks this "consistency" is not needed.
It is true that there is not much harm in keeping .cmd at the behavior of .command now. But I remember the trailer.<token>.runmode that Christan said before, perhaps adding it in the subsequent iterations can solve Junio's doubts. Sometimes I also confirm that the behavior of git interpret-trailers is very strange too.
Quoted 24 lines
Quoted 15 lines
Quoted 15 lines
+$ cat ~/bin/gcount
Documentation/git-interpret-trailers.txt +14
-0+#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "replace" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" <<EOF +> subject +> +> message +> +> EOF +subject + +messageQuoted 8 lines
Documentation/git-interpret-trailers.txt subject · line 374
Quoted 3 lines
Documentation/git-interpret-trailers.txt +3
-0+ +Commit-count: 22484 Junio C Hamano +------------This and the other (omitted) example demonstrates how the initial "empty" invocation is useless by using "replace". Which also means that you cannot add more than one trailer of the same <key> with the mechanism (since the older ones are replaced with the latest).
Quoted 5 lines
You can add more than one trailer with the same key if you don't use "replace" but use "--trim-empty" on the command line, so that an empty trailer added by the initial invocation is removed. And we can later add a
trailer.<token>.runModeto remove the initial invocation.
Yes, something like:
trailer.see.command=echo "$ARG"
git interpret-trailers --trim-empty --trailer="see = lll" --trailer="see:jj"</dev/null
see: lll
see: jj
Quoted 6 lines
Quoted 2 lines
The code change and the test change are consistent with the design, though.
Yeah, this patch looks good to me now.
Thanks!
So is there anything else should I improve?
Thanks.
--
ZheNing Hu
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 10 lines · ZheNing Hu
Quoted 7 lines
It might be desirable to make it easier for people to migrate from ".command" to ".cmd". I agree this is debatable, but I don't see a big downside in it. Maybe, if no argument was passed at all the first time the command is called instead of the empty string, the command could then know that it's called for the first time. I am not sure this would be very helpful in practice though.
If i'm not wrong, Christan meant that this command must run so it's "consistency", and Junio thinks this "consistency" is not needed.
My stance actually is a bit stronger than that. I suspect that running the command without argument once even when no --trailer on the command line asks for that <key> is a misfeature, if not a bug (only because it is now documented by 1/2 as such---before that, at least I did not read the document that way). And unless it is shown that it is not a misfeature but is a useful behaviour with an example use case that benefits from it, I would prefer not to replicate it in the ".cmd".
Quoted 2 lines
It is true that there is not much harm in keeping
.cmdat the behavior of.commandnow.
It is far from "there is not much harm". It misses the whole point of the exercise.
Only replacing the first occurrence and not the second and subsequent occurrence is not what we are keeping in ".cmd".
Replacing in an unsafe way with respect to the command line syntax is not what we are keeping in ".cmd".
That is because these two are misfeatures if not bugs (only because they are documented).
In fact, the only reason why we are introducing .cmd is so that we can deprecate .command and get rid of its misfeatures while keeping only good bits.
So I am waiting to hear why it is not a misfeature. If it is not, then surely I am fine to keep it for now and add a workaround later, but until that happens, I do not think "commit --trailer" can be used as a way to allow end-users emulate "-s" for their favorite trailer like helped-by, acked-by, etc.
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 42 lines · Junio C Hamano <[email protected]> 于2021年4月14日周三 上午3:18写道:
Quoted 10 lines · ZheNing Hu
Quoted 7 lines
It might be desirable to make it easier for people to migrate from ".command" to ".cmd". I agree this is debatable, but I don't see a big downside in it. Maybe, if no argument was passed at all the first time the command is called instead of the empty string, the command could then know that it's called for the first time. I am not sure this would be very helpful in practice though.
If i'm not wrong, Christan meant that this command must run so it's "consistency", and Junio thinks this "consistency" is not needed.
My stance actually is a bit stronger than that. I suspect that running the command without argument once even when no --trailer on the command line asks for that <key> is a misfeature, if not a bug (only because it is now documented by 1/2 as such---before that, at least I did not read the document that way). And unless it is shown that it is not a misfeature but is a useful behaviour with an example use case that benefits from it, I would prefer not to replicate it in the ".cmd".
Quoted 2 lines
It is true that there is not much harm in keeping
.cmdat the behavior of.commandnow.It is far from "there is not much harm". It misses the whole point of the exercise.
Only replacing the first occurrence and not the second and subsequent occurrence is not what we are keeping in ".cmd".
Replacing in an unsafe way with respect to the command line syntax is not what we are keeping in ".cmd".
That is because these two are misfeatures if not bugs (only because they are documented).
In fact, the only reason why we are introducing .cmd is so that we can deprecate .command and get rid of its misfeatures while keeping only good bits.
Quoted 6 lines
So I am waiting to hear why it is not a misfeature. If it is not, then surely I am fine to keep it for now and add a workaround later, but until that happens, I do not think "commit --trailer" can be used as a way to allow end-users emulate "-s" for their favorite trailer like helped-by, acked-by, etc.
If it is really necessary to solve this "empty execution" in .cmd, Maybe we need to consider two points:
* Do we need a new config flag as you said [implicitExecution = false] or just drop it? Has anyone been relying on the "empty execution" of .command before? This may be worthy of concern.
* Do we need trailer.<token>.runMode as Christan said before? I rejected his this suggestion before, and now I regret it a bit.
--
ZheNing Hu
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 7 lines · ZheNing Hu
Quoted 6 lines
So I am waiting to hear why it is not a misfeature. If it is not, then surely I am fine to keep it for now and add a workaround later, but until that happens, I do not think "commit --trailer" can be used as a way to allow end-users emulate "-s" for their favorite trailer like helped-by, acked-by, etc.
Quoted 6 lines
If it is really necessary to solve this "empty execution" in .cmd,
Maybe we need to consider two points:
* Do we need a new config flag as you said[implicitExecution = false]or just drop it? Has anyone been relying on the "empty execution" of .command before? This may be worthy of concern.
Yes, if it is useful sometimes to run the .command or .cmd with empty <value> even when nobody asks for it on the command line with a "--trailer=<key>:<value>" option, then I agree that the users should be able to choose between running and not running [*].
Quoted 2 lines
* Do we need
trailer.<token>.runModeas Christan said before? I rejected his this suggestion before, and now I regret it a bit.
So far, I haven't heard anything that indicates it is a useful behaviour for .command, so my preference is to get rid of the behaviour when we introduce .cmd to deprecate .command; yes, until we get rid of .command, the behaviour between the two would be inconsistent but that is unavoidable when making a bugfix that is backward incompatible.
When (and only when) anybody finds a credible use case, we can add a mechanism to optionally turn it on (e.g. .runMode).
That is my thinking right at this moment, but that's of course subject to change when a use case that would be helped by having this extra execution.
[Footnote]
* Right now, all I know is that not being able to turn it off makes it impossible to use "git commit --trailer" as a more general substitute for "git commit --signoff" without breaking other trailers (e.g. --trim-empty may get rid of the result of the extra execution, but would remove other trailers that can be legitimately empty). And making it on by default with configuration would mean that even though we designed .cmd as a better version of the .command feature with its misdesign corrected, we'd inherit one misdesign from it, which defeats one third of the point of introducing the .cmd in the first place ;-)
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 42 lines · Junio C Hamano <[email protected]> 于2021年4月15日周四 上午4:33写道:
Quoted 7 lines · ZheNing Hu
Quoted 6 lines
So I am waiting to hear why it is not a misfeature. If it is not, then surely I am fine to keep it for now and add a workaround later, but until that happens, I do not think "commit --trailer" can be used as a way to allow end-users emulate "-s" for their favorite trailer like helped-by, acked-by, etc.
Quoted 6 lines
If it is really necessary to solve this "empty execution" in .cmd,
Maybe we need to consider two points:
* Do we need a new config flag as you said[implicitExecution = false]or just drop it? Has anyone been relying on the "empty execution" of .command before? This may be worthy of concern.Yes, if it is useful sometimes to run the .command or .cmd with empty <value> even when nobody asks for it on the command line with a "--trailer=<key>:<value>" option, then I agree that the users should be able to choose between running and not running [*].
Quoted 2 lines
* Do we need
trailer.<token>.runModeas Christan said before? I rejected his this suggestion before, and now I regret it a bit.So far, I haven't heard anything that indicates it is a useful behaviour for .command, so my preference is to get rid of the behaviour when we introduce .cmd to deprecate .command; yes, until we get rid of .command, the behaviour between the two would be inconsistent but that is unavoidable when making a bugfix that is backward incompatible.
When (and only when) anybody finds a credible use case, we can add a mechanism to optionally turn it on (e.g. .runMode).
That is my thinking right at this moment, but that's of course subject to change when a use case that would be helped by having this extra execution.
[Footnote]
Quoted 10 lines
* Right now, all I know is that not being able to turn it off makes it impossible to use "git commit --trailer" as a more general substitute for "git commit --signoff" without breaking other trailers (e.g. --trim-empty may get rid of the result of the extra execution, but would remove other trailers that can be legitimately empty). And making it on by default with configuration would mean that even though we designed .cmd as a better version of the .command feature with its misdesign corrected, we'd inherit one misdesign from it, which defeats one third of the point of introducing the .cmd in the first place ;-)
Perhaps such a modification can meet our temporary needs!
@@ -721,9 +738,10 @@ static void process_command_line_args(struct list_head *arg_head,
char *cl_separators = xstrfmt("=%s", separators);
/* Add an arg item for each configured trailer with a command */
list_for_each(pos, &conf_head) {
item = list_entry(pos, struct arg_item, list);- if (item->conf.cmd || item->conf.command)
+ if (item->conf.command)
I'm so busy today that I probably haven't had time to put this into a patch today,
If this solution is reasonable, I will send a new version of the patch tomorrow. As you said, first solve the misfeature, and we can add [trailer.runMode] later.
Thanks, Junio!
--
ZheNing Hu
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
Quoted 24 lines · ZheNing Hu
Quoted 10 lines · Junio C Hamano <[email protected]> 于2021年4月15日周四 上午4:33写道:
So far, I haven't heard anything that indicates it is a useful behaviour for .command, so my preference is to get rid of the behaviour when we introduce .cmd to deprecate .command; yes, until we get rid of .command, the behaviour between the two would be inconsistent but that is unavoidable when making a bugfix that is backward incompatible.
When (and only when) anybody finds a credible use case, we can add a mechanism to optionally turn it on (e.g. .runMode).
...
Perhaps such a modification can meet our temporary needs!(quoted diff) +1
-1@@ -721,9 +738,10 @@ static void process_command_line_args(struct list_head *arg_head, char *cl_separators = xstrfmt("=%s", separators); /* Add an arg item for each configured trailer with a command */ list_for_each(pos, &conf_head) { item = list_entry(pos, struct arg_item, list); - if (item->conf.cmd || item->conf.command) + if (item->conf.command)
Quoted 4 lines
I'm so busy today that I probably haven't had time to put this into a patch today,
If this solution is reasonable, I will send a new version of the patch tomorrow. As you said, first solve the misfeature, and we can add [trailer.runMode] later.
I am perfectly fine (or rather I'd be happy) to wait for a while to see such a patch, as it would be a good idea to give time to those who do have need for this extra/empty execution to chime in. So, there is no need to rush.
Thanks.
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
In reply to Junio C HamanoQuoted 22 lines · Junio C Hamano
Quoted 7 lines · ZheNing Hu
Quoted 6 lines
So I am waiting to hear why it is not a misfeature. If it is not, then surely I am fine to keep it for now and add a workaround later, but until that happens, I do not think "commit --trailer" can be used as a way to allow end-users emulate "-s" for their favorite trailer like helped-by, acked-by, etc.
Quoted 6 lines
If it is really necessary to solve this "empty execution" in .cmd,
Maybe we need to consider two points:
* Do we need a new config flag as you said[implicitExecution = false]or just drop it? Has anyone been relying on the "empty execution" of .command before? This may be worthy of concern.Yes, if it is useful sometimes to run the .command or .cmd with empty <value> even when nobody asks for it on the command line with a "--trailer=<key>:<value>" option, then I agree that the users should be able to choose between running and not running [*].
Quoted 5 lines
Quoted 2 lines
* Do we need
trailer.<token>.runModeas Christan said before? I rejected his this suggestion before, and now I regret it a bit.So far, I haven't heard anything that indicates it is a useful behaviour for .command,
Well the git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"' has been documented in the EXAMPLES section of the git interpret-trailers doc since when ".command" was implemented, and I believe that reviewers thought that it was a good feature to have then.
Quoted 6 lines
so my preference is to get rid of the
behaviour when we introduce .cmd to deprecate .command; yes, until we get rid of .command, the behaviour between the two would be inconsistent but that is unavoidable when making a bugfix that is backward incompatible.
Quoted 6 lines
When (and only when) anybody finds a credible use case, we can add a mechanism to optionally turn it on (e.g. .runMode).
That is my thinking right at this moment, but that's of course subject to change when a use case that would be helped by having this extra execution.
Such use cases and some of this were discussed when git interpret-trailers was initially implemented.
For example in https://lore.kernel.org/git/CAP8UFD2oXpW9QEkSh+vpNGRAxRFp0zJF39ZZ8sUZLTcKB9mHWQ@mail.gmail.com/
I suggested the following:
[trailer "m-o-b"]
key = "Made-on-branch: "
command = "git name-rev --name-only HEAD"when someone wanted a way to always add "a trailer for the branch that the commit was checked in to at the time"
In https://lore.kernel.org/git/[email protected]/ Michael Haggerty suggested:
"Maybe there should be a trailer.<token>.trimEmpty config option."
I haven't fully checked the discussions, so there might be other examples.
Re: [PATCH v9 2/2] [GSOC] trailer: add new .cmd config option
In reply to Christian CouderQuoted 6 lines · Christian Couder
It might be desirable to make it easier for people to migrate from ".command" to ".cmd". I agree this is debatable, but I don't see a big downside in it. Maybe, if no argument was passed at all the first time the command is called instead of the empty string, the command could then know that it's called for the first time. I am not sure this would be very helpful in practice though.
An integration of the trailer mechanism into the "git commit" command, which cannot emulate "-s" at the end-user level, is something I would call a big failure, though.
Quoted 9 lines
Quoted 4 lines
This and the other (omitted) example demonstrates how the initial "empty" invocation is useless by using "replace". Which also means that you cannot add more than one trailer of the same <key> with the mechanism (since the older ones are replaced with the latest).
You can add more than one trailer with the same key if you don't use "replace" but use "--trim-empty" on the command line, so that an empty trailer added by the initial invocation is removed. And we can later add a
trailer.<token>.runModeto remove the initial invocation.
As I said in the other message (not the one you are responding to), trim-empty is not a viable workaround. Imagine what happens when you want to always add a trailer (unrelated to signed-off-by), for which it is perfectly valid not to have any value. An attempt to work around the problem "extra call without being asked from the command line" behaviour has on our emulated "signed-off-by" example with --trim-empty would nuke such an unrelated trailer.
Besides, if the command produced non-empty value, e.g.
[trailer "baz"] command = "echo B $ARG Z"
the extra call without being asked from the command line will still give "baz: B Z" that is not empty.
So... I am very curious to learn what the intended use case is for this puzzling feature. If it turns out to be that it behaves only because it was coded that way without any real benefit, I would strongly prefer not to carry it over to the new .cmd thing, which is an attempt to deprecate .command to get rid of its broken parts (so far, we identified two---only the first occurrence is replaced, and the replacement can break command line syntax) while salvaging its good parts (being able to programmatically decide the value). And so far what I heard hasn't convinced me that this behaviour falls into the latter category.
Thanks.
v10 cover trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
At the same time, the trailer.<token>.command has another design
disadvantages: It will automatically execute with a empty value in <token> <value> pair, which will create a trailer that we don’t expect.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above problems.
We are now writing documents that are more readable and correct than before.
ZheNing Hu (2):
[GSOC] docs: correct descript of trailer.<token>.command [GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt | 93 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 +++++++++++++++++++++ trailer.c | 35 ++++++--- 3 files changed, 186 insertions(+), 26 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v10
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v10
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v9:
1: 8129ef6c476b = 1: 8129ef6c476b [GSOC] docs: correct descript of trailer.<token>.command 2: 7f645ec95f48 ! 2: daa889bd0ade [GSOC] trailer: add new .cmd config option
@@ Commit message
replaced with the value given to the interpret-trailer command for the token in a '--trailer <token>=<value>' argument.
- This has two downsides:
+ This has three downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them
@@ Commit message
a broken command that is not syntactically correct (or worse).
+ * The first occurrence of substring $ARG will be replaced
+ with the empty string, in the command when the command is
+ first called to add a trailer with the specified <token>.
+ This is a bad design, the nature of automatic execution
+ causes it to add a trailer that we don't expect.
+
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their
- scripts.
+ scripts. At the same time, in order to allow
+ git interpret-trailers to better simulate the behavior
+ of git command -s, 'trailer.<token>.cmd' will not
+ automatically execute.
@@ Documentation/git-interpret-trailers.txt: leading and trailing whitespace trimme
-occurrence of substring $ARG in the command. This way the -command can produce a <value> computed from the <value> passed
-in the '--trailer <token>=<value>' argument.
-+of these arguments, if any, will be passed to the command as its -+first argument. This way the command can produce a <value> computed -+from the <value> passed in the '--trailer <token>=<value>' argument.
- +
+-+
-For consistency, the first occurrence of substring $ARG is
-also replaced, this time with the empty string, in the command -when the command is first called to add a trailer with the -specified <token>.
-+For consistency, the $1 is also passed, this time with the empty string, -+in the command when the command is first called to add a trailer with -+the specified <token>.
++of these arguments, if any, will be passed to the command as its ++first argument. This way the command can produce a <value> computed ++from the <value> passed in the '--trailer <token>=<value>' argument.
EXAMPLES
--------
@@ Documentation/git-interpret-trailers.txt: subject
+#!/bin/sh
+test -n "$1" && git shortlog -s --author="$1" HEAD || true
+$ git config trailer.cnt.key "Commit-count: "
-+$ git config trailer.cnt.ifExists "replace"
++$ git config trailer.cnt.ifExists "addIfDifferentNeighbor"
+$ git config trailer.cnt.cmd "~/bin/gcount"
-+$ git interpret-trailers --trailer="cnt:Junio" <<EOF
++$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF
+> subject
+>
+> message
@@ Documentation/git-interpret-trailers.txt: subject
+message
+
+Commit-count: 22484 Junio C Hamano
++Commit-count: 1117 Linus Torvalds
+------------
+
+* Configure a 'ref' trailer with a cmd use a global script glog-grep
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ git config trailer.bug.cmd "echo \"maybe is\"" &&
+ cat >expected2 <<-EOF &&
+
-+ Bug-maker: maybe is
+ Bug-maker: maybe is him
+ Bug-maker: maybe is me
+ EOF
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+test_expect_success 'with cmd and $1' '
+ test_when_finished "git config --remove-section trailer.bug" &&
+ git config trailer.bug.key "Bug-maker: " &&
-+ git config trailer.bug.ifExists "replace" &&
++ git config trailer.bug.ifExists "add" &&
+ git config trailer.bug.cmd "echo \"\$1\" is" &&
+ cat >expected2 <<-EOF &&
+
++ Bug-maker: him is him
+ Bug-maker: me is me
+ EOF
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
@@ trailer.c: static int git_trailer_config(const char *conf_key, const char *value
case TRAILER_WHERE:
if (trailer_set_where(&conf->where, value))
warning(_("unknown value '%s' for key '%s'"), value, conf_key);
-@@ trailer.c: static void process_command_line_args(struct list_head *arg_head,
- /* Add an arg item for each configured trailer with a command */
- list_for_each(pos, &conf_head) {
- item = list_entry(pos, struct arg_item, list);
-- if (item->conf.command)
-+ if (item->conf.cmd || item->conf.command)
- add_arg_item(arg_head,
- xstrdup(token_from_item(item, NULL)),
- xstrdup(""),
Signature · 1 line
gitgitgadget
PATCH v10 1/2 docs: correct descript of trailer.<token>.command
From: ZheNing Hu <[email protected]>
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
In addition, clarify that $ARG in command can only be replaced once.
--- Documentation/git-interpret-trailers.txt | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-)
Documentation/git-interpret-trailers.txt +21 -16
@@ -232,25 +232,30 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: - This option can be used to specify a shell command that will - be called to automatically add or modify a trailer with the - specified <token>. + This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + -If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>. EXAMPLES --------
Signature · 1 line
gitgitgadget
Re: [PATCH v10 1/2] [GSOC] docs: correct descript of trailer.<token>.command
Quoted 1 line · ZheNing Hu via GitGitGadget
Subject: Re: [PATCH v10 1/2] [GSOC] docs: correct descript of trailer.<token>.command
s/descript/&ion/ (no need to resend only to fix this).
Quoted 18 lines
Documentation/git-interpret-trailers.txt +9
-0@@ -232,25 +232,30 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: + This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 254
Quoted 10 lines
Documentation/git-interpret-trailers.txt +8
-0+leading and trailing whitespace trimmed off. + +If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. +
Makes quite a lot of sense. I wouldn't have got confused by the behaviour of .command if it were documented like the above from day one. Very nice.
Documentation/git-interpret-trailers.txt trailer.<token>.ifmissing:: · line 258
Quoted 4 lines
Documentation/git-interpret-trailers.txt +4
-0+For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>.
OK, so "for consistency" is about consistency between the "execute once first without being asked" case (where there is no plausible source of $ARG), and "execute because we were asked by a command line option (where we are given <value> to replace $ARG).
Makes sense.
Will queue. Thanks.
PATCH v10 2/2 trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token in a '--trailer <token>=<value>' argument.
This has three downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
* The first occurrence of substring $ARG will be replaced with the empty string, in the command when the command is first called to add a trailer with the specified <token>. This is a bad design, the nature of automatic execution causes it to add a trailer that we don't expect.
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts. At the same time, in order to allowgit interpret-trailers to better simulate the behavior of git command -s, 'trailer.<token>.cmd' will not automatically execute.
--- Documentation/git-interpret-trailers.txt | 74 ++++++++++++++++++--- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++++ trailer.c | 35 +++++++--- 3 files changed, 174 insertions(+), 19 deletions(-)
Documentation/git-interpret-trailers.txt +65 -9
@@ -232,6 +232,20 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: + This option behaves in the same way as 'trailer.<token>.cmd', except + that it doesn't pass anything as argument to the specified command. + Instead the first occurrence of substring $ARG is replaced by the + value that would be passed as argument. ++ +The 'trailer.<token>.command' option has been deprecated in favor of +'trailer.<token>.cmd' due to the fact that $ARG in the user's command is +only replaced once and that the original way of replacing $ARG is not safe. ++ +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored. + +trailer.<token>.cmd:: This option can be used to specify a shell command that will be called: once to automatically add a trailer with the specified <token>, and then each time a '--trailer <token>=<value>' argument to modify the <value> of
@@ -247,15 +261,9 @@ leading and trailing whitespace trimmed off. If some '--trailer <token>=<value>' arguments are also passed on the command line, the command is called again once for each of these arguments with the same <token>. And the <value> part -of these arguments, if any, will be used to replace the first -occurrence of substring `$ARG` in the command. This way the -command can produce a <value> computed from the <value> passed -in the '--trailer <token>=<value>' argument. -+ -For consistency, the first occurrence of substring `$ARG` is -also replaced, this time with the empty string, in the command -when the command is first called to add a trailer with the -specified <token>. +of these arguments, if any, will be passed to the command as its +first argument. This way the command can produce a <value> computed +from the <value> passed in the '--trailer <token>=<value>' argument. EXAMPLES --------
@@ -338,6 +346,54 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +test -n "$1" && git shortlog -s --author="$1" HEAD || true +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "addIfDifferentNeighbor" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +Commit-count: 1117 Linus Torvalds +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +84 -0
96 lines not on this page · raw message
trailer.c +25 -10
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_push (&cp.args, cmd.buf); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
Signature · 1 line
gitgitgadget
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Hmph, I am getting the following while applying.
.git/rebase-apply/patch:67: trailing whitespace.
Quoted 1 line
.git/rebase-apply/patch:69: trailing whitespace.
Quoted 1 line
.git/rebase-apply/patch:92: trailing whitespace.
Quoted 1 line
.git/rebase-apply/patch:94: trailing whitespace.
Quoted 1 line
warning: 4 lines applied after fixing whitespace errors.
Applying: trailer: add new .cmd config option
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetQuoted 9 lines · ZheNing Hu via GitGitGadget
Introduce a new
trailer.<token>.cmdconfiguration that takes higher precedence to deprecate and eventually removetrailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts. At the same time, in order to allowgit interpret-trailersto better simulate the behavior ofgit command -s, 'trailer.<token>.cmd' will not automatically execute.
OK. I think there still will be disagreement on this last point between Christian and I, but I'd be happy with this as the first cut for newly introduced .cmd and then when it becomes needed add something like the attached patch on top to optionally run the given command when configured.
trailer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
trailer.c +2 -1
@@ -723,7 +723,8 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if ((item->conf.run_implicitly && item->conf.cmd) || + item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Quoted 15 lines · Junio C Hamano
OK. I think there still will be disagreement on this last point between Christian and I, but I'd be happy with this as the first cut for newly introduced .cmd and then when it becomes needed add something like the attached patch on top to optionally run the given command when configured.
trailer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)trailer.c +0
-0
trailer.c static void process_command_line_args(struct list_head *arg_head, · line 730
Quoted 9 lines
trailer.c +2
-1@@ -723,7 +723,8 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if ((item->conf.run_implicitly && item->conf.cmd) || + item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),
Actually, if we were to do this, I actually suspect that, unlike the textual replacement of $ARG in the old .command configuration, we should take advantage of the fact that the command can tell the cases between an empty string given as $1 and no positional argument was given for $1. So what add_arg_item() does here for .command (which has to give an empty string, because it will textually replace an occurrence of $ARG) and for .cmd may have to be different. Perhaps record NULL here, so that when the command line is formed, we can tell that we do not want add an extra "" that becomes $1, when we are dealing with .cmd in this codepath.
Thanks.
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Quoted 29 lines · Junio C Hamano
Quoted 15 lines · Junio C Hamano
OK. I think there still will be disagreement on this last point between Christian and I, but I'd be happy with this as the first cut for newly introduced .cmd and then when it becomes needed add something like the attached patch on top to optionally run the given command when configured.
trailer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)trailer.c +0
-0trailer.c static void process_command_line_args(struct list_head *arg_head, · line 730
Quoted 9 lines
trailer.c +2
-1@@ -723,7 +723,8 @@ static void process_command_line_args(struct list_head *arg_head,/* Add an arg item for each configured trailer with a command */ list_for_each (pos, &conf_head) { item = list_entry(pos, struct arg_item, list); -if (item->conf.command) +if ((item->conf.run_implicitly && item->conf.cmd) || + item->conf.command) add_arg_item(arg_head, xstrdup(token_from_item(item, NULL)), xstrdup(""),Actually, if we were to do this, I actually suspect that, unlike the textual replacement of $ARG in the old .command configuration, we
Quoted 8 lines
should take advantage of the fact that the command can tell the cases between an empty string given as $1 and no positional argument was given for $1. So what
add_arg_item()does here for .command (which has to give an empty string, because it will textually replace an occurrence of $ARG) and for .cmd may have to be different. Perhaps record NULL here, so that when the command line is formed, we can tell that we do not want add an extra "" that becomes $1, when we are dealing with .cmd in this codepath.
And continuing this line of thought, I think it would be a perfectly fine extension to allow the script/program that is launched by the .command or .cmd mechanism to signal interpret-trailers that it does not want it to add a trailer as the result of this invocation by exiting with non-zero. And that would be a reasonable way forward without having to add yet another ugly workaround .runMode.
For example, trailer.signoff.cmd could be this script:
#!/bin/sh if test $# != 1 then exit 1 else git log -1 --author="$1" --format='"%aN" <$aE>' fi
where the "implicit" invocation is signalled by not passing any argument, to which the script reacts by exiting with 1, and the interpret-trailers would discard the result of the unasked-for invocation.
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Quoted 17 lines · Junio C Hamano
And continuing this line of thought, I think it would be a perfectly fine extension to allow the script/program that is launched by the .command or .cmd mechanism to signal interpret-trailers that it does not want it to add a trailer as the result of this invocation by exiting with non-zero. And that would be a reasonable way forward without having to add yet another ugly workaround .runMode.
For example, trailer.signoff.cmd could be this script:
#!/bin/sh if test $# != 1 then exit 1 else git log -1 --author="$1" --format='"%aN" <$aE>' fi
Quoted 4 lines
where the "implicit" invocation is signalled by not passing any argument, to which the script reacts by exiting with 1, and the interpret-trailers would discard the result of the unasked-for invocation.
The beauty of this approach, compared to say .runMode, is that the program specified by .cmd (and .command, except that it cannot tell if the invocation is in response to explicit --trailer=<key>:<value> request, or the extra one that is done even without being asked) have even better control in squelching the trailer output. Not just to silence the extra unasked-for invocation, it can inspect the value given to each of --trailer=<key>:<value> option and decide not to add a trailer in response to it.
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Quoted 25 lines · Junio C Hamano <[email protected]> 于2021年4月17日周六 上午11:36写道:
Quoted 17 lines · Junio C Hamano
And continuing this line of thought, I think it would be a perfectly fine extension to allow the script/program that is launched by the .command or .cmd mechanism to signal interpret-trailers that it does not want it to add a trailer as the result of this invocation by exiting with non-zero. And that would be a reasonable way forward without having to add yet another ugly workaround .runMode.
For example, trailer.signoff.cmd could be this script:
#!/bin/sh if test $# != 1 then exit 1 else git log -1 --author="$1" --format='"%aN" <$aE>' fiQuoted 4 lines
where the "implicit" invocation is signalled by not passing any argument, to which the script reacts by exiting with 1, and the interpret-trailers would discard the result of the unasked-for invocation.
Quoted 9 lines
The beauty of this approach, compared to say .runMode, is that the program specified by .cmd (and .command, except that it cannot tell if the invocation is in response to explicit --trailer=<key>:<value> request, or the extra one that is done even without being asked) have even better control in squelching the trailer output. Not just to silence the extra unasked-for invocation, it can inspect the value given to each of --trailer=<key>:<value> option and decide not to add a trailer in response to it.
If I understand correctly, Your approach may be like this:
First, Those <token> <value> pairs we passed on the command line will use one positional parameter in the shell-script.
Second, if it is the trailer implicitly added, originally it was <token> "", now we turn it to <token> NULL, This will make the shell-script not pass positional parameters.
Then our shell script can distinguish them by the value of $#.
If we want shell-script to execute implicitly anyway, We can do nothing. the shell-script can be like as Christian mention:
#!/bin/sh
echo "$(git config user.name) <$(git config user.email)>"
But If we want shell-script to reject implicit execution, We can judge the value of $# : 0 exit , 1 normal as you mention:
#!/bin/sh
if test $# != 1
then
exit 0
else
git log -1 --author="$1" --format='%aN <%aE>'
fi
I agree with your approach.
But when I am reproducing your solution, I may be in trouble:
If we let shell-script exit(1), capture_command() will output "running trailer command '%s' failed" which is its origin strategy in order to catch the user's command error.
But If we use exit(0) , The headache is coming again:
Signed-off-by:
the empty value trailer still output. What we want is that those "<token> NULL" are rejected here, we don’t want any other output, do we?
Thanks.
--
ZheNing Hu
Re: [PATCH v10 2/2] [GSOC] trailer: add new .cmd config option
Quoted 4 lines · ZheNing Hu
But when I am reproducing your solution, I may be in trouble:
If we let shell-scriptexit(1),capture_command()will output "running trailer command '%s' failed" which is its origin strategy in order to catch the user's command error.
Yes, if we were to take that route, the trailer.c code needs to be taught to conditionally not to pass $1, and capture_command() needs to be taught to conditionally be silent on non-zero exit, as it now is a perfectly sane for the program to exit with non-zero status in some cases (like this one).
v11 cover trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above problems.
We are now writing documents that are more readable and correct than before.
ZheNing Hu (2):
[GSOC] docs: correct description of .command
[GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt | 111 ++++++++++++++++++--- t/t7513-interpret-trailers.sh | 122 +++++++++++++++++++++++ trailer.c | 79 ++++++++++++--- 3 files changed, 280 insertions(+), 32 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v11
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v11
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v10:
1: 8129ef6c476b ! 1: 34210e5bd3da [GSOC] docs: correct descript of trailer.<token>.command
@@ Metadata
Author: ZheNing Hu <[email protected]>
## Commit message ##
- [GSOC] docs: correct descript of trailer.<token>.command
+ [GSOC] docs: correct description of .command
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify
2: daa889bd0ade ! 2: 9c0fc91aba24 [GSOC] trailer: add new .cmd config option
@@ Commit message
replaced with the value given to the `interpret-trailer`
command for the token in a '--trailer <token>=<value>' argument.
- This has three downsides:
+ This has two downsides:
* The use of $ARG in the mechanism misleads the users that
the value is passed in the shell variable, and tempt them
@@ Commit message
a broken command that is not syntactically correct (or
worse).
- * The first occurrence of substring `$ARG` will be replaced
- with the empty string, in the command when the command is
- first called to add a trailer with the specified <token>.
- This is a bad design, the nature of automatic execution
- causes it to add a trailer that we don't expect.
-
Introduce a new `trailer.<token>.cmd` configuration that
takes higher precedence to deprecate and eventually remove
`trailer.<token>.command`, which passes the value as an
@@ Commit message
refer to the value as positional argument, $1, in their
scripts. At the same time, in order to allow
`git interpret-trailers` to better simulate the behavior
- of `git command -s`, 'trailer.<token>.cmd' will not
- automatically execute.
+ of `git command -s`, the first implicitly executed command
+ will not pass positional parameters, users can use this
+ feature to suppress its output.
Helped-by: Junio C Hamano <[email protected]>
Helped-by: Christian Couder <[email protected]>
@@ Documentation/git-interpret-trailers.txt: leading and trailing whitespace trimme
-occurrence of substring `$ARG` in the command. This way the
-command can produce a <value> computed from the <value> passed
-in the '--trailer <token>=<value>' argument.
--+
++of these arguments, if any, will be passed to the command as its
++first argument. This way the command can produce a <value> computed
++from the <value> passed in the '--trailer <token>=<value>' argument.
+ +
-For consistency, the first occurrence of substring `$ARG` is
-also replaced, this time with the empty string, in the command
-when the command is first called to add a trailer with the
-specified <token>.
-+of these arguments, if any, will be passed to the command as its
-+first argument. This way the command can produce a <value> computed
-+from the <value> passed in the '--trailer <token>=<value>' argument.
++It is worth mentioning that the command is first called to add a
++trailer with the specified <token> and without positional argument.
++Users can make use of this output when they need automatically add
++some trailers. On the other hand, users can use a trick to suppress
++this output by judging whether the number of positional parameters
++is equal to one, if it is true, execute the commands, otherwise exit
++with non-zero to suppress the output.
EXAMPLES
--------
@@ Documentation/git-interpret-trailers.txt: subject
+------------
+$ cat ~/bin/gcount
+#!/bin/sh
-+test -n "$1" && git shortlog -s --author="$1" HEAD || true
++if test "$#" != 1
++then
++ exit 1
++else
++ test -n "$1" && git shortlog -s --author="$1" HEAD || true
++fi
+$ git config trailer.cnt.key "Commit-count: "
+$ git config trailer.cnt.ifExists "addIfDifferentNeighbor"
+$ git config trailer.cnt.cmd "~/bin/gcount"
+$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF
+> subject
-+>
++>
+> message
-+>
++>
+> EOF
+subject
+
@@ Documentation/git-interpret-trailers.txt: subject
+------------
+$ cat ~/bin/glog-grep
+#!/bin/sh
-+test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
++if test "$#" != 1
++then
++ exit 1
++else
++ test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
++fi
+$ git config trailer.ref.key "Reference-to: "
+$ git config trailer.ref.ifExists "replace"
+$ git config trailer.ref.cmd "~/bin/glog-grep"
+$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
+> subject
-+>
++>
+> message
-+>
++>
+> EOF
+subject
+
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ git config trailer.bug.cmd "echo \"maybe is\"" &&
+ cat >expected2 <<-EOF &&
+
++ Bug-maker: maybe is
+ Bug-maker: maybe is him
+ Bug-maker: maybe is me
+ EOF
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ git config trailer.bug.cmd "echo \"\$1\" is" &&
+ cat >expected2 <<-EOF &&
+
++ Bug-maker: is
+ Bug-maker: him is him
+ Bug-maker: me is me
+ EOF
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ EOF
+ cat >echoscript <<-EOF &&
+ #!/bin/sh
-+ echo who is "\$1"
++ if test "\$#" != 1
++ then
++ exit 1
++ else
++ echo who is "\$1"
++ fi
+ EOF
+ chmod +x echoscript &&
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
++
++test_expect_success 'with cmd, $1 and without --trailer' '
++ test_when_finished "git config --remove-section trailer.bug" &&
++ test_when_finished "git config --remove-section trailer.gub" &&
++ git config trailer.bug.key "Bug-maker: " &&
++ git config trailer.bug.ifExists "replace" &&
++ git config trailer.bug.cmd "./echoscript" &&
++ git config trailer.gub.key "Gub-maker: " &&
++ git config trailer.gub.ifExists "replace" &&
++ git config trailer.gub.cmd "./echoscript2" &&
++ cat >expected2 <<-EOF &&
++
++ Gub-maker: si ohw
++ EOF
++ cat >echoscript <<-EOF &&
++ #!/bin/sh
++ if test "\$#" != 1
++ then
++ exit 1
++ else
++ echo who is "\$1"
++ fi
++ EOF
++ cat >echoscript2 <<-EOF &&
++ echo si ohw "\$1"
++ EOF
++ chmod +x echoscript &&
++ chmod +x echoscript2 &&
++ git interpret-trailers >actual2 &&
++ test_cmp expected2 actual2
++'
+
test_expect_success 'without config' '
sed -e "s/ Z\$/ /" >expected <<-\EOF &&
@@ trailer.c: static void free_arg_item(struct arg_item *item)
free(item->conf.command);
+ free(item->conf.cmd);
free(item->token);
- free(item->value);
+- free(item->value);
++ if (item->value)
++ FREE_AND_NULL(item->value);
free(item);
+ }
+
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
return 1;
}
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
+
+ if (capture_command(&cp, &buf, 1024)) {
+- error(_("running trailer command '%s' failed"), cmd.buf);
+ strbuf_release(&buf);
+- result = xstrdup("");
++ if (!conf->cmd || arg) {
++ error(_("running trailer command '%s' failed"), cmd.buf);
++ result = xstrdup("");
++ } else
++ result = NULL;
+ } else {
+ strbuf_trim(&buf);
+ result = strbuf_detach(&buf, NULL);
@@ trailer.c: static char *apply_command(const char *command, const char *arg)
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
{
- if (arg_tok->conf.command) {
+- const char *arg;
+- if (arg_tok->value && arg_tok->value[0]) {
+ if (arg_tok->conf.command || arg_tok->conf.cmd) {
- const char *arg;
- if (arg_tok->value && arg_tok->value[0]) {
++ const char *arg = NULL;
++
++ if ((arg_tok->value && arg_tok->value[0]) ||
++ (arg_tok->conf.cmd && !arg_tok->value)) {
arg = arg_tok->value;
+ } else {
+ if (in_tok && in_tok->value)
@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
else
arg = xstrdup("");
}
- arg_tok->value = apply_command(arg_tok->conf.command, arg);
+- free((char *)arg);
+ arg_tok->value = apply_command(&arg_tok->conf, arg);
- free((char *)arg);
++ if (arg)
++ free((char *)arg);
}
}
+
+@@ trailer.c: static void apply_arg_if_exists(struct trailer_item *in_tok,
+ break;
+ case EXISTS_REPLACE:
+ apply_item_command(in_tok, arg_tok);
++ if (!arg_tok->value) {
++ free_arg_item(arg_tok);
++ return;
++ }
+ add_arg_to_input_list(on_tok, arg_tok);
+ list_del(&in_tok->list);
+ free_trailer_item(in_tok);
+ break;
+ case EXISTS_ADD:
+ apply_item_command(in_tok, arg_tok);
++ if (!arg_tok->value) {
++ free_arg_item(arg_tok);
++ return;
++ }
+ add_arg_to_input_list(on_tok, arg_tok);
+ break;
+ case EXISTS_ADD_IF_DIFFERENT:
+ apply_item_command(in_tok, arg_tok);
++ if (!arg_tok->value) {
++ free_arg_item(arg_tok);
++ return;
++ }
+ if (check_if_different(in_tok, arg_tok, 1, head))
+ add_arg_to_input_list(on_tok, arg_tok);
+ else
+@@ trailer.c: static void apply_arg_if_exists(struct trailer_item *in_tok,
+ break;
+ case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
+ apply_item_command(in_tok, arg_tok);
++ if (!arg_tok->value) {
++ free_arg_item(arg_tok);
++ return;
++ }
+ if (check_if_different(on_tok, arg_tok, 0, head))
+ add_arg_to_input_list(on_tok, arg_tok);
+ else
+@@ trailer.c: static void apply_arg_if_missing(struct list_head *head,
+ case MISSING_ADD:
+ where = arg_tok->conf.where;
+ apply_item_command(NULL, arg_tok);
++ if (!arg_tok->value) {
++ free_arg_item(arg_tok);
++ return;
++ }
+ to_add = trailer_from_arg(arg_tok);
+ if (after_or_end(where))
+ list_add_tail(&to_add->list, head);
@@ trailer.c: static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
dst->name = xstrdup_or_null(src->name);
dst->key = xstrdup_or_null(src->key);
@@ trailer.c: static int git_trailer_config(const char *conf_key, const char *value
case TRAILER_WHERE:
if (trailer_set_where(&conf->where, value))
warning(_("unknown value '%s' for key '%s'"), value, conf_key);
+@@ trailer.c: static void process_command_line_args(struct list_head *arg_head,
+ xstrdup(token_from_item(item, NULL)),
+ xstrdup(""),
+ &item->conf, NULL);
++ else if (item->conf.cmd)
++ add_arg_item(arg_head,
++ xstrdup(token_from_item(item, NULL)),
++ NULL,
++ &item->conf, NULL);
+ }
+
+ /* Add an arg item for each trailer on the command line */Signature · 1 line
gitgitgadget
PATCH v11 1/2 docs: correct description of .command
From: ZheNing Hu <[email protected]>
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
In addition, clarify that $ARG in command can only be replaced once.
--- Documentation/git-interpret-trailers.txt | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-)
Documentation/git-interpret-trailers.txt +21 -16
@@ -232,25 +232,30 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: - This option can be used to specify a shell command that will - be called to automatically add or modify a trailer with the - specified <token>. + This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + -If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>. EXAMPLES --------
Signature · 1 line
gitgitgadget
PATCH v11 2/2 trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token in a '--trailer <token>=<value>' argument.
This has two downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts. At the same time, in order to allowgit interpret-trailers to better simulate the behavior of git command -s, the first implicitly executed command will not pass positional parameters, users can use this feature to suppress its output.
--- Documentation/git-interpret-trailers.txt | 90 +++++++++++++++-- t/t7513-interpret-trailers.sh | 122 +++++++++++++++++++++++ trailer.c | 79 ++++++++++++--- 3 files changed, 267 insertions(+), 24 deletions(-)
Documentation/git-interpret-trailers.txt +82 -8
@@ -232,6 +232,20 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: + This option behaves in the same way as 'trailer.<token>.cmd', except + that it doesn't pass anything as argument to the specified command. + Instead the first occurrence of substring $ARG is replaced by the + value that would be passed as argument. ++ +The 'trailer.<token>.command' option has been deprecated in favor of +'trailer.<token>.cmd' due to the fact that $ARG in the user's command is +only replaced once and that the original way of replacing $ARG is not safe. ++ +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored. + +trailer.<token>.cmd:: This option can be used to specify a shell command that will be called: once to automatically add a trailer with the specified <token>, and then each time a '--trailer <token>=<value>' argument to modify the <value> of
@@ -247,15 +261,17 @@ leading and trailing whitespace trimmed off. If some '--trailer <token>=<value>' arguments are also passed on the command line, the command is called again once for each of these arguments with the same <token>. And the <value> part -of these arguments, if any, will be used to replace the first -occurrence of substring `$ARG` in the command. This way the -command can produce a <value> computed from the <value> passed -in the '--trailer <token>=<value>' argument. +of these arguments, if any, will be passed to the command as its +first argument. This way the command can produce a <value> computed +from the <value> passed in the '--trailer <token>=<value>' argument. + -For consistency, the first occurrence of substring `$ARG` is -also replaced, this time with the empty string, in the command -when the command is first called to add a trailer with the -specified <token>. +It is worth mentioning that the command is first called to add a +trailer with the specified <token> and without positional argument. +Users can make use of this output when they need automatically add +some trailers. On the other hand, users can use a trick to suppress +this output by judging whether the number of positional parameters +is equal to one, if it is true, execute the commands, otherwise exit +with non-zero to suppress the output. EXAMPLES --------
@@ -338,6 +354,64 @@ subject Fix #42 ------------ +* Configure a 'cnt' trailer with a cmd use a global script `gcount` +to record commit counts of a specified author and show how it works: ++ +------------ +$ cat ~/bin/gcount +#!/bin/sh +if test "$#" != 1 +then + exit 1 +else + test -n "$1" && git shortlog -s --author="$1" HEAD || true +fi +$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "addIfDifferentNeighbor" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF +> subject +> +> message +> +> EOF +subject + +message + +Commit-count: 22484 Junio C Hamano +Commit-count: 1117 Linus Torvalds +------------ + +* Configure a 'ref' trailer with a cmd use a global script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +if test "$#" != 1 +then + exit 1 +else + test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +fi +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +122 -0
134 lines not on this page · raw message
trailer.c +63 -16
180 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetQuoted 10 lines · ZheNing Hu via GitGitGadget
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG:1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Quoted 4 lines
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above problems.
We are now writing documents that are more readable and correct than before.
Here is a good spot to summarize what changed since the previous round.
It seems that this now has "exit non-zero to tell the caller not to add the trailer for this execuation". Is that the only change you made?
I was hoping that we'd declare victory with what was in v10 (with possibly typos and minor stylistic fixes if needed---I no longer remember details), let it go through the usual course of cooking in 'next' and merged down to 'master', and then after the dust settles, we'd be adding this "by exiting with non-zero status, scripts can signal a trailer not to be added for a particular invocation" as a new feature, if it turns out to be necessary.
But let's see what's new in this iteration.
Quoted 8 lines
+#!/bin/sh
-+test -n "$1" && git shortlog -s --author="$1" HEAD || true
++if test "$#" != 1
++then
++ exit 1
++else
++ test -n "$1" && git shortlog -s --author="$1" HEAD || true
++fiI find this dubious. Why not
if test "$#" != 1 || test -z "$1" then exit 1 else git shortlog -s --author="$1" HEAD fi
That is, if you happened to give an empty string, your version gives "" to <value> and returns success, letting a trailer "cnt:" with empty value. Is that what we really want?
Quoted 16 lines
+$ git config trailer.cnt.key "Commit-count: "
+$ git config trailer.cnt.ifExists "addIfDifferentNeighbor"
+$ git config trailer.cnt.cmd "~/bin/gcount"
+$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF
+> subject
-+>
++>
+> message
-+>
++>
+> EOF
+subject
+
@@ Documentation/git-interpret-trailers.txt: subject
+------------
+$ cat ~/bin/glog-grepQuoted 8 lines
+#!/bin/sh
-+test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
++if test "$#" != 1
++then
++ exit 1
++else
++ test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
++fiDitto.
Quoted 6 lines
+ if (capture_command(&cp, &buf, 1024)) {
+- error(_("running trailer command '%s' failed"), cmd.buf);
+ strbuf_release(&buf);
+- result = xstrdup("");
++ if (!conf->cmd || arg) {
++ error(_("running trailer command '%s' failed"), cmd.buf);I am not sure about this part. If .cmd (the new style) exits with a non-zero status for user-supplied --trailer=<token>:<value> (because it did not like the <value>), is that "running failed"? The script is expected to express yes/no with its exit status, so I would say it is not failing, but successfully expressed its displeasure and vetoed the particular trailer from getting added. IOW, "|| arg" part in the condition feels iffy to me.
Quoted 6 lines
++ result =
xstrdup("");
++ } else
++ result = NULL;
+ } else {
+strbuf_trim(&buf);
+ result =strbuf_detach(&buf, NULL);
OK.
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 16 lines · Junio C Hamano <[email protected]> 于2021年4月18日周日 上午6:26写道:
Quoted 13 lines · ZheNing Hu via GitGitGadget
In https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using
strbuf_replace()to replace $ARG:1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above problems.
Quoted 9 lines
Quoted 1 line
We are now writing documents that are more readable and correct than before.
Here is a good spot to summarize what changed since the previous round.
It seems that this now has "exit non-zero to tell the caller not to add the trailer for this execuation". Is that the only change you made?
Yes, I think the more accurate one should be "exit non-zero to tell the caller not to add the trailer for this implicit execuation", You also said below, it may not be so good.
Quoted 8 lines
I was hoping that we'd declare victory with what was in v10 (with possibly typos and minor stylistic fixes if needed---I no longer remember details), let it go through the usual course of cooking in 'next' and merged down to 'master', and then after the dust settles, we'd be adding this "by exiting with non-zero status, scripts can signal a trailer not to be added for a particular invocation" as a new feature, if it turns out to be necessary.
Thanks for your and Christian's help this month!
OK, I understand, then I can wait for a while until trailer_cmd merge to master.
Quoted 21 lines
But let's see what's new in this iteration.
Quoted 8 lines
+#!/bin/sh -+test -n "$1" && git shortlog -s --author="$1" HEAD || true ++if test "$#" != 1 ++then ++ exit 1 ++else ++ test -n "$1" && git shortlog -s --author="$1" HEAD || true ++fiI find this dubious. Why not
if test "$#" != 1 || test -z "$1" then exit 1 else git shortlog -s --author="$1" HEAD fi
Quoted 3 lines
That is, if you happened to give an empty string, your version gives "" to <value> and returns success, letting a trailer "cnt:" with empty value. Is that what we really want?
If it's the user use --trailer="cnt:" instread of command implict running, I think keep it is right.
In fact, it should be said that it is equivalent to exit(0) if the user use --trailer="cnt:".
Quoted 35 lines
Quoted 17 lines
+$ git config trailer.cnt.key "Commit-count: " +$ git config trailer.cnt.ifExists "addIfDifferentNeighbor" +$ git config trailer.cnt.cmd "~/bin/gcount" +$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF +> subject -+> ++> +> message -+> ++> +> EOF +subject + @@ Documentation/git-interpret-trailers.txt: subject +------------ +$ cat ~/bin/glog-grepQuoted 8 lines
+#!/bin/sh -+test -n "$1" && git log --grep "$1" --pretty=reference -1 || true ++if test "$#" != 1 ++then ++ exit 1 ++else ++ test -n "$1" && git log --grep "$1" --pretty=reference -1 || true ++fiDitto.
Quoted 6 lines
+ if (capture_command(&cp, &buf, 1024)) { +- error(_("running trailer command '%s' failed"), cmd.buf); + strbuf_release(&buf); +- result = xstrdup(""); ++ if (!conf->cmd || arg) { ++ error(_("running trailer command '%s' failed"), cmd.buf);
Quoted 8 lines
I am not sure about this part. If .cmd (the new style) exits with a non-zero status for user-supplied --trailer=<token>:<value> (because it did not like the <value>), is that "running failed"? The script is expected to express yes/no with its exit status, so I would say it is not failing, but successfully expressed its displeasure and vetoed the particular trailer from getting added. IOW, "|| arg" part in the condition feels iffy to me.
Well, you mean we can take advantage of non-zero exits instead of just removing implicitly executed content. I argee with you, this place is worth change.
Quoted 8 lines
Quoted 6 lines
++ result =
xstrdup("");
++ } else
++ result = NULL;
+ } else {
+strbuf_trim(&buf);
+ result =strbuf_detach(&buf, NULL);OK.
Thanks.
--
ZheNing Hu
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 24 lines · ZheNing Hu
OK, I understand, then I can wait for a while until
trailer_cmdmerge to master.Quoted 21 lines
But let's see what's new in this iteration.
Quoted 8 lines
+#!/bin/sh -+test -n "$1" && git shortlog -s --author="$1" HEAD || true ++if test "$#" != 1 ++then ++ exit 1 ++else ++ test -n "$1" && git shortlog -s --author="$1" HEAD || true ++fiI find this dubious. Why not
if test "$#" != 1 || test -z "$1" then exit 1 else git shortlog -s --author="$1" HEAD fi
Quoted 6 lines
Quoted 3 lines
That is, if you happened to give an empty string, your version gives "" to <value> and returns success, letting a trailer "cnt:" with empty value. Is that what we really want?
If it's the user use
--trailer="cnt:"instread of command implict running, I think keep it is right.
No, if you give an empty string, you'd end up running "shortlog" with --author="" and give whatever random number it comes up with, which I do not think is what you would want.
That is why --trailer=cnt: without name to match --author can be rejected with "exit 1" to demonstrate the feature. The .cmd can squelch not just the "unasked for extra invocation", but invocation from the command line whose <value> was bogus, unlike the .runmode feature we've seen proposed earlier.
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines
+ if (capture_command(&cp, &buf, 1024)) { +- error(_("running trailer command '%s' failed"), cmd.buf); + strbuf_release(&buf); +- result = xstrdup(""); ++ if (!conf->cmd || arg) { ++ error(_("running trailer command '%s' failed"), cmd.buf);Quoted 7 lines
I am not sure about this part. If .cmd (the new style) exits with a non-zero status for user-supplied --trailer=<token>:<value> (because it did not like the <value>), is that "running failed"? The script is expected to express yes/no with its exit status, so I would say it is not failing, but successfully expressed its displeasure and vetoed the particular trailer from getting added. IOW, "|| arg" part in the condition feels iffy to me.
Quoted 3 lines
Well, you mean we can take advantage of non-zero exits instead of just removing implicitly executed content. I argee with you, this place is worth change.
Yup, that is what I meant.
In any case, let's see how well the base topic fares.
Thanks.
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 38 lines · Junio C Hamano <[email protected]> 于2021年4月21日周三 上午8:09写道:
Quoted 24 lines · ZheNing Hu
OK, I understand, then I can wait for a while until
trailer_cmdmerge to master.Quoted 21 lines
But let's see what's new in this iteration.
Quoted 8 lines
+#!/bin/sh -+test -n "$1" && git shortlog -s --author="$1" HEAD || true ++if test "$#" != 1 ++then ++ exit 1 ++else ++ test -n "$1" && git shortlog -s --author="$1" HEAD || true ++fiI find this dubious. Why not
if test "$#" != 1 || test -z "$1" then exit 1 else git shortlog -s --author="$1" HEAD fiQuoted 6 lines
Quoted 3 lines
That is, if you happened to give an empty string, your version gives "" to <value> and returns success, letting a trailer "cnt:" with empty value. Is that what we really want?
If it's the user use
--trailer="cnt:"instread of command implict running, I think keep it is right.No, if you give an empty string, you'd end up running "shortlog" with --author="" and give whatever random number it comes up with, which I do not think is what you would want.
Quoted 6 lines
That is why --trailer=cnt: without name to match --author can be rejected with "exit 1" to demonstrate the feature. The .cmd can squelch not just the "unasked for extra invocation", but invocation from the command line whose <value> was bogus, unlike the .runmode feature we've seen proposed earlier.
I admit that your idea makes sense, but we actually have another requirement:
Construct a trailer with an empty value.
The Commit-Count example above may not be good, Let’s take a look at the Signed-off-by.
e.g. --trailer="sign:", we expect to output a "Signed-off-by: ", then we can fill it
with the "name <email>" pair we want, this is when we shouldn't return non-zero and suppress its output.
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 6 lines
+ if (capture_command(&cp, &buf, 1024)) { +- error(_("running trailer command '%s' failed"), cmd.buf); + strbuf_release(&buf); +- result = xstrdup(""); ++ if (!conf->cmd || arg) { ++ error(_("running trailer command '%s' failed"), cmd.buf);I am not sure about this part. If .cmd (the new style) exits with a non-zero status for user-supplied --trailer=<token>:<value> (because it did not like the <value>), is that "running failed"? The script is expected to express yes/no with its exit status, so I would say it is not failing, but successfully expressed its displeasure and vetoed the particular trailer from getting added. IOW, "|| arg" part in the condition feels iffy to me.
Quoted 8 lines
Quoted 3 lines
Well, you mean we can take advantage of non-zero exits instead of just removing implicitly executed content. I argee with you, this place is worth change.
Yup, that is what I meant.
In any case, let's see how well the base topic fares.
Yes, I don't know if Christian agrees with temporary situation.
Quoted 1 line
Thanks.
Thanks.
--
ZheNing Hu
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 2 lines · ZheNing Hu
I admit that your idea makes sense, but we actually have another requirement:
Construct a trailer with an empty value.
It can be done with a different script given to .cmd, which would say "exit 0" when allowing an empty string given as its input to appear in the output.
I was reacting what the "count" example does, and found that counting commits by all authors (that is what an empty string would match when given to --author="") somewhat illogical in the context of that example.
After all, these examples are to pique readers' interest by demonstrating what the mechanism can do and how it can be used, and for this feature, I think showing that
(1) we can squelch the output from unasked-for execution;
(2) we can reject --trailer=<key>:<value> when we do not like the
given <value>;
(3) we can insert the trailer with the value we compute (and it is OK for the computed result happens to be an empty string).
should be plenty sufficient.
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 10 lines · Junio C Hamano <[email protected]> 于2021年4月22日周四 上午7:40写道:
Quoted 2 lines · ZheNing Hu
I admit that your idea makes sense, but we actually have another requirement:
Construct a trailer with an empty value.It can be done with a different script given to .cmd, which would say "exit 0" when allowing an empty string given as its input to appear in the output.
Now I think that we should keep those trailers which ask for a "name <email>" pair, like "Helped-by", "Signed-off-by", when we provide a "help:","sign:" in command line, This allows the user to dynamically fill in the "name <email>" pair of other people in the commit message later. It is worthwhile for users to exit with exit(0).
But those dispensable things like "Commit-Count", It must depend on a person's statistics in the git repository. So "cnt:" is meaningless, users' script can let it exit(1).
Quoted 5 lines
I was reacting what the "count" example does, and found that counting commits by all authors (that is what an empty string would match when given to --author="") somewhat illogical in the context of that example.
The "Commit-Count" in the example here can only target a specific person, which has great limitations.
I have a bold idea:
Our current --trailer can only fill in one data item, and we don't expect it to fill
in multiple rows. something like "Commit-Count", we hope to count the number of commits from everyone. But as we can see:
Commit-count: 7 Linus Arver
1117 Linus Torvalds
So If we have the opportunity to capture every line or every "block" of content, and feed it to git interpret-trailer, maybe we can get something like:
Commit-count: 7 Linus Arver
Commit-count: 1117 Linus Torvalds
This will definitely make it easy for us to generate a lot of trailer at once. For example, a newbie like me, after making a patch, want to --cc all authors of one file, maybe I only need a command to get it.
I don't know if it's a bit whimsical.
Quoted 6 lines
After all, these examples are to pique readers' interest by demonstrating what the mechanism can do and how it can be used, and for this feature, I think showing that
(1) we can squelch the output from unasked-for execution;
Quoted 7 lines
(2) we can reject --trailer=<key>:<value> when we do not like the
given <value>;(3) we can insert the trailer with the value we compute (and it is OK for the computed result happens to be an empty string).
should be plenty sufficient.
OK. I will add these three examples in the new patch (when .cmd merge to master).
Thanks.
--
ZheNing Hu
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 9 lines · ZheNing Hu
Now I think that we should keep those trailers which ask for a "name <email>" pair, like "Helped-by", "Signed-off-by", when we provide a "help:","sign:" in command line, This allows the user to dynamically fill in the "name <email>" pair of other people in the commit message later. It is worthwhile for users to exit with exit(0).
But those dispensable things like "Commit-Count", It must depend on a person's statistics in the git repository. So "cnt:" is meaningless, users' script can let it exit(1).
Perhaps, but at this point what you think (or what I think) does not matter. That was the whole point of letting .cmd script signal Git if the result from the invocation should be kept or discarded with its exit status. What would be sufficient here for us to do is to agree that it would be good to have a minimal set (perhaps a pair) of examples to demonstrate that the script can choose to keep or discard a meaningless trailer entry with its exit status.
Re: [PATCH v11 0/2] [GSOC] trailer: add new .cmd config option
Quoted 13 lines · Junio C Hamano <[email protected]> 于2021年4月27日周二 下午2:49写道:
Quoted 9 lines · ZheNing Hu
Now I think that we should keep those trailers which ask for a "name <email>" pair, like "Helped-by", "Signed-off-by", when we provide a "help:","sign:" in command line, This allows the user to dynamically fill in the "name <email>" pair of other people in the commit message later. It is worthwhile for users to exit with exit(0).
But those dispensable things like "Commit-Count", It must depend on a person's statistics in the git repository. So "cnt:" is meaningless, users' script can let it exit(1).
Quoted 7 lines
Perhaps, but at this point what you think (or what I think) does not matter. That was the whole point of letting .cmd script signal Git if the result from the invocation should be kept or discarded with its exit status. What would be sufficient here for us to do is to agree that it would be good to have a minimal set (perhaps a pair) of examples to demonstrate that the script can choose to keep or discard a meaningless trailer entry with its exit status.
Yes, I argee.
Due to previous attempts, it seems that such an example is well given:
"Commit-Count" is the trailer that should be discarded. "Signed-off-by" is the trailer worth be kept.
Thanks.
--
ZheNing Hu
v12 cover trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetIn https://lore.kernel.org/git/[email protected]/ Junio and Christian talked about the problem of using strbuf_replace() to replace $ARG:
1. if the user's script has more than one $ARG, only the first one will be replaced, which is incorrected.
2. $ARG is textually replaced without shell syntax, which may result a broken command when $ARG include some unmatching single quote, very unsafe.
Now pass trailer value as $1 to the trailer command with another trailer.<token>.cmd config, to solve these above problems.
We are now writing documents that are more readable and correct than before.
Change from last version: Change docs example "Count-count" to "Helped-by".
ZheNing Hu (2):
[GSOC] docs: correct descript of trailer.<token>.command [GSOC] trailer: add new .cmd config option
Documentation/git-interpret-trailers.txt | 94 ++++++++++++++++++++---- t/t7513-interpret-trailers.sh | 84 +++++++++++++++++++++ trailer.c | 35 ++++++--- 3 files changed, 187 insertions(+), 26 deletions(-)
base-commit: 142430338477d9d1bb25be66267225fb58498d92
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-913%2Fadlternative%2Ftrailer-pass-ARG-env-v12
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-913/adlternative/trailer-pass-ARG-env-v12
Pull-Request: https://github.com/gitgitgadget/git/pull/913
Range-diff vs v11:
1: 34210e5bd3da ! 1: 8129ef6c476b [GSOC] docs: correct description of .command
@@ Metadata
Author: ZheNing Hu <[email protected]>
## Commit message ##
- [GSOC] docs: correct description of .command
+ [GSOC] docs: correct descript of trailer.<token>.command
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify
2: 9c0fc91aba24 ! 2: edb7f1961ddb [GSOC] trailer: add new .cmd config option
@@ Commit message
replaced with the value given to the `interpret-trailer`
command for the token in a '--trailer <token>=<value>' argument.
- This has two downsides:
+ This has three downsides:
* The use of $ARG in the mechanism misleads the users that
the value is passed in the shell variable, and tempt them
@@ Commit message
a broken command that is not syntactically correct (or
worse).
+ * The first occurrence of substring `$ARG` will be replaced
+ with the empty string, in the command when the command is
+ first called to add a trailer with the specified <token>.
+ This is a bad design, the nature of automatic execution
+ causes it to add a trailer that we don't expect.
+
Introduce a new `trailer.<token>.cmd` configuration that
takes higher precedence to deprecate and eventually remove
`trailer.<token>.command`, which passes the value as an
@@ Commit message
refer to the value as positional argument, $1, in their
scripts. At the same time, in order to allow
`git interpret-trailers` to better simulate the behavior
- of `git command -s`, the first implicitly executed command
- will not pass positional parameters, users can use this
- feature to suppress its output.
+ of `git command -s`, 'trailer.<token>.cmd' will not
+ automatically execute.
Helped-by: Junio C Hamano <[email protected]>
Helped-by: Christian Couder <[email protected]>
@@ Documentation/git-interpret-trailers.txt: leading and trailing whitespace trimme
-occurrence of substring `$ARG` in the command. This way the
-command can produce a <value> computed from the <value> passed
-in the '--trailer <token>=<value>' argument.
-+of these arguments, if any, will be passed to the command as its
-+first argument. This way the command can produce a <value> computed
-+from the <value> passed in the '--trailer <token>=<value>' argument.
- +
+-+
-For consistency, the first occurrence of substring `$ARG` is
-also replaced, this time with the empty string, in the command
-when the command is first called to add a trailer with the
-specified <token>.
-+It is worth mentioning that the command is first called to add a
-+trailer with the specified <token> and without positional argument.
-+Users can make use of this output when they need automatically add
-+some trailers. On the other hand, users can use a trick to suppress
-+this output by judging whether the number of positional parameters
-+is equal to one, if it is true, execute the commands, otherwise exit
-+with non-zero to suppress the output.
++of these arguments, if any, will be passed to the command as its
++first argument. This way the command can produce a <value> computed
++from the <value> passed in the '--trailer <token>=<value>' argument.
EXAMPLES
--------
@@ Documentation/git-interpret-trailers.txt: subject
Fix #42
------------
-+* Configure a 'cnt' trailer with a cmd use a global script `gcount`
-+to record commit counts of a specified author and show how it works:
++* Configure a 'help' trailer with a cmd use a script `glog-find-author`
++ which search specified author identity from git log in git repository
++ and show how it works:
++
+------------
-+$ cat ~/bin/gcount
++$ cat ~/bin/glog-find-author
+#!/bin/sh
-+if test "$#" != 1
-+then
-+ exit 1
-+else
-+ test -n "$1" && git shortlog -s --author="$1" HEAD || true
-+fi
-+$ git config trailer.cnt.key "Commit-count: "
-+$ git config trailer.cnt.ifExists "addIfDifferentNeighbor"
-+$ git config trailer.cnt.cmd "~/bin/gcount"
-+$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF
++test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
++$ git config trailer.help.key "Helped-by: "
++$ git config trailer.help.ifExists "addIfDifferentNeighbor"
++$ git config trailer.help.cmd "~/bin/glog-find-author"
++$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <<EOF
+> subject
-+>
++>
+> message
-+>
++>
+> EOF
+subject
+
+message
+
-+Commit-count: 22484 Junio C Hamano
-+Commit-count: 1117 Linus Torvalds
++Helped-by: Junio C Hamano <[email protected]>
++Helped-by: Christian Couder <[email protected]>
+------------
+
-+* Configure a 'ref' trailer with a cmd use a global script `glog-grep`
++* Configure a 'ref' trailer with a cmd use a script `glog-grep`
+ to grep last relevant commit from git log in the git repository
+ and show how it works:
++
+------------
+$ cat ~/bin/glog-grep
+#!/bin/sh
-+if test "$#" != 1
-+then
-+ exit 1
-+else
-+ test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
-+fi
++test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
+$ git config trailer.ref.key "Reference-to: "
+$ git config trailer.ref.ifExists "replace"
+$ git config trailer.ref.cmd "~/bin/glog-grep"
+$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
+> subject
-+>
++>
+> message
-+>
++>
+> EOF
+subject
+
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ git config trailer.bug.cmd "echo \"maybe is\"" &&
+ cat >expected2 <<-EOF &&
+
-+ Bug-maker: maybe is
+ Bug-maker: maybe is him
+ Bug-maker: maybe is me
+ EOF
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ git config trailer.bug.cmd "echo \"\$1\" is" &&
+ cat >expected2 <<-EOF &&
+
-+ Bug-maker: is
+ Bug-maker: him is him
+ Bug-maker: me is me
+ EOF
@@ t/t7513-interpret-trailers.sh: test_expect_success 'setup' '
+ EOF
+ cat >echoscript <<-EOF &&
+ #!/bin/sh
-+ if test "\$#" != 1
-+ then
-+ exit 1
-+ else
-+ echo who is "\$1"
-+ fi
++ echo who is "\$1"
+ EOF
+ chmod +x echoscript &&
+ git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
+ >actual2 &&
+ test_cmp expected2 actual2
+'
-+
-+test_expect_success 'with cmd, $1 and without --trailer' '
-+ test_when_finished "git config --remove-section trailer.bug" &&
-+ test_when_finished "git config --remove-section trailer.gub" &&
-+ git config trailer.bug.key "Bug-maker: " &&
-+ git config trailer.bug.ifExists "replace" &&
-+ git config trailer.bug.cmd "./echoscript" &&
-+ git config trailer.gub.key "Gub-maker: " &&
-+ git config trailer.gub.ifExists "replace" &&
-+ git config trailer.gub.cmd "./echoscript2" &&
-+ cat >expected2 <<-EOF &&
-+
-+ Gub-maker: si ohw
-+ EOF
-+ cat >echoscript <<-EOF &&
-+ #!/bin/sh
-+ if test "\$#" != 1
-+ then
-+ exit 1
-+ else
-+ echo who is "\$1"
-+ fi
-+ EOF
-+ cat >echoscript2 <<-EOF &&
-+ echo si ohw "\$1"
-+ EOF
-+ chmod +x echoscript &&
-+ chmod +x echoscript2 &&
-+ git interpret-trailers >actual2 &&
-+ test_cmp expected2 actual2
-+'
+
test_expect_success 'without config' '
sed -e "s/ Z\$/ /" >expected <<-\EOF &&
@@ trailer.c: static void free_arg_item(struct arg_item *item)
free(item->conf.command);
+ free(item->conf.cmd);
free(item->token);
-- free(item->value);
-+ if (item->value)
-+ FREE_AND_NULL(item->value);
+ free(item->value);
free(item);
- }
-
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
return 1;
}
@@ trailer.c: static int check_if_different(struct trailer_item *in_tok,
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
-
- if (capture_command(&cp, &buf, 1024)) {
-- error(_("running trailer command '%s' failed"), cmd.buf);
- strbuf_release(&buf);
-- result = xstrdup("");
-+ if (!conf->cmd || arg) {
-+ error(_("running trailer command '%s' failed"), cmd.buf);
-+ result = xstrdup("");
-+ } else
-+ result = NULL;
- } else {
- strbuf_trim(&buf);
- result = strbuf_detach(&buf, NULL);
@@ trailer.c: static char *apply_command(const char *command, const char *arg)
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
{
- if (arg_tok->conf.command) {
-- const char *arg;
-- if (arg_tok->value && arg_tok->value[0]) {
+ if (arg_tok->conf.command || arg_tok->conf.cmd) {
-+ const char *arg = NULL;
-+
-+ if ((arg_tok->value && arg_tok->value[0]) ||
-+ (arg_tok->conf.cmd && !arg_tok->value)) {
+ const char *arg;
+ if (arg_tok->value && arg_tok->value[0]) {
arg = arg_tok->value;
- } else {
- if (in_tok && in_tok->value)
@@ trailer.c: static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
else
arg = xstrdup("");
}
- arg_tok->value = apply_command(arg_tok->conf.command, arg);
-- free((char *)arg);
+ arg_tok->value = apply_command(&arg_tok->conf, arg);
-+ if (arg)
-+ free((char *)arg);
+ free((char *)arg);
}
}
-
-@@ trailer.c: static void apply_arg_if_exists(struct trailer_item *in_tok,
- break;
- case EXISTS_REPLACE:
- apply_item_command(in_tok, arg_tok);
-+ if (!arg_tok->value) {
-+ free_arg_item(arg_tok);
-+ return;
-+ }
- add_arg_to_input_list(on_tok, arg_tok);
- list_del(&in_tok->list);
- free_trailer_item(in_tok);
- break;
- case EXISTS_ADD:
- apply_item_command(in_tok, arg_tok);
-+ if (!arg_tok->value) {
-+ free_arg_item(arg_tok);
-+ return;
-+ }
- add_arg_to_input_list(on_tok, arg_tok);
- break;
- case EXISTS_ADD_IF_DIFFERENT:
- apply_item_command(in_tok, arg_tok);
-+ if (!arg_tok->value) {
-+ free_arg_item(arg_tok);
-+ return;
-+ }
- if (check_if_different(in_tok, arg_tok, 1, head))
- add_arg_to_input_list(on_tok, arg_tok);
- else
-@@ trailer.c: static void apply_arg_if_exists(struct trailer_item *in_tok,
- break;
- case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
- apply_item_command(in_tok, arg_tok);
-+ if (!arg_tok->value) {
-+ free_arg_item(arg_tok);
-+ return;
-+ }
- if (check_if_different(on_tok, arg_tok, 0, head))
- add_arg_to_input_list(on_tok, arg_tok);
- else
-@@ trailer.c: static void apply_arg_if_missing(struct list_head *head,
- case MISSING_ADD:
- where = arg_tok->conf.where;
- apply_item_command(NULL, arg_tok);
-+ if (!arg_tok->value) {
-+ free_arg_item(arg_tok);
-+ return;
-+ }
- to_add = trailer_from_arg(arg_tok);
- if (after_or_end(where))
- list_add_tail(&to_add->list, head);
@@ trailer.c: static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
dst->name = xstrdup_or_null(src->name);
dst->key = xstrdup_or_null(src->key);
@@ trailer.c: static int git_trailer_config(const char *conf_key, const char *value
case TRAILER_WHERE:
if (trailer_set_where(&conf->where, value))
warning(_("unknown value '%s' for key '%s'"), value, conf_key);
-@@ trailer.c: static void process_command_line_args(struct list_head *arg_head,
- xstrdup(token_from_item(item, NULL)),
- xstrdup(""),
- &item->conf, NULL);
-+ else if (item->conf.cmd)
-+ add_arg_item(arg_head,
-+ xstrdup(token_from_item(item, NULL)),
-+ NULL,
-+ &item->conf, NULL);
- }
-
- /* Add an arg item for each trailer on the command line */Signature · 1 line
gitgitgadget
PATCH v12 1/2 docs: correct descript of trailer.<token>.command
From: ZheNing Hu <[email protected]>
In the original documentation of trailer.<token>.command, some descriptions are easily misunderstood. So let's modify it to increase its readability.
In addition, clarify that $ARG in command can only be replaced once.
--- Documentation/git-interpret-trailers.txt | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-)
Documentation/git-interpret-trailers.txt +21 -16
@@ -232,25 +232,30 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: - This option can be used to specify a shell command that will - be called to automatically add or modify a trailer with the - specified <token>. + This option can be used to specify a shell command that will be called: + once to automatically add a trailer with the specified <token>, and then + each time a '--trailer <token>=<value>' argument to modify the <value> of + the trailer that this option would produce. + -When this option is specified, the behavior is as if a special -'<token>=<value>' argument were added at the beginning of the command -line, where <value> is taken to be the standard output of the -specified command with any leading and trailing whitespace trimmed -off. +When the specified command is first called to add a trailer +with the specified <token>, the behavior is as if a special +'--trailer <token>=<value>' argument was added at the beginning +of the "git interpret-trailers" command, where <value> +is taken to be the standard output of the command with any +leading and trailing whitespace trimmed off. + -If the command contains the `$ARG` string, this string will be -replaced with the <value> part of an existing trailer with the same -<token>, if any, before the command is launched. +If some '--trailer <token>=<value>' arguments are also passed +on the command line, the command is called again once for each +of these arguments with the same <token>. And the <value> part +of these arguments, if any, will be used to replace the first +occurrence of substring `$ARG` in the command. This way the +command can produce a <value> computed from the <value> passed +in the '--trailer <token>=<value>' argument. + -If some '<token>=<value>' arguments are also passed on the command -line, when a 'trailer.<token>.command' is configured, the command will -also be executed for each of these arguments. And the <value> part of -these arguments, if any, will be used to replace the `$ARG` string in -the command. +For consistency, the first occurrence of substring `$ARG` is +also replaced, this time with the empty string, in the command +when the command is first called to add a trailer with the +specified <token>. EXAMPLES --------
Signature · 1 line
gitgitgadget
PATCH v12 2/2 trailer: add new .cmd config option
In reply to ZheNing Hu via GitGitGadgetFrom: ZheNing Hu <[email protected]>
The trailer.<token>.command configuration variable specifies a command (run via the shell, so it does not have to be a single name or path to the command, but can be a shell script), and the first occurrence of substring $ARG is replaced with the value given to the interpret-trailer command for the token in a '--trailer <token>=<value>' argument.
This has three downsides:
* The use of $ARG in the mechanism misleads the users that the value is passed in the shell variable, and tempt them to use $ARG more than once, but that would not work, as the second and subsequent $ARG are not replaced.
* Because $ARG is textually replaced without regard to the shell language syntax, even '$ARG' (inside a single-quote pair), which a user would expect to stay intact, would be replaced, and worse, if the value had an unmatched single quote (imagine a name like "O'Connor", substituted into NAME='$ARG' to make it NAME='O'Connor'), it would result in a broken command that is not syntactically correct (or worse).
* The first occurrence of substring $ARG will be replaced with the empty string, in the command when the command is first called to add a trailer with the specified <token>. This is a bad design, the nature of automatic execution causes it to add a trailer that we don't expect.
Introduce a new trailer.<token>.cmd configuration that takes higher precedence to deprecate and eventually remove trailer.<token>.command, which passes the value as an argument to the command. Instead of "$ARG", users can refer to the value as positional argument, $1, in their scripts. At the same time, in order to allowgit interpret-trailers to better simulate the behavior of git command -s, 'trailer.<token>.cmd' will not automatically execute.
--- Documentation/git-interpret-trailers.txt | 75 ++++++++++++++++++--- t/t7513-interpret-trailers.sh | 84 ++++++++++++++++++++++++ trailer.c | 35 +++++++--- 3 files changed, 175 insertions(+), 19 deletions(-)
Documentation/git-interpret-trailers.txt +66 -9
@@ -232,6 +232,20 @@ trailer.<token>.ifmissing:: that option for trailers with the specified <token>. trailer.<token>.command:: + This option behaves in the same way as 'trailer.<token>.cmd', except + that it doesn't pass anything as argument to the specified command. + Instead the first occurrence of substring $ARG is replaced by the + value that would be passed as argument. ++ +The 'trailer.<token>.command' option has been deprecated in favor of +'trailer.<token>.cmd' due to the fact that $ARG in the user's command is +only replaced once and that the original way of replacing $ARG is not safe. ++ +When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given +for the same <token>, 'trailer.<token>.cmd' is used and +'trailer.<token>.command' is ignored. + +trailer.<token>.cmd:: This option can be used to specify a shell command that will be called: once to automatically add a trailer with the specified <token>, and then each time a '--trailer <token>=<value>' argument to modify the <value> of
@@ -247,15 +261,9 @@ leading and trailing whitespace trimmed off. If some '--trailer <token>=<value>' arguments are also passed on the command line, the command is called again once for each of these arguments with the same <token>. And the <value> part -of these arguments, if any, will be used to replace the first -occurrence of substring `$ARG` in the command. This way the -command can produce a <value> computed from the <value> passed -in the '--trailer <token>=<value>' argument. -+ -For consistency, the first occurrence of substring `$ARG` is -also replaced, this time with the empty string, in the command -when the command is first called to add a trailer with the -specified <token>. +of these arguments, if any, will be passed to the command as its +first argument. This way the command can produce a <value> computed +from the <value> passed in the '--trailer <token>=<value>' argument. EXAMPLES --------
@@ -338,6 +346,55 @@ subject Fix #42 ------------ +* Configure a 'help' trailer with a cmd use a script `glog-find-author` + which search specified author identity from git log in git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-find-author +#!/bin/sh +test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true +$ git config trailer.help.key "Helped-by: " +$ git config trailer.help.ifExists "addIfDifferentNeighbor" +$ git config trailer.help.cmd "~/bin/glog-find-author" +$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Helped-by: Junio C Hamano <[email protected]> +Helped-by: Christian Couder <[email protected]> +------------ + +* Configure a 'ref' trailer with a cmd use a script `glog-grep` + to grep last relevant commit from git log in the git repository + and show how it works: ++ +------------ +$ cat ~/bin/glog-grep +#!/bin/sh +test -n "$1" && git log --grep "$1" --pretty=reference -1 || true +$ git config trailer.ref.key "Reference-to: " +$ git config trailer.ref.ifExists "replace" +$ git config trailer.ref.cmd "~/bin/glog-grep" +$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF +> subject +> +> message +> +> EOF +subject + +message + +Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07) +------------ + * Configure a 'see' trailer with a command to show the subject of a commit that is related, and show how it works: +
t/t7513-interpret-trailers.sh +84 -0
96 lines not on this page · raw message
trailer.c +25 -10
@@ -14,6 +14,7 @@ struct conf_info {char *name;char *key;char *command; +char *cmd;enum trailer_where where;enum trailer_if_exists if_exists;enum trailer_if_missing if_missing;
@@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)free (item->conf.name);free (item->conf.key);free (item->conf.command); +free (item->conf.cmd);free (item->token);free (item->value);free (item);
@@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,return 1 ; } -static char *apply_command (const char *command,const char *arg) +static char *apply_command (struct conf_info *conf,const char *arg) {struct strbuf cmd =STRBUF_INIT ;struct strbuf buf =STRBUF_INIT ;struct child_process cp =CHILD_PROCESS_INIT ;char *result; -strbuf_addstr (&cmd, command); -if (arg) -strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); - -strvec_push (&cp.args, cmd.buf); +if (conf->cmd) { +strbuf_addstr (&cmd, conf->cmd); +strvec_push (&cp.args, cmd.buf); +if (arg) +strvec_push (&cp.args, arg); + }else if (conf->command) { +strbuf_addstr (&cmd, conf->command); +if (arg) +strbuf_replace (&cmd,TRAILER_ARG_STRING , arg); +strvec_push (&cp.args, cmd.buf); + } cp.env = local_repo_env; cp.no_stdin =1 ; cp.use_shell =1 ;
@@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)static void apply_item_command (struct trailer_item *in_tok,struct arg_item *arg_tok) { -if (arg_tok->conf.command) { +if (arg_tok->conf.command || arg_tok->conf.cmd) {const char *arg;if (arg_tok->value && arg_tok->value[0 ]) { arg = arg_tok->value;
@@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *argelse arg =xstrdup ("" ); } - arg_tok->value =apply_command (arg_tok->conf.command, arg); + arg_tok->value =apply_command (&arg_tok->conf, arg);free ((char *)arg); } }
@@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src) dst->name =xstrdup_or_null (src->name); dst->key =xstrdup_or_null (src->key); dst->command =xstrdup_or_null (src->command); + dst->cmd =xstrdup_or_null (src->cmd); }static struct arg_item *get_conf_item (const char *name)
@@ -454,8 +463,8 @@ static struct arg_item *get_conf_item(const char *name)return item; } -enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_WHERE , -TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; +enum trailer_info_type {TRAILER_KEY ,TRAILER_COMMAND ,TRAILER_CMD , +TRAILER_WHERE ,TRAILER_IF_EXISTS ,TRAILER_IF_MISSING }; static struct { const char *name;
@@ -463,6 +472,7 @@ static struct { } trailer_config_items[] = { { "key", TRAILER_KEY }, { "command", TRAILER_COMMAND }, + { "cmd", TRAILER_CMD }, { "where", TRAILER_WHERE }, { "ifexists", TRAILER_IF_EXISTS }, { "ifmissing", TRAILER_IF_MISSING }
@@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)warning (_ ("more than one %s" ), conf_key); conf->command =xstrdup (value);break ; +case TRAILER_CMD : +if (conf->cmd) +warning (_ ("more than one %s" ), conf_key); + conf->cmd =xstrdup (value); +break ;case TRAILER_WHERE :if (trailer_set_where (&conf->where, value))warning (_ ("unknown value '%s' for key '%s'" ), value, conf_key);
Signature · 1 line
gitgitgadget