pretty: %G[?GS] placeholders

Add new placeholders related to the GPG signature on signed commits. - %GG to show the raw verification message from GPG; - %G? to show either "G" for Good, "B" for Bad; - %GS to show the name of the signer. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Oct 21, 2011 at 21:06 UTC f6667c5ee8148af28cc97049695f60f5105b3061
1 file changed +86
pretty.c
+86
@@ -9,6 +9,7 @@
9 #include "notes.h"
10 #include "color.h"
11 #include "reflog-walk.h"
12 +#include "gpg-interface.h"
13
14 static char *user_format;
15 static struct cmt_fmt_map {
@@ -640,6 +641,12 @@ struct format_commit_context {
641 const struct pretty_print_context *pretty_ctx;
642 unsigned commit_header_parsed:1;
643 unsigned commit_message_parsed:1;
644 + unsigned commit_signature_parsed:1;
645 + struct {
646 + char *gpg_output;
647 + char good_bad;
648 + char *signer;
649 + } signature;
650 char *message;
651 size_t width, indent1, indent2;
652
@@ -822,6 +829,59 @@ static void rewrap_message_tail(struct strbuf *sb,
829 c->indent2 = new_indent2;
830 }
831
832 +static struct {
833 + char result;
834 + const char *check;
835 +} signature_check[] = {
836 + { 'G', ": Good signature from " },
837 + { 'B', ": BAD signature from " },
838 +};
839 +
840 +static void parse_signature_lines(struct format_commit_context *ctx)
841 +{
842 + const char *buf = ctx->signature.gpg_output;
843 + int i;
844 +
845 + for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
846 + const char *found = strstr(buf, signature_check[i].check);
847 + const char *next;
848 + if (!found)
849 + continue;
850 + ctx->signature.good_bad = signature_check[i].result;
851 + found += strlen(signature_check[i].check);
852 + next = strchrnul(found, '\n');
853 + ctx->signature.signer = xmemdupz(found, next - found);
854 + break;
855 + }
856 +}
857 +
858 +static void parse_commit_signature(struct format_commit_context *ctx)
859 +{
860 + struct strbuf payload = STRBUF_INIT;
861 + struct strbuf signature = STRBUF_INIT;
862 + struct strbuf gpg_output = STRBUF_INIT;
863 + int status;
864 +
865 + ctx->commit_signature_parsed = 1;
866 +
867 + if (parse_signed_commit(ctx->commit->object.sha1,
868 + &payload, &signature) <= 0)
869 + goto out;
870 + status = verify_signed_buffer(payload.buf, payload.len,
871 + signature.buf, signature.len,
872 + &gpg_output);
873 + if (status && !gpg_output.len)
874 + goto out;
875 + ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
876 + parse_signature_lines(ctx);
877 +
878 + out:
879 + strbuf_release(&gpg_output);
880 + strbuf_release(&payload);
881 + strbuf_release(&signature);
882 +}
883 +
884 +
885 static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
886 void *context)
887 {
@@ -974,6 +1034,30 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
1034 return 0;
1035 }
1036
1037 + if (placeholder[0] == 'G') {
1038 + if (!c->commit_signature_parsed)
1039 + parse_commit_signature(c);
1040 + switch (placeholder[1]) {
1041 + case 'G':
1042 + if (c->signature.gpg_output)
1043 + strbuf_addstr(sb, c->signature.gpg_output);
1044 + break;
1045 + case '?':
1046 + switch (c->signature.good_bad) {
1047 + case 'G':
1048 + case 'B':
1049 + strbuf_addch(sb, c->signature.good_bad);
1050 + }
1051 + break;
1052 + case 'S':
1053 + if (c->signature.signer)
1054 + strbuf_addstr(sb, c->signature.signer);
1055 + break;
1056 + }
1057 + return 2;
1058 + }
1059 +
1060 +
1061 /* For the rest we have to parse the commit header. */
1062 if (!c->commit_header_parsed)
1063 parse_commit_header(c);
@@ -1114,6 +1198,8 @@ void format_commit_message(const struct commit *commit,
1198
1199 if (context.message != commit->buffer)
1200 free(context.message);
1201 + free(context.signature.gpg_output);
1202 + free(context.signature.signer);
1203 }
1204
1205 static void pp_header(const struct pretty_print_context *pp,