@@ -35,8 +35,11 @@ static const char *fast_export_usage[] = {
35
35
NULL
36
36
};
37
37
38
+ enum sign_mode { SIGN_ABORT , SIGN_VERBATIM , SIGN_STRIP , SIGN_WARN_VERBATIM , SIGN_WARN_STRIP };
39
+
38
40
static int progress ;
39
- static enum signed_tag_mode { SIGNED_TAG_ABORT , VERBATIM , WARN_VERBATIM , WARN_STRIP , STRIP } signed_tag_mode = SIGNED_TAG_ABORT ;
41
+ static enum sign_mode signed_tag_mode = SIGN_ABORT ;
42
+ static enum sign_mode signed_commit_mode = SIGN_ABORT ;
40
43
static enum tag_of_filtered_mode { TAG_FILTERING_ABORT , DROP , REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT ;
41
44
static enum reencode_mode { REENCODE_ABORT , REENCODE_YES , REENCODE_NO } reencode_mode = REENCODE_ABORT ;
42
45
static int fake_missing_tagger ;
@@ -53,23 +56,24 @@ static int anonymize;
53
56
static struct hashmap anonymized_seeds ;
54
57
static struct revision_sources revision_sources ;
55
58
56
- static int parse_opt_signed_tag_mode (const struct option * opt ,
59
+ static int parse_opt_sign_mode (const struct option * opt ,
57
60
const char * arg , int unset )
58
61
{
59
- enum signed_tag_mode * val = opt -> value ;
60
-
61
- if (unset || !strcmp (arg , "abort" ))
62
- * val = SIGNED_TAG_ABORT ;
62
+ enum sign_mode * val = opt -> value ;
63
+ if (unset )
64
+ return 0 ;
65
+ else if (!strcmp (arg , "abort" ))
66
+ * val = SIGN_ABORT ;
63
67
else if (!strcmp (arg , "verbatim" ) || !strcmp (arg , "ignore" ))
64
- * val = VERBATIM ;
68
+ * val = SIGN_VERBATIM ;
65
69
else if (!strcmp (arg , "warn-verbatim" ) || !strcmp (arg , "warn" ))
66
- * val = WARN_VERBATIM ;
70
+ * val = SIGN_WARN_VERBATIM ;
67
71
else if (!strcmp (arg , "warn-strip" ))
68
- * val = WARN_STRIP ;
72
+ * val = SIGN_WARN_STRIP ;
69
73
else if (!strcmp (arg , "strip" ))
70
- * val = STRIP ;
74
+ * val = SIGN_STRIP ;
71
75
else
72
- return error ("Unknown signed-tags mode: %s" , arg );
76
+ return error ("Unknown %s mode: %s" , opt -> long_name , arg );
73
77
return 0 ;
74
78
}
75
79
@@ -611,6 +615,44 @@ static void anonymize_ident_line(const char **beg, const char **end)
611
615
* end = out -> buf + out -> len ;
612
616
}
613
617
618
+ /*
619
+ * find_commit_multiline_header is similar to find_commit_header,
620
+ * except that it handles multi-line headers, rathar than simply
621
+ * returning the first line of the header.
622
+ *
623
+ * The returned string has had the ' ' line continuation markers
624
+ * removed, and points to statically allocated memory (not to memory
625
+ * within 'msg'), so it is only valid until the next call to
626
+ * find_commit_multiline_header.
627
+ *
628
+ * If the header is found, then *end is set to point at the '\n' in
629
+ * msg that immediately follows the header value.
630
+ */
631
+ static const char * find_commit_multiline_header (const char * msg ,
632
+ const char * key ,
633
+ const char * * end )
634
+ {
635
+ struct strbuf val = STRBUF_INIT ;
636
+ const char * bol , * eol ;
637
+ size_t len ;
638
+
639
+ bol = find_commit_header (msg , key , & len );
640
+ if (!bol )
641
+ return NULL ;
642
+ eol = bol + len ;
643
+ strbuf_add (& val , bol , len );
644
+
645
+ while (eol [0 ] == '\n' && eol [1 ] == ' ' ) {
646
+ bol = eol + 2 ;
647
+ eol = strchrnul (bol , '\n' );
648
+ strbuf_addch (& val , '\n' );
649
+ strbuf_add (& val , bol , eol - bol );
650
+ }
651
+
652
+ * end = eol ;
653
+ return strbuf_detach (& val , NULL );
654
+ }
655
+
614
656
static void handle_commit (struct commit * commit , struct rev_info * rev ,
615
657
struct string_list * paths_of_changed_objects )
616
658
{
@@ -619,6 +661,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
619
661
const char * author , * author_end , * committer , * committer_end ;
620
662
const char * encoding = NULL ;
621
663
size_t encoding_len ;
664
+ const char * signature_alg = NULL , * signature = NULL ;
622
665
const char * message ;
623
666
char * reencoded = NULL ;
624
667
struct commit_list * p ;
@@ -645,17 +688,25 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
645
688
commit_buffer_cursor = committer_end = strchrnul (committer , '\n' );
646
689
647
690
/*
648
- * find_commit_header() gets a `+ 1` because
649
- * commit_buffer_cursor points at the trailing "\n" at the end
650
- * of the previous line, but find_commit_header() wants a
691
+ * find_commit_header() and find_commit_multiline_header() get
692
+ * a `+ 1` because commit_buffer_cursor points at the trailing
693
+ * "\n" at the end of the previous line, but they want a
651
694
* pointer to the beginning of the next line.
652
695
*/
696
+
653
697
if (* commit_buffer_cursor == '\n' ) {
654
698
encoding = find_commit_header (commit_buffer_cursor + 1 , "encoding" , & encoding_len );
655
699
if (encoding )
656
700
commit_buffer_cursor = encoding + encoding_len ;
657
701
}
658
702
703
+ if (* commit_buffer_cursor == '\n' ) {
704
+ if ((signature = find_commit_multiline_header (commit_buffer_cursor + 1 , "gpgsig" , & commit_buffer_cursor )))
705
+ signature_alg = "sha1" ;
706
+ else if ((signature = find_commit_multiline_header (commit_buffer_cursor + 1 , "gpgsig-sha256" , & commit_buffer_cursor )))
707
+ signature_alg = "sha256" ;
708
+ }
709
+
659
710
message = strstr (commit_buffer_cursor , "\n\n" );
660
711
if (message )
661
712
message += 2 ;
@@ -719,6 +770,29 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
719
770
printf ("%.*s\n%.*s\n" ,
720
771
(int )(author_end - author ), author ,
721
772
(int )(committer_end - committer ), committer );
773
+ if (signature )
774
+ switch (signed_commit_mode ) {
775
+ case SIGN_ABORT :
776
+ die ("encountered signed commit %s; use "
777
+ "--signed-commits=<mode> to handle it" ,
778
+ oid_to_hex (& commit -> object .oid ));
779
+ case SIGN_WARN_VERBATIM :
780
+ warning ("exporting signed commit %s" ,
781
+ oid_to_hex (& commit -> object .oid ));
782
+ /* fallthru */
783
+ case SIGN_VERBATIM :
784
+ printf ("gpgsig %s\ndata %u\n%s" ,
785
+ signature_alg ,
786
+ (unsigned )strlen (signature ),
787
+ signature );
788
+ break ;
789
+ case SIGN_WARN_STRIP :
790
+ warning ("stripping signature from commit %s" ,
791
+ oid_to_hex (& commit -> object .oid ));
792
+ /* fallthru */
793
+ case SIGN_STRIP :
794
+ break ;
795
+ }
722
796
if (!reencoded && encoding )
723
797
printf ("encoding %.*s\n" , (int )encoding_len , encoding );
724
798
printf ("data %u\n%s" ,
@@ -834,21 +908,21 @@ static void handle_tag(const char *name, struct tag *tag)
834
908
"\n-----BEGIN PGP SIGNATURE-----\n" );
835
909
if (signature )
836
910
switch (signed_tag_mode ) {
837
- case SIGNED_TAG_ABORT :
911
+ case SIGN_ABORT :
838
912
die ("encountered signed tag %s; use "
839
913
"--signed-tags=<mode> to handle it" ,
840
914
oid_to_hex (& tag -> object .oid ));
841
- case WARN_VERBATIM :
915
+ case SIGN_WARN_VERBATIM :
842
916
warning ("exporting signed tag %s" ,
843
917
oid_to_hex (& tag -> object .oid ));
844
918
/* fallthru */
845
- case VERBATIM :
919
+ case SIGN_VERBATIM :
846
920
break ;
847
- case WARN_STRIP :
921
+ case SIGN_WARN_STRIP :
848
922
warning ("stripping signature from tag %s" ,
849
923
oid_to_hex (& tag -> object .oid ));
850
924
/* fallthru */
851
- case STRIP :
925
+ case SIGN_STRIP :
852
926
message_size = signature + 1 - message ;
853
927
break ;
854
928
}
@@ -1194,6 +1268,7 @@ int cmd_fast_export(int argc,
1194
1268
const char * prefix ,
1195
1269
struct repository * repo UNUSED )
1196
1270
{
1271
+ const char * env_signed_commits_noabort ;
1197
1272
struct rev_info revs ;
1198
1273
struct commit * commit ;
1199
1274
char * export_filename = NULL ,
@@ -1207,7 +1282,10 @@ int cmd_fast_export(int argc,
1207
1282
N_ ("show progress after <n> objects" )),
1208
1283
OPT_CALLBACK (0 , "signed-tags" , & signed_tag_mode , N_ ("mode" ),
1209
1284
N_ ("select handling of signed tags" ),
1210
- parse_opt_signed_tag_mode ),
1285
+ parse_opt_sign_mode ),
1286
+ OPT_CALLBACK (0 , "signed-commits" , & signed_commit_mode , N_ ("mode" ),
1287
+ N_ ("select handling of signed commits" ),
1288
+ parse_opt_sign_mode ),
1211
1289
OPT_CALLBACK (0 , "tag-of-filtered-object" , & tag_of_filtered_mode , N_ ("mode" ),
1212
1290
N_ ("select handling of tags that tag filtered objects" ),
1213
1291
parse_opt_tag_of_filtered_mode ),
@@ -1248,6 +1326,10 @@ int cmd_fast_export(int argc,
1248
1326
if (argc == 1 )
1249
1327
usage_with_options (fast_export_usage , options );
1250
1328
1329
+ env_signed_commits_noabort = getenv ("FAST_EXPORT_SIGNED_COMMITS_NOABORT" );
1330
+ if (env_signed_commits_noabort && * env_signed_commits_noabort )
1331
+ signed_commit_mode = SIGN_WARN_STRIP ;
1332
+
1251
1333
/* we handle encodings */
1252
1334
git_config (git_default_config , NULL );
1253
1335
0 commit comments