git-p4: correct --prepare-p4-only instructions
[gitweb.git] / commit.c
index 65179f96eecc85082f9bf3f0312676878d92861d..19cf8f9c67bd0f4d71172f33424f7d2371a3af68 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -430,12 +430,7 @@ struct commit_list *copy_commit_list(struct commit_list *list)
        struct commit_list *head = NULL;
        struct commit_list **pp = &head;
        while (list) {
-               struct commit_list *new;
-               new = xmalloc(sizeof(struct commit_list));
-               new->item = list->item;
-               new->next = NULL;
-               *pp = new;
-               pp = &new->next;
+               pp = commit_list_append(list->item, pp);
                list = list->next;
        }
        return head;
@@ -589,26 +584,19 @@ define_commit_slab(author_date_slab, unsigned long);
 static void record_author_date(struct author_date_slab *author_date,
                               struct commit *commit)
 {
-       const char *buf, *line_end, *ident_line;
        const char *buffer = get_commit_buffer(commit, NULL);
        struct ident_split ident;
+       const char *ident_line;
+       size_t ident_len;
        char *date_end;
        unsigned long date;
 
-       for (buf = buffer; buf; buf = line_end + 1) {
-               line_end = strchrnul(buf, '\n');
-               ident_line = skip_prefix(buf, "author ");
-               if (!ident_line) {
-                       if (!line_end[0] || line_end[1] == '\n')
-                               return; /* end of header */
-                       continue;
-               }
-               if (split_ident_line(&ident,
-                                    ident_line, line_end - ident_line) ||
-                   !ident.date_begin || !ident.date_end)
-                       goto fail_exit; /* malformed "author" line */
-               break;
-       }
+       ident_line = find_commit_header(buffer, "author", &ident_len);
+       if (!ident_line)
+               goto fail_exit; /* no author line */
+       if (split_ident_line(&ident, ident_line, ident_len) ||
+           !ident.date_begin || !ident.date_end)
+               goto fail_exit; /* malformed "author" line */
 
        date = strtoul(ident.date_begin, &date_end, 10);
        if (date_end != ident.date_end)
@@ -770,45 +758,41 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
 
 static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
 
-static struct commit *interesting(struct commit_list *list)
+static int queue_has_nonstale(struct prio_queue *queue)
 {
-       while (list) {
-               struct commit *commit = list->item;
-               list = list->next;
-               if (commit->object.flags & STALE)
-                       continue;
-               return commit;
+       int i;
+       for (i = 0; i < queue->nr; i++) {
+               struct commit *commit = queue->array[i].data;
+               if (!(commit->object.flags & STALE))
+                       return 1;
        }
-       return NULL;
+       return 0;
 }
 
 /* all input commits in one and twos[] must have been parsed! */
 static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
 {
-       struct commit_list *list = NULL;
+       struct prio_queue queue = { compare_commits_by_commit_date };
        struct commit_list *result = NULL;
        int i;
 
        one->object.flags |= PARENT1;
-       commit_list_insert_by_date(one, &list);
-       if (!n)
-               return list;
+       if (!n) {
+               commit_list_append(one, &result);
+               return result;
+       }
+       prio_queue_put(&queue, one);
+
        for (i = 0; i < n; i++) {
                twos[i]->object.flags |= PARENT2;
-               commit_list_insert_by_date(twos[i], &list);
+               prio_queue_put(&queue, twos[i]);
        }
 
-       while (interesting(list)) {
-               struct commit *commit;
+       while (queue_has_nonstale(&queue)) {
+               struct commit *commit = prio_queue_get(&queue);
                struct commit_list *parents;
-               struct commit_list *next;
                int flags;
 
-               commit = list->item;
-               next = list->next;
-               free(list);
-               list = next;
-
                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
                if (flags == (PARENT1 | PARENT2)) {
                        if (!(commit->object.flags & RESULT)) {
@@ -827,11 +811,11 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
                        if (parse_commit(p))
                                return NULL;
                        p->object.flags |= flags;
-                       commit_list_insert_by_date(p, &list);
+                       prio_queue_put(&queue, p);
                }
        }
 
-       free_commit_list(list);
+       clear_prio_queue(&queue);
        return result;
 }
 
@@ -976,12 +960,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
        }
 
        /* There are more than one */
-       cnt = 0;
-       list = result;
-       while (list) {
-               list = list->next;
-               cnt++;
-       }
+       cnt = commit_list_count(result);
        rslt = xcalloc(cnt, sizeof(*rslt));
        for (list = result, i = 0; list; list = list->next)
                rslt[i++] = list->item;
@@ -1161,6 +1140,40 @@ int parse_signed_commit(const struct commit *commit,
        return saw_signature;
 }
 
+int remove_signature(struct strbuf *buf)
+{
+       const char *line = buf->buf;
+       const char *tail = buf->buf + buf->len;
+       int in_signature = 0;
+       const char *sig_start = NULL;
+       const char *sig_end = NULL;
+
+       while (line < tail) {
+               const char *next = memchr(line, '\n', tail - line);
+               next = next ? next + 1 : tail;
+
+               if (in_signature && line[0] == ' ')
+                       sig_end = next;
+               else if (starts_with(line, gpg_sig_header) &&
+                        line[gpg_sig_header_len] == ' ') {
+                       sig_start = line;
+                       sig_end = next;
+                       in_signature = 1;
+               } else {
+                       if (*line == '\n')
+                               /* dump the whole remainder of the buffer */
+                               next = tail;
+                       in_signature = 0;
+               }
+               line = next;
+       }
+
+       if (sig_start)
+               strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start);
+
+       return sig_start != NULL;
+}
+
 static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
 {
        struct merge_remote_desc *desc;
@@ -1201,44 +1214,7 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
        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;
-
-               found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1);
-               if (!found) {
-                       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)
+void check_commit_signature(const struct commit *commit, struct signature_check *sigc)
 {
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
@@ -1255,6 +1231,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check
                                      &gpg_output, &gpg_status);
        if (status && !gpg_output.len)
                goto out;
+       sigc->payload = strbuf_detach(&payload, NULL);
        sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
        sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
        parse_gpg_output(sigc);
@@ -1299,6 +1276,19 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
        return extra;
 }
 
+void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data)
+{
+       struct commit_extra_header *extra, *to_free;
+
+       to_free = read_commit_extra_headers(commit, NULL);
+       for (extra = to_free; extra; extra = extra->next) {
+               if (strcmp(extra->key, "mergetag"))
+                       continue; /* not a merge tag */
+               fn(commit, extra, data);
+       }
+       free_commit_extra_headers(to_free);
+}
+
 static inline int standard_header_field(const char *field, size_t len)
 {
        return ((len == 4 && !memcmp(field, "tree ", 5)) ||
@@ -1628,3 +1618,25 @@ void print_commit_list(struct commit_list *list,
                printf(format, sha1_to_hex(list->item->object.sha1));
        }
 }
+
+const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
+{
+       int key_len = strlen(key);
+       const char *line = msg;
+
+       while (line) {
+               const char *eol = strchrnul(line, '\n');
+
+               if (line == eol)
+                       return NULL;
+
+               if (eol - line > key_len &&
+                   !strncmp(line, key, key_len) &&
+                   line[key_len] == ' ') {
+                       *out_len = eol - line - key_len - 1;
+                       return line + key_len + 1;
+               }
+               line = *eol ? eol + 1 : NULL;
+       }
+       return NULL;
+}