Skip to content

Commit 94cd175

Browse files
pyokagangitster
authored andcommitted
builtin-am: support and auto-detect mercurial patches
Since 0cfd112 (am: preliminary support for hg patches, 2011-08-29), git-am.sh could convert mercurial patches to an RFC2822 mail patch suitable for parsing with git-mailinfo, and queue them in the state directory for application. Since 15ced75 (git-am foreign patch support: autodetect some patch formats, 2009-05-27), git-am.sh was able to auto-detect mercurial patches by checking if the file begins with the line: # HG changeset patch Re-implement the above in builtin/am.c. Helped-by: Stefan Beller <[email protected]> Signed-off-by: Paul Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 336108c commit 94cd175

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

builtin/am.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ enum patch_format {
8181
PATCH_FORMAT_UNKNOWN = 0,
8282
PATCH_FORMAT_MBOX,
8383
PATCH_FORMAT_STGIT,
84-
PATCH_FORMAT_STGIT_SERIES
84+
PATCH_FORMAT_STGIT_SERIES,
85+
PATCH_FORMAT_HG
8586
};
8687

8788
enum keep_type {
@@ -656,6 +657,11 @@ static int detect_patch_format(const char **paths)
656657
goto done;
657658
}
658659

660+
if (!strcmp(l1.buf, "# HG changeset patch")) {
661+
ret = PATCH_FORMAT_HG;
662+
goto done;
663+
}
664+
659665
strbuf_reset(&l2);
660666
strbuf_getline_crlf(&l2, fp);
661667
strbuf_reset(&l3);
@@ -853,6 +859,68 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,
853859
return ret;
854860
}
855861

862+
/**
863+
* A split_patches_conv() callback that converts a mercurial patch to a RFC2822
864+
* message suitable for parsing with git-mailinfo.
865+
*/
866+
static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
867+
{
868+
struct strbuf sb = STRBUF_INIT;
869+
870+
while (!strbuf_getline(&sb, in, '\n')) {
871+
const char *str;
872+
873+
if (skip_prefix(sb.buf, "# User ", &str))
874+
fprintf(out, "From: %s\n", str);
875+
else if (skip_prefix(sb.buf, "# Date ", &str)) {
876+
unsigned long timestamp;
877+
long tz, tz2;
878+
char *end;
879+
880+
errno = 0;
881+
timestamp = strtoul(str, &end, 10);
882+
if (errno)
883+
return error(_("invalid timestamp"));
884+
885+
if (!skip_prefix(end, " ", &str))
886+
return error(_("invalid Date line"));
887+
888+
errno = 0;
889+
tz = strtol(str, &end, 10);
890+
if (errno)
891+
return error(_("invalid timezone offset"));
892+
893+
if (*end)
894+
return error(_("invalid Date line"));
895+
896+
/*
897+
* mercurial's timezone is in seconds west of UTC,
898+
* however git's timezone is in hours + minutes east of
899+
* UTC. Convert it.
900+
*/
901+
tz2 = labs(tz) / 3600 * 100 + labs(tz) % 3600 / 60;
902+
if (tz > 0)
903+
tz2 = -tz2;
904+
905+
fprintf(out, "Date: %s\n", show_date(timestamp, tz2, DATE_MODE(RFC2822)));
906+
} else if (starts_with(sb.buf, "# ")) {
907+
continue;
908+
} else {
909+
fprintf(out, "\n%s\n", sb.buf);
910+
break;
911+
}
912+
}
913+
914+
strbuf_reset(&sb);
915+
while (strbuf_fread(&sb, 8192, in) > 0) {
916+
fwrite(sb.buf, 1, sb.len, out);
917+
strbuf_reset(&sb);
918+
}
919+
920+
strbuf_release(&sb);
921+
return 0;
922+
}
923+
856924
/**
857925
* Splits a list of files/directories into individual email patches. Each path
858926
* in `paths` must be a file/directory that is formatted according to
@@ -885,6 +953,8 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
885953
return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
886954
case PATCH_FORMAT_STGIT_SERIES:
887955
return split_mail_stgit_series(state, paths, keep_cr);
956+
case PATCH_FORMAT_HG:
957+
return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
888958
default:
889959
die("BUG: invalid patch_format");
890960
}
@@ -1937,6 +2007,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
19372007
*opt_value = PATCH_FORMAT_STGIT;
19382008
else if (!strcmp(arg, "stgit-series"))
19392009
*opt_value = PATCH_FORMAT_STGIT_SERIES;
2010+
else if (!strcmp(arg, "hg"))
2011+
*opt_value = PATCH_FORMAT_HG;
19402012
else
19412013
return error(_("Invalid value for --patch-format: %s"), arg);
19422014
return 0;

0 commit comments

Comments
 (0)