Git fork
at reftables-rust 200 lines 5.5 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2 3#include "git-compat-util.h" 4#include "config.h" 5#include "commit.h" 6#include "environment.h" 7#include "gettext.h" 8#include "refs.h" 9#include "notes-utils.h" 10#include "strbuf.h" 11 12void create_notes_commit(struct repository *r, 13 struct notes_tree *t, 14 const struct commit_list *parents, 15 const char *msg, size_t msg_len, 16 struct object_id *result_oid) 17{ 18 struct commit_list *parents_to_free = NULL; 19 struct object_id tree_oid; 20 21 assert(t->initialized); 22 23 if (write_notes_tree(t, &tree_oid)) 24 die("Failed to write notes tree to database"); 25 26 if (!parents) { 27 /* Deduce parent commit from t->ref */ 28 struct object_id parent_oid; 29 if (!refs_read_ref(get_main_ref_store(the_repository), t->ref, &parent_oid)) { 30 struct commit *parent = lookup_commit(r, &parent_oid); 31 if (repo_parse_commit(r, parent)) 32 die("Failed to find/parse commit %s", t->ref); 33 commit_list_insert(parent, &parents_to_free); 34 parents = parents_to_free; 35 } 36 /* else: t->ref points to nothing, assume root/orphan commit */ 37 } 38 39 if (commit_tree(msg, msg_len, &tree_oid, parents, result_oid, NULL, 40 NULL)) 41 die("Failed to commit notes tree to database"); 42 43 free_commit_list(parents_to_free); 44} 45 46void commit_notes(struct repository *r, struct notes_tree *t, const char *msg) 47{ 48 struct strbuf buf = STRBUF_INIT; 49 struct object_id commit_oid; 50 51 if (!t) 52 t = &default_notes_tree; 53 if (!t->initialized || !t->update_ref || !*t->update_ref) 54 die(_("Cannot commit uninitialized/unreferenced notes tree")); 55 if (!t->dirty) 56 return; /* don't have to commit an unchanged tree */ 57 58 /* Prepare commit message and reflog message */ 59 strbuf_addstr(&buf, msg); 60 strbuf_complete_line(&buf); 61 62 create_notes_commit(r, t, NULL, buf.buf, buf.len, &commit_oid); 63 strbuf_insertstr(&buf, 0, "notes: "); 64 refs_update_ref(get_main_ref_store(the_repository), buf.buf, 65 t->update_ref, &commit_oid, NULL, 0, 66 UPDATE_REFS_DIE_ON_ERR); 67 68 strbuf_release(&buf); 69} 70 71int parse_notes_merge_strategy(const char *v, enum notes_merge_strategy *s) 72{ 73 if (!strcmp(v, "manual")) 74 *s = NOTES_MERGE_RESOLVE_MANUAL; 75 else if (!strcmp(v, "ours")) 76 *s = NOTES_MERGE_RESOLVE_OURS; 77 else if (!strcmp(v, "theirs")) 78 *s = NOTES_MERGE_RESOLVE_THEIRS; 79 else if (!strcmp(v, "union")) 80 *s = NOTES_MERGE_RESOLVE_UNION; 81 else if (!strcmp(v, "cat_sort_uniq")) 82 *s = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ; 83 else 84 return -1; 85 86 return 0; 87} 88 89static combine_notes_fn parse_combine_notes_fn(const char *v) 90{ 91 if (!strcasecmp(v, "overwrite")) 92 return combine_notes_overwrite; 93 else if (!strcasecmp(v, "ignore")) 94 return combine_notes_ignore; 95 else if (!strcasecmp(v, "concatenate")) 96 return combine_notes_concatenate; 97 else if (!strcasecmp(v, "cat_sort_uniq")) 98 return combine_notes_cat_sort_uniq; 99 else 100 return NULL; 101} 102 103static int notes_rewrite_config(const char *k, const char *v, 104 const struct config_context *ctx UNUSED, 105 void *cb) 106{ 107 struct notes_rewrite_cfg *c = cb; 108 if (starts_with(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) { 109 c->enabled = git_config_bool(k, v); 110 return 0; 111 } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) { 112 if (!v) 113 return config_error_nonbool(k); 114 c->combine = parse_combine_notes_fn(v); 115 if (!c->combine) { 116 error(_("Bad notes.rewriteMode value: '%s'"), v); 117 return 1; 118 } 119 return 0; 120 } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) { 121 if (!v) 122 return config_error_nonbool(k); 123 /* note that a refs/ prefix is implied in the 124 * underlying for_each_glob_ref */ 125 if (starts_with(v, "refs/notes/")) 126 string_list_add_refs_by_glob(c->refs, v); 127 else 128 warning(_("Refusing to rewrite notes in %s" 129 " (outside of refs/notes/)"), v); 130 return 0; 131 } 132 133 return 0; 134} 135 136 137struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) 138{ 139 struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg)); 140 const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT); 141 const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT); 142 c->cmd = cmd; 143 c->enabled = 1; 144 c->combine = combine_notes_concatenate; 145 CALLOC_ARRAY(c->refs, 1); 146 c->refs->strdup_strings = 1; 147 c->refs_from_env = 0; 148 c->mode_from_env = 0; 149 if (rewrite_mode_env) { 150 c->mode_from_env = 1; 151 c->combine = parse_combine_notes_fn(rewrite_mode_env); 152 if (!c->combine) 153 /* 154 * TRANSLATORS: The first %s is the name of 155 * the environment variable, the second %s is 156 * its value. 157 */ 158 error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT, 159 rewrite_mode_env); 160 } 161 if (rewrite_refs_env) { 162 c->refs_from_env = 1; 163 string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env); 164 } 165 repo_config(the_repository, notes_rewrite_config, c); 166 if (!c->enabled || !c->refs->nr) { 167 string_list_clear(c->refs, 0); 168 free(c->refs); 169 free(c); 170 return NULL; 171 } 172 c->trees = load_notes_trees(c->refs, NOTES_INIT_WRITABLE); 173 string_list_clear(c->refs, 0); 174 free(c->refs); 175 return c; 176} 177 178int copy_note_for_rewrite(struct notes_rewrite_cfg *c, 179 const struct object_id *from_obj, const struct object_id *to_obj) 180{ 181 int ret = 0; 182 int i; 183 for (i = 0; c->trees[i]; i++) 184 ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret; 185 return ret; 186} 187 188void finish_copy_notes_for_rewrite(struct repository *r, 189 struct notes_rewrite_cfg *c, 190 const char *msg) 191{ 192 int i; 193 for (i = 0; c->trees[i]; i++) { 194 commit_notes(r, c->trees[i], msg); 195 free_notes(c->trees[i]); 196 free(c->trees[i]); 197 } 198 free(c->trees); 199 free(c); 200}