changeset 376:9327e9325645

Use tbdelta to push added tags into .hgtags.
author Dirkjan Ochtman <dirkjan@ochtman.nl>
date Fri, 29 May 2009 15:28:44 +0200
parents af9fc01299b4
children 7e9269555e72
files hgsubversion/hg_delta_editor.py hgsubversion/stupid.py hgsubversion/svnrepo.py tests/test_tags.py
diffstat 4 files changed, 73 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/hg_delta_editor.py
+++ b/hgsubversion/hg_delta_editor.py
@@ -566,8 +566,9 @@ class HgChangeReceiver(delta.Editor):
                     and branch not in added_branches):
                     parent = {branch: (None, 0, revision.revnum)}
             added_branches.update(parent)
+        rmtags = dict((t, self.tags[t][0]) for t in tags_to_delete)
         return {
-            'tags': (added_tags, tags_to_delete),
+            'tags': (added_tags, rmtags),
             'branches': (added_branches, self.branches_to_delete),
         }
 
@@ -616,6 +617,52 @@ class HgChangeReceiver(delta.Editor):
         check = lambda x: x[0][1] == branch and x[0][0] < rev.revnum
         return sorted(filter(check, self.revmap.iteritems()), reverse=True)
 
+    def committags(self, delta, rev, endbranches):
+
+        date = self.fixdate(rev.date)
+        # determine additions/deletions per branch
+        branches = {}
+        for tag, source in delta[0].iteritems():
+            b, r = source
+            branches.setdefault(b, []).append(('add', tag, r))
+        for tag, branch in delta[1].iteritems():
+            branches.setdefault(branch, []).append(('rm', tag, None))
+
+        for b, tags in branches.iteritems():
+
+            # modify parent's .hgtags source
+            parent = self.repo[{None: 'default'}.get(b, b)]
+            if '.hgtags' not in parent:
+                src = ''
+            else:
+                src = parent['.hgtags'].data()
+            for op, tag, r in sorted(tags, reverse=True):
+                if op == 'add':
+                    tagged = node.hex(self.revmap[r, b])
+                elif op == 'rm':
+                    tagged = node.hex(node.nullid)
+                src += '%s %s\n' % (tagged, tag)
+
+            # add new changeset containing updated .hgtags
+            def fctxfun(repo, memctx, path):
+                return context.memfilectx(path='.hgtags', data=src,
+                                          islink=False, isexec=False,
+                                          copied=None)
+            extra = util.build_extra(rev.revnum, b, self.uuid, self.subdir)
+            ctx = context.memctx(self.repo,
+                                 (parent.node(), node.nullid),
+                                 rev.message or ' ',
+                                 ['.hgtags'],
+                                 fctxfun,
+                                 self.authors[rev.author],
+                                 date,
+                                 extra)
+            new = self.repo.commitctx(ctx)
+            if (rev.revnum, b) not in self.revmap:
+                self.add_to_revmap(rev.revnum, b, new)
+            if b in endbranches:
+                endbranches[b] = new
+
     def commit_current_delta(self, tbdelta):
         if hasattr(self, '_exception_info'):  #pragma: no cover
             traceback.print_exception(*self._exception_info)
@@ -740,7 +787,11 @@ class HgChangeReceiver(delta.Editor):
             if (rev.revnum, branch) not in self.revmap:
                 self.add_to_revmap(rev.revnum, branch, new_hash)
 
-        # 3. close any branches that need it
+        # 3. handle tags
+        if tbdelta['tags'][0] or tbdelta['tags'][1]:
+            self.committags(tbdelta['tags'], rev, closebranches)
+
+        # 4. close any branches that need it
         for branch in tbdelta['branches'][1]:
             # self.get_parent_revision(rev.revnum, branch)
             ha = closebranches.get(branch)
@@ -752,9 +803,10 @@ class HgChangeReceiver(delta.Editor):
         self.clear_current_info()
 
     def delbranch(self, branch, node, rev):
-        def del_all_files(*args):
-            raise IOError
-        files = self.repo[node].manifest().keys()
+        pctx = self.repo[node]
+        def filectxfun(repo, memctx, path):
+            return pctx[path]
+        files = pctx.manifest().keys()
         extra = {'close': 1}
         if self.usebranchnames:
             extra['branch'] = branch or 'default'
@@ -762,7 +814,7 @@ class HgChangeReceiver(delta.Editor):
                              (node, revlog.nullid),
                              rev.message or util.default_commit_msg,
                              files,
-                             del_all_files,
+                             filectxfun,
                              self.authors[rev.author],
                              self.fixdate(rev.date),
                              extra)
