changeset 1232:ba8485b9fee0

editor: correctly import copies of directories from non-tracked or closed branches
author David Schleimer <dschleimer@fb.com>
date Sun, 17 Nov 2013 09:57:00 -0800
parents 5c2917375961
children 0d0132cba155
files hgsubversion/editor.py tests/fixtures/copyafterclose.sh tests/fixtures/copyafterclose.svndump tests/test_fetch_branches.py tests/test_util.py
diffstat 5 files changed, 368 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/editor.py
+++ b/hgsubversion/editor.py
@@ -239,6 +239,13 @@ class HgEditor(svnwrap.Editor):
         else:
             # Resolve missing directories content immediately so the
             # missing files maybe processed by delete actions.
+            # we remove the missing directory entries to deal with the case
+            # where a directory is replaced from e.g. a closed branch
+            # this will show up as a delete and then a copy
+            # we process deletes after missing, so we can handle a directory
+            # copy plus delete of file in that directory.  This means that we
+            # need to be sure that only things whose final disposition is
+            # deletion remain in self._deleted at the end of the editing process.
             rev = self.current.rev.revnum
             path = path + '/'
             parentdir = path[len(root):]
@@ -248,6 +255,7 @@ class HgEditor(svnwrap.Editor):
                 f = parentdir + f
                 if not self.meta.is_path_valid(f, False):
                     continue
+                self._deleted.discard(f)
                 self._missing.add(f)
 
     @svnwrap.ieditor
@@ -431,7 +439,7 @@ class HgEditor(svnwrap.Editor):
             source_rev = copyfrom_revision
             frompath, source_branch = self.meta.split_branch_path(copyfrom_path)[:2]
         new_hash = self.meta.get_parent_revision(source_rev + 1, source_branch, True)
-        if new_hash == node.nullid:
+        if frompath is None or new_hash == node.nullid:
             self.addmissing(path, isdir=True)
             return baton
         fromctx = self._getctx(new_hash)
