hgext/convert/git.py
changeset 4534 cc9b79216a76
parent 4532 c3a78a49d7f0
child 4687 06a0e0557edc
equal deleted inserted replaced
4533:36abb07c79d4 4534:cc9b79216a76
       
     1 # git support for the convert extension
       
     2 
       
     3 import os
       
     4 
       
     5 from common import NoRepo, commit, converter_source
       
     6 
       
     7 def recode(s):
       
     8     try:
       
     9         return s.decode("utf-8").encode("utf-8")
       
    10     except:
       
    11         try:
       
    12             return s.decode("latin-1").encode("utf-8")
       
    13         except:
       
    14             return s.decode("utf-8", "replace").encode("utf-8")
       
    15 
       
    16 class convert_git(converter_source):
       
    17     def __init__(self, ui, path):
       
    18         if os.path.isdir(path + "/.git"):
       
    19             path += "/.git"
       
    20         self.path = path
       
    21         self.ui = ui
       
    22         if not os.path.exists(path + "/objects"):
       
    23             raise NoRepo("couldn't open GIT repo %s" % path)
       
    24 
       
    25     def getheads(self):
       
    26         fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
       
    27         return [fh.read()[:-1]]
       
    28 
       
    29     def catfile(self, rev, type):
       
    30         if rev == "0" * 40: raise IOError()
       
    31         fh = os.popen("GIT_DIR=%s git-cat-file %s %s 2>/dev/null"
       
    32                       % (self.path, type, rev))
       
    33         return fh.read()
       
    34 
       
    35     def getfile(self, name, rev):
       
    36         return self.catfile(rev, "blob")
       
    37 
       
    38     def getmode(self, name, rev):
       
    39         return self.modecache[(name, rev)]
       
    40 
       
    41     def getchanges(self, version):
       
    42         self.modecache = {}
       
    43         fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s"
       
    44                       % (self.path, version))
       
    45         changes = []
       
    46         for l in fh:
       
    47             if "\t" not in l: continue
       
    48             m, f = l[:-1].split("\t")
       
    49             m = m.split()
       
    50             h = m[3]
       
    51             p = (m[1] == "100755")
       
    52             s = (m[1] == "120000")
       
    53             self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
       
    54             changes.append((f, h))
       
    55         return changes
       
    56 
       
    57     def getcommit(self, version):
       
    58         c = self.catfile(version, "commit") # read the commit hash
       
    59         end = c.find("\n\n")
       
    60         message = c[end+2:]
       
    61         message = recode(message)
       
    62         l = c[:end].splitlines()
       
    63         manifest = l[0].split()[1]
       
    64         parents = []
       
    65         for e in l[1:]:
       
    66             n, v = e.split(" ", 1)
       
    67             if n == "author":
       
    68                 p = v.split()
       
    69                 tm, tz = p[-2:]
       
    70                 author = " ".join(p[:-2])
       
    71                 if author[0] == "<": author = author[1:-1]
       
    72                 author = recode(author)
       
    73             if n == "committer":
       
    74                 p = v.split()
       
    75                 tm, tz = p[-2:]
       
    76                 committer = " ".join(p[:-2])
       
    77                 if committer[0] == "<": committer = committer[1:-1]
       
    78                 committer = recode(committer)
       
    79                 message += "\ncommitter: %s\n" % committer
       
    80             if n == "parent": parents.append(v)
       
    81 
       
    82         tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
       
    83         tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
       
    84         date = tm + " " + str(tz)
       
    85 
       
    86         c = commit(parents=parents, date=date, author=author, desc=message)
       
    87         return c
       
    88 
       
    89     def gettags(self):
       
    90         tags = {}
       
    91         fh = os.popen('git-ls-remote --tags "%s" 2>/dev/null' % self.path)
       
    92         prefix = 'refs/tags/'
       
    93         for line in fh:
       
    94             line = line.strip()
       
    95             if not line.endswith("^{}"):
       
    96                 continue
       
    97             node, tag = line.split(None, 1)
       
    98             if not tag.startswith(prefix):
       
    99                 continue
       
   100             tag = tag[len(prefix):-3]
       
   101             tags[tag] = node
       
   102 
       
   103         return tags