From: Junio C Hamano Date: Sun, 27 Aug 2017 05:55:04 +0000 (-0700) Subject: Merge branch 'jk/trailers-parse' X-Git-Tag: v2.15.0-rc0~127 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=06cf4f2d87d670f6d49c208fa41933941205da90;p=git Merge branch 'jk/trailers-parse' "git interpret-trailers" has been taught a "--parse" and a few other options to make it easier for scripts to grab existing trailer lines from a commit log message. * jk/trailers-parse: doc/interpret-trailers: fix "the this" typo pretty: support normalization options for %(trailers) t4205: refactor %(trailers) tests pretty: move trailer formatting to trailer.c interpret-trailers: add --parse convenience option interpret-trailers: add an option to unfold values interpret-trailers: add an option to show only existing trailers interpret-trailers: add an option to show only the trailers trailer: put process_trailers() options into a struct --- 06cf4f2d87d670f6d49c208fa41933941205da90 diff --cc Documentation/git-interpret-trailers.txt index 0ef93204f1,2e22210734..9dd19a1dd9 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@@ -80,29 -83,22 +83,45 @@@ OPTION trailer to the input messages. See the description of this command. +--where :: +--no-where:: + Specify where all new trailers will be added. A setting + provided with '--where' overrides all configuration variables + and applies to all '--trailer' options until the next occurrence of + '--where' or '--no-where'. + +--if-exists :: +--no-if-exists:: + Specify what action will be performed when there is already at + least one trailer with the same in the message. A setting + provided with '--if-exists' overrides all configuration variables + and applies to all '--trailer' options until the next occurrence of + '--if-exists' or '--no-if-exists'. + +--if-missing :: +--no-if-missing:: + Specify what action will be performed when there is no other + trailer with the same in the message. A setting + provided with '--if-missing' overrides all configuration variables + and applies to all '--trailer' options until the next occurrence of + '--if-missing' or '--no-if-missing'. + + --only-trailers:: + Output only the trailers, not any other parts of the input. + + --only-input:: + Output only trailers that exist in the input; do not add any + from the command-line or by following configured `trailer.*` + rules. + + --unfold:: + Remove any whitespace-continuation in trailers, so that each + trailer appears on a line by itself with its full content. + + --parse:: + A convenience alias for `--only-trailers --only-input + --unfold`. + CONFIGURATION VARIABLES ----------------------- diff --cc builtin/interpret-trailers.c index d7cbaf60f9,555111a078..b742539d4d --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@@ -16,99 -16,54 +16,119 @@@ static const char * const git_interpret NULL }; +static enum trailer_where where; +static enum trailer_if_exists if_exists; +static enum trailer_if_missing if_missing; + +static int option_parse_where(const struct option *opt, + const char *arg, int unset) +{ + return trailer_set_where(&where, arg); +} + +static int option_parse_if_exists(const struct option *opt, + const char *arg, int unset) +{ + return trailer_set_if_exists(&if_exists, arg); +} + +static int option_parse_if_missing(const struct option *opt, + const char *arg, int unset) +{ + return trailer_set_if_missing(&if_missing, arg); +} + +static void new_trailers_clear(struct list_head *trailers) +{ + struct list_head *pos, *tmp; + struct new_trailer_item *item; + + list_for_each_safe(pos, tmp, trailers) { + item = list_entry(pos, struct new_trailer_item, list); + list_del(pos); + free(item); + } +} + +static int option_parse_trailer(const struct option *opt, + const char *arg, int unset) +{ + struct list_head *trailers = opt->value; + struct new_trailer_item *item; + + if (unset) { + new_trailers_clear(trailers); + return 0; + } + + if (!arg) + return -1; + + item = xmalloc(sizeof(*item)); + item->text = arg; + item->where = where; + item->if_exists = if_exists; + item->if_missing = if_missing; + list_add_tail(&item->list, trailers); + return 0; +} + + static int parse_opt_parse(const struct option *opt, const char *arg, + int unset) + { + struct process_trailer_options *v = opt->value; + v->only_trailers = 1; + v->only_input = 1; + v->unfold = 1; + return 0; + } + int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) { - int in_place = 0; - int trim_empty = 0; + struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; - struct string_list trailers = STRING_LIST_INIT_NODUP; + LIST_HEAD(trailers); struct option options[] = { - OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")), - OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")), + OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")), + OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")), + + OPT_CALLBACK(0, "where", NULL, N_("action"), + N_("where to place the new trailer"), option_parse_where), + OPT_CALLBACK(0, "if-exists", NULL, N_("action"), + N_("action if trailer already exists"), option_parse_if_exists), + OPT_CALLBACK(0, "if-missing", NULL, N_("action"), + N_("action if trailer is missing"), option_parse_if_missing), + + OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")), + OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")), + OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")), + { OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse }, - OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), - N_("trailer(s) to add")), + OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"), + N_("trailer(s) to add"), option_parse_trailer), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_interpret_trailers_usage, 0); - if (opts.only_input && trailers.nr) ++ if (opts.only_input && !list_empty(&trailers)) + usage_msg_opt( + _("--trailer with --only-input does not make sense"), + git_interpret_trailers_usage, + options); + if (argc) { int i; for (i = 0; i < argc; i++) - process_trailers(argv[i], in_place, trim_empty, &trailers); + process_trailers(argv[i], &opts, &trailers); } else { - if (in_place) + if (opts.in_place) die(_("no input file given for in-place editing")); - process_trailers(NULL, in_place, trim_empty, &trailers); + process_trailers(NULL, &opts, &trailers); } - string_list_clear(&trailers, 0); + new_trailers_clear(&trailers); return 0; } diff --cc trailer.c index d441cd9ac6,6ec5505dc4..c30e3a0c04 --- a/trailer.c +++ b/trailer.c @@@ -993,11 -1000,11 +1026,11 @@@ static FILE *create_in_place_tempfile(c return outfile; } - void process_trailers(const char *file, int in_place, int trim_empty, + void process_trailers(const char *file, + const struct process_trailer_options *opts, - struct string_list *trailers) + struct list_head *new_trailer_head) { LIST_HEAD(head); - LIST_HEAD(arg_head); struct strbuf sb = STRBUF_INIT; int trailer_end; FILE *outfile = stdout; @@@ -1010,13 -1017,15 +1043,15 @@@ outfile = create_in_place_tempfile(file); /* Print the lines before the trailers */ - trailer_end = process_input_file(outfile, sb.buf, &head); - - process_command_line_args(&arg_head, new_trailer_head); + trailer_end = process_input_file(outfile, sb.buf, &head, opts); - process_trailers_lists(&head, &arg_head); + if (!opts->only_input) { + LIST_HEAD(arg_head); - process_command_line_args(&arg_head, trailers); ++ process_command_line_args(&arg_head, new_trailer_head); + process_trailers_lists(&head, &arg_head); + } - print_all(outfile, &head, trim_empty); + print_all(outfile, &head, opts); free_all(&head); diff --cc trailer.h index 973b533a1a,a172811022..6d7f8c2a52 --- a/trailer.h +++ b/trailer.h @@@ -49,22 -22,19 +49,33 @@@ struct trailer_info size_t trailer_nr; }; +/* + * A list that represents newly-added trailers, such as those provided + * with the --trailer command line option of git-interpret-trailers. + */ +struct new_trailer_item { + struct list_head list; + + const char *text; + + enum trailer_where where; + enum trailer_if_exists if_exists; + enum trailer_if_missing if_missing; +}; + - void process_trailers(const char *file, int in_place, int trim_empty, + struct process_trailer_options { + int in_place; + int trim_empty; + int only_trailers; + int only_input; + int unfold; + }; + + #define PROCESS_TRAILER_OPTIONS_INIT {0} + + void process_trailers(const char *file, + const struct process_trailer_options *opts, - struct string_list *trailers); + struct list_head *new_trailer_head); void trailer_info_get(struct trailer_info *info, const char *str);