new file mode 100755
--- /dev/null
+++ b/tests/fixtures/copyafterclose.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+rm -rf temp
+mkdir temp
+cd temp
+svnadmin create repo
+repo=file://`pwd`/repo
+svn co $repo wc
+cd wc
+mkdir branches trunk tags
+svn add *
+svn ci -m 'btt'
+
+cd trunk
+echo trunk1 > file
+mkdir dir
+echo trunk1 > dir/file
+svn add file dir
+svn ci -m 'Add file and dir.'
+cd ..
+svn up
+
+svn cp trunk branches/test
+svn ci -m 'Branch.'
+svn up
+
+cd branches/test/
+echo branch1 > file
+echo branch1 > dir/file
+svn ci -m 'edit on branch.'
+cd ../../
+svn up
+
+cd trunk
+echo trunk2 > file
+echo trunk2 > dir/file
+svn ci -m 'edit on trunk'
+cd ..
+svn up
+
+svn rm trunk
+svn ci -m 'Close trunk.'
+svn up
+
+cd branches/test
+svn rm file
+svn cp $repo/trunk/file@5 file
+svn rm dir
+svn cp $repo/trunk/dir@5 dir
+svn ci -m 'copy from trunk before close'
+cd ../..
+svn up
+
+cd ../..
+svnadmin dump temp/repo > copyafterclose.svndump
+echo
+echo 'Complete.'
+echo 'You probably want to clean up temp now.'
+echo 'Dump in copyafterclose.svndump'
+exit 0
new file mode 100644
--- /dev/null
+++ b/tests/fixtures/copyafterclose.svndump
@@ -0,0 +1,285 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 288797d9-b527-4683-aa49-2eb9e084ffad
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.334418Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 108
+Content-length: 108
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.393547Z
+K 7
+svn:log
+V 3
+btt
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 123
+Content-length: 123
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.442353Z
+K 7
+svn:log
+V 17
+Add file and dir.
+PROPS-END
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 7
+Text-content-md5: 5f2a436c7d4aa15dfbdca7b303fcae35
+Text-content-sha1: 391157987cb6fefff86fd89353356611ea621906
+Content-length: 17
+
+PROPS-END
+trunk1
+
+
+Node-path: trunk/file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 7
+Text-content-md5: 5f2a436c7d4aa15dfbdca7b303fcae35
+Text-content-sha1: 391157987cb6fefff86fd89353356611ea621906
+Content-length: 17
+
+PROPS-END
+trunk1
+
+
+Revision-number: 3
+Prop-content-length: 112
+Content-length: 112
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.504478Z
+K 7
+svn:log
+V 7
+Branch.
+PROPS-END
+
+Node-path: branches/test
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Revision-number: 4
+Prop-content-length: 121
+Content-length: 121
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.549176Z
+K 7
+svn:log
+V 15
+edit on branch.
+PROPS-END
+
+Node-path: branches/test/dir/file
+Node-kind: file
+Node-action: change
+Text-content-length: 8
+Text-content-md5: ed787ace107676c1dfcced2ae527df92
+Text-content-sha1: b8486c4feca589a4237a1ee428322d7109ede12e
+Content-length: 8
+
+branch1
+
+
+Node-path: branches/test/file
+Node-kind: file
+Node-action: change
+Text-content-length: 8
+Text-content-md5: ed787ace107676c1dfcced2ae527df92
+Text-content-sha1: b8486c4feca589a4237a1ee428322d7109ede12e
+Content-length: 8
+
+branch1
+
+
+Revision-number: 5
+Prop-content-length: 119
+Content-length: 119
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.600193Z
+K 7
+svn:log
+V 13
+edit on trunk
+PROPS-END
+
+Node-path: trunk/dir/file
+Node-kind: file
+Node-action: change
+Text-content-length: 7
+Text-content-md5: 28d0a7e7ef2864416b7a9398623e4d09
+Text-content-sha1: 91454e2d3487f712490f17481157e389c11a6fe0
+Content-length: 7
+
+trunk2
+
+
+Node-path: trunk/file
+Node-kind: file
+Node-action: change
+Text-content-length: 7
+Text-content-md5: 28d0a7e7ef2864416b7a9398623e4d09
+Text-content-sha1: 91454e2d3487f712490f17481157e389c11a6fe0
+Content-length: 7
+
+trunk2
+
+
+Revision-number: 6
+Prop-content-length: 118
+Content-length: 118
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.650888Z
+K 7
+svn:log
+V 12
+Close trunk.
+PROPS-END
+
+Node-path: trunk
+Node-action: delete
+
+
+Revision-number: 7
+Prop-content-length: 134
+Content-length: 134
+
+K 10
+svn:author
+V 10
+dschleimer
+K 8
+svn:date
+V 27
+2014-04-03T22:42:41.757761Z
+K 7
+svn:log
+V 28
+copy from trunk before close
+PROPS-END
+
+Node-path: branches/test/dir
+Node-kind: dir
+Node-action: delete
+
+Node-path: branches/test/dir
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: trunk/dir
+
+
+
+
+Node-path: branches/test/file
+Node-kind: file
+Node-action: delete
+
+Node-path: branches/test/file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: trunk/file
+Text-copy-source-md5: 28d0a7e7ef2864416b7a9398623e4d09
+Text-copy-source-sha1: 91454e2d3487f712490f17481157e389c11a6fe0
+
+
+
+
--- a/tests/test_fetch_branches.py
+++ b/tests/test_fetch_branches.py
@@ -50,9 +50,7 @@ class TestFetchBranches(test_util.TestBa
         self.assertEqual(['a', 'c', 'z'], sorted(r.manifest()))
 
     def test_renamed_branch_to_trunk(self):
-        config = {'hgsubversion.failonmissing': 'true'}
-        repo = self._load_fixture_and_fetch('branch_rename_to_trunk.svndump',
-                                            config=config)
+        repo = self._load_fixture_and_fetch('branch_rename_to_trunk.svndump')
         self.assertEqual(repo['default'].parents()[0].branch(), 'dev_branch')
         self.assert_('iota' in repo['default'])
         self.assertEqual(repo['old_trunk'].parents()[0].branch(), 'default')
@@ -73,6 +71,15 @@ class TestFetchBranches(test_util.TestBa
         self.assertEqual(repo['test'].extra().get('close'), '1')
         self.assertEqual(repo['test']['b'].data(), 'a\n')
 
+    def test_copyafterclose(self):
+        repo = self._load_fixture_and_fetch('copyafterclose.svndump')
+        self.assertEqual(repo['tip'].branch(), 'test')
+        self.assert_('file' in repo['test'])
+        self.assertEqual(repo['test']['file'].data(), 'trunk2\n')
+        self.assert_('dir/file' in repo['test'])
+        self.assertEqual(repo['test']['dir/file'].data(), 'trunk2\n')
+
+
     def test_branch_create_with_dir_delete_works(self):
         repo = self._load_fixture_and_fetch('branch_create_with_dir_delete.svndump')
         self.assertEqual(repo['tip'].manifest().keys(),
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -138,6 +138,10 @@ custom = {
         'old_trunk': 'branches/old_trunk',
         },
     'copies.svndump': trunk_only,
+    'copyafterclose.svndump': {
+        'default': 'trunk',
+        'test': 'branches/test'
+        },
     'copybeforeclose.svndump': {
         'default': 'trunk',
         'test': 'branches/test'