[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] Fix issue #1673 - svn merge reports File Not Found (single, unmodified,

From: Marcos Chaves <mchvs_at_hotmail.com>
Date: 2004-08-08 23:15:34 CEST

Hello.

I split the patch for this issue in two: the bug fix patch and the
regression test patch.

The first patch fixes issue #1673 by ignoring ENOENT (file not found)
when deleting temporary files that may not exist if they were
renamed. It is the second approach presented by Francois Beausoleil
when the issue was discussed.

The second patch is the regression test for this modification.

My suggestion on how to apply the patches is:

  1) Apply the regression test patch (the second one) and verify
     that the test actually fails.
  2) Apply the bug fix patch (the first one).
  3) Verify that now the new test case passes.

Marcos

- - - - - 8< - - - - -

* subversion/libsvn_client/diff.c
   (do_single_file_merge): ignore ENOENT from svn_io_remove_file()
     because the temporary files may not exist if they were renamed.

Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c (revision 10521)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -1411,6 +1411,7 @@
   svn_wc_notify_state_t text_state = svn_wc_notify_state_unknown;
   const char *URL1, *path1, *URL2, *path2;
   svn_opt_revision_t *revision1, *revision2;
+ svn_error_t *err;

   SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));

@@ -1475,8 +1476,15 @@
                                mimetype1, mimetype2,
                                merge_b));

- SVN_ERR (svn_io_remove_file (tmpfile1, pool));
- SVN_ERR (svn_io_remove_file (tmpfile2, pool));
+ /* Ignore if temporary file not found. It may have been renamed. */
+ if ((err = svn_io_remove_file (tmpfile1, pool)) && (err->apr_err !=
ENOENT))
+ {
+ return err;
+ }
+ if ((err = svn_io_remove_file (tmpfile2, pool)) && (err->apr_err !=
ENOENT))
+ {
+ return err;
+ }

   /* Deduce property diffs, and merge those too. */
   SVN_ERR (svn_prop_diffs (&propchanges, props2, props1, pool));

- - - - - 8< - - - - -

* subversion/tests/clients/cmdline/merge_tests.py
   (merge_binary_with_common_ancestry): regression test for
     issue #1673.

Index: subversion/tests/clients/cmdline/merge_tests.py
===================================================================
--- subversion/tests/clients/cmdline/merge_tests.py (revision 10521)
+++ subversion/tests/clients/cmdline/merge_tests.py (working copy)
@@ -1794,7 +1794,198 @@
                                        1, # please check props
                                        1) # and do a dry-run also)

+#----------------------------------------------------------------------

