From 3c6eb4ec50d9a4a9017fb8c1f220d12dceb206b1 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 31 Oct 2021 13:15:08 -0400 Subject: [PATCH 1/3] pretty.c: rework describe options parsing for better extensibility It contains option arguments only, not options. We would like to add option support here too, but to do that we need to distinguish between different types of options. Lay out the groundwork for distinguishing between bools, strings, etc. and move the central logic (validating values and pushing new arguments to *args) into the successful match, because that will be fairly conditional on what type of argument is being parsed. Signed-off-by: Eli Schwartz Signed-off-by: Junio C Hamano --- pretty.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pretty.c b/pretty.c index 73b5ead509..6e945fdb18 100644 --- a/pretty.c +++ b/pretty.c @@ -1216,28 +1216,39 @@ int format_set_trailers_options(struct process_trailer_options *opts, static size_t parse_describe_args(const char *start, struct strvec *args) { - const char *options[] = { "match", "exclude" }; + struct { + char *name; + enum { + DESCRIBE_ARG_STRING, + } type; + } option[] = { + { "exclude", DESCRIBE_ARG_STRING }, + { "match", DESCRIBE_ARG_STRING }, + }; const char *arg = start; for (;;) { - const char *matched = NULL; + int found = 0; const char *argval; size_t arglen = 0; int i; - for (i = 0; i < ARRAY_SIZE(options); i++) { - if (match_placeholder_arg_value(arg, options[i], &arg, - &argval, &arglen)) { - matched = options[i]; + for (i = 0; !found && i < ARRAY_SIZE(option); i++) { + switch (option[i].type) { + case DESCRIBE_ARG_STRING: + if (match_placeholder_arg_value(arg, option[i].name, &arg, + &argval, &arglen)) { + if (!arglen) + return 0; + strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval); + found = 1; + } break; } } - if (!matched) + if (!found) break; - if (!arglen) - return 0; - strvec_pushf(args, "--%s=%.*s", matched, (int)arglen, argval); } return arg - start; } From 1d517ceab98fd5c3c1a8fb6ef575b44c31ea7a9e Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 31 Oct 2021 13:15:09 -0400 Subject: [PATCH 2/3] pretty: add tag option to %(describe) The %(describe) placeholder by default, like `git describe`, only supports annotated tags. However, some people do use lightweight tags for releases, and would like to describe those anyway. The command line tool has an option to support this. Teach the placeholder to support this as well. Signed-off-by: Eli Schwartz Signed-off-by: Junio C Hamano --- Documentation/pretty-formats.txt | 12 +++++++----- pretty.c | 12 ++++++++++++ t/t4205-log-pretty-formats.sh | 8 ++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index ef6bd420ae..1ee47bd4a3 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -220,6 +220,8 @@ The placeholders are: inconsistent when tags are added or removed at the same time. + +** 'tags[=]': Instead of only considering annotated tags, + consider lightweight tags as well. ** 'match=': Only consider tags matching the given `glob(7)` pattern, excluding the "refs/tags/" prefix. ** 'exclude=': Do not consider tags matching the given @@ -273,11 +275,6 @@ endif::git-rev-list[] If any option is provided multiple times the last occurrence wins. + -The boolean options accept an optional value `[=]`. The values -`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean" -sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean -option is given with no value, it's enabled. -+ ** 'key=': only show trailers with specified key. Matching is done case-insensitively and trailing colon is optional. If option is given multiple times trailer lines matching any of the keys are @@ -313,6 +310,11 @@ insert an empty string unless we are traversing reflog entries (e.g., by decoration format if `--decorate` was not already provided on the command line. +The boolean options accept an optional value `[=]`. The values +`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean" +sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean +option is given with no value, it's enabled. + If you add a `+` (plus sign) after '%' of a placeholder, a line-feed is inserted immediately before the expansion if and only if the placeholder expands to a non-empty string. diff --git a/pretty.c b/pretty.c index 6e945fdb18..52741fa0a9 100644 --- a/pretty.c +++ b/pretty.c @@ -1219,9 +1219,11 @@ static size_t parse_describe_args(const char *start, struct strvec *args) struct { char *name; enum { + DESCRIBE_ARG_BOOL, DESCRIBE_ARG_STRING, } type; } option[] = { + { "tags", DESCRIBE_ARG_BOOL}, { "exclude", DESCRIBE_ARG_STRING }, { "match", DESCRIBE_ARG_STRING }, }; @@ -1231,10 +1233,20 @@ static size_t parse_describe_args(const char *start, struct strvec *args) int found = 0; const char *argval; size_t arglen = 0; + int optval = 0; int i; for (i = 0; !found && i < ARRAY_SIZE(option); i++) { switch (option[i].type) { + case DESCRIBE_ARG_BOOL: + if (match_placeholder_bool_arg(arg, option[i].name, &arg, &optval)) { + if (optval) + strvec_pushf(args, "--%s", option[i].name); + else + strvec_pushf(args, "--no-%s", option[i].name); + found = 1; + } + break; case DESCRIBE_ARG_STRING: if (match_placeholder_arg_value(arg, option[i].name, &arg, &argval, &arglen)) { diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 5865daa8f8..d4acf8882f 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -1002,4 +1002,12 @@ test_expect_success '%(describe:exclude=...) vs git describe --exclude ...' ' test_cmp expect actual ' +test_expect_success '%(describe:tags) vs git describe --tags' ' + test_when_finished "git tag -d tagname" && + git tag tagname && + git describe --tags >expect && + git log -1 --format="%(describe:tags)" >actual && + test_cmp expect actual +' + test_done From eccd97d0b02a87db0b0e828dd4f0b441c5462a9c Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 31 Oct 2021 13:15:10 -0400 Subject: [PATCH 3/3] pretty: add abbrev option to %(describe) The %(describe) placeholder by default, like `git describe`, uses a seven-character abbreviated commit object name. This may not be sufficient to fully describe all commits in a given repository, resulting in a placeholder replacement changing its length because the repository grew in size. This could cause the output of git-archive to change. Add the --abbrev option to `git describe` to the placeholder interface in order to provide tools to the user for fine-tuning project defaults and ensure reproducible archives. One alternative would be to just always specify --abbrev=40 but this may be a bit too biased... Signed-off-by: Eli Schwartz Signed-off-by: Junio C Hamano --- Documentation/pretty-formats.txt | 4 ++++ pretty.c | 15 +++++++++++++++ t/t4205-log-pretty-formats.sh | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 1ee47bd4a3..9e943fb74b 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -222,6 +222,10 @@ The placeholders are: + ** 'tags[=]': Instead of only considering annotated tags, consider lightweight tags as well. +** 'abbrev=': Instead of using the default number of hexadecimal digits + (which will vary according to the number of objects in the repository with a + default of 7) of the abbreviated object name, use digits, or as many + digits as needed to form a unique object name. ** 'match=': Only consider tags matching the given `glob(7)` pattern, excluding the "refs/tags/" prefix. ** 'exclude=': Do not consider tags matching the given diff --git a/pretty.c b/pretty.c index 52741fa0a9..d5a34eff91 100644 --- a/pretty.c +++ b/pretty.c @@ -1220,10 +1220,12 @@ static size_t parse_describe_args(const char *start, struct strvec *args) char *name; enum { DESCRIBE_ARG_BOOL, + DESCRIBE_ARG_INTEGER, DESCRIBE_ARG_STRING, } type; } option[] = { { "tags", DESCRIBE_ARG_BOOL}, + { "abbrev", DESCRIBE_ARG_INTEGER }, { "exclude", DESCRIBE_ARG_STRING }, { "match", DESCRIBE_ARG_STRING }, }; @@ -1247,6 +1249,19 @@ static size_t parse_describe_args(const char *start, struct strvec *args) found = 1; } break; + case DESCRIBE_ARG_INTEGER: + if (match_placeholder_arg_value(arg, option[i].name, &arg, + &argval, &arglen)) { + char *endptr; + if (!arglen) + return 0; + strtol(argval, &endptr, 10); + if (endptr - argval != arglen) + return 0; + strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval); + found = 1; + } + break; case DESCRIBE_ARG_STRING: if (match_placeholder_arg_value(arg, option[i].name, &arg, &argval, &arglen)) { diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index d4acf8882f..35eef4c865 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -1010,4 +1010,12 @@ test_expect_success '%(describe:tags) vs git describe --tags' ' test_cmp expect actual ' +test_expect_success '%(describe:abbrev=...) vs git describe --abbrev=...' ' + test_when_finished "git tag -d tagname" && + git tag -a -m tagged tagname && + git describe --abbrev=15 >expect && + git log -1 --format="%(describe:abbrev=15)" >actual && + test_cmp expect actual +' + test_done