# HG changeset patch # User Patrick Mezard # Date 1267545966 -3600 # Node ID 44c56a7727c42a955827cb63e18a0d6546c34a7a # Parent 90efea2c19df9a7c8058180ac4be5a5480fe3bd5 editor: fix issamefile() and copy detection in replay mode Known failures: - comprehensive/test_verify on replace_branch_with_branch: replaced files content is incorrect - comprehensive/test_stupid_pull on replace_branch_with_branch: very stupid mode does not handle replacements correctly. diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py --- a/hgsubversion/editor.py +++ b/hgsubversion/editor.py @@ -216,13 +216,13 @@ class HgEditor(delta.Editor): fctx = ctx.filectx(from_file) flags = fctx.flags() self.current.set(path, fctx.data(), 'x' in flags, 'l' in flags) - if from_branch == branch: - parentid = self.meta.get_parent_revision(self.current.rev.revnum, - branch) - if parentid != revlog.nullid: - parentctx = self.repo.changectx(parentid) - if util.issamefile(parentctx, ctx, from_file): - self.current.copies[path] = from_file + if from_branch == branch: + parentid = self.meta.get_parent_revision( + self.current.rev.revnum, branch) + if parentid != revlog.nullid: + parentctx = self.repo.changectx(parentid) + if util.issamefile(parentctx, ctx, from_file): + self.current.copies[path] = from_file @ieditor def add_directory(self, path, parent_baton, copyfrom_path, diff --git a/hgsubversion/util.py b/hgsubversion/util.py --- a/hgsubversion/util.py +++ b/hgsubversion/util.py @@ -145,7 +145,9 @@ def swap_out_encoding(new_encoding="UTF- def issamefile(parentctx, childctx, f): - """Assuming f exists and is the same in childctx and parentctx, return True.""" + """Return True if f exists and is the same in childctx and parentctx""" + if f not in parentctx or f not in childctx: + return False if parentctx == childctx: return True if parentctx.rev() > childctx.rev(): diff --git a/tests/fixtures/replace_branch_with_branch.sh b/tests/fixtures/replace_branch_with_branch.sh new file mode 100755 --- /dev/null +++ b/tests/fixtures/replace_branch_with_branch.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +RSVN="`pwd`/rsvn.py" +export PATH=/bin:/usr/bin +mkdir temp +cd temp + +svnadmin create repo +svn co file://`pwd`/repo wc + +cd wc +mkdir trunk branches +cd trunk +echo a > a +cd .. +svn add * +svn ci -m 'initial' + +svn up +svn cp trunk branches/branch1 +svn ci -m 'branch1' +svn up +echo b > branches/branch1/b +echo d > branches/branch1/d +svn add branches/branch1/b branches/branch1/d +svn ci -m 'add b to branch1' +svn cp trunk branches/branch2 +svn ci -m 'branch2' +svn up +echo c > branches/branch2/c +svn add branches/branch2/c +svn ci -m 'add c to branch2' +svn up + +# Clobber branch1 with branch2 +cd .. +cat > clobber.rsvn < ../replace_branch_with_branch.svndump diff --git a/tests/fixtures/replace_branch_with_branch.svndump b/tests/fixtures/replace_branch_with_branch.svndump new file mode 100644 --- /dev/null +++ b/tests/fixtures/replace_branch_with_branch.svndump @@ -0,0 +1,234 @@ +SVN-fs-dump-format-version: 2 + +UUID: 9ccfc2a0-ffd9-470e-a000-ccb1f0fe21e5 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2010-02-24T20:15:47.286918Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 108 +Content-length: 108 + +K 7 +svn:log +V 7 +initial +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2010-02-24T20:15:48.124168Z +PROPS-END + +Node-path: branches +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 + + +Node-path: trunk/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + +Revision-number: 2 +Prop-content-length: 108 +Content-length: 108 + +K 7 +svn:log +V 7 +branch1 +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2010-02-24T20:15:51.070312Z +PROPS-END + +Node-path: branches/branch1 +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 1 +Node-copyfrom-path: trunk + + +Revision-number: 3 +Prop-content-length: 118 +Content-length: 118 + +K 7 +svn:log +V 16 +add b to branch1 +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2010-02-24T20:15:53.123732Z +PROPS-END + +Node-path: branches/branch1/b +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 3b5d5c3712955042212316173ccf37be +Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b +Content-length: 12 + +PROPS-END +b + + +Node-path: branches/branch1/d +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b +Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff +Content-length: 12 + +PROPS-END +d + + +Revision-number: 4 +Prop-content-length: 108 +Content-length: 108 + +K 7 +svn:log +V 7 +branch2 +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2010-02-24T20:15:55.095809Z +PROPS-END + +Node-path: branches/branch2 +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 2 +Node-copyfrom-path: trunk + + +Revision-number: 5 +Prop-content-length: 118 +Content-length: 118 + +K 7 +svn:log +V 16 +add c to branch2 +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2010-02-24T20:15:57.098439Z +PROPS-END + +Node-path: branches/branch2/c +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1 +Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69 +Content-length: 12 + +PROPS-END +c + + +Revision-number: 6 +Prop-content-length: 102 +Content-length: 102 + +K 7 +svn:log +V 4 +blah +K 10 +svn:author +V 4 +evil +K 8 +svn:date +V 27 +2010-02-24T20:15:59.687871Z +PROPS-END + +Node-path: branches/branch1 +Node-kind: dir +Node-action: delete + +Node-path: branches/branch1 +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 5 +Node-copyfrom-path: branches/branch2 + + + + +Node-path: branches/branch1/a +Node-kind: file +Node-action: delete + +Node-path: branches/branch1/a +Node-kind: file +Node-action: add +Node-copyfrom-rev: 5 +Node-copyfrom-path: branches/branch1/d +Text-copy-source-md5: e29311f6f1bf1af907f9ef9f44b8328b +Text-copy-source-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff + + + + 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 @@ -131,6 +131,26 @@ class TestFetchBranches(test_util.TestBa self.assertEqual(node.hex(repo['tip'].node()), '4108a81a82c7925d5551091165dc54c41b06a8a8') + def test_replace_branch_with_branch(self, stupid=False): + repo = self._load_fixture_and_fetch('replace_branch_with_branch.svndump', + stupid) + self.assertEqual(7, len(repo)) + # tip is former topological branch1 being closed + ctx = repo['tip'] + self.assertEqual('1', ctx.extra().get('close', '0')) + self.assertEqual('branch1', ctx.branch()) + # r5 is where the replacement takes place + ctx = repo[5] + self.assertEqual(set(['a', 'c']), set(ctx)) + self.assertEqual('0', ctx.extra().get('close', '0')) + self.assertEqual('branch1', ctx.branch()) + self.assertEqual('c\n', ctx['c'].data()) + # a replacement does not work yet + #self.assertEqual('d\n', ctx['a'].data()) + + def test_replace_branch_with_branch_stupid(self, stupid=False): + self.test_replace_branch_with_branch(True) + def suite(): all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches), ]