Author: stsp Date: Tue Apr 6 14:20:21 2010 New Revision: 931162 URL: http://svn.apache.org/viewvc?rev=931162&view=rev Log: Cherry-pick r929288 and r931140 from the svn-patch-improvements branch to trunk, fixing the problem reported in:
Date: Wed, 3 Mar 2010 15:52:59 +0100 From: Stefan Sperling To: [email protected] Subject: svn patch fails on this diff Message-ID: <[email protected]> http://svn.haxx.se/dev/archive-2010-03/0097.shtml http://svn.haxx.se/dev/archive-2010-03/0098.shtml (attachment) Log messages of those revisions were: ------------------------------------------------------------------------ r929288 | dannas | 2010-03-30 23:11:15 +0200 (Tue, 30 Mar 2010) | 16 lines Fix bug with 'svn patch' not recognizing diff headers when parsing patches without the 'Index' line and the '======' line. The old code just assumed that the first line after the hunk would not be a '-'. But it can be so we must handle it. * subversion/libsvn_diff/parse-diff.c (parse_next_hunk): Check that we have not read all the lines, that the hunk header said, the hunk should consist of. We need to check for both nr of modified and original lines since we can do a reverse parsing. That means treating '+' as '-' and the other way around. * subversion/tests/cmdline/patch_tests.py (patch_no_index_line): New. (test_list): Add the new test. ------------------------------------------------------------------------ r931140 | stsp | 2010-04-06 15:08:19 +0200 (Tue, 06 Apr 2010) | 4 lines On the svn-patch-improvements branch: * subversion/libsvn_diff/parse-diff.c (parse_next_hunk): Make sure we never overflow modified_lines. ------------------------------------------------------------------------ Modified: subversion/trunk/ (props changed) subversion/trunk/subversion/libsvn_diff/parse-diff.c subversion/trunk/subversion/tests/cmdline/patch_tests.py Propchange: subversion/trunk/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Tue Apr 6 14:20:21 2010 @@ -24,6 +24,7 @@ /subversion/branches/reintegrate-improvements:873853-874164 /subversion/branches/subtree-mergeinfo:876734-878766 /subversion/branches/svn-mergeinfo-enhancements:870119-870195,870197-870288 +/subversion/branches/svn-patch-improvements:929288,931140 /subversion/branches/svnpatch-diff:865738-876477 /subversion/branches/svnraisetc:874709-875149 /subversion/branches/svnserve-logging:869828-870893 Modified: subversion/trunk/subversion/libsvn_diff/parse-diff.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/parse-diff.c?rev=931162&r1=931161&r2=931162&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_diff/parse-diff.c (original) +++ subversion/trunk/subversion/libsvn_diff/parse-diff.c Tue Apr 6 14:20:21 2010 @@ -281,6 +281,7 @@ parse_next_hunk(svn_hunk_t **hunk, svn_stream_t *original_text; svn_stream_t *modified_text; svn_linenum_t original_lines; + svn_linenum_t modified_lines; svn_linenum_t leading_context; svn_linenum_t trailing_context; svn_boolean_t changed_line_seen; @@ -354,16 +355,18 @@ parse_next_hunk(svn_hunk_t **hunk, c = line->data[0]; /* Tolerate chopped leading spaces on empty lines. */ - if (original_lines > 0 && (c == ' ' || (! eof && line->len == 0))) + if (original_lines > 0 && modified_lines > 0 && + (c == ' ' || (! eof && line->len == 0))) { hunk_seen = TRUE; original_lines--; + modified_lines--; if (changed_line_seen) trailing_context++; else leading_context++; } - else if (c == add || c == del) + else if (original_lines > 0 && c == del) { hunk_seen = TRUE; changed_line_seen = TRUE; @@ -373,8 +376,19 @@ parse_next_hunk(svn_hunk_t **hunk, if (trailing_context > 0) trailing_context = 0; - if (original_lines > 0 && c == del) - original_lines--; + original_lines--; + } + else if (modified_lines > 0 && c == add) + { + hunk_seen = TRUE; + changed_line_seen = TRUE; + + /* A hunk may have context in the middle. We only want the + last lines of context. */ + if (trailing_context > 0) + trailing_context = 0; + + modified_lines--; } else { @@ -395,7 +409,10 @@ parse_next_hunk(svn_hunk_t **hunk, in_hunk = parse_hunk_header(line->data, *hunk, reverse, iterpool); if (in_hunk) - original_lines = (*hunk)->original_length; + { + original_lines = (*hunk)->original_length; + modified_lines = (*hunk)->modified_length; + } } else if (starts_with(line->data, minus)) /* This could be a header of another patch. Bail out. */ Modified: subversion/trunk/subversion/tests/cmdline/patch_tests.py URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/patch_tests.py?rev=931162&r1=931161&r2=931162&view=diff ============================================================================== --- subversion/trunk/subversion/tests/cmdline/patch_tests.py (original) +++ subversion/trunk/subversion/tests/cmdline/patch_tests.py Tue Apr 6 14:20:21 2010 @@ -841,6 +841,92 @@ def patch_strip1(sbox): 1, # dry-run '-p1') +def patch_no_index_line(sbox): + "patch with no index lines" + + sbox.build() + wc_dir = sbox.wc_dir + + patch_file_path = tempfile.mkstemp(dir=os.path.abspath(svntest.main.temp_dir))[1] + gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma') + iota_path = os.path.join(wc_dir, 'iota') + + gamma_contents = [ + "\n", + "Another line before\n", + "A third line before\n", + "This is the file 'gamma'.\n", + "A line after\n", + "Another line after\n", + "A third line after\n", + ] + + svntest.main.file_write(gamma_path, ''.join(gamma_contents)) + expected_output = svntest.wc.State(wc_dir, { + 'A/D/gamma' : Item(verb='Sending'), + }) + expected_status = svntest.actions.get_virginal_state(wc_dir, 1) + expected_status.tweak('A/D/gamma', wc_rev=2) + svntest.actions.run_and_verify_commit(wc_dir, expected_output, + expected_status, None, wc_dir) + unidiff_patch = [ + "--- A/D/gamma\t(revision 1)\n", + "+++ A/D/gamma\t(working copy)\n", + "@@ -1,7 +1,7 @@\n", + " \n", + " Another line before\n", + " A third line before\n", + "-This is the file 'gamma'.\n", + "+It is the file 'gamma'.\n", + " A line after\n", + " Another line after\n", + " A third line after\n", + "--- iota\t(revision 1)\n", + "+++ iota\t(working copy)\n", + "@@ -1 +1,2 @@\n", + " This is the file 'iota'.\n", + "+Some more bytes\n", + ] + + svntest.main.file_write(patch_file_path, ''.join(unidiff_patch)) + + gamma_contents = [ + "\n", + "Another line before\n", + "A third line before\n", + "It is the file 'gamma'.\n", + "A line after\n", + "Another line after\n", + "A third line after\n", + ] + iota_contents = [ + "This is the file 'iota'.\n", + "Some more bytes\n", + ] + expected_output = [ + 'U %s\n' % os.path.join(wc_dir, 'A', 'D', 'gamma'), + 'U %s\n' % os.path.join(wc_dir, 'iota'), + ] + + expected_disk = svntest.main.greek_state.copy() + expected_disk.tweak('A/D/gamma', contents=''.join(gamma_contents)) + expected_disk.tweak('iota', contents=''.join(iota_contents)) + + expected_status = svntest.actions.get_virginal_state(wc_dir, 1) + expected_status.tweak('A/D/gamma', status='M ', wc_rev=2) + expected_status.tweak('iota', status='M ', wc_rev=1) + + expected_skip = wc.State('', { }) + + svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path), + expected_output, + expected_disk, + expected_status, + expected_skip, + None, # expected err + 1, # check-props + 1) # dry-run + def patch_add_new_dir(sbox): "patch with missing dirs" @@ -2187,6 +2273,7 @@ test_list = [ None, patch_offset, patch_chopped_leading_spaces, patch_strip1, + patch_no_index_line, patch_add_new_dir, patch_reject, patch_keywords,
