changeset 729:467b95348e6a

implement tag renames This uses a separate map, since the purpose is very different from the purpose of the TagMap that we currently have. It seemed to me that unifying both will only serve to make the implementation more complicated. The name TagRenames is not that elegant, but I didn't have any better idea. Feel free to change.
author Dirkjan Ochtman <dirkjan@ochtman.nl>
date Fri, 08 Oct 2010 19:07:04 +0200
parents cfefeefad199
children efb87d5bb311 050f03a3bdf5
files hgsubversion/__init__.py hgsubversion/maps.py hgsubversion/svnmeta.py hgsubversion/wrappers.py tests/test_fetch_mappings.py
diffstat 5 files changed, 123 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/__init__.py
+++ b/hgsubversion/__init__.py
@@ -82,6 +82,7 @@ wrapcmds = { # cmd: generic, target, fix
         ('', 'layout', 'auto', ('import standard layout or single '
                                 'directory? Can be standard, single, or auto.')),
         ('', 'branchmap', '', 'file containing rules for branch conversion'),
+        ('', 'tagmap', '', 'file containing rules for renaming tags'),
         ('', 'startrev', '', ('convert Subversion revisions starting at the one '
                               'specified, either an integer revision or HEAD; '
                               'HEAD causes only the latest revision to be '
--- a/hgsubversion/maps.py
+++ b/hgsubversion/maps.py
@@ -100,7 +100,8 @@ class AuthorMap(dict):
 class Tags(dict):
     """Map tags to converted node identifier.
 
-    tag names are non-empty strings.
+    tag names are non-empty strings. Tags are saved in a file
+    called tagmap, for backwards compatibility reasons.
     """
     VERSION = 2
 
@@ -361,3 +362,61 @@ class BranchMap(dict):
         if writing:
             writing.flush()
             writing.close()
+
+class TagMap(dict):
+    '''Facility for controlled renaming of tags. Example:
+
+    oldname = newname
+    other =
+
+	The oldname tag from SVN will be represented as newname in the hg tags;
+	the other tag will not be reflected in the hg repository.
+    '''
+
+    def __init__(self, ui, path):
+        self.ui = ui
+        self.path = path
+        self.super = super(TagMap, self)
+        self.super.__init__()
+        self.load(path)
+
+    def load(self, path):
+        '''Load mappings from a file at the specified path.'''
+        if not os.path.exists(path):
+            return
+
+        writing = False
+        if path != self.path:
+            writing = open(self.path, 'a')
+
+        self.ui.note('reading tag renames from %s\n' % path)
+        f = open(path, 'r')
+        for number, line in enumerate(f):
+
+            if writing:
+                writing.write(line)
+
+            line = line.split('#')[0]
+            if not line.strip():
+                continue
+
+            try:
+                src, dst = line.split('=', 1)
+            except (IndexError, ValueError):
+                msg = 'ignoring line %i in tag renames %s: %s\n'
+                self.ui.status(msg % (number, path, line.rstrip()))
+                continue
+
+            src = src.strip()
+            dst = dst.strip()
+            self.ui.debug('adding tag %s to tag renames\n' % src)
+
+            if src in self and dst != self[src]:
+                msg = 'overriding tag rename: "%s" to "%s" (%s)\n'
+                self.ui.status(msg % (self[src], dst, src))
+            self[src] = dst
+
+        f.close()
+        if writing:
+            writing.flush()
+            writing.close()
--- a/hgsubversion/svnmeta.py
+++ b/hgsubversion/svnmeta.py
@@ -54,6 +54,7 @@ class SVNMeta(object):
         self.usebranchnames = self.ui.configbool('hgsubversion',
                                                  'usebranchnames', True)
         branchmap = self.ui.config('hgsubversion', 'branchmap')
+        tagmap = self.ui.config('hgsubversion', 'tagmap')
 
         # FIXME: test that this hasn't changed! defer & compare?
         if subdir:
@@ -90,10 +91,15 @@ class SVNMeta(object):
         self.authors = maps.AuthorMap(self.ui, self.authors_file,
                                  defaulthost=author_host)
         if authors: self.authors.load(authors)
+
         self.branchmap = maps.BranchMap(self.ui, self.branchmapfile)
         if branchmap:
             self.branchmap.load(branchmap)
 
+        self.tagmap = maps.TagMap(self.ui, self.tagmapfile)
+        if tagmap:
+            self.tagmap.load(tagmap)
+
         self.lastdate = '1970-01-01 00:00:00 -0000'
         self.filemap = maps.FileMap(repo)
         self.addedtags = {}
@@ -163,6 +169,11 @@ class SVNMeta(object):
     def branchmapfile(self):
         return os.path.join(self.meta_data_dir, 'branchmap')
 
+    @property
+    def tagmapfile(self):
+        # called tag-renames for backwards compatibility
+        return os.path.join(self.meta_data_dir, 'tag-renames')
+
     @property
     def layoutfile(self):
         return os.path.join(self.meta_data_dir, 'layout')
@@ -577,7 +588,7 @@ class SVNMeta(object):
             tagdata = parentctx.filectx('.hgtags').data()
         else:
             tagdata = ''
-        tagdata += '%s %s\n' % (node.hex(hash), tag, )
+        tagdata += '%s %s\n' % (node.hex(hash), self.tagmap.get(tag, tag))
         def hgtagsfn(repo, memctx, path):
             assert path == '.hgtags'
             return context.memfilectx(path=path,
@@ -632,6 +643,11 @@ class SVNMeta(object):
 
             fromtag = self.get_path_tag(self.remotename(b))
             for op, tag, r in sorted(tags, reverse=True):
+
+                if tag in self.tagmap and not self.tagmap[tag]:
+                    continue
+
+                tagged = node.hex(node.nullid) # op != 'add'
                 if op == 'add':
                     if fromtag:
                         if fromtag in self.tags:
@@ -639,9 +655,8 @@ class SVNMeta(object):
                     else:
                         tagged = node.hex(self.revmap[
                             self.get_parent_svn_branch_and_rev(r, b)])
-                else:
-                    tagged = node.hex(node.nullid)
-                src += '%s %s\n' % (tagged, tag)
+
+                src += '%s %s\n' % (tagged, self.tagmap.get(tag, tag))
                 self.tags[tag] = node.bin(tagged), rev.revnum
 
             # add new changeset containing updated .hgtags
--- a/hgsubversion/wrappers.py
+++ b/hgsubversion/wrappers.py
@@ -401,6 +401,7 @@ optionmap = {
     'authors': ('hgsubversion', 'authormap'),
     'filemap': ('hgsubversion', 'filemap'),
     'branchmap': ('hgsubversion', 'branchmap'),
+    'tagmap': ('hgsubversion', 'tagmap'),
     'stupid': ('hgsubversion', 'stupid'),
     'defaulthost': ('hgsubversion', 'defaulthost'),
     'defaultauthors': ('hgsubversion', 'defaultauthors'),
--- a/tests/test_fetch_mappings.py
+++ b/tests/test_fetch_mappings.py
@@ -25,6 +25,10 @@ class MapTests(test_util.TestBase):
     @property
     def branchmap(self):
         return os.path.join(self.tmpdir, 'branchmap')
+	
+    @property
+    def tagmap(self):
+        return os.path.join(self.tmpdir, 'tagmap')
 
     def test_author_map(self, stupid=False):
         test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump')
@@ -243,5 +247,43 @@ class MapTests(test_util.TestBase):
         self.assertRaises(hgutil.Abort,
                           maps.BranchMap, self.ui(), self.branchmap)
 
+    def test_tagmap(self, stupid=False):
+        test_util.load_svndump_fixture(self.repo_path,
+                                       'basic_tag_tests.svndump')
+        tagmap = open(self.tagmap, 'w')
+        tagmap.write("tag_r3 = 3.x # stuffy\n")
+        tagmap.write("copied_tag = \n")
+        tagmap.close()
+
+        ui = self.ui(stupid)
+        ui.setconfig('hgsubversion', 'tagmap', self.tagmap)
+        commands.clone(ui, test_util.fileurl(self.repo_path),
+                       self.wc_path, tagmap=self.tagmap)
+        tags = self.repo.tags()
+        assert 'tag_r3' not in tags
+        assert '3.x' in tags
+        assert 'copied_tag' not in tags
+
+    def test_tagmap_stupid(self):
+        self.test_tagmap(True)
+
+    def test_tagren_changed(self, stupid=False):
+        test_util.load_svndump_fixture(self.repo_path,
+                                       'commit-to-tag.svndump')
+        tagmap = open(self.tagmap, 'w')
+        tagmap.write("edit-at-create = edit-past\n")
+        tagmap.write("also-edit = \n")
+        tagmap.write("will-edit = edit-future\n")
+        tagmap.close()
+
+        ui = self.ui(stupid)
+        ui.setconfig('hgsubversion', 'tagmap', self.tagmap)
+        commands.clone(ui, test_util.fileurl(self.repo_path),
+                       self.wc_path, tagmap=self.tagmap)
+        tags = self.repo.tags()
+
+    def test_tagren_changed_stupid(self):
+        self.test_tagren_changed(True)
+
 def suite():
     return unittest.TestLoader().loadTestsFromTestCase(MapTests)