Author: sbutler
Date: Mon Jun 6 11:18:29 2011
New Revision: 1132598
URL: http://svn.apache.org/viewvc?rev=1132598&view=rev
Log:
A partial fix for issue 3899 "Auto-resolve conflicts at wc-wc copy/move
destination". There are no longer any conflicts at copy destinations.
The test is XFAIL because text-conflicted files are copied as-is, with
conflict-marker lines. They should be copied from the ".working"
file, if it exists, on the principle that a local copy includes all
local modifications.
* subversion/libsvn_wc/wc-queries.sql
(STMT_SELECT_CONFLICT_MARKER_FILES): New query.
* subversion/libsvn_wc/copy.c
(copy_versioned_dir): When copying unversioned filesystem children,
skip any conflict-marker files.
* subversion/libsvn_wc/wc_db.h
(svn_wc__db_get_conflict_marker_files): New function.
* subversion/libsvn_wc/wc_db.c
(svn_wc__db_get_conflict_marker_files): New function.
(copy_actual): New helper function.
(cross_db_copy, db_op_copy): Use copy_actual.
* subversion/tests/cmdline/copy_tests.py
(): Import a few handy functions directly.
(copying_conflicts): New XFAIL test.
(test_list): Add the test.
* subversion/tests/cmdline/svntest/sandbox.py
(Sandbox.simple_move): New method.
Modified:
subversion/trunk/subversion/libsvn_wc/copy.c
subversion/trunk/subversion/libsvn_wc/wc-queries.sql
subversion/trunk/subversion/libsvn_wc/wc_db.c
subversion/trunk/subversion/libsvn_wc/wc_db.h
subversion/trunk/subversion/tests/cmdline/copy_tests.py
subversion/trunk/subversion/tests/cmdline/svntest/sandbox.py
Modified: subversion/trunk/subversion/libsvn_wc/copy.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/copy.c?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/copy.c (original)
+++ subversion/trunk/subversion/libsvn_wc/copy.c Mon Jun 6 11:18:29 2011
@@ -482,10 +482,16 @@ copy_versioned_dir(svn_wc__db_t *db,
}
}
- /* Copy all the remaining filesystem children, which are unversioned. */
+ /* Copy the remaining filesystem children, which are unversioned, skipping
+ any conflict-marker files. */
if (disk_children)
{
apr_hash_index_t *hi;
+ apr_hash_t *marker_files;
+
+ SVN_ERR(svn_wc__db_get_conflict_marker_files(&marker_files, db,
+ src_abspath, scratch_pool,
+ scratch_pool));
for (hi = apr_hash_first(scratch_pool, disk_children); hi;
hi = apr_hash_next(hi))
@@ -497,6 +503,10 @@ copy_versioned_dir(svn_wc__db_t *db,
if (svn_wc_is_adm_dir(name, iterpool))
continue;
+ if (marker_files &&
+ apr_hash_get(marker_files, name, APR_HASH_KEY_STRING))
+ continue;
+
svn_pool_clear(iterpool);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Mon Jun 6 11:18:29
2011
@@ -695,6 +695,13 @@ WHERE wc_id = ?1 AND parent_relpath = ?2
AND (conflict_new IS NULL) AND (conflict_working IS NULL)
AND (tree_conflict_data IS NULL))
+-- STMT_SELECT_CONFLICT_MARKER_FILES
+SELECT prop_reject, conflict_old, conflict_new, conflict_working
+FROM actual_node
+WHERE wc_id = ?1 AND (local_relpath = ?2 OR parent_relpath = ?2)
+ AND ((prop_reject IS NOT NULL) OR (conflict_old IS NOT NULL)
+ OR (conflict_new IS NOT NULL) OR (conflict_working IS NOT NULL))
+
-- STMT_SELECT_ACTUAL_CHILDREN_TREE_CONFLICT
SELECT local_relpath, tree_conflict_data
FROM actual_node
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Mon Jun 6 11:18:29 2011
@@ -3172,6 +3172,52 @@ svn_wc__db_externals_gather_definitions(
svn_sqlite__reset(stmt)));
}
+/* Copy the ACTUAL data for SRC_RELPATH and tweak it to refer to DST_RELPATH.
+ The new ACTUAL data won't have any conflicts. */
+static svn_error_t *
+copy_actual(svn_wc__db_wcroot_t *src_wcroot,
+ const char *src_relpath,
+ svn_wc__db_wcroot_t *dst_wcroot,
+ const char *dst_relpath,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
+ STMT_SELECT_ACTUAL_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ apr_size_t props_size;
+ const char *changelist;
+ const char *properties;
+
+ /* Skipping conflict data... */
+ changelist = svn_sqlite__column_text(stmt, 1, scratch_pool);
+ /* No need to parse the properties when simply copying. */
+ properties = svn_sqlite__column_blob(stmt, 6, &props_size, scratch_pool);
+
+ if (changelist || properties)
+ {
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb,
+ STMT_INSERT_ACTUAL_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "issbssssss",
+ dst_wcroot->wc_id, dst_relpath,
+ svn_relpath_dirname(dst_relpath, scratch_pool),
+ properties, props_size, NULL, NULL, NULL,
+ NULL, changelist, NULL));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
/* Helper for svn_wc__db_op_copy to handle copying from one db to
another */
static svn_error_t *
@@ -3195,8 +3241,6 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
const char *changed_author;
const svn_checksum_t *checksum;
apr_hash_t *props;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
svn_depth_t depth;
SVN_ERR_ASSERT(kind == svn_wc__db_kind_file
@@ -3235,62 +3279,8 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
SVN_ERR(insert_working_node(&iwb, dst_wcroot, dst_relpath, scratch_pool));
- SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
- STMT_SELECT_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- {
- /* ### STMT_INSERT_ACTUAL_NODE doesn't cover every column, it's
- ### enough for some cases but will probably need to extended. */
- const char *prop_reject = svn_sqlite__column_text(stmt, 0, scratch_pool);
- const char *changelist = svn_sqlite__column_text(stmt, 1, scratch_pool);
- const char *conflict_old = svn_sqlite__column_text(stmt, 2,
scratch_pool);
- const char *conflict_new = svn_sqlite__column_text(stmt, 3,
scratch_pool);
- const char *conflict_wrk = svn_sqlite__column_text(stmt, 4,
scratch_pool);
- const char *tree_conflict_data = svn_sqlite__column_text(stmt, 5,
- scratch_pool);
- apr_size_t props_size;
- /* No need to parse the properties when simply copying. */
- const char *properties = svn_sqlite__column_blob(stmt, 6, &props_size,
- scratch_pool);
-
- SVN_ERR(svn_sqlite__reset(stmt));
-
- if (prop_reject)
- prop_reject = svn_relpath_join(dst_relpath,
- svn_relpath_skip_ancestor(src_relpath,
- prop_reject),
- scratch_pool);
- if (conflict_old)
- conflict_old = svn_relpath_join(dst_relpath,
- svn_relpath_skip_ancestor(src_relpath,
-
conflict_old),
- scratch_pool);
- if (conflict_new)
- conflict_new = svn_relpath_join(dst_relpath,
- svn_relpath_skip_ancestor(src_relpath,
-
conflict_new),
- scratch_pool);
- if (conflict_wrk)
- conflict_wrk = svn_relpath_join(dst_relpath,
- svn_relpath_skip_ancestor(src_relpath,
-
conflict_wrk),
- scratch_pool);
-
- /* ### Do we need to adjust relpaths in tree conflict data? */
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb,
- STMT_INSERT_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "issbssssss",
- dst_wcroot->wc_id, dst_relpath,
- svn_relpath_dirname(dst_relpath, scratch_pool),
- properties, props_size,
- conflict_old, conflict_new, conflict_wrk,
- prop_reject, changelist, tree_conflict_data));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- }
- SVN_ERR(svn_sqlite__reset(stmt));
+ SVN_ERR(copy_actual(src_wcroot, src_relpath,
+ dst_wcroot, dst_relpath, scratch_pool));
return SVN_NO_ERROR;
}
@@ -3563,11 +3553,8 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
SVN_ERR(svn_sqlite__step_done(stmt));
/* ### Copying changelist is OK for a move but what about a copy? */
- SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
- STMT_INSERT_ACTUAL_NODE_FROM_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isss", src_wcroot->wc_id, src_relpath,
- dst_relpath, dst_parent_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
+ SVN_ERR(copy_actual(src_wcroot, src_relpath,
+ dst_wcroot, dst_relpath, scratch_pool));
if (dst_np_op_depth > 0)
{
@@ -10127,6 +10114,59 @@ svn_wc__db_read_conflict_victims(const a
svn_error_t *
+svn_wc__db_get_conflict_marker_files(apr_hash_t **marker_files,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ /* The parent should be a working copy directory. */
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+ local_abspath, scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ /* Look for text and property conflicts in ACTUAL */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_CONFLICT_MARKER_FILES));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ *marker_files = apr_hash_make(result_pool);
+ else
+ *marker_files = NULL;
+
+ while (have_row)
+ {
+ /* Collect the basenames of any conflict marker files. */
+ const char *marker_relpath;
+ const char *basename;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ marker_relpath = svn_sqlite__column_text(stmt, i, scratch_pool);
+ if (marker_relpath)
+ {
+ basename = svn_dirent_basename(marker_relpath, result_pool);
+ apr_hash_set(*marker_files, basename, APR_HASH_KEY_STRING,
+ basename);
+ }
+ }
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+
+ return svn_sqlite__reset(stmt);
+}
+
+
+svn_error_t *
svn_wc__db_read_conflicts(const apr_array_header_t **conflicts,
svn_wc__db_t *db,
const char *local_abspath,
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Mon Jun 6 11:18:29 2011
@@ -2062,6 +2062,20 @@ svn_wc__db_read_conflict_victims(const a
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/* Read into *MARKER_FILES the basenames of the immediate children of
+ LOCAL_ABSPATH in DB that are unversioned marker files for text or
+ property conflicts. The files may have been deleted by the user.
+
+ Allocate *MARKER_FILES in RESULT_POOL and do temporary allocations
+ in SCRATCH_POOL */
+/* ### This function will probably be removed. */
+svn_error_t *
+svn_wc__db_get_conflict_marker_files(apr_hash_t **markers,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/* Read into CONFLICTS svn_wc_conflict_description2_t* structs
for all conflicts that have LOCAL_ABSPATH as victim.
Modified: subversion/trunk/subversion/tests/cmdline/copy_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/copy_tests.py?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/copy_tests.py Mon Jun 6 11:18:29
2011
@@ -30,7 +30,13 @@ import stat, os, re, shutil
# Our testing module
import svntest
from svntest import main
-from svntest.main import SVN_PROP_MERGEINFO
+from svntest.main import (
+ SVN_PROP_MERGEINFO,
+ file_append,
+ file_write,
+ make_log_msg,
+ run_svn,
+)
# (abbreviation)
Skip = svntest.testcase.Skip_deco
@@ -5214,7 +5220,169 @@ def case_only_rename(sbox):
# Test that the necessary deletes and adds are present in status.
svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+@XFail()
+@Issue(3899)
+def copying_conflicts(sbox):
+ """copying conflicts"""
+
+ # The destination of a copy operation should *not* be conflicted,
+ # and should contain the "mine-full" contents.
+
+ sbox.build()
+ wc = sbox.ospath
+ def url(relpath):
+ return '/'.join([sbox.repo_url, relpath])
+
+ # Create an assortment of conflicts.
+ # text A/B/E/alpha
+ # property (dir) A/D/H
+ # property (file) A/D/H/chi
+ # tree: local delete, incoming edit A/D/gamma
+ # tree: local edit, incoming delete A/D/G
+ # tree: local add, incoming add A/Q
+ # tree: local missing, incoming edit A/B/E/sigma
+
+ ### As we improve tree-conflict handling, this test may need some
+ ### maintenance.
+
+ # Create a branch for merging.
+ run_svn(None, 'cp', url('A'), url('A2'), '-m', make_log_msg()) # r2
+ sbox.simple_update()
+
+ # This revision won't be included in the merge, producing a "local
+ # missing" tree conflict.
+ file_write(wc('A2/B/E/sigma'), "New for merge.\n")
+ sbox.simple_add('A2/B/E/sigma')
+
+ sbox.simple_commit('A2') # r3
+
+ # Make "incoming" changes in A2 for the merge
+ # incoming edits
+ file_append(wc('A2/B/E/alpha'), "Edit for merge\n")
+ file_append(wc('A2/B/E/sigma'), "Edit for merge\n")
+ sbox.simple_propset('foo', '99', 'A2/D/H')
+ sbox.simple_propset('foo', '99', 'A2/D/H/chi')
+ # incoming add
+ sbox.simple_mkdir('A2/Q')
+ file_write(wc('A2/Q/zeta'), "New for merge\n")
+ sbox.simple_add('A2/Q/zeta')
+ sbox.simple_commit('A2') # r4
+
+ # Make some "local" changes in A before the merge.
+ # local edit
+ file_append(wc('A/B/E/alpha'), "Local edit\n")
+ sbox.simple_propset('foo', '100', 'A/D/H')
+ sbox.simple_propset('foo', '100', 'A/D/H/chi')
+ # local add
+ sbox.simple_mkdir('A/Q')
+ file_write(wc('A/Q/sigma'), "New local file\n")
+ sbox.simple_add('A/Q/sigma')
+
+ # Make some "incoming" changes in A before the update.
+ # incoming edit
+ file_append(wc('A/D/gamma'), "Edit for merge\n")
+ # incoming delete
+ sbox.simple_rm('A/D/G')
+
+ sbox.simple_commit('A') # r5
+
+ # Roll back, make local, uncommitted changes.
+ run_svn(None, 'up', '-r', 4, sbox.wc_dir)
+ # local delete
+ sbox.simple_rm('A/D/gamma')
+ # local edit
+ file_append(wc('A/D/G/rho'), "Local edit\n")
+
+ # Update to reveal the "local {delete,edit'}" tree conflicts,
+ # which we can't yet catch when merging.
+ sbox.simple_update()
+
+ # Merge just one revision to reveal more conflicts.
+ run_svn(None, 'merge', '-c', 4, url('A2'), wc('A'))
+
+ # Prepare for local copies and moves.
+ sbox.simple_mkdir('copy-dest')
+ sbox.simple_mkdir('move-dest')
+
+ # Copy conflict victims.
+ sbox.simple_copy('A/B/E/alpha', 'copy-dest')
+ sbox.simple_copy('A/D/H', 'copy-dest')
+ sbox.simple_copy('A/D/G', 'copy-dest')
+ sbox.simple_copy('A/Q', 'copy-dest')
+
+ # Copy directories with conflicted children.
+ sbox.simple_copy('A/B', 'copy-dest')
+ sbox.simple_copy('A/D', 'copy-dest')
+
+ # Everything copied without conflicts. The entry_status for D/G is
+ # for 1.6 compatibility (see notes/api-errata/1.7/wc003.xt).
+ expected_status = svntest.wc.State(wc('copy-dest'), {
+ '' : Item(status='A ', wc_rev=0),
+ 'B' : Item(status='A ', copied='+', wc_rev='-'),
+ 'B/E' : Item(status=' ', copied='+', wc_rev='-'),
+ 'B/E/alpha' : Item(status='M ', copied='+', wc_rev='-'),
+ 'B/E/beta' : Item(status=' ', copied='+', wc_rev='-'),
+ 'B/F' : Item(status=' ', copied='+', wc_rev='-'),
+ 'B/lambda' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D' : Item(status='A ', copied='+', wc_rev='-'),
+ 'D/G' : Item(status='A ', copied='+', wc_rev='-',
+ entry_status=' '),
+ 'D/G/pi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/G/rho' : Item(status='M ', copied='+', wc_rev='-'),
+ 'D/G/tau' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/H' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/H/chi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/H/omega' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/H/psi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'D/gamma' : Item(status='D ', copied='+', wc_rev='-'),
+ 'G' : Item(status='A ', copied='+', wc_rev='-'),
+ 'G/pi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'G/rho' : Item(status='M ', copied='+', wc_rev='-'),
+ 'G/tau' : Item(status=' ', copied='+', wc_rev='-'),
+ 'H' : Item(status='A ', copied='+', wc_rev='-'),
+ 'H/chi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'H/omega' : Item(status=' ', copied='+', wc_rev='-'),
+ 'H/psi' : Item(status=' ', copied='+', wc_rev='-'),
+ 'Q' : Item(status='A ', copied='+', wc_rev='-'),
+ 'Q/sigma' : Item(status=' ', copied='+', wc_rev='-'),
+ 'alpha' : Item(status='A ', copied='+', wc_rev='-'),
+ })
+ svntest.actions.run_and_verify_status(wc('copy-dest'), expected_status)
+
+ # Only the local changes remain at the copy destinations.
+ ### Currently fails because alpha and B/E/alpha contain conflict-marker text.
+ expected_disk = svntest.wc.State('', {
+ 'B/E/alpha' : Item(contents="This is the file 'alpha'.\n"
+ "Local edit\n"),
+ 'B/E/beta' : Item(contents="This is the file 'beta'.\n"),
+ 'B/F' : Item(),
+ 'B/lambda' : Item(contents="This is the file 'lambda'.\n"),
+ 'D/G/pi' : Item(contents="This is the file 'pi'.\n"),
+ 'D/G/rho' : Item(contents="This is the file 'rho'.\n"
+ "Local edit\n"),
+ 'D/G/tau' : Item(contents="This is the file 'tau'.\n"),
+ 'D/H' : Item(props={'foo':'100'}),
+ 'D/H/chi' : Item(contents="This is the file 'chi'.\n",
+ props={'foo':'100'}),
+ 'D/H/omega' : Item(contents="This is the file 'omega'.\n"),
+ 'D/H/psi' : Item(contents="This is the file 'psi'.\n"),
+ 'G/pi' : Item(contents="This is the file 'pi'.\n"),
+ 'G/rho' : Item(contents="This is the file 'rho'.\n"
+ "Local edit\n"),
+ 'G/tau' : Item(contents="This is the file 'tau'.\n"),
+ 'H' : Item(props={'foo':'100'}),
+ 'H/chi' : Item(contents="This is the file 'chi'.\n",
+ props={'foo':'100'}),
+ 'H/omega' : Item(contents="This is the file 'omega'.\n"),
+ 'H/psi' : Item(contents="This is the file 'psi'.\n"),
+ 'Q/sigma' : Item(contents="New local file\n"),
+ 'alpha' : Item(contents="This is the file 'alpha'.\n"
+ "Local edit\n"),
+ })
+ svntest.actions.verify_disk(wc('copy-dest'), expected_disk, True)
+
########################################################################
# Run the tests
@@ -5324,6 +5492,7 @@ test_list = [ None,
deleted_file_with_case_clash,
copy_base_of_deleted,
case_only_rename,
+ copying_conflicts,
]
if __name__ == '__main__':
Modified: subversion/trunk/subversion/tests/cmdline/svntest/sandbox.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/sandbox.py?rev=1132598&r1=1132597&r2=1132598&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/sandbox.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/sandbox.py Mon Jun 6
11:18:29 2011
@@ -258,6 +258,12 @@ class Sandbox:
dest = self.ospath(dest)
svntest.main.run_svn(False, 'copy', source, dest)
+ def simple_move(self, source, dest):
+ """SOURCE and DEST are relpaths relative to the WC."""
+ source = self.ospath(source)
+ dest = self.ospath(dest)
+ svntest.main.run_svn(False, 'move', source, dest)
+
def simple_repo_copy(self, source, dest):
"""SOURCE and DEST are relpaths relative to the repo root."""
svntest.main.run_svn(False, 'copy', '-m', svntest.main.make_log_msg(),