You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2018/01/24 19:48:22 UTC
svn commit: r1822151 - in /subversion/trunk/subversion:
libsvn_diff/parse-diff.c tests/cmdline/patch_tests.py
Author: julianfoad
Date: Wed Jan 24 19:48:22 2018
New Revision: 1822151
URL: http://svn.apache.org/viewvc?rev=1822151&view=rev
Log:
Teach 'patch' to read an svn:mergeinfo property change formatted as a normal
property diff.
Previously it could only read the pretty-printed format.
Part of issue #3747 "'svn diff' and 'svn patch' support of svn:mergeinfo".
* subversion/libsvn_diff/parse-diff.c
(parse_pretty_mergeinfo_line): Rename from 'parse_mergeinfo'. Don't munge
the hunk header object. Improve documentation.
(parse_next_hunk): When parsing pretty-printed mergeinfo, allow to fall
through to normal processing if pretty-print format is not found. If
a pretty-print hunk is found, return a hunk object. (Previously it
quietly processed it and moved on to the next hunk without informing
the caller.)
(parse_hunks): Instead of skipping storing any mergeinfo hunks, only
skip storing pretty-print-mergeinfo hunks, but do store those formatted
in the regular property diff format.
* subversion/tests/cmdline/patch_tests.py
(patch_mergeinfo_in_regular_prop_format): New test.
(test_list): Run it.
Modified:
subversion/trunk/subversion/libsvn_diff/parse-diff.c
subversion/trunk/subversion/tests/cmdline/patch_tests.py
Modified: subversion/trunk/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/parse-diff.c?rev=1822151&r1=1822150&r2=1822151&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/trunk/subversion/libsvn_diff/parse-diff.c Wed Jan 24 19:48:22 2018
@@ -69,6 +69,11 @@ struct svn_diff_hunk_t {
/* APR file handle to the patch file this hunk came from. */
apr_file_t *apr_file;
+ /* Whether the hunk was interpreted as pretty-print mergeinfo. If so,
+ the hunk content is in PATCH and the rest of this hunk object is
+ mostly uninitialized. */
+ svn_boolean_t is_pretty_print_mergeinfo;
+
/* Ranges used to keep track of this hunk's texts positions within
* the patch file. */
struct svn_diff__hunk_range diff_text_range;
@@ -899,10 +904,6 @@ parse_prop_name(const char **prop_name,
* The hunk header has the following format:
* ## -0,NUMBER_OF_REVERSE_MERGES +0,NUMBER_OF_FORWARD_MERGES ##
*
- * At this point, the number of reverse merges has already been
- * parsed into HUNK->ORIGINAL_LENGTH, and the number of forward
- * merges has been parsed into HUNK->MODIFIED_LENGTH.
- *
* The header is followed by a list of mergeinfo, one path per line.
* This function parses such lines. Lines describing reverse merges
* appear first, and then all lines describing forward merges appear.
@@ -914,18 +915,27 @@ parse_prop_name(const char **prop_name,
* ":r", which in turn is followed by a mergeinfo revision range,
* which is terminated by whitespace or end-of-string.
*
- * If the current line meets the above criteria and we're able
- * to parse valid mergeinfo from it, the resulting mergeinfo
- * is added to patch->mergeinfo or patch->reverse_mergeinfo,
- * and we proceed to the next line.
+ * *NUMBER_OF_REVERSE_MERGES and *NUMBER_OF_FORWARD_MERGES are the
+ * numbers of reverse and forward merges remaining to be read. This
+ * function decrements *NUMBER_OF_REVERSE_MERGES for each LINE
+ * parsed until that is zero, then *NUMBER_OF_FORWARD_MERGES for
+ * each LINE parsed until that is zero. If both are zero, it parses
+ * and discards LINE.
+ *
+ * If LINE is successfully parsed, *FOUND_MERGEINFO is set to TRUE,
+ * otherwise to FALSE.
+ *
+ * If LINE is successfully parsed and counted, the resulting mergeinfo
+ * is added to PATCH->mergeinfo or PATCH->reverse_mergeinfo.
*/
static svn_error_t *
-parse_mergeinfo(svn_boolean_t *found_mergeinfo,
- svn_stringbuf_t *line,
- svn_diff_hunk_t *hunk,
- svn_patch_t *patch,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+parse_pretty_mergeinfo_line(svn_boolean_t *found_mergeinfo,
+ svn_linenum_t *number_of_reverse_merges,
+ svn_linenum_t *number_of_forward_merges,
+ svn_stringbuf_t *line,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
char *slash = strchr(line->data, '/');
char *colon = strrchr(line->data, ':');
@@ -972,7 +982,7 @@ parse_mergeinfo(svn_boolean_t *found_mer
if (mergeinfo)
{
- if (hunk->original_length > 0) /* reverse merges */
+ if (*number_of_reverse_merges > 0) /* reverse merges */
{
if (patch->reverse)
{
@@ -994,9 +1004,9 @@ parse_mergeinfo(svn_boolean_t *found_mer
result_pool,
scratch_pool));
}
- hunk->original_length--;
+ (*number_of_reverse_merges)--;
}
- else if (hunk->modified_length > 0) /* forward merges */
+ else if (number_of_forward_merges > 0) /* forward merges */
{
if (patch->reverse)
{
@@ -1018,7 +1028,7 @@ parse_mergeinfo(svn_boolean_t *found_mer
result_pool,
scratch_pool));
}
- hunk->modified_length--;
+ (*number_of_forward_merges)--;
}
*found_mergeinfo = TRUE;
@@ -1165,18 +1175,48 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
if (in_hunk && *is_property && *prop_name &&
strcmp(*prop_name, SVN_PROP_MERGEINFO) == 0)
{
- svn_boolean_t found_mergeinfo;
+ svn_boolean_t found_pretty_mergeinfo_line;
- SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
- result_pool, iterpool));
- if (found_mergeinfo)
- continue; /* Proceed to the next line in the svn:mergeinfo hunk. */
- else
+ if (! hunk_seen)
+ {
+ /* We're reading the first line of the hunk, so the start
+ * of the line just read is the hunk text's byte offset. */
+ start = last_line;
+ }
+
+ SVN_ERR(parse_pretty_mergeinfo_line(&found_pretty_mergeinfo_line,
+ &original_lines, &modified_lines,
+ line, patch,
+ result_pool, iterpool));
+ if (found_pretty_mergeinfo_line)
{
- /* Perhaps we can also use original_lines/modified_lines here */
+ hunk_seen = TRUE;
+ (*hunk)->is_pretty_print_mergeinfo = TRUE;
+ continue; /* Proceed to the next line in the svn:mergeinfo hunk. */
+ }
- in_hunk = FALSE; /* On to next property */
+ if ((*hunk)->is_pretty_print_mergeinfo)
+ {
+ /* We have reached the end of the pretty-print-mergeinfo hunk.
+ (This format uses only one hunk.) */
+ if (eof)
+ {
+ /* The hunk ends at EOF. */
+ end = pos;
+ }
+ else
+ {
+ /* The start of the current line marks the first byte
+ * after the hunk text. */
+ end = last_line;
+ }
+ original_end = end;
+ modified_end = end;
+ break;
}
+
+ /* Otherwise, this is a property diff in the
+ regular format so fall through to normal processing. */
}
if (in_hunk)
@@ -1971,10 +2011,10 @@ parse_hunks(svn_patch_t *patch, apr_file
else
last_prop_name = prop_name;
- /* Skip svn:mergeinfo properties.
- * Mergeinfo data cannot be represented as a hunk and
+ /* Skip pretty-printed svn:mergeinfo property hunks.
+ * Pretty-printed mergeinfo data cannot be represented as a hunk and
* is therefore stored in PATCH itself. */
- if (strcmp(prop_name, SVN_PROP_MERGEINFO) == 0)
+ if (hunk->is_pretty_print_mergeinfo)
continue;
SVN_ERR(add_property_hunk(patch, prop_name, hunk, prop_operation,
Modified: subversion/trunk/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/patch_tests.py?rev=1822151&r1=1822150&r2=1822151&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/patch_tests.py Wed Jan 24 19:48:22 2018
@@ -7791,6 +7791,68 @@ def patch_merge(sbox):
expected_disk, None,
expected_skip)
+def patch_mergeinfo_in_regular_prop_format(sbox):
+ "patch mergeinfo in regular prop format"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ strip_count = wc_dir.count(os.path.sep)+1
+
+ sbox.simple_copy('A/B/E', 'E')
+ sbox.simple_append('A/B/E/alpha', 'extra\nlines\n')
+ sbox.simple_commit()
+
+ sbox.simple_propset('a', 'A', 'E') # 'a' < 'svn:mergeinfo'
+ sbox.simple_propset('z', 'Z', 'E') # 'z' > 'svn:mergeinfo'
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'merge', '^/A/B/E', sbox.ospath('E'))
+ # Rename 'svn:mergeinfo' to 'svn_mergeinfo' so that 'diff' doesn't
+ # pretty-print it; then rename it back before we run it through 'patch'.
+ # (Alternatively, we could disable pretty-printing when we implement a
+ # command-line switch to do so.)
+ mergeinfo_value = sbox.simple_propget('svn:mergeinfo', 'E')
+ sbox.simple_propdel('svn:mergeinfo', 'E')
+ sbox.simple_propset('svn_mergeinfo', mergeinfo_value, 'E')
+
+ _, diff, _ = svntest.actions.run_and_verify_svn(None, [],
+ 'diff', wc_dir)
+ diff = re.sub('svn_mergeinfo', 'svn:mergeinfo', ''.join(diff))
+
+ sbox.simple_revert('E', 'E/alpha')
+
+ patch = sbox.get_tempname('recurse.patch')
+ svntest.main.file_write(patch, diff, mode='wb')
+
+ expected_output = wc.State(wc_dir, {
+ 'E' : Item(status=' U'),
+ 'E/alpha' : Item(status='U '),
+ })
+ expected_skip = wc.State(wc_dir, {})
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ 'E' : Item(status=' M', wc_rev='2'),
+ 'E/alpha' : Item(status='M ', wc_rev='2'),
+ 'E/beta' : Item(status=' ', wc_rev='2'),
+ })
+ expected_status.tweak('A/B/E/alpha', wc_rev=2)
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('A/B/E/alpha', contents="This is the file 'alpha'.\nextra\nlines\n")
+ expected_disk.add({
+ 'E' : Item(props={'a': 'A',
+ # here is the correctly patched mergeinfo
+ 'svn:mergeinfo': '/A/B/E:2',
+ 'z': 'Z'}),
+ 'E/beta' : Item(contents="This is the file 'beta'.\n"),
+ 'E/alpha' : Item(contents="This is the file 'alpha'.\nextra\nlines\n"),
+ })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
########################################################################
#Run the tests
@@ -7874,6 +7936,7 @@ test_list = [ None,
missing_trailing_context,
patch_missed_trail,
patch_merge,
+ patch_mergeinfo_in_regular_prop_format,
]
if __name__ == '__main__':