From: Junio C Hamano Date: Mon, 1 Jul 2013 19:41:19 +0000 (-0700) Subject: Merge branch 'jk/commit-info-slab' X-Git-Tag: v1.8.4-rc0~100 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/55f34c8d39dac8a90d4944a77cb7614256c62018?ds=inline;hp=-c Merge branch 'jk/commit-info-slab' Allow adding custom information to commit objects in order to represent unbound number of flag bits etc. * jk/commit-info-slab: commit-slab: introduce a macro to define a slab for new type commit-slab: avoid large realloc commit: allow associating auxiliary info on-demand --- 55f34c8d39dac8a90d4944a77cb7614256c62018 diff --combined commit.c index 888e02ae2f,f97456ddfa..a1096a2b5a --- a/commit.c +++ b/commit.c @@@ -8,12 -8,14 +8,14 @@@ #include "notes.h" #include "gpg-interface.h" #include "mergesort.h" + #include "commit-slab.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); int save_commit_buffer = 1; const char *commit_type = "commit"; + static int commit_count; static struct commit *check_commit(struct object *obj, const unsigned char *sha1, @@@ -58,8 -60,11 +60,11 @@@ struct commit *lookup_commit_or_die(con struct commit *lookup_commit(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); - if (!obj) - return create_object(sha1, OBJ_COMMIT, alloc_commit_node()); + if (!obj) { + struct commit *c = alloc_commit_node(); + c->index = commit_count++; + return create_object(sha1, OBJ_COMMIT, c); + } if (!obj->type) obj->type = OBJ_COMMIT; return check_commit(obj, sha1, 0); @@@ -463,23 -468,14 +468,23 @@@ static void clear_commit_marks_1(struc } } -void clear_commit_marks(struct commit *commit, unsigned int mark) +void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark) { struct commit_list *list = NULL; - commit_list_insert(commit, &list); + + while (nr--) { + commit_list_insert(*commit, &list); + commit++; + } while (list) clear_commit_marks_1(&list, pop_commit(&list), mark); } +void clear_commit_marks(struct commit *commit, unsigned int mark) +{ + clear_commit_marks_many(1, &commit, mark); +} + void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark) { struct object *object; @@@ -506,6 -502,13 +511,13 @@@ struct commit *pop_commit(struct commit return item; } + /* + * Topological sort support + */ + + /* count number of children that have not been emitted */ + define_commit_slab(indegree_slab, int); + /* * Performs an in-place topological sort on the list supplied. */ @@@ -514,15 -517,18 +526,18 @@@ void sort_in_topological_order(struct c struct commit_list *next, *orig = *list; struct commit_list *work, **insert; struct commit_list **pptr; + struct indegree_slab indegree; if (!orig) return; *list = NULL; + init_indegree_slab(&indegree); + /* Mark them and clear the indegree */ for (next = orig; next; next = next->next) { struct commit *commit = next->item; - commit->indegree = 1; + *(indegree_slab_at(&indegree, commit)) = 1; } /* update the indegree */ @@@ -530,9 -536,10 +545,10 @@@ struct commit_list * parents = next->item->parents; while (parents) { struct commit *parent = parents->item; + int *pi = indegree_slab_at(&indegree, parent); - if (parent->indegree) - parent->indegree++; + if (*pi) + (*pi)++; parents = parents->next; } } @@@ -549,7 -556,7 +565,7 @@@ for (next = orig; next; next = next->next) { struct commit *commit = next->item; - if (commit->indegree == 1) + if (*(indegree_slab_at(&indegree, commit)) == 1) insert = &commit_list_insert(commit, insert)->next; } @@@ -570,8 -577,9 +586,9 @@@ commit = work_item->item; for (parents = commit->parents; parents ; parents = parents->next) { struct commit *parent = parents->item; + int *pi = indegree_slab_at(&indegree, parent); - if (!parent->indegree) + if (!*pi) continue; /* @@@ -579,7 -587,7 +596,7 @@@ * when all their children have been emitted thereby * guaranteeing topological order. */ - if (--parent->indegree == 1) { + if (--(*pi) == 1) { if (!lifo) commit_list_insert_by_date(parent, &work); else @@@ -590,10 -598,12 +607,12 @@@ * work_item is a commit all of whose children * have already been emitted. we can emit it now. */ - commit->indegree = 0; + *(indegree_slab_at(&indegree, commit)) = 0; *pptr = work_item; pptr = &work_item->next; } + + clear_indegree_slab(&indegree); } /* merge-base stuff */ @@@ -806,7 -816,8 +825,7 @@@ struct commit_list *get_merge_bases_man if (!result || !result->next) { if (cleanup) { clear_commit_marks(one, all_flags); - for (i = 0; i < n; i++) - clear_commit_marks(twos[i], all_flags); + clear_commit_marks_many(n, twos, all_flags); } return result; } @@@ -824,7 -835,8 +843,7 @@@ free_commit_list(result); clear_commit_marks(one, all_flags); - for (i = 0; i < n; i++) - clear_commit_marks(twos[i], all_flags); + clear_commit_marks_many(n, twos, all_flags); cnt = remove_redundant(rslt, cnt); result = NULL; @@@ -859,36 -871,25 +878,36 @@@ int is_descendant_of(struct commit *com } /* - * Is "commit" an ancestor of (i.e. reachable from) the "reference"? + * Is "commit" an ancestor of one of the "references"? */ -int in_merge_bases(struct commit *commit, struct commit *reference) +int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference) { struct commit_list *bases; - int ret = 0; + int ret = 0, i; - if (parse_commit(commit) || parse_commit(reference)) + if (parse_commit(commit)) return ret; + for (i = 0; i < nr_reference; i++) + if (parse_commit(reference[i])) + return ret; - bases = paint_down_to_common(commit, 1, &reference); + bases = paint_down_to_common(commit, nr_reference, reference); if (commit->object.flags & PARENT2) ret = 1; clear_commit_marks(commit, all_flags); - clear_commit_marks(reference, all_flags); + clear_commit_marks_many(nr_reference, reference, all_flags); free_commit_list(bases); return ret; } +/* + * Is "commit" an ancestor of (i.e. reachable from) the "reference"? + */ +int in_merge_bases(struct commit *commit, struct commit *reference) +{ + return in_merge_bases_many(commit, 1, &reference); +} + struct commit_list *reduce_heads(struct commit_list *heads) { struct commit_list *p; @@@ -1041,76 -1042,6 +1060,76 @@@ free_return free(buf); } +static struct { + char result; + const char *check; +} sigcheck_gpg_status[] = { + { 'G', "\n[GNUPG:] GOODSIG " }, + { 'B', "\n[GNUPG:] BADSIG " }, + { 'U', "\n[GNUPG:] TRUST_NEVER" }, + { 'U', "\n[GNUPG:] TRUST_UNDEFINED" }, +}; + +static void parse_gpg_output(struct signature_check *sigc) +{ + const char *buf = sigc->gpg_status; + int i; + + /* Iterate over all search strings */ + for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { + const char *found, *next; + + if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) { + /* At the very beginning of the buffer */ + found = buf + strlen(sigcheck_gpg_status[i].check + 1); + } else { + found = strstr(buf, sigcheck_gpg_status[i].check); + if (!found) + continue; + found += strlen(sigcheck_gpg_status[i].check); + } + sigc->result = sigcheck_gpg_status[i].result; + /* The trust messages are not followed by key/signer information */ + if (sigc->result != 'U') { + sigc->key = xmemdupz(found, 16); + found += 17; + next = strchrnul(found, '\n'); + sigc->signer = xmemdupz(found, next - found); + } + } +} + +void check_commit_signature(const struct commit* commit, struct signature_check *sigc) +{ + struct strbuf payload = STRBUF_INIT; + struct strbuf signature = STRBUF_INIT; + struct strbuf gpg_output = STRBUF_INIT; + struct strbuf gpg_status = STRBUF_INIT; + int status; + + sigc->result = 'N'; + + if (parse_signed_commit(commit->object.sha1, + &payload, &signature) <= 0) + goto out; + status = verify_signed_buffer(payload.buf, payload.len, + signature.buf, signature.len, + &gpg_output, &gpg_status); + if (status && !gpg_output.len) + goto out; + sigc->gpg_output = strbuf_detach(&gpg_output, NULL); + sigc->gpg_status = strbuf_detach(&gpg_status, NULL); + parse_gpg_output(sigc); + + out: + strbuf_release(&gpg_status); + strbuf_release(&gpg_output); + strbuf_release(&payload); + strbuf_release(&signature); +} + + + void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail) { diff --combined commit.h index 6e9c7cd9d5,70e749d69f..350472114b --- a/commit.h +++ b/commit.h @@@ -5,7 -5,6 +5,7 @@@ #include "tree.h" #include "strbuf.h" #include "decorate.h" +#include "gpg-interface.h" struct commit_list { struct commit *item; @@@ -15,7 -14,7 +15,7 @@@ struct commit { struct object object; void *util; - unsigned int indegree; + unsigned int index; unsigned long date; struct commit_list *parents; struct tree *tree; @@@ -101,7 -100,6 +101,7 @@@ struct userformat_want extern int has_non_ascii(const char *text); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ extern char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, const char *output_encoding); extern void logmsg_free(char *msg, const struct commit *commit); extern void get_commit_format(const char *arg, struct rev_info *); @@@ -139,7 -137,6 +139,7 @@@ struct commit *pop_most_recent_commit(s struct commit *pop_commit(struct commit_list **stack); void clear_commit_marks(struct commit *commit, unsigned int mark); +void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark); void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark); /* @@@ -176,12 -173,9 +176,12 @@@ extern int for_each_commit_graft(each_c extern int is_repository_shallow(void); extern struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag); +extern void check_shallow_file_for_update(void); +extern void set_alternate_shallow_file(const char *path); int is_descendant_of(struct commit *, struct commit_list *); int in_merge_bases(struct commit *, struct commit *); +int in_merge_bases_many(struct commit *, int, struct commit **); extern int interactive_add(int argc, const char **argv, const char *prefix, int patch); extern int run_add_interactive(const char *revision, const char *patch_mode, @@@ -236,13 -230,4 +236,13 @@@ extern void print_commit_list(struct co const char *format_cur, const char *format_last); +/* + * Check the signature of the given commit. The result of the check is stored + * in sig->check_result, 'G' for a good signature, 'U' for a good signature + * from an untrusted signer, 'B' for a bad signature and 'N' for no signature + * at all. This may allocate memory for sig->gpg_output, sig->gpg_status, + * sig->signer and sig->key. + */ +extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc); + #endif /* COMMIT_H */