|
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 |