From 785f745daf567aeabe47cb01024ea879b9e15c2f Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Mon, 15 Jun 2020 15:05:58 +0200 Subject: [PATCH] C: normalize reflog messages This behavior can be overridden with config.exact_log_message --- c/include/reftable.h | 7 +++++ c/stack_test.c | 61 +++++++++++++++++++++++++++++++++++++++++++- c/writer.c | 21 +++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/c/include/reftable.h b/c/include/reftable.h index 86f2dcf..3038dbe 100644 --- a/c/include/reftable.h +++ b/c/include/reftable.h @@ -101,6 +101,8 @@ enum reftable_error { - on writing a record with NULL ref_name. - on writing a reftable_ref_record outside the table limits - on writing a ref or log record before the stack's next_update_index + - on writing a log record with multiline message with + exact_log_message unset - on reading a reftable_ref_record from log iterator, or vice versa. */ REFTABLE_API_ERROR = -6, @@ -155,6 +157,11 @@ struct reftable_write_options { /* boolean: do not check ref names for validity or dir/file conflicts. */ int skip_name_check; + + /* boolean: copy log messages exactly. If unset, check that the message + * is a single line, and add '\n' if missing. + */ + int exact_log_message; }; /* reftable_block_stats holds statistics for a single block type */ diff --git a/c/stack_test.c b/c/stack_test.c index 9d40901..2850513 100644 --- a/c/stack_test.c +++ b/c/stack_test.c @@ -310,7 +310,9 @@ static void test_reftable_stack_add(void) { int i = 0; int err = 0; - struct reftable_write_options cfg = { 0 }; + struct reftable_write_options cfg = { + .exact_log_message = true, + }; struct reftable_stack *st = NULL; char dir[256] = "/tmp/stack_test.XXXXXX"; struct reftable_ref_record refs[2] = { { 0 } }; @@ -380,6 +382,61 @@ static void test_reftable_stack_add(void) clear_dir(dir); } +static void test_reftable_stack_log_normalize(void) +{ + int err = 0; + struct reftable_write_options cfg = { + 0, + }; + struct reftable_stack *st = NULL; + char dir[256] = "/tmp/stack_test.XXXXXX"; + + byte h1[SHA1_SIZE] = { 0x01 }, h2[SHA1_SIZE] = { 0x02 }; + + struct reftable_log_record input = { + .ref_name = "branch", + .update_index = 1, + .new_hash = h1, + .old_hash = h2, + }; + struct reftable_log_record dest = { + .update_index = 0, + }; + struct write_log_arg arg = { + .log = &input, + .update_index = 1, + }; + + assert(mkdtemp(dir)); + err = reftable_new_stack(&st, dir, cfg); + assert_err(err); + + input.message = "one\ntwo"; + err = reftable_stack_add(st, &write_test_log, &arg); + assert(err == REFTABLE_API_ERROR); + + input.message = "one"; + err = reftable_stack_add(st, &write_test_log, &arg); + assert_err(err); + + err = reftable_stack_read_log(st, input.ref_name, &dest); + assert_err(err); + assert(0 == strcmp(dest.message, "one\n")); + + input.message = "two\n"; + arg.update_index = 2; + err = reftable_stack_add(st, &write_test_log, &arg); + assert_err(err); + err = reftable_stack_read_log(st, input.ref_name, &dest); + assert_err(err); + assert(0 == strcmp(dest.message, "two\n")); + + /* cleanup */ + reftable_stack_destroy(st); + reftable_log_record_clear(&dest); + clear_dir(dir); +} + static void test_reftable_stack_tombstone(void) { int i = 0; @@ -718,6 +775,8 @@ int stack_test_main(int argc, const char *argv[]) &test_reftable_stack_update_index_check); add_test_case("test_reftable_stack_lock_failure", &test_reftable_stack_lock_failure); + add_test_case("test_reftable_stack_log_normalize", + &test_reftable_stack_log_normalize); add_test_case("test_reftable_stack_tombstone", &test_reftable_stack_tombstone); add_test_case("test_reftable_stack_add_one", diff --git a/c/writer.c b/c/writer.c index c55ff23..85207fd 100644 --- a/c/writer.c +++ b/c/writer.c @@ -289,6 +289,8 @@ int reftable_writer_add_log(struct reftable_writer *w, struct reftable_log_record *log) { struct reftable_record rec = { 0 }; + char *input_log_message = log->message; + struct slice cleaned_message = SLICE_INIT; int err; if (log->ref_name == NULL) return REFTABLE_API_ERROR; @@ -300,11 +302,30 @@ int reftable_writer_add_log(struct reftable_writer *w, return err; } + if (!w->opts.exact_log_message && log->message != NULL) { + slice_set_string(&cleaned_message, log->message); + + while (cleaned_message.len && + cleaned_message.buf[cleaned_message.len - 1] == '\n') + cleaned_message.len--; + if (strchr(slice_as_string(&cleaned_message), '\n')) { + // multiple lines not allowed. + err = REFTABLE_API_ERROR; + goto done; + } + slice_addstr(&cleaned_message, "\n"); + log->message = (char *)slice_as_string(&cleaned_message); + } + w->next -= w->pending_padding; w->pending_padding = 0; reftable_record_from_log(&rec, log); err = writer_add_record(w, &rec); + +done: + log->message = input_log_message; + slice_release(&cleaned_message); return err; }