Merge branch 'jk/trailers-parse'
authorJunio C Hamano <gitster@pobox.com>
Sun, 27 Aug 2017 05:55:04 +0000 (22:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 27 Aug 2017 05:55:04 +0000 (22:55 -0700)
"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

1  2 
Documentation/git-interpret-trailers.txt
Documentation/pretty-formats.txt
builtin/interpret-trailers.c
pretty.c
t/t7513-interpret-trailers.sh
trailer.c
trailer.h

@@@ -80,29 -83,22 +83,45 @@@ OPTION
        trailer to the input messages. See the description of this
        command.
  
 +--where <placement>::
 +--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 <action>::
 +--no-if-exists::
 +      Specify what action will be performed when there is already at
 +      least one trailer with the same <token> 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 <action>::
 +--no-if-missing::
 +      Specify what action will be performed when there is no other
 +      trailer with the same <token> 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
  -----------------------
  
Simple merge
@@@ -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 pretty.c
Simple merge
Simple merge
diff --cc 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;
                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
+++ b/trailer.h
@@@ -49,22 -22,19 +49,33 @@@ struct trailer_info 
        size_t trailer_nr;
  };
  
- void process_trailers(const char *file, int in_place, int trim_empty,
 +/*
 + * 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;
 +};
 +
 -                    struct string_list *trailers);
+ 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 list_head *new_trailer_head);
  
  void trailer_info_get(struct trailer_info *info, const char *str);