Merge pull request #3433 from libgit2/cmn/config-comment Keep config comments in the same place as git
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
diff --git a/src/config_file.c b/src/config_file.c
index a3fec1b..46f21c0 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -1711,6 +1711,7 @@ static const char *quotes_for_value(const char *value)
struct write_data {
git_buf *buf;
+ git_buf buffered_comment;
unsigned int in_section : 1,
preg_replaced : 1;
const char *section;
@@ -1719,16 +1720,21 @@ struct write_data {
const char *value;
};
-static int write_line(struct write_data *write_data, const char *line, size_t line_len)
+static int write_line_to(git_buf *buf, const char *line, size_t line_len)
{
- int result = git_buf_put(write_data->buf, line, line_len);
+ int result = git_buf_put(buf, line, line_len);
if (!result && line_len && line[line_len-1] != '\n')
- result = git_buf_printf(write_data->buf, "\n");
+ result = git_buf_printf(buf, "\n");
return result;
}
+static int write_line(struct write_data *write_data, const char *line, size_t line_len)
+{
+ return write_line_to(write_data->buf, line, line_len);
+}
+
static int write_value(struct write_data *write_data)
{
const char *q;
@@ -1770,6 +1776,14 @@ static int write_on_section(
write_data->in_section = strcmp(current_section, write_data->section) == 0;
+ /*
+ * If there were comments just before this section, dump them as well.
+ */
+ if (!result) {
+ result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size);
+ git_buf_clear(&write_data->buffered_comment);
+ }
+
if (!result)
result = write_line(write_data, line, line_len);
@@ -1787,10 +1801,19 @@ static int write_on_variable(
{
struct write_data *write_data = (struct write_data *)data;
bool has_matched = false;
+ int error;
GIT_UNUSED(reader);
GIT_UNUSED(current_section);
+ /*
+ * If there were comments just before this variable, let's dump them as well.
+ */
+ if ((error = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
+ return error;
+
+ git_buf_clear(&write_data->buffered_comment);
+
/* See if we are to update this name/value pair; first examine name */
if (write_data->in_section &&
strcasecmp(write_data->name, var_name) == 0)
@@ -1825,7 +1848,7 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin
GIT_UNUSED(reader);
write_data = (struct write_data *)data;
- return write_line(write_data, line, line_len);
+ return write_line_to(&write_data->buffered_comment, line, line_len);
}
static int write_on_eof(struct reader **reader, void *data)
@@ -1835,6 +1858,12 @@ static int write_on_eof(struct reader **reader, void *data)
GIT_UNUSED(reader);
+ /*
+ * If we've buffered comments when reaching EOF, make sure to dump them.
+ */
+ if ((result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
+ return result;
+
/* If we are at the EOF and have not written our value (again, for a
* simple name/value set, not a multivar) then we have never seen the
* section in question and should create a new section and write the
@@ -1892,6 +1921,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
section = git__strndup(key, ldot - key);
write_data.buf = &buf;
+ git_buf_init(&write_data.buffered_comment, 0);
write_data.section = section;
write_data.in_section = 0;
write_data.preg_replaced = 0;
@@ -1901,6 +1931,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
result = config_parse(reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
git__free(section);
+ git_buf_free(&write_data.buffered_comment);
if (result < 0) {
git_filebuf_cleanup(&file);
diff --git a/tests/config/write.c b/tests/config/write.c
index 9ad11ab..e634aa3 100644
--- a/tests/config/write.c
+++ b/tests/config/write.c
@@ -530,6 +530,9 @@ void test_config_write__outside_change(void)
git_config_free(cfg);
}
+#define FOO_COMMENT \
+ "; another comment!\n"
+
#define SECTION_FOO \
"\n" \
" \n" \
@@ -537,7 +540,8 @@ void test_config_write__outside_change(void)
" # here's a comment\n" \
"\tname = \"value\"\n" \
" name2 = \"value2\"\n" \
- "; another comment!\n"
+
+#define SECTION_FOO_WITH_COMMENT SECTION_FOO FOO_COMMENT
#define SECTION_BAR \
"[section \"bar\"]\t\n" \
@@ -553,7 +557,7 @@ void test_config_write__preserves_whitespace_and_comments(void)
git_buf newfile = GIT_BUF_INIT;
/* This config can occur after removing and re-adding the origin remote */
- const char *file_content = SECTION_FOO SECTION_BAR;
+ const char *file_content = SECTION_FOO_WITH_COMMENT SECTION_BAR;
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, file_content);
@@ -567,9 +571,10 @@ void test_config_write__preserves_whitespace_and_comments(void)
cl_assert_equal_strn(SECTION_FOO, n, strlen(SECTION_FOO));
n += strlen(SECTION_FOO);
-
cl_assert_equal_strn("\tother = otherval\n", n, strlen("\tother = otherval\n"));
n += strlen("\tother = otherval\n");
+ cl_assert_equal_strn(FOO_COMMENT, n, strlen(FOO_COMMENT));
+ n += strlen(FOO_COMMENT);
cl_assert_equal_strn(SECTION_BAR, n, strlen(SECTION_BAR));
n += strlen(SECTION_BAR);