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,