diff hgext/convert/hg.py @ 5344:cc34be74eeec

Merge with crew-stable.
author Bryan O'Sullivan <bos@serpentine.com>
date Sat, 29 Sep 2007 21:10:54 -0700
parents 26692d08c2f9 11e1e574da02
children 9c0f864fddca 4fbd27bf04b1
line wrap: on
line diff
--- a/hgext/convert/hg.py
+++ b/hgext/convert/hg.py
@@ -1,20 +1,45 @@
 # hg backend for convert extension
 
+# Note for hg->hg conversion: Old versions of Mercurial didn't trim
+# the whitespace from the ends of commit messages, but new versions
+# do.  Changesets created by those older versions, then converted, may
+# thus have different hashes for changesets that are otherwise
+# identical.
+
+
 import os, time
-from mercurial import hg
+from mercurial.i18n import _
+from mercurial.node import *
+from mercurial import hg, lock, revlog, util
 
-from common import NoRepo, converter_sink
+from common import NoRepo, commit, converter_source, converter_sink
 
-class convert_mercurial(converter_sink):
+class mercurial_sink(converter_sink):
     def __init__(self, ui, path):
         self.path = path
         self.ui = ui
+        self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
+        self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
+        self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
+        self.lastbranch = None
         try:
             self.repo = hg.repository(self.ui, path)
         except:
-            raise NoRepo("could open hg repo %s" % path)
+            raise NoRepo("could not open hg repo %s as sink" % path)
+        self.lock = None
+        self.wlock = None
 
-    def mapfile(self):
+    def before(self):
+        self.wlock = self.repo.wlock()
+        self.lock = self.repo.lock()
+        self.repo.dirstate.clear()
+
+    def after(self):
+        self.repo.dirstate.invalidate()
+        self.lock = None
+        self.wlock = None
+
+    def revmapfile(self):
         return os.path.join(self.path, ".hg", "shamap")
 
     def authorfile(self):
@@ -22,12 +47,15 @@ class convert_mercurial(converter_sink):
 
     def getheads(self):
         h = self.repo.changelog.heads()
-        return [ hg.hex(x) for x in h ]
+        return [ hex(x) for x in h ]
 
     def putfile(self, f, e, data):
         self.repo.wwrite(f, data, e)
-        if self.repo.dirstate.state(f) == '?':
-            self.repo.dirstate.update([f], "a")
+        if f not in self.repo.dirstate:
+            self.repo.dirstate.normallookup(f)
+
+    def copyfile(self, source, dest):
+        self.repo.copy(source, dest)
 
     def delfile(self, f):
         try:
@@ -36,6 +64,30 @@ class convert_mercurial(converter_sink):
         except:
             pass
 
+    def setbranch(self, branch, pbranch, parents):
+        if (not self.clonebranches) or (branch == self.lastbranch):
+            return
+
+        self.lastbranch = branch
+        self.after()
+        if not branch:
+            branch = 'default'
+        if not pbranch:
+            pbranch = 'default'
+
+        branchpath = os.path.join(self.path, branch)
+        try:
+            self.repo = hg.repository(self.ui, branchpath)
+        except:
+            if not parents:
+                self.repo = hg.repository(self.ui, branchpath, create=True)
+            else:
+                self.ui.note(_('cloning branch %s to %s\n') % (pbranch, branch))
+                hg.clone(self.ui, os.path.join(self.path, pbranch),
+                         branchpath, rev=parents, update=False,
+                         stream=True)
+                self.repo = hg.repository(self.ui, branchpath)
+
     def putcommit(self, files, parents, commit):
         seen = {}
         pl = []
@@ -51,16 +103,17 @@ class convert_mercurial(converter_sink):
 
         text = commit.desc
         extra = {}
-        try:
-            extra["branch"] = commit.branch
-        except AttributeError:
-            pass
+        if self.branchnames and commit.branch:
+            extra['branch'] = commit.branch
+        if commit.rev:
+            extra['convert_revision'] = commit.rev
 
         while parents:
             p1 = p2
             p2 = parents.pop(0)
             a = self.repo.rawcommit(files, text, commit.author, commit.date,
-                                    hg.bin(p1), hg.bin(p2), extra=extra)
+                                    bin(p1), bin(p2), extra=extra)
+            self.repo.dirstate.clear()
             text = "(octopus merge fixup)\n"
             p2 = hg.hex(self.repo.changelog.tip())
 
@@ -89,6 +142,69 @@ class convert_mercurial(converter_sink):
             f.close()
             if not oldlines: self.repo.add([".hgtags"])
             date = "%s 0" % int(time.mktime(time.gmtime()))
+            extra = {}
+            if self.tagsbranch != 'default':
+                extra['branch'] = self.tagsbranch
+            try:
+                tagparent = self.repo.changectx(self.tagsbranch).node()
+            except hg.RepoError, inst:
+                tagparent = nullid
             self.repo.rawcommit([".hgtags"], "update tags", "convert-repo",
-                                date, self.repo.changelog.tip(), hg.nullid)
-            return hg.hex(self.repo.changelog.tip())
+                                date, tagparent, nullid)
+            return hex(self.repo.changelog.tip())
+
+class mercurial_source(converter_source):
+    def __init__(self, ui, path, rev=None):
+        converter_source.__init__(self, ui, path, rev)
+        self.repo = hg.repository(self.ui, path)
+        self.lastrev = None
+        self.lastctx = None
+
+    def changectx(self, rev):
+        if self.lastrev != rev:
+            self.lastctx = self.repo.changectx(rev)
+            self.lastrev = rev
+        return self.lastctx
+
+    def getheads(self):
+        if self.rev:
+            return [hex(self.repo.changectx(self.rev).node())]
+        else:
+            return [hex(node) for node in self.repo.heads()]
+
+    def getfile(self, name, rev):
+        try:
+            return self.changectx(rev).filectx(name).data()
+        except revlog.LookupError, err:
+            raise IOError(err)
+
+    def getmode(self, name, rev):
+        m = self.changectx(rev).manifest()
+        return (m.execf(name) and 'x' or '') + (m.linkf(name) and 'l' or '')
+
+    def getchanges(self, rev):
+        ctx = self.changectx(rev)
+        m, a, r = self.repo.status(ctx.parents()[0].node(), ctx.node())[:3]
+        changes = [(name, rev) for name in m + a + r]
+        changes.sort()
+        return (changes, self.getcopies(ctx, m + a))
+
+    def getcopies(self, ctx, files):
+        copies = {}
+        for name in files:
+            try:
+                copies[name] = ctx.filectx(name).renamed()[0]
+            except TypeError:
+                pass
+        return copies
+
+    def getcommit(self, rev):
+        ctx = self.changectx(rev)
+        parents = [hex(p.node()) for p in ctx.parents() if p.node() != nullid]
+        return commit(author=ctx.user(), date=util.datestr(ctx.date()),
+                      desc=ctx.description(), parents=parents,
+                      branch=ctx.branch())
+
+    def gettags(self):
+        tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
+        return dict([(name, hex(node)) for name, node in tags])