diff --git a/Makefile b/Makefile index 79f961ee4b..e1583761df 100644 --- a/Makefile +++ b/Makefile @@ -696,6 +696,7 @@ LIB_H += merge-recursive.h LIB_H += mergesort.h LIB_H += notes-cache.h LIB_H += notes-merge.h +LIB_H += notes-utils.h LIB_H += notes.h LIB_H += object.h LIB_H += pack-revindex.h @@ -830,6 +831,7 @@ LIB_OBJS += name-hash.o LIB_OBJS += notes.o LIB_OBJS += notes-cache.o LIB_OBJS += notes-merge.o +LIB_OBJS += notes-utils.o LIB_OBJS += object.o LIB_OBJS += pack-check.o LIB_OBJS += pack-revindex.o diff --git a/builtin.h b/builtin.h index 64bab6bf54..1ed8edb0cb 100644 --- a/builtin.h +++ b/builtin.h @@ -5,7 +5,6 @@ #include "strbuf.h" #include "cache.h" #include "commit.h" -#include "notes.h" #define DEFAULT_MERGE_LOG_LEN 20 @@ -26,21 +25,6 @@ struct fmt_merge_msg_opts { extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out, struct fmt_merge_msg_opts *); -struct notes_rewrite_cfg { - struct notes_tree **trees; - const char *cmd; - int enabled; - combine_notes_fn combine; - struct string_list *refs; - int refs_from_env; - int mode_from_env; -}; - -struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd); -int copy_note_for_rewrite(struct notes_rewrite_cfg *c, - const unsigned char *from_obj, const unsigned char *to_obj); -void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c); - extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size); extern int cmd_add(int argc, const char **argv, const char *prefix); diff --git a/builtin/commit.c b/builtin/commit.c index 1621dfcd40..6b693c16d8 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -29,6 +29,7 @@ #include "gpg-interface.h" #include "column.h" #include "sequencer.h" +#include "notes-utils.h" static const char * const builtin_commit_usage[] = { N_("git commit [options] [--] ..."), @@ -1593,7 +1594,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (cfg) { /* we are amending, so current_head is not NULL */ copy_note_for_rewrite(cfg, current_head->object.sha1, sha1); - finish_copy_notes_for_rewrite(cfg); + finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'"); } run_rewrite_hook(current_head->object.sha1, sha1); } diff --git a/builtin/notes.c b/builtin/notes.c index 57748a6fb6..9ed2508f03 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -18,9 +18,7 @@ #include "parse-options.h" #include "string-list.h" #include "notes-merge.h" - -static void commit_notes(struct notes_tree *t, const char *msg); -static combine_notes_fn parse_combine_notes_fn(const char *v); +#include "notes-utils.h" static const char * const git_notes_usage[] = { N_("git notes [--ref ] [list []]"), @@ -287,139 +285,13 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset return parse_reuse_arg(opt, arg, unset); } -static void commit_notes(struct notes_tree *t, const char *msg) -{ - struct strbuf buf = STRBUF_INIT; - unsigned char commit_sha1[20]; - - if (!t) - t = &default_notes_tree; - if (!t->initialized || !t->ref || !*t->ref) - die(_("Cannot commit uninitialized/unreferenced notes tree")); - if (!t->dirty) - return; /* don't have to commit an unchanged tree */ - - /* Prepare commit message and reflog message */ - strbuf_addstr(&buf, msg); - if (buf.buf[buf.len - 1] != '\n') - strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */ - - create_notes_commit(t, NULL, &buf, commit_sha1); - strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ - update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR); - - strbuf_release(&buf); -} - -static combine_notes_fn parse_combine_notes_fn(const char *v) -{ - if (!strcasecmp(v, "overwrite")) - return combine_notes_overwrite; - else if (!strcasecmp(v, "ignore")) - return combine_notes_ignore; - else if (!strcasecmp(v, "concatenate")) - return combine_notes_concatenate; - else if (!strcasecmp(v, "cat_sort_uniq")) - return combine_notes_cat_sort_uniq; - else - return NULL; -} - -static int notes_rewrite_config(const char *k, const char *v, void *cb) -{ - struct notes_rewrite_cfg *c = cb; - if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) { - c->enabled = git_config_bool(k, v); - return 0; - } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) { - if (!v) - config_error_nonbool(k); - c->combine = parse_combine_notes_fn(v); - if (!c->combine) { - error(_("Bad notes.rewriteMode value: '%s'"), v); - return 1; - } - return 0; - } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) { - /* note that a refs/ prefix is implied in the - * underlying for_each_glob_ref */ - if (!prefixcmp(v, "refs/notes/")) - string_list_add_refs_by_glob(c->refs, v); - else - warning(_("Refusing to rewrite notes in %s" - " (outside of refs/notes/)"), v); - return 0; - } - - return 0; -} - - -struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) -{ - struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg)); - const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT); - const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT); - c->cmd = cmd; - c->enabled = 1; - c->combine = combine_notes_concatenate; - c->refs = xcalloc(1, sizeof(struct string_list)); - c->refs->strdup_strings = 1; - c->refs_from_env = 0; - c->mode_from_env = 0; - if (rewrite_mode_env) { - c->mode_from_env = 1; - c->combine = parse_combine_notes_fn(rewrite_mode_env); - if (!c->combine) - /* TRANSLATORS: The first %s is the name of the - environment variable, the second %s is its value */ - error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT, - rewrite_mode_env); - } - if (rewrite_refs_env) { - c->refs_from_env = 1; - string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env); - } - git_config(notes_rewrite_config, c); - if (!c->enabled || !c->refs->nr) { - string_list_clear(c->refs, 0); - free(c->refs); - free(c); - return NULL; - } - c->trees = load_notes_trees(c->refs); - string_list_clear(c->refs, 0); - free(c->refs); - return c; -} - -int copy_note_for_rewrite(struct notes_rewrite_cfg *c, - const unsigned char *from_obj, const unsigned char *to_obj) -{ - int ret = 0; - int i; - for (i = 0; c->trees[i]; i++) - ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret; - return ret; -} - -void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c) -{ - int i; - for (i = 0; c->trees[i]; i++) { - commit_notes(c->trees[i], "Notes added by 'git notes copy'"); - free_notes(c->trees[i]); - } - free(c->trees); - free(c); -} - static int notes_copy_from_stdin(int force, const char *rewrite_cmd) { struct strbuf buf = STRBUF_INIT; struct notes_rewrite_cfg *c = NULL; struct notes_tree *t = NULL; int ret = 0; + const char *msg = "Notes added by 'git notes copy'"; if (rewrite_cmd) { c = init_copy_notes_for_rewrite(rewrite_cmd); @@ -461,10 +333,10 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd) } if (!rewrite_cmd) { - commit_notes(t, "Notes added by 'git notes copy'"); + commit_notes(t, msg); free_notes(t); } else { - finish_copy_notes_for_rewrite(c); + finish_copy_notes_for_rewrite(c, msg); } return ret; } diff --git a/notes-merge.c b/notes-merge.c index 0f67bd3f96..ab18857074 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -9,6 +9,7 @@ #include "notes.h" #include "notes-merge.h" #include "strbuf.h" +#include "notes-utils.h" struct notes_merge_pair { unsigned char obj[20], base[20], local[20], remote[20]; @@ -530,32 +531,6 @@ static int merge_from_diffs(struct notes_merge_options *o, return conflicts ? -1 : 1; } -void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1) -{ - unsigned char tree_sha1[20]; - - assert(t->initialized); - - if (write_notes_tree(t, tree_sha1)) - die("Failed to write notes tree to database"); - - if (!parents) { - /* Deduce parent commit from t->ref */ - unsigned char parent_sha1[20]; - if (!read_ref(t->ref, parent_sha1)) { - struct commit *parent = lookup_commit(parent_sha1); - if (!parent || parse_commit(parent)) - die("Failed to find/parse commit %s", t->ref); - commit_list_insert(parent, &parents); - } - /* else: t->ref points to nothing, assume root/orphan commit */ - } - - if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL)) - die("Failed to commit notes tree to database"); -} - int notes_merge(struct notes_merge_options *o, struct notes_tree *local_tree, unsigned char *result_sha1) diff --git a/notes-merge.h b/notes-merge.h index 0c11b173a1..1d01f6aacf 100644 --- a/notes-merge.h +++ b/notes-merge.h @@ -25,20 +25,6 @@ struct notes_merge_options { void init_notes_merge_options(struct notes_merge_options *o); -/* - * Create new notes commit from the given notes tree - * - * Properties of the created commit: - * - tree: the result of converting t to a tree object with write_notes_tree(). - * - parents: the given parents OR (if NULL) the commit referenced by t->ref. - * - author/committer: the default determined by commmit_tree(). - * - commit message: msg - * - * The resulting commit SHA1 is stored in result_sha1. - */ -void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1); - /* * Merge notes from o->remote_ref into o->local_ref * diff --git a/notes-utils.c b/notes-utils.c new file mode 100644 index 0000000000..9107c379d9 --- /dev/null +++ b/notes-utils.c @@ -0,0 +1,157 @@ +#include "cache.h" +#include "commit.h" +#include "refs.h" +#include "notes-utils.h" + +void create_notes_commit(struct notes_tree *t, struct commit_list *parents, + const struct strbuf *msg, unsigned char *result_sha1) +{ + unsigned char tree_sha1[20]; + + assert(t->initialized); + + if (write_notes_tree(t, tree_sha1)) + die("Failed to write notes tree to database"); + + if (!parents) { + /* Deduce parent commit from t->ref */ + unsigned char parent_sha1[20]; + if (!read_ref(t->ref, parent_sha1)) { + struct commit *parent = lookup_commit(parent_sha1); + if (!parent || parse_commit(parent)) + die("Failed to find/parse commit %s", t->ref); + commit_list_insert(parent, &parents); + } + /* else: t->ref points to nothing, assume root/orphan commit */ + } + + if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL)) + die("Failed to commit notes tree to database"); +} + +void commit_notes(struct notes_tree *t, const char *msg) +{ + struct strbuf buf = STRBUF_INIT; + unsigned char commit_sha1[20]; + + if (!t) + t = &default_notes_tree; + if (!t->initialized || !t->ref || !*t->ref) + die(_("Cannot commit uninitialized/unreferenced notes tree")); + if (!t->dirty) + return; /* don't have to commit an unchanged tree */ + + /* Prepare commit message and reflog message */ + strbuf_addstr(&buf, msg); + if (buf.buf[buf.len - 1] != '\n') + strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */ + + create_notes_commit(t, NULL, &buf, commit_sha1); + strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ + update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR); + + strbuf_release(&buf); +} + +static combine_notes_fn parse_combine_notes_fn(const char *v) +{ + if (!strcasecmp(v, "overwrite")) + return combine_notes_overwrite; + else if (!strcasecmp(v, "ignore")) + return combine_notes_ignore; + else if (!strcasecmp(v, "concatenate")) + return combine_notes_concatenate; + else if (!strcasecmp(v, "cat_sort_uniq")) + return combine_notes_cat_sort_uniq; + else + return NULL; +} + +static int notes_rewrite_config(const char *k, const char *v, void *cb) +{ + struct notes_rewrite_cfg *c = cb; + if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) { + c->enabled = git_config_bool(k, v); + return 0; + } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) { + if (!v) + config_error_nonbool(k); + c->combine = parse_combine_notes_fn(v); + if (!c->combine) { + error(_("Bad notes.rewriteMode value: '%s'"), v); + return 1; + } + return 0; + } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) { + /* note that a refs/ prefix is implied in the + * underlying for_each_glob_ref */ + if (!prefixcmp(v, "refs/notes/")) + string_list_add_refs_by_glob(c->refs, v); + else + warning(_("Refusing to rewrite notes in %s" + " (outside of refs/notes/)"), v); + return 0; + } + + return 0; +} + + +struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) +{ + struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg)); + const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT); + const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT); + c->cmd = cmd; + c->enabled = 1; + c->combine = combine_notes_concatenate; + c->refs = xcalloc(1, sizeof(struct string_list)); + c->refs->strdup_strings = 1; + c->refs_from_env = 0; + c->mode_from_env = 0; + if (rewrite_mode_env) { + c->mode_from_env = 1; + c->combine = parse_combine_notes_fn(rewrite_mode_env); + if (!c->combine) + /* TRANSLATORS: The first %s is the name of the + environment variable, the second %s is its value */ + error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT, + rewrite_mode_env); + } + if (rewrite_refs_env) { + c->refs_from_env = 1; + string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env); + } + git_config(notes_rewrite_config, c); + if (!c->enabled || !c->refs->nr) { + string_list_clear(c->refs, 0); + free(c->refs); + free(c); + return NULL; + } + c->trees = load_notes_trees(c->refs); + string_list_clear(c->refs, 0); + free(c->refs); + return c; +} + +int copy_note_for_rewrite(struct notes_rewrite_cfg *c, + const unsigned char *from_obj, const unsigned char *to_obj) +{ + int ret = 0; + int i; + for (i = 0; c->trees[i]; i++) + ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret; + return ret; +} + +void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg) +{ + int i; + for (i = 0; c->trees[i]; i++) { + commit_notes(c->trees[i], msg); + free_notes(c->trees[i]); + } + free(c->trees); + free(c); +} diff --git a/notes-utils.h b/notes-utils.h new file mode 100644 index 0000000000..b4cb1bfb43 --- /dev/null +++ b/notes-utils.h @@ -0,0 +1,37 @@ +#ifndef NOTES_UTILS_H +#define NOTES_UTILS_H + +#include "notes.h" + +/* + * Create new notes commit from the given notes tree + * + * Properties of the created commit: + * - tree: the result of converting t to a tree object with write_notes_tree(). + * - parents: the given parents OR (if NULL) the commit referenced by t->ref. + * - author/committer: the default determined by commmit_tree(). + * - commit message: msg + * + * The resulting commit SHA1 is stored in result_sha1. + */ +void create_notes_commit(struct notes_tree *t, struct commit_list *parents, + const struct strbuf *msg, unsigned char *result_sha1); + +void commit_notes(struct notes_tree *t, const char *msg); + +struct notes_rewrite_cfg { + struct notes_tree **trees; + const char *cmd; + int enabled; + combine_notes_fn combine; + struct string_list *refs; + int refs_from_env; + int mode_from_env; +}; + +struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd); +int copy_note_for_rewrite(struct notes_rewrite_cfg *c, + const unsigned char *from_obj, const unsigned char *to_obj); +void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg); + +#endif