From: Jonathan Tan <jonathantanmy@google.com>
To: git@vger.kernel.org
Cc: Jonathan Tan <jonathantanmy@google.com>,
sbeller@google.com, gitster@pobox.com
Subject: [PATCH v5 8/8] trailer: support values folded to multiple lines
Date: Fri, 21 Oct 2016 10:55:03 -0700 [thread overview]
Message-ID: <b75fc95acb015dd69d8326bf69201965a3d18c87.1477072247.git.jonathantanmy@google.com> (raw)
In-Reply-To: <cover.1477072247.git.jonathantanmy@google.com>
In-Reply-To: <cover.1477072247.git.jonathantanmy@google.com>
Currently, interpret-trailers requires that a trailer be only on 1 line.
For example:
a: first line
second line
would be interpreted as one trailer line followed by one non-trailer line.
Make interpret-trailers support RFC 822-style folding, treating those
lines as one logical trailer.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
---
Documentation/git-interpret-trailers.txt | 7 +-
t/t7513-interpret-trailers.sh | 169 +++++++++++++++++++++++++++++++
trailer.c | 45 ++++++--
3 files changed, 211 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 4966b5b..e99bda6 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -57,11 +57,12 @@ minus signs start the patch part of the message.
When reading trailers, there can be whitespaces after the
token, the separator and the value. There can also be whitespaces
-inside the token and the value.
+inside the token and the value. The value may be split over multiple lines with
+each subsequent line starting with whitespace, like the "folding" in RFC 822.
Note that 'trailers' do not follow and are not intended to follow many
-rules for RFC 822 headers. For example they do not follow the line
-folding rules, the encoding rules and probably many other rules.
+rules for RFC 822 headers. For example they do not follow
+the encoding rules and probably many other rules.
OPTIONS
-------
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 3d94b3a..4dd1d7c 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -256,6 +256,175 @@ test_expect_success 'line with leading whitespace is not trailer' '
test_cmp expected actual
'
+test_expect_success 'multiline field treated as one trailer for 25% check' '
+ q_to_tab >patch <<-\EOF &&
+
+ Signed-off-by: a <a@example.com>
+ name: value on
+ Qmultiple lines
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ Signed-off-by: a <a@example.com>
+ name: value on
+ Qmultiple lines
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ this is not a trailer
+ name: value
+ EOF
+ git interpret-trailers --trailer "name: value" patch >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'multiline field treated as atomic for placement' '
+ q_to_tab >patch <<-\EOF &&
+
+ another: trailer
+ name: value on
+ Qmultiple lines
+ another: trailer
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: value on
+ Qmultiple lines
+ name: value
+ another: trailer
+ EOF
+ test_config trailer.name.where after &&
+ git interpret-trailers --trailer "name: value" patch >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'multiline field treated as atomic for replacement' '
+ q_to_tab >patch <<-\EOF &&
+
+ another: trailer
+ name: value on
+ Qmultiple lines
+ another: trailer
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ another: trailer
+ name: value
+ EOF
+ test_config trailer.name.ifexists replace &&
+ git interpret-trailers --trailer "name: value" patch >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'multiline field treated as atomic for difference check' '
+ q_to_tab >patch <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ EOF
+ test_config trailer.name.ifexists addIfDifferent &&
+
+ q_to_tab >trailer <<-\EOF &&
+ name: first line
+ Qsecond line
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ EOF
+ git interpret-trailers --trailer "$(cat trailer)" patch >actual &&
+ test_cmp expected actual &&
+
+ q_to_tab >trailer <<-\EOF &&
+ name: first line
+ QQQQQsecond line
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ name: first line
+ QQQQQsecond line
+ EOF
+ git interpret-trailers --trailer "$(cat trailer)" patch >actual &&
+ test_cmp expected actual &&
+
+ q_to_tab >trailer <<-\EOF &&
+ name: first line *DIFFERENT*
+ Qsecond line
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ name: first line *DIFFERENT*
+ Qsecond line
+ EOF
+ git interpret-trailers --trailer "$(cat trailer)" patch >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'multiline field treated as atomic for neighbor check' '
+ q_to_tab >patch <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ EOF
+ test_config trailer.name.where after &&
+ test_config trailer.name.ifexists addIfDifferentNeighbor &&
+
+ q_to_tab >trailer <<-\EOF &&
+ name: first line
+ Qsecond line
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ another: trailer
+ EOF
+ git interpret-trailers --trailer "$(cat trailer)" patch >actual &&
+ test_cmp expected actual &&
+
+ q_to_tab >trailer <<-\EOF &&
+ name: first line
+ QQQQQsecond line
+ EOF
+ q_to_tab >expected <<-\EOF &&
+
+ another: trailer
+ name: first line
+ Qsecond line
+ name: first line
+ QQQQQsecond line
+ another: trailer
+ EOF
+ git interpret-trailers --trailer "$(cat trailer)" patch >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'with config setup' '
git config trailer.ack.key "Acked-by: " &&
cat >expected <<-\EOF &&
diff --git a/trailer.c b/trailer.c
index d978437..65866d0 100644
--- a/trailer.c
+++ b/trailer.c
@@ -619,12 +619,14 @@ static void parse_trailer(struct strbuf *tok, struct strbuf *val,
}
}
-static void add_trailer_item(struct list_head *head, char *tok, char *val)
+static struct trailer_item *add_trailer_item(struct list_head *head, char *tok,
+ char *val)
{
struct trailer_item *new = xcalloc(sizeof(*new), 1);
new->token = tok;
new->value = val;
list_add_tail(&new->list, head);
+ return new;
}
static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
@@ -732,6 +734,14 @@ static int find_trailer_start(struct strbuf **lines, int count)
{
int start, end_of_title, only_spaces = 1;
int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
+ /*
+ * Number of possible continuation lines encountered. This will be
+ * reset to 0 if we encounter a trailer (since those lines are to be
+ * considered continuations of that trailer), and added to
+ * non_trailer_lines if we encounter a non-trailer (since those lines
+ * are to be considered non-trailers).
+ */
+ int possible_continuation_lines = 0;
/* The first paragraph is the title and cannot be trailers */
for (start = 0; start < count; start++) {
@@ -752,11 +762,15 @@ static int find_trailer_start(struct strbuf **lines, int count)
const char **p;
int separator_pos;
- if (lines[start]->buf[0] == comment_line_char)
+ if (lines[start]->buf[0] == comment_line_char) {
+ non_trailer_lines += possible_continuation_lines;
+ possible_continuation_lines = 0;
continue;
+ }
if (contains_only_spaces(lines[start]->buf)) {
if (only_spaces)
continue;
+ non_trailer_lines += possible_continuation_lines;
if (recognized_prefix &&
trailer_lines * 3 >= non_trailer_lines)
return start + 1;
@@ -769,16 +783,18 @@ static int find_trailer_start(struct strbuf **lines, int count)
for (p = git_generated_prefixes; *p; p++) {
if (starts_with(lines[start]->buf, *p)) {
trailer_lines++;
+ possible_continuation_lines = 0;
recognized_prefix = 1;
goto continue_outer_loop;
}
}
- separator_pos = find_separator(lines[start]->buf);
+ separator_pos = find_separator(lines[start]->buf, separators);
if (separator_pos >= 1 && !isspace(lines[start]->buf[0])) {
struct list_head *pos;
trailer_lines++;
+ possible_continuation_lines = 0;
if (recognized_prefix)
continue;
list_for_each(pos, &conf_head) {
@@ -790,8 +806,13 @@ static int find_trailer_start(struct strbuf **lines, int count)
break;
}
}
- } else
+ } else if (isspace(lines[start]->buf[0]))
+ possible_continuation_lines++;
+ else {
non_trailer_lines++;
+ non_trailer_lines += possible_continuation_lines;
+ possible_continuation_lines = 0;
+ }
continue_outer_loop:
;
}
@@ -840,6 +861,7 @@ static int process_input_file(FILE *outfile,
int patch_start, trailer_start, trailer_end, i;
struct strbuf tok = STRBUF_INIT;
struct strbuf val = STRBUF_INIT;
+ struct trailer_item *last = NULL;
/* Get the line count */
while (lines[count])
@@ -860,19 +882,28 @@ static int process_input_file(FILE *outfile,
int separator_pos;
if (lines[i]->buf[0] == comment_line_char)
continue;
+ if (last && isspace(lines[i]->buf[0])) {
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addf(&sb, "%s\n%s", last->value, lines[i]->buf);
+ strbuf_strip_suffix(&sb, "\n");
+ free(last->value);
+ last->value = strbuf_detach(&sb, NULL);
+ continue;
+ }
separator_pos = find_separator(lines[i]->buf, separators);
if (separator_pos >= 1) {
parse_trailer(&tok, &val, NULL, lines[i]->buf,
separator_pos);
- add_trailer_item(head,
- strbuf_detach(&tok, NULL),
- strbuf_detach(&val, NULL));
+ last = add_trailer_item(head,
+ strbuf_detach(&tok, NULL),
+ strbuf_detach(&val, NULL));
} else {
strbuf_addbuf(&val, lines[i]);
strbuf_strip_suffix(&val, "\n");
add_trailer_item(head,
NULL,
strbuf_detach(&val, NULL));
+ last = NULL;
}
}
--
2.8.0.rc3.226.g39d4020
prev parent reply other threads:[~2016-10-21 17:56 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-12 1:23 [PATCH 0/5] allow non-trailers and multiple-line trailers Jonathan Tan
2016-10-12 1:23 ` [PATCH 1/5] trailer: use singly-linked list, not doubly Jonathan Tan
2016-10-12 6:24 ` Junio C Hamano
2016-10-12 15:38 ` Christian Couder
2016-10-12 17:26 ` Jeff King
2016-10-12 1:23 ` [PATCH 2/5] trailer: streamline trailer item create and add Jonathan Tan
2016-10-12 1:23 ` [PATCH 3/5] trailer: make args have their own struct Jonathan Tan
2016-10-12 1:23 ` [PATCH 4/5] trailer: allow non-trailers in trailer block Jonathan Tan
2016-10-12 1:23 ` [PATCH 5/5] trailer: support values folded to multiple lines Jonathan Tan
2016-10-12 6:23 ` Junio C Hamano
2016-10-12 23:40 ` [PATCH v2 0/6] allow non-trailers and multiple-line trailers Jonathan Tan
2016-10-12 23:40 ` [PATCH v2 1/6] trailer: improve const correctness Jonathan Tan
2016-10-12 23:40 ` [PATCH v2 2/6] trailer: use list.h for doubly-linked list Jonathan Tan
2016-10-14 17:29 ` Jakub Narębski
2016-10-14 18:27 ` Junio C Hamano
2016-10-12 23:40 ` [PATCH v2 3/6] trailer: streamline trailer item create and add Jonathan Tan
2016-10-12 23:40 ` [PATCH v2 4/6] trailer: make args have their own struct Jonathan Tan
2016-10-12 23:40 ` [PATCH v2 5/6] trailer: allow non-trailers in trailer block Jonathan Tan
2016-10-12 23:40 ` [PATCH v2 6/6] trailer: support values folded to multiple lines Jonathan Tan
2016-10-14 17:37 ` [PATCH v3 0/6] allow non-trailers and multiple-line trailers Jonathan Tan
2016-10-14 17:37 ` [PATCH v3 1/6] trailer: improve const correctness Jonathan Tan
2016-10-17 22:49 ` Stefan Beller
2016-10-14 17:37 ` [PATCH v3 2/6] trailer: use list.h for doubly-linked list Jonathan Tan
2016-10-14 17:38 ` [PATCH v3 3/6] trailer: streamline trailer item create and add Jonathan Tan
2016-10-17 23:01 ` Stefan Beller
2016-10-14 17:38 ` [PATCH v3 4/6] trailer: make args have their own struct Jonathan Tan
2016-10-17 23:20 ` Stefan Beller
2016-10-18 16:05 ` Junio C Hamano
2016-10-14 17:38 ` [PATCH v3 5/6] trailer: allow non-trailers in trailer block Jonathan Tan
2016-10-18 0:49 ` Stefan Beller
2016-10-18 1:42 ` Junio C Hamano
2016-10-18 2:02 ` Jonathan Tan
2016-10-18 16:36 ` Junio C Hamano
2016-10-19 18:00 ` Jonathan Tan
2016-10-19 19:24 ` Junio C Hamano
2016-10-14 17:38 ` [PATCH v3 6/6] trailer: support values folded to multiple lines Jonathan Tan
2016-10-18 0:55 ` Stefan Beller
2016-10-20 21:39 ` [PATCH v4 0/8] allow non-trailers and multiple-line trailers Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 1/8] trailer: improve const correctness Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 2/8] trailer: use list.h for doubly-linked list Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 3/8] trailer: streamline trailer item create and add Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 4/8] trailer: make args have their own struct Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 5/8] trailer: clarify failure modes in parse_trailer Jonathan Tan
2016-10-20 22:07 ` Stefan Beller
2016-10-20 22:14 ` Junio C Hamano
2016-10-20 22:40 ` Jonathan Tan
2016-10-20 22:45 ` Junio C Hamano
2016-10-20 22:49 ` Jonathan Tan
2016-10-21 0:18 ` Junio C Hamano
2016-10-22 13:07 ` Christian Couder
2016-10-22 16:19 ` Junio C Hamano
2016-10-22 9:29 ` Christian Couder
2016-10-20 22:45 ` Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 6/8] trailer: allow non-trailers in trailer block Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 7/8] trailer: forbid leading whitespace in trailers Jonathan Tan
2016-10-20 21:39 ` [PATCH v4 8/8] trailer: support values folded to multiple lines Jonathan Tan
2016-10-21 17:54 ` [PATCH v5 0/8] allow non-trailers and multiple-line trailers Jonathan Tan
2016-10-21 23:59 ` Junio C Hamano
2016-10-22 0:06 ` Stefan Beller
2016-10-21 17:54 ` [PATCH v5 1/8] trailer: improve const correctness Jonathan Tan
2016-10-21 17:54 ` [PATCH v5 2/8] trailer: use list.h for doubly-linked list Jonathan Tan
2016-10-21 17:54 ` [PATCH v5 3/8] trailer: streamline trailer item create and add Jonathan Tan
2016-10-21 17:54 ` [PATCH v5 4/8] trailer: make args have their own struct Jonathan Tan
2016-10-21 17:55 ` [PATCH v5 5/8] trailer: clarify failure modes in parse_trailer Jonathan Tan
2016-10-21 17:55 ` [PATCH v5 6/8] trailer: allow non-trailers in trailer block Jonathan Tan
2016-10-21 17:55 ` [PATCH v5 7/8] trailer: forbid leading whitespace in trailers Jonathan Tan
2016-10-21 17:55 ` Jonathan Tan [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b75fc95acb015dd69d8326bf69201965a3d18c87.1477072247.git.jonathantanmy@google.com \
--to=jonathantanmy@google.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=sbeller@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).