From: Junio C Hamano Date: Wed, 2 Sep 2015 19:50:21 +0000 (-0700) Subject: Merge branch 'cc/trailers-corner-case-fix' X-Git-Tag: v2.6.0-rc0~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/cdd00dfe9431b431e488d0bb77d39f1461a9dcc5?ds=inline;hp=-c Merge branch 'cc/trailers-corner-case-fix' The "interpret-trailers" helper mistook a multi-paragraph title of a commit log message with a colon in it as the end of the trailer block. * cc/trailers-corner-case-fix: trailer: support multiline title --- cdd00dfe9431b431e488d0bb77d39f1461a9dcc5 diff --combined t/t7513-interpret-trailers.sh index 9577b4effb,1abec57f6e..322c436a49 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@@ -112,6 -112,20 +112,20 @@@ test_expect_success 'with only a title test_cmp expected actual ' + test_expect_success 'with multiline title in the message' ' + cat >expected <<-\EOF && + place of + code: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + printf "%s\n" "place of" "code: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual + ' + test_expect_success 'with config setup' ' git config trailer.ack.key "Acked-by: " && cat >expected <<-\EOF && @@@ -226,7 -240,7 +240,7 @@@ test_expect_success 'with 2 files argum ' test_expect_success 'with message that has comments' ' - cat basic_message >>message_with_comments && + cat basic_message >message_with_comments && sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF && # comment @@@ -245,44 -259,12 +259,44 @@@ Reviewed-by: Johan Cc: Peff + # last comment + EOF cat basic_patch >>expected && git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual && test_cmp expected actual ' +test_expect_success 'with message that has an old style conflict block' ' + cat basic_message >message_with_comments && + sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF && + # comment + + # other comment + Cc: Z + # yet another comment + Reviewed-by: Johan + Reviewed-by: Z + # last comment + + Conflicts: + + EOF + cat basic_message >expected && + cat >>expected <<-\EOF && + # comment + + Reviewed-by: Johan + Cc: Peff + # last comment + + Conflicts: + + EOF + git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual && + test_cmp expected actual +' + test_expect_success 'with commit complex message and trailer args' ' cat complex_message_body >expected && sed -e "s/ Z\$/ /" >>expected <<-\EOF && diff --combined trailer.c index b8088687d4,5ec5f9ddc1..6f3416feba --- a/trailer.c +++ b/trailer.c @@@ -1,7 -1,7 +1,7 @@@ #include "cache.h" #include "string-list.h" #include "run-command.h" -#include "string-list.h" +#include "commit.h" #include "trailer.h" /* * Copyright (c) 2013, 2014 Christian Couder @@@ -214,6 -214,16 +214,6 @@@ static struct trailer_item *remove_firs return item; } -static int read_from_command(struct child_process *cp, struct strbuf *buf) -{ - if (run_command(cp)) - return error("running trailer command '%s' failed", cp->argv[0]); - if (strbuf_read(buf, cp->out, 1024) < 1) - return error("reading from trailer command '%s' failed", cp->argv[0]); - strbuf_trim(buf); - return 0; -} - static const char *apply_command(const char *command, const char *arg) { struct strbuf cmd = STRBUF_INIT; @@@ -230,16 -240,14 +230,16 @@@ cp.argv = argv; cp.env = local_repo_env; cp.no_stdin = 1; - cp.out = -1; cp.use_shell = 1; - if (read_from_command(&cp, &buf)) { + if (capture_command(&cp, &buf, 1024)) { + error("running trailer command '%s' failed", cmd.buf); strbuf_release(&buf); result = xstrdup(""); - } else + } else { + strbuf_trim(&buf); result = strbuf_detach(&buf, NULL); + } strbuf_release(&cmd); return result; @@@ -735,15 -743,22 +735,22 @@@ static int find_patch_start(struct strb */ static int find_trailer_start(struct strbuf **lines, int count) { - int start, only_spaces = 1; + int start, end_of_title, only_spaces = 1; + + /* The first paragraph is the title and cannot be trailers */ + for (start = 0; start < count; start++) { + if (lines[start]->buf[0] == comment_line_char) + continue; + if (contains_only_spaces(lines[start]->buf)) + break; + } + end_of_title = start; /* * Get the start of the trailers by looking starting from the end * for a line with only spaces before lines with one separator. - * The first line must not be analyzed as the others as it - * should be either the message title or a blank line. */ - for (start = count - 1; start >= 1; start--) { + for (start = count - 1; start >= end_of_title; start--) { if (lines[start]->buf[0] == comment_line_char) continue; if (contains_only_spaces(lines[start]->buf)) { @@@ -762,22 -777,6 +769,22 @@@ return only_spaces ? count : 0; } +/* Get the index of the end of the trailers */ +static int find_trailer_end(struct strbuf **lines, int patch_start) +{ + struct strbuf sb = STRBUF_INIT; + int i, ignore_bytes; + + for (i = 0; i < patch_start; i++) + strbuf_addbuf(&sb, lines[i]); + ignore_bytes = ignore_non_trailer(&sb); + strbuf_release(&sb); + for (i = patch_start - 1; i >= 0 && ignore_bytes > 0; i--) + ignore_bytes -= lines[i]->len; + + return i + 1; +} + static int has_blank_line_before(struct strbuf **lines, int start) { for (;start >= 0; start--) { @@@ -800,15 -799,14 +807,15 @@@ static int process_input_file(struct st struct trailer_item **in_tok_last) { int count = 0; - int patch_start, trailer_start, i; + int patch_start, trailer_start, trailer_end, i; /* Get the line count */ while (lines[count]) count++; patch_start = find_patch_start(lines, count); - trailer_start = find_trailer_start(lines, patch_start); + trailer_end = find_trailer_end(lines, patch_start); + trailer_start = find_trailer_start(lines, trailer_end); /* Print lines before the trailers as is */ print_lines(lines, 0, trailer_start); @@@ -817,14 -815,14 +824,14 @@@ printf("\n"); /* Parse trailer lines */ - for (i = trailer_start; i < patch_start; i++) { + for (i = trailer_start; i < trailer_end; i++) { if (lines[i]->buf[0] != comment_line_char) { struct trailer_item *new = create_trailer_item(lines[i]->buf); add_trailer_item(in_tok_first, in_tok_last, new); } } - return patch_start; + return trailer_end; } static void free_all(struct trailer_item **first) @@@ -841,7 -839,7 +848,7 @@@ void process_trailers(const char *file struct trailer_item *in_tok_last = NULL; struct trailer_item *arg_tok_first; struct strbuf **lines; - int patch_start; + int trailer_end; /* Default config must be setup first */ git_config(git_trailer_default_config, NULL); @@@ -850,7 -848,7 +857,7 @@@ lines = read_input_file(file); /* Print the lines before the trailers */ - patch_start = process_input_file(lines, &in_tok_first, &in_tok_last); + trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last); arg_tok_first = process_command_line_args(trailers); @@@ -861,7 -859,7 +868,7 @@@ free_all(&in_tok_first); /* Print the lines after the trailers as is */ - print_lines(lines, patch_start, INT_MAX); + print_lines(lines, trailer_end, INT_MAX); strbuf_list_free(lines); }