Author: stsp
Date: Sun Sep 23 09:40:44 2018
New Revision: 1841731
URL: http://svn.apache.org/viewvc?rev=1841731&view=rev
Log:
Fix an endless loop in the interactive conflict resolver.
The problem was that the library returned SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
and this error code makes 'svn' retry resolution under the assumption that a
resolution option could not be executed successfully for some reason.
In this case the error was due to a buggy consistency check which ensures
that the client has already fetched details from the repository.
This check should only trigger during SVN client development, never during
regular usage. And, in fact, 'svn' had already fetched the details, but the
consistency check inside the library didn't look at all the relevant data.
Fix the consistency check in the library and add a regression test.
* subversion/libsvn_client/conflicts.c
(svn_client_conflict_option_get_moved_to_repos_relpath_candidates2): Fix
the check which ensures that details have already been fetched from
the repository. Details for a 'local missing' conflict may contain
no information about moves but still contain information about working
copy siblings. Working copy siblings are not a valid result from this
function, so return a NULL repository path array in this case.
* subversion/tests/cmdline/tree_conflict_tests.py
(local_missing_dir_endless_loop): New test. This test will trigger an
endless loop if the above bug is not yet fixed. I believe this is the
first Python test which uses the interactive resolver, so it may also
serve as an example of how the resolver can be used from Python tests.
(test_list): Add test.
Modified:
subversion/trunk/subversion/libsvn_client/conflicts.c
subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1841731&r1=1841730&r2=1841731&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Sun Sep 23 09:40:44
2018
@@ -10565,7 +10565,8 @@ svn_client_conflict_option_get_moved_to_
struct conflict_tree_local_missing_details *details;
details = conflict->tree_conflict_local_details;
- if (details == NULL || details->wc_move_targets == NULL)
+ if (details == NULL ||
+ (details->wc_move_targets == NULL && details->wc_siblings == NULL))
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Getting a list of possible move targets "
"requires details for tree conflict at '%s'
"
@@ -10573,9 +10574,12 @@ svn_client_conflict_option_get_moved_to_
svn_dirent_local_style(victim_abspath,
scratch_pool));
- SVN_ERR(get_repos_relpath_candidates(possible_moved_to_repos_relpaths,
- details->wc_move_targets,
- result_pool, scratch_pool));
+ if (details->wc_move_targets)
+ SVN_ERR(get_repos_relpath_candidates(possible_moved_to_repos_relpaths,
+ details->wc_move_targets,
+ result_pool, scratch_pool));
+ else
+ *possible_moved_to_repos_relpaths = NULL;
}
else
{
Modified: subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py?rev=1841731&r1=1841730&r2=1841731&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py Sun Sep 23
09:40:44 2018
@@ -1506,6 +1506,47 @@ def update_delete_mixed_rev(sbox):
}
run_and_verify_info([expected_info], sbox.repo_url + '/A/B/E/alpha2')
+# NB: This test will run forever if the bug it is testing for is present!
+def local_missing_dir_endless_loop(sbox):
+ "endless loop when resolving local-missing dir"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ sbox.simple_copy('A', 'A1')
+ sbox.simple_commit()
+ sbox.simple_update()
+ sbox.simple_move('A/B', 'A/B2')
+ sbox.simple_commit()
+ sbox.simple_update()
+ main.file_append(sbox.ospath("A/B2/lambda"), "This is more content.\n")
+ sbox.simple_commit()
+ sbox.simple_update()
+
+ # Create a config which enables the interactive conflict resolver
+ config_contents = '''\
+[auth]
+password-stores =
+
+[miscellany]
+interactive-conflicts = true
+'''
+ config_dir = sbox.create_config_dir(config_contents)
+
+ # Bug: 'svn' keeps retrying interactive conflict resolution while the library
+ # keeps signalling 'SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE' -> endless loop
+ main.run_svn("Tree conflict on '%s'" % sbox.ospath("A1/B2"),
+ 'merge', '-c4', '^/A', sbox.ospath('A1'),
+ '--config-dir', config_dir, '--force-interactive')
+
+ # If everything works as expected the resolver will recommended a
+ # resolution option and 'svn' will resolve the conflict automatically.
+ # Verify that 'A1/B/lambda' contains the merged content:
+ contents = open(sbox.ospath('A1/B/lambda'), 'rb').readlines()
+ svntest.verify.compare_and_display_lines(
+ "A1/B/lambda has unexpectected contents", sbox.ospath("A1/B/lambda"),
+ [ "This is the file 'lambda'.\n", "This is more content.\n"], contents)
+
+
#######################################################################
# Run the tests
@@ -1537,6 +1578,7 @@ test_list = [ None,
actual_only_node_behaviour,
update_dir_with_not_present,
update_delete_mixed_rev,
+ local_missing_dir_endless_loop,
]
if __name__ == '__main__':