#!/usr/bin/env python # # copy_tests.py: testing the many uses of 'svn cp' and 'svn mv' # # Subversion is a tool for revision control. # See http://subversion.apache.org for more information. # # ==================================================================== # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. ###################################################################### # General modules import stat, os, re, shutil # Our testing module import svntest from svntest import main from svntest.main import ( SVN_PROP_MERGEINFO, file_append, file_write, make_log_msg, run_svn, ) # (abbreviation) Skip = svntest.testcase.Skip_deco SkipUnless = svntest.testcase.SkipUnless_deco XFail = svntest.testcase.XFail_deco Issues = svntest.testcase.Issues_deco Issue = svntest.testcase.Issue_deco Wimp = svntest.testcase.Wimp_deco Item = svntest.wc.StateItem exp_noop_up_out = svntest.actions.expected_noop_update_output # #---------------------------------------------------------------------- # Helper for wc_copy_replacement and repos_to_wc_copy_replacement def copy_replace(sbox, wc_copy): """Tests for 'R'eplace functionanity for files. Depending on the value of wc_copy either a working copy (when true) or a url (when false) copy source is used.""" sbox.build() wc_dir = sbox.wc_dir # File scheduled for deletion rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path) # Status before attempting copies expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # The copy shouldn't fail if wc_copy: pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') else: pi_src = sbox.repo_url + '/A/D/G/pi' svntest.actions.run_and_verify_svn(None, None, [], 'cp', pi_src, rho_path) # Now commit expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-') svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_status.tweak('A/D/G/rho', status=' ', copied=None, wc_rev='2') expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho': Item(verb='Replacing'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Helper for wc_copy_replace_with_props and # repos_to_wc_copy_replace_with_props def copy_replace_with_props(sbox, wc_copy): """Tests for 'R'eplace functionanity for files with props. Depending on the value of wc_copy either a working copy (when true) or a url (when false) copy source is used.""" sbox.build() wc_dir = sbox.wc_dir # Use a temp file to set properties with wildcards in their values # otherwise Win32/VS2005 will expand them prop_path = os.path.join(wc_dir, 'proptmp') svntest.main.file_append(prop_path, '*') # Set props on file which is copy-source later on pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') svntest.actions.run_and_verify_svn(None, None, [], 'ps', 'phony-prop', '-F', prop_path, pi_path) os.remove(prop_path) svntest.actions.run_and_verify_svn(None, None, [], 'ps', 'svn:eol-style', 'LF', rho_path) # Verify props having been set expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('A/D/G/pi', props={ 'phony-prop': '*' }) expected_disk.tweak('A/D/G/rho', props={ 'svn:eol-style': 'LF' }) actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1) svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree()) # Commit props expected_output = svntest.wc.State(wc_dir, { 'A/D/G/pi': Item(verb='Sending'), 'A/D/G/rho': Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/pi', wc_rev='2') expected_status.tweak('A/D/G/rho', wc_rev='2') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Bring wc into sync svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) # File scheduled for deletion svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path) # Status before attempting copies expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.tweak('A/D/G/rho', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # The copy shouldn't fail if wc_copy: pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') else: pi_src = sbox.repo_url + '/A/D/G/pi' svntest.actions.run_and_verify_svn(None, None, [], 'cp', pi_src, rho_path) # Verify both content and props have been copied if wc_copy: props = { 'phony-prop' : '*'} else: props = { 'phony-prop' : '*'} expected_disk.tweak('A/D/G/rho', contents="This is the file 'pi'.\n", props=props) actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1) svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree()) # Now commit and verify expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-') svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_status.tweak('A/D/G/rho', status=' ', copied=None, wc_rev='3') expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho': Item(verb='Replacing'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) ###################################################################### # Tests # # Each test must return on success or raise on failure. # (Taken from notes/copy-planz.txt:) # # We have four use cases for 'svn cp' now. # # A. svn cp wc_path1 wc_path2 # # This duplicates a path in the working copy, and schedules it # for addition with history. # # B. svn cp URL [-r rev] wc_path # # This "checks out" URL (in REV) into the working copy at # wc_path, integrates it, and schedules it for addition with # history. # # C. svn cp wc_path URL # # This immediately commits wc_path to URL on the server; the # commit will be an addition with history. The commit will not # change the working copy at all. # # D. svn cp URL1 [-r rev] URL2 # # This causes a server-side copy to happen immediately; no # working copy is required. # TESTS THAT NEED TO BE WRITTEN # # Use Cases A & C # # -- single files, with/without local mods, as both 'cp' and 'mv'. # (need to verify commit worked by updating a 2nd working copy # to see the local mods) # # -- dir copy, has mixed revisions # # -- dir copy, has local mods (an edit, an add, a delete, and a replace) # # -- dir copy, has mixed revisions AND local mods # # -- dir copy, has mixed revisions AND another previously-made copy! # (perhaps done as two nested 'mv' commands!) # # Use Case D # # By the time the copy setup algorithm is complete, the copy # operation will have four parts: SRC-DIR, SRC-BASENAME, DST-DIR, # DST-BASENAME. In all cases, SRC-DIR/SRC-BASENAME and DST_DIR must # already exist before the operation, but DST_DIR/DST_BASENAME must # NOT exist. # # Besides testing things that don't meet the above criteria, we want to # also test valid cases: # # - where SRC-DIR/SRC-BASENAME is a file or a dir. # - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is a parent/grandparent # directory of DST-DIR # - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is a child/grandchild # directory of DST-DIR # - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is not in the lineage # of DST-DIR at all #---------------------------------------------------------------------- @Issue(1091) def basic_copy_and_move_files(sbox): "basic copy and move commands -- on files only" sbox.build() wc_dir = sbox.wc_dir mu_path = os.path.join(wc_dir, 'A', 'mu') iota_path = os.path.join(wc_dir, 'iota') rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') D_path = os.path.join(wc_dir, 'A', 'D') alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha') H_path = os.path.join(wc_dir, 'A', 'D', 'H') F_path = os.path.join(wc_dir, 'A', 'B', 'F') alpha2_path = os.path.join(wc_dir, 'A', 'C', 'alpha2') # Make local mods to mu and rho svntest.main.file_append(mu_path, 'appended mu text') svntest.main.file_append(rho_path, 'new appended text for rho') # Copy rho to D -- local mods svntest.actions.run_and_verify_svn(None, None, [], 'cp', rho_path, D_path) # Copy alpha to C -- no local mods, and rename it to 'alpha2' also svntest.actions.run_and_verify_svn(None, None, [], 'cp', alpha_path, alpha2_path) # Move mu to H -- local mods svntest.actions.run_and_verify_svn(None, None, [], 'mv', mu_path, H_path) # Move iota to F -- no local mods svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, F_path) # Created expected output tree for 'svn ci': # We should see four adds, two deletes, and one change in total. expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho' : Item(verb='Sending'), 'A/D/rho' : Item(verb='Adding'), 'A/C/alpha2' : Item(verb='Adding'), 'A/D/H/mu' : Item(verb='Adding'), 'A/B/F/iota' : Item(verb='Adding'), 'A/mu' : Item(verb='Deleting'), 'iota' : Item(verb='Deleting'), }) # Create expected status tree; all local revisions should be at 1, # but several files should be at revision 2. Also, two files should # be missing. expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', 'A/mu', wc_rev=2) expected_status.add({ 'A/D/rho' : Item(status=' ', wc_rev=2), 'A/C/alpha2' : Item(status=' ', wc_rev=2), 'A/D/H/mu' : Item(status=' ', wc_rev=2), 'A/B/F/iota' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/mu', 'iota') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Issue 1091, alpha2 would now have the wrong checksum and so a # subsequent commit would fail svntest.main.file_append(alpha2_path, 'appended alpha2 text') expected_output = svntest.wc.State(wc_dir, { 'A/C/alpha2' : Item(verb='Sending'), }) expected_status.tweak('A/C/alpha2', wc_rev=3) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Assure that attempts at local copy and move fail when a log # message is provided. expected_stderr = \ ".*Local, non-commit operations do not take a log message" svntest.actions.run_and_verify_svn(None, None, expected_stderr, 'cp', '-m', 'op fails', rho_path, D_path) svntest.actions.run_and_verify_svn(None, None, expected_stderr, 'mv', '-m', 'op fails', rho_path, D_path) #---------------------------------------------------------------------- # This test passes over ra_local certainly; we're adding it because at # one time it failed over ra_neon. Specifically, it failed when # mod_dav_svn first started sending vsn-rsc-urls as "CR/path", and was # sending bogus CR/paths for items within copied subtrees. def receive_copy_in_update(sbox): "receive a copied directory during update" sbox.build() wc_dir = sbox.wc_dir # Make a backup copy of the working copy. wc_backup = sbox.add_wc_path('backup') svntest.actions.duplicate_dir(wc_dir, wc_backup) # Define a zillion paths in both working copies. G_path = os.path.join(wc_dir, 'A', 'D', 'G') newG_path = os.path.join(wc_dir, 'A', 'B', 'newG') # Copy directory A/D to A/B/newG svntest.actions.run_and_verify_svn(None, None, [], 'cp', G_path, newG_path) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/B/newG' : Item(verb='Adding'), }) # Create expected status tree. expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/newG' : Item(status=' ', wc_rev=2), 'A/B/newG/pi' : Item(status=' ', wc_rev=2), 'A/B/newG/rho' : Item(status=' ', wc_rev=2), 'A/B/newG/tau' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Now update the other working copy; it should receive a full add of # the newG directory and its contents. # Expected output of update expected_output = svntest.wc.State(wc_backup, { 'A/B/newG' : Item(status='A '), 'A/B/newG/pi' : Item(status='A '), 'A/B/newG/rho' : Item(status='A '), 'A/B/newG/tau' : Item(status='A '), }) # Create expected disk tree for the update. expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/B/newG' : Item(), 'A/B/newG/pi' : Item("This is the file 'pi'.\n"), 'A/B/newG/rho' : Item("This is the file 'rho'.\n"), 'A/B/newG/tau' : Item("This is the file 'tau'.\n"), }) # Create expected status tree for the update. expected_status = svntest.actions.get_virginal_state(wc_backup, 2) expected_status.add({ 'A/B/newG' : Item(status=' ', wc_rev=2), 'A/B/newG/pi' : Item(status=' ', wc_rev=2), 'A/B/newG/rho' : Item(status=' ', wc_rev=2), 'A/B/newG/tau' : Item(status=' ', wc_rev=2), }) # Do the update and check the results in three ways. svntest.actions.run_and_verify_update(wc_backup, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Regression test for issue #683. In particular, this bug prevented # us from running 'svn cp -r N src_URL dst_URL' as a means of # resurrecting a deleted directory. Also, the final 'update' at the # end of this test was uncovering a ghudson 'deleted' edge-case bug. # (In particular, re-adding G to D, when D already had a 'deleted' # entry for G. The entry-merge wasn't overwriting the 'deleted' # attribute, and thus the newly-added G was ending up disconnected # from D.) @Issue(683) def resurrect_deleted_dir(sbox): "resurrect a deleted directory" sbox.build() wc_dir = sbox.wc_dir G_path = os.path.join(wc_dir, 'A', 'D', 'G') # Delete directory A/D/G, commit that as r2. svntest.actions.run_and_verify_svn(None, None, [], 'rm', '--force', G_path) expected_output = svntest.wc.State(wc_dir, { 'A/D/G' : Item(verb='Deleting'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.remove('A/D/G') expected_status.remove('A/D/G/pi') expected_status.remove('A/D/G/rho') expected_status.remove('A/D/G/tau') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Use 'svn cp URL@1 URL' to resurrect the deleted directory, where # the two URLs are identical. This used to trigger a failure. url = sbox.repo_url + '/A/D/G' svntest.actions.run_and_verify_svn(None, None, [], 'cp', url + '@1', url, '-m', 'logmsg') # For completeness' sake, update to HEAD, and verify we have a full # greek tree again, all at revision 3. expected_output = svntest.wc.State(wc_dir, { 'A/D/G' : Item(status='A '), 'A/D/G/pi' : Item(status='A '), 'A/D/G/rho' : Item(status='A '), 'A/D/G/tau' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_status = svntest.actions.get_virginal_state(wc_dir, 3) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) def copy_deleted_dir_into_prefix(sbox): "copy a deleted dir to a prefix of its old path" sbox.build() wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') # Delete directory A/D, commit that as r2. svntest.actions.run_and_verify_svn(None, None, [], 'rm', '--force', D_path) expected_output = svntest.wc.State(wc_dir, { 'A/D' : Item(verb='Deleting'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) # Ok, copy from a deleted URL into a prefix of that URL, this used to # result in an assert failing. url1 = sbox.repo_url + '/A/D/G' url2 = sbox.repo_url + '/A/D' svntest.actions.run_and_verify_svn(None, None, [], 'cp', url1 + '@1', url2, '-m', 'logmsg') #---------------------------------------------------------------------- # Test that we're enforcing proper 'svn cp' overwrite behavior. Note # that svn_fs_copy() will always overwrite its destination if an entry # by the same name already exists. However, libsvn_client should be # doing existence checks to prevent directories from being # overwritten, and files can't be overwritten because the RA layers # are doing out-of-dateness checks during the commit. def no_copy_overwrites(sbox): "svn cp URL URL cannot overwrite destination" sbox.build() wc_dir = sbox.wc_dir fileURL1 = sbox.repo_url + "/A/B/E/alpha" fileURL2 = sbox.repo_url + "/A/B/E/beta" dirURL1 = sbox.repo_url + "/A/D/G" dirURL2 = sbox.repo_url + "/A/D/H" # Expect out-of-date failure if 'svn cp URL URL' tries to overwrite a file svntest.actions.run_and_verify_svn("Whoa, I was able to overwrite a file!", None, svntest.verify.AnyOutput, 'cp', fileURL1, fileURL2, '-m', 'fooogle') # Create A/D/H/G by running 'svn cp ...A/D/G .../A/D/H' svntest.actions.run_and_verify_svn(None, None, [], 'cp', dirURL1, dirURL2, '-m', 'fooogle') # Repeat the last command. It should *fail* because A/D/H/G already exists. svntest.actions.run_and_verify_svn( "Whoa, I was able to overwrite a directory!", None, svntest.verify.AnyOutput, 'cp', dirURL1, dirURL2, '-m', 'fooogle') #---------------------------------------------------------------------- # Issue 845. WC -> WC copy should not overwrite base text-base @Issue(845) def no_wc_copy_overwrites(sbox): "svn cp PATH PATH cannot overwrite destination" sbox.build(read_only = True) wc_dir = sbox.wc_dir # File simply missing tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau') os.remove(tau_path) # Status before attempting copies expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/tau', status='! ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # These copies should fail pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput, 'cp', pi_path, rho_path) svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput, 'cp', pi_path, tau_path) # Status after failed copies should not have changed svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- # Takes out working-copy locks for A/B2 and child A/B2/E. At one stage # during issue 749 the second lock cause an already-locked error. @Issue(749) def copy_modify_commit(sbox): "copy a tree and modify before commit" sbox.build() wc_dir = sbox.wc_dir B_path = os.path.join(wc_dir, 'A', 'B') B2_path = os.path.join(wc_dir, 'A', 'B2') svntest.actions.run_and_verify_svn(None, None, [], 'cp', B_path, B2_path) alpha_path = os.path.join(wc_dir, 'A', 'B2', 'E', 'alpha') svntest.main.file_append(alpha_path, "modified alpha") expected_output = svntest.wc.State(wc_dir, { 'A/B2' : Item(verb='Adding'), 'A/B2/E/alpha' : Item(verb='Sending'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) #---------------------------------------------------------------------- # Issue 591, at one point copying a file from URL to WC didn't copy # properties. @Issue(591) def copy_files_with_properties(sbox): "copy files with properties" sbox.build() wc_dir = sbox.wc_dir # Set a property on a file rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'pname', 'pval', rho_path) # and commit it expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', status=' ', wc_rev=2) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Set another property, but don't commit it yet svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'pname2', 'pval2', rho_path) # WC to WC copy of file with committed and uncommitted properties rho_wc_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho_wc') svntest.actions.run_and_verify_svn(None, None, [], 'copy', rho_path, rho_wc_path) # REPOS to WC copy of file with properties rho_url_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho_url') rho_url = sbox.repo_url + '/A/D/G/rho' svntest.actions.run_and_verify_svn(None, None, [], 'copy', rho_url, rho_url_path) # Properties are not visible in WC status 'A' expected_status.add({ 'A/D/G/rho' : Item(status=' M', wc_rev='2'), 'A/D/G/rho_wc' : Item(status='A ', wc_rev='-', copied='+'), 'A/D/G/rho_url' : Item(status='A ', wc_rev='-', copied='+'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Check properties explicitly svntest.actions.run_and_verify_svn(None, ['pval\n'], [], 'propget', 'pname', rho_wc_path) svntest.actions.run_and_verify_svn(None, ['pval2\n'], [], 'propget', 'pname2', rho_wc_path) svntest.actions.run_and_verify_svn(None, ['pval\n'], [], 'propget', 'pname', rho_url_path) # Commit and properties are visible in status expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho' : Item(verb='Sending'), 'A/D/G/rho_wc' : Item(verb='Adding'), 'A/D/G/rho_url' : Item(verb='Adding'), }) expected_status.tweak('A/D/G/rho', status=' ', wc_rev=3) expected_status.remove('A/D/G/rho_wc', 'A/D/G/rho_url') expected_status.add({ 'A/D/G/rho_wc' : Item(status=' ', wc_rev=3), 'A/D/G/rho_url' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Issue 918 @Issue(918) def copy_delete_commit(sbox): "copy a tree and delete part of it before commit" sbox.build() wc_dir = sbox.wc_dir B_path = os.path.join(wc_dir, 'A', 'B') B2_path = os.path.join(wc_dir, 'A', 'B2') # copy a tree svntest.actions.run_and_verify_svn(None, None, [], 'cp', B_path, B2_path) # delete two files lambda_path = os.path.join(wc_dir, 'A', 'B2', 'lambda') alpha_path = os.path.join(wc_dir, 'A', 'B2', 'E', 'alpha') svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path, lambda_path) # commit copied tree containing a deleted file expected_output = svntest.wc.State(wc_dir, { 'A/B2' : Item(verb='Adding'), 'A/B2/lambda' : Item(verb='Deleting'), 'A/B2/E/alpha' : Item(verb='Deleting'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) # copy a tree svntest.actions.run_and_verify_svn(None, None, [], 'cp', os.path.join(wc_dir, 'A', 'B'), os.path.join(wc_dir, 'A', 'B3')) # delete a directory E_path = os.path.join(wc_dir, 'A', 'B3', 'E') svntest.actions.run_and_verify_svn(None, None, [], 'rm', E_path) # commit copied tree containing a deleted directory expected_output = svntest.wc.State(wc_dir, { 'A/B3' : Item(verb='Adding'), 'A/B3/E' : Item(verb='Deleting'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) #---------------------------------------------------------------------- @Issues(931,932) def mv_and_revert_directory(sbox): "move and revert a directory" sbox.build(read_only = True) wc_dir = sbox.wc_dir E_path = os.path.join(wc_dir, 'A', 'B', 'E') F_path = os.path.join(wc_dir, 'A', 'B', 'F') new_E_path = os.path.join(F_path, 'E') # Issue 931: move failed to lock the directory being deleted svntest.actions.run_and_verify_svn(None, None, [], 'move', E_path, F_path) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ') expected_status.add({ 'A/B/F/E' : Item(status='A ', wc_rev='-', copied='+'), 'A/B/F/E/alpha' : Item(status=' ', wc_rev='-', copied='+'), 'A/B/F/E/beta' : Item(status=' ', wc_rev='-', copied='+'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Issue 932: revert failed to lock the parent directory svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive', new_E_path) expected_status.remove('A/B/F/E', 'A/B/F/E/alpha', 'A/B/F/E/beta') svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- # Issue 982. When copying a file with the executable bit set, the copied # file should also have its executable bit set. @Issue(982) @SkipUnless(svntest.main.is_posix_os) def copy_preserve_executable_bit(sbox): "executable bit should be preserved when copying" # Bootstrap sbox.build() wc_dir = sbox.wc_dir # Create two paths newpath1 = os.path.join(wc_dir, 'newfile1') newpath2 = os.path.join(wc_dir, 'newfile2') # Create the first file. svntest.main.file_append(newpath1, "a new file") svntest.actions.run_and_verify_svn(None, None, [], 'add', newpath1) mode1 = os.stat(newpath1)[stat.ST_MODE] # Doing this to get the executable bit set on systems that support # that -- the property itself is not the point. svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'svn:executable', 'on', newpath1) mode2 = os.stat(newpath1)[stat.ST_MODE] if mode1 == mode2: print("setting svn:executable did not change file's permissions") raise svntest.Failure # Commit the file svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'create file and set svn:executable', wc_dir) # Copy the file svntest.actions.run_and_verify_svn(None, None, [], 'cp', newpath1, newpath2) mode3 = os.stat(newpath2)[stat.ST_MODE] # The mode on the original and copied file should be identical if mode2 != mode3: print("permissions on the copied file are not identical to original file") raise svntest.Failure #---------------------------------------------------------------------- # Issue 1029, copy failed with a "working copy not locked" error @Issue(1029) def wc_to_repos(sbox): "working-copy to repository copy" sbox.build() wc_dir = sbox.wc_dir beta_path = os.path.join(wc_dir, "A", "B", "E", "beta") beta2_url = sbox.repo_url + "/A/B/E/beta2" H_path = os.path.join(wc_dir, "A", "D", "H") H2_url = sbox.repo_url + "/A/D/H2" # modify some items to be copied svntest.main.file_append(os.path.join(wc_dir, 'A', 'D', 'H', 'omega'), "new otext\n") svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'foo', 'bar', beta_path) # copy a file svntest.actions.run_and_verify_svn(None, None, [], '-m', 'fumble file', 'copy', beta_path, beta2_url) # and a directory svntest.actions.run_and_verify_svn(None, None, [], '-m', 'fumble dir', 'copy', H_path, H2_url) # copy a file to a directory svntest.actions.run_and_verify_svn(None, None, [], '-m', 'fumble file', 'copy', beta_path, H2_url) # update the working copy. post-update mereinfo elision will remove # A/D/H2/beta's mergeinfo, leaving a local mod. expected_output = svntest.wc.State(wc_dir, { 'A/B/E/beta2' : Item(status='A '), 'A/D/H2' : Item(status='A '), 'A/D/H2/chi' : Item(status='A '), 'A/D/H2/omega' : Item(status='A '), 'A/D/H2/psi' : Item(status='A '), 'A/D/H2/beta' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('A/D/H/omega', contents="This is the file 'omega'.\nnew otext\n") expected_disk.add({ 'A/B/E/beta2' : Item("This is the file 'beta'.\n"), 'A/D/H2/chi' : Item("This is the file 'chi'.\n"), 'A/D/H2/omega' : Item("This is the file 'omega'.\nnew otext\n"), 'A/D/H2/psi' : Item("This is the file 'psi'.\n"), 'A/D/H2/beta' : Item("This is the file 'beta'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 4) expected_status.add({ 'A/B/E/beta' : Item(status=' M', wc_rev=4), 'A/D/H/omega' : Item(status='M ', wc_rev=4), 'A/B/E/beta2' : Item(status=' ', wc_rev=4), 'A/D/H2' : Item(status=' ', wc_rev=4), 'A/D/H2/chi' : Item(status=' ', wc_rev=4), 'A/D/H2/omega' : Item(status=' ', wc_rev=4), 'A/D/H2/psi' : Item(status=' ', wc_rev=4), 'A/D/H2/beta' : Item(status=' ', wc_rev=4), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # check local property was copied svntest.actions.run_and_verify_svn(None, ['bar\n'], [], 'propget', 'foo', beta_path + "2") #---------------------------------------------------------------------- # Issue 1090: various use-cases of 'svn cp URL wc' where the # repositories might be different, or be the same repository. @Issues(1090,1444) def repos_to_wc(sbox): "repository to working-copy copy" sbox.build() wc_dir = sbox.wc_dir # We have a standard repository and working copy. Now we create a # second repository with the same greek tree, but different UUID. repo_dir = sbox.repo_dir other_repo_dir, other_repo_url = sbox.add_repo_path('other') svntest.main.copy_repos(repo_dir, other_repo_dir, 1, 1) # URL->wc copy: # copy a file and a directory from the same repository. # we should get some scheduled additions *with history*. E_url = sbox.repo_url + "/A/B/E" pi_url = sbox.repo_url + "/A/D/G/pi" pi_path = os.path.join(wc_dir, 'pi') svntest.actions.run_and_verify_svn(None, None, [], 'copy', E_url, wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'copy', pi_url, wc_dir) # Extra test: modify file ASAP to check there was a timestamp sleep svntest.main.file_append(pi_path, 'zig\n') expected_output = svntest.actions.get_virginal_state(wc_dir, 1) expected_output.add({ 'pi' : Item(status='A ', copied='+', wc_rev='-'), 'E' : Item(status='A ', copied='+', wc_rev='-'), 'E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'E/beta' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_output) # Modification will only show up if timestamps differ exit_code, out, err = svntest.main.run_svn(None, 'diff', pi_path) if err or not out: print("diff failed") raise svntest.Failure for line in out: if line == '+zig\n': # Crude check for diff-like output break else: print("diff output incorrect %s" % out) raise svntest.Failure # Revert everything and verify. svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir) svntest.main.safe_rmtree(os.path.join(wc_dir, 'E')) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) svntest.actions.run_and_verify_status(wc_dir, expected_output) # URL->wc copy: # Copy an empty directory from the same repository, see issue #1444. C_url = sbox.repo_url + "/A/C" svntest.actions.run_and_verify_svn(None, None, [], 'copy', C_url, wc_dir) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) expected_output.add({ 'C' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_output) # Revert everything and verify. svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir) svntest.main.safe_rmtree(os.path.join(wc_dir, 'C')) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) svntest.actions.run_and_verify_status(wc_dir, expected_output) # URL->wc copy: # copy a file and a directory from a foreign repository. # we should get some scheduled additions *without history*. E_url = other_repo_url + "/A/B/E" pi_url = other_repo_url + "/A/D/G/pi" # Expect an error in the directory case until we allow this copy to succeed. expected_error = "svn: E200007: Source URL '.*foreign repository" svntest.actions.run_and_verify_svn(None, None, expected_error, 'copy', E_url, wc_dir) # But file case should work fine. svntest.actions.run_and_verify_svn(None, None, [], 'copy', pi_url, wc_dir) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) expected_output.add({ 'pi' : Item(status='A ', wc_rev='0', entry_rev='1'), }) svntest.actions.run_and_verify_status(wc_dir, expected_output) # Revert everything and verify. svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) # URL->wc copy: # Copy a directory to a pre-existing WC directory. # The source directory should be copied *under* the target directory. B_url = sbox.repo_url + "/A/B" D_dir = os.path.join(wc_dir, 'A', 'D') svntest.actions.run_and_verify_svn(None, None, [], 'copy', B_url, D_dir) expected_output = svntest.actions.get_virginal_state(wc_dir, 1) expected_output.add({ 'A/D/B' : Item(status='A ', copied='+', wc_rev='-'), 'A/D/B/lambda' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/B/E' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/B/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/B/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/B/F' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_output) # Validate the merge info of the copy destination (we expect none) svntest.actions.run_and_verify_svn(None, [], [], 'propget', SVN_PROP_MERGEINFO, os.path.join(D_dir, 'B')) #---------------------------------------------------------------------- # Issue 1084: ra_svn move/copy bug @Issue(1084) def copy_to_root(sbox): 'copy item to root of repository' sbox.build() wc_dir = sbox.wc_dir root = sbox.repo_url mu = root + '/A/mu' svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-m', '', mu, root) # Update to HEAD, and check to see if the files really were copied in the # repo expected_output = svntest.wc.State(wc_dir, { 'mu': Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'mu': Item(contents="This is the file 'mu'.\n") }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'mu': Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- @Issue(1367) def url_copy_parent_into_child(sbox): "copy URL URL/subdir" sbox.build() wc_dir = sbox.wc_dir B_url = sbox.repo_url + "/A/B" F_url = sbox.repo_url + "/A/B/F" # Issue 1367 parent/child URL-to-URL was rejected. svntest.actions.run_and_verify_svn(None, ['\n', 'Committed revision 2.\n'], [], 'cp', '-m', 'a can of worms', B_url, F_url) # Do an update to verify the copy worked expected_output = svntest.wc.State(wc_dir, { 'A/B/F/B' : Item(status='A '), 'A/B/F/B/E' : Item(status='A '), 'A/B/F/B/E/alpha' : Item(status='A '), 'A/B/F/B/E/beta' : Item(status='A '), 'A/B/F/B/F' : Item(status='A '), 'A/B/F/B/lambda' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/B/F/B' : Item(), 'A/B/F/B/E' : Item(), 'A/B/F/B/E/alpha' : Item("This is the file 'alpha'.\n"), 'A/B/F/B/E/beta' : Item("This is the file 'beta'.\n"), 'A/B/F/B/F' : Item(), 'A/B/F/B/lambda' : Item("This is the file 'lambda'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/B/F/B' : Item(status=' ', wc_rev=2), 'A/B/F/B/E' : Item(status=' ', wc_rev=2), 'A/B/F/B/E/alpha' : Item(status=' ', wc_rev=2), 'A/B/F/B/E/beta' : Item(status=' ', wc_rev=2), 'A/B/F/B/F' : Item(status=' ', wc_rev=2), 'A/B/F/B/lambda' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- @Issue(1367) def wc_copy_parent_into_child(sbox): "copy WC URL/subdir" sbox.build(create_wc = False) wc_dir = sbox.wc_dir B_url = sbox.repo_url + "/A/B" F_B_url = sbox.repo_url + "/A/B/F/B" # Want a smaller WC svntest.main.safe_rmtree(wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'checkout', B_url, wc_dir) # Issue 1367: A) copying '.' to URL failed with a parent/child # error, and also B) copying root of a working copy attempted to # lock the non-working copy parent directory. was_cwd = os.getcwd() os.chdir(wc_dir) svntest.actions.run_and_verify_svn(None, ['Adding copy of .\n', '\n', 'Committed revision 2.\n'], [], 'cp', '-m', 'a larger can', '.', F_B_url) os.chdir(was_cwd) # Do an update to verify the copy worked expected_output = svntest.wc.State(wc_dir, { 'F/B' : Item(status='A '), 'F/B/E' : Item(status='A '), 'F/B/E/alpha' : Item(status='A '), 'F/B/E/beta' : Item(status='A '), 'F/B/F' : Item(status='A '), 'F/B/lambda' : Item(status='A '), }) expected_disk = svntest.wc.State('', { 'E' : Item(), 'E/alpha' : Item("This is the file 'alpha'.\n"), 'E/beta' : Item("This is the file 'beta'.\n"), 'F' : Item(), 'lambda' : Item("This is the file 'lambda'.\n"), 'F/B' : Item(), 'F/B/E' : Item(), 'F/B/E/alpha' : Item("This is the file 'alpha'.\n"), 'F/B/E/beta' : Item("This is the file 'beta'.\n"), 'F/B/F' : Item(), 'F/B/lambda' : Item("This is the file 'lambda'.\n"), }) expected_status = svntest.wc.State(wc_dir, { '' : Item(status=' ', wc_rev=2), 'E' : Item(status=' ', wc_rev=2), 'E/alpha' : Item(status=' ', wc_rev=2), 'E/beta' : Item(status=' ', wc_rev=2), 'F' : Item(status=' ', wc_rev=2), 'lambda' : Item(status=' ', wc_rev=2), 'F/B' : Item(status=' ', wc_rev=2), 'F/B/E' : Item(status=' ', wc_rev=2), 'F/B/E/alpha' : Item(status=' ', wc_rev=2), 'F/B/E/beta' : Item(status=' ', wc_rev=2), 'F/B/F' : Item(status=' ', wc_rev=2), 'F/B/lambda' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Issue 1419: at one point ra_neon->get_uuid() was failing on a # non-existent public URL, which prevented us from resurrecting files # (svn cp -rOLD URL wc). @Issue(1419) def resurrect_deleted_file(sbox): "resurrect a deleted file" sbox.build() wc_dir = sbox.wc_dir # Delete a file in the repository via immediate commit rho_url = sbox.repo_url + '/A/D/G/rho' svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_url, '-m', 'rev 2') # Update the wc to HEAD (r2) expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho' : Item(status='D '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.remove('A/D/G/rho') expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.remove('A/D/G/rho') svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # repos->wc copy, to resurrect deleted file. svntest.actions.run_and_verify_svn("Copy error:", None, [], 'cp', rho_url + '@1', wc_dir) # status should now show the file scheduled for addition-with-history expected_status.add({ 'rho' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #------------------------------------------------------------- # Regression tests for Issue #1297: # svn diff failed after a repository to WC copy of a single file # This test checks just that. @Issue(1297) def diff_repos_to_wc_copy(sbox): "copy file from repos to working copy and run diff" sbox.build(read_only = True) wc_dir = sbox.wc_dir iota_repos_path = sbox.repo_url + '/iota' target_wc_path = os.path.join(wc_dir, 'new_file') # Copy a file from the repository to the working copy. svntest.actions.run_and_verify_svn(None, None, [], 'cp', iota_repos_path, target_wc_path) # Run diff. svntest.actions.run_and_verify_svn(None, None, [], 'diff', wc_dir) #------------------------------------------------------------- @Issue(1473) def repos_to_wc_copy_eol_keywords(sbox): "repos->WC copy with keyword or eol property set" # See issue #1473: repos->wc copy would seg fault if svn:keywords or # svn:eol were set on the copied file, because we'd be querying an # entry for keyword values when the entry was still null (because # not yet been fully installed in the wc). sbox.build() wc_dir = sbox.wc_dir iota_repos_path = sbox.repo_url + '/iota' iota_wc_path = os.path.join(wc_dir, 'iota') target_wc_path = os.path.join(wc_dir, 'new_file') # Modify iota to make it checkworthy. svntest.main.file_write(iota_wc_path, "Hello\nSubversion\n$LastChangedRevision$\n", "ab") svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'svn:eol-style', 'CRLF', iota_wc_path) svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'svn:keywords', 'Rev', iota_wc_path) svntest.actions.run_and_verify_svn(None, None, [], 'commit', '-m', 'log msg', wc_dir) # Copy a file from the repository to the working copy. svntest.actions.run_and_verify_svn(None, None, [], 'cp', iota_repos_path, target_wc_path) # The original bug was that the copy would seg fault. So we test # that the copy target exists now; if it doesn't, it's probably # because of the segfault. Note that the crash would be independent # of whether there are actually any line breaks or keywords in the # file's contents -- the mere existence of the property would # trigger the bug. if not os.path.exists(target_wc_path): raise svntest.Failure # Okay, if we got this far, we might as well make sure that the # translations/substitutions were done correctly: f = open(target_wc_path, "rb") raw_contents = f.read() f.seek(0, 0) line_contents = f.readlines() f.close() if re.match('[^\\r]\\n', raw_contents): raise svntest.Failure if not re.match('.*\$LastChangedRevision:\s*\d+\s*\$', line_contents[3]): raise svntest.Failure #------------------------------------------------------------- # Regression test for revision 7331, with commented-out parts for a further # similar bug. def revision_kinds_local_source(sbox): "revision-kind keywords with non-URL source" sbox.build() wc_dir = sbox.wc_dir mu_path = os.path.join(wc_dir, 'A', 'mu') # Make a file with different content in each revision and WC; BASE != HEAD. expected_output = svntest.wc.State(wc_dir, { 'A/mu' : Item(verb='Sending'), }) svntest.main.file_append(mu_path, "New r2 text.\n") svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) svntest.main.file_append(mu_path, "New r3 text.\n") svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None, wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'up', '-r2', mu_path) svntest.main.file_append(mu_path, "Working copy.\n") r1 = "This is the file 'mu'.\n" r2 = r1 + "New r2 text.\n" r3 = r2 + "New r3 text.\n" rWC = r2 + "Working copy.\n" expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('A/mu', contents=rWC) # Test the various revision-kind keywords, and none. sub_tests = [ ('file0', 2, rWC, None), ('file1', 3, r3, 'HEAD'), ('file2', 2, r2, 'BASE'), # ('file3', 2, r2, 'COMMITTED'), # ('file4', 1, r1, 'PREV'), ] for dst, from_rev, text, peg_rev in sub_tests: dst_path = os.path.join(wc_dir, dst) if peg_rev is None: svntest.actions.run_and_verify_svn(None, None, [], "copy", mu_path, dst_path) else: svntest.actions.run_and_verify_svn(None, None, [], "copy", mu_path + "@" + peg_rev, dst_path) expected_disk.add({ dst: Item(contents=text) }) # Check that the copied-from revision == from_rev. exit_code, output, errput = svntest.main.run_svn(None, "info", dst_path) for line in output: if line.rstrip() == "Copied From Rev: " + str(from_rev): break else: print("%s should have been copied from revision %s" % (dst, from_rev)) raise svntest.Failure # Check that the new files have the right contents actual_disk = svntest.tree.build_tree_from_wc(wc_dir) svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree()) #------------------------------------------------------------- # Regression test for issue 1581. @Issue(1581) def copy_over_missing_file(sbox): "copy over a missing file" sbox.build(read_only = True) wc_dir = sbox.wc_dir mu_path = os.path.join(wc_dir, 'A', 'mu') iota_path = os.path.join(wc_dir, 'iota') iota_url = sbox.repo_url + "/iota" # Make the target missing. os.remove(mu_path) # Try both wc->wc copy and repos->wc copy, expect failures: svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput, 'cp', iota_path, mu_path) svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput, 'cp', iota_url, mu_path) # Make sure that the working copy is not corrupted: expected_disk = svntest.main.greek_state.copy() expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_output = svntest.wc.State(wc_dir, {'A/mu' : Item(verb='Restored')}) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Regression test for issue 1634 @Issue(1634) def repos_to_wc_1634(sbox): "copy a deleted directory back from the repos" sbox.build() wc_dir = sbox.wc_dir # First delete a subdirectory and commit. E_path = os.path.join(wc_dir, 'A', 'B', 'E') svntest.actions.run_and_verify_svn(None, None, [], 'delete', E_path) expected_output = svntest.wc.State(wc_dir, { 'A/B/E' : Item(verb='Deleting'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Now copy the directory back. E_url = sbox.repo_url + "/A/B/E@1" svntest.actions.run_and_verify_svn(None, None, [], 'copy', E_url, E_path) expected_status.add({ 'A/B/E' : Item(status='A ', copied='+', wc_rev='-'), 'A/B/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'A/B/E/beta' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/B/E' : Item(status='A ', copied='+', wc_rev='-'), 'A/B/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'A/B/E/beta' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- # Regression test for issue 1814 @Issue(1814) def double_uri_escaping_1814(sbox): "check for double URI escaping in svn ls -R" sbox.build(create_wc = False) base_url = sbox.repo_url + '/base' # rev. 2 svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'mybase', base_url) orig_url = base_url + '/foo%20bar' # rev. 3 svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'r1', orig_url) orig_rev = 3 # rev. 4 new_url = base_url + '/foo_bar' svntest.actions.run_and_verify_svn(None, None, [], 'mv', '-m', 'r2', orig_url, new_url) # This had failed with ra_neon because "foo bar" would be double-encoded # "foo bar" ==> "foo%20bar" ==> "foo%2520bar" svntest.actions.run_and_verify_svn(None, None, [], 'ls', ('-r'+str(orig_rev)), '-R', base_url) #---------------------------------------------------------------------- # Regression test for issues 2404 @Issue(2404) def wc_to_wc_copy_between_different_repos(sbox): "wc to wc copy attempts between different repos" sbox.build(read_only = True) wc_dir = sbox.wc_dir sbox2 = sbox.clone_dependent() sbox2.build() wc2_dir = sbox2.wc_dir # Attempt a copy between different repositories. exit_code, out, err = svntest.main.run_svn(1, 'cp', os.path.join(wc2_dir, 'A'), os.path.join(wc_dir, 'A', 'B')) for line in err: if line.find("it is not from repository") != -1: break else: raise svntest.Failure #---------------------------------------------------------------------- # Regression test for issues 2101, 2020 and 3776 @Issues(2101,2020,3776) def wc_to_wc_copy_deleted(sbox): "wc to wc copy with presence=not-present items" sbox.build() wc_dir = sbox.wc_dir B_path = os.path.join(wc_dir, 'A', 'B') B2_path = os.path.join(wc_dir, 'A', 'B2') # Schedule for delete svntest.actions.run_and_verify_svn(None, None, [], 'rm', os.path.join(B_path, 'E', 'alpha'), os.path.join(B_path, 'lambda'), os.path.join(B_path, 'F')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/B/E/alpha', 'A/B/lambda', 'A/B/F', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # Commit to get state not-present expected_status.remove('A/B/E/alpha', 'A/B/lambda', 'A/B/F') expected_output = svntest.wc.State(wc_dir, { 'A/B/E/alpha' : Item(verb='Deleting'), 'A/B/lambda' : Item(verb='Deleting'), 'A/B/F' : Item(verb='Deleting'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Copy including stuff in state not-present svntest.actions.run_and_verify_svn(None, None, [], 'copy', B_path, B2_path) expected_status.add({ 'A/B2' : Item(status='A ', wc_rev='-', copied='+'), 'A/B2/E' : Item(status=' ', wc_rev='-', copied='+'), 'A/B2/E/beta' : Item(status=' ', wc_rev='-', copied='+'), 'A/B2/E/alpha' : Item(status='D ', wc_rev='-', copied='+'), 'A/B2/lambda' : Item(status='D ', wc_rev='-', copied='+'), 'A/B2/F' : Item(status='D ', wc_rev='-', copied='+'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Reverting the copied not-present is a no-op. svntest.main.run_svn(1, 'revert', os.path.join(B2_path, 'F')) svntest.main.run_svn(1, 'revert', os.path.join(B2_path, 'lambda')) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Revert the entire copy including the schedule not-present bits svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive', B2_path) expected_status.remove('A/B2', 'A/B2/E', 'A/B2/E/beta', 'A/B2/E/alpha', 'A/B2/lambda', 'A/B2/F') svntest.actions.run_and_verify_status(wc_dir, expected_status) svntest.main.safe_rmtree(B2_path) # Copy again and commit svntest.actions.run_and_verify_svn(None, None, [], 'copy', B_path, B2_path) expected_status.add({ 'A/B2' : Item(status='A ', copied='+', wc_rev='-'), 'A/B2/lambda' : Item(status='D ', copied='+', wc_rev='-'), 'A/B2/F' : Item(status='D ', copied='+', wc_rev='-'), 'A/B2/E' : Item(status=' ', copied='+', wc_rev='-'), 'A/B2/E/alpha' : Item(status='D ', copied='+', wc_rev='-'), 'A/B2/E/beta' : Item(status=' ', copied='+', wc_rev='-') }) svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_status.remove('A/B2/lambda', 'A/B2/F', 'A/B2/E/alpha') expected_status.tweak('A/B2', 'A/B2/E', 'A/B2/E/beta', status=' ', copied=None, wc_rev=3) expected_output = svntest.wc.State(wc_dir, { 'A/B2' : Item(verb='Adding'), 'A/B2/E/alpha' : Item(verb='Deleting'), 'A/B2/lambda' : Item(verb='Deleting'), 'A/B2/F' : Item(verb='Deleting'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test for copy into a non-existent URL path def url_to_non_existent_url_path(sbox): "svn cp src-URL non-existent-URL-path" sbox.build(create_wc = False) dirURL1 = sbox.repo_url + "/A/B/E" dirURL2 = sbox.repo_url + "/G/C/E/I" # Look for both possible versions of the error message, as the DAV # error is worded differently from that of other RA layers. msg = ".*: (" + \ "|".join(["Path 'G(/C/E)?' not present", ".*G(/C/E)?' path not found", "File not found.*'/G/C/E/I'", ]) + ")" # Expect failure on 'svn cp SRC DST' where one or more ancestor # directories of DST do not exist exit_code, out, err = svntest.main.run_svn(1, 'cp', dirURL1, dirURL2, '-m', 'fooogle') for err_line in err: if re.match (msg, err_line): break else: print("message \"%s\" not found in error output: %s" % (msg, err)) raise svntest.Failure #---------------------------------------------------------------------- # Test for a copying (URL to URL) an old rev of a deleted file in a # deleted directory. def non_existent_url_to_url(sbox): "svn cp oldrev-of-deleted-URL URL" sbox.build(create_wc = False) adg_url = sbox.repo_url + '/A/D/G' pi_url = sbox.repo_url + '/A/D/G/pi' new_url = sbox.repo_url + '/newfile' svntest.actions.run_and_verify_svn(None, None, [], 'delete', adg_url, '-m', '') svntest.actions.run_and_verify_svn(None, None, [], 'copy', pi_url + '@1', new_url, '-m', '') #---------------------------------------------------------------------- def old_dir_url_to_url(sbox): "test URL to URL copying edge case" sbox.build(create_wc = False) adg_url = sbox.repo_url + '/A/D/G' pi_url = sbox.repo_url + '/A/D/G/pi' iota_url = sbox.repo_url + '/iota' new_url = sbox.repo_url + '/newfile' # Delete a directory svntest.actions.run_and_verify_svn(None, None, [], 'delete', adg_url, '-m', '') # Copy a file to where the directory used to be svntest.actions.run_and_verify_svn(None, None, [], 'copy', iota_url, adg_url, '-m', '') # Try copying a file that was in the deleted directory that is now a # file svntest.actions.run_and_verify_svn(None, None, [], 'copy', pi_url + '@1', new_url, '-m', '') #---------------------------------------------------------------------- # Test fix for issue 2224 - copying wc dir to itself causes endless # recursion @Issue(2224) def wc_copy_dir_to_itself(sbox): "copy wc dir to itself" sbox.build(read_only = True) wc_dir = sbox.wc_dir dnames = ['A','A/B'] for dirname in dnames: dir_path = os.path.join(wc_dir, dirname) # try to copy dir to itself svntest.actions.run_and_verify_svn(None, [], '.*Cannot copy .* into its own child.*', 'copy', dir_path, dir_path) #---------------------------------------------------------------------- @Issue(2153) def mixed_wc_to_url(sbox): "copy a complex mixed-rev wc" # For issue 2153. # # Copy a mixed-revision wc (that also has some uncommitted local # mods, and an entry marked as 'deleted') to a URL. Make sure the # copy gets the uncommitted mods, and does not contain the deleted # file. sbox.build() wc_dir = sbox.wc_dir Z_url = sbox.repo_url + '/A/D/Z' Z2_url = sbox.repo_url + '/A/D/Z2' G_path = os.path.join(wc_dir, 'A', 'D', 'G') B_path = os.path.join(wc_dir, 'A', 'B') X_path = os.path.join(wc_dir, 'A', 'D', 'G', 'X') Y_path = os.path.join(wc_dir, 'A', 'D', 'G', 'Y') E_path = os.path.join(wc_dir, 'A', 'D', 'G', 'X', 'E') alpha_path = os.path.join(wc_dir, 'A', 'D', 'G', 'X', 'E', 'alpha') pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') # Remove A/D/G/pi, then commit that removal. svntest.actions.run_and_verify_svn(None, None, [], 'rm', pi_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', "Delete pi.", wc_dir) # Make a modification to A/D/G/rho, then commit that modification. svntest.main.file_append(rho_path, "\nFirst modification to rho.\n") svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', "Modify rho.", wc_dir) # Make another modification to A/D/G/rho, but don't commit it. svntest.main.file_append(rho_path, "Second modification to rho.\n") # Copy into the source, delete part of the copy, add a non-copied directory svntest.actions.run_and_verify_svn(None, None, [], 'cp', B_path, X_path) svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path) svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', Y_path) # Now copy local A/D/G to create new directory A/D/Z the repository. svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-m', "Make a copy.", G_path, Z_url) expected_output = svntest.verify.UnorderedOutput([ 'A + A/D/Z/\n', ' (from A/D/G/:r1)\n', 'A + A/D/Z/X/\n', ' (from A/B/:r1)\n', 'D A/D/Z/X/E/alpha\n', 'A A/D/Z/Y/\n', 'D A/D/Z/pi\n', 'D A/D/Z/rho\n', 'A + A/D/Z/rho\n', ' (from A/D/G/rho:r3)\n', ]) svntest.actions.run_and_verify_svnlook(None, expected_output, [], 'changed', sbox.repo_dir, '--copy-info') # Copy from copied source svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-m', "Make a copy.", E_path, Z2_url) expected_output = svntest.verify.UnorderedOutput([ 'A + A/D/Z2/\n', ' (from A/B/E/:r1)\n', 'D A/D/Z2/alpha\n', ]) svntest.actions.run_and_verify_svnlook(None, expected_output, [], 'changed', sbox.repo_dir, '--copy-info') # Check out A/D/Z. If it has pi, that's a bug; or if its rho does # not have the second local mod, that's also a bug. svntest.main.safe_rmtree(wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'co', Z_url, wc_dir) if os.path.exists(os.path.join(wc_dir, 'pi')): raise svntest.Failure("Path 'pi' exists but should be gone.") fp = open(os.path.join(wc_dir, 'rho'), 'r') found_it = 0 for line in fp.readlines(): if re.match("^Second modification to rho.", line): found_it = 1 if not found_it: raise svntest.Failure("The second modification to rho didn't make it.") #---------------------------------------------------------------------- # Issue 845 and 1516: WC replacement of files requires # a second text-base and prop-base @Issues(845,1516) def wc_copy_replacement(sbox): "svn cp PATH PATH replace file" copy_replace(sbox, 1) def wc_copy_replace_with_props(sbox): "svn cp PATH PATH replace file with props" copy_replace_with_props(sbox, 1) def repos_to_wc_copy_replacement(sbox): "svn cp URL PATH replace file" copy_replace(sbox, 0) def repos_to_wc_copy_replace_with_props(sbox): "svn cp URL PATH replace file with props" copy_replace_with_props(sbox, 0) # See also delete_replace_delete() which does the same for a directory. def delete_replaced_file(sbox): "delete a file scheduled for replacement" sbox.build(read_only = True) wc_dir = sbox.wc_dir # File scheduled for deletion. rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path) # Status before attempting copies expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # Copy 'pi' over 'rho' with history. pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi') svntest.actions.run_and_verify_svn(None, None, [], 'cp', pi_src, rho_path) # Check that file copied. expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-') svntest.actions.run_and_verify_status(wc_dir, expected_status) # Now delete replaced file. svntest.actions.run_and_verify_svn(None, None, [], 'rm', '--force', rho_path) # Verify status after deletion. expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) @Issue(2436) def mv_unversioned_file(sbox): "move an unversioned file" # Issue #2436: Attempting to move an unversioned file would seg fault. sbox.build(read_only = True) wc_dir = sbox.wc_dir unver_path_1 = os.path.join(wc_dir, 'unversioned1') dest_path_1 = os.path.join(wc_dir, 'dest') svntest.main.file_append(unver_path_1, "an unversioned file") unver_path_2 = os.path.join(wc_dir, 'A', 'unversioned2') dest_path_2 = os.path.join(wc_dir, 'A', 'dest_forced') svntest.main.file_append(unver_path_2, "another unversioned file") # Try to move an unversioned file. svntest.actions.run_and_verify_svn(None, None, ".*unversioned1.* is not under version control.*", 'mv', unver_path_1, dest_path_1) # Try to forcibly move an unversioned file. svntest.actions.run_and_verify_svn(None, None, ".*unversioned2.* is not under version control.*", 'mv', unver_path_2, dest_path_2) @Issue(2435) def force_move(sbox): "'move' should not lose local mods" # Issue #2435: 'svn move' / 'svn mv' can lose local modifications. sbox.build() wc_dir = sbox.wc_dir file_name = "iota" file_path = os.path.join(wc_dir, file_name) # modify the content file_handle = open(file_path, "a") file_handle.write("Added contents\n") file_handle.close() expected_file_content = [ "This is the file 'iota'.\n", "Added contents\n", ] # check for the new content file_handle = open(file_path, "r") modified_file_content = file_handle.readlines() file_handle.close() if modified_file_content != expected_file_content: raise svntest.Failure("Test setup failed. Incorrect file contents.") # force move the file move_output = [ "A dest\n", "D iota\n", ] was_cwd = os.getcwd() os.chdir(wc_dir) svntest.actions.run_and_verify_svn(None, move_output, [], 'move', file_name, "dest") os.chdir(was_cwd) # check for the new content file_handle = open(os.path.join(wc_dir, "dest"), "r") modified_file_content = file_handle.readlines() file_handle.close() # Error if we dont find the modified contents... if modified_file_content != expected_file_content: raise svntest.Failure("File modifications were lost on 'move'") # Commit the move and make sure the new content actually reaches # the repository. expected_output = svntest.wc.State(wc_dir, { 'iota': Item(verb='Deleting'), 'dest': Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.remove("iota") expected_status.add({ 'dest': Item(status=' ', wc_rev='2'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) svntest.actions.run_and_verify_svn('Cat file', expected_file_content, [], 'cat', sbox.repo_url + '/dest') def copy_copied_file_and_dir(sbox): "copy a copied file and dir" # Improve support for copy and move # Allow copy of copied items without a commit between sbox.build() wc_dir = sbox.wc_dir rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') rho_copy_path_1 = os.path.join(wc_dir, 'A', 'D', 'rho_copy_1') rho_copy_path_2 = os.path.join(wc_dir, 'A', 'B', 'F', 'rho_copy_2') # Copy A/D/G/rho to A/D/rho_copy_1 svntest.actions.run_and_verify_svn(None, None, [], 'cp', rho_path, rho_copy_path_1) # Copy the copied file: A/D/rho_copy_1 to A/B/F/rho_copy_2 svntest.actions.run_and_verify_svn(None, None, [], 'cp', rho_copy_path_1, rho_copy_path_2) E_path = os.path.join(wc_dir, 'A', 'B', 'E') E_path_copy_1 = os.path.join(wc_dir, 'A', 'B', 'F', 'E_copy_1') E_path_copy_2 = os.path.join(wc_dir, 'A', 'D', 'G', 'E_copy_2') # Copy A/B/E to A/B/F/E_copy_1 svntest.actions.run_and_verify_svn(None, None, [], 'cp', E_path, E_path_copy_1) # Copy the copied dir: A/B/F/E_copy_1 to A/D/G/E_copy_2 svntest.actions.run_and_verify_svn(None, None, [], 'cp', E_path_copy_1, E_path_copy_2) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/D/rho_copy_1' : Item(verb='Adding'), 'A/B/F/rho_copy_2' : Item(verb='Adding'), 'A/B/F/E_copy_1/' : Item(verb='Adding'), 'A/D/G/E_copy_2/' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/rho_copy_1' : Item(status=' ', wc_rev=2), 'A/B/F/rho_copy_2' : Item(status=' ', wc_rev=2), 'A/B/F/E_copy_1' : Item(status=' ', wc_rev=2), 'A/B/F/E_copy_1/alpha' : Item(status=' ', wc_rev=2), 'A/B/F/E_copy_1/beta' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_2' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_2/alpha' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_2/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_copied_file_and_dir(sbox): "move a copied file and dir" sbox.build() wc_dir = sbox.wc_dir rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') rho_copy_path = os.path.join(wc_dir, 'A', 'D', 'rho_copy') rho_copy_move_path = os.path.join(wc_dir, 'A', 'B', 'F', 'rho_copy_moved') # Copy A/D/G/rho to A/D/rho_copy svntest.actions.run_and_verify_svn(None, None, [], 'cp', rho_path, rho_copy_path) # Move the copied file: A/D/rho_copy to A/B/F/rho_copy_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', rho_copy_path, rho_copy_move_path) E_path = os.path.join(wc_dir, 'A', 'B', 'E') E_path_copy = os.path.join(wc_dir, 'A', 'B', 'F', 'E_copy') E_path_copy_move = os.path.join(wc_dir, 'A', 'D', 'G', 'E_copy_moved') # Copy A/B/E to A/B/F/E_copy svntest.actions.run_and_verify_svn(None, None, [], 'cp', E_path, E_path_copy) # Move the copied file: A/B/F/E_copy to A/D/G/E_copy_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', E_path_copy, E_path_copy_move) # Created expected output tree for 'svn ci': # Since we are moving items that were only *scheduled* for addition # we expect only to additions when checking in, rather than a # deletion/addition pair. expected_output = svntest.wc.State(wc_dir, { 'A/B/F/rho_copy_moved' : Item(verb='Adding'), 'A/D/G/E_copy_moved/' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/rho_copy_moved' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_moved' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_moved/alpha' : Item(status=' ', wc_rev=2), 'A/D/G/E_copy_moved/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_moved_file_and_dir(sbox): "move a moved file and dir" sbox.build() wc_dir = sbox.wc_dir rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') rho_move_path = os.path.join(wc_dir, 'A', 'D', 'rho_moved') rho_move_moved_path = os.path.join(wc_dir, 'A', 'B', 'F', 'rho_move_moved') # Move A/D/G/rho to A/D/rho_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', rho_path, rho_move_path) # Move the moved file: A/D/rho_moved to A/B/F/rho_move_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', rho_move_path, rho_move_moved_path) E_path = os.path.join(wc_dir, 'A', 'B', 'E') E_path_moved = os.path.join(wc_dir, 'A', 'B', 'F', 'E_moved') E_path_move_moved = os.path.join(wc_dir, 'A', 'D', 'G', 'E_move_moved') # Copy A/B/E to A/B/F/E_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', E_path, E_path_moved) # Move the moved file: A/B/F/E_moved to A/D/G/E_move_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', E_path_moved, E_path_move_moved) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/B/E' : Item(verb='Deleting'), 'A/D/G/E_move_moved/' : Item(verb='Adding'), 'A/D/G/rho' : Item(verb='Deleting'), 'A/B/F/rho_move_moved' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/G/E_move_moved/' : Item(status=' ', wc_rev=2), 'A/D/G/E_move_moved/alpha' : Item(status=' ', wc_rev=2), 'A/D/G/E_move_moved/beta' : Item(status=' ', wc_rev=2), 'A/B/F/rho_move_moved' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/D/G/rho') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_file_within_moved_dir(sbox): "move a file twice within a moved dir" sbox.build() wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') D_path_moved = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved') # Move A/B/D to A/B/F/D_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, D_path_moved) chi_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H', 'chi') chi_moved_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H', 'chi_moved') chi_moved_again_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H', 'chi_moved_again') # Move A/B/F/D_moved/H/chi to A/B/F/D_moved/H/chi_moved # then move that to A/B/F/D_moved/H/chi_moved_again svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_path, chi_moved_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_moved_path, chi_moved_again_path) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/B/F/D_moved/' : Item(verb='Adding'), 'A/B/F/D_moved/H/chi' : Item(verb='Deleting'), 'A/B/F/D_moved/H/chi_moved_again' : Item(verb='Adding'), 'A/D' : Item(verb='Deleting'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/D_moved' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/gamma' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/pi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/rho' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/tau' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H/omega' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H/psi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H/chi_moved_again' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/D', 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', ) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_file_out_of_moved_dir(sbox): "move a file out of a moved dir" sbox.build() wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') D_path_moved = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved') # Move A/B/D to A/B/F/D_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, D_path_moved) chi_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H', 'chi') chi_moved_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H', 'chi_moved') chi_moved_again_path = os.path.join(wc_dir, 'A', 'C', 'chi_moved_again') # Move A/B/F/D_moved/H/chi to A/B/F/D_moved/H/chi_moved # then move that to A/C/chi_moved_again svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_path, chi_moved_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_moved_path, chi_moved_again_path) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/B/F/D_moved/' : Item(verb='Adding'), 'A/B/F/D_moved/H/chi' : Item(verb='Deleting'), 'A/C/chi_moved_again' : Item(verb='Adding'), 'A/D' : Item(verb='Deleting'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/D_moved' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/gamma' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/pi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/rho' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/tau' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H/omega' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H/psi' : Item(status=' ', wc_rev=2), 'A/C/chi_moved_again' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/D', 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', ) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_dir_within_moved_dir(sbox): "move a dir twice within a moved dir" sbox.build() wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') D_path_moved = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved') # Move A/D to A/B/F/D_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, D_path_moved) H_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H') H_moved_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H_moved') H_moved_again_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H_moved_again') # Move A/B/F/D_moved/H to A/B/F/D_moved/H_moved # then move that to A/B/F/D_moved/H_moved_again svntest.actions.run_and_verify_svn(None, None, [], 'mv', H_path, H_moved_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', H_moved_path, H_moved_again_path) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/D' : Item(verb='Deleting'), 'A/B/F/D_moved' : Item(verb='Adding'), 'A/B/F/D_moved/H' : Item(verb='Deleting'), 'A/B/F/D_moved/H_moved_again' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/D_moved' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/gamma' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/pi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/rho' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/tau' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H_moved_again' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H_moved_again/omega' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H_moved_again/psi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/H_moved_again/chi' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/D', 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', ) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def move_dir_out_of_moved_dir(sbox): "move a dir out of a moved dir" sbox.build() wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') D_path_moved = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved') # Move A/D to A/B/F/D_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, D_path_moved) H_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H') H_moved_path = os.path.join(wc_dir, 'A', 'B', 'F', 'D_moved', 'H_moved') H_moved_again_path = os.path.join(wc_dir, 'A', 'C', 'H_moved_again') # Move A/B/F/D_moved/H to A/B/F/D_moved/H_moved # then move that to A/C/H_moved_again svntest.actions.run_and_verify_svn(None, None, [], 'mv', H_path, H_moved_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', H_moved_path, H_moved_again_path) # Created expected output tree for 'svn ci': expected_output = svntest.wc.State(wc_dir, { 'A/D' : Item(verb='Deleting'), 'A/B/F/D_moved' : Item(verb='Adding'), 'A/B/F/D_moved/H' : Item(verb='Deleting'), 'A/C/H_moved_again' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/D_moved' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/gamma' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/pi' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/rho' : Item(status=' ', wc_rev=2), 'A/B/F/D_moved/G/tau' : Item(status=' ', wc_rev=2), 'A/C/H_moved_again' : Item(status=' ', wc_rev=2), 'A/C/H_moved_again/omega' : Item(status=' ', wc_rev=2), 'A/C/H_moved_again/psi' : Item(status=' ', wc_rev=2), 'A/C/H_moved_again/chi' : Item(status=' ', wc_rev=2), }) expected_status.remove('A/D', 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', ) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Includes regression testing for issue #3429 ("svn mv A B; svn mv B A" # generates replace without history). @Issue(3429) def move_file_back_and_forth(sbox): "move a moved file back to original location" sbox.build() wc_dir = sbox.wc_dir rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') rho_move_path = os.path.join(wc_dir, 'A', 'D', 'rho_moved') # Move A/D/G/rho away from and then back to its original path svntest.actions.run_and_verify_svn(None, None, [], 'mv', rho_path, rho_move_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', rho_move_path, rho_path) # Check expected status before commit expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/G/rho' : Item(status='R ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Commit, and check expected output and status expected_output = svntest.wc.State(wc_dir, { 'A/D/G/rho' : Item(verb='Replacing'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/G/rho' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Includes regression testing for issue #3429 ("svn mv A B; svn mv B A" # generates replace without history). @Issue(3429) def move_dir_back_and_forth(sbox): "move a moved dir back to original location" sbox.build(read_only = True) wc_dir = sbox.wc_dir D_path = os.path.join(wc_dir, 'A', 'D') D_move_path = os.path.join(wc_dir, 'D_moved') # Move A/D to D_moved svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, D_move_path) # Move the moved dir: D_moved back to its starting # location at A/D. if svntest.main.wc_is_singledb(wc_dir): # In single-db target is gone on-disk after it was moved away, so this # move works ok expected_err = [] else: # In !SINGLE_DB the target of the copy exists on-dir, so svn tries # to move the file below the deleted directory expected_err = '.*Cannot copy to .*as it is scheduled for deletion' svntest.actions.run_and_verify_svn(None, None, expected_err, 'mv', D_move_path, D_path) if svntest.main.wc_is_singledb(wc_dir): # Verify that the status indicates a replace with history expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D' : Item(status='R ', copied='+', wc_rev='-'), 'A/D/G' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/gamma' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/H' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/H/chi' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/H/omega' : Item(status=' ', copied='+', wc_rev='-'), 'A/D/H/psi' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) def copy_move_added_paths(sbox): "copy and move added paths without commits" sbox.build() wc_dir = sbox.wc_dir # Create a new file and schedule it for addition upsilon_path = os.path.join(wc_dir, 'A', 'D', 'upsilon') svntest.main.file_write(upsilon_path, "This is the file 'upsilon'\n") svntest.actions.run_and_verify_svn(None, None, [], 'add', upsilon_path) # Create a dir with children and schedule it for addition I_path = os.path.join(wc_dir, 'A', 'D', 'I') J_path = os.path.join(I_path, 'J') eta_path = os.path.join(I_path, 'eta') theta_path = os.path.join(I_path, 'theta') kappa_path = os.path.join(J_path, 'kappa') os.mkdir(I_path) os.mkdir(J_path) svntest.main.file_write(eta_path, "This is the file 'eta'\n") svntest.main.file_write(theta_path, "This is the file 'theta'\n") svntest.main.file_write(kappa_path, "This is the file 'kappa'\n") svntest.actions.run_and_verify_svn(None, None, [], 'add', I_path) # Create another dir and schedule it for addition K_path = os.path.join(wc_dir, 'K') os.mkdir(K_path) svntest.actions.run_and_verify_svn(None, None, [], 'add', K_path) # Verify all the adds took place correctly. expected_status_after_adds = svntest.actions.get_virginal_state(wc_dir, 1) expected_status_after_adds.add({ 'A/D/I' : Item(status='A ', wc_rev='0'), 'A/D/I/eta' : Item(status='A ', wc_rev='0'), 'A/D/I/J' : Item(status='A ', wc_rev='0'), 'A/D/I/J/kappa' : Item(status='A ', wc_rev='0'), 'A/D/I/theta' : Item(status='A ', wc_rev='0'), 'A/D/upsilon' : Item(status='A ', wc_rev='0'), 'K' : Item(status='A ', wc_rev='0'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status_after_adds) # Scatter some unversioned paths within the added dir I. unversioned_path_1 = os.path.join(I_path, 'unversioned1') unversioned_path_2 = os.path.join(J_path, 'unversioned2') L_path = os.path.join(I_path, "L_UNVERSIONED") unversioned_path_3 = os.path.join(L_path, 'unversioned3') svntest.main.file_write(unversioned_path_1, "An unversioned file\n") svntest.main.file_write(unversioned_path_2, "An unversioned file\n") os.mkdir(L_path) svntest.main.file_write(unversioned_path_3, "An unversioned file\n") # Copy added dir A/D/I to added dir K/I I_copy_path = os.path.join(K_path, 'I') svntest.actions.run_and_verify_svn(None, None, [], 'cp', I_path, I_copy_path) # Copy added file A/D/upsilon into added dir K upsilon_copy_path = os.path.join(K_path, 'upsilon') svntest.actions.run_and_verify_svn(None, None, [], 'cp', upsilon_path, upsilon_copy_path) # Move added file A/D/upsilon to upsilon, # then move it again to A/upsilon upsilon_move_path = os.path.join(wc_dir, 'upsilon') upsilon_move_path_2 = os.path.join(wc_dir, 'A', 'upsilon') svntest.actions.run_and_verify_svn(None, None, [], 'mv', upsilon_path, upsilon_move_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', upsilon_move_path, upsilon_move_path_2) # Move added dir A/D/I to A/B/I, # then move it again to A/D/H/I I_move_path = os.path.join(wc_dir, 'A', 'B', 'I') I_move_path_2 = os.path.join(wc_dir, 'A', 'D', 'H', 'I') svntest.actions.run_and_verify_svn(None, None, [], 'mv', I_path, I_move_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', I_move_path, I_move_path_2) # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { 'A/D/H/I' : Item(verb='Adding'), 'A/D/H/I/J' : Item(verb='Adding'), 'A/D/H/I/J/kappa' : Item(verb='Adding'), 'A/D/H/I/eta' : Item(verb='Adding'), 'A/D/H/I/theta' : Item(verb='Adding'), 'A/upsilon' : Item(verb='Adding'), 'K' : Item(verb='Adding'), 'K/I' : Item(verb='Adding'), 'K/I/J' : Item(verb='Adding'), 'K/I/J/kappa' : Item(verb='Adding'), 'K/I/eta' : Item(verb='Adding'), 'K/I/theta' : Item(verb='Adding'), 'K/upsilon' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/H/I' : Item(status=' ', wc_rev=2), 'A/D/H/I/J' : Item(status=' ', wc_rev=2), 'A/D/H/I/J/kappa' : Item(status=' ', wc_rev=2), 'A/D/H/I/eta' : Item(status=' ', wc_rev=2), 'A/D/H/I/theta' : Item(status=' ', wc_rev=2), 'A/upsilon' : Item(status=' ', wc_rev=2), 'K' : Item(status=' ', wc_rev=2), 'K/I' : Item(status=' ', wc_rev=2), 'K/I/J' : Item(status=' ', wc_rev=2), 'K/I/J/kappa' : Item(status=' ', wc_rev=2), 'K/I/eta' : Item(status=' ', wc_rev=2), 'K/I/theta' : Item(status=' ', wc_rev=2), 'K/upsilon' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Run_and_verify_commit() doesn't handle status of unversioned paths # so manually confirm unversioned paths got copied and moved too. unversioned_paths = [ os.path.join(wc_dir, 'A', 'D', 'H', 'I', 'unversioned1'), os.path.join(wc_dir, 'A', 'D', 'H', 'I', 'L_UNVERSIONED'), os.path.join(wc_dir, 'A', 'D', 'H', 'I', 'L_UNVERSIONED', 'unversioned3'), os.path.join(wc_dir, 'A', 'D', 'H', 'I', 'J', 'unversioned2'), os.path.join(wc_dir, 'K', 'I', 'unversioned1'), os.path.join(wc_dir, 'K', 'I', 'L_UNVERSIONED'), os.path.join(wc_dir, 'K', 'I', 'L_UNVERSIONED', 'unversioned3'), os.path.join(wc_dir, 'K', 'I', 'J', 'unversioned2')] for path in unversioned_paths: if not os.path.exists(path): raise svntest.Failure("Unversioned path '%s' not found." % path) def copy_added_paths_with_props(sbox): "copy added uncommitted paths with props" sbox.build() wc_dir = sbox.wc_dir # Create a new file, schedule it for addition and set properties upsilon_path = os.path.join(wc_dir, 'A', 'D', 'upsilon') svntest.main.file_write(upsilon_path, "This is the file 'upsilon'\n") svntest.actions.run_and_verify_svn(None, None, [], 'add', upsilon_path) svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'foo', 'bar', upsilon_path) # Create a dir and schedule it for addition and set properties I_path = os.path.join(wc_dir, 'A', 'D', 'I') os.mkdir(I_path) svntest.actions.run_and_verify_svn(None, None, [], 'add', I_path) svntest.actions.run_and_verify_svn(None, None, [], 'propset', 'foo', 'bar', I_path) # Verify all the adds took place correctly. expected_status_after_adds = svntest.actions.get_virginal_state(wc_dir, 1) expected_status_after_adds.add({ 'A/D/upsilon' : Item(status='A ', wc_rev='0'), 'A/D/I' : Item(status='A ', wc_rev='0'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status_after_adds) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/D/upsilon' : Item(props={'foo' : 'bar'}, contents="This is the file 'upsilon'\n"), 'A/D/I' : Item(props={'foo' : 'bar'}), }) # Read disk state with props actual_disk_tree = svntest.tree.build_tree_from_wc(wc_dir, 1) # Compare actual vs. expected disk trees. svntest.tree.compare_trees("disk", actual_disk_tree, expected_disk.old_tree()) # Copy added dir I to dir A/C I_copy_path = os.path.join(wc_dir, 'A', 'C', 'I') svntest.actions.run_and_verify_svn(None, None, [], 'cp', I_path, I_copy_path) # Copy added file A/upsilon into dir A/C upsilon_copy_path = os.path.join(wc_dir, 'A', 'C', 'upsilon') svntest.actions.run_and_verify_svn(None, None, [], 'cp', upsilon_path, upsilon_copy_path) # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { 'A/D/upsilon' : Item(verb='Adding'), 'A/D/I' : Item(verb='Adding'), 'A/C/upsilon' : Item(verb='Adding'), 'A/C/I' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/upsilon' : Item(status=' ', wc_rev=2), 'A/D/I' : Item(status=' ', wc_rev=2), 'A/C/upsilon' : Item(status=' ', wc_rev=2), 'A/C/I' : Item(status=' ', wc_rev=2), }) # Tweak expected disk tree expected_disk.add({ 'A/C/upsilon' : Item(props={ 'foo' : 'bar'}, contents="This is the file 'upsilon'\n"), 'A/C/I' : Item(props={ 'foo' : 'bar'}), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Read disk state with props actual_disk_tree = svntest.tree.build_tree_from_wc(wc_dir, 1) # Compare actual vs. expected disk trees. svntest.tree.compare_trees("disk", actual_disk_tree, expected_disk.old_tree()) def copy_added_paths_to_URL(sbox): "copy added path to URL" sbox.build() wc_dir = sbox.wc_dir # Create a new file and schedule it for addition upsilon_path = os.path.join(wc_dir, 'A', 'D', 'upsilon') svntest.main.file_write(upsilon_path, "This is the file 'upsilon'\n") svntest.actions.run_and_verify_svn(None, None, [], 'add', upsilon_path) # Create a dir with children and schedule it for addition I_path = os.path.join(wc_dir, 'A', 'D', 'I') J_path = os.path.join(I_path, 'J') eta_path = os.path.join(I_path, 'eta') theta_path = os.path.join(I_path, 'theta') kappa_path = os.path.join(J_path, 'kappa') os.mkdir(I_path) os.mkdir(J_path) svntest.main.file_write(eta_path, "This is the file 'eta'\n") svntest.main.file_write(theta_path, "This is the file 'theta'\n") svntest.main.file_write(kappa_path, "This is the file 'kappa'\n") svntest.actions.run_and_verify_svn(None, None, [], 'add', I_path) # Verify all the adds took place correctly. expected_status_after_adds = svntest.actions.get_virginal_state(wc_dir, 1) expected_status_after_adds.add({ 'A/D/I' : Item(status='A ', wc_rev='0'), 'A/D/I/eta' : Item(status='A ', wc_rev='0'), 'A/D/I/J' : Item(status='A ', wc_rev='0'), 'A/D/I/J/kappa' : Item(status='A ', wc_rev='0'), 'A/D/I/theta' : Item(status='A ', wc_rev='0'), 'A/D/upsilon' : Item(status='A ', wc_rev='0'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status_after_adds) # Scatter some unversioned paths within the added dir I. # These don't get copied in a WC->URL copy obviously. unversioned_path_1 = os.path.join(I_path, 'unversioned1') unversioned_path_2 = os.path.join(J_path, 'unversioned2') L_path = os.path.join(I_path, "L_UNVERSIONED") unversioned_path_3 = os.path.join(L_path, 'unversioned3') svntest.main.file_write(unversioned_path_1, "An unversioned file\n") svntest.main.file_write(unversioned_path_2, "An unversioned file\n") os.mkdir(L_path) svntest.main.file_write(unversioned_path_3, "An unversioned file\n") # Copy added file A/D/upsilon to URL://A/C/upsilon upsilon_copy_URL = sbox.repo_url + '/A/C/upsilon' svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-m', '', upsilon_path, upsilon_copy_URL) # Validate the merge info of the copy destination (we expect none). svntest.actions.run_and_verify_svn(None, [], [], 'propget', SVN_PROP_MERGEINFO, upsilon_copy_URL) # Copy added dir A/D/I to URL://A/D/G/I I_copy_URL = sbox.repo_url + '/A/D/G/I' svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-m', '', I_path, I_copy_URL) # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { 'A/D/I' : Item(verb='Adding'), 'A/D/I/J' : Item(verb='Adding'), 'A/D/I/J/kappa' : Item(verb='Adding'), 'A/D/I/eta' : Item(verb='Adding'), 'A/D/I/theta' : Item(verb='Adding'), 'A/D/upsilon' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/D/I' : Item(status=' ', wc_rev=4), 'A/D/I/J' : Item(status=' ', wc_rev=4), 'A/D/I/J/kappa' : Item(status=' ', wc_rev=4), 'A/D/I/eta' : Item(status=' ', wc_rev=4), 'A/D/I/theta' : Item(status=' ', wc_rev=4), 'A/D/upsilon' : Item(status=' ', wc_rev=4), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Created expected output for update expected_output = svntest.wc.State(wc_dir, { 'A/D/G/I' : Item(status='A '), 'A/D/G/I/theta' : Item(status='A '), 'A/D/G/I/J' : Item(status='A '), 'A/D/G/I/J/kappa' : Item(status='A '), 'A/D/G/I/eta' : Item(status='A '), 'A/C/upsilon' : Item(status='A '), }) # Created expected disk for update expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/D/G/I' : Item(), 'A/D/G/I/theta' : Item("This is the file 'theta'\n"), 'A/D/G/I/J' : Item(), 'A/D/G/I/J/kappa' : Item("This is the file 'kappa'\n"), 'A/D/G/I/eta' : Item("This is the file 'eta'\n"), 'A/C/upsilon' : Item("This is the file 'upsilon'\n"), 'A/D/I' : Item(), 'A/D/I/J' : Item(), 'A/D/I/J/kappa' : Item("This is the file 'kappa'\n"), 'A/D/I/eta' : Item("This is the file 'eta'\n"), 'A/D/I/theta' : Item("This is the file 'theta'\n"), 'A/D/upsilon' : Item("This is the file 'upsilon'\n"), 'A/D/I/L_UNVERSIONED/unversioned3' : Item("An unversioned file\n"), 'A/D/I/L_UNVERSIONED' : Item(), 'A/D/I/unversioned1' : Item("An unversioned file\n"), 'A/D/I/J/unversioned2' : Item("An unversioned file\n"), }) # Some more changes to the expected_status to reflect post update WC expected_status.tweak(wc_rev=4) expected_status.add({ 'A/C' : Item(status=' ', wc_rev=4), 'A/C/upsilon' : Item(status=' ', wc_rev=4), 'A/D/G' : Item(status=' ', wc_rev=4), 'A/D/G/I' : Item(status=' ', wc_rev=4), 'A/D/G/I/theta' : Item(status=' ', wc_rev=4), 'A/D/G/I/J' : Item(status=' ', wc_rev=4), 'A/D/G/I/J/kappa' : Item(status=' ', wc_rev=4), 'A/D/G/I/eta' : Item(status=' ', wc_rev=4), }) # Update WC, the WC->URL copies above should be added svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Issue #1869. @Issue(1869) def move_to_relative_paths(sbox): "move file using relative dst path names" sbox.build() wc_dir = sbox.wc_dir E_path = os.path.join(wc_dir, 'A', 'B', 'E') rel_path = os.path.join('..', '..', '..') current_dir = os.getcwd() os.chdir(E_path) svntest.main.run_svn(None, 'mv', 'beta', rel_path) os.chdir(current_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'beta' : Item(status='A ', copied='+', wc_rev='-'), 'A/B/E/beta' : Item(status='D ', wc_rev='1') }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- def move_from_relative_paths(sbox): "move file using relative src path names" sbox.build(read_only = True) wc_dir = sbox.wc_dir F_path = os.path.join(wc_dir, 'A', 'B', 'F') beta_rel_path = os.path.join('..', 'E', 'beta') current_dir = os.getcwd() os.chdir(F_path) svntest.main.run_svn(None, 'mv', beta_rel_path, '.') os.chdir(current_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/beta' : Item(status='A ', copied='+', wc_rev='-'), 'A/B/E/beta' : Item(status='D ', wc_rev='1') }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- def copy_to_relative_paths(sbox): "copy file using relative dst path names" sbox.build(read_only = True) wc_dir = sbox.wc_dir E_path = os.path.join(wc_dir, 'A', 'B', 'E') rel_path = os.path.join('..', '..', '..') current_dir = os.getcwd() os.chdir(E_path) svntest.main.run_svn(None, 'cp', 'beta', rel_path) os.chdir(current_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'beta' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- def copy_from_relative_paths(sbox): "copy file using relative src path names" sbox.build(read_only = True) wc_dir = sbox.wc_dir F_path = os.path.join(wc_dir, 'A', 'B', 'F') beta_rel_path = os.path.join('..', 'E', 'beta') current_dir = os.getcwd() os.chdir(F_path) svntest.main.run_svn(None, 'cp', beta_rel_path, '.') os.chdir(current_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/beta' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- # Test moving multiple files within a wc. def move_multiple_wc(sbox): "svn mv multiple files to a common directory" sbox.build() wc_dir = sbox.wc_dir chi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'chi') psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') omega_path = os.path.join(wc_dir, 'A', 'D', 'H', 'omega') E_path = os.path.join(wc_dir, 'A', 'B', 'E') C_path = os.path.join(wc_dir, 'A', 'C') # Move chi, psi, omega and E to A/C svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_path, psi_path, omega_path, E_path, C_path) # Create expected output expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(verb='Adding'), 'A/C/psi' : Item(verb='Adding'), 'A/C/omega' : Item(verb='Adding'), 'A/C/E' : Item(verb='Adding'), 'A/D/H/chi' : Item(verb='Deleting'), 'A/D/H/psi' : Item(verb='Deleting'), 'A/D/H/omega' : Item(verb='Deleting'), 'A/B/E' : Item(verb='Deleting'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) # Add the moved files expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=2), 'A/C/psi' : Item(status=' ', wc_rev=2), 'A/C/omega' : Item(status=' ', wc_rev=2), 'A/C/E' : Item(status=' ', wc_rev=2), 'A/C/E/alpha' : Item(status=' ', wc_rev=2), 'A/C/E/beta' : Item(status=' ', wc_rev=2), }) # Removed the moved files expected_status.remove('A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/E') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test copying multiple files within a wc. def copy_multiple_wc(sbox): "svn cp multiple files to a common directory" sbox.build() wc_dir = sbox.wc_dir chi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'chi') psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') omega_path = os.path.join(wc_dir, 'A', 'D', 'H', 'omega') E_path = os.path.join(wc_dir, 'A', 'B', 'E') C_path = os.path.join(wc_dir, 'A', 'C') # Copy chi, psi, omega and E to A/C svntest.actions.run_and_verify_svn(None, None, [], 'cp', chi_path, psi_path, omega_path, E_path, C_path) # Create expected output expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(verb='Adding'), 'A/C/psi' : Item(verb='Adding'), 'A/C/omega' : Item(verb='Adding'), 'A/C/E' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) # Add the moved files expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=2), 'A/C/psi' : Item(status=' ', wc_rev=2), 'A/C/omega' : Item(status=' ', wc_rev=2), 'A/C/E' : Item(status=' ', wc_rev=2), 'A/C/E/alpha' : Item(status=' ', wc_rev=2), 'A/C/E/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test moving multiple files within a repo. def move_multiple_repo(sbox): "move multiple files within a repo" sbox.build() wc_dir = sbox.wc_dir chi_url = sbox.repo_url + '/A/D/H/chi' psi_url = sbox.repo_url + '/A/D/H/psi' omega_url = sbox.repo_url + '/A/D/H/omega' E_url = sbox.repo_url + '/A/B/E' C_url = sbox.repo_url + '/A/C' # Move three files and a directory in the repo to a different location # in the repo svntest.actions.run_and_verify_svn(None, None, [], 'mv', chi_url, psi_url, omega_url, E_url, C_url, '-m', 'logmsg') # Update to HEAD, and check to see if the files really moved in the repo expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(status='A '), 'A/C/psi' : Item(status='A '), 'A/C/omega' : Item(status='A '), 'A/C/E' : Item(status='A '), 'A/C/E/alpha' : Item(status='A '), 'A/C/E/beta' : Item(status='A '), 'A/D/H/chi' : Item(status='D '), 'A/D/H/psi' : Item(status='D '), 'A/D/H/omega' : Item(status='D '), 'A/B/E' : Item(status='D '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.remove('A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/E') expected_disk.add({ 'A/C/chi' : Item(contents="This is the file 'chi'.\n"), 'A/C/psi' : Item(contents="This is the file 'psi'.\n"), 'A/C/omega' : Item(contents="This is the file 'omega'.\n"), 'A/C/E' : Item(), 'A/C/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 'A/C/E/beta' : Item(contents="This is the file 'beta'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.remove('A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/E') expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=2), 'A/C/psi' : Item(status=' ', wc_rev=2), 'A/C/omega' : Item(status=' ', wc_rev=2), 'A/C/E' : Item(status=' ', wc_rev=2), 'A/C/E/alpha' : Item(status=' ', wc_rev=2), 'A/C/E/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Test copying multiple files within a repo. def copy_multiple_repo(sbox): "copy multiple files within a repo" sbox.build() wc_dir = sbox.wc_dir chi_url = sbox.repo_url + '/A/D/H/chi' psi_url = sbox.repo_url + '/A/D/H/psi' omega_url = sbox.repo_url + '/A/D/H/omega' E_url = sbox.repo_url + '/A/B/E' C_url = sbox.repo_url + '/A/C' # Copy three files and a directory in the repo to a different location # in the repo svntest.actions.run_and_verify_svn(None, None, [], 'cp', chi_url, psi_url, omega_url, E_url, C_url, '-m', 'logmsg') # Update to HEAD, and check to see if the files really moved in the repo expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(status='A '), 'A/C/psi' : Item(status='A '), 'A/C/omega' : Item(status='A '), 'A/C/E' : Item(status='A '), 'A/C/E/alpha' : Item(status='A '), 'A/C/E/beta' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/C/chi' : Item(contents="This is the file 'chi'.\n"), 'A/C/psi' : Item(contents="This is the file 'psi'.\n"), 'A/C/omega' : Item(contents="This is the file 'omega'.\n"), 'A/C/E' : Item(), 'A/C/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 'A/C/E/beta' : Item(contents="This is the file 'beta'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=2), 'A/C/psi' : Item(status=' ', wc_rev=2), 'A/C/omega' : Item(status=' ', wc_rev=2), 'A/C/E' : Item(status=' ', wc_rev=2), 'A/C/E/alpha' : Item(status=' ', wc_rev=2), 'A/C/E/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Test moving copying multiple files from a repo to a wc @Issue(2955) def copy_multiple_repo_wc(sbox): "copy multiple files from a repo to a wc" sbox.build() wc_dir = sbox.wc_dir chi_url = sbox.repo_url + '/A/D/H/chi' psi_url = sbox.repo_url + '/A/D/H/psi' omega_with_space_url = sbox.repo_url + '/A/D/H/omega 2' E_url = sbox.repo_url + '/A/B/E' C_path = os.path.join(wc_dir, 'A', 'C') # We need this in order to check that we don't end up with URI-encoded # paths in the WC (issue #2955) svntest.actions.run_and_verify_svn(None, None, [], 'mv', '-m', 'log_msg', sbox.repo_url + '/A/D/H/omega', omega_with_space_url) # Perform the copy and check the output svntest.actions.run_and_verify_svn(None, None, [], 'cp', chi_url, psi_url, omega_with_space_url, E_url, C_path) # Commit the changes, and verify the content actually got copied expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(verb='Adding'), 'A/C/psi' : Item(verb='Adding'), 'A/C/omega 2' : Item(verb='Adding'), 'A/C/E' : Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=3), 'A/C/psi' : Item(status=' ', wc_rev=3), 'A/C/omega 2' : Item(status=' ', wc_rev=3), 'A/C/E' : Item(status=' ', wc_rev=3), 'A/C/E/alpha' : Item(status=' ', wc_rev=3), 'A/C/E/beta' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test moving copying multiple files from a wc to a repo def copy_multiple_wc_repo(sbox): "copy multiple files from a wc to a repo" sbox.build() wc_dir = sbox.wc_dir chi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'chi') psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') omega_path = os.path.join(wc_dir, 'A', 'D', 'H', 'omega') E_path = os.path.join(wc_dir, 'A', 'B', 'E') C_url = sbox.repo_url + '/A/C' # Perform the copy and check the output svntest.actions.run_and_verify_svn(None, None, [], 'cp', chi_path, psi_path, omega_path, E_path, C_url, '-m', 'logmsg') # Update to HEAD, and check to see if the files really got copied in the repo expected_output = svntest.wc.State(wc_dir, { 'A/C/chi' : Item(status='A '), 'A/C/psi' : Item(status='A '), 'A/C/omega' : Item(status='A '), 'A/C/E' : Item(status='A '), 'A/C/E/alpha' : Item(status='A '), 'A/C/E/beta' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/C/chi': Item(contents="This is the file 'chi'.\n"), 'A/C/psi': Item(contents="This is the file 'psi'.\n"), 'A/C/omega': Item(contents="This is the file 'omega'.\n"), 'A/C/E' : Item(), 'A/C/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 'A/C/E/beta' : Item(contents="This is the file 'beta'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/C/chi' : Item(status=' ', wc_rev=2), 'A/C/psi' : Item(status=' ', wc_rev=2), 'A/C/omega' : Item(status=' ', wc_rev=2), 'A/C/E' : Item(status=' ', wc_rev=2), 'A/C/E/alpha' : Item(status=' ', wc_rev=2), 'A/C/E/beta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Test copying local files using peg revision syntax # (Issue 2546) @Issue(2546) def copy_peg_rev_local_files(sbox): "copy local files using peg rev syntax" sbox.build() wc_dir = sbox.wc_dir psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') new_iota_path = os.path.join(wc_dir, 'new_iota') iota_path = os.path.join(wc_dir, 'iota') sigma_path = os.path.join(wc_dir, 'sigma') psi_text = "This is the file 'psi'.\n" iota_text = "This is the file 'iota'.\n" # Play a shell game with some WC files, then commit the changes back # to the repository (making r2). svntest.actions.run_and_verify_svn(None, None, [], 'mv', psi_path, new_iota_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, psi_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', new_iota_path, iota_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 2', wc_dir) # Copy using a peg rev (remember, the object at iota_path at HEAD # was at psi_path back at r1). svntest.actions.run_and_verify_svn(None, None, [], 'cp', iota_path + '@HEAD', '-r', '1', sigma_path) # Commit and verify disk contents svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'rev 3') expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('A/D/H/psi', contents=iota_text) expected_disk.add({ 'iota' : Item(contents=psi_text), 'A/D/H/psi' : Item(contents=iota_text), 'sigma' : Item(contents=psi_text, props={}), }) actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 3) svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree()) #---------------------------------------------------------------------- # Test copying local directories using peg revision syntax # (Issue 2546) @Issue(2546) def copy_peg_rev_local_dirs(sbox): "copy local dirs using peg rev syntax" sbox.build() wc_dir = sbox.wc_dir E_path = os.path.join(wc_dir, 'A', 'B', 'E') G_path = os.path.join(wc_dir, 'A', 'D', 'G') I_path = os.path.join(wc_dir, 'A', 'D', 'I') J_path = os.path.join(wc_dir, 'A', 'J') alpha_path = os.path.join(E_path, 'alpha') # Make some changes to the repository svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 2', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'mv', E_path, I_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 3', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'mv', G_path, E_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 4', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'mv', I_path, G_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 5', wc_dir) # Copy using a peg rev svntest.actions.run_and_verify_svn(None, None, [], 'cp', G_path + '@HEAD', '-r', '1', J_path) # Commit and verify disk contents svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'rev 6') expected_disk = svntest.main.greek_state.copy() expected_disk.remove('A/B/E/beta') expected_disk.remove('A/B/E/alpha') expected_disk.remove('A/D/G/pi') expected_disk.remove('A/D/G/rho') expected_disk.remove('A/D/G/tau') expected_disk.add({ 'A/B/E' : Item(), 'A/B/E/pi' : Item(contents="This is the file 'pi'.\n"), 'A/B/E/rho' : Item(contents="This is the file 'rho'.\n"), 'A/B/E/tau' : Item(contents="This is the file 'tau'.\n"), 'A/D/G' : Item(), 'A/D/G/beta' : Item(contents="This is the file 'beta'.\n"), 'A/J' : Item(), 'A/J/alpha' : Item(contents="This is the file 'alpha'.\n"), 'A/J/beta' : Item(contents="This is the file 'beta'.\n"), }) actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 5) svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree()) #---------------------------------------------------------------------- # Test copying urls using peg revision syntax # (Issue 2546) @Issues(2546,3651) def copy_peg_rev_url(sbox): "copy urls using peg rev syntax" sbox.build() wc_dir = sbox.wc_dir psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') new_iota_path = os.path.join(wc_dir, 'new_iota') iota_path = os.path.join(wc_dir, 'iota') iota_url = sbox.repo_url + '/iota' sigma_url = sbox.repo_url + '/sigma' psi_text = "This is the file 'psi'.\n" iota_text = "This is the file 'iota'.\n" # Make some changes to the repository svntest.actions.run_and_verify_svn(None, None, [], 'mv', psi_path, new_iota_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, psi_path) svntest.actions.run_and_verify_svn(None, None, [], 'mv', new_iota_path, iota_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', 'rev 2', wc_dir) # Copy using a peg rev # Add peg rev '@HEAD' to sigma_url when copying which tests for issue #3651. svntest.actions.run_and_verify_svn(None, None, [], 'cp', iota_url + '@HEAD', '-r', '1', sigma_url + '@HEAD', '-m', 'rev 3') # Validate the copy destination's mergeinfo (we expect none). svntest.actions.run_and_verify_svn(None, [], [], 'propget', SVN_PROP_MERGEINFO, sigma_url) # Update to HEAD and verify disk contents expected_output = svntest.wc.State(wc_dir, { 'sigma' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('iota', contents=psi_text) expected_disk.tweak('A/D/H/psi', contents=iota_text) expected_disk.add({ 'sigma' : Item(contents=psi_text), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 3) expected_status.add({ 'sigma' : Item(status=' ', wc_rev=3) }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Test copying an older revision of a wc directory in the wc. def old_dir_wc_to_wc(sbox): "copy old revision of wc dir to new dir" sbox.build() wc_dir = sbox.wc_dir E = os.path.join(wc_dir, 'A', 'B', 'E') E2 = os.path.join(wc_dir, 'E2') E_url = sbox.repo_url + '/A/B/E' alpha_url = E_url + '/alpha' # delete E/alpha in r2 svntest.actions.run_and_verify_svn(None, None, [], 'rm', '-m', '', alpha_url) # delete E in r3 svntest.actions.run_and_verify_svn(None, None, [], 'rm', '-m', '', E_url) # Copy an old revision of E into a new path in the WC svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-r1', E, E2) # Create expected output tree. expected_output = svntest.wc.State(wc_dir, { 'E2' : Item(verb='Adding'), }) # Created expected status tree. expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'E2' : Item(status=' ', wc_rev=4), 'E2/alpha' : Item(status=' ', wc_rev=4), 'E2/beta' : Item(status=' ', wc_rev=4), }) # Commit the one file. svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test copying and creating parents in the wc def copy_make_parents_wc_wc(sbox): "svn cp --parents WC_PATH WC_PATH" sbox.build() wc_dir = sbox.wc_dir iota_path = os.path.join(wc_dir, 'iota') new_iota_path = os.path.join(wc_dir, 'X', 'Y', 'Z', 'iota') # Copy iota svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', iota_path, new_iota_path) # Create expected output expected_output = svntest.wc.State(wc_dir, { 'X' : Item(verb='Adding'), 'X/Y' : Item(verb='Adding'), 'X/Y/Z' : Item(verb='Adding'), 'X/Y/Z/iota' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) # Add the moved files expected_status.add({ 'X' : Item(status=' ', wc_rev=2), 'X/Y' : Item(status=' ', wc_rev=2), 'X/Y/Z' : Item(status=' ', wc_rev=2), 'X/Y/Z/iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test copying and creating parents from the repo to the wc def copy_make_parents_repo_wc(sbox): "svn cp --parents URL WC_PATH" sbox.build() wc_dir = sbox.wc_dir iota_url = sbox.repo_url + '/iota' new_iota_path = os.path.join(wc_dir, 'X', 'Y', 'Z', 'iota') # Copy iota svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', iota_url, new_iota_path) # Create expected output expected_output = svntest.wc.State(wc_dir, { 'X' : Item(verb='Adding'), 'X/Y' : Item(verb='Adding'), 'X/Y/Z' : Item(verb='Adding'), 'X/Y/Z/iota' : Item(verb='Adding'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) # Add the moved files expected_status.add({ 'X' : Item(status=' ', wc_rev=2), 'X/Y' : Item(status=' ', wc_rev=2), 'X/Y/Z' : Item(status=' ', wc_rev=2), 'X/Y/Z/iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) #---------------------------------------------------------------------- # Test copying and creating parents from the wc to the repo def copy_make_parents_wc_repo(sbox): "svn cp --parents WC_PATH URL" sbox.build() wc_dir = sbox.wc_dir iota_path = os.path.join(wc_dir, 'iota') new_iota_url = sbox.repo_url + '/X/Y/Z/iota' # Copy iota svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', '-m', 'log msg', iota_path, new_iota_url) # Update to HEAD and verify disk contents expected_output = svntest.wc.State(wc_dir, { 'X' : Item(status='A '), 'X/Y' : Item(status='A '), 'X/Y/Z' : Item(status='A '), 'X/Y/Z/iota' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'X' : Item(), 'X/Y' : Item(), 'X/Y/Z' : Item(), 'X/Y/Z/iota' : Item(contents="This is the file 'iota'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'X' : Item(status=' ', wc_rev=2), 'X/Y' : Item(status=' ', wc_rev=2), 'X/Y/Z' : Item(status=' ', wc_rev=2), 'X/Y/Z/iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) #---------------------------------------------------------------------- # Test copying and creating parents from repo to repo def copy_make_parents_repo_repo(sbox): "svn cp --parents URL URL" sbox.build() wc_dir = sbox.wc_dir iota_url = sbox.repo_url + '/iota' new_iota_url = sbox.repo_url + '/X/Y/Z/iota' # Copy iota svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', '-m', 'log msg', iota_url, new_iota_url) # Update to HEAD and verify disk contents expected_output = svntest.wc.State(wc_dir, { 'X' : Item(status='A '), 'X/Y' : Item(status='A '), 'X/Y/Z' : Item(status='A '), 'X/Y/Z/iota' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'X' : Item(), 'X/Y' : Item(), 'X/Y/Z' : Item(), 'X/Y/Z/iota' : Item(contents="This is the file 'iota'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'X' : Item(status=' ', wc_rev=2), 'X/Y' : Item(status=' ', wc_rev=2), 'X/Y/Z' : Item(status=' ', wc_rev=2), 'X/Y/Z/iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Test for issue #2894 # Can't perform URL to WC copy if URL needs URI encoding. @Issue(2894) def URI_encoded_repos_to_wc(sbox): "copy a URL that needs URI encoding to WC" sbox.build() wc_dir = sbox.wc_dir expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_disk = svntest.main.greek_state.copy() def copy_URL_to_WC(URL_rel_path, dest_name, rev): lines = [ "A " + os.path.join(wc_dir, dest_name, "B") + "\n", "A " + os.path.join(wc_dir, dest_name, "B", "lambda") + "\n", "A " + os.path.join(wc_dir, dest_name, "B", "E") + "\n", "A " + os.path.join(wc_dir, dest_name, "B", "E", "alpha") + "\n", "A " + os.path.join(wc_dir, dest_name, "B", "E", "beta") + "\n", "A " + os.path.join(wc_dir, dest_name, "B", "F") + "\n", "A " + os.path.join(wc_dir, dest_name, "mu") + "\n", "A " + os.path.join(wc_dir, dest_name, "C") + "\n", "A " + os.path.join(wc_dir, dest_name, "D") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "gamma") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "G") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "G", "pi") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "G", "rho") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "G", "tau") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "H") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "H", "chi") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "H", "omega") + "\n", "A " + os.path.join(wc_dir, dest_name, "D", "H", "psi") + "\n", "Checked out revision " + str(rev - 1) + ".\n", "A " + os.path.join(wc_dir, dest_name) + "\n"] expected = svntest.verify.UnorderedOutput(lines) expected_status.add({ dest_name + "/B" : Item(status=' ', wc_rev=rev), dest_name + "/B/lambda" : Item(status=' ', wc_rev=rev), dest_name + "/B/E" : Item(status=' ', wc_rev=rev), dest_name + "/B/E/alpha" : Item(status=' ', wc_rev=rev), dest_name + "/B/E/beta" : Item(status=' ', wc_rev=rev), dest_name + "/B/F" : Item(status=' ', wc_rev=rev), dest_name + "/mu" : Item(status=' ', wc_rev=rev), dest_name + "/C" : Item(status=' ', wc_rev=rev), dest_name + "/D" : Item(status=' ', wc_rev=rev), dest_name + "/D/gamma" : Item(status=' ', wc_rev=rev), dest_name + "/D/G" : Item(status=' ', wc_rev=rev), dest_name + "/D/G/pi" : Item(status=' ', wc_rev=rev), dest_name + "/D/G/rho" : Item(status=' ', wc_rev=rev), dest_name + "/D/G/tau" : Item(status=' ', wc_rev=rev), dest_name + "/D/H" : Item(status=' ', wc_rev=rev), dest_name + "/D/H/chi" : Item(status=' ', wc_rev=rev), dest_name + "/D/H/omega" : Item(status=' ', wc_rev=rev), dest_name + "/D/H/psi" : Item(status=' ', wc_rev=rev), dest_name : Item(status=' ', wc_rev=rev)}) expected_disk.add({ dest_name : Item(props={}), dest_name + '/B' : Item(), dest_name + '/B/lambda' : Item("This is the file 'lambda'.\n"), dest_name + '/B/E' : Item(), dest_name + '/B/E/alpha' : Item("This is the file 'alpha'.\n"), dest_name + '/B/E/beta' : Item("This is the file 'beta'.\n"), dest_name + '/B/F' : Item(), dest_name + '/mu' : Item("This is the file 'mu'.\n"), dest_name + '/C' : Item(), dest_name + '/D' : Item(), dest_name + '/D/gamma' : Item("This is the file 'gamma'.\n"), dest_name + '/D/G' : Item(), dest_name + '/D/G/pi' : Item("This is the file 'pi'.\n"), dest_name + '/D/G/rho' : Item("This is the file 'rho'.\n"), dest_name + '/D/G/tau' : Item("This is the file 'tau'.\n"), dest_name + '/D/H' : Item(), dest_name + '/D/H/chi' : Item("This is the file 'chi'.\n"), dest_name + '/D/H/omega' : Item("This is the file 'omega'.\n"), dest_name + '/D/H/psi' : Item("This is the file 'psi'.\n"), }) # Make a copy svntest.actions.run_and_verify_svn(None, expected, [], 'copy', sbox.repo_url + '/' + URL_rel_path, os.path.join(wc_dir, dest_name)) expected_output = svntest.wc.State(wc_dir, {dest_name : Item(verb='Adding')}) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) copy_URL_to_WC('A', 'A COPY', 2) copy_URL_to_WC('A COPY', 'A_COPY_2', 3) #---------------------------------------------------------------------- # Issue #3068: copy source parent may be unversioned @Issue(3068) def allow_unversioned_parent_for_copy_src(sbox): "copy wc in unversioned parent to other wc" sbox.build(read_only = True) wc_dir = sbox.wc_dir # Make the "other" working copy wc2_dir = sbox.add_wc_path('other') svntest.actions.duplicate_dir(wc_dir, wc2_dir) copy_to_path = os.path.join(wc_dir, 'A', 'copy_of_wc2') # Copy the wc-in-unversioned-parent working copy to our original wc. svntest.actions.run_and_verify_svn(None, None, [], 'cp', wc2_dir, copy_to_path) def unneeded_parents(sbox): "svn cp --parents FILE_URL DIR_URL" # In this message... # # http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=138738 # From: Alexander Kitaev # To: dev@subversion.tigris.org # Subject: 1.5.x segmentation fault on Repos to Repos copy # Message-ID: <4830332A.6060301@svnkit.com> # Date: Sun, 18 May 2008 15:46:18 +0200 # # ...Alexander Kitaev describes the bug: # # svn cp --parents SRC_FILE_URL DST_DIR_URL -m "message" # # SRC_FILE_URL - existing file # DST_DIR_URL - existing directory # # Omitting "--parents" option makes above copy operation work as # expected. # # Bug is in libsvn_client/copy.c:801, where "dir" should be # checked for null before using it in svn_ra_check_path call. # # At first we couldn't reproduce it, but later he added this: # # Looks like there is one more condition to reproduce the problem - # dst URL should has no more segments count than source one. # # In other words, if we had "/A/B" below instead of "/A" (adjusting # expected_* accordingly, of course), the bug wouldn't reproduce. sbox.build() wc_dir = sbox.wc_dir iota_url = sbox.repo_url + '/iota' A_url = sbox.repo_url + '/A' # The --parents is unnecessary, but should still work (not segfault). svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', '-m', 'log msg', iota_url, A_url) # Verify that it worked. expected_output = svntest.wc.State(wc_dir, { 'A/iota' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/iota' : Item(contents="This is the file 'iota'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update( wc_dir, expected_output, expected_disk, expected_status) def double_parents_with_url(sbox): "svn cp --parents URL/src_dir URL/dst_dir" sbox.build() wc_dir = sbox.wc_dir E_url = sbox.repo_url + '/A/B/E' Z_url = sbox.repo_url + '/A/B/Z' # --parents shouldn't result in a double commit of the same directory. svntest.actions.run_and_verify_svn(None, None, [], 'cp', '--parents', '-m', 'log msg', E_url, Z_url) # Verify that it worked. expected_output = svntest.wc.State(wc_dir, { 'A/B/Z/alpha' : Item(status='A '), 'A/B/Z/beta' : Item(status='A '), 'A/B/Z' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/B/Z/alpha' : Item(contents="This is the file 'alpha'.\n"), 'A/B/Z/beta' : Item(contents="This is the file 'beta'.\n"), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/B/Z/alpha' : Item(status=' ', wc_rev=2), 'A/B/Z/beta' : Item(status=' ', wc_rev=2), 'A/B/Z' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update( wc_dir, expected_output, expected_disk, expected_status) # Used to cause corruption not fixable by 'svn cleanup'. def copy_into_absent_dir(sbox): "copy file into absent dir" sbox.build(read_only = True) wc_dir = sbox.wc_dir A_path = os.path.join(wc_dir, 'A') iota_path = os.path.join(wc_dir, 'iota') # Remove 'A' svntest.main.safe_rmtree(A_path) # Copy into the now-missing dir. This used to give this error: # svn: In directory '.' # svn: Error processing command 'modify-entry' in '.' # svn: Error modifying entry for 'A' # svn: Entry 'A' is already under version control svntest.actions.run_and_verify_svn(None, None, ".*: Path '.*' is not a directory", 'cp', iota_path, A_path) # 'cleanup' should not error. svntest.actions.run_and_verify_svn(None, None, [], 'cleanup', wc_dir) def find_copyfrom_information_upstairs(sbox): "renaming inside a copied subtree shouldn't hang" # The final command in this series would cause the client to hang... # # ${SVN} cp A A2 # cd A2/B # ${SVN} mkdir blah # ${SVN} mv lambda blah # # ...because it wouldn't walk up past "" to find copyfrom information # (which would be in A2/.svn/entries, not on A2/B/.svn/entries). # Instead, it would keep thinking the parent of "" is "", and so # loop forever, gobbling a little bit more memory with each iteration. # # Two things fixed this: # # 1) The client walks upward beyond CWD now, so it finds the # copyfrom information. # # 2) Even if we do top out at "" without finding copyfrom information # (say, because someone has corrupted their working copy), we'll # still detect it and error, thus breaking the loop. # # This only tests case (1). We could test that (2) gets the expected # error ("no parent with copyfrom information found above 'lambda'"), # but we'd need to chroot to the top of the working copy or manually # corrupt the wc by removing the copyfrom lines from A2/.svn/entries. sbox.build() wc_dir = sbox.wc_dir A_path = os.path.join(wc_dir, 'A') A2_path = os.path.join(wc_dir, 'A2') B2_path = os.path.join(A2_path, 'B') svntest.actions.run_and_verify_svn(None, None, [], 'cp', A_path, A2_path) saved_cwd = os.getcwd() try: os.chdir(B2_path) svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', 'blah') svntest.actions.run_and_verify_svn(None, None, [], 'mv', 'lambda', 'blah') finally: os.chdir(saved_cwd) #---------------------------------------------------------------------- def change_case_of_hostname(input): "Change the case of the hostname, try uppercase first" m = re.match(r"^(.*://)([^/]*)(.*)", input) if m: scheme = m.group(1) host = m.group(2).upper() if host == m.group(2): host = m.group(2).lower() path = m.group(3) return scheme + host + path # regression test for issue #2475 - move file and folder @Issue(2475) def path_move_and_copy_between_wcs_2475(sbox): "issue #2475 - move and copy between working copies" sbox.build() # checkout a second working copy, use repository url with different case wc2_dir = sbox.add_wc_path('2') repo_url2 = change_case_of_hostname(sbox.repo_url) expected_output = svntest.main.greek_state.copy() expected_output.wc_dir = wc2_dir expected_output.tweak(status='A ', contents=None) expected_wc = svntest.main.greek_state # Do a checkout, and verify the resulting output and disk contents. svntest.actions.run_and_verify_checkout(repo_url2, wc2_dir, expected_output, expected_wc) # Copy a file from wc to wc2 mu_path = os.path.join(sbox.wc_dir, 'A', 'mu') E_path = os.path.join(wc2_dir, 'A', 'B', 'E') svntest.main.run_svn(None, 'cp', mu_path, E_path) # Copy a folder from wc to wc2 C_path = os.path.join(sbox.wc_dir, 'A', 'C') B_path = os.path.join(wc2_dir, 'A', 'B') svntest.main.run_svn(None, 'cp', C_path, B_path) # Move a file from wc to wc2 mu_path = os.path.join(sbox.wc_dir, 'A', 'mu') B_path = os.path.join(wc2_dir, 'A', 'B') svntest.main.run_svn(None, 'mv', mu_path, B_path) # Move a folder from wc to wc2 C_path = os.path.join(sbox.wc_dir, 'A', 'C') D_path = os.path.join(wc2_dir, 'A', 'D') svntest.main.run_svn(None, 'mv', C_path, D_path) # Verify modified status expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.tweak('A/mu', 'A/C', status='D ') svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) expected_status2 = svntest.actions.get_virginal_state(wc2_dir, 1) expected_status2.add({ 'A/B/mu' : Item(status='A ', copied='+', wc_rev='-') }) expected_status2.add({ 'A/B/C' : Item(status='A ', copied='+', wc_rev='-') }) expected_status2.add({ 'A/B/E/mu' : Item(status='A ', copied='+', wc_rev='-') }) expected_status2.add({ 'A/D/C' : Item(status='A ', copied='+', wc_rev='-') }) svntest.actions.run_and_verify_status(wc2_dir, expected_status2) # regression test for issue #2475 - direct copy in the repository # this test handles the 'direct move' case too, that uses the same code. @Issue(2475) def path_copy_in_repo_2475(sbox): "issue #2475 - direct copy in the repository" sbox.build() repo_url2 = change_case_of_hostname(sbox.repo_url) # Copy a file from repo to repo2 mu_url = sbox.repo_url + '/A/mu' E_url = repo_url2 + '/A/B/E' svntest.main.run_svn(None, 'cp', mu_url, E_url, '-m', 'copy mu to /A/B/E') # For completeness' sake, update to HEAD, and verify we have a full # greek tree again, all at revision 2. expected_output = svntest.wc.State(sbox.wc_dir, { 'A/B/E/mu' : Item(status='A '), }) expected_disk = svntest.main.greek_state.copy() expected_disk.add({'A/B/E/mu' : Item("This is the file 'mu'.\n") }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2) expected_status.add({'A/B/E/mu' : Item(status=' ', wc_rev=2) }) svntest.actions.run_and_verify_update(sbox.wc_dir, expected_output, expected_disk, expected_status) def commit_copy_depth_empty(sbox): "copy a wcdir, then commit it with --depth empty" sbox.build() a = os.path.join(sbox.wc_dir, 'A') new_a = os.path.join(sbox.wc_dir, 'new_A') svntest.actions.run_and_verify_svn(None, None, [], 'cp', a, new_a) svntest.actions.run_and_verify_svn(None, None, [], 'ci', new_a, '--depth', 'empty', '-m', 'Copied directory') def copy_below_copy(sbox): "copy a dir below a copied dir" sbox.build() A = os.path.join(sbox.wc_dir, 'A') new_A = os.path.join(sbox.wc_dir, 'new_A') new_A_D = os.path.join(new_A, 'D') new_A_new_D = os.path.join(new_A, 'new_D') new_A_mu = os.path.join(new_A, 'mu') new_A_new_mu = os.path.join(new_A, 'new_mu') svntest.actions.run_and_verify_svn(None, None, [], 'cp', A, new_A) svntest.actions.run_and_verify_svn(None, None, [], 'cp', new_A_D, new_A_new_D) svntest.actions.run_and_verify_svn(None, None, [], 'cp', new_A_mu, new_A_new_mu) expected_output = svntest.wc.State(sbox.wc_dir, { 'new_A' : Item(verb='Adding'), 'new_A/new_D' : Item(verb='Adding'), 'new_A/new_mu' : Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.add({ 'new_A' : Item(status=' ', wc_rev='2'), 'new_A/new_D' : Item(status=' ', wc_rev='2'), 'new_A/new_D/gamma' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/pi' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/rho' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/tau' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H/chi' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H/omega': Item(status=' ', wc_rev='2'), 'new_A/new_D/H/psi' : Item(status=' ', wc_rev='2'), 'new_A/D' : Item(status=' ', wc_rev='2'), 'new_A/D/H' : Item(status=' ', wc_rev='2'), 'new_A/D/H/chi' : Item(status=' ', wc_rev='2'), 'new_A/D/H/omega' : Item(status=' ', wc_rev='2'), 'new_A/D/H/psi' : Item(status=' ', wc_rev='2'), 'new_A/D/G' : Item(status=' ', wc_rev='2'), 'new_A/D/G/rho' : Item(status=' ', wc_rev='2'), 'new_A/D/G/pi' : Item(status=' ', wc_rev='2'), 'new_A/D/G/tau' : Item(status=' ', wc_rev='2'), 'new_A/D/gamma' : Item(status=' ', wc_rev='2'), 'new_A/new_mu' : Item(status=' ', wc_rev='2'), 'new_A/B' : Item(status=' ', wc_rev='2'), 'new_A/B/E' : Item(status=' ', wc_rev='2'), 'new_A/B/E/alpha' : Item(status=' ', wc_rev='2'), 'new_A/B/E/beta' : Item(status=' ', wc_rev='2'), 'new_A/B/F' : Item(status=' ', wc_rev='2'), 'new_A/B/lambda' : Item(status=' ', wc_rev='2'), 'new_A/C' : Item(status=' ', wc_rev='2'), 'new_A/mu' : Item(status=' ', wc_rev='2'), }) svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output, expected_status, None, sbox.wc_dir) def move_below_move(sbox): "move a dir below a moved dir" sbox.build() A = os.path.join(sbox.wc_dir, 'A') new_A = os.path.join(sbox.wc_dir, 'new_A') new_A_D = os.path.join(new_A, 'D') new_A_new_D = os.path.join(new_A, 'new_D') new_A_mu = os.path.join(new_A, 'mu') new_A_new_mu = os.path.join(new_A, 'new_mu') svntest.actions.run_and_verify_svn(None, None, [], 'mv', A, new_A) svntest.actions.run_and_verify_svn(None, None, [], 'mv', new_A_D, new_A_new_D) svntest.actions.run_and_verify_svn(None, None, [], 'mv', new_A_mu, new_A_new_mu) expected_output = svntest.wc.State(sbox.wc_dir, { 'A' : Item(verb='Deleting'), 'new_A/D' : Item(verb='Deleting'), 'new_A/mu' : Item(verb='Deleting'), 'new_A' : Item(verb='Adding'), 'new_A/new_D' : Item(verb='Adding'), 'new_A/new_mu' : Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.add({ 'new_A' : Item(status=' ', wc_rev='2'), 'new_A/new_D' : Item(status=' ', wc_rev='2'), 'new_A/new_D/gamma' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/pi' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/rho' : Item(status=' ', wc_rev='2'), 'new_A/new_D/G/tau' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H/chi' : Item(status=' ', wc_rev='2'), 'new_A/new_D/H/omega': Item(status=' ', wc_rev='2'), 'new_A/new_D/H/psi' : Item(status=' ', wc_rev='2'), 'new_A/new_mu' : Item(status=' ', wc_rev='2'), 'new_A/B' : Item(status=' ', wc_rev='2'), 'new_A/B/E' : Item(status=' ', wc_rev='2'), 'new_A/B/E/alpha' : Item(status=' ', wc_rev='2'), 'new_A/B/E/beta' : Item(status=' ', wc_rev='2'), 'new_A/B/F' : Item(status=' ', wc_rev='2'), 'new_A/B/lambda' : Item(status=' ', wc_rev='2'), 'new_A/C' : Item(status=' ', wc_rev='2'), }) expected_status.remove('A', 'A/D', 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/B/lambda', 'A/C', 'A/mu') svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output, expected_status, None, sbox.wc_dir) def reverse_merge_move(sbox): """reverse merge move""" # Alias for svntest.actions.run_and_verify_svn rav_svn = svntest.actions.run_and_verify_svn wc_dir = sbox.wc_dir a_dir = os.path.join(wc_dir, 'A') a_repo_url = sbox.repo_url + '/A' sbox.build() # Create another working copy path and checkout. wc2_dir = sbox.add_wc_path('2') rav_svn(None, None, [], 'co', sbox.repo_url, wc2_dir) # Update working directory and ensure that we are at revision 1. rav_svn(None, exp_noop_up_out(1), [], 'up', wc_dir) # Add new folder and file, later commit new_path = os.path.join(a_dir, 'New') os.mkdir(new_path) first_path = os.path.join(new_path, 'first') svntest.main.file_append(first_path, 'appended first text') svntest.main.run_svn(None, "add", new_path) rav_svn(None, None, [], 'ci', wc_dir, '-m', 'Add new folder %s' % new_path) rav_svn(None, exp_noop_up_out(2), [], 'up', wc_dir) # Reverse merge to revert previous changes and commit rav_svn(None, None, [], 'merge', '-c', '-2', a_repo_url, a_dir) rav_svn(None, None, [], 'ci', '-m', 'Reverting svn merge -c -2.', a_dir) rav_svn(None, exp_noop_up_out(3), [], 'up', wc_dir) # Reverse merge again to undo last revert. rav_svn(None, None, [], 'merge', '-c', '-3', a_repo_url, a_dir) # Move new added file to another one and commit. second_path = os.path.join(new_path, 'second') rav_svn(None, None, [], 'move', first_path, second_path) rav_svn(None, "Adding.*New|Adding.*first||Committed revision 4.", [], 'ci', '-m', 'Revert svn merge. svn mv %s %s.' % (first_path, second_path), a_dir) # Update second working copy. There was a bug (at least on the 1.6.x # branch) in which this update received both "first" and "second". expected_output = svntest.wc.State(wc2_dir, { 'A/New' : Item(status='A '), 'A/New/second' : Item(status='A '), }) svntest.actions.run_and_verify_update(wc2_dir, expected_output, None, None) @Issue(3699) def nonrecursive_commit_of_copy(sbox): """commit only top of copy; check child behavior""" sbox.build() wc_dir = sbox.wc_dir main.run_svn(None, 'cp', os.path.join(wc_dir, 'A'), os.path.join(wc_dir, 'A_new')) main.run_svn(None, 'cp', os.path.join(wc_dir, 'A/D/G'), os.path.join(wc_dir, 'A_new/G_new')) main.run_svn(None, 'rm', os.path.join(wc_dir, 'A_new/C')) main.run_svn(None, 'rm', os.path.join(wc_dir, 'A_new/B/E')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A_new' : Item(status='A ', copied='+', wc_rev='-'), 'A_new/D' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/G' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/H' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/H/psi' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/H/chi' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/H/omega' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/D/gamma' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/B' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/B/lambda' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/B/E' : Item(status='D ', copied='+', wc_rev='-'), 'A_new/B/E/alpha' : Item(status='D ', copied='+', wc_rev='-'), 'A_new/B/E/beta' : Item(status='D ', copied='+', wc_rev='-'), 'A_new/B/F' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/mu' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/C' : Item(status='D ', copied='+', wc_rev='-'), 'A_new/G_new' : Item(status='A ', copied='+', wc_rev='-'), 'A_new/G_new/pi' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/G_new/rho' : Item(status=' ', copied='+', wc_rev='-'), 'A_new/G_new/tau' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_output = svntest.wc.State(wc_dir, { 'A_new': Item(verb='Adding'), }) # These nodes are added by the commit expected_status.tweak('A_new', 'A_new/D', 'A_new/D/G', 'A_new/D/G/pi', 'A_new/D/G/rho', 'A_new/D/G/tau', 'A_new/D/H', 'A_new/D/H/psi', 'A_new/D/H/chi', 'A_new/D/H/omega', 'A_new/D/gamma', 'A_new/B', 'A_new/B/lambda', 'A_new/B/F', 'A_new/mu', status=' ', copied=None, wc_rev='2') # And these are now normal deletes, because their parent was committed. expected_status.tweak('A_new/C', 'A_new/B/E', 'A_new/B/E/alpha', 'A_new/B/E/beta', copied=None, wc_rev='2') # 'A_new/G_new' and everything below should still be added # as their operation root was not committed svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir, '--depth', 'immediates') # Regression test for issue #3474 - making a new subdir, moving files into it # and then renaming the subdir, breaks history of the moved files. @Issue(3474) def copy_added_dir_with_copy(sbox): """copy of new dir with copied file keeps history""" sbox.build() wc_dir = sbox.wc_dir new_dir = os.path.join(wc_dir, 'NewDir'); new_dir2 = os.path.join(wc_dir, 'NewDir2'); # Alias for svntest.actions.run_and_verify_svn rav_svn = svntest.actions.run_and_verify_svn rav_svn(None, None, [], 'mkdir', new_dir) rav_svn(None, None, [], 'cp', os.path.join(wc_dir, 'A', 'mu'), new_dir) rav_svn(None, None, [], 'cp', new_dir, new_dir2) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add( { 'NewDir' : Item(status='A ', wc_rev='0'), 'NewDir/mu' : Item(status='A ', copied='+', wc_rev='-'), 'NewDir2' : Item(status='A ', wc_rev='0'), 'NewDir2/mu' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) @SkipUnless(svntest.main.is_posix_os) @Issue(3303) def copy_broken_symlink(sbox): """copy broken symlink""" ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3303. ## sbox.build() wc_dir = sbox.wc_dir new_symlink = os.path.join(wc_dir, 'new_symlink'); copied_symlink = os.path.join(wc_dir, 'copied_symlink'); os.symlink('linktarget', new_symlink) # Alias for svntest.actions.run_and_verify_svn rav_svn = svntest.actions.run_and_verify_svn rav_svn(None, None, [], 'add', new_symlink) rav_svn(None, None, [], 'cp', new_symlink, copied_symlink) # Check whether both new_symlink and copied_symlink are added to the # working copy expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add( { 'new_symlink' : Item(status='A ', wc_rev='0'), 'copied_symlink' : Item(status='A ', wc_rev='0'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) def move_dir_containing_move(sbox): """move a directory containing moved node""" sbox.build() svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('A/B/E/alpha'), sbox.ospath('A/B/E/alpha_moved')) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('A/B/F'), sbox.ospath('A/B/F_moved')) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('A/B'), sbox.ospath('A/B_tmp')) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.tweak('A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/B/lambda', status='D ') expected_status.add({ 'A/B_tmp' : Item(status='A ', copied='+', wc_rev='-'), # alpha has a revision that isn't reported by status. 'A/B_tmp/E' : Item(status=' ', copied='+', wc_rev='-'), 'A/B_tmp/E/alpha' : Item(status='D ', copied='+', wc_rev='-'), 'A/B_tmp/E/alpha_moved' : Item(status='A ', copied='+', wc_rev='-'), 'A/B_tmp/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 'A/B_tmp/F' : Item(status='D ', copied='+', wc_rev='-'), 'A/B_tmp/F_moved' : Item(status='A ', copied='+', wc_rev='-'), 'A/B_tmp/lambda' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('A/B_tmp'), sbox.ospath('A/B_moved')) expected_status.remove('A/B_tmp', 'A/B_tmp/E', 'A/B_tmp/E/alpha', 'A/B_tmp/E/alpha_moved', 'A/B_tmp/E/beta', 'A/B_tmp/F', 'A/B_tmp/F_moved', 'A/B_tmp/lambda') expected_status.add({ 'A/B_moved' : Item(status='A ', copied='+', wc_rev='-'), 'A/B_moved/E' : Item(status=' ', copied='+', wc_rev='-'), 'A/B_moved/E/alpha' : Item(status='D ', copied='+', wc_rev='-'), 'A/B_moved/E/alpha_moved' : Item(status='A ', copied='+', wc_rev='-'), 'A/B_moved/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 'A/B_moved/F' : Item(status='D ', copied='+', wc_rev='-'), 'A/B_moved/F_moved' : Item(status='A ', copied='+', wc_rev='-'), 'A/B_moved/lambda' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) expected_output = svntest.wc.State(sbox.wc_dir, { 'A/B' : Item(verb='Deleting'), 'A/B_moved' : Item(verb='Adding'), 'A/B_moved/E/alpha' : Item(verb='Deleting'), 'A/B_moved/E/alpha_moved': Item(verb='Adding'), 'A/B_moved/F' : Item(verb='Deleting'), 'A/B_moved/F_moved' : Item(verb='Adding'), }) expected_status.tweak('A/B_moved', 'A/B_moved/E', 'A/B_moved/E/alpha_moved', 'A/B_moved/E/beta', 'A/B_moved/F_moved', 'A/B_moved/lambda', status=' ', copied=None, wc_rev='2') expected_status.remove('A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/B/lambda', 'A/B_moved/E/alpha', 'A/B_moved/F') svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output, expected_status, None, sbox.wc_dir) def copy_dir_with_space(sbox): """copy a directory with whitespace to one without""" sbox.build() wc_dir = sbox.wc_dir svntest.actions.run_and_verify_svn(None, None, [], 'cp', os.path.join(wc_dir, 'A', 'B', 'E'), os.path.join(wc_dir, 'E with spaces')) svntest.actions.run_and_verify_svn(None, None, [], 'cp', os.path.join(wc_dir, 'A', 'B', 'E', 'alpha'), os.path.join(wc_dir, 'E with spaces', 'al pha')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_output = svntest.wc.State(wc_dir, { 'E with spaces' : Item(verb='Adding'), 'E with spaces/al pha' : Item(verb='Adding'), }) expected_status.add({ 'E with spaces' : Item(status=' ', wc_rev='2'), 'E with spaces/alpha' : Item(status=' ', wc_rev='2'), 'E with spaces/beta' : Item(status=' ', wc_rev='2'), 'E with spaces/al pha' : Item(status=' ', wc_rev='2'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'cp', os.path.join(wc_dir, 'E with spaces'), os.path.join(wc_dir, 'E also spaces') ) svntest.actions.run_and_verify_svn(None, None, [], 'cp', os.path.join(wc_dir, 'E with spaces/al pha'), os.path.join(wc_dir, 'E also spaces/al b') ) expected_output = svntest.wc.State(wc_dir, { 'E also spaces' : Item(verb='Adding'), 'E also spaces/al b': Item(verb='Adding'), }) expected_status.add({ 'E also spaces' : Item(status=' ', wc_rev='3'), 'E also spaces/beta': Item(status=' ', wc_rev='3'), 'E also spaces/al b': Item(status=' ', wc_rev='3'), 'E also spaces/alpha': Item(status=' ', wc_rev='3'), 'E also spaces/al pha': Item(status=' ', wc_rev='3'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'mv', os.path.join(wc_dir, 'E with spaces'), os.path.join(wc_dir, 'E new spaces') ) svntest.actions.run_and_verify_svn(None, None, [], 'mv', os.path.join(wc_dir, 'E new spaces/al pha'), os.path.join(wc_dir, 'E also spaces/al c') ) expected_output = svntest.wc.State(wc_dir, { 'E with spaces' : Item(verb='Deleting'), 'E also spaces/al c': Item(verb='Adding'), 'E new spaces' : Item(verb='Adding'), 'E new spaces/al pha': Item(verb='Deleting'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'E also spaces' : Item(status=' ', wc_rev='3'), 'E also spaces/beta': Item(status=' ', wc_rev='3'), 'E also spaces/al b': Item(status=' ', wc_rev='3'), 'E also spaces/al c': Item(status=' ', wc_rev='4'), 'E also spaces/alpha': Item(status=' ', wc_rev='3'), 'E also spaces/al pha': Item(status=' ', wc_rev='3'), 'E new spaces' : Item(status=' ', wc_rev='4'), 'E new spaces/alpha': Item(status=' ', wc_rev='4'), 'E new spaces/beta' : Item(status=' ', wc_rev='4'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Regression test for issue #3676 @Issue(3676) def changed_data_should_match_checkout(sbox): """changed data after commit should match checkout""" sbox.build() wc_dir = sbox.wc_dir A_B_E = os.path.join(wc_dir, 'A', 'B', 'E') E_new = os.path.join(wc_dir, 'E_new') verify_dir = sbox.add_wc_path('verify') svntest.actions.run_and_verify_svn(None, None, [], 'copy', A_B_E, E_new) sbox.simple_commit() svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'co', sbox.repo_url, verify_dir) was_cwd = os.getcwd() os.chdir(verify_dir) rv, verify_out, err = main.run_svn(None, 'status', '-v') os.chdir(was_cwd) os.chdir(wc_dir) verify_out = svntest.verify.UnorderedOutput(verify_out) svntest.actions.run_and_verify_svn(None, verify_out, [], 'status', '-v') os.chdir(was_cwd) # Regression test for issue #3676 for copies including directories @Issue(3676) def changed_dir_data_should_match_checkout(sbox): """changed dir after commit should match checkout""" sbox.build() wc_dir = sbox.wc_dir A_B = os.path.join(wc_dir, 'A', 'B') B_new = os.path.join(wc_dir, 'B_new') verify_dir = sbox.add_wc_path('verify') svntest.actions.run_and_verify_svn(None, None, [], 'copy', A_B, B_new) sbox.simple_commit() svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'co', sbox.repo_url, verify_dir) was_cwd = os.getcwd() os.chdir(verify_dir) rv, verify_out, err = main.run_svn(None, 'status', '-v') os.chdir(was_cwd) os.chdir(wc_dir) rv, verify_out2, err = main.run_svn (None, 'status', '-v') os.chdir(was_cwd) # The order of the status output is not absolutely defined, but # otherwise should match svntest.verify.verify_outputs(None, sorted(verify_out2), None, sorted(verify_out), None) def move_added_nodes(sbox): """move added nodes""" sbox.build() svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', sbox.ospath('X'), sbox.ospath('X/Y')) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.add({ 'X' : Item(status='A ', wc_rev='0'), 'X/Y' : Item(status='A ', wc_rev='0'), }) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('X/Y'), sbox.ospath('X/Z')) expected_status.remove('X/Y') expected_status.add({'X/Z' : Item(status='A ', wc_rev='0')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('X/Z'), sbox.ospath('Z')) expected_status.remove('X/Z') expected_status.add({'Z' : Item(status='A ', wc_rev='0')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'mv', sbox.ospath('Z'), sbox.ospath('X/Z')) expected_status.remove('Z') expected_status.add({'X/Z' : Item(status='A ', wc_rev='0')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) def copy_over_deleted_dir(sbox): "copy a directory over a deleted directory" sbox.build(read_only = True) main.run_svn(None, 'rm', os.path.join(sbox.wc_dir, 'A/B')) main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A/D'), os.path.join(sbox.wc_dir, 'A/B')) @Issue(3314) def mixed_rev_copy_del(sbox): """copy mixed-rev and delete children""" sbox.build() wc_dir = sbox.wc_dir # Delete and commit A/B/E/alpha svntest.main.run_svn(None, 'rm', sbox.ospath('A/B/E/alpha')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/B/E/alpha', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_output = svntest.wc.State(wc_dir, { 'A/B/E/alpha': Item(verb='Deleting'), }) expected_status.remove('A/B/E/alpha') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Update to r2, then update A/B/E/alpha and A/B/E/beta to r1 svntest.main.run_svn(None, 'up', wc_dir) expected_status.tweak(wc_rev=2) svntest.actions.run_and_verify_status(wc_dir, expected_status) svntest.main.run_svn(None, 'up', '-r1', sbox.ospath('A/B/E/alpha'), sbox.ospath('A/B/E/beta')) expected_status.add({ 'A/B/E/alpha' : Item(status=' ', wc_rev=1), }) expected_status.tweak('A/B/E/beta', wc_rev=1) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Copy A/B/E to A/B/E_copy svntest.actions.run_and_verify_svn(None, None, [], 'cp', sbox.ospath('A/B/E'), sbox.ospath('A/B/E_copy')) expected_status.add({ 'A/B/E_copy' : Item(status='A ', copied='+', wc_rev='-'), # In the entries world mixed revision copies have only a single op_root 'A/B/E_copy/alpha' : Item(status='A ', copied='+', wc_rev='-', entry_status=' '), 'A/B/E_copy/beta' : Item(status='A ', copied='+', wc_rev='-', entry_status=' '), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Delete A/B/E_copy/alpha and A/B/E_copy/beta svntest.main.run_svn(None, 'rm', '--force', sbox.ospath('A/B/E_copy/alpha'), sbox.ospath('A/B/E_copy/beta')) expected_status.tweak('A/B/E_copy/alpha', 'A/B/E_copy/beta', status='D ', entry_status=None) svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_output = svntest.wc.State(wc_dir, { 'A/B/E_copy' : Item(verb='Adding'), 'A/B/E_copy/beta' : Item(verb='Deleting'), }) expected_status.tweak('A/B/E_copy', wc_rev=3, copied=None, status=' ') expected_status.remove('A/B/E_copy/alpha', 'A/B/E_copy/beta') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) def copy_delete_undo(sbox, use_revert): "copy, delete child, undo" sbox.build() wc_dir = sbox.wc_dir # Copy directory with children svntest.main.run_svn(wc_dir, 'copy', sbox.ospath('A/B/E'), sbox.ospath('A/B/E-copied')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/E-copied' : Item(status='A ', copied='+', wc_rev='-'), 'A/B/E-copied/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'A/B/E-copied/beta' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Delete a child svntest.main.run_svn(wc_dir, 'rm', sbox.ospath('A/B/E-copied/alpha')) expected_status.tweak('A/B/E-copied/alpha', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # Undo the whole copy if (use_revert): svntest.main.run_svn(wc_dir, 'revert', '--recursive', sbox.ospath('A/B/E-copied')) svntest.main.safe_rmtree(os.path.join(wc_dir, 'A/B/E-copied')) else: svntest.main.run_svn(wc_dir, 'rm', '--force', sbox.ospath('A/B/E-copied')) expected_status.remove('A/B/E-copied', 'A/B/E-copied/alpha', 'A/B/E-copied/beta') # Undo via revert FAILs here because a wq item remains svntest.actions.run_and_verify_status(wc_dir, expected_status) # Copy a directory without children. svntest.main.run_svn(wc_dir, 'copy', sbox.ospath('A/B/F'), sbox.ospath('A/B/E-copied')) expected_status.add({ 'A/B/E-copied' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) def copy_delete_delete(sbox): "copy, delete child, delete copy" copy_delete_undo(sbox, False) @Issue(3784) def copy_delete_revert(sbox): "copy, delete child, revert copy" copy_delete_undo(sbox, True) # See also delete_replaced_file() which does the same for a file. def delete_replace_delete(sbox): "delete a directory scheduled for replacement" sbox.build() wc_dir = sbox.wc_dir # Delete directory with children svntest.main.run_svn(wc_dir, 'rm', sbox.ospath('A/B/E')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) # Replace with directory with different children svntest.main.run_svn(wc_dir, 'copy', sbox.ospath('A/D/G'), sbox.ospath('A/B/E')) expected_status.tweak('A/B/E', status='R ', copied='+', wc_rev='-') expected_status.add({ 'A/B/E/pi' : Item(status=' ', copied='+', wc_rev='-'), 'A/B/E/rho' : Item(status=' ', copied='+', wc_rev='-'), 'A/B/E/tau' : Item(status=' ', copied='+', wc_rev='-'), }) # A/B/E/alpha and A/B/E/beta show up as deleted, is that right? svntest.actions.run_and_verify_status(wc_dir, expected_status) # Delete replacement svntest.main.run_svn(wc_dir, 'rm', '--force', sbox.ospath('A/B/E')) expected_status.tweak('A/B/E', status='D ', copied=None, wc_rev='1') expected_status.remove('A/B/E/pi', 'A/B/E/rho', 'A/B/E/tau') svntest.actions.run_and_verify_status(wc_dir, expected_status) A_B_children = ['A/B/lambda', 'A/B/F', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/E'] A_D_children = ['A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega'] def copy_repos_over_deleted_same_kind(sbox): "copy repos node over deleted node, same kind" sbox.build(read_only = True) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) # Set up some deleted paths sbox.simple_rm('iota', 'A/B') for path in ['iota', 'A/B'] + A_B_children: expected_status.tweak(path, status='D ') # Test copying main.run_svn(None, 'cp', sbox.repo_url + '/A/mu', sbox.ospath('iota')) expected_status.tweak('iota', status='R ', wc_rev='-', copied='+') main.run_svn(None, 'cp', sbox.repo_url + '/A/D', sbox.ospath('A/B')) expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+') for child in A_D_children: expected_status.add({ child.replace('A/D', 'A/B'): Item(status=' ', wc_rev='-', copied='+')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) def copy_repos_over_deleted_other_kind(sbox): "copy repos node over deleted node, other kind" sbox.build(read_only = True) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) # Set up some deleted paths sbox.simple_rm('iota', 'A/B') for path in ['iota', 'A/B'] + A_B_children: expected_status.tweak(path, status='D ') # Test copying main.run_svn(None, 'cp', sbox.repo_url + '/iota', sbox.ospath('A/B')) expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+') expected_status.remove(*A_B_children) main.run_svn(None, 'cp', sbox.repo_url + '/A/B', sbox.ospath('iota')) expected_status.tweak('iota', status='R ', wc_rev='-', copied='+') for child in A_B_children: expected_status.add({ child.replace('A/B', 'iota'): Item(status=' ', wc_rev='-', copied='+')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) def copy_wc_over_deleted_same_kind(sbox): "copy WC node over a deleted node, same kind" sbox.build(read_only = True) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) # Set up some deleted paths sbox.simple_rm('iota', 'A/B') for path in ['iota', 'A/B'] + A_B_children: expected_status.tweak(path, status='D ') # Test copying main.run_svn(None, 'cp', sbox.ospath('A/mu'), sbox.ospath('iota')) expected_status.tweak('iota', status='R ', wc_rev='-', copied='+') main.run_svn(None, 'cp', sbox.ospath('A/D'), sbox.ospath('A/B')) expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+') for child in A_D_children: expected_status.add({ child.replace('A/D', 'A/B'): Item(status=' ', wc_rev='-', copied='+')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) def copy_wc_over_deleted_other_kind(sbox): "copy WC node over deleted node, other kind" sbox.build(read_only = True) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) # Set up some deleted paths sbox.simple_rm('iota', 'A/B') for path in ['iota', 'A/B'] + A_B_children: expected_status.tweak(path, status='D ') # Test copying main.run_svn(None, 'cp', sbox.ospath('A/mu'), sbox.ospath('A/B')) expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+') expected_status.remove(*A_B_children) main.run_svn(None, 'cp', sbox.ospath('A/D'), sbox.ospath('iota')) expected_status.tweak('iota', status='R ', wc_rev='-', copied='+') for child in A_D_children: expected_status.add({ child.replace('A/D', 'iota'): Item(status=' ', wc_rev='-', copied='+')}) svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) def move_wc_and_repo_dir_to_itself(sbox): "move wc and repo dir to itself" sbox.build(read_only = True) wc_dir = os.path.join(sbox.wc_dir, 'A') repo_url = sbox.repo_url + '/A' # try to move wc dir to itself svntest.actions.run_and_verify_svn(None, [], '.*Cannot move path.* into itself.*', 'move', wc_dir, wc_dir) # try to move repo dir to itself svntest.actions.run_and_verify_svn(None, [], '.*Cannot move URL.* into itself.*', 'move', repo_url, repo_url) @Issues(2763,3314) def copy_wc_url_with_absent(sbox): "copy wc to url with several absent children" sbox.build() wc_dir = sbox.wc_dir # A/B a normal delete sbox.simple_rm('A/B') # A/no not-present but in HEAD sbox.simple_copy('A/mu', 'A/no') sbox.simple_commit('A/no') svntest.main.run_svn(None, 'up', '-r', '1', sbox.ospath('A/no')) # A/mu not-present and not in HEAD sbox.simple_rm('A/mu') sbox.simple_commit('A/mu') # A/D excluded svntest.main.run_svn(None, 'up', '--set-depth', 'exclude', os.path.join(sbox.wc_dir, 'A/D')) # Test issue #3314 after copy sbox.simple_copy('A', 'A_copied') svntest.main.run_svn(None, 'ci', os.path.join(sbox.wc_dir, 'A_copied'), '-m', 'Commit A_copied') # This tests issue #2763 svntest.main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A'), '^/A_tagged', '-m', 'Tag A') # And perform a normal commit svntest.main.run_svn(None, 'ci', os.path.join(sbox.wc_dir, 'A'), '-m', 'Commit A') expected_output = svntest.wc.State(wc_dir, { 'A_tagged' : Item(status='A '), 'A_tagged/D' : Item(status='A '), 'A_tagged/D/gamma' : Item(status='A '), 'A_tagged/D/H' : Item(status='A '), 'A_tagged/D/H/psi' : Item(status='A '), 'A_tagged/D/H/chi' : Item(status='A '), 'A_tagged/D/H/omega': Item(status='A '), 'A_tagged/D/G' : Item(status='A '), 'A_tagged/D/G/pi' : Item(status='A '), 'A_tagged/D/G/rho' : Item(status='A '), 'A_tagged/D/G/tau' : Item(status='A '), 'A_tagged/C' : Item(status='A '), 'A/no' : Item(status='A '), }) # This should bring in A_tagged and A/no svntest.actions.run_and_verify_update(wc_dir, expected_output, None, None) # And now bring in the excluded nodes from A and A_copied expected_output = svntest.wc.State(wc_dir, { 'A/D' : Item(status='A '), 'A/D/G' : Item(status='A '), 'A/D/G/pi' : Item(status='A '), 'A/D/G/tau' : Item(status='A '), 'A/D/G/rho' : Item(status='A '), 'A/D/H' : Item(status='A '), 'A/D/H/psi' : Item(status='A '), 'A/D/H/chi' : Item(status='A '), 'A/D/H/omega' : Item(status='A '), 'A/D/gamma' : Item(status='A '), 'A_copied/D' : Item(status='A '), 'A_copied/D/H' : Item(status='A '), 'A_copied/D/H/omega': Item(status='A '), 'A_copied/D/H/psi' : Item(status='A '), 'A_copied/D/H/chi' : Item(status='A '), 'A_copied/D/G' : Item(status='A '), 'A_copied/D/G/tau' : Item(status='A '), 'A_copied/D/G/rho' : Item(status='A '), 'A_copied/D/G/pi' : Item(status='A '), 'A_copied/D/gamma' : Item(status='A '), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, None, None, None, None, None, None, None, False, wc_dir, '--set-depth', 'infinity') # Except for A/no, the 3 directories should now have the same children items = { '' : Item(status=' ', wc_rev='6'), 'C' : Item(status=' ', wc_rev='6'), 'D' : Item(status=' ', wc_rev='6'), 'D/gamma' : Item(status=' ', wc_rev='6'), 'D/H' : Item(status=' ', wc_rev='6'), 'D/H/psi' : Item(status=' ', wc_rev='6'), 'D/H/chi' : Item(status=' ', wc_rev='6'), 'D/H/omega' : Item(status=' ', wc_rev='6'), 'D/G' : Item(status=' ', wc_rev='6'), 'D/G/pi' : Item(status=' ', wc_rev='6'), 'D/G/tau' : Item(status=' ', wc_rev='6'), 'D/G/rho' : Item(status=' ', wc_rev='6'), } expected_status = svntest.wc.State(os.path.join(wc_dir, 'A_copied'), items) svntest.actions.run_and_verify_status(os.path.join(wc_dir, 'A_copied'), expected_status) expected_status = svntest.wc.State(os.path.join(wc_dir, 'A_tagged'), items) svntest.actions.run_and_verify_status(os.path.join(wc_dir, 'A_tagged'), expected_status) expected_status.add({ 'no' : Item(status=' ', wc_rev='6') }) expected_status = svntest.wc.State(os.path.join(wc_dir, 'A'), items) svntest.actions.run_and_verify_status(os.path.join(wc_dir, 'A'), expected_status) def copy_url_shortcut(sbox): "copy using URL shortcut source" sbox.build(read_only = True) wc_dir = sbox.wc_dir # Can't use ^/A/D/G shortcut here because wc/X is unversioned. svntest.actions.run_and_verify_svn(None, None, [], 'copy', sbox.ospath('A/D/G'), sbox.ospath('X')) svntest.actions.run_and_verify_svn(None, None, [], 'rm', sbox.ospath('X/pi')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'X' : Item(status='A ', copied='+', wc_rev='-'), 'X/pi' : Item(status='D ', copied='+', wc_rev='-'), 'X/rho' : Item(status=' ', copied='+', wc_rev='-'), 'X/tau' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Can use ^/A/D/G even though X/pi is a delete within a copy. svntest.actions.run_and_verify_svn(None, None, [], 'copy', '^/A/D/G/pi', sbox.ospath('X/pi')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'X' : Item(status='A ', copied='+', wc_rev='-'), 'X/pi' : Item(status='R ', copied='+', wc_rev='-', entry_status=' '), 'X/rho' : Item(status=' ', copied='+', wc_rev='-'), 'X/tau' : Item(status=' ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Regression test for issue #3865: 'svn' on Windows cannot address # scheduled-for-delete file, if another file differing only in case is # present on disk @Issue(3865) def deleted_file_with_case_clash(sbox): """address a deleted file hidden by case clash""" sbox.build(read_only = True) wc_dir = sbox.wc_dir iota_path = os.path.join(wc_dir, 'iota') iota2_path = os.path.join(wc_dir, 'iota2') IOTA_path = os.path.join(wc_dir, 'IOTA') iota_url = sbox.repo_url + '/iota' # Perform a case-only rename in two steps. svntest.main.run_svn(None, 'move', iota_path, iota2_path) svntest.main.run_svn(None, 'move', iota2_path, IOTA_path) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status='D ', wc_rev=1), 'IOTA' : Item(status='A ', copied='+', wc_rev='-'), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Perform 'info' calls on both the deleted and added paths, to see if # we get the correct information. The deleted path is not on disk and # hidden by the on-disk case-clashing file, but we should be able to # target it explicitly because it's in the wc-db. expected_info_iota = {'Path' : re.escape(iota_path), 'Schedule' : 'delete', 'Copied From URL': None, } svntest.actions.run_and_verify_info([expected_info_iota], iota_path) expected_info_IOTA = {'Path' : re.escape(IOTA_path), 'Schedule' : 'add', 'Copied From URL': iota_url, } svntest.actions.run_and_verify_info([expected_info_IOTA], IOTA_path) def copy_base_of_deleted(sbox): """copy -rBASE deleted""" sbox.build(read_only = True) wc_dir = sbox.wc_dir svntest.actions.run_and_verify_svn(None, None, [], 'rm', sbox.ospath('A/mu')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/mu', status='D ') svntest.actions.run_and_verify_status(wc_dir, expected_status) svntest.actions.run_and_verify_svn(None, None, [], 'cp', '-rBASE', sbox.ospath('A/mu'), sbox.ospath('A/mu2')) expected_status.add({ 'A/mu2' : Item(status='A ', copied='+', wc_rev='-'), }) # Regression test for issue #3702: Unable to perform case-only rename # on windows. @Issue(3702) # APR's apr_filepath_merge() with APR_FILEPATH_TRUENAME is broken on OS X. @XFail(svntest.main.is_os_darwin) def case_only_rename(sbox): """case-only rename""" sbox.build() wc_dir = sbox.wc_dir iota_path = os.path.join(wc_dir, 'iota') IoTa_path = os.path.join(wc_dir, 'IoTa') B_path = os.path.join(wc_dir, 'A/B') b_path = os.path.join(wc_dir, 'A/b') # Perform a couple of case-only renames. svntest.main.run_svn(None, 'move', iota_path, IoTa_path) svntest.main.run_svn(None, 'move', B_path, b_path) # Create expected status. expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status='D ', wc_rev=1), 'IoTa' : Item(status='A ', copied='+', wc_rev='-'), 'A/B' : Item(status='D ', wc_rev='1'), 'A/B/lambda' : Item(status='D ', wc_rev='1'), 'A/B/E' : Item(status='D ', wc_rev='1'), 'A/B/E/alpha' : Item(status='D ', wc_rev='1'), 'A/B/E/beta' : Item(status='D ', wc_rev='1'), 'A/B/F' : Item(status='D ', wc_rev='1'), 'A/b' : Item(status='A ', copied='+', wc_rev='-'), 'A/b/E' : Item(status=' ', copied='+', wc_rev='-'), 'A/b/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 'A/b/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 'A/b/F' : Item(status=' ', copied='+', wc_rev='-'), 'A/b/lambda' : Item(status=' ', copied='+', wc_rev='-'), }) # 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 copy_and_move_conflicts(sbox): """copy and move conflicts""" # The destination of a copy or move 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 # text (resolved by deleting markers) 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/beta'), "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") file_append(wc('A/B/E/beta'), "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')) # Resolve one text conflict via marker file deletion. os.remove(wc('A/B/E/beta.merge-left.r3')) os.remove(wc('A/B/E/beta.working')) os.remove(wc('A/B/E/beta')) os.rename(wc('A/B/E/beta.merge-right.r4'), wc('A/B/E/beta')) # 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=' ', copied='+', wc_rev='-'), 'B/E/beta' : Item(status='M ', 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 appear at the copy destinations. Note that # B/E/beta had been resolved via marker-file deletion before the copy. 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" "Edit for merge\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) # Move conflict victims. sbox.simple_move('A/B/E/alpha', 'move-dest') sbox.simple_move('A/D/H', 'move-dest') sbox.simple_move('A/D/G', 'move-dest') sbox.simple_move('A/Q', 'move-dest') # Move directories with conflicted children. sbox.simple_move('A/B', 'move-dest') sbox.simple_move('A/D', 'move-dest') # Expect same status and disk content as at the copy destination, except # that A/B/E/alpha, A/D/G, and A/D/H were moved away first. expected_status.wc_dir = wc('move-dest') expected_status.tweak('B/E/alpha', 'D/H', 'D/H/chi', 'D/H/omega', 'D/H/psi', status='D ') # A/D/G had been re-added from r4 due to a "local edit, incoming delete" # tree conflict, so moving it away has a different effect. expected_status.remove('D/G', 'D/G/pi', 'D/G/rho', 'D/G/tau') svntest.actions.run_and_verify_status(wc('move-dest'), expected_status) expected_disk = svntest.wc.State('', { 'B/E/beta' : Item(contents="This is the file 'beta'.\n" "Edit for merge\n"), 'B/lambda' : Item(contents="This is the file 'lambda'.\n"), 'B/F' : Item(), 'H' : Item(props={'foo':'100'}), 'H/chi' : Item(contents="This is the file 'chi'.\n", props={'foo':'100'}), 'H/psi' : Item(contents="This is the file 'psi'.\n"), 'H/omega' : Item(contents="This is the file 'omega'.\n"), 'D' : Item(), 'G/tau' : Item(contents="This is the file 'tau'.\n"), 'G/rho' : Item(contents="This is the file 'rho'.\n" "Local edit\n"), 'G/pi' : Item(contents="This is the file 'pi'.\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('move-dest'), expected_disk, True) def copy_deleted_dir(sbox): "try to copy a deleted directory that exists" sbox.build(read_only = True) sbox.simple_rm('iota') sbox.simple_rm('A') svntest.actions.run_and_verify_svn(None, None, 'svn: E145000: Path.* does not exist', 'cp', sbox.ospath('iota'), sbox.ospath('new_iota')) svntest.actions.run_and_verify_svn(None, None, 'svn: E145000: Path.* does not exist', 'cp', sbox.ospath('A/D'), sbox.ospath('new_D')) svntest.main.file_write(sbox.ospath('iota'), 'Not iota!') os.mkdir(sbox.ospath('A')) os.mkdir(sbox.ospath('A/D')) # These two invocations raise an assertion. svntest.actions.run_and_verify_svn(None, None, 'svn: E155035: Deleted node.* can\'t be.*', 'cp', sbox.ospath('iota'), sbox.ospath('new_iota')) svntest.actions.run_and_verify_svn(None, None, 'svn: E155035: Deleted node.* can\'t be.*', 'cp', sbox.ospath('A/D'), sbox.ospath('new_D')) ######################################################################## # Run the tests # list all tests here, starting with None: test_list = [ None, basic_copy_and_move_files, receive_copy_in_update, resurrect_deleted_dir, no_copy_overwrites, no_wc_copy_overwrites, copy_modify_commit, copy_files_with_properties, copy_delete_commit, mv_and_revert_directory, copy_preserve_executable_bit, wc_to_repos, repos_to_wc, copy_to_root, url_copy_parent_into_child, wc_copy_parent_into_child, resurrect_deleted_file, diff_repos_to_wc_copy, repos_to_wc_copy_eol_keywords, revision_kinds_local_source, copy_over_missing_file, repos_to_wc_1634, double_uri_escaping_1814, wc_to_wc_copy_between_different_repos, wc_to_wc_copy_deleted, url_to_non_existent_url_path, non_existent_url_to_url, old_dir_url_to_url, wc_copy_dir_to_itself, mixed_wc_to_url, wc_copy_replacement, wc_copy_replace_with_props, repos_to_wc_copy_replacement, repos_to_wc_copy_replace_with_props, delete_replaced_file, mv_unversioned_file, force_move, copy_deleted_dir_into_prefix, copy_copied_file_and_dir, move_copied_file_and_dir, move_moved_file_and_dir, move_file_within_moved_dir, move_file_out_of_moved_dir, move_dir_within_moved_dir, move_dir_out_of_moved_dir, move_file_back_and_forth, move_dir_back_and_forth, copy_move_added_paths, copy_added_paths_with_props, copy_added_paths_to_URL, move_to_relative_paths, move_from_relative_paths, copy_to_relative_paths, copy_from_relative_paths, move_multiple_wc, copy_multiple_wc, move_multiple_repo, copy_multiple_repo, copy_multiple_repo_wc, copy_multiple_wc_repo, copy_peg_rev_local_files, copy_peg_rev_local_dirs, copy_peg_rev_url, old_dir_wc_to_wc, copy_make_parents_wc_wc, copy_make_parents_repo_wc, copy_make_parents_wc_repo, copy_make_parents_repo_repo, URI_encoded_repos_to_wc, allow_unversioned_parent_for_copy_src, unneeded_parents, double_parents_with_url, copy_into_absent_dir, find_copyfrom_information_upstairs, path_move_and_copy_between_wcs_2475, path_copy_in_repo_2475, commit_copy_depth_empty, copy_below_copy, move_below_move, reverse_merge_move, nonrecursive_commit_of_copy, copy_added_dir_with_copy, copy_broken_symlink, move_dir_containing_move, copy_dir_with_space, changed_data_should_match_checkout, changed_dir_data_should_match_checkout, move_added_nodes, copy_over_deleted_dir, mixed_rev_copy_del, copy_delete_delete, copy_delete_revert, delete_replace_delete, copy_repos_over_deleted_same_kind, copy_repos_over_deleted_other_kind, copy_wc_over_deleted_same_kind, copy_wc_over_deleted_other_kind, move_wc_and_repo_dir_to_itself, copy_wc_url_with_absent, copy_url_shortcut, deleted_file_with_case_clash, copy_base_of_deleted, case_only_rename, copy_and_move_conflicts, copy_deleted_dir, ] if __name__ == '__main__': svntest.main.run_tests(test_list) # NOTREACHED ### End of file.