convert-repo: add some smarts
authorMatt Mackall <mpm@selenic.com>
Wed, 20 Dec 2006 16:31:46 -0600
changeset 3938 0fab73b3f453
parent 3937 ac02810132ca
child 3939 b58c1681d23b
convert-repo: add some smarts autodetect source and destination repo types autodetect read and write capabilities of converters default destination directory (<src>-hg) default map file (<dest>/.hg/shamap) more verbose by default add a -q switch add IO functions
contrib/convert-repo
--- a/contrib/convert-repo	Wed Dec 20 13:11:35 2006 -0600
+++ b/contrib/convert-repo	Wed Dec 20 16:31:46 2006 -0600
@@ -22,10 +22,20 @@
 # be run repeatedly to copy new commits.
 
 import sys, os, zlib, sha, time
+os.environ["HGENCODING"] = "utf-8"
+from mercurial import hg, ui, util, fancyopts
 
-os.environ["HGENCODING"] = "utf-8"
+class Abort(Exception): pass
+
+quiet = 0
+def status(msg):
+    if not quiet: sys.stdout.write(str(msg))
 
-from mercurial import hg, ui, util
+def warn(msg):
+    sys.stderr.write(str(msg))
+
+def abort(msg):
+    raise Abort(msg)
 
 def recode(s):
     try:
@@ -38,7 +48,11 @@
 
 class convert_git:
     def __init__(self, path):
+        if os.path.isdir(path + "/.git"):
+            path += "/.git"
         self.path = path
+        if not os.path.exists(path + "/HEAD"):
+            raise TypeError("couldn't open GIT repo %s" % path)
 
     def getheads(self):
         fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
@@ -110,7 +124,13 @@
     def __init__(self, path):
         self.path = path
         u = ui.ui()
-        self.repo = hg.repository(u, path)
+        try:
+            self.repo = hg.repository(u, path)
+        except:
+            raise TypeError("could open hg repo %s" % path)
+
+    def mapfile(self):
+        return os.path.join(self.path, ".hg", "shamap")
 
     def getheads(self):
         h = self.repo.changelog.heads()
@@ -170,7 +190,7 @@
         newlines.sort()
 
         if newlines != oldlines:
-            #print "updating tags"
+            status("updating tags\n")
             f = self.repo.wfile(".hgtags", "w")
             f.write("".join(newlines))
             f.close()
@@ -180,8 +200,21 @@
                                 date, self.repo.changelog.tip(), hg.nullid)
             return hg.hex(self.repo.changelog.tip())
 
+converters = [convert_git, convert_mercurial]
+
+def converter(path):
+    if not os.path.isdir(path):
+        abort("%s: not a directory\n" % path)
+    for c in converters:
+        try:
+            return c(path)
+        except TypeError:
+            pass
+    abort("%s: unknown repository type\n" % path)
+
 class convert:
     def __init__(self, source, dest, mapfile):
+
         self.source = source
         self.dest = dest
         self.mapfile = mapfile
@@ -272,17 +305,20 @@
         file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev]))
 
     def convert(self):
+        status("scanning source...\n")
         heads = self.source.getheads()
         parents = self.walktree(heads)
+        status("sorting...\n")
         t = self.toposort(parents)
         t = [n for n in t if n not in self.map]
         num = len(t)
         c = None
 
+        status("converting...\n")
         for c in t:
             num -= 1
             desc = self.commitcache[c][3].splitlines()[0]
-            #print num, desc
+            status("%d %s\n" % (num, desc))
             self.copy(c)
 
         tags = self.source.gettags()
@@ -299,9 +335,40 @@
             if nrev:
                 file(self.mapfile, "a").write("%s %s\n" % (c, nrev))
 
-gitpath, hgpath, mapfile = sys.argv[1:]
-if os.path.isdir(gitpath + "/.git"):
-    gitpath += "/.git"
+def command(src, dest=None, mapfile=None, **opts):
+    srcc = converter(src)
+    if not hasattr(srcc, "getcommit"):
+        abort("%s: can't read from this repo type\n" % src)
+
+    if not dest:
+        dest = src + "-hg"
+        status("assuming destination %s\n" % dest)
+        if not os.path.isdir(dest):
+            status("creating repository %s\n" % dest)
+            os.system("hg init " + dest)
+    destc = converter(dest)
+    if not hasattr(destc, "putcommit"):
+        abort("%s: can't write to this repo type\n" % src)
 
-c = convert(convert_git(gitpath), convert_mercurial(hgpath), mapfile)
-c.convert()
+    if not mapfile:
+        try:
+            mapfile = destc.mapfile()
+        except:
+            mapfile = os.path.join(destc, "map")
+
+    c = convert(srcc, destc, mapfile)
+    c.convert()
+
+options = [('q', 'quiet', None, 'suppress output')]
+opts = {}
+args = fancyopts.fancyopts(sys.argv[1:], options, opts)
+
+if opts['quiet']:
+    quiet = 1
+
+try:
+    command(*args, **opts)
+except Abort, inst:
+    warn(inst)
+except KeyboardInterrupt:
+    status("interrupted\n")