You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/12/18 18:36:29 UTC
svn commit: r1220465 [11/13] - in /subversion/branches/file-handle-cache: ./
build/ build/ac-macros/ contrib/client-side/emacs/
contrib/server-side/mod_dontdothat/ notes/
subversion/bindings/javahl/tests/org/apache/subversion/javahl/
subversion/binding...
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/dav-mirror-autocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/dav-mirror-autocheck.sh?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/dav-mirror-autocheck.sh (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/dav-mirror-autocheck.sh Sun Dec 18 17:36:24 2011
@@ -323,7 +323,7 @@ fi
[ -r "$MOD_AUTHZ_SVN" ] \
|| fail "authz_svn_module not found, please use '--enable-shared --enable-dso --with-apxs' with your 'configure' script"
-export LD_LIBRARY_PATH="$ABS_BUILDDIR/subversion/libsvn_ra_neon/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_local/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_svn/.libs"
+export LD_LIBRARY_PATH="$ABS_BUILDDIR/subversion/libsvn_ra_neon/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_local/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_svn/.libs:$LD_LIBRARY_PATH"
MASTER_REPOS="${MASTER_REPOS:-"$HTTPD_ROOT/master_repos"}"
SLAVE_REPOS="${SLAVE_REPOS:-"$HTTPD_ROOT/slave_repos"}"
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/davautocheck.sh?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/davautocheck.sh Sun Dec 18 17:36:24 2011
@@ -195,7 +195,7 @@ fi
[ -r "$MOD_AUTHZ_SVN" ] \
|| fail "authz_svn_module not found, please use '--enable-shared --enable-dso --with-apxs' with your 'configure' script"
-export LD_LIBRARY_PATH="$ABS_BUILDDIR/subversion/libsvn_ra_neon/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_local/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_svn/.libs"
+export LD_LIBRARY_PATH="$ABS_BUILDDIR/subversion/libsvn_ra_neon/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_local/.libs:$ABS_BUILDDIR/subversion/libsvn_ra_svn/.libs:$LD_LIBRARY_PATH"
case "`uname`" in
Darwin*) LDD='otool -L'
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/depth_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/depth_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/depth_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/depth_tests.py Sun Dec 18 17:36:24 2011
@@ -1076,7 +1076,8 @@ def diff_in_depthy_wc(sbox):
"___________________________________________________________________\n",
"Deleted: foo\n",
"## -1 +0,0 ##\n",
- "-foo-val\n"]
+ "-foo-val\n",
+ "\\ No newline at end of property\n"]
os.chdir(wc_empty)
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/diff_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/diff_tests.py Sun Dec 18 17:36:24 2011
@@ -146,15 +146,20 @@ def make_diff_prop_header(path):
"___________________________________________________________________\n"
]
+def make_diff_prop_val(plus_minus, pval):
+ "Return diff for prop value PVAL, with leading PLUS_MINUS (+ or -)."
+ if len(pval) > 0 and pval[-1] != '\n':
+ return [plus_minus + pval + "\n","\\ No newline at end of property\n"]
+ return [plus_minus + pval]
+
def make_diff_prop_deleted(pname, pval):
"""Return a property diff for deletion of property PNAME, old value PVAL.
PVAL is a single string with no embedded newlines. Return the result
as a list of newline-terminated strings."""
return [
"Deleted: " + pname + "\n",
- "## -1 +0,0 ##\n",
- "-" + pval + "\n"
- ]
+ "## -1 +0,0 ##\n"
+ ] + make_diff_prop_val("-", pval)
def make_diff_prop_added(pname, pval):
"""Return a property diff for addition of property PNAME, new value PVAL.
@@ -163,8 +168,7 @@ def make_diff_prop_added(pname, pval):
return [
"Added: " + pname + "\n",
"## -0,0 +1 ##\n",
- "+" + pval + "\n"
- ]
+ ] + make_diff_prop_val("+", pval)
def make_diff_prop_modified(pname, pval1, pval2):
"""Return a property diff for modification of property PNAME, old value
@@ -173,9 +177,7 @@ def make_diff_prop_modified(pname, pval1
return [
"Modified: " + pname + "\n",
"## -1 +1 ##\n",
- "-" + pval1 + "\n",
- "+" + pval2 + "\n"
- ]
+ ] + make_diff_prop_val("-", pval1) + make_diff_prop_val("+", pval2)
######################################################################
# Diff output checker
@@ -1218,6 +1220,7 @@ def diff_deleted_in_head(sbox):
#----------------------------------------------------------------------
+@Issue(2873)
def diff_targets(sbox):
"select diff targets"
@@ -1263,30 +1266,20 @@ def diff_targets(sbox):
update_path,
add_path)
- regex = 'svn: E195012: Unable to find repository location for \'.*\''
- for line in err_output:
- if re.match(regex, line):
- break
- else:
+ if check_update_a_file(diff_output) or check_add_a_file(diff_output):
raise svntest.Failure
exit_code, diff_output, err_output = svntest.main.run_svn(1,
'diff', '-r1:2',
add_path)
- for line in err_output:
- if re.match(regex, line):
- break
- else:
+
+ if not check_update_a_file(diff_output) or check_add_a_file(diff_output):
raise svntest.Failure
exit_code, diff_output, err_output = svntest.main.run_svn(
1, 'diff', '-r1:2', '--old', parent_path, 'alpha', 'theta')
- regex = 'svn: E160013: \'.*\' was not found in the repository'
- for line in err_output:
- if re.match(regex, line):
- break
- else:
+ if check_update_a_file(diff_output) or check_add_a_file(diff_output):
raise svntest.Failure
exit_code, diff_output, err_output = svntest.main.run_svn(
@@ -2863,18 +2856,18 @@ def diff_with_depth(sbox):
A_header = make_diff_header('A', "revision 1", "working copy")
B_header = make_diff_header(B_path, "revision 1", "working copy")
- expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:6])
- expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:6]
- + iota_header + diff[7:12])
- expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+ expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:7])
+ expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+ + iota_header + diff[8:14])
+ expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+ iota_header
- + diff[7:12]
- + A_header + diff[8:18])
- expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+ + diff[8:14]
+ + A_header + diff[15:21])
+ expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+ iota_header
- + diff[7:12]
- + A_header + diff[8:18]
- + B_header + diff[12:])
+ + diff[8:14]
+ + A_header + diff[15:21]
+ + B_header + diff[22:])
os.chdir(sbox.wc_dir)
@@ -2910,18 +2903,18 @@ def diff_with_depth(sbox):
A_header = make_diff_header('A', "revision 1", "revision 2")
B_header = make_diff_header(B_path, "revision 1", "revision 2")
- expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:6])
- expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:6]
- + iota_header + diff[7:12])
- expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+ expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:7])
+ expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+ + iota_header + diff[8:14])
+ expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+ iota_header
- + diff[7:12]
- + A_header + diff[8:18])
+ + diff[8:14]
+ + A_header + diff[15:21])
expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+ iota_header
- + diff[7:12]
- + A_header + diff[8:18]
- + B_header + diff[12:])
+ + diff[8:14]
+ + A_header + diff[15:21]
+ + B_header + diff[22:])
# Test repos-repos diff.
svntest.actions.run_and_verify_svn(None, expected_empty, [],
@@ -2954,10 +2947,10 @@ def diff_with_depth(sbox):
make_diff_prop_header(".") + \
make_diff_prop_modified("foo1", "bar1", "baz1")
- expected_empty = svntest.verify.UnorderedOutput(diff_wc_repos[43:])
- expected_files = svntest.verify.UnorderedOutput(diff_wc_repos[29:])
- expected_immediates = svntest.verify.UnorderedOutput(diff_wc_repos[11:22]
- +diff_wc_repos[29:])
+ expected_empty = svntest.verify.UnorderedOutput(diff_wc_repos[49:])
+ expected_files = svntest.verify.UnorderedOutput(diff_wc_repos[33:])
+ expected_immediates = svntest.verify.UnorderedOutput(diff_wc_repos[13:26]
+ +diff_wc_repos[33:])
expected_infinity = svntest.verify.UnorderedOutput(diff_wc_repos[:])
svntest.actions.run_and_verify_svn(None, None, [],
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/externals_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/externals_tests.py Sun Dec 18 17:36:24 2011
@@ -225,7 +225,7 @@ def change_external_expect_error(path, n
but expect to get an error message that matches EXPECTED_ERR."""
svntest.actions.set_prop('svn:externals', new_val, path,
- expected_err=expected_err)
+ expected_re_string=expected_err)
def probe_paths_exist(paths):
@@ -706,6 +706,13 @@ def disallow_dot_or_dotdot_directory_ref
if not external_urls: external_urls = list(external_url_for.values())
externals_value_8 = external_urls.pop() + " /foo \n"
if not external_urls: external_urls = list(external_url_for.values())
+ if svntest.main.is_os_windows():
+ externals_value_9 = external_urls.pop() + " D:/foo\n"
+ if not external_urls: external_urls = list(external_url_for.values())
+ externals_value_10 = external_urls.pop() + " D:\\foo\n"
+ if not external_urls: external_urls = list(external_url_for.values())
+ externals_value_11 = external_urls.pop() + " D:foo\n"
+ if not external_urls: external_urls = list(external_url_for.values())
set_externals_for_path_expect_error(B_path, externals_value_1)
set_externals_for_path_expect_error(G_path, externals_value_2)
@@ -715,6 +722,10 @@ def disallow_dot_or_dotdot_directory_ref
set_externals_for_path_expect_error(B_path, externals_value_6)
set_externals_for_path_expect_error(G_path, externals_value_7)
set_externals_for_path_expect_error(H_path, externals_value_8)
+ if svntest.main.is_os_windows():
+ set_externals_for_path_expect_error(B_path, externals_value_9)
+ set_externals_for_path_expect_error(B_path, externals_value_10)
+ set_externals_for_path_expect_error(B_path, externals_value_11)
#----------------------------------------------------------------------
@@ -2098,6 +2109,547 @@ def copy_file_externals(sbox):
actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
expected_status, None, None, None, None, None, True, wc_dir)
+def include_externals(sbox):
+ "commit --include-externals"
+ # svntest.factory.make(sbox, """
+ # mkdir Z
+ # echo 'This is the file zeta.' > Z/zeta
+ # svn add Z
+ # svn mkdir --parents Xpegged X/Y
+ # svn ci
+ # svn up
+ # svn ps svn:externals "^/Z xZ" A/D/H
+ # svn ps svn:externals "^/iota@1 Xpegged/xiota" wc_dir
+ # # ^^^ manually set externals to:
+ # # ^/iota@1 Xpegged/xiota
+ # # -r1 ^/A/B/E Xpegged/xE
+ # # ^/A/mu X/xmu
+ # # ^/A/B/lambda X/Y/xlambda
+ # # ^/A/D/G X/xG
+ # # ^/A/D/H X/Y/xH
+ # """)
+ # exit(0)
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ A_D_H = os.path.join(wc_dir, 'A', 'D', 'H')
+ X = os.path.join(wc_dir, 'X')
+ X_Y = os.path.join(wc_dir, 'X', 'Y')
+ Xpegged = os.path.join(wc_dir, 'Xpegged')
+ Z = os.path.join(wc_dir, 'Z')
+ Z_zeta = os.path.join(wc_dir, 'Z', 'zeta')
+
+ # mkdir Z
+ os.makedirs(Z)
+
+ # echo 'This is the file zeta.' > Z/zeta
+ main.file_write(Z_zeta, 'This is the file zeta.\n')
+
+ # svn add Z
+ expected_stdout = verify.UnorderedOutput([
+ 'A ' + Z + '\n',
+ 'A ' + Z_zeta + '\n',
+ ])
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'add', Z)
+
+ # svn mkdir --parents Xpegged X/Y
+ expected_stdout = verify.UnorderedOutput([
+ 'A ' + Xpegged + '\n',
+ 'A ' + X + '\n',
+ 'A ' + X_Y + '\n',
+ ])
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'mkdir',
+ '--parents', Xpegged, X_Y)
+
+ # svn ci
+ expected_output = svntest.wc.State(wc_dir, {
+ 'Z' : Item(verb='Adding'),
+ 'Z/zeta' : Item(verb='Adding'),
+ 'X' : Item(verb='Adding'),
+ 'X/Y' : Item(verb='Adding'),
+ 'Xpegged' : Item(verb='Adding'),
+ })
+
+ expected_status = actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ 'Z' : Item(status=' ', wc_rev='2'),
+ 'Z/zeta' : Item(status=' ', wc_rev='2'),
+ 'X' : Item(status=' ', wc_rev='2'),
+ 'X/Y' : Item(status=' ', wc_rev='2'),
+ 'Xpegged' : Item(status=' ', wc_rev='2'),
+ })
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, wc_dir)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.add({
+ 'Z' : Item(),
+ 'Z/zeta' : Item(contents="This is the file zeta.\n"),
+ 'Xpegged' : Item(),
+ 'X' : Item(),
+ 'X/Y' : Item(),
+ })
+
+ expected_status.tweak(wc_rev='2')
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # svn ps svn:externals "^/Z xZ" A/D/H
+ expected_stdout = ["property 'svn:externals' set on '" + A_D_H + "'\n"]
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'ps',
+ 'svn:externals', '^/Z xZ', A_D_H)
+
+ # svn ps svn:externals "^/iota@1 Xpegged/xiota" wc_dir
+ expected_stdout = ["property 'svn:externals' set on '" + wc_dir + "'\n"]
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'ps',
+ 'svn:externals',
+ '''
+ ^/iota@1 Xpegged/xiota
+ -r1 ^/A/B/E Xpegged/xE
+ ^/A/mu X/xmu
+ ^/A/B/lambda X/Y/xlambda
+ ^/A/D/G X/xG
+ ^/A/D/H X/Y/xH
+ ''', wc_dir)
+
+ # svntest.factory.make(sbox, prev_disk=expected_disk,
+ # prev_status=expected_status,
+ # commands = """
+ # svn ci
+ # svn up
+ # echo mod >> Xpegged/xE/alpha
+ # echo mod >> X/xmu
+ # echo mod >> X/Y/xlambda
+ # echo mod >> X/xG/pi
+ # echo mod >> X/Y/xH/chi
+ # echo mod >> X/Y/xH/xZ/zeta
+ # svn status
+ # # Expect no externals to be committed
+ # svn ci
+ # # Expect no externals to be committed, because pegged
+ # svn ci --include-externals Xpegged
+ # # Expect no externals to be committed, because of depth
+ # svn ci --depth=immediates --include-externals
+ # # Expect only unpegged externals to be committed (those in X/)
+ # svn ci --include-externals
+ # # ### Below, manually add:
+ # # expected_status.tweak('A/D/H/xZ', 'Xpegged/xE', 'X/Y/xH', 'X/xG',
+ # # wc_rev=None)
+ # svn up
+ # # new mods to check more cases
+ # echo mod >> X/xmu
+ # echo mod >> X/Y/xlambda
+ # echo mod >> X/xG/pi
+ # echo mod >> X/Y/xH/chi
+ # echo mod >> X/Y/xH/xZ/zeta
+ # svn status
+ # # Expect no externals to be committed, because of depth
+ # svn ci --include-externals --depth=empty X
+ # # Expect only file external xmu to be committed, because of depth
+ # svn ci --include-externals --depth=files X
+ # svn status
+ # # ### Below, manually add:
+ # # expected_status.tweak('A/D/H/xZ', 'Xpegged/xE', 'X/Y/xH', 'X/xG',
+ # # wc_rev=None)
+ # svn up
+ # echo mod >> X/xG/pi
+ # svn status
+ # # Expect explicit targets to be committed
+ # svn ci X/Y/xlambda X/xG
+ # svn status
+ # """)
+
+ X = os.path.join(wc_dir, 'X')
+ X_xG = os.path.join(wc_dir, 'X', 'xG')
+ X_xG_pi = os.path.join(wc_dir, 'X', 'xG', 'pi')
+ X_xmu = os.path.join(wc_dir, 'X', 'xmu')
+ X_Y_xH_chi = os.path.join(wc_dir, 'X', 'Y', 'xH', 'chi')
+ X_Y_xH_xZ_zeta = os.path.join(wc_dir, 'X', 'Y', 'xH', 'xZ', 'zeta')
+ X_Y_xlambda = os.path.join(wc_dir, 'X', 'Y', 'xlambda')
+ Xpegged = os.path.join(wc_dir, 'Xpegged')
+ Xpegged_xE_alpha = os.path.join(wc_dir, 'Xpegged', 'xE', 'alpha')
+
+ # svn ci
+ expected_output = svntest.wc.State(wc_dir, {
+ '' : Item(verb='Sending'),
+ 'A/D/H' : Item(verb='Sending'),
+ })
+
+ expected_status.tweak('', 'A/D/H', wc_rev='3')
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, wc_dir)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/xmu' : Item(status='A '),
+ 'X/xG/tau' : Item(status='A '),
+ 'X/xG/rho' : Item(status='A '),
+ 'X/xG/pi' : Item(status='A '),
+ 'X/Y/xH' : Item(status=' U'),
+ 'X/Y/xH/psi' : Item(status='A '),
+ 'X/Y/xH/xZ/zeta' : Item(status='A '),
+ 'X/Y/xH/chi' : Item(status='A '),
+ 'X/Y/xH/omega' : Item(status='A '),
+ 'X/Y/xlambda' : Item(status='A '),
+ 'A/D/H/xZ/zeta' : Item(status='A '),
+ 'Xpegged/xiota' : Item(status='A '),
+ 'Xpegged/xE/alpha' : Item(status='A '),
+ 'Xpegged/xE/beta' : Item(status='A '),
+ })
+
+ expected_disk.add({
+ 'Xpegged/xE' : Item(),
+ 'Xpegged/xE/beta' : Item(contents="This is the file 'beta'.\n"),
+ 'Xpegged/xE/alpha' : Item(contents="This is the file 'alpha'.\n"),
+ 'Xpegged/xiota' : Item(contents="This is the file 'iota'.\n"),
+ 'A/D/H/xZ' : Item(),
+ 'A/D/H/xZ/zeta' : Item(contents="This is the file zeta.\n"),
+ 'X/Y/xlambda' : Item(contents="This is the file 'lambda'.\n"),
+ 'X/Y/xH' : Item(),
+ 'X/Y/xH/chi' : Item(contents="This is the file 'chi'.\n"),
+ 'X/Y/xH/xZ' : Item(),
+ 'X/Y/xH/xZ/zeta' : Item(contents="This is the file zeta.\n"),
+ 'X/Y/xH/psi' : Item(contents="This is the file 'psi'.\n"),
+ 'X/Y/xH/omega' : Item(contents="This is the file 'omega'.\n"),
+ 'X/xmu' : Item(contents="This is the file 'mu'.\n"),
+ 'X/xG' : Item(),
+ 'X/xG/tau' : Item(contents="This is the file 'tau'.\n"),
+ 'X/xG/rho' : Item(contents="This is the file 'rho'.\n"),
+ 'X/xG/pi' : Item(contents="This is the file 'pi'.\n"),
+ })
+
+ expected_status.tweak(wc_rev='3')
+ expected_status.add({
+ 'A/D/H/xZ' : Item(status='X '),
+ 'Xpegged/xiota' : Item(status=' ', wc_rev='1', switched='X'),
+ 'Xpegged/xE' : Item(status='X '),
+ 'X/Y/xH' : Item(status='X '),
+ 'X/Y/xlambda' : Item(status=' ', wc_rev='3', switched='X'),
+ 'X/xmu' : Item(status=' ', wc_rev='3', switched='X'),
+ 'X/xG' : Item(status='X '),
+ })
+ expected_status.tweak('Xpegged/xiota', wc_rev='1')
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # echo mod >> Xpegged/xE/alpha
+ main.file_append(Xpegged_xE_alpha, 'mod\n')
+
+ # echo mod >> X/xmu
+ main.file_append(X_xmu, 'mod\n')
+
+ # echo mod >> X/Y/xlambda
+ main.file_append(X_Y_xlambda, 'mod\n')
+
+ # echo mod >> X/xG/pi
+ main.file_append(X_xG_pi, 'mod\n')
+
+ # echo mod >> X/Y/xH/chi
+ main.file_append(X_Y_xH_chi, 'mod\n')
+
+ # echo mod >> X/Y/xH/xZ/zeta
+ main.file_append(X_Y_xH_xZ_zeta, 'mod\n')
+
+ # svn status
+ expected_status.tweak('X/Y/xlambda', 'X/xmu', status='M ')
+
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+ # Expect no externals to be committed
+ # svn ci
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, wc_dir)
+
+ # Expect no externals to be committed, because pegged
+ # svn ci --include-externals Xpegged
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--include-externals', Xpegged)
+
+ # Expect no externals to be committed, because of depth
+ # svn ci --depth=immediates --include-externals
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--depth=immediates', '--include-externals', wc_dir)
+
+ # Expect only unpegged externals to be committed (those in X/)
+ # svn ci --include-externals
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/xmu' : Item(verb='Sending'),
+ 'X/Y/xlambda' : Item(verb='Sending'),
+ 'X/Y/xH/xZ/zeta' : Item(verb='Sending'),
+ 'X/Y/xH/chi' : Item(verb='Sending'),
+ 'X/xG/pi' : Item(verb='Sending'),
+ })
+
+ expected_status.tweak(status=' ')
+ expected_status.tweak('X/Y/xlambda', 'X/xmu', wc_rev='4')
+ expected_status.tweak('X/Y/xH', 'X/xG', 'A/D/H/xZ', 'Xpegged/xE',
+ status='X ')
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--include-externals', wc_dir)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A/mu' : Item(status='U '),
+ 'A/D/H/chi' : Item(status='U '),
+ 'A/D/H/xZ/zeta' : Item(status='U '),
+ 'A/D/G/pi' : Item(status='U '),
+ 'A/B/lambda' : Item(status='U '),
+ 'Z/zeta' : Item(status='U '),
+ })
+
+ expected_disk.tweak('Xpegged/xE/alpha',
+ contents="This is the file 'alpha'.\nmod\n")
+ expected_disk.tweak('A/D/H/chi', 'X/Y/xH/chi',
+ contents="This is the file 'chi'.\nmod\n")
+ expected_disk.tweak('A/D/H/xZ/zeta', 'X/Y/xH/xZ/zeta', 'Z/zeta',
+ contents='This is the file zeta.\nmod\n')
+ expected_disk.tweak('A/D/G/pi', 'X/xG/pi',
+ contents="This is the file 'pi'.\nmod\n")
+ expected_disk.tweak('A/mu', 'X/xmu',
+ contents="This is the file 'mu'.\nmod\n")
+ expected_disk.tweak('A/B/lambda', 'X/Y/xlambda',
+ contents="This is the file 'lambda'.\nmod\n")
+
+ expected_status.tweak(wc_rev='4')
+ expected_status.tweak('Xpegged/xiota', wc_rev='1')
+ expected_status.tweak('A/D/H/xZ', 'Xpegged/xE', 'X/Y/xH', 'X/xG',
+ wc_rev=None)
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # new mods to check more cases
+ # echo mod >> X/xmu
+ main.file_append(X_xmu, 'mod\n')
+
+ # echo mod >> X/Y/xlambda
+ main.file_append(X_Y_xlambda, 'mod\n')
+
+ # echo mod >> X/xG/pi
+ main.file_append(X_xG_pi, 'mod\n')
+
+ # echo mod >> X/Y/xH/chi
+ main.file_append(X_Y_xH_chi, 'mod\n')
+
+ # echo mod >> X/Y/xH/xZ/zeta
+ main.file_append(X_Y_xH_xZ_zeta, 'mod\n')
+
+ # svn status
+ expected_status.tweak('X/Y/xlambda', 'X/xmu', status='M ')
+
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+ # Expect no externals to be committed, because of depth
+ # svn ci --include-externals --depth=empty X
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--include-externals', '--depth=empty', X)
+
+ # Expect only file external xmu to be committed, because of depth
+ # svn ci --include-externals --depth=files X
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/xmu' : Item(verb='Sending'),
+ })
+
+ expected_status.tweak(status=' ')
+ expected_status.tweak('X/xmu', wc_rev='5')
+ expected_status.tweak('X/Y/xlambda', status='M ')
+ expected_status.tweak('X/Y/xH', 'X/xG', 'A/D/H/xZ', 'Xpegged/xE',
+ status='X ')
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--include-externals', '--depth=files', X)
+
+ # svn status
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A/mu' : Item(status='U '),
+ })
+
+ expected_disk.tweak('A/mu', 'X/xmu',
+ contents="This is the file 'mu'.\nmod\nmod\n")
+ expected_disk.tweak('X/Y/xlambda',
+ contents="This is the file 'lambda'.\nmod\nmod\n")
+ expected_disk.tweak('X/Y/xH/chi',
+ contents="This is the file 'chi'.\nmod\nmod\n")
+ expected_disk.tweak('X/Y/xH/xZ/zeta',
+ contents='This is the file zeta.\nmod\nmod\n')
+ expected_disk.tweak('X/xG/pi',
+ contents="This is the file 'pi'.\nmod\nmod\n")
+
+ expected_status.tweak(wc_rev='5')
+ expected_status.tweak('Xpegged/xiota', wc_rev='1')
+ expected_status.tweak('A/D/H/xZ', 'Xpegged/xE', 'X/Y/xH', 'X/xG',
+ wc_rev=None)
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # echo mod >> X/xG/pi
+ main.file_append(X_xG_pi, 'mod\n')
+
+ # svn status
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+ # Expect explicit targets to be committed
+ # svn ci X/Y/xlambda X/xG
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/Y/xlambda' : Item(verb='Sending'),
+ 'X/xG/pi' : Item(verb='Sending'),
+ })
+
+ expected_status.tweak(status=' ')
+ expected_status.tweak('X/Y/xlambda', wc_rev='6')
+ expected_status.tweak('X/Y/xH', 'X/xG', 'A/D/H/xZ', 'Xpegged/xE',
+ status='X ')
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, X_Y_xlambda, X_xG)
+
+ # svn status
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+
+@XFail()
+def include_immediate_dir_externals(sbox):
+ "commit --include-externals --depth=immediates"
+ # See also comment inside svn_client_commit6().
+
+ # svntest.factory.make(sbox,"""
+ # svn mkdir X
+ # svn ci
+ # svn up
+ # svn ps svn:externals "^/A/B/E X/XE" wc_dir
+ # svn ci
+ # svn up
+ #
+ # svn ps some change X/XE
+ # echo mod >> X/XE/alpha
+ #
+ # svn st X/XE
+ # # Expect only the propset on X/XE to be committed.
+ # # Should be like 'svn commit --include-externals --depth=empty X/XE'.
+ # svn commit --include-externals --depth=immediates X
+ # """)
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ X = os.path.join(wc_dir, 'X')
+ X_XE = os.path.join(wc_dir, 'X', 'XE')
+ X_XE_alpha = os.path.join(wc_dir, 'X', 'XE', 'alpha')
+
+ # svn mkdir X
+ expected_stdout = ['A ' + X + '\n']
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'mkdir', X)
+
+ # svn ci
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X' : Item(verb='Adding'),
+ })
+
+ expected_status = actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ 'X' : Item(status=' ', wc_rev='2'),
+ })
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, wc_dir)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {})
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.add({
+ 'X' : Item(),
+ })
+
+ expected_status.tweak(wc_rev='2')
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # svn ps svn:externals "^/A/B/E X/XE" wc_dir
+ expected_stdout = ["property 'svn:externals' set on '" + wc_dir + "'\n"]
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'ps',
+ 'svn:externals', '^/A/B/E X/XE', wc_dir)
+
+ # svn ci
+ expected_output = svntest.wc.State(wc_dir, {
+ '' : Item(verb='Sending'),
+ })
+
+ expected_status.tweak('', wc_rev='3')
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, wc_dir)
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/XE/alpha' : Item(status='A '),
+ 'X/XE/beta' : Item(status='A '),
+ })
+
+ expected_disk.add({
+ 'X/XE' : Item(),
+ 'X/XE/alpha' : Item(contents="This is the file 'alpha'.\n"),
+ 'X/XE/beta' : Item(contents="This is the file 'beta'.\n"),
+ })
+
+ expected_status.tweak(wc_rev='3')
+ expected_status.add({
+ 'X/XE' : Item(status='X '),
+ })
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+ # svn ps some change X/XE
+ expected_stdout = ["property 'some' set on '" + X_XE + "'\n"]
+
+ actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'ps', 'some',
+ 'change', X_XE)
+
+ # echo mod >> X/XE/alpha
+ main.file_append(X_XE_alpha, 'mod\n')
+
+ # svn st X/XE
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+ # Expect only the propset on X/XE to be committed.
+ # Should be like 'svn commit --include-externals --depth=empty X/XE'.
+ # svn commit --include-externals --depth=immediates X
+ expected_output = svntest.wc.State(wc_dir, {
+ 'X/XE' : Item(verb='Sending'),
+ })
+
+ actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+ None, '--include-externals', '--depth=immediates', X)
+
########################################################################
# Run the tests
@@ -2140,6 +2692,8 @@ test_list = [ None,
file_externals_different_repos,
file_external_in_unversioned,
copy_file_externals,
+ include_externals,
+ include_immediate_dir_externals,
]
if __name__ == '__main__':
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Sun Dec 18 17:36:24 2011
@@ -38,6 +38,10 @@ usage: 1. log [PATH][@REV]
svn log http://www.example.com/repo/project foo.c bar.c
svn log http://www.example.com/repo/project@50 foo.c bar.c
+ This command shows the log entry for the revision the branch
+ ^/branches/foo was created in:
+ svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo
+
Valid options:
-r [--revision] ARG : ARG (some commands also take ARG1:ARG2 range)
A revision argument can be one of:
@@ -157,9 +161,10 @@ Valid options:
--ignore-ancestry : ignore ancestry when calculating merges
--force : force operation to run
--accept ARG : specify automatic conflict resolution action
- ('postpone', 'base', 'mine-conflict',
+ ('postpone', 'working', 'base', 'mine-conflict',
'theirs-conflict', 'mine-full', 'theirs-full',
'edit', 'launch')
+ (shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')
Global options:
--username ARG : specify a username ARG
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/input_validation_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/input_validation_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/input_validation_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/input_validation_tests.py Sun Dec 18 17:36:24 2011
@@ -151,13 +151,18 @@ def invalid_log_targets(sbox):
def invalid_merge_args(sbox):
"invalid arguments for 'merge'"
sbox.build(read_only=True)
- run_and_verify_svn_in_wc(sbox, "svn: E195002: A working copy merge source needs "
- "an explicit revision", 'merge', 'iota', '^/')
- for (src, target) in [('iota@HEAD', '^/'), ('iota@BASE', 'file://')]:
- run_and_verify_svn_in_wc(sbox, "svn: E205000: Merge sources must both be either "
- "paths or URLs", 'merge', src, target)
+ for args in [('iota', 'A/mu@HEAD'),
+ ('iota@BASE', 'A/mu@HEAD')]:
+ run_and_verify_svn_in_wc(sbox, "svn: E195002: .* working copy .* revision",
+ 'merge', *args)
+ for args in [(sbox.repo_url, 'A@1', 'A'),
+ ('^/A', 'A@HEAD', 'A'),
+ ('A@HEAD', '^/A', 'A'),
+ ('A@HEAD', '^/A')]:
+ run_and_verify_svn_in_wc(sbox, "svn: E205000: Merge sources must both "
+ "be either paths or URLs", 'merge', *args)
run_and_verify_svn_in_wc(sbox, "svn: E155010: Path '.*' does not exist",
- 'merge', 'iota@BASE', 'iota@HEAD', 'nonexistent')
+ 'merge', '^/@0', '^/@1', 'nonexistent')
run_and_verify_svn_in_wc(sbox, "svn: E205000: Too many arguments given",
'merge', '-c42', '^/A/B', '^/A/C', 'iota')
run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot specify a revision range with" +
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/log_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/log_tests.py Sun Dec 18 17:36:24 2011
@@ -2093,6 +2093,45 @@ def merge_sensitive_log_copied_path_inhe
log_chain = parse_log_output(out)
check_merge_results(log_chain, expected_merges)
+#----------------------------------------------------------------------
+def log_diff(sbox):
+ "'svn log --diff'"
+
+ guarantee_repos_and_wc(sbox)
+
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+
+ exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
+ 'log', '--diff')
+ os.chdir(was_cwd)
+
+ for line in output:
+ if line.startswith('Index:'):
+ break
+ else:
+ raise SVNLogParseError("no diffs found in log output")
+
+ # After a copy, a log of the copy destination used to fail because the
+ # diff tried to use the head-revision URL with the old revision numbers
+ # without using the correct peg revision.
+
+ sbox.simple_copy('A', 'A2')
+ sbox.simple_commit()
+
+ os.chdir(sbox.wc_dir)
+ exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
+ 'log', '--diff',
+ '-r10:8', 'A2')
+ os.chdir(was_cwd)
+
+ for line in output:
+ if line.startswith('Index:'):
+ break
+ else:
+ raise SVNLogParseError("no diffs found in log output")
+
+
########################################################################
# Run the tests
@@ -2133,6 +2172,7 @@ test_list = [ None,
log_with_unrelated_peg_and_operative_revs,
log_on_nonexistent_path_and_valid_rev,
merge_sensitive_log_copied_path_inherited_mergeinfo,
+ log_diff,
]
if __name__ == '__main__':
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_authz_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_authz_tests.py Sun Dec 18 17:36:24 2011
@@ -73,7 +73,10 @@ from svntest.actions import inject_confl
# This is *not* a full test of issue #2829, see also merge_tests.py,
# search for "2829". This tests the problem where a merge adds a path
# with a missing sibling and so needs its own explicit mergeinfo.
-@Issues(2893,2997,2829)
+#
+# #4056 - Don't record non-inheritable mergeinfo if missing subtrees are not
+# touched by the full-depth diff
+@Issues(2893,2997,2829,4056)
@SkipUnless(svntest.main.server_has_mergeinfo)
@Skip(svntest.main.is_ra_type_file)
def mergeinfo_and_skipped_paths(sbox):
@@ -393,10 +396,54 @@ def mergeinfo_and_skipped_paths(sbox):
# Merge -r7:9 to the restricted WC's A_COPY_2/D/H.
#
+ # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a missing sibling 'psi',
+ # but since 'psi' is untouched by the merge it isn't skipped, and since it
+ # isn't skipped, its parent 'A_COPY_2/D/H' won't get non-inheritable
+ # mergeinfo set on it to describe the merge, so none of the parent's
+ # children will get explicit mergeinfo -- see issue #4056.
+ expected_output = wc.State(A_COPY_2_H_path, {
+ 'omega' : Item(status='U '),
+ 'zeta' : Item(status='A '),
+ })
+ expected_mergeinfo_output = wc.State(A_COPY_2_H_path, {
+ '' : Item(status=' U'),
+ 'omega' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(A_COPY_2_H_path, {
+ 'omega' : Item(status=' U'),
+ })
+ expected_status = wc.State(A_COPY_2_H_path, {
+ '' : Item(status=' M', wc_rev=8),
+ 'chi' : Item(status=' ', wc_rev=8),
+ 'omega' : Item(status='M ', wc_rev=8),
+ 'zeta' : Item(status='A ', copied='+', wc_rev='-'),
+ })
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9'}),
+ 'omega' : Item("New content"),
+ 'chi' : Item("This is the file 'chi'.\n"),
+ 'zeta' : Item("This is the file 'zeta'.\n"),
+ })
+ expected_skip = wc.State(A_COPY_2_H_path, {})
+ svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+ sbox.repo_url + '/A/D/H', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None,
+ None, 1, 0)
+
+ # Merge -r4:9 to the restricted WC's A_COPY_2/D/H.
+ #
# r9 adds a path, 'A_COPY_2/D/H/zeta', which has a parent with
- # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing).
- # 'A_COPY_2/D/H/zeta' must therefore get its own explicit mergeinfo from
- # this merge.
+ # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing
+ # and skipped). 'A_COPY_2/D/H/zeta' must therefore get its own explicit
+ # mergeinfo from this merge.
+ svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive',
+ wc_restricted)
expected_output = wc.State(A_COPY_2_H_path, {
'omega' : Item(status='U '),
'zeta' : Item(status='A '),
@@ -415,15 +462,17 @@ def mergeinfo_and_skipped_paths(sbox):
'zeta' : Item(status='A ', copied='+', wc_rev='-'),
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9*'}),
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-9*'}),
'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8-9'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/omega:5-9'}),
'chi' : Item("This is the file 'chi'.\n"),
'zeta' : Item("This is the file 'zeta'.\n",
props={SVN_PROP_MERGEINFO : '/A/D/H/zeta:9'}),
})
- expected_skip = wc.State(A_COPY_2_H_path, {})
- svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+ expected_skip = wc.State(A_COPY_2_H_path, {
+ 'psi' : Item(),
+ })
+ svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '4', '9',
sbox.repo_url + '/A/D/H', None,
expected_output,
expected_mergeinfo_output,
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tests.py Sun Dec 18 17:36:24 2011
@@ -49,15 +49,31 @@ from svntest.actions import make_conflic
from svntest.actions import inject_conflict_into_expected_state
def expected_merge_output(rev_ranges, additional_lines=None, foreign=False,
- elides=False, two_url=False):
+ elides=False, two_url=False, target=None,
+ text_conflicts=0, prop_conflicts=0, tree_conflicts=0):
"""Generate an (inefficient) regex representing the expected merge
- output and mergeinfo notifications from REV_RANGES (a list of 'range' lists
- of the form [start, end] or [single_rev] --> [single_rev - 1, single_rev]),
- and ADDITIONAL_LINES (a list of strings). If REV_RANGES is None then only
- the standard notification for a 3-way merge is expected. If ELIDES is true
- add to the regex an expression representing elision notification. If TWO_URL
- us true tweak the regex to expect the appropriate mergeinfo notification
- for a 3-way merge."""
+ output and mergeinfo notifications from REV_RANGES and ADDITIONAL_LINES.
+
+ REV_RANGES is a list of revision ranges for which mergeinfo is being
+ recorded. Each range is of the form [start, end] (where both START and
+ END are inclusive, unlike in '-rX:Y') or the form [single_rev] (which is
+ like '-c SINGLE_REV'). If REV_RANGES is None then only the standard
+ notification for a 3-way merge is expected.
+
+ ADDITIONAL_LINES is a list of strings to match the other lines of output;
+ these are basically regular expressions except that backslashes will be
+ escaped herein.
+
+ If ELIDES is true, add to the regex an expression representing elision
+ notification. If TWO_URL is true, tweak the regex to expect the
+ appropriate mergeinfo notification for a 3-way merge.
+
+ TARGET is the local path to the target, as it should appear in
+ notifications; if None, it is not checked.
+
+ TEXT_CONFLICTS, PROP_CONFLICTS and TREE_CONFLICTS specify the number of
+ each kind of conflict to expect."""
+
if rev_ranges is None:
lines = [svntest.main.merge_notify_line(None, None, False, foreign)]
else:
@@ -69,8 +85,8 @@ def expected_merge_output(rev_ranges, ad
else:
end_rev = None
lines += [svntest.main.merge_notify_line(start_rev, end_rev,
- True, foreign)]
- lines += [svntest.main.mergeinfo_notify_line(start_rev, end_rev)]
+ True, foreign, target)]
+ lines += [svntest.main.mergeinfo_notify_line(start_rev, end_rev, target)]
if (elides):
lines += ["--- Eliding mergeinfo from .*\n"]
@@ -94,6 +110,16 @@ def expected_merge_output(rev_ranges, ad
if sys.platform == 'win32' and additional_lines != None:
additional_lines = additional_lines.replace("\\", "\\\\")
lines.append(str(additional_lines))
+
+ if text_conflicts or prop_conflicts or tree_conflicts:
+ lines.append("Summary of conflicts:\n")
+ if text_conflicts:
+ lines.append(" Text conflicts: %d\n" % text_conflicts)
+ if prop_conflicts:
+ lines.append(" Property conflicts: %d\n" % prop_conflicts)
+ if tree_conflicts:
+ lines.append(" Tree conflicts: %d\n" % tree_conflicts)
+
return "|".join(lines)
def check_mergeinfo_recursively(root_path, subpaths_mergeinfo):
@@ -835,7 +861,8 @@ def merge_similar_unrelated_trees(sbox):
#----------------------------------------------------------------------
def merge_one_file_helper(sbox, arg_flav, record_only = 0):
- "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
+ """ARG_FLAV is one of 'r' (revision range) or 'c' (single change) or
+ '*' (no revision specified)."""
if arg_flav not in ('r', 'c', '*'):
raise svntest.Failure("Unrecognized flavor of merge argument")
@@ -972,9 +999,13 @@ def merge_record_only(sbox):
merge_one_file_helper(sbox, 'r', 1)
#----------------------------------------------------------------------
-# This is a regression for the enhancement added in issue #785.
+# This is a regression test for the enhancement added in issue #785 "add
+# friendly enhancement to 'svn merge'", which is about inferring that
+# the default target of "svn merge [-r...] FILE" should not be "." but
+# rather should be "FILE".
def merge_with_implicit_target_helper(sbox, arg_flav):
- "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
+ """ARG_FLAV is one of 'r' (revision range) or 'c' (single change) or
+ '*' (no revision specified)."""
if arg_flav not in ('r', 'c', '*'):
raise svntest.Failure("Unrecognized flavor of merge argument")
@@ -5573,7 +5604,7 @@ def merge_to_switched_path(sbox):
# 3188: Mergeinfo on switched targets/subtrees should
# elide to repos
@SkipUnless(server_has_mergeinfo)
-@Issue(2823,2839,3187,3188)
+@Issue(2823,2839,3187,3188,4056)
def merge_to_path_with_switched_children(sbox):
"merge to path with switched children"
@@ -5668,18 +5699,18 @@ def merge_to_path_with_switched_children
'omega' : Item(status=' U')
})
expected_elision_output = wc.State(A_COPY_H_path, {
+ 'omega' : Item(status=' U')
})
expected_status = wc.State(A_COPY_H_path, {
'' : Item(status=' M', wc_rev=8),
'psi' : Item(status=' ', wc_rev=8, switched='S'),
- 'omega' : Item(status='MM', wc_rev=8),
+ 'omega' : Item(status='M ', wc_rev=8),
'chi' : Item(status=' ', wc_rev=8),
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
'psi' : Item("This is the file 'psi'.\n"),
- 'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'omega' : Item("New content"),
'chi' : Item("This is the file 'chi'.\n"),
})
expected_skip = wc.State(A_COPY_H_path, { })
@@ -5713,7 +5744,7 @@ def merge_to_path_with_switched_children
'' : Item(status=' M', wc_rev=8),
'H' : Item(status=' M', wc_rev=8),
'H/chi' : Item(status=' ', wc_rev=8),
- 'H/omega' : Item(status='MM', wc_rev=8),
+ 'H/omega' : Item(status='M ', wc_rev=8),
'H/psi' : Item(status=' ', wc_rev=8, switched='S'),
'G' : Item(status=' M', wc_rev=8, switched='S'),
'G/pi' : Item(status=' ', wc_rev=8),
@@ -5723,10 +5754,9 @@ def merge_to_path_with_switched_children
})
expected_disk_D = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A/D:6*'}),
- 'H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+ 'H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
'H/chi' : Item("This is the file 'chi'.\n"),
- 'H/omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'H/omega' : Item("New content"),
'H/psi' : Item("This is the file 'psi'.\n",),
'G' : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
'G/pi' : Item("This is the file 'pi'.\n"),
@@ -5760,10 +5790,10 @@ def merge_to_path_with_switched_children
})
expected_elision_output = wc.State(A_COPY_D_path, {
})
- expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
- expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+ expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
+ expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
expected_disk_D.tweak('H/psi', contents="New content",
- props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
+ props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
expected_status_D.tweak('H/psi', status='MM')
svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
sbox.repo_url + '/A/D', None,
@@ -5804,7 +5834,7 @@ def merge_to_path_with_switched_children
'D/H' : Item(status=' M', wc_rev=8),
'D/H/chi' : Item(status=' ', wc_rev=8),
'D/H/psi' : Item(status='MM', wc_rev=8, switched='S'),
- 'D/H/omega' : Item(status='MM', wc_rev=8),
+ 'D/H/omega' : Item(status='M ', wc_rev=8),
})
expected_disk = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}),
@@ -5816,19 +5846,18 @@ def merge_to_path_with_switched_children
'B/lambda' : Item("This is the file 'lambda'.\n"),
'B/F' : Item(),
'C' : Item(),
- 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-6*'}),
+ 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5,6*'}),
'D/G' : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
'D/G/pi' : Item("This is the file 'pi'.\n"),
'D/G/rho' : Item("New content",
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'}),
'D/G/tau' : Item("This is the file 'tau'.\n"),
'D/gamma' : Item("This is the file 'gamma'.\n"),
- 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'}),
+ 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
'D/H/chi' : Item("This is the file 'chi'.\n"),
'D/H/psi' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
- 'D/H/omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+ 'D/H/omega' : Item("New content"),
})
expected_skip = wc.State(A_COPY_path, { })
svntest.actions.run_and_verify_merge(A_COPY_path, '4', '8',
@@ -5839,7 +5868,6 @@ def merge_to_path_with_switched_children
expected_disk,
expected_status, expected_skip,
None, None, None, None, None, 1)
-
# Commit changes thus far.
expected_output = svntest.wc.State(wc_dir, {
'A_COPY' : Item(verb='Sending'),
@@ -5866,17 +5894,16 @@ def merge_to_path_with_switched_children
wc_disk.tweak("A_COPY/B/E/beta",
contents="New content")
wc_disk.tweak("A_COPY/D",
- props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
+ props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
wc_disk.tweak("A_COPY/D/G",
props={SVN_PROP_MERGEINFO : '/A/D/G:6*'})
wc_disk.tweak("A_COPY/D/G/rho",
contents="New content",
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
wc_disk.tweak("A_COPY/D/H",
- props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+ props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
wc_disk.tweak("A_COPY/D/H/omega",
- contents="New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
+ contents="New content")
wc_disk.tweak("A_COPY_2", props={})
svntest.actions.run_and_verify_switch(sbox.wc_dir, A_COPY_psi_path,
sbox.repo_url + "/A_COPY/D/H/psi",
@@ -5915,8 +5942,7 @@ def merge_to_path_with_switched_children
expected_disk = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'}),
'psi' : Item("New content"),
- 'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'omega' : Item("New content"),
'chi' : Item("This is the file 'chi'.\n"),
})
expected_skip = wc.State(A_COPY_H_path, { })
@@ -5966,14 +5992,11 @@ def merge_to_path_with_switched_children
expected_status_D.tweak('H/psi', wc_rev=10, switched=None)
expected_status_D.tweak('H/omega', wc_rev=9)
expected_status_D.tweak('G', 'G/rho', switched='S', wc_rev=9)
- expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*,10*',
+ expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*,10',
"prop:name" : "propval"})
expected_disk_D.tweak('G/rho',
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'})
-
- expected_disk_D.tweak('H/omega',
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
expected_disk_D.tweak('H/psi', contents="New content", props={})
svntest.actions.run_and_verify_merge(A_COPY_D_path, '9', '10',
sbox.repo_url + '/A/D', None,
@@ -6034,7 +6057,6 @@ def merge_to_path_with_switched_children
'D/G' : Item(status=' U'),
'D/G/rho' : Item(status=' U'),
'D/H' : Item(status=' U'),
- 'D/H/omega' : Item(status=' U'),
})
expected_elision_output = wc.State(A_COPY_path, {
'' : Item(status=' U'),
@@ -6042,7 +6064,6 @@ def merge_to_path_with_switched_children
'D/G' : Item(status=' U'),
'D/G/rho' : Item(status=' U'),
'D/H' : Item(status=' U'),
- 'D/H/omega' : Item(status=' U'),
})
expected_status = wc.State(A_COPY_path, {
'' : Item(status=' M', wc_rev=10),
@@ -6063,7 +6084,7 @@ def merge_to_path_with_switched_children
'D/H' : Item(status=' M', wc_rev=10),
'D/H/chi' : Item(status=' ', wc_rev=10),
'D/H/psi' : Item(status='M ', wc_rev=10),
- 'D/H/omega' : Item(status='MM', wc_rev=10),
+ 'D/H/omega' : Item(status='M ', wc_rev=10),
})
expected_disk = wc.State('', {
'B' : Item(),
@@ -7260,7 +7281,7 @@ def merge_with_depth_files(sbox):
#
# Test issue #3407 'Shallow merges incorrectly set mergeinfo on children'.
@SkipUnless(server_has_mergeinfo)
-@Issues(2976,3392,3407)
+@Issues(2976,3392,3407,4057)
def merge_away_subtrees_noninheritable_ranges(sbox):
"subtrees can lose non-inheritable ranges"
@@ -7579,8 +7600,9 @@ def merge_away_subtrees_noninheritable_r
svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
- # Merge r8 from A/D/H to A_COPY_D/H at depth empty, creating non-inheritable
- # mergeinfo on the target. Commit this merge as r13.
+ # Merge r8 from A/D/H to A_COPY_D/H at depth empty. Since r8 affects only
+ # A_COPY/D/H itself, the resulting mergeinfo is inheritabled. Commit this
+ # merge as r13.
expected_output = wc.State(H_COPY_2_path, {
'' : Item(status=' U'),
})
@@ -7596,7 +7618,7 @@ def merge_away_subtrees_noninheritable_r
'chi' : Item(status=' ', wc_rev=12),
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*',
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8',
"prop:name" : "propval"}),
'psi' : Item("This is the file 'psi'.\n"),
'omega' : Item("This is the file 'omega'.\n"),
@@ -12509,24 +12531,46 @@ def svn_copy(s_rev, path1, path2):
svntest.actions.run_and_verify_svn(None, None, [], 'copy', '--parents',
'-r', s_rev, path1, path2)
-def svn_merge(rev_spec, source, target, exp_out=None, *args):
- """Merge a single change from path 'source' to path 'target'.
- SRC_CHANGE_NUM is either a number (to cherry-pick that specific change)
- or a command-line option revision range string such as '-r10:20'.
- *ARGS are additional arguments passed to svn merge."""
+def svn_merge(rev_range, source, target, lines=None, elides=[],
+ text_conflicts=0, prop_conflicts=0, tree_conflicts=0, args=[]):
+ """Merge a single change from path SOURCE to path TARGET and verify the
+ output and that there is no error. (The changes made are not verified.)
+
+ REV_RANGE is either a number (to cherry-pick that specific change) or a
+ two-element list [X,Y] to pick the revision range '-r(X-1):Y'.
+
+ LINES is a list of regular expressions to match other lines of output; if
+ LINES is 'None' then match all normal (non-conflicting) merges.
+
+ ELIDES is a list of paths on which mergeinfo elision should be reported.
+
+ TEXT_CONFLICTS, PROP_CONFLICTS and TREE_CONFLICTS specify the number of
+ each kind of conflict to expect.
+
+ ARGS are additional arguments passed to svn merge."""
+
source = local_path(source)
target = local_path(target)
- if isinstance(rev_spec, int):
- rev_spec = '-c' + str(rev_spec)
- if exp_out is None:
- target_re = re.escape(target)
- exp_1 = "--- Merging r.* into '" + target_re + ".*':"
- exp_2 = "(A |D |[UG] | [UG]|[UG][UG]) " + target_re + ".*"
- exp_3 = "--- Recording mergeinfo for merge of r.* into '" + \
- target_re + ".*':"
- exp_out = svntest.verify.RegexOutput(exp_1 + "|" + exp_2 + "|" + exp_3)
+ elides = [local_path(p) for p in elides]
+ if isinstance(rev_range, int):
+ mi_rev_range = [rev_range]
+ rev_arg = '-c' + str(rev_range)
+ else:
+ mi_rev_range = rev_range
+ rev_arg = '-r' + str(rev_range[0] - 1) + ':' + str(rev_range[1])
+ if lines is None:
+ lines = ["(A |D |[UG] | [UG]|[UG][UG]) " + target + ".*\n"]
+ else:
+ # Expect mergeinfo on the target; caller must supply matches for any
+ # subtree mergeinfo paths.
+ lines.append(" [UG] " + target + "\n")
+ exp_out = expected_merge_output([mi_rev_range], lines, target=target,
+ elides=elides,
+ text_conflicts=text_conflicts,
+ prop_conflicts=prop_conflicts,
+ tree_conflicts=tree_conflicts)
svntest.actions.run_and_verify_svn(None, exp_out, [],
- 'merge', rev_spec, source, target, *args)
+ 'merge', rev_arg, source, target, *args)
#----------------------------------------------------------------------
# Tests for merging the deletion of a node, where the node to be deleted
@@ -12558,7 +12602,8 @@ def del_identical_file(sbox):
svn_copy(s_rev_mod, source, target)
sbox.simple_commit(target)
# Should be deleted quietly.
- svn_merge(s_rev_del, source, target, '--- Merging|D |--- Recording| U')
+ svn_merge(s_rev_del, source, target,
+ ['D %s\n' % local_path('A/D/G2/tau')])
# Make a differing copy, locally modify it so it's the same,
# and merge a deletion to it.
@@ -12567,7 +12612,8 @@ def del_identical_file(sbox):
sbox.simple_commit(target)
svn_modfile(target+"/tau")
# Should be deleted quietly.
- svn_merge(s_rev_del, source, target, '--- Merging|D |--- Recording| U')
+ svn_merge(s_rev_del, source, target,
+ ['D %s\n' % local_path('A/D/G3/tau')])
os.chdir(saved_cwd)
@@ -12594,10 +12640,11 @@ def del_sched_add_hist_file(sbox):
svn_copy(s_rev_orig, source, target)
sbox.simple_commit(target)
s_rev = 3
- svn_merge(s_rev_add, source, target, '--- Merging|A |--- Recording| U')
+ svn_merge(s_rev_add, source, target,
+ ['A %s\n' % local_path('A/D/G2/file')])
# Should be deleted quietly.
svn_merge(-s_rev_add, source, target,
- '--- Reverse-merging|D |--- Recording| U| G|--- Eliding')
+ ['D %s\n' % local_path('A/D/G2/file')], elides=['A/D/G2'])
os.chdir(saved_cwd)
@@ -13052,15 +13099,9 @@ def merge_two_edits_to_same_prop(sbox):
rev4 = initial_rev + 4
# Merge the two changes together to source.
- svn_merge('-r'+str(rev3-1)+':'+str(rev4), A_COPY_path, A_path, [
- "--- Merging r9 through r10 into '%s':\n" % A_path,
+ svn_merge([rev3, rev4], A_COPY_path, A_path, [
" C %s\n" % mu_path,
- "--- Recording mergeinfo for merge of r9 through r10 into '%s':\n" \
- % A_path,
- " U A\n",
- "Summary of conflicts:\n",
- " Property conflicts: 1\n"],
- '--allow-mixed-revisions')
+ ], prop_conflicts=1, args=['--allow-mixed-revisions'])
# Revert changes to source wc, to test next scenario of #3250
svntest.actions.run_and_verify_svn(None, None, [],
@@ -13068,21 +13109,11 @@ def merge_two_edits_to_same_prop(sbox):
# Merge the first change, then the second, to source.
svn_merge(rev3, A_COPY_path, A_path, [
- "--- Merging r9 into '%s':\n" % A_path,
" C %s\n" % mu_path,
- "--- Recording mergeinfo for merge of r9 into '%s':\n" % A_path,
- " U A\n",
- "Summary of conflicts:\n",
- " Property conflicts: 1\n"],
- '--allow-mixed-revisions')
+ ], prop_conflicts=1, args=['--allow-mixed-revisions'])
svn_merge(rev4, A_COPY_path, A_path, [
- "--- Merging r10 into '%s':\n" % A_path,
" C %s\n" % mu_path,
- "--- Recording mergeinfo for merge of r10 into '%s':\n" % A_path,
- " G A\n",
- "Summary of conflicts:\n",
- " Property conflicts: 1\n"],
- '--allow-mixed-revisions')
+ ], prop_conflicts=1, args=['--allow-mixed-revisions'])
os.chdir(was_cwd)
@@ -13131,8 +13162,8 @@ def merge_an_eol_unification_and_set_svn
sbox.simple_commit('A_COPY')
# Merge the two changes together to the target branch.
- svn_merge('-r'+str(rev1)+':'+str(rev3), 'A', 'A_COPY', None,
- '--allow-mixed-revisions')
+ svn_merge([rev2, rev3], 'A', 'A_COPY',
+ args=['--allow-mixed-revisions'])
# That merge should succeed.
# Surprise: setting svn:eol-style='LF' instead of 'native' doesn't fail.
@@ -16680,11 +16711,9 @@ def foreign_repos_prop_conflict(sbox):
# Now, merge the propchange to the *second* working copy.
expected_output = [' C %s\n' % (os.path.join(other_wc_dir,
- "A", "D", "G")),
- 'Summary of conflicts:\n',
- ' Property conflicts: 1\n',
- ]
- expected_output = expected_merge_output([[3]], expected_output, True)
+ "A", "D", "G"))]
+ expected_output = expected_merge_output([[3]], expected_output, True,
+ prop_conflicts=1)
svntest.actions.run_and_verify_svn(None,
expected_output,
[], 'merge', '-c3',
@@ -16822,7 +16851,7 @@ def merge_adds_subtree_with_mergeinfo(sb
#----------------------------------------------------------------------
# A test for issue #3978 'reverse merge which adds subtree fails'.
-@Issue(3978)
+@Issue(3978,4057)
@SkipUnless(server_has_mergeinfo)
def reverse_merge_adds_subtree(sbox):
"reverse merge adds subtree"
@@ -16849,6 +16878,9 @@ def reverse_merge_adds_subtree(sbox):
'Cherry-pick r7 from A to A_COPY', wc_dir)
# r9 - File depth sync merge from A/D/H to A_COPY/D/H/
+ # This shallow merge does not create non-inheritable mergeinfo because of
+ # the issue #4057 fix; all subtrees affected by the diff are present, so
+ # non-inheritable mergeinfo is not required.
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
svntest.actions.run_and_verify_svn(None, None, [], 'merge',
sbox.repo_url + '/A/D/H',
@@ -16886,7 +16918,6 @@ def reverse_merge_adds_subtree(sbox):
# ..\..\..\subversion\libsvn_subr\kitchensink.c:57: (apr_err=200022)
# svn: E200022: Negative revision number found parsing '-7'
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
- svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
expected_output = wc.State(A_COPY_path, {
'D/H/chi' : Item(status='A '),
})
@@ -16935,12 +16966,10 @@ def reverse_merge_adds_subtree(sbox):
'D/G/rho' : Item("This is the file 'rho'.\n"),
'D/G/tau' : Item("This is the file 'tau'.\n"),
'D/gamma' : Item("This is the file 'gamma'.\n"),
- 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:2-6*,8*'}),
+ 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:2-6,8'}),
'D/H/chi' : Item("This is the file 'chi'.\n"),
- 'D/H/psi' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/psi:2-8'}),
- 'D/H/omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:2-8'}),
+ 'D/H/psi' : Item("New content"),
+ 'D/H/omega' : Item("New content"),
})
expected_skip = wc.State('.', { })
svntest.actions.run_and_verify_merge(A_COPY_path, 7, 6,
@@ -17111,6 +17140,215 @@ def record_only_merge_adds_new_subtree_m
None, None, None, None,
None, 1, False)
+#----------------------------------------------------------------------
+# Setup helper for issue #4056 and issue #4057 tests.
+def noninheritable_mergeinfo_test_set_up(sbox):
+ '''Starting with standard greek tree, copy 'A' to 'branch' in r2 and
+ then made a file edit to A/B/lambda in r3.
+ Return (expected_output, expected_mergeinfo_output, expected_elision_output,
+ expected_status, expected_disk, expected_skip) for a merge of
+ r3 from ^/A/B to branch/B.'''
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
+ B_branch_path = os.path.join(wc_dir, 'branch', 'B')
+
+ # r2 - Branch ^/A to ^/branch.
+ svntest.main.run_svn(None, 'copy', sbox.repo_url + '/A',
+ sbox.repo_url + '/branch', '-m', 'make a branch')
+
+ # r3 - Make an edit to A/B/lambda.
+ svntest.main.file_write(lambda_path, "trunk edit.\n")
+ svntest.main.run_svn(None, 'commit', '-m', 'file edit', wc_dir)
+ svntest.main.run_svn(None, 'up', wc_dir)
+
+ expected_output = wc.State(B_branch_path, {
+ 'lambda' : Item(status='U '),
+ })
+ expected_mergeinfo_output = wc.State(B_branch_path, {
+ '' : Item(status=' U'),
+ 'lambda' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(B_branch_path, {
+ 'lambda' : Item(status=' U'),
+ })
+ expected_status = wc.State(B_branch_path, {
+ '' : Item(status=' M'),
+ 'lambda' : Item(status='M '),
+ 'E' : Item(status=' '),
+ 'E/alpha' : Item(status=' '),
+ 'E/beta' : Item(status=' '),
+ 'F' : Item(status=' '),
+ })
+ expected_status.tweak(wc_rev='3')
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3'}),
+ 'lambda' : Item("trunk edit.\n"),
+ 'E' : Item(),
+ 'E/alpha' : Item("This is the file 'alpha'.\n"),
+ 'E/beta' : Item("This is the file 'beta'.\n"),
+ 'F' : Item(),
+ })
+ expected_skip = wc.State(B_branch_path, {})
+
+ return expected_output, expected_mergeinfo_output, expected_elision_output, \
+ expected_status, expected_disk, expected_skip
+
+
+#----------------------------------------------------------------------
+# Test for issue #4056 "don't record non-inheritable mergeinfo if missing
+# subtrees are not touched by the full-depth diff".
+@Issue(4056)
+@SkipUnless(server_has_mergeinfo)
+def unnecessary_noninheritable_mergeinfo_missing_subtrees(sbox):
+ "missing subtrees untouched by infinite depth merge"
+
+ B_branch_path = os.path.join(sbox.wc_dir, 'branch', 'B')
+
+ # Setup a simple branch to which
+ expected_output, expected_mergeinfo_output, expected_elision_output, \
+ expected_status, expected_disk, expected_skip = \
+ noninheritable_mergeinfo_test_set_up(sbox)
+
+ # Create a shallow merge target; set depth of branch/B to files.
+ svntest.main.run_svn(None, 'up', '--set-depth=files', B_branch_path)
+ expected_status.remove('E', 'E/alpha', 'E/beta', 'F')
+ expected_disk.remove('E', 'E/alpha', 'E/beta', 'F')
+
+ # Merge r3 from ^/A/B to branch/B
+ #
+ # Merge is smart enough to realize that despite the shallow merge target,
+ # the diff can only affect branch/B/lambda, which is still present, so there
+ # is no need to record non-inheritable mergeinfo on the target
+ # or any subtree mergeinfo whatsoever:
+ #
+ # >svn pg svn:mergeinfo -vR
+ # Properties on 'branch\B':
+ # svn:mergeinfo
+ # /A/B:3 <-- Nothing was skipped, so doesn't need
+ # to be non-inheritable.
+ svntest.actions.run_and_verify_merge(B_branch_path,
+ '2', '3',
+ sbox.repo_url + '/A/B', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None, 1, 1,
+ B_branch_path)
+
+#----------------------------------------------------------------------
+# Test for issue #4057 "don't record non-inheritable mergeinfo in shallow
+# merge if entire diff is within requested depth".
+@Issue(4057)
+@SkipUnless(server_has_mergeinfo)
+def unnecessary_noninheritable_mergeinfo_shallow_merge(sbox):
+ "shallow merge reaches all necessary subtrees"
+
+ B_branch_path = os.path.join(sbox.wc_dir, 'branch', 'B')
+ E_path = os.path.join(sbox.wc_dir, 'A', 'B', 'E')
+
+ # Setup a simple branch to which
+ expected_output, expected_mergeinfo_output, expected_elision_output, \
+ expected_status, expected_disk, expected_skip = \
+ noninheritable_mergeinfo_test_set_up(sbox)
+
+ # Merge r3 from ^/A/B to branch/B at operational depth=files
+ #
+ # Previously this failed because merge wasn't smart enough to
+ # realize that despite being a shallow merge, the diff can
+ # only affect branch/B/lambda, which is within the specified
+ # depth, so there is no need to record non-inheritable mergeinfo
+ # or subtree mergeinfo:
+ #
+ # >svn pg svn:mergeinfo -vR
+ # Properties on 'branch\B':
+ # svn:mergeinfo
+ # /A/B:3* <-- Should be inheritable
+ # Properties on 'branch\B\lambda':
+ # svn:mergeinfo
+ # /A/B/lambda:3 <-- Not necessary
+ expected_skip = wc.State(B_branch_path, {})
+ svntest.actions.run_and_verify_merge(B_branch_path, '2', '3',
+ sbox.repo_url + '/A/B', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None, 1, 1,
+ '--depth', 'files', B_branch_path)
+
+ # Revert the merge and then make a prop change to A/B/E in r4.
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'revert', '--recursive', sbox.wc_dir)
+ svntest.actions.run_and_verify_svn(None,
+ ["property 'prop:name' set on '" +
+ E_path + "'\n"], [], 'ps',
+ 'prop:name', 'propval', E_path)
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'ci', '-m', 'A new property on a dir',
+ sbox.wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'up', sbox.wc_dir)
+
+ # Merge r4 from ^/A/B to branch/B at operational depth=immediates
+ #
+ # Previously this failed because the mergetracking logic didn't realize
+ # that despite being a shallow merge, the diff only affected branch/B/E,
+ # which was within the specified depth, so there was no need to record
+ # non-inheritable mergeinfo or subtree mergeinfo:
+ #
+ # >svn pg svn:mergeinfo -vR
+ # Properties on 'branch\B':
+ # svn:mergeinfo
+ # /A/B:4* <-- Should be inheritable
+ # Properties on 'branch\B\E':
+ # svn:mergeinfo
+ # /A/B/E:4 <-- Not necessary
+ expected_output = wc.State(B_branch_path, {
+ 'E' : Item(status=' U'),
+ })
+ expected_mergeinfo_output = wc.State(B_branch_path, {
+ '' : Item(status=' U'),
+ 'E' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(B_branch_path, {
+ 'E' : Item(status=' U'),
+ })
+ expected_status = wc.State(B_branch_path, {
+ '' : Item(status=' M'),
+ 'lambda' : Item(status=' '),
+ 'E' : Item(status=' M'),
+ 'E/alpha' : Item(status=' '),
+ 'E/beta' : Item(status=' '),
+ 'F' : Item(status=' '),
+ })
+ expected_status.tweak(wc_rev='4')
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:4'}),
+ 'lambda' : Item("This is the file 'lambda'.\n"),
+ 'E' : Item(props={'prop:name' : 'propval'}),
+ 'E/alpha' : Item("This is the file 'alpha'.\n"),
+ 'E/beta' : Item("This is the file 'beta'.\n"),
+ 'F' : Item(),
+ })
+ svntest.actions.run_and_verify_merge(B_branch_path, '3', '4',
+ sbox.repo_url + '/A/B', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None, 1, 1,
+ '--depth', 'immediates', B_branch_path)
+
########################################################################
# Run the tests
@@ -17239,6 +17477,8 @@ test_list = [ None,
reverse_merge_adds_subtree,
merged_deletion_causes_tree_conflict,
record_only_merge_adds_new_subtree_mergeinfo,
+ unnecessary_noninheritable_mergeinfo_missing_subtrees,
+ unnecessary_noninheritable_mergeinfo_shallow_merge,
]
if __name__ == '__main__':
Modified: subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/file-handle-cache/subversion/tests/cmdline/merge_tree_conflict_tests.py Sun Dec 18 17:36:24 2011
@@ -46,6 +46,7 @@ from svntest.main import server_has_merg
from merge_tests import set_up_branch
from merge_tests import svn_copy
from merge_tests import svn_merge
+from merge_tests import expected_merge_output
#----------------------------------------------------------------------
@SkipUnless(server_has_mergeinfo)
@@ -680,25 +681,16 @@ def del_differing_file(sbox):
'newprop', 'v', target+"/pi")
dir_D = os.path.join('A','D')
- dir_G2 = os.path.join(dir_D, 'G2')
tau = os.path.join(dir_D,'G2','tau')
pi = os.path.join(dir_D, 'G2', 'pi')
# Should complain and "skip" it.
svn_merge(s_rev_tau, source, target, [
- "--- Merging r2 into '%s':\n" % dir_G2,
- " C %s\n" % tau,
- "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G2),
- " U %s\n" % (dir_G2),
- "Summary of conflicts:\n",
- " Tree conflicts: 1\n"])
+ " C %s\n" % tau, # merge
+ ], tree_conflicts=1)
svn_merge(s_rev_pi, source, target, [
- "--- Merging r3 into '%s':\n" % dir_G2,
- " C %s\n" % pi,
- "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G2),
- " G %s\n" % (dir_G2),
- "Summary of conflicts:\n",
- " Tree conflicts: 1\n"])
+ " C %s\n" % pi, # merge
+ ], tree_conflicts=1)
# Copy a file, modify it, commit, and merge a deletion to it.
@@ -710,26 +702,17 @@ def del_differing_file(sbox):
sbox.simple_commit(target)
- dir_G3 = os.path.join(dir_D, 'G3')
tau = os.path.join(dir_D,'G3','tau')
pi = os.path.join(dir_D, 'G3', 'pi')
# Should complain and "skip" it.
svn_merge(s_rev_tau, source, target, [
- "--- Merging r2 into '%s':\n" % dir_G3,
" C %s\n" % tau,
- "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G3),
- " U %s\n" % (dir_G3),
- "Summary of conflicts:\n",
- " Tree conflicts: 1\n"])
+ ], tree_conflicts=1)
svn_merge(s_rev_pi, source, target, [
- "--- Merging r3 into '%s':\n" % dir_G3,
" C %s\n" % pi,
- "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G3),
- " G %s\n" % (dir_G3),
- "Summary of conflicts:\n",
- " Tree conflicts: 1\n"])
+ ], tree_conflicts=1)
os.chdir(saved_cwd)
@@ -1738,18 +1721,15 @@ def merge_replace_causes_tree_conflict(s
'propname', 'propval', A_D_H)
# svn merge $URL/A $URL/branch A
- expected_stdout = verify.UnorderedOutput([
- "--- Merging differences between repository URLs into '" + A + "':\n",
+ expected_stdout = expected_merge_output(None, [
+ # merge
' C ' + A_B_E + '\n',
' C ' + A_mu + '\n',
' C ' + A_D_G_pi + '\n',
' C ' + A_D_H + '\n',
- "--- Recording mergeinfo for merge between repository URLs into '" \
- + A + "':\n",
+ # mergeinfo
' U ' + A + '\n',
- 'Summary of conflicts:\n',
- ' Tree conflicts: 4\n',
- ])
+ ], target=A, two_url=True, tree_conflicts=4)
actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge',
url_A, url_branch, A)
@@ -1829,15 +1809,10 @@ def merge_replace_causes_tree_conflict2(
### A file-with-file replacement onto a deleted file.
# svn merge $URL/A/mu $URL/branch/mu A/mu
- expected_stdout = verify.UnorderedOutput([
- "--- Merging differences between repository URLs into '" + A + "':\n",
- ' C ' + A_mu + '\n',
- "--- Recording mergeinfo for merge between repository URLs into '" +
- A + "':\n",
- " U " + A + "\n",
- 'Summary of conflicts:\n',
- ' Tree conflicts: 1\n',
- ])
+ expected_stdout = expected_merge_output(None, [
+ ' C ' + A_mu + '\n', # merge
+ " U " + A + "\n", # mergeinfo
+ ], target=A, two_url=True, tree_conflicts=1)
actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge',
url_A, url_branch, A, '--depth=files')
@@ -1853,15 +1828,10 @@ def merge_replace_causes_tree_conflict2(
### A dir-with-dir replacement onto a deleted directory.
# svn merge $URL/A/B $URL/branch/B A/B
- expected_stdout = verify.UnorderedOutput([
- "--- Merging differences between repository URLs into '" + A_B + "':\n",
- ' C ' + A_B_E + '\n',
- "--- Recording mergeinfo for merge between repository URLs into '" +
- A_B + "':\n",
- " U " + A_B + "\n",
- 'Summary of conflicts:\n',
- ' Tree conflicts: 1\n',
- ])
+ expected_stdout = expected_merge_output(None, [
+ ' C ' + A_B_E + '\n', # merge
+ " U " + A_B + "\n", # mergeinfo
+ ], target=A_B, two_url=True, tree_conflicts=1)
actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge',
url_A_B, url_branch_B, A_B)
@@ -1877,16 +1847,11 @@ def merge_replace_causes_tree_conflict2(
### A dir-with-file replacement onto a deleted directory.
# svn merge --depth=immediates $URL/A/D $URL/branch/D A/D
- expected_stdout = verify.UnorderedOutput([
- "--- Merging differences between repository URLs into '" + A_D + "':\n",
- ' C ' + A_D_H + '\n',
- "--- Recording mergeinfo for merge between repository URLs into '" +
- A_D + "':\n",
- " U " + A_D + "\n",
+ expected_stdout = expected_merge_output(None, [
+ ' C ' + A_D_H + '\n', # merge
+ " U " + A_D + "\n", # mergeinfo
" U " + A_D_G + "\n",
- 'Summary of conflicts:\n',
- ' Tree conflicts: 1\n',
- ])
+ ], target=A_D, two_url=True, tree_conflicts=1)
actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge',
'--depth=immediates', url_A_D, url_branch_D, A_D)
@@ -1902,20 +1867,9 @@ def merge_replace_causes_tree_conflict2(
### A file-with-dir replacement onto a deleted file.
# svn merge $URL/A/D/G $URL/branch/D/G A/D/G
- expected_stdout = verify.UnorderedOutput([
- "--- Merging differences between repository URLs into '" + A_D_G +
- "':\n",
- ' C ' + A_D_G_pi + '\n',
- "--- Recording mergeinfo for merge between repository URLs into '" +
- A_D_G + "':\n",
- "--- Eliding mergeinfo from '" + A_D_G_pi + "':\n",
- " U " + A_D_G_pi + "\n",
- "--- Eliding mergeinfo from '" + A_D_G_pi + "':\n",
- " U " + A_D_G_pi + "\n",
- " G " + A_D_G + "\n",
- 'Summary of conflicts:\n',
- ' Tree conflicts: 1\n',
- ])
+ expected_stdout = expected_merge_output(None, [
+ ' C ' + A_D_G_pi + '\n', # merge
+ ], target=A_D_G, elides=[A_D_G_pi, A_D_G], two_url=True, tree_conflicts=1)
actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge',
url_A_D_G, url_branch_D_G, A_D_G)
@@ -1975,15 +1929,10 @@ def merge_replace_on_del_fails(sbox):
# Sync merge ^/A to branch
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
- expected_stdout = verify.UnorderedOutput([
- "--- Merging r2 through r4 into '" + branch_path + "':\n",
- ' C ' + C_branch_path + '\n',
- "--- Recording mergeinfo for merge of r2 through r4 into '" \
- + branch_path + "':\n",
- ' U ' + branch_path + '\n',
- 'Summary of conflicts:\n',
- ' Tree conflicts: 1\n',
- ])
+ expected_stdout = expected_merge_output([[2,4]], [
+ ' C ' + C_branch_path + '\n', # merge
+ ' U ' + branch_path + '\n', # mergeinfo
+ ], target=branch_path, tree_conflicts=1)
# This currently fails with:
#
# >svn merge ^/A branch