зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/apply-epoch-patch'
* jc/apply-epoch-patch: apply: notice creation/removal patches produced by GNU diff
This commit is contained in:
Коммит
5762101602
|
@ -457,6 +457,76 @@ static int guess_p_value(const char *nameline)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does the ---/+++ line has the POSIX timestamp after the last HT?
|
||||||
|
* GNU diff puts epoch there to signal a creation/deletion event. Is
|
||||||
|
* this such a timestamp?
|
||||||
|
*/
|
||||||
|
static int has_epoch_timestamp(const char *nameline)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are only interested in epoch timestamp; any non-zero
|
||||||
|
* fraction cannot be one, hence "(\.0+)?" in the regexp below.
|
||||||
|
* For the same reason, the date must be either 1969-12-31 or
|
||||||
|
* 1970-01-01, and the seconds part must be "00".
|
||||||
|
*/
|
||||||
|
const char stamp_regexp[] =
|
||||||
|
"^(1969-12-31|1970-01-01)"
|
||||||
|
" "
|
||||||
|
"[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
|
||||||
|
" "
|
||||||
|
"([-+][0-2][0-9][0-5][0-9])\n";
|
||||||
|
const char *timestamp = NULL, *cp;
|
||||||
|
static regex_t *stamp;
|
||||||
|
regmatch_t m[10];
|
||||||
|
int zoneoffset;
|
||||||
|
int hourminute;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
for (cp = nameline; *cp != '\n'; cp++) {
|
||||||
|
if (*cp == '\t')
|
||||||
|
timestamp = cp + 1;
|
||||||
|
}
|
||||||
|
if (!timestamp)
|
||||||
|
return 0;
|
||||||
|
if (!stamp) {
|
||||||
|
stamp = xmalloc(sizeof(*stamp));
|
||||||
|
if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
|
||||||
|
warning("Cannot prepare timestamp regexp %s",
|
||||||
|
stamp_regexp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
|
||||||
|
if (status) {
|
||||||
|
if (status != REG_NOMATCH)
|
||||||
|
warning("regexec returned %d for input: %s",
|
||||||
|
status, timestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneoffset = strtol(timestamp + m[3].rm_so + 1, NULL, 10);
|
||||||
|
zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
|
||||||
|
if (timestamp[m[3].rm_so] == '-')
|
||||||
|
zoneoffset = -zoneoffset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
|
||||||
|
* (west of GMT) or 1970-01-01 (east of GMT)
|
||||||
|
*/
|
||||||
|
if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) ||
|
||||||
|
(0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hourminute = (strtol(timestamp + 11, NULL, 10) * 60 +
|
||||||
|
strtol(timestamp + 14, NULL, 10) -
|
||||||
|
zoneoffset);
|
||||||
|
|
||||||
|
return ((zoneoffset < 0 && hourminute == 1440) ||
|
||||||
|
(0 <= zoneoffset && !hourminute));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the name etc info from the ---/+++ lines of a traditional patch header
|
* Get the name etc info from the ---/+++ lines of a traditional patch header
|
||||||
*
|
*
|
||||||
|
@ -493,7 +563,17 @@ static void parse_traditional_patch(const char *first, const char *second, struc
|
||||||
} else {
|
} else {
|
||||||
name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
|
name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
|
||||||
name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB);
|
name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB);
|
||||||
patch->old_name = patch->new_name = name;
|
if (has_epoch_timestamp(first)) {
|
||||||
|
patch->is_new = 1;
|
||||||
|
patch->is_delete = 0;
|
||||||
|
patch->new_name = name;
|
||||||
|
} else if (has_epoch_timestamp(second)) {
|
||||||
|
patch->is_new = 0;
|
||||||
|
patch->is_delete = 1;
|
||||||
|
patch->old_name = name;
|
||||||
|
} else {
|
||||||
|
patch->old_name = patch->new_name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!name)
|
if (!name)
|
||||||
die("unable to find filename in patch at line %d", linenr);
|
die("unable to find filename in patch at line %d", linenr);
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009 Junio C Hamano
|
||||||
|
|
||||||
|
test_description='git-apply notices removal patches generated by GNU diff'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
cat <<-EOF >c &&
|
||||||
|
diff -ruN a/file b/file
|
||||||
|
--- a/file TS0
|
||||||
|
+++ b/file TS1
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+something
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<-EOF >d &&
|
||||||
|
diff -ruN a/file b/file
|
||||||
|
--- a/file TS0
|
||||||
|
+++ b/file TS1
|
||||||
|
@@ -1 +0,0 @@
|
||||||
|
-something
|
||||||
|
EOF
|
||||||
|
|
||||||
|
timeWest="1982-09-16 07:00:00.000000000 -0800" &&
|
||||||
|
timeGMT="1982-09-16 15:00:00.000000000 +0000" &&
|
||||||
|
timeEast="1982-09-17 00:00:00.000000000 +0900" &&
|
||||||
|
|
||||||
|
epocWest="1969-12-31 16:00:00.000000000 -0800" &&
|
||||||
|
epocGMT="1970-01-01 00:00:00.000000000 +0000" &&
|
||||||
|
epocEast="1970-01-01 09:00:00.000000000 +0900" &&
|
||||||
|
|
||||||
|
sed -e "s/TS0/$epocWest/" -e "s/TS1/$timeWest/" <c >createWest.patch &&
|
||||||
|
sed -e "s/TS0/$epocEast/" -e "s/TS1/$timeEast/" <c >createEast.patch &&
|
||||||
|
sed -e "s/TS0/$epocGMT/" -e "s/TS1/$timeGMT/" <c >createGMT.patch &&
|
||||||
|
|
||||||
|
sed -e "s/TS0/$timeWest/" -e "s/TS1/$timeWest/" <c >addWest.patch &&
|
||||||
|
sed -e "s/TS0/$timeEast/" -e "s/TS1/$timeEast/" <c >addEast.patch &&
|
||||||
|
sed -e "s/TS0/$timeGMT/" -e "s/TS1/$timeGMT/" <c >addGMT.patch &&
|
||||||
|
|
||||||
|
sed -e "s/TS0/$timeWest/" -e "s/TS1/$timeWest/" <d >emptyWest.patch &&
|
||||||
|
sed -e "s/TS0/$timeEast/" -e "s/TS1/$timeEast/" <d >emptyEast.patch &&
|
||||||
|
sed -e "s/TS0/$timeGMT/" -e "s/TS1/$timeGMT/" <d >emptyGMT.patch &&
|
||||||
|
|
||||||
|
sed -e "s/TS0/$timeWest/" -e "s/TS1/$epocWest/" <d >removeWest.patch &&
|
||||||
|
sed -e "s/TS0/$timeEast/" -e "s/TS1/$epocEast/" <d >removeEast.patch &&
|
||||||
|
sed -e "s/TS0/$timeGMT/" -e "s/TS1/$epocGMT/" <d >removeGMT.patch &&
|
||||||
|
|
||||||
|
echo something >something &&
|
||||||
|
>empty
|
||||||
|
'
|
||||||
|
|
||||||
|
for patch in *.patch
|
||||||
|
do
|
||||||
|
test_expect_success "test $patch" '
|
||||||
|
rm -f file .git/index &&
|
||||||
|
case "$patch" in
|
||||||
|
create*)
|
||||||
|
# must be able to create
|
||||||
|
git apply --index $patch &&
|
||||||
|
test_cmp file something &&
|
||||||
|
# must notice the file is already there
|
||||||
|
>file &&
|
||||||
|
git add file &&
|
||||||
|
test_must_fail git apply $patch
|
||||||
|
;;
|
||||||
|
add*)
|
||||||
|
# must be able to create or patch
|
||||||
|
git apply $patch &&
|
||||||
|
test_cmp file something &&
|
||||||
|
>file &&
|
||||||
|
git apply $patch &&
|
||||||
|
test_cmp file something
|
||||||
|
;;
|
||||||
|
empty*)
|
||||||
|
# must leave an empty file
|
||||||
|
cat something >file &&
|
||||||
|
git add file &&
|
||||||
|
git apply --index $patch &&
|
||||||
|
test -f file &&
|
||||||
|
test_cmp empty file
|
||||||
|
;;
|
||||||
|
remove*)
|
||||||
|
# must remove the file
|
||||||
|
cat something >file &&
|
||||||
|
git add file &&
|
||||||
|
git apply --index $patch &&
|
||||||
|
! test -f file
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
|
test_done
|
Загрузка…
Ссылка в новой задаче