+# Regression test for issue #1673
+# Merge a binary file from two URL with a common ancestry
+
+def merge_binary_with_common_ancestry(sbox):
+ "merge binary files with common ancestry"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Create the common ancestry path
+ I_path = os.path.join(wc_dir, 'I')
+ svntest.main.run_svn(None, 'mkdir', I_path)
+
+ # Add a binary file to the common ancestry path
+ fp = open(os.path.join(sys.path[0], "theta.bin"))
+ theta_contents = fp.read()
+ fp.close()
+ theta_I_path = os.path.join(wc_dir, 'I', 'theta')
+ fp = open(theta_I_path, 'w')
+ fp.write(theta_contents)
+ fp.close()
+ svntest.main.run_svn(None, 'add', theta_I_path)
+ svntest.main.run_svn(None, 'propset', 'svn:mime-type',
+ 'application/octet-stream', theta_I_path)
+
+ # Commit the ancestry
+ expected_output = wc.State(wc_dir, {
+ 'I' : Item(verb='Adding'),
+ 'I/theta' : Item(verb='Adding (bin)'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=2)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=2),
+ 'I/theta' : Item(status=' ', wc_rev=2, repos_rev=2),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Create the first branch
+ J_path = os.path.join(wc_dir, 'J')
+ svntest.main.run_svn(None, 'copy', I_path, J_path)
+
+ # Commit the first branch
+ expected_output = wc.State(wc_dir, {
+ 'J' : Item(verb='Adding'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=3)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=3),
+ 'I/theta' : Item(status=' ', wc_rev=2, repos_rev=3),
+ 'J' : Item(status=' ', wc_rev=3, repos_rev=3),
+ 'J/theta' : Item(status=' ', wc_rev=3, repos_rev=3),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Create the path where the files will be merged
+ K_path = os.path.join(wc_dir, 'K')
+ svntest.main.run_svn(None, 'mkdir', K_path)
+
+ # Commit the new path
+ expected_output = wc.State(wc_dir, {
+ 'K' : Item(verb='Adding'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=4)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=4),
+ 'I/theta' : Item(status=' ', wc_rev=2, repos_rev=4),
+ 'J' : Item(status=' ', wc_rev=3, repos_rev=4),
+ 'J/theta' : Item(status=' ', wc_rev=3, repos_rev=4),
+ 'K' : Item(status=' ', wc_rev=4, repos_rev=4),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Copy 'I/theta' to 'K/'. This file will be merged later.
+ theta_K_path = os.path.join(wc_dir, 'K', 'theta')
+ svntest.main.run_svn(None, 'copy', theta_I_path, theta_K_path)
+
+ # Commit the new file
+ expected_output = wc.State(wc_dir, {
+ 'K/theta' : Item(verb='Adding (bin)'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=5)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=5),
+ 'I/theta' : Item(status=' ', wc_rev=2, repos_rev=5),
+ 'J' : Item(status=' ', wc_rev=3, repos_rev=5),
+ 'J/theta' : Item(status=' ', wc_rev=3, repos_rev=5),
+ 'K' : Item(status=' ', wc_rev=4, repos_rev=5),
+ 'K/theta' : Item(status=' ', wc_rev=5, repos_rev=5),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Modify the original ancestry 'I/theta'
+ svntest.main.file_append(theta_I_path, "some extra junk")
+
+ # Commit the modification
+ expected_output = wc.State(wc_dir, {
+ 'I/theta' : Item(verb='Sending'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=6)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=6),
+ 'I/theta' : Item(status=' ', wc_rev=6, repos_rev=6),
+ 'J' : Item(status=' ', wc_rev=3, repos_rev=6),
+ 'J/theta' : Item(status=' ', wc_rev=3, repos_rev=6),
+ 'K' : Item(status=' ', wc_rev=4, repos_rev=6),
+ 'K/theta' : Item(status=' ', wc_rev=5, repos_rev=6),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Create the second branch from the modified ancestry
+ L_path = os.path.join(wc_dir, 'L')
+ svntest.main.run_svn(None, 'copy', I_path, L_path)
+
+ # Commit the second branch
+ expected_output = wc.State(wc_dir, {
+ 'L' : Item(verb='Adding'),
+ 'L/theta' : Item(verb='Adding (bin)'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak(repos_rev=7)
+ expected_status.add({
+ 'I' : Item(status=' ', wc_rev=2, repos_rev=7),
+ 'I/theta' : Item(status=' ', wc_rev=6, repos_rev=7),
+ 'J' : Item(status=' ', wc_rev=3, repos_rev=7),
+ 'J/theta' : Item(status=' ', wc_rev=3, repos_rev=7),
+ 'K' : Item(status=' ', wc_rev=4, repos_rev=7),
+ 'K/theta' : Item(status=' ', wc_rev=5, repos_rev=7),
+ 'L' : Item(status=' ', wc_rev=7, repos_rev=7),
+ 'L/theta' : Item(status=' ', wc_rev=7, repos_rev=7),
+ })
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status,
+ None,
+ None, None,
+ None, None,
+ wc_dir)
+
+ # Now merge first ('J/') and second ('L/') branches into 'K/'
+ saved_cwd = os.getcwd()
+ try:
+ os.chdir(K_path)
+ theta_J_url = svntest.main.current_repo_url + '/J/theta'
+ theta_L_url = svntest.main.current_repo_url + '/L/theta'
+ svntest.actions.run_and_verify_svn(None, ['U theta\n'], [], 'merge',
theta_J_url, theta_L_url)
+ finally:
+ os.chdir(saved_cwd)
+
+
########################################################################
# Run the tests

@@ -1816,6 +2007,7 @@
               merge_skips_obstructions,
               merge_into_missing,
               dry_run_adds_file_with_prop,
+ merge_binary_with_common_ancestry,
               # property_merges_galore, # Would be nice to have this.
               # tree_merges_galore, # Would be nice to have this.
               # various_merges_galore, # Would be nice to have this.

_________________________________________________________________
MSN Messenger: converse com os seus amigos online.
http://messenger.msn.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sun Aug 8 23:15:49 2004

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.