Merge branch 'bc/vcs-svn-cleanup' into next
[gitweb.git] / trailer.c
index 07580af9c07ae343f8e09aa2241ecc7eb1d51cd3..c30e3a0c0415db110bfce8d29514a8258647d7f7 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "config.h"
 #include "string-list.h"
 #include "run-command.h"
 #include "commit.h"
  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
  */
 
-enum action_where { WHERE_END, WHERE_AFTER, WHERE_BEFORE, WHERE_START };
-enum action_if_exists { EXISTS_ADD_IF_DIFFERENT_NEIGHBOR, EXISTS_ADD_IF_DIFFERENT,
-                       EXISTS_ADD, EXISTS_REPLACE, EXISTS_DO_NOTHING };
-enum action_if_missing { MISSING_ADD, MISSING_DO_NOTHING };
-
 struct conf_info {
        char *name;
        char *key;
        char *command;
-       enum action_where where;
-       enum action_if_exists if_exists;
-       enum action_if_missing if_missing;
+       enum trailer_where where;
+       enum trailer_if_exists if_exists;
+       enum trailer_if_missing if_missing;
 };
 
 static struct conf_info default_conf_info;
@@ -62,7 +58,7 @@ static const char *git_generated_prefixes[] = {
                pos != (head); \
                pos = is_reverse ? pos->prev : pos->next)
 
-static int after_or_end(enum action_where where)
+static int after_or_end(enum trailer_where where)
 {
        return (where == WHERE_AFTER) || (where == WHERE_END);
 }
