diff hgext/convert/git.py @ 4536:cc9b79216a76

Split convert extension into common and repository type modules
author Brendan Cully <brendan@kublai.com>
date Sun, 10 Jun 2007 20:08:47 -0700
parents hgext/convert/__init__.py@c3a78a49d7f0
children 06a0e0557edc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/convert/git.py	Sun Jun 10 20:08:47 2007 -0700
@@ -0,0 +1,103 @@
+# git support for the convert extension
+
+import os
+
+from common import NoRepo, commit, converter_source
+
+def recode(s):
+    try:
+        return s.decode("utf-8").encode("utf-8")
+    except:
+        try:
+            return s.decode("latin-1").encode("utf-8")
+        except:
+            return s.decode("utf-8", "replace").encode("utf-8")
+
+class convert_git(converter_source):
+    def __init__(self, ui, path):
+        if os.path.isdir(path + "/.git"):
+            path += "/.git"
+        self.path = path
+        self.ui = ui
+        if not os.path.exists(path + "/objects"):
+            raise NoRepo("couldn't open GIT repo %s" % path)
+
+    def getheads(self):
+        fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
+        return [fh.read()[:-1]]
+
+    def catfile(self, rev, type):
+        if rev == "0" * 40: raise IOError()
+        fh = os.popen("GIT_DIR=%s git-cat-file %s %s 2>/dev/null"
+                      % (self.path, type, rev))
+        return fh.read()
+
+    def getfile(self, name, rev):
+        return self.catfile(rev, "blob")
+
+    def getmode(self, name, rev):
+        return self.modecache[(name, rev)]
+
+    def getchanges(self, version):
+        self.modecache = {}
+        fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s"
+                      % (self.path, version))
+        changes = []
+        for l in fh:
+            if "\t" not in l: continue
+            m, f = l[:-1].split("\t")
+            m = m.split()
+            h = m[3]
+            p = (m[1] == "100755")
+            s = (m[1] == "120000")
+            self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
+            changes.append((f, h))
+        return changes
+
+    def getcommit(self, version):
+        c = self.catfile(version, "commit") # read the commit hash
+        end = c.find("\n\n")
+        message = c[end+2:]
+        message = recode(message)
+        l = c[:end].splitlines()
+        manifest = l[0].split()[1]
+        parents = []
+        for e in l[1:]:
+            n, v = e.split(" ", 1)
+            if n == "author":
+                p = v.split()
+                tm, tz = p[-2:]
+                author = " ".join(p[:-2])
+                if author[0] == "<": author = author[1:-1]
+                author = recode(author)
+            if n == "committer":
+                p = v.split()
+                tm, tz = p[-2:]
+                committer = " ".join(p[:-2])
+                if committer[0] == "<": committer = committer[1:-1]
+                committer = recode(committer)
+                message += "\ncommitter: %s\n" % committer
+            if n == "parent": parents.append(v)
+
+        tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
+        tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
+        date = tm + " " + str(tz)
+
+        c = commit(parents=parents, date=date, author=author, desc=message)
+        return c
+
+    def gettags(self):
+        tags = {}
+        fh = os.popen('git-ls-remote --tags "%s" 2>/dev/null' % self.path)
+        prefix = 'refs/tags/'
+        for line in fh:
+            line = line.strip()
+            if not line.endswith("^{}"):
+                continue
+            node, tag = line.split(None, 1)
+            if not tag.startswith(prefix):
+                continue
+            tag = tag[len(prefix):-3]
+            tags[tag] = node
+
+        return tags