# HG changeset patch # User David Schleimer # Date 1384711020 28800 # Node ID ba8485b9fee0d244d124812a457fb0ced8821af8 # Parent 5c29173759610c399c6982b7fb6645931aa50b5d editor: correctly import copies of directories from non-tracked or closed branches diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py --- 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) diff --git a/tests/fixtures/copyafterclose.sh b/tests/fixtures/copyafterclose.sh 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 diff --git a/tests/fixtures/copyafterclose.svndump b/tests/fixtures/copyafterclose.svndump 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 + + + + diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py --- 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(), diff --git a/tests/test_util.py b/tests/test_util.py --- 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'