You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/09/28 15:57:31 UTC
svn commit: r1705692 - in /subversion/trunk/subversion:
libsvn_client/patch.c svn/notify.c tests/cmdline/patch_tests.py
Author: rhuijben
Date: Mon Sep 28 13:57:30 2015
New Revision: 1705692
URL: http://svn.apache.org/viewvc?rev=1705692&view=rev
Log:
Tweak the 'svn patch' property code to properly allow repeating patches
as already applied.
Found by r1705663 work.
* subversion/libsvn_client/patch.c
(patch_target_t): Add booleans for already applied handling.
(get_hunk_info): Detect deletes that are already applied.
(send_patch_notification): Improve notification info to avoid
notifying about hunks without an attached file.
(apply_one_patch): Register already applied hunks.
* subversion/svn/notify.c
(notify_body): Notify filenames when property changes are merged.
Modified:
subversion/trunk/subversion/libsvn_client/patch.c
subversion/trunk/subversion/svn/notify.c
subversion/trunk/subversion/tests/cmdline/patch_tests.py
Modified: subversion/trunk/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/patch.c?rev=1705692&r1=1705691&r2=1705692&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/patch.c (original)
+++ subversion/trunk/subversion/libsvn_client/patch.c Mon Sep 28 13:57:30 2015
@@ -219,6 +219,12 @@ typedef struct patch_target_t {
/* True if at least one property hunk was rejected. */
svn_boolean_t had_prop_rejects;
+ /* True if at least one hunk was handled as already applied */
+ svn_boolean_t had_already_applied;
+
+ /* True if at least one property hunk was handled as already applied */
+ svn_boolean_t had_prop_already_applied;
+
/* True if the target file had local modifications before the
* patch was applied to it. */
svn_boolean_t local_mods;
@@ -1879,9 +1885,15 @@ get_hunk_info(hunk_info_t **hi, patch_ta
SVN_ERR(seek_to_line(content, saved_line, scratch_pool));
}
+ else if (!content->existed && svn_diff_hunk_get_modified_start(hunk) == 0)
+ {
+ /* The hunk wants to delete a file or property which doesn't exist. */
+ matched_line = 0;
+ already_applied = TRUE;
+ }
else
{
- /* The hunk wants to modify a file which doesn't exist. */
+ /* The hunk wants to modify a file or property which doesn't exist. */
matched_line = 0;
}
@@ -2196,11 +2208,19 @@ send_patch_notification(const patch_targ
notify->content_state = svn_wc_notify_state_merged;
else if (target->has_text_changes)
notify->content_state = svn_wc_notify_state_changed;
+ else if (target->had_already_applied)
+ notify->content_state = svn_wc_notify_state_merged;
+ else
+ notify->content_state = svn_wc_notify_state_unchanged;
if (target->had_prop_rejects)
notify->prop_state = svn_wc_notify_state_conflicted;
else if (target->has_prop_changes)
notify->prop_state = svn_wc_notify_state_changed;
+ else if (target->had_prop_already_applied)
+ notify->prop_state = svn_wc_notify_state_merged;
+ else
+ notify->prop_state = svn_wc_notify_state_unchanged;
}
ctx->notify_func2(ctx->notify_baton2, notify, pool);
@@ -2412,7 +2432,10 @@ apply_one_patch(patch_target_t **patch_t
hi = APR_ARRAY_IDX(target->content->hunks, i, hunk_info_t *);
if (hi->already_applied)
- continue;
+ {
+ target->had_already_applied = TRUE;;
+ continue;
+ }
else if (hi->rejected)
SVN_ERR(reject_hunk(target, target->content, hi->hunk,
NULL /* prop_name */,
@@ -2620,7 +2643,10 @@ apply_one_patch(patch_target_t **patch_t
hi = APR_ARRAY_IDX(prop_target->content->hunks, i,
hunk_info_t *);
if (hi->already_applied)
- continue;
+ {
+ target->had_prop_already_applied = TRUE;
+ continue;
+ }
else if (hi->rejected)
SVN_ERR(reject_hunk(target, prop_target->content, hi->hunk,
prop_target->name,
Modified: subversion/trunk/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/notify.c?rev=1705692&r1=1705691&r2=1705692&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/notify.c (original)
+++ subversion/trunk/subversion/svn/notify.c Mon Sep 28 13:57:30 2015
@@ -415,8 +415,10 @@ notify_body(struct notify_baton *nb,
store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
statchar_buf[1] = 'C';
}
+ else if (n->prop_state == svn_wc_notify_state_merged)
+ statchar_buf[1] = 'G';
else if (n->prop_state == svn_wc_notify_state_changed)
- statchar_buf[1] = 'U';
+ statchar_buf[1] = 'U';
if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
{
Modified: subversion/trunk/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/patch_tests.py?rev=1705692&r1=1705691&r2=1705692&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/patch_tests.py Mon Sep 28 13:57:30 2015
@@ -6198,7 +6198,144 @@ def patch_ambiguous_executability_consis
expected_status, expected_skip,
error_re_string=None,
check_props=True)
-
+
+def patch_prop_madness(sbox):
+ "patch property madness"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_propset('mod_s', 'value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_s_n', 'no-eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l', 'this\nis\na\nvery\nvery\nlong\nvalue.\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l_n', 'this\nis\na\nvery\nvery\nlong\nvalue.\n'
+ 'without\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('del', 'value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('del_n', 'no-eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_commit()
+
+ sbox.simple_propset('mod_s', 'other\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_s_n', 'still no eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l', 'this\nis\na\nsomewhat\nlong\nvalue.\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l_n', 'this\nis\na\nanother\n..\nlong\nvalue.\n'
+ 'without\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ sbox.simple_propdel('del', 'iota', 'A/mu')
+
+ sbox.simple_propdel('del_n', 'iota', 'A/mu')
+
+ sbox.simple_propset('add_s', 'new-value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_s_n', 'new other no eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_l', 'this\nis\nsomething\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_l_n', 'this\nhas\nno\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ _, output, _ = svntest.actions.run_and_verify_svn(None, [],
+ 'diff', wc_dir)
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+ new_props = props={
+ 'mod_s' : 'other\n',
+ 'mod_s_n' : 'still no eol',
+ 'mod_l' : 'this\nis\na\nsomewhat\nlong\nvalue.\n',
+ 'mod_l_n' : 'this\nis\na\nanother\n..\nlong\nvalue.\nwithout\neol',
+ 'add_s' : 'new-value\n',
+ 'add_s_n' : 'new other no eol',
+ 'add_l' : 'this\nis\nsomething\n',
+ 'add_l_n' : 'this\nhas\nno\neol'
+ }
+
+ expected_status.tweak('iota', 'A/mu', status=' M', wc_rev='2')
+ expected_disk.tweak('iota', 'A/mu', props=props)
+
+ svntest.actions.verify_disk(wc_dir, expected_disk, True)
+ #svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'revert', wc_dir, '-R')
+
+ patch = sbox.get_tempname('patch')
+ svntest.main.file_write(patch, ''.join(output), mode='wb')
+
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(status=' U'),
+ 'iota' : Item(status=' U'),
+ })
+ expected_skip= wc.State(wc_dir, {
+ })
+
+ strip_count = wc_dir.count(os.path.sep)+1
+
+ # Patch once
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
+ # Patch again
+ expected_output.tweak('A/mu', 'iota', status=' G')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
+ # Reverse
+ expected_output.tweak('A/mu', 'iota', status=' U')
+ props = {
+ 'mod_l_n' : 'this\nis\na\nvery\nvery\nlong\nvalue.\nwithout\neol',
+ 'mod_l' : 'this\nis\na\nvery\nvery\nlong\nvalue.\n',
+ 'mod_s' : 'value\n',
+ 'mod_s_n' : 'no-eol',
+ 'del' : 'value\n',
+ 'del_n' : 'no-eol',
+ }
+ expected_disk.tweak('A/mu', 'iota', props=props)
+ expected_status.tweak('A/mu', 'iota', status=' ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--reverse-diff',
+ '--strip', strip_count)
+
+ # And repeat
+ expected_output.tweak('A/mu', 'iota', status=' G')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--reverse-diff',
+ '--strip', strip_count)
+
########################################################################
#Run the tests
@@ -6270,6 +6407,7 @@ test_list = [ None,
patch_deletes_executability,
patch_ambiguous_executability_contradiction,
patch_ambiguous_executability_consistent,
+ patch_prop_madness,
]
if __name__ == '__main__':