--- a/hgsubversion/stupid.py
+++ b/hgsubversion/stupid.py
@@ -549,6 +549,9 @@ def convert_rev(ui, hg_editor, svn, r, t
         if closed is not None:
             deleted_branches[branch] = closed
 
+    if tbdelta['tags'][0] or tbdelta['tags'][1]:
+        hg_editor.committags(tbdelta['tags'], r, deleted_branches)
+
     for b, parent in deleted_branches.iteritems():
         if parent == node.nullid:
             continue
--- a/hgsubversion/svnrepo.py
+++ b/hgsubversion/svnrepo.py
@@ -74,15 +74,6 @@ def generate_repo_class(ui, repo):
             raise hgutil.Abort('cannot display incoming changes from '
                                'Subversion repositories, yet')
 
-        @localsvn
-        def tags(self):
-            tags = superclass.tags(self)
-            hg_editor = hg_delta_editor.HgChangeReceiver(repo=self)
-            for tag, source in hg_editor.tags.iteritems():
-                target = hg_editor.get_parent_revision(source[1]+1, source[0])
-                tags['tag/%s' % tag] = target
-            return tags
-
     repo.__class__ = svnlocalrepo
 
 class svnremoterepo(mercurial.repo.repository):
--- a/tests/test_tags.py
+++ b/tests/test_tags.py
@@ -13,21 +13,12 @@ class TestTags(test_util.TestBase):
         return test_util.load_fixture_and_fetch(fixture_name, self.repo_path,
                                                 self.wc_path, stupid=stupid)
 
-    def _test_tag_revision_info(self, repo):
-        print repo.tags()
-        self.assertEqual(node.hex(repo[0].node()),
-                         '434ed487136c1b47c1e8f952edb4dc5a8e6328df')
-        self.assertEqual(node.hex(repo['tip'].node()),
-                         'c95251e0dd04697deee99b79cc407d7db76e6a5f')
-        self.assertEqual(repo['tip'], repo[1])
-
     def test_tags(self, stupid=False):
         repo = self._load_fixture_and_fetch('basic_tag_tests.svndump',
                                             stupid=stupid)
-        self._test_tag_revision_info(repo)
-        repo = self.repo
-        self.assertEqual(repo['tip'].node(), repo['tag/tag_r3'].node())
-        self.assertEqual(repo['tip'].node(), repo['tag/copied_tag'].node())
+        self.assertEqual(sorted(repo.tags()), ['copied_tag', 'tag_r3', 'tip'])
+        self.assertEqual(repo['tag_r3'], repo['copied_tag'])
+        self.assertEqual(repo['tag_r3'].rev(), 1)
 
     def test_tags_stupid(self):
         self.test_tags(stupid=True)
@@ -35,10 +26,8 @@ class TestTags(test_util.TestBase):
     def test_remove_tag(self, stupid=False):
         repo = self._load_fixture_and_fetch('remove_tag_test.svndump',
                                             stupid=stupid)
-        self._test_tag_revision_info(repo)
-        repo = self.repo
-        self.assertEqual(repo['tip'].node(), repo['tag/tag_r3'].node())
-        self.assert_('tag/copied_tag' not in repo.tags())
+        self.assertEqual(repo['tag_r3'].rev(), 1)
+        self.assert_('copied_tag' not in repo.tags())
 
     def test_remove_tag_stupid(self):
         self.test_remove_tag(stupid=True)
@@ -46,11 +35,8 @@ class TestTags(test_util.TestBase):
     def test_rename_tag(self, stupid=False):
         repo = self._load_fixture_and_fetch('rename_tag_test.svndump',
                                             stupid=stupid)
-        self._test_tag_revision_info(repo)
-        repo = self.repo
-        self.assertEqual(repo['tip'].node(), repo['tag/tag_r3'].node())
-        self.assertEqual(repo['tip'].node(), repo['tag/other_tag_r3'].node())
-        self.assert_('tag/copied_tag' not in repo.tags())
+        self.assertEqual(repo['tag_r3'], repo['other_tag_r3'])
+        self.assert_('copied_tag' not in repo.tags())
 
     def test_rename_tag_stupid(self):
         self.test_rename_tag(stupid=True)
@@ -58,11 +44,9 @@ class TestTags(test_util.TestBase):
     def test_branch_from_tag(self, stupid=False):
         repo = self._load_fixture_and_fetch('branch_from_tag.svndump',
                                             stupid=stupid)
-        repo = self.repo
-        self.assertEqual(repo['tip'].node(), repo['branch_from_tag'].node())
-        self.assertEqual(repo[1].node(), repo['tag/tag_r3'].node())
-        self.assertEqual(repo['branch_from_tag'].parents()[0].node(),
-                         repo['tag/copied_tag'].node())
+        self.assert_('branch_from_tag' in repo.branchtags())
+        self.assertEqual(repo[1], repo['tag_r3'])
+        self.assertEqual(repo['branch_from_tag'].parents()[0], repo['copied_tag'])
 
     def test_branch_from_tag_stupid(self):
         self.test_branch_from_tag(stupid=True)
@@ -70,15 +54,9 @@ class TestTags(test_util.TestBase):
     def test_tag_by_renaming_branch(self, stupid=False):
         repo = self._load_fixture_and_fetch('tag_by_rename_branch.svndump',
                                             stupid=stupid)
-        repo = self.repo
-        branches = set()
-        for h in repo.heads():
-            ctx = repo[h]
-            if 'close' not in ctx.extra():
-                branches.add(ctx.branch())
-
+        branches = set(repo[h] for h in repo.heads(closed=False))
         self.assert_('dummy' not in branches)
-        self.assertEqual(repo['tag/dummy'], repo['tip'].parents()[0])
+        self.assertEqual(repo['dummy'], repo['tip'].parents()[0].parents()[0])
         extra = repo['tip'].extra().copy()
         extra.pop('convert_revision', None)
         self.assertEqual(extra, {'branch': 'dummy', 'close': '1'})