##// END OF EJS Templates
style: remove multiple statement on a single line...
Boris Feld -
r35646:ab11af15 default
parent child Browse files
Show More
@@ -1,476 +1,478 b''
1 # git.py - git support for the convert extension
1 # git.py - git support for the convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import os
9 import os
10
10
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial import (
12 from mercurial import (
13 config,
13 config,
14 error,
14 error,
15 node as nodemod,
15 node as nodemod,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 common,
19 common,
20 )
20 )
21
21
22 class submodule(object):
22 class submodule(object):
23 def __init__(self, path, node, url):
23 def __init__(self, path, node, url):
24 self.path = path
24 self.path = path
25 self.node = node
25 self.node = node
26 self.url = url
26 self.url = url
27
27
28 def hgsub(self):
28 def hgsub(self):
29 return "%s = [git]%s" % (self.path, self.url)
29 return "%s = [git]%s" % (self.path, self.url)
30
30
31 def hgsubstate(self):
31 def hgsubstate(self):
32 return "%s %s" % (self.node, self.path)
32 return "%s %s" % (self.node, self.path)
33
33
34 # Keys in extra fields that should not be copied if the user requests.
34 # Keys in extra fields that should not be copied if the user requests.
35 bannedextrakeys = {
35 bannedextrakeys = {
36 # Git commit object built-ins.
36 # Git commit object built-ins.
37 'tree',
37 'tree',
38 'parent',
38 'parent',
39 'author',
39 'author',
40 'committer',
40 'committer',
41 # Mercurial built-ins.
41 # Mercurial built-ins.
42 'branch',
42 'branch',
43 'close',
43 'close',
44 }
44 }
45
45
46 class convert_git(common.converter_source, common.commandline):
46 class convert_git(common.converter_source, common.commandline):
47 # Windows does not support GIT_DIR= construct while other systems
47 # Windows does not support GIT_DIR= construct while other systems
48 # cannot remove environment variable. Just assume none have
48 # cannot remove environment variable. Just assume none have
49 # both issues.
49 # both issues.
50
50
51 def _gitcmd(self, cmd, *args, **kwargs):
51 def _gitcmd(self, cmd, *args, **kwargs):
52 return cmd('--git-dir=%s' % self.path, *args, **kwargs)
52 return cmd('--git-dir=%s' % self.path, *args, **kwargs)
53
53
54 def gitrun0(self, *args, **kwargs):
54 def gitrun0(self, *args, **kwargs):
55 return self._gitcmd(self.run0, *args, **kwargs)
55 return self._gitcmd(self.run0, *args, **kwargs)
56
56
57 def gitrun(self, *args, **kwargs):
57 def gitrun(self, *args, **kwargs):
58 return self._gitcmd(self.run, *args, **kwargs)
58 return self._gitcmd(self.run, *args, **kwargs)
59
59
60 def gitrunlines0(self, *args, **kwargs):
60 def gitrunlines0(self, *args, **kwargs):
61 return self._gitcmd(self.runlines0, *args, **kwargs)
61 return self._gitcmd(self.runlines0, *args, **kwargs)
62
62
63 def gitrunlines(self, *args, **kwargs):
63 def gitrunlines(self, *args, **kwargs):
64 return self._gitcmd(self.runlines, *args, **kwargs)
64 return self._gitcmd(self.runlines, *args, **kwargs)
65
65
66 def gitpipe(self, *args, **kwargs):
66 def gitpipe(self, *args, **kwargs):
67 return self._gitcmd(self._run3, *args, **kwargs)
67 return self._gitcmd(self._run3, *args, **kwargs)
68
68
69 def __init__(self, ui, repotype, path, revs=None):
69 def __init__(self, ui, repotype, path, revs=None):
70 super(convert_git, self).__init__(ui, repotype, path, revs=revs)
70 super(convert_git, self).__init__(ui, repotype, path, revs=revs)
71 common.commandline.__init__(self, ui, 'git')
71 common.commandline.__init__(self, ui, 'git')
72
72
73 # Pass an absolute path to git to prevent from ever being interpreted
73 # Pass an absolute path to git to prevent from ever being interpreted
74 # as a URL
74 # as a URL
75 path = os.path.abspath(path)
75 path = os.path.abspath(path)
76
76
77 if os.path.isdir(path + "/.git"):
77 if os.path.isdir(path + "/.git"):
78 path += "/.git"
78 path += "/.git"
79 if not os.path.exists(path + "/objects"):
79 if not os.path.exists(path + "/objects"):
80 raise common.NoRepo(_("%s does not look like a Git repository") %
80 raise common.NoRepo(_("%s does not look like a Git repository") %
81 path)
81 path)
82
82
83 # The default value (50) is based on the default for 'git diff'.
83 # The default value (50) is based on the default for 'git diff'.
84 similarity = ui.configint('convert', 'git.similarity')
84 similarity = ui.configint('convert', 'git.similarity')
85 if similarity < 0 or similarity > 100:
85 if similarity < 0 or similarity > 100:
86 raise error.Abort(_('similarity must be between 0 and 100'))
86 raise error.Abort(_('similarity must be between 0 and 100'))
87 if similarity > 0:
87 if similarity > 0:
88 self.simopt = ['-C%d%%' % similarity]
88 self.simopt = ['-C%d%%' % similarity]
89 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder')
89 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder')
90 if findcopiesharder:
90 if findcopiesharder:
91 self.simopt.append('--find-copies-harder')
91 self.simopt.append('--find-copies-harder')
92
92
93 renamelimit = ui.configint('convert', 'git.renamelimit')
93 renamelimit = ui.configint('convert', 'git.renamelimit')
94 self.simopt.append('-l%d' % renamelimit)
94 self.simopt.append('-l%d' % renamelimit)
95 else:
95 else:
96 self.simopt = []
96 self.simopt = []
97
97
98 common.checktool('git', 'git')
98 common.checktool('git', 'git')
99
99
100 self.path = path
100 self.path = path
101 self.submodules = []
101 self.submodules = []
102
102
103 self.catfilepipe = self.gitpipe('cat-file', '--batch')
103 self.catfilepipe = self.gitpipe('cat-file', '--batch')
104
104
105 self.copyextrakeys = self.ui.configlist('convert', 'git.extrakeys')
105 self.copyextrakeys = self.ui.configlist('convert', 'git.extrakeys')
106 banned = set(self.copyextrakeys) & bannedextrakeys
106 banned = set(self.copyextrakeys) & bannedextrakeys
107 if banned:
107 if banned:
108 raise error.Abort(_('copying of extra key is forbidden: %s') %
108 raise error.Abort(_('copying of extra key is forbidden: %s') %
109 _(', ').join(sorted(banned)))
109 _(', ').join(sorted(banned)))
110
110
111 committeractions = self.ui.configlist('convert', 'git.committeractions')
111 committeractions = self.ui.configlist('convert', 'git.committeractions')
112
112
113 messagedifferent = None
113 messagedifferent = None
114 messagealways = None
114 messagealways = None
115 for a in committeractions:
115 for a in committeractions:
116 if a.startswith(('messagedifferent', 'messagealways')):
116 if a.startswith(('messagedifferent', 'messagealways')):
117 k = a
117 k = a
118 v = None
118 v = None
119 if '=' in a:
119 if '=' in a:
120 k, v = a.split('=', 1)
120 k, v = a.split('=', 1)
121
121
122 if k == 'messagedifferent':
122 if k == 'messagedifferent':
123 messagedifferent = v or 'committer:'
123 messagedifferent = v or 'committer:'
124 elif k == 'messagealways':
124 elif k == 'messagealways':
125 messagealways = v or 'committer:'
125 messagealways = v or 'committer:'
126
126
127 if messagedifferent and messagealways:
127 if messagedifferent and messagealways:
128 raise error.Abort(_('committeractions cannot define both '
128 raise error.Abort(_('committeractions cannot define both '
129 'messagedifferent and messagealways'))
129 'messagedifferent and messagealways'))
130
130
131 dropcommitter = 'dropcommitter' in committeractions
131 dropcommitter = 'dropcommitter' in committeractions
132 replaceauthor = 'replaceauthor' in committeractions
132 replaceauthor = 'replaceauthor' in committeractions
133
133
134 if dropcommitter and replaceauthor:
134 if dropcommitter and replaceauthor:
135 raise error.Abort(_('committeractions cannot define both '
135 raise error.Abort(_('committeractions cannot define both '
136 'dropcommitter and replaceauthor'))
136 'dropcommitter and replaceauthor'))
137
137
138 if dropcommitter and messagealways:
138 if dropcommitter and messagealways:
139 raise error.Abort(_('committeractions cannot define both '
139 raise error.Abort(_('committeractions cannot define both '
140 'dropcommitter and messagealways'))
140 'dropcommitter and messagealways'))
141
141
142 if not messagedifferent and not messagealways:
142 if not messagedifferent and not messagealways:
143 messagedifferent = 'committer:'
143 messagedifferent = 'committer:'
144
144
145 self.committeractions = {
145 self.committeractions = {
146 'dropcommitter': dropcommitter,
146 'dropcommitter': dropcommitter,
147 'replaceauthor': replaceauthor,
147 'replaceauthor': replaceauthor,
148 'messagedifferent': messagedifferent,
148 'messagedifferent': messagedifferent,
149 'messagealways': messagealways,
149 'messagealways': messagealways,
150 }
150 }
151
151
152 def after(self):
152 def after(self):
153 for f in self.catfilepipe:
153 for f in self.catfilepipe:
154 f.close()
154 f.close()
155
155
156 def getheads(self):
156 def getheads(self):
157 if not self.revs:
157 if not self.revs:
158 output, status = self.gitrun('rev-parse', '--branches', '--remotes')
158 output, status = self.gitrun('rev-parse', '--branches', '--remotes')
159 heads = output.splitlines()
159 heads = output.splitlines()
160 if status:
160 if status:
161 raise error.Abort(_('cannot retrieve git heads'))
161 raise error.Abort(_('cannot retrieve git heads'))
162 else:
162 else:
163 heads = []
163 heads = []
164 for rev in self.revs:
164 for rev in self.revs:
165 rawhead, ret = self.gitrun('rev-parse', '--verify', rev)
165 rawhead, ret = self.gitrun('rev-parse', '--verify', rev)
166 heads.append(rawhead[:-1])
166 heads.append(rawhead[:-1])
167 if ret:
167 if ret:
168 raise error.Abort(_('cannot retrieve git head "%s"') % rev)
168 raise error.Abort(_('cannot retrieve git head "%s"') % rev)
169 return heads
169 return heads
170
170
171 def catfile(self, rev, type):
171 def catfile(self, rev, type):
172 if rev == nodemod.nullhex:
172 if rev == nodemod.nullhex:
173 raise IOError
173 raise IOError
174 self.catfilepipe[0].write(rev+'\n')
174 self.catfilepipe[0].write(rev+'\n')
175 self.catfilepipe[0].flush()
175 self.catfilepipe[0].flush()
176 info = self.catfilepipe[1].readline().split()
176 info = self.catfilepipe[1].readline().split()
177 if info[1] != type:
177 if info[1] != type:
178 raise error.Abort(_('cannot read %r object at %s') % (type, rev))
178 raise error.Abort(_('cannot read %r object at %s') % (type, rev))
179 size = int(info[2])
179 size = int(info[2])
180 data = self.catfilepipe[1].read(size)
180 data = self.catfilepipe[1].read(size)
181 if len(data) < size:
181 if len(data) < size:
182 raise error.Abort(_('cannot read %r object at %s: unexpected size')
182 raise error.Abort(_('cannot read %r object at %s: unexpected size')
183 % (type, rev))
183 % (type, rev))
184 # read the trailing newline
184 # read the trailing newline
185 self.catfilepipe[1].read(1)
185 self.catfilepipe[1].read(1)
186 return data
186 return data
187
187
188 def getfile(self, name, rev):
188 def getfile(self, name, rev):
189 if rev == nodemod.nullhex:
189 if rev == nodemod.nullhex:
190 return None, None
190 return None, None
191 if name == '.hgsub':
191 if name == '.hgsub':
192 data = '\n'.join([m.hgsub() for m in self.submoditer()])
192 data = '\n'.join([m.hgsub() for m in self.submoditer()])
193 mode = ''
193 mode = ''
194 elif name == '.hgsubstate':
194 elif name == '.hgsubstate':
195 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
195 data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
196 mode = ''
196 mode = ''
197 else:
197 else:
198 data = self.catfile(rev, "blob")
198 data = self.catfile(rev, "blob")
199 mode = self.modecache[(name, rev)]
199 mode = self.modecache[(name, rev)]
200 return data, mode
200 return data, mode
201
201
202 def submoditer(self):
202 def submoditer(self):
203 null = nodemod.nullhex
203 null = nodemod.nullhex
204 for m in sorted(self.submodules, key=lambda p: p.path):
204 for m in sorted(self.submodules, key=lambda p: p.path):
205 if m.node != null:
205 if m.node != null:
206 yield m
206 yield m
207
207
208 def parsegitmodules(self, content):
208 def parsegitmodules(self, content):
209 """Parse the formatted .gitmodules file, example file format:
209 """Parse the formatted .gitmodules file, example file format:
210 [submodule "sub"]\n
210 [submodule "sub"]\n
211 \tpath = sub\n
211 \tpath = sub\n
212 \turl = git://giturl\n
212 \turl = git://giturl\n
213 """
213 """
214 self.submodules = []
214 self.submodules = []
215 c = config.config()
215 c = config.config()
216 # Each item in .gitmodules starts with whitespace that cant be parsed
216 # Each item in .gitmodules starts with whitespace that cant be parsed
217 c.parse('.gitmodules', '\n'.join(line.strip() for line in
217 c.parse('.gitmodules', '\n'.join(line.strip() for line in
218 content.split('\n')))
218 content.split('\n')))
219 for sec in c.sections():
219 for sec in c.sections():
220 s = c[sec]
220 s = c[sec]
221 if 'url' in s and 'path' in s:
221 if 'url' in s and 'path' in s:
222 self.submodules.append(submodule(s['path'], '', s['url']))
222 self.submodules.append(submodule(s['path'], '', s['url']))
223
223
224 def retrievegitmodules(self, version):
224 def retrievegitmodules(self, version):
225 modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules'))
225 modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules'))
226 if ret:
226 if ret:
227 # This can happen if a file is in the repo that has permissions
227 # This can happen if a file is in the repo that has permissions
228 # 160000, but there is no .gitmodules file.
228 # 160000, but there is no .gitmodules file.
229 self.ui.warn(_("warning: cannot read submodules config file in "
229 self.ui.warn(_("warning: cannot read submodules config file in "
230 "%s\n") % version)
230 "%s\n") % version)
231 return
231 return
232
232
233 try:
233 try:
234 self.parsegitmodules(modules)
234 self.parsegitmodules(modules)
235 except error.ParseError:
235 except error.ParseError:
236 self.ui.warn(_("warning: unable to parse .gitmodules in %s\n")
236 self.ui.warn(_("warning: unable to parse .gitmodules in %s\n")
237 % version)
237 % version)
238 return
238 return
239
239
240 for m in self.submodules:
240 for m in self.submodules:
241 node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path))
241 node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path))
242 if ret:
242 if ret:
243 continue
243 continue
244 m.node = node.strip()
244 m.node = node.strip()
245
245
246 def getchanges(self, version, full):
246 def getchanges(self, version, full):
247 if full:
247 if full:
248 raise error.Abort(_("convert from git does not support --full"))
248 raise error.Abort(_("convert from git does not support --full"))
249 self.modecache = {}
249 self.modecache = {}
250 cmd = ['diff-tree','-z', '--root', '-m', '-r'] + self.simopt + [version]
250 cmd = ['diff-tree','-z', '--root', '-m', '-r'] + self.simopt + [version]
251 output, status = self.gitrun(*cmd)
251 output, status = self.gitrun(*cmd)
252 if status:
252 if status:
253 raise error.Abort(_('cannot read changes in %s') % version)
253 raise error.Abort(_('cannot read changes in %s') % version)
254 changes = []
254 changes = []
255 copies = {}
255 copies = {}
256 seen = set()
256 seen = set()
257 entry = None
257 entry = None
258 subexists = [False]
258 subexists = [False]
259 subdeleted = [False]
259 subdeleted = [False]
260 difftree = output.split('\x00')
260 difftree = output.split('\x00')
261 lcount = len(difftree)
261 lcount = len(difftree)
262 i = 0
262 i = 0
263
263
264 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules')
264 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules')
265 def add(entry, f, isdest):
265 def add(entry, f, isdest):
266 seen.add(f)
266 seen.add(f)
267 h = entry[3]
267 h = entry[3]
268 p = (entry[1] == "100755")
268 p = (entry[1] == "100755")
269 s = (entry[1] == "120000")
269 s = (entry[1] == "120000")
270 renamesource = (not isdest and entry[4][0] == 'R')
270 renamesource = (not isdest and entry[4][0] == 'R')
271
271
272 if f == '.gitmodules':
272 if f == '.gitmodules':
273 if skipsubmodules:
273 if skipsubmodules:
274 return
274 return
275
275
276 subexists[0] = True
276 subexists[0] = True
277 if entry[4] == 'D' or renamesource:
277 if entry[4] == 'D' or renamesource:
278 subdeleted[0] = True
278 subdeleted[0] = True
279 changes.append(('.hgsub', nodemod.nullhex))
279 changes.append(('.hgsub', nodemod.nullhex))
280 else:
280 else:
281 changes.append(('.hgsub', ''))
281 changes.append(('.hgsub', ''))
282 elif entry[1] == '160000' or entry[0] == ':160000':
282 elif entry[1] == '160000' or entry[0] == ':160000':
283 if not skipsubmodules:
283 if not skipsubmodules:
284 subexists[0] = True
284 subexists[0] = True
285 else:
285 else:
286 if renamesource:
286 if renamesource:
287 h = nodemod.nullhex
287 h = nodemod.nullhex
288 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
288 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
289 changes.append((f, h))
289 changes.append((f, h))
290
290
291 while i < lcount:
291 while i < lcount:
292 l = difftree[i]
292 l = difftree[i]
293 i += 1
293 i += 1
294 if not entry:
294 if not entry:
295 if not l.startswith(':'):
295 if not l.startswith(':'):
296 continue
296 continue
297 entry = l.split()
297 entry = l.split()
298 continue
298 continue
299 f = l
299 f = l
300 if entry[4][0] == 'C':
300 if entry[4][0] == 'C':
301 copysrc = f
301 copysrc = f
302 copydest = difftree[i]
302 copydest = difftree[i]
303 i += 1
303 i += 1
304 f = copydest
304 f = copydest
305 copies[copydest] = copysrc
305 copies[copydest] = copysrc
306 if f not in seen:
306 if f not in seen:
307 add(entry, f, False)
307 add(entry, f, False)
308 # A file can be copied multiple times, or modified and copied
308 # A file can be copied multiple times, or modified and copied
309 # simultaneously. So f can be repeated even if fdest isn't.
309 # simultaneously. So f can be repeated even if fdest isn't.
310 if entry[4][0] == 'R':
310 if entry[4][0] == 'R':
311 # rename: next line is the destination
311 # rename: next line is the destination
312 fdest = difftree[i]
312 fdest = difftree[i]
313 i += 1
313 i += 1
314 if fdest not in seen:
314 if fdest not in seen:
315 add(entry, fdest, True)
315 add(entry, fdest, True)
316 # .gitmodules isn't imported at all, so it being copied to
316 # .gitmodules isn't imported at all, so it being copied to
317 # and fro doesn't really make sense
317 # and fro doesn't really make sense
318 if f != '.gitmodules' and fdest != '.gitmodules':
318 if f != '.gitmodules' and fdest != '.gitmodules':
319 copies[fdest] = f
319 copies[fdest] = f
320 entry = None
320 entry = None
321
321
322 if subexists[0]:
322 if subexists[0]:
323 if subdeleted[0]:
323 if subdeleted[0]:
324 changes.append(('.hgsubstate', nodemod.nullhex))
324 changes.append(('.hgsubstate', nodemod.nullhex))
325 else:
325 else:
326 self.retrievegitmodules(version)
326 self.retrievegitmodules(version)
327 changes.append(('.hgsubstate', ''))
327 changes.append(('.hgsubstate', ''))
328 return (changes, copies, set())
328 return (changes, copies, set())
329
329
330 def getcommit(self, version):
330 def getcommit(self, version):
331 c = self.catfile(version, "commit") # read the commit hash
331 c = self.catfile(version, "commit") # read the commit hash
332 end = c.find("\n\n")
332 end = c.find("\n\n")
333 message = c[end + 2:]
333 message = c[end + 2:]
334 message = self.recode(message)
334 message = self.recode(message)
335 l = c[:end].splitlines()
335 l = c[:end].splitlines()
336 parents = []
336 parents = []
337 author = committer = None
337 author = committer = None
338 extra = {}
338 extra = {}
339 for e in l[1:]:
339 for e in l[1:]:
340 n, v = e.split(" ", 1)
340 n, v = e.split(" ", 1)
341 if n == "author":
341 if n == "author":
342 p = v.split()
342 p = v.split()
343 tm, tz = p[-2:]
343 tm, tz = p[-2:]
344 author = " ".join(p[:-2])
344 author = " ".join(p[:-2])
345 if author[0] == "<": author = author[1:-1]
345 if author[0] == "<":
346 author = author[1:-1]
346 author = self.recode(author)
347 author = self.recode(author)
347 if n == "committer":
348 if n == "committer":
348 p = v.split()
349 p = v.split()
349 tm, tz = p[-2:]
350 tm, tz = p[-2:]
350 committer = " ".join(p[:-2])
351 committer = " ".join(p[:-2])
351 if committer[0] == "<": committer = committer[1:-1]
352 if committer[0] == "<":
353 committer = committer[1:-1]
352 committer = self.recode(committer)
354 committer = self.recode(committer)
353 if n == "parent":
355 if n == "parent":
354 parents.append(v)
356 parents.append(v)
355 if n in self.copyextrakeys:
357 if n in self.copyextrakeys:
356 extra[n] = v
358 extra[n] = v
357
359
358 if self.committeractions['dropcommitter']:
360 if self.committeractions['dropcommitter']:
359 committer = None
361 committer = None
360 elif self.committeractions['replaceauthor']:
362 elif self.committeractions['replaceauthor']:
361 author = committer
363 author = committer
362
364
363 if committer:
365 if committer:
364 messagealways = self.committeractions['messagealways']
366 messagealways = self.committeractions['messagealways']
365 messagedifferent = self.committeractions['messagedifferent']
367 messagedifferent = self.committeractions['messagedifferent']
366 if messagealways:
368 if messagealways:
367 message += '\n%s %s\n' % (messagealways, committer)
369 message += '\n%s %s\n' % (messagealways, committer)
368 elif messagedifferent and author != committer:
370 elif messagedifferent and author != committer:
369 message += '\n%s %s\n' % (messagedifferent, committer)
371 message += '\n%s %s\n' % (messagedifferent, committer)
370
372
371 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
373 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
372 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
374 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
373 date = tm + " " + str(tz)
375 date = tm + " " + str(tz)
374 saverev = self.ui.configbool('convert', 'git.saverev')
376 saverev = self.ui.configbool('convert', 'git.saverev')
375
377
376 c = common.commit(parents=parents, date=date, author=author,
378 c = common.commit(parents=parents, date=date, author=author,
377 desc=message,
379 desc=message,
378 rev=version,
380 rev=version,
379 extra=extra,
381 extra=extra,
380 saverev=saverev)
382 saverev=saverev)
381 return c
383 return c
382
384
383 def numcommits(self):
385 def numcommits(self):
384 output, ret = self.gitrunlines('rev-list', '--all')
386 output, ret = self.gitrunlines('rev-list', '--all')
385 if ret:
387 if ret:
386 raise error.Abort(_('cannot retrieve number of commits in %s') \
388 raise error.Abort(_('cannot retrieve number of commits in %s') \
387 % self.path)
389 % self.path)
388 return len(output)
390 return len(output)
389
391
390 def gettags(self):
392 def gettags(self):
391 tags = {}
393 tags = {}
392 alltags = {}
394 alltags = {}
393 output, status = self.gitrunlines('ls-remote', '--tags', self.path)
395 output, status = self.gitrunlines('ls-remote', '--tags', self.path)
394
396
395 if status:
397 if status:
396 raise error.Abort(_('cannot read tags from %s') % self.path)
398 raise error.Abort(_('cannot read tags from %s') % self.path)
397 prefix = 'refs/tags/'
399 prefix = 'refs/tags/'
398
400
399 # Build complete list of tags, both annotated and bare ones
401 # Build complete list of tags, both annotated and bare ones
400 for line in output:
402 for line in output:
401 line = line.strip()
403 line = line.strip()
402 if line.startswith("error:") or line.startswith("fatal:"):
404 if line.startswith("error:") or line.startswith("fatal:"):
403 raise error.Abort(_('cannot read tags from %s') % self.path)
405 raise error.Abort(_('cannot read tags from %s') % self.path)
404 node, tag = line.split(None, 1)
406 node, tag = line.split(None, 1)
405 if not tag.startswith(prefix):
407 if not tag.startswith(prefix):
406 continue
408 continue
407 alltags[tag[len(prefix):]] = node
409 alltags[tag[len(prefix):]] = node
408
410
409 # Filter out tag objects for annotated tag refs
411 # Filter out tag objects for annotated tag refs
410 for tag in alltags:
412 for tag in alltags:
411 if tag.endswith('^{}'):
413 if tag.endswith('^{}'):
412 tags[tag[:-3]] = alltags[tag]
414 tags[tag[:-3]] = alltags[tag]
413 else:
415 else:
414 if tag + '^{}' in alltags:
416 if tag + '^{}' in alltags:
415 continue
417 continue
416 else:
418 else:
417 tags[tag] = alltags[tag]
419 tags[tag] = alltags[tag]
418
420
419 return tags
421 return tags
420
422
421 def getchangedfiles(self, version, i):
423 def getchangedfiles(self, version, i):
422 changes = []
424 changes = []
423 if i is None:
425 if i is None:
424 output, status = self.gitrunlines('diff-tree', '--root', '-m',
426 output, status = self.gitrunlines('diff-tree', '--root', '-m',
425 '-r', version)
427 '-r', version)
426 if status:
428 if status:
427 raise error.Abort(_('cannot read changes in %s') % version)
429 raise error.Abort(_('cannot read changes in %s') % version)
428 for l in output:
430 for l in output:
429 if "\t" not in l:
431 if "\t" not in l:
430 continue
432 continue
431 m, f = l[:-1].split("\t")
433 m, f = l[:-1].split("\t")
432 changes.append(f)
434 changes.append(f)
433 else:
435 else:
434 output, status = self.gitrunlines('diff-tree', '--name-only',
436 output, status = self.gitrunlines('diff-tree', '--name-only',
435 '--root', '-r', version,
437 '--root', '-r', version,
436 '%s^%s' % (version, i + 1), '--')
438 '%s^%s' % (version, i + 1), '--')
437 if status:
439 if status:
438 raise error.Abort(_('cannot read changes in %s') % version)
440 raise error.Abort(_('cannot read changes in %s') % version)
439 changes = [f.rstrip('\n') for f in output]
441 changes = [f.rstrip('\n') for f in output]
440
442
441 return changes
443 return changes
442
444
443 def getbookmarks(self):
445 def getbookmarks(self):
444 bookmarks = {}
446 bookmarks = {}
445
447
446 # Handle local and remote branches
448 # Handle local and remote branches
447 remoteprefix = self.ui.config('convert', 'git.remoteprefix')
449 remoteprefix = self.ui.config('convert', 'git.remoteprefix')
448 reftypes = [
450 reftypes = [
449 # (git prefix, hg prefix)
451 # (git prefix, hg prefix)
450 ('refs/remotes/origin/', remoteprefix + '/'),
452 ('refs/remotes/origin/', remoteprefix + '/'),
451 ('refs/heads/', '')
453 ('refs/heads/', '')
452 ]
454 ]
453
455
454 exclude = {
456 exclude = {
455 'refs/remotes/origin/HEAD',
457 'refs/remotes/origin/HEAD',
456 }
458 }
457
459
458 try:
460 try:
459 output, status = self.gitrunlines('show-ref')
461 output, status = self.gitrunlines('show-ref')
460 for line in output:
462 for line in output:
461 line = line.strip()
463 line = line.strip()
462 rev, name = line.split(None, 1)
464 rev, name = line.split(None, 1)
463 # Process each type of branch
465 # Process each type of branch
464 for gitprefix, hgprefix in reftypes:
466 for gitprefix, hgprefix in reftypes:
465 if not name.startswith(gitprefix) or name in exclude:
467 if not name.startswith(gitprefix) or name in exclude:
466 continue
468 continue
467 name = '%s%s' % (hgprefix, name[len(gitprefix):])
469 name = '%s%s' % (hgprefix, name[len(gitprefix):])
468 bookmarks[name] = rev
470 bookmarks[name] = rev
469 except Exception:
471 except Exception:
470 pass
472 pass
471
473
472 return bookmarks
474 return bookmarks
473
475
474 def checkrevformat(self, revstr, mapname='splicemap'):
476 def checkrevformat(self, revstr, mapname='splicemap'):
475 """ git revision string is a 40 byte hex """
477 """ git revision string is a 40 byte hex """
476 self.checkhexformat(revstr, mapname)
478 self.checkhexformat(revstr, mapname)
General Comments 0
You need to be logged in to leave comments. Login now