convert: add a mode where mercurial_sink skips empty revisions.
authorAlexis S. L. Carvalho <alexis@cecm.usp.br>
Thu, 04 Oct 2007 23:21:37 -0300
changeset 5378 8a2915f57dfc
parent 5377 756a43a30e34
child 5379 d3e51dc804f8
convert: add a mode where mercurial_sink skips empty revisions. The getchanges function of some converter_source classes can return some false positives. I.e. they sometimes claim that a file "foo" was changed in some revision, even though its contents are still the same. convert_svn is particularly bad, but I think this can also happen with convert_cvs and, at least in theory, with mercurial_source. For regular conversions this is not really a problem - as long as getfile returns the right contents, we'll get a converted revision with the right contents. But when we use --filemap, this could lead to superfluous revisions being converted. Instead of fixing every converter_source, I decided to change mercurial_sink to work around this problem. When --filemap is used, we're interested only in revisions that touch some specific files. If a revision doesn't change any of these files, then we're not interested in it (at least for revisions with a single parent; merges are special). For mercurial_sink, we abuse this property and rollback a commit if the manifest text hasn't changed. This avoids duplicating the logic from localrepo.filecommit to detect unchanged files.
hgext/convert/__init__.py
hgext/convert/common.py
hgext/convert/hg.py
--- a/hgext/convert/__init__.py	Thu Oct 04 23:21:37 2007 -0300
+++ b/hgext/convert/__init__.py	Thu Oct 04 23:21:37 2007 -0300
@@ -382,6 +382,7 @@
     fmap = opts.get('filemap')
     if fmap:
         srcc = filemap.filemap_source(ui, srcc, fmap)
+        destc.setfilemapmode(True)
 
     if not revmapfile:
         try:
--- a/hgext/convert/common.py	Thu Oct 04 23:21:37 2007 -0300
+++ b/hgext/convert/common.py	Thu Oct 04 23:21:37 2007 -0300
@@ -167,3 +167,13 @@
         pbranch: branch name of parent commit
         parents: destination revisions of parent"""
         pass
+
+    def setfilemapmode(self, active):
+        """Tell the destination that we're using a filemap
+
+        Some converter_sources (svn in particular) can claim that a file
+        was changed in a revision, even if there was no change.  This method
+        tells the destination that we're using a filemap and that it should
+        filter empty revisions.
+        """
+        pass
--- a/hgext/convert/hg.py	Thu Oct 04 23:21:37 2007 -0300
+++ b/hgext/convert/hg.py	Thu Oct 04 23:21:37 2007 -0300
@@ -28,6 +28,7 @@
             raise NoRepo("could not open hg repo %s as sink" % path)
         self.lock = None
         self.wlock = None
+        self.filemapmode = False
 
     def before(self):
         self.wlock = self.repo.wlock()
@@ -96,6 +97,10 @@
                 pl.append(p)
                 seen[p] = 1
         parents = pl
+        nparents = len(parents)
+        if self.filemapmode and nparents == 1:
+            m1node = self.repo.changelog.read(bin(parents[0]))[0]
+            parent = parents[0]
 
         if len(parents) < 2: parents.append("0" * 40)
         if len(parents) < 2: parents.append("0" * 40)
@@ -117,6 +122,13 @@
             text = "(octopus merge fixup)\n"
             p2 = hg.hex(self.repo.changelog.tip())
 
+        if self.filemapmode and nparents == 1:
+            man = self.repo.manifest
+            mnode = self.repo.changelog.read(bin(p2))[0]
+            if not man.cmp(m1node, man.revision(mnode)):
+                self.repo.rollback()
+                self.repo.dirstate.clear()
+                return parent
         return p2
 
     def puttags(self, tags):
@@ -153,6 +165,9 @@
                                 date, tagparent, nullid)
             return hex(self.repo.changelog.tip())
 
+    def setfilemapmode(self, active):
+        self.filemapmode = active
+
 class mercurial_source(converter_source):
     def __init__(self, ui, path, rev=None):
         converter_source.__init__(self, ui, path, rev)