##// END OF EJS Templates
convert: support non annotated tags in git backend...
Edouard Gomez -
r16259:589aab2c default
parent child Browse files
Show More
@@ -1,205 +1,215
1 1 # git.py - git support for the convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import os
9 9 from mercurial import util
10 10 from mercurial.node import hex, nullid
11 11 from mercurial.i18n import _
12 12
13 13 from common import NoRepo, commit, converter_source, checktool
14 14
15 15 class convert_git(converter_source):
16 16 # Windows does not support GIT_DIR= construct while other systems
17 17 # cannot remove environment variable. Just assume none have
18 18 # both issues.
19 19 if util.safehasattr(os, 'unsetenv'):
20 20 def gitopen(self, s, noerr=False):
21 21 prevgitdir = os.environ.get('GIT_DIR')
22 22 os.environ['GIT_DIR'] = self.path
23 23 try:
24 24 if noerr:
25 25 (stdin, stdout, stderr) = util.popen3(s)
26 26 return stdout
27 27 else:
28 28 return util.popen(s, 'rb')
29 29 finally:
30 30 if prevgitdir is None:
31 31 del os.environ['GIT_DIR']
32 32 else:
33 33 os.environ['GIT_DIR'] = prevgitdir
34 34 else:
35 35 def gitopen(self, s, noerr=False):
36 36 if noerr:
37 37 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
38 38 return so
39 39 else:
40 40 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
41 41
42 42 def gitread(self, s):
43 43 fh = self.gitopen(s)
44 44 data = fh.read()
45 45 return data, fh.close()
46 46
47 47 def __init__(self, ui, path, rev=None):
48 48 super(convert_git, self).__init__(ui, path, rev=rev)
49 49
50 50 if os.path.isdir(path + "/.git"):
51 51 path += "/.git"
52 52 if not os.path.exists(path + "/objects"):
53 53 raise NoRepo(_("%s does not look like a Git repository") % path)
54 54
55 55 checktool('git', 'git')
56 56
57 57 self.path = path
58 58
59 59 def getheads(self):
60 60 if not self.rev:
61 61 heads, ret = self.gitread('git rev-parse --branches --remotes')
62 62 heads = heads.splitlines()
63 63 else:
64 64 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
65 65 heads = [heads[:-1]]
66 66 if ret:
67 67 raise util.Abort(_('cannot retrieve git heads'))
68 68 return heads
69 69
70 70 def catfile(self, rev, type):
71 71 if rev == hex(nullid):
72 72 raise IOError()
73 73 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
74 74 if ret:
75 75 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
76 76 return data
77 77
78 78 def getfile(self, name, rev):
79 79 data = self.catfile(rev, "blob")
80 80 mode = self.modecache[(name, rev)]
81 81 return data, mode
82 82
83 83 def getchanges(self, version):
84 84 self.modecache = {}
85 85 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
86 86 changes = []
87 87 seen = set()
88 88 entry = None
89 89 for l in fh.read().split('\x00'):
90 90 if not entry:
91 91 if not l.startswith(':'):
92 92 continue
93 93 entry = l
94 94 continue
95 95 f = l
96 96 if f not in seen:
97 97 seen.add(f)
98 98 entry = entry.split()
99 99 h = entry[3]
100 100 p = (entry[1] == "100755")
101 101 s = (entry[1] == "120000")
102 102 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
103 103 changes.append((f, h))
104 104 entry = None
105 105 if fh.close():
106 106 raise util.Abort(_('cannot read changes in %s') % version)
107 107 return (changes, {})
108 108
109 109 def getcommit(self, version):
110 110 c = self.catfile(version, "commit") # read the commit hash
111 111 end = c.find("\n\n")
112 112 message = c[end + 2:]
113 113 message = self.recode(message)
114 114 l = c[:end].splitlines()
115 115 parents = []
116 116 author = committer = None
117 117 for e in l[1:]:
118 118 n, v = e.split(" ", 1)
119 119 if n == "author":
120 120 p = v.split()
121 121 tm, tz = p[-2:]
122 122 author = " ".join(p[:-2])
123 123 if author[0] == "<": author = author[1:-1]
124 124 author = self.recode(author)
125 125 if n == "committer":
126 126 p = v.split()
127 127 tm, tz = p[-2:]
128 128 committer = " ".join(p[:-2])
129 129 if committer[0] == "<": committer = committer[1:-1]
130 130 committer = self.recode(committer)
131 131 if n == "parent":
132 132 parents.append(v)
133 133
134 134 if committer and committer != author:
135 135 message += "\ncommitter: %s\n" % committer
136 136 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
137 137 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
138 138 date = tm + " " + str(tz)
139 139
140 140 c = commit(parents=parents, date=date, author=author, desc=message,
141 141 rev=version)
142 142 return c
143 143
144 144 def gettags(self):
145 145 tags = {}
146 alltags = {}
146 147 fh = self.gitopen('git ls-remote --tags "%s"' % self.path)
147 148 prefix = 'refs/tags/'
149
150 # Build complete list of tags, both annotated and bare ones
148 151 for line in fh:
149 152 line = line.strip()
150 if not line.endswith("^{}"):
151 continue
152 153 node, tag = line.split(None, 1)
153 154 if not tag.startswith(prefix):
154 155 continue
155 tag = tag[len(prefix):-3]
156 tags[tag] = node
156 alltags[tag[len(prefix):]] = node
157 157 if fh.close():
158 158 raise util.Abort(_('cannot read tags from %s') % self.path)
159 159
160 # Filter out tag objects for annotated tag refs
161 for tag in alltags:
162 if tag.endswith('^{}'):
163 tags[tag[:-3]] = alltags[tag]
164 else:
165 if tag + '^{}' in alltags:
166 continue
167 else:
168 tags[tag] = alltags[tag]
169
160 170 return tags
161 171
162 172 def getchangedfiles(self, version, i):
163 173 changes = []
164 174 if i is None:
165 175 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
166 176 for l in fh:
167 177 if "\t" not in l:
168 178 continue
169 179 m, f = l[:-1].split("\t")
170 180 changes.append(f)
171 181 else:
172 182 fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
173 183 % (version, version, i + 1))
174 184 changes = [f.rstrip('\n') for f in fh]
175 185 if fh.close():
176 186 raise util.Abort(_('cannot read changes in %s') % version)
177 187
178 188 return changes
179 189
180 190 def getbookmarks(self):
181 191 bookmarks = {}
182 192
183 193 # Interesting references in git are prefixed
184 194 prefix = 'refs/heads/'
185 195 prefixlen = len(prefix)
186 196
187 197 # factor two commands
188 198 gitcmd = { 'remote/': 'git ls-remote --heads origin',
189 199 '': 'git show-ref'}
190 200
191 201 # Origin heads
192 202 for reftype in gitcmd:
193 203 try:
194 204 fh = self.gitopen(gitcmd[reftype], noerr=True)
195 205 for line in fh:
196 206 line = line.strip()
197 207 rev, name = line.split(None, 1)
198 208 if not name.startswith(prefix):
199 209 continue
200 210 name = '%s%s' % (reftype, name[prefixlen:])
201 211 bookmarks[name] = rev
202 212 except:
203 213 pass
204 214
205 215 return bookmarks
General Comments 0
You need to be logged in to leave comments. Login now