@@ -202,7 +198,7 @@ static int check_if_different(struct trailer_item *in_tok,
                              int check_all,
                              struct list_head *head)
 {
-       enum action_where where = arg_tok->conf.where;
+       enum trailer_where where = arg_tok->conf.where;
        struct list_head *next_head;
        do {
                if (same_trailer(in_tok, arg_tok))
@@ -301,13 +297,16 @@ static void apply_arg_if_exists(struct trailer_item *in_tok,
                else
                        free_arg_item(arg_tok);
                break;
+       default:
+               die("BUG: trailer.c: unhandled value %d",
+                   arg_tok->conf.if_exists);
        }
 }
 
 static void apply_arg_if_missing(struct list_head *head,
                                 struct arg_item *arg_tok)
 {
-       enum action_where where;
+       enum trailer_where where;
        struct trailer_item *to_add;
 
        switch (arg_tok->conf.if_missing) {
@@ -322,6 +321,10 @@ static void apply_arg_if_missing(struct list_head *head,
                        list_add_tail(&to_add->list, head);
                else
                        list_add(&to_add->list, head);
+               break;
+       default:
+               die("BUG: trailer.c: unhandled value %d",
+                   arg_tok->conf.if_missing);
        }
 }
 
@@ -332,7 +335,7 @@ static int find_same_and_apply_arg(struct list_head *head,
        struct trailer_item *in_tok;
        struct trailer_item *on_tok;
 
-       enum action_where where = arg_tok->conf.where;
+       enum trailer_where where = arg_tok->conf.where;
        int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE);
        int backwards = after_or_end(where);
        struct trailer_item *start_tok;
@@ -374,44 +377,50 @@ static void process_trailers_lists(struct list_head *head,
        }
 }
 
-static int set_where(struct conf_info *item, const char *value)
+int trailer_set_where(enum trailer_where *item, const char *value)
 {
-       if (!strcasecmp("after", value))
-               item->where = WHERE_AFTER;
+       if (!value)
+               *item = WHERE_DEFAULT;
+       else if (!strcasecmp("after", value))
+               *item = WHERE_AFTER;
        else if (!strcasecmp("before", value))
-               item->where = WHERE_BEFORE;
+               *item = WHERE_BEFORE;
        else if (!strcasecmp("end", value))
-               item->where = WHERE_END;
+               *item = WHERE_END;
        else if (!strcasecmp("start", value))
-               item->where = WHERE_START;
+               *item = WHERE_START;
        else
                return -1;
        return 0;
 }
 
-static int set_if_exists(struct conf_info *item, const char *value)
+int trailer_set_if_exists(enum trailer_if_exists *item, const char *value)
 {
-       if (!strcasecmp("addIfDifferent", value))
-               item->if_exists = EXISTS_ADD_IF_DIFFERENT;
+       if (!value)
+               *item = EXISTS_DEFAULT;
+       else if (!strcasecmp("addIfDifferent", value))
+               *item = EXISTS_ADD_IF_DIFFERENT;
        else if (!strcasecmp("addIfDifferentNeighbor", value))
-               item->if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
+               *item = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
        else if (!strcasecmp("add", value))
-               item->if_exists = EXISTS_ADD;
+               *item = EXISTS_ADD;
        else if (!strcasecmp("replace", value))
-               item->if_exists = EXISTS_REPLACE;
+               *item = EXISTS_REPLACE;
        else if (!strcasecmp("doNothing", value))
-               item->if_exists = EXISTS_DO_NOTHING;
+               *item = EXISTS_DO_NOTHING;
        else
                return -1;
        return 0;
 }
 
-static int set_if_missing(struct conf_info *item, const char *value)
+int trailer_set_if_missing(enum trailer_if_missing *item, const char *value)
 {
-       if (!strcasecmp("doNothing", value))
-               item->if_missing = MISSING_DO_NOTHING;
+       if (!value)
+               *item = MISSING_DEFAULT;
+       else if (!strcasecmp("doNothing", value))
+               *item = MISSING_DO_NOTHING;
        else if (!strcasecmp("add", value))
-               item->if_missing = MISSING_ADD;
+               *item = MISSING_ADD;
        else
                return -1;
        return 0;
@@ -471,15 +480,18 @@ static int git_trailer_default_config(const char *conf_key, const char *value, v
        variable_name = strrchr(trailer_item, '.');
        if (!variable_name) {
                if (!strcmp(trailer_item, "where")) {
-                       if (set_where(&default_conf_info, value) < 0)
+                       if (trailer_set_where(&default_conf_info.where,
+                                             value) < 0)
                                warning(_("unknown value '%s' for key '%s'"),
                                        value, conf_key);
                } else if (!strcmp(trailer_item, "ifexists")) {
-                       if (set_if_exists(&default_conf_info, value) < 0)
+                       if (trailer_set_if_exists(&default_conf_info.if_exists,
+                                                 value) < 0)
                                warning(_("unknown value '%s' for key '%s'"),
                                        value, conf_key);
                } else if (!strcmp(trailer_item, "ifmissing")) {
-                       if (set_if_missing(&default_conf_info, value) < 0)
+                       if (trailer_set_if_missing(&default_conf_info.if_missing,
+                                                  value) < 0)
                                warning(_("unknown value '%s' for key '%s'"),
                                        value, conf_key);
                } else if (!strcmp(trailer_item, "separators")) {
@@ -533,15 +545,15 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)
                conf->command = xstrdup(value);
                break;
        case TRAILER_WHERE:
-               if (set_where(conf, value))
+               if (trailer_set_where(&conf->where, value))
                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
                break;
        case TRAILER_IF_EXISTS:
-               if (set_if_exists(conf, value))
+               if (trailer_set_if_exists(&conf->if_exists, value))
                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
                break;
        case TRAILER_IF_MISSING:
-               if (set_if_missing(conf, value))
+               if (trailer_set_if_missing(&conf->if_missing, value))
                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
                break;
        default:
@@ -556,6 +568,9 @@ static void ensure_configured(void)
                return;
 
        /* Default config must be setup first */
+       default_conf_info.where = WHERE_END;
+       default_conf_info.if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
+       default_conf_info.if_missing = MISSING_ADD;
        git_config(git_trailer_default_config, NULL);
        git_config(git_trailer_config, NULL);
        configured = 1;
@@ -659,19 +674,27 @@ static struct trailer_item *add_trailer_item(struct list_head *head, char *tok,
 }
 
 static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
-                        const struct conf_info *conf)
+                        const struct conf_info *conf,
+                        const struct new_trailer_item *new_trailer_item)
 {
        struct arg_item *new = xcalloc(sizeof(*new), 1);
        new->token = tok;
        new->value = val;
        duplicate_conf(&new->conf, conf);
+       if (new_trailer_item) {
+               if (new_trailer_item->where != WHERE_DEFAULT)
+                       new->conf.where = new_trailer_item->where;
+               if (new_trailer_item->if_exists != EXISTS_DEFAULT)
+                       new->conf.if_exists = new_trailer_item->if_exists;
+               if (new_trailer_item->if_missing != MISSING_DEFAULT)
+                       new->conf.if_missing = new_trailer_item->if_missing;
+       }
        list_add_tail(&new->list, arg_head);
 }
 
 static void process_command_line_args(struct list_head *arg_head,
-                                     struct string_list *trailers)
+                                     struct list_head *new_trailer_head)
 {
-       struct string_list_item *tr;
        struct arg_item *item;
        struct strbuf tok = STRBUF_INIT;
        struct strbuf val = STRBUF_INIT;
@@ -691,26 +714,29 @@ static void process_command_line_args(struct list_head *arg_head,
                        add_arg_item(arg_head,
                                     xstrdup(token_from_item(item, NULL)),
                                     xstrdup(""),
-                                    &item->conf);
+                                    &item->conf, NULL);
        }
 
        /* Add an arg item for each trailer on the command line */
-       for_each_string_list_item(tr, trailers) {
-               int separator_pos = find_separator(tr->string, cl_separators);
+       list_for_each(pos, new_trailer_head) {
+               struct new_trailer_item *tr =
+                       list_entry(pos, struct new_trailer_item, list);
+               int separator_pos = find_separator(tr->text, cl_separators);
+
                if (separator_pos == 0) {
                        struct strbuf sb = STRBUF_INIT;
-                       strbuf_addstr(&sb, tr->string);
+                       strbuf_addstr(&sb, tr->text);
                        strbuf_trim(&sb);
                        error(_("empty trailer token in trailer '%.*s'"),
                              (int) sb.len, sb.buf);
                        strbuf_release(&sb);
                } else {
-                       parse_trailer(&tok, &val, &conf, tr->string,
+                       parse_trailer(&tok, &val, &conf, tr->text,
                                      separator_pos);
                        add_arg_item(arg_head,
                                     strbuf_detach(&tok, NULL),
                                     strbuf_detach(&val, NULL),
-                                    conf);
+                                    conf, tr);
                }
        }
 
@@ -1002,7 +1028,7 @@ static FILE *create_in_place_tempfile(const char *file)
 
 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);
        struct strbuf sb = STRBUF_INIT;
@@ -1021,7 +1047,7 @@ void process_trailers(const char *file,
 
        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);
        }
 
