68 def gitpipe(self, *args, **kwargs): |
68 def gitpipe(self, *args, **kwargs): |
69 return self._gitcmd(self._run3, *args, **kwargs) |
69 return self._gitcmd(self._run3, *args, **kwargs) |
70 |
70 |
71 def __init__(self, ui, repotype, path, revs=None): |
71 def __init__(self, ui, repotype, path, revs=None): |
72 super(convert_git, self).__init__(ui, repotype, path, revs=revs) |
72 super(convert_git, self).__init__(ui, repotype, path, revs=revs) |
73 common.commandline.__init__(self, ui, 'git') |
73 common.commandline.__init__(self, ui, b'git') |
74 |
74 |
75 # Pass an absolute path to git to prevent from ever being interpreted |
75 # Pass an absolute path to git to prevent from ever being interpreted |
76 # as a URL |
76 # as a URL |
77 path = os.path.abspath(path) |
77 path = os.path.abspath(path) |
78 |
78 |
79 if os.path.isdir(path + "/.git"): |
79 if os.path.isdir(path + b"/.git"): |
80 path += "/.git" |
80 path += b"/.git" |
81 if not os.path.exists(path + "/objects"): |
81 if not os.path.exists(path + b"/objects"): |
82 raise common.NoRepo( |
82 raise common.NoRepo( |
83 _("%s does not look like a Git repository") % path |
83 _(b"%s does not look like a Git repository") % path |
84 ) |
84 ) |
85 |
85 |
86 # The default value (50) is based on the default for 'git diff'. |
86 # The default value (50) is based on the default for 'git diff'. |
87 similarity = ui.configint('convert', 'git.similarity') |
87 similarity = ui.configint(b'convert', b'git.similarity') |
88 if similarity < 0 or similarity > 100: |
88 if similarity < 0 or similarity > 100: |
89 raise error.Abort(_('similarity must be between 0 and 100')) |
89 raise error.Abort(_(b'similarity must be between 0 and 100')) |
90 if similarity > 0: |
90 if similarity > 0: |
91 self.simopt = ['-C%d%%' % similarity] |
91 self.simopt = [b'-C%d%%' % similarity] |
92 findcopiesharder = ui.configbool('convert', 'git.findcopiesharder') |
92 findcopiesharder = ui.configbool( |
|
93 b'convert', b'git.findcopiesharder' |
|
94 ) |
93 if findcopiesharder: |
95 if findcopiesharder: |
94 self.simopt.append('--find-copies-harder') |
96 self.simopt.append(b'--find-copies-harder') |
95 |
97 |
96 renamelimit = ui.configint('convert', 'git.renamelimit') |
98 renamelimit = ui.configint(b'convert', b'git.renamelimit') |
97 self.simopt.append('-l%d' % renamelimit) |
99 self.simopt.append(b'-l%d' % renamelimit) |
98 else: |
100 else: |
99 self.simopt = [] |
101 self.simopt = [] |
100 |
102 |
101 common.checktool('git', 'git') |
103 common.checktool(b'git', b'git') |
102 |
104 |
103 self.path = path |
105 self.path = path |
104 self.submodules = [] |
106 self.submodules = [] |
105 |
107 |
106 self.catfilepipe = self.gitpipe('cat-file', '--batch') |
108 self.catfilepipe = self.gitpipe(b'cat-file', b'--batch') |
107 |
109 |
108 self.copyextrakeys = self.ui.configlist('convert', 'git.extrakeys') |
110 self.copyextrakeys = self.ui.configlist(b'convert', b'git.extrakeys') |
109 banned = set(self.copyextrakeys) & bannedextrakeys |
111 banned = set(self.copyextrakeys) & bannedextrakeys |
110 if banned: |
112 if banned: |
111 raise error.Abort( |
113 raise error.Abort( |
112 _('copying of extra key is forbidden: %s') |
114 _(b'copying of extra key is forbidden: %s') |
113 % _(', ').join(sorted(banned)) |
115 % _(b', ').join(sorted(banned)) |
114 ) |
116 ) |
115 |
117 |
116 committeractions = self.ui.configlist('convert', 'git.committeractions') |
118 committeractions = self.ui.configlist( |
|
119 b'convert', b'git.committeractions' |
|
120 ) |
117 |
121 |
118 messagedifferent = None |
122 messagedifferent = None |
119 messagealways = None |
123 messagealways = None |
120 for a in committeractions: |
124 for a in committeractions: |
121 if a.startswith(('messagedifferent', 'messagealways')): |
125 if a.startswith((b'messagedifferent', b'messagealways')): |
122 k = a |
126 k = a |
123 v = None |
127 v = None |
124 if '=' in a: |
128 if b'=' in a: |
125 k, v = a.split('=', 1) |
129 k, v = a.split(b'=', 1) |
126 |
130 |
127 if k == 'messagedifferent': |
131 if k == b'messagedifferent': |
128 messagedifferent = v or 'committer:' |
132 messagedifferent = v or b'committer:' |
129 elif k == 'messagealways': |
133 elif k == b'messagealways': |
130 messagealways = v or 'committer:' |
134 messagealways = v or b'committer:' |
131 |
135 |
132 if messagedifferent and messagealways: |
136 if messagedifferent and messagealways: |
133 raise error.Abort( |
137 raise error.Abort( |
134 _( |
138 _( |
135 'committeractions cannot define both ' |
139 b'committeractions cannot define both ' |
136 'messagedifferent and messagealways' |
140 b'messagedifferent and messagealways' |
137 ) |
141 ) |
138 ) |
142 ) |
139 |
143 |
140 dropcommitter = 'dropcommitter' in committeractions |
144 dropcommitter = b'dropcommitter' in committeractions |
141 replaceauthor = 'replaceauthor' in committeractions |
145 replaceauthor = b'replaceauthor' in committeractions |
142 |
146 |
143 if dropcommitter and replaceauthor: |
147 if dropcommitter and replaceauthor: |
144 raise error.Abort( |
148 raise error.Abort( |
145 _( |
149 _( |
146 'committeractions cannot define both ' |
150 b'committeractions cannot define both ' |
147 'dropcommitter and replaceauthor' |
151 b'dropcommitter and replaceauthor' |
148 ) |
152 ) |
149 ) |
153 ) |
150 |
154 |
151 if dropcommitter and messagealways: |
155 if dropcommitter and messagealways: |
152 raise error.Abort( |
156 raise error.Abort( |
153 _( |
157 _( |
154 'committeractions cannot define both ' |
158 b'committeractions cannot define both ' |
155 'dropcommitter and messagealways' |
159 b'dropcommitter and messagealways' |
156 ) |
160 ) |
157 ) |
161 ) |
158 |
162 |
159 if not messagedifferent and not messagealways: |
163 if not messagedifferent and not messagealways: |
160 messagedifferent = 'committer:' |
164 messagedifferent = b'committer:' |
161 |
165 |
162 self.committeractions = { |
166 self.committeractions = { |
163 'dropcommitter': dropcommitter, |
167 b'dropcommitter': dropcommitter, |
164 'replaceauthor': replaceauthor, |
168 b'replaceauthor': replaceauthor, |
165 'messagedifferent': messagedifferent, |
169 b'messagedifferent': messagedifferent, |
166 'messagealways': messagealways, |
170 b'messagealways': messagealways, |
167 } |
171 } |
168 |
172 |
169 def after(self): |
173 def after(self): |
170 for f in self.catfilepipe: |
174 for f in self.catfilepipe: |
171 f.close() |
175 f.close() |
172 |
176 |
173 def getheads(self): |
177 def getheads(self): |
174 if not self.revs: |
178 if not self.revs: |
175 output, status = self.gitrun('rev-parse', '--branches', '--remotes') |
179 output, status = self.gitrun( |
|
180 b'rev-parse', b'--branches', b'--remotes' |
|
181 ) |
176 heads = output.splitlines() |
182 heads = output.splitlines() |
177 if status: |
183 if status: |
178 raise error.Abort(_('cannot retrieve git heads')) |
184 raise error.Abort(_(b'cannot retrieve git heads')) |
179 else: |
185 else: |
180 heads = [] |
186 heads = [] |
181 for rev in self.revs: |
187 for rev in self.revs: |
182 rawhead, ret = self.gitrun('rev-parse', '--verify', rev) |
188 rawhead, ret = self.gitrun(b'rev-parse', b'--verify', rev) |
183 heads.append(rawhead[:-1]) |
189 heads.append(rawhead[:-1]) |
184 if ret: |
190 if ret: |
185 raise error.Abort(_('cannot retrieve git head "%s"') % rev) |
191 raise error.Abort(_(b'cannot retrieve git head "%s"') % rev) |
186 return heads |
192 return heads |
187 |
193 |
188 def catfile(self, rev, ftype): |
194 def catfile(self, rev, ftype): |
189 if rev == nodemod.nullhex: |
195 if rev == nodemod.nullhex: |
190 raise IOError |
196 raise IOError |
191 self.catfilepipe[0].write(rev + '\n') |
197 self.catfilepipe[0].write(rev + b'\n') |
192 self.catfilepipe[0].flush() |
198 self.catfilepipe[0].flush() |
193 info = self.catfilepipe[1].readline().split() |
199 info = self.catfilepipe[1].readline().split() |
194 if info[1] != ftype: |
200 if info[1] != ftype: |
195 raise error.Abort( |
201 raise error.Abort( |
196 _('cannot read %r object at %s') |
202 _(b'cannot read %r object at %s') |
197 % (pycompat.bytestr(ftype), rev) |
203 % (pycompat.bytestr(ftype), rev) |
198 ) |
204 ) |
199 size = int(info[2]) |
205 size = int(info[2]) |
200 data = self.catfilepipe[1].read(size) |
206 data = self.catfilepipe[1].read(size) |
201 if len(data) < size: |
207 if len(data) < size: |
202 raise error.Abort( |
208 raise error.Abort( |
203 _('cannot read %r object at %s: unexpected size') % (ftype, rev) |
209 _(b'cannot read %r object at %s: unexpected size') |
|
210 % (ftype, rev) |
204 ) |
211 ) |
205 # read the trailing newline |
212 # read the trailing newline |
206 self.catfilepipe[1].read(1) |
213 self.catfilepipe[1].read(1) |
207 return data |
214 return data |
208 |
215 |
209 def getfile(self, name, rev): |
216 def getfile(self, name, rev): |
210 if rev == nodemod.nullhex: |
217 if rev == nodemod.nullhex: |
211 return None, None |
218 return None, None |
212 if name == '.hgsub': |
219 if name == b'.hgsub': |
213 data = '\n'.join([m.hgsub() for m in self.submoditer()]) |
220 data = b'\n'.join([m.hgsub() for m in self.submoditer()]) |
214 mode = '' |
221 mode = b'' |
215 elif name == '.hgsubstate': |
222 elif name == b'.hgsubstate': |
216 data = '\n'.join([m.hgsubstate() for m in self.submoditer()]) |
223 data = b'\n'.join([m.hgsubstate() for m in self.submoditer()]) |
217 mode = '' |
224 mode = b'' |
218 else: |
225 else: |
219 data = self.catfile(rev, "blob") |
226 data = self.catfile(rev, b"blob") |
220 mode = self.modecache[(name, rev)] |
227 mode = self.modecache[(name, rev)] |
221 return data, mode |
228 return data, mode |
222 |
229 |
223 def submoditer(self): |
230 def submoditer(self): |
224 null = nodemod.nullhex |
231 null = nodemod.nullhex |
234 """ |
241 """ |
235 self.submodules = [] |
242 self.submodules = [] |
236 c = config.config() |
243 c = config.config() |
237 # Each item in .gitmodules starts with whitespace that cant be parsed |
244 # Each item in .gitmodules starts with whitespace that cant be parsed |
238 c.parse( |
245 c.parse( |
239 '.gitmodules', |
246 b'.gitmodules', |
240 '\n'.join(line.strip() for line in content.split('\n')), |
247 b'\n'.join(line.strip() for line in content.split(b'\n')), |
241 ) |
248 ) |
242 for sec in c.sections(): |
249 for sec in c.sections(): |
243 s = c[sec] |
250 s = c[sec] |
244 if 'url' in s and 'path' in s: |
251 if b'url' in s and b'path' in s: |
245 self.submodules.append(submodule(s['path'], '', s['url'])) |
252 self.submodules.append(submodule(s[b'path'], b'', s[b'url'])) |
246 |
253 |
247 def retrievegitmodules(self, version): |
254 def retrievegitmodules(self, version): |
248 modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules')) |
255 modules, ret = self.gitrun( |
|
256 b'show', b'%s:%s' % (version, b'.gitmodules') |
|
257 ) |
249 if ret: |
258 if ret: |
250 # This can happen if a file is in the repo that has permissions |
259 # This can happen if a file is in the repo that has permissions |
251 # 160000, but there is no .gitmodules file. |
260 # 160000, but there is no .gitmodules file. |
252 self.ui.warn( |
261 self.ui.warn( |
253 _("warning: cannot read submodules config file in " "%s\n") |
262 _(b"warning: cannot read submodules config file in " b"%s\n") |
254 % version |
263 % version |
255 ) |
264 ) |
256 return |
265 return |
257 |
266 |
258 try: |
267 try: |
259 self.parsegitmodules(modules) |
268 self.parsegitmodules(modules) |
260 except error.ParseError: |
269 except error.ParseError: |
261 self.ui.warn( |
270 self.ui.warn( |
262 _("warning: unable to parse .gitmodules in %s\n") % version |
271 _(b"warning: unable to parse .gitmodules in %s\n") % version |
263 ) |
272 ) |
264 return |
273 return |
265 |
274 |
266 for m in self.submodules: |
275 for m in self.submodules: |
267 node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path)) |
276 node, ret = self.gitrun(b'rev-parse', b'%s:%s' % (version, m.path)) |
268 if ret: |
277 if ret: |
269 continue |
278 continue |
270 m.node = node.strip() |
279 m.node = node.strip() |
271 |
280 |
272 def getchanges(self, version, full): |
281 def getchanges(self, version, full): |
273 if full: |
282 if full: |
274 raise error.Abort(_("convert from git does not support --full")) |
283 raise error.Abort(_(b"convert from git does not support --full")) |
275 self.modecache = {} |
284 self.modecache = {} |
276 cmd = ( |
285 cmd = ( |
277 ['diff-tree', '-z', '--root', '-m', '-r'] + self.simopt + [version] |
286 [b'diff-tree', b'-z', b'--root', b'-m', b'-r'] |
|
287 + self.simopt |
|
288 + [version] |
278 ) |
289 ) |
279 output, status = self.gitrun(*cmd) |
290 output, status = self.gitrun(*cmd) |
280 if status: |
291 if status: |
281 raise error.Abort(_('cannot read changes in %s') % version) |
292 raise error.Abort(_(b'cannot read changes in %s') % version) |
282 changes = [] |
293 changes = [] |
283 copies = {} |
294 copies = {} |
284 seen = set() |
295 seen = set() |
285 entry = None |
296 entry = None |
286 subexists = [False] |
297 subexists = [False] |
287 subdeleted = [False] |
298 subdeleted = [False] |
288 difftree = output.split('\x00') |
299 difftree = output.split(b'\x00') |
289 lcount = len(difftree) |
300 lcount = len(difftree) |
290 i = 0 |
301 i = 0 |
291 |
302 |
292 skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules') |
303 skipsubmodules = self.ui.configbool(b'convert', b'git.skipsubmodules') |
293 |
304 |
294 def add(entry, f, isdest): |
305 def add(entry, f, isdest): |
295 seen.add(f) |
306 seen.add(f) |
296 h = entry[3] |
307 h = entry[3] |
297 p = entry[1] == "100755" |
308 p = entry[1] == b"100755" |
298 s = entry[1] == "120000" |
309 s = entry[1] == b"120000" |
299 renamesource = not isdest and entry[4][0] == 'R' |
310 renamesource = not isdest and entry[4][0] == b'R' |
300 |
311 |
301 if f == '.gitmodules': |
312 if f == b'.gitmodules': |
302 if skipsubmodules: |
313 if skipsubmodules: |
303 return |
314 return |
304 |
315 |
305 subexists[0] = True |
316 subexists[0] = True |
306 if entry[4] == 'D' or renamesource: |
317 if entry[4] == b'D' or renamesource: |
307 subdeleted[0] = True |
318 subdeleted[0] = True |
308 changes.append(('.hgsub', nodemod.nullhex)) |
319 changes.append((b'.hgsub', nodemod.nullhex)) |
309 else: |
320 else: |
310 changes.append(('.hgsub', '')) |
321 changes.append((b'.hgsub', b'')) |
311 elif entry[1] == '160000' or entry[0] == ':160000': |
322 elif entry[1] == b'160000' or entry[0] == b':160000': |
312 if not skipsubmodules: |
323 if not skipsubmodules: |
313 subexists[0] = True |
324 subexists[0] = True |
314 else: |
325 else: |
315 if renamesource: |
326 if renamesource: |
316 h = nodemod.nullhex |
327 h = nodemod.nullhex |
317 self.modecache[(f, h)] = (p and "x") or (s and "l") or "" |
328 self.modecache[(f, h)] = (p and b"x") or (s and b"l") or b"" |
318 changes.append((f, h)) |
329 changes.append((f, h)) |
319 |
330 |
320 while i < lcount: |
331 while i < lcount: |
321 l = difftree[i] |
332 l = difftree[i] |
322 i += 1 |
333 i += 1 |
323 if not entry: |
334 if not entry: |
324 if not l.startswith(':'): |
335 if not l.startswith(b':'): |
325 continue |
336 continue |
326 entry = tuple(pycompat.bytestr(p) for p in l.split()) |
337 entry = tuple(pycompat.bytestr(p) for p in l.split()) |
327 continue |
338 continue |
328 f = l |
339 f = l |
329 if entry[4][0] == 'C': |
340 if entry[4][0] == b'C': |
330 copysrc = f |
341 copysrc = f |
331 copydest = difftree[i] |
342 copydest = difftree[i] |
332 i += 1 |
343 i += 1 |
333 f = copydest |
344 f = copydest |
334 copies[copydest] = copysrc |
345 copies[copydest] = copysrc |
335 if f not in seen: |
346 if f not in seen: |
336 add(entry, f, False) |
347 add(entry, f, False) |
337 # A file can be copied multiple times, or modified and copied |
348 # A file can be copied multiple times, or modified and copied |
338 # simultaneously. So f can be repeated even if fdest isn't. |
349 # simultaneously. So f can be repeated even if fdest isn't. |
339 if entry[4][0] == 'R': |
350 if entry[4][0] == b'R': |
340 # rename: next line is the destination |
351 # rename: next line is the destination |
341 fdest = difftree[i] |
352 fdest = difftree[i] |
342 i += 1 |
353 i += 1 |
343 if fdest not in seen: |
354 if fdest not in seen: |
344 add(entry, fdest, True) |
355 add(entry, fdest, True) |
345 # .gitmodules isn't imported at all, so it being copied to |
356 # .gitmodules isn't imported at all, so it being copied to |
346 # and fro doesn't really make sense |
357 # and fro doesn't really make sense |
347 if f != '.gitmodules' and fdest != '.gitmodules': |
358 if f != b'.gitmodules' and fdest != b'.gitmodules': |
348 copies[fdest] = f |
359 copies[fdest] = f |
349 entry = None |
360 entry = None |
350 |
361 |
351 if subexists[0]: |
362 if subexists[0]: |
352 if subdeleted[0]: |
363 if subdeleted[0]: |
353 changes.append(('.hgsubstate', nodemod.nullhex)) |
364 changes.append((b'.hgsubstate', nodemod.nullhex)) |
354 else: |
365 else: |
355 self.retrievegitmodules(version) |
366 self.retrievegitmodules(version) |
356 changes.append(('.hgsubstate', '')) |
367 changes.append((b'.hgsubstate', b'')) |
357 return (changes, copies, set()) |
368 return (changes, copies, set()) |
358 |
369 |
359 def getcommit(self, version): |
370 def getcommit(self, version): |
360 c = self.catfile(version, "commit") # read the commit hash |
371 c = self.catfile(version, b"commit") # read the commit hash |
361 end = c.find("\n\n") |
372 end = c.find(b"\n\n") |
362 message = c[end + 2 :] |
373 message = c[end + 2 :] |
363 message = self.recode(message) |
374 message = self.recode(message) |
364 l = c[:end].splitlines() |
375 l = c[:end].splitlines() |
365 parents = [] |
376 parents = [] |
366 author = committer = None |
377 author = committer = None |
367 extra = {} |
378 extra = {} |
368 for e in l[1:]: |
379 for e in l[1:]: |
369 n, v = e.split(" ", 1) |
380 n, v = e.split(b" ", 1) |
370 if n == "author": |
381 if n == b"author": |
371 p = v.split() |
382 p = v.split() |
372 tm, tz = p[-2:] |
383 tm, tz = p[-2:] |
373 author = " ".join(p[:-2]) |
384 author = b" ".join(p[:-2]) |
374 if author[0] == "<": |
385 if author[0] == b"<": |
375 author = author[1:-1] |
386 author = author[1:-1] |
376 author = self.recode(author) |
387 author = self.recode(author) |
377 if n == "committer": |
388 if n == b"committer": |
378 p = v.split() |
389 p = v.split() |
379 tm, tz = p[-2:] |
390 tm, tz = p[-2:] |
380 committer = " ".join(p[:-2]) |
391 committer = b" ".join(p[:-2]) |
381 if committer[0] == "<": |
392 if committer[0] == b"<": |
382 committer = committer[1:-1] |
393 committer = committer[1:-1] |
383 committer = self.recode(committer) |
394 committer = self.recode(committer) |
384 if n == "parent": |
395 if n == b"parent": |
385 parents.append(v) |
396 parents.append(v) |
386 if n in self.copyextrakeys: |
397 if n in self.copyextrakeys: |
387 extra[n] = v |
398 extra[n] = v |
388 |
399 |
389 if self.committeractions['dropcommitter']: |
400 if self.committeractions[b'dropcommitter']: |
390 committer = None |
401 committer = None |
391 elif self.committeractions['replaceauthor']: |
402 elif self.committeractions[b'replaceauthor']: |
392 author = committer |
403 author = committer |
393 |
404 |
394 if committer: |
405 if committer: |
395 messagealways = self.committeractions['messagealways'] |
406 messagealways = self.committeractions[b'messagealways'] |
396 messagedifferent = self.committeractions['messagedifferent'] |
407 messagedifferent = self.committeractions[b'messagedifferent'] |
397 if messagealways: |
408 if messagealways: |
398 message += '\n%s %s\n' % (messagealways, committer) |
409 message += b'\n%s %s\n' % (messagealways, committer) |
399 elif messagedifferent and author != committer: |
410 elif messagedifferent and author != committer: |
400 message += '\n%s %s\n' % (messagedifferent, committer) |
411 message += b'\n%s %s\n' % (messagedifferent, committer) |
401 |
412 |
402 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] |
413 tzs, tzh, tzm = tz[-5:-4] + b"1", tz[-4:-2], tz[-2:] |
403 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) |
414 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) |
404 date = tm + " " + (b"%d" % tz) |
415 date = tm + b" " + (b"%d" % tz) |
405 saverev = self.ui.configbool('convert', 'git.saverev') |
416 saverev = self.ui.configbool(b'convert', b'git.saverev') |
406 |
417 |
407 c = common.commit( |
418 c = common.commit( |
408 parents=parents, |
419 parents=parents, |
409 date=date, |
420 date=date, |
410 author=author, |
421 author=author, |
414 saverev=saverev, |
425 saverev=saverev, |
415 ) |
426 ) |
416 return c |
427 return c |
417 |
428 |
418 def numcommits(self): |
429 def numcommits(self): |
419 output, ret = self.gitrunlines('rev-list', '--all') |
430 output, ret = self.gitrunlines(b'rev-list', b'--all') |
420 if ret: |
431 if ret: |
421 raise error.Abort( |
432 raise error.Abort( |
422 _('cannot retrieve number of commits in %s') % self.path |
433 _(b'cannot retrieve number of commits in %s') % self.path |
423 ) |
434 ) |
424 return len(output) |
435 return len(output) |
425 |
436 |
426 def gettags(self): |
437 def gettags(self): |
427 tags = {} |
438 tags = {} |
428 alltags = {} |
439 alltags = {} |
429 output, status = self.gitrunlines('ls-remote', '--tags', self.path) |
440 output, status = self.gitrunlines(b'ls-remote', b'--tags', self.path) |
430 |
441 |
431 if status: |
442 if status: |
432 raise error.Abort(_('cannot read tags from %s') % self.path) |
443 raise error.Abort(_(b'cannot read tags from %s') % self.path) |
433 prefix = 'refs/tags/' |
444 prefix = b'refs/tags/' |
434 |
445 |
435 # Build complete list of tags, both annotated and bare ones |
446 # Build complete list of tags, both annotated and bare ones |
436 for line in output: |
447 for line in output: |
437 line = line.strip() |
448 line = line.strip() |
438 if line.startswith("error:") or line.startswith("fatal:"): |
449 if line.startswith(b"error:") or line.startswith(b"fatal:"): |
439 raise error.Abort(_('cannot read tags from %s') % self.path) |
450 raise error.Abort(_(b'cannot read tags from %s') % self.path) |
440 node, tag = line.split(None, 1) |
451 node, tag = line.split(None, 1) |
441 if not tag.startswith(prefix): |
452 if not tag.startswith(prefix): |
442 continue |
453 continue |
443 alltags[tag[len(prefix) :]] = node |
454 alltags[tag[len(prefix) :]] = node |
444 |
455 |
445 # Filter out tag objects for annotated tag refs |
456 # Filter out tag objects for annotated tag refs |
446 for tag in alltags: |
457 for tag in alltags: |
447 if tag.endswith('^{}'): |
458 if tag.endswith(b'^{}'): |
448 tags[tag[:-3]] = alltags[tag] |
459 tags[tag[:-3]] = alltags[tag] |
449 else: |
460 else: |
450 if tag + '^{}' in alltags: |
461 if tag + b'^{}' in alltags: |
451 continue |
462 continue |
452 else: |
463 else: |
453 tags[tag] = alltags[tag] |
464 tags[tag] = alltags[tag] |
454 |
465 |
455 return tags |
466 return tags |
456 |
467 |
457 def getchangedfiles(self, version, i): |
468 def getchangedfiles(self, version, i): |
458 changes = [] |
469 changes = [] |
459 if i is None: |
470 if i is None: |
460 output, status = self.gitrunlines( |
471 output, status = self.gitrunlines( |
461 'diff-tree', '--root', '-m', '-r', version |
472 b'diff-tree', b'--root', b'-m', b'-r', version |
462 ) |
473 ) |
463 if status: |
474 if status: |
464 raise error.Abort(_('cannot read changes in %s') % version) |
475 raise error.Abort(_(b'cannot read changes in %s') % version) |
465 for l in output: |
476 for l in output: |
466 if "\t" not in l: |
477 if b"\t" not in l: |
467 continue |
478 continue |
468 m, f = l[:-1].split("\t") |
479 m, f = l[:-1].split(b"\t") |
469 changes.append(f) |
480 changes.append(f) |
470 else: |
481 else: |
471 output, status = self.gitrunlines( |
482 output, status = self.gitrunlines( |
472 'diff-tree', |
483 b'diff-tree', |
473 '--name-only', |
484 b'--name-only', |
474 '--root', |
485 b'--root', |
475 '-r', |
486 b'-r', |
476 version, |
487 version, |
477 '%s^%d' % (version, i + 1), |
488 b'%s^%d' % (version, i + 1), |
478 '--', |
489 b'--', |
479 ) |
490 ) |
480 if status: |
491 if status: |
481 raise error.Abort(_('cannot read changes in %s') % version) |
492 raise error.Abort(_(b'cannot read changes in %s') % version) |
482 changes = [f.rstrip('\n') for f in output] |
493 changes = [f.rstrip(b'\n') for f in output] |
483 |
494 |
484 return changes |
495 return changes |
485 |
496 |
486 def getbookmarks(self): |
497 def getbookmarks(self): |
487 bookmarks = {} |
498 bookmarks = {} |
488 |
499 |
489 # Handle local and remote branches |
500 # Handle local and remote branches |
490 remoteprefix = self.ui.config('convert', 'git.remoteprefix') |
501 remoteprefix = self.ui.config(b'convert', b'git.remoteprefix') |
491 reftypes = [ |
502 reftypes = [ |
492 # (git prefix, hg prefix) |
503 # (git prefix, hg prefix) |
493 ('refs/remotes/origin/', remoteprefix + '/'), |
504 (b'refs/remotes/origin/', remoteprefix + b'/'), |
494 ('refs/heads/', ''), |
505 (b'refs/heads/', b''), |
495 ] |
506 ] |
496 |
507 |
497 exclude = { |
508 exclude = { |
498 'refs/remotes/origin/HEAD', |
509 b'refs/remotes/origin/HEAD', |
499 } |
510 } |
500 |
511 |
501 try: |
512 try: |
502 output, status = self.gitrunlines('show-ref') |
513 output, status = self.gitrunlines(b'show-ref') |
503 for line in output: |
514 for line in output: |
504 line = line.strip() |
515 line = line.strip() |
505 rev, name = line.split(None, 1) |
516 rev, name = line.split(None, 1) |
506 # Process each type of branch |
517 # Process each type of branch |
507 for gitprefix, hgprefix in reftypes: |
518 for gitprefix, hgprefix in reftypes: |
508 if not name.startswith(gitprefix) or name in exclude: |
519 if not name.startswith(gitprefix) or name in exclude: |
509 continue |
520 continue |
510 name = '%s%s' % (hgprefix, name[len(gitprefix) :]) |
521 name = b'%s%s' % (hgprefix, name[len(gitprefix) :]) |
511 bookmarks[name] = rev |
522 bookmarks[name] = rev |
512 except Exception: |
523 except Exception: |
513 pass |
524 pass |
514 |
525 |
515 return bookmarks |
526 return bookmarks |
516 |
527 |
517 def checkrevformat(self, revstr, mapname='splicemap'): |
528 def checkrevformat(self, revstr, mapname=b'splicemap'): |
518 """ git revision string is a 40 byte hex """ |
529 """ git revision string is a 40 byte hex """ |
519 self.checkhexformat(revstr, mapname) |
530 self.checkhexformat(revstr, mapname) |