|
9 | 9 | #include "notes.h"
|
10 | 10 | #include "color.h"
|
11 | 11 | #include "reflog-walk.h"
|
| 12 | +#include "gpg-interface.h" |
12 | 13 |
|
13 | 14 | static char *user_format;
|
14 | 15 | static struct cmt_fmt_map {
|
@@ -640,6 +641,12 @@ struct format_commit_context {
|
640 | 641 | const struct pretty_print_context *pretty_ctx;
|
641 | 642 | unsigned commit_header_parsed:1;
|
642 | 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; |
643 | 650 | char *message;
|
644 | 651 | size_t width, indent1, indent2;
|
645 | 652 |
|
@@ -822,6 +829,59 @@ static void rewrap_message_tail(struct strbuf *sb,
|
822 | 829 | c->indent2 = new_indent2;
|
823 | 830 | }
|
824 | 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 | + |
825 | 885 | static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
826 | 886 | void *context)
|
827 | 887 | {
|
@@ -974,6 +1034,30 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
974 | 1034 | return 0;
|
975 | 1035 | }
|
976 | 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 | + |
977 | 1061 | /* For the rest we have to parse the commit header. */
|
978 | 1062 | if (!c->commit_header_parsed)
|
979 | 1063 | parse_commit_header(c);
|
@@ -1114,6 +1198,8 @@ void format_commit_message(const struct commit *commit,
|
1114 | 1198 |
|
1115 | 1199 | if (context.message != commit->buffer)
|
1116 | 1200 | free(context.message);
|
| 1201 | + free(context.signature.gpg_output); |
| 1202 | + free(context.signature.signer); |
1117 | 1203 | }
|
1118 | 1204 |
|
1119 | 1205 | static void pp_header(const struct pretty_print_context *pp,
|
|
0 commit comments