log-tree: show mergetag in log --show-signature output

A commit object that merges a signed tag records the "mergetag" extended header. Check the validity of the GPG signature on it, and show it in a way similar to how "gpgsig" extended header is shown. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jan 4, 2012 at 13:51 UTC 824958e50b250e957998626a21763603ca30e832
1 file changed +75 -1
log-tree.c
+75 -1
@@ -443,6 +443,78 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
443 strbuf_release(&signature);
444 }
445
446 +static int which_parent(const unsigned char *sha1, const struct commit *commit)
447 +{
448 + int nth;
449 + const struct commit_list *parent;
450 +
451 + for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
452 + if (!hashcmp(parent->item->object.sha1, sha1))
453 + return nth;
454 + nth++;
455 + }
456 + return -1;
457 +}
458 +
459 +static void show_one_mergetag(struct rev_info *opt,
460 + struct commit_extra_header *extra,
461 + struct commit *commit)
462 +{
463 + unsigned char sha1[20];
464 + struct tag *tag;
465 + struct strbuf verify_message;
466 + int status, nth;
467 + size_t payload_size, gpg_message_offset;
468 +
469 + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1);
470 + tag = lookup_tag(sha1);
471 + if (!tag)
472 + return; /* error message already given */
473 +
474 + strbuf_init(&verify_message, 256);
475 + if (parse_tag_buffer(tag, extra->value, extra->len))
476 + strbuf_addstr(&verify_message, "malformed mergetag\n");
477 + else if ((nth = which_parent(tag->tagged->sha1, commit)) < 0)
478 + strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
479 + tag->tag, tag->tagged->sha1);
480 + else
481 + strbuf_addf(&verify_message,
482 + "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
483 + gpg_message_offset = verify_message.len;
484 +
485 + payload_size = parse_signature(extra->value, extra->len);
486 + if ((extra->len <= payload_size) ||
487 + (verify_signed_buffer(extra->value, payload_size,
488 + extra->value + payload_size,
489 + extra->len - payload_size,
490 + &verify_message) &&
491 + verify_message.len <= gpg_message_offset)) {
492 + strbuf_addstr(&verify_message, "No signature\n");
493 + status = -1;
494 + }
495 + else if (strstr(verify_message.buf + gpg_message_offset,
496 + ": Good signature from "))
497 + status = 0;
498 + else
499 + status = -1;
500 +
501 + show_sig_lines(opt, status, verify_message.buf);
502 + strbuf_release(&verify_message);
503 +}
504 +
505 +static void show_mergetag(struct rev_info *opt, struct commit *commit)
506 +{
507 + struct commit_extra_header *extra, *to_free;
508 +
509 + to_free = read_commit_extra_headers(commit, NULL);
510 + for (extra = to_free; extra; extra = extra->next) {
511 + if (strcmp(extra->key, "mergetag"))
512 + continue; /* not a merge tag */
513 + show_one_mergetag(opt, extra, commit);
514 + }
515 + free_commit_extra_headers(to_free);
516 +}
517 +
518 void show_log(struct rev_info *opt)
519 {
520 struct strbuf msgbuf = STRBUF_INIT;
@@ -554,8 +626,10 @@ void show_log(struct rev_info *opt)
626 }
627 }
628
557 - if (opt->show_signature)
629 + if (opt->show_signature) {
630 show_signature(opt, commit);
631 + show_mergetag(opt, commit);
632 + }
633
634 if (!commit->buffer)
635 return;