@@ -1095,8 +1121,36 @@ static void format_trailer_info(struct strbuf *out,
                                const struct trailer_info *info,
                                const struct process_trailer_options *opts)
 {
-       strbuf_add(out, info->trailer_start,
-                  info->trailer_end - info->trailer_start);
+       int i;
+
+       /* If we want the whole block untouched, we can take the fast path. */
+       if (!opts->only_trailers && !opts->unfold) {
+               strbuf_add(out, info->trailer_start,
+                          info->trailer_end - info->trailer_start);
+               return;
+       }
+
+       for (i = 0; i < info->trailer_nr; i++) {
+               char *trailer = info->trailers[i];
+               int separator_pos = find_separator(trailer, separators);
+
+               if (separator_pos >= 1) {
+                       struct strbuf tok = STRBUF_INIT;
+                       struct strbuf val = STRBUF_INIT;
+
+                       parse_trailer(&tok, &val, NULL, trailer, separator_pos);
+                       if (opts->unfold)
+                               unfold_value(&val);
+
+                       strbuf_addf(out, "%s: %s\n", tok.buf, val.buf);
+                       strbuf_release(&tok);
+                       strbuf_release(&val);
+
+               } else if (!opts->only_trailers) {
+                       strbuf_addstr(out, trailer);
+               }
+       }
+
 }
 
 void format_trailers_from_commit(struct strbuf *out, const char *msg,