49 |
49 |
50 |
50 |
51 class mercurial_sink(common.converter_sink): |
51 class mercurial_sink(common.converter_sink): |
52 def __init__(self, ui, repotype, path): |
52 def __init__(self, ui, repotype, path): |
53 common.converter_sink.__init__(self, ui, repotype, path) |
53 common.converter_sink.__init__(self, ui, repotype, path) |
54 self.branchnames = ui.configbool('convert', 'hg.usebranchnames') |
54 self.branchnames = ui.configbool(b'convert', b'hg.usebranchnames') |
55 self.clonebranches = ui.configbool('convert', 'hg.clonebranches') |
55 self.clonebranches = ui.configbool(b'convert', b'hg.clonebranches') |
56 self.tagsbranch = ui.config('convert', 'hg.tagsbranch') |
56 self.tagsbranch = ui.config(b'convert', b'hg.tagsbranch') |
57 self.lastbranch = None |
57 self.lastbranch = None |
58 if os.path.isdir(path) and len(os.listdir(path)) > 0: |
58 if os.path.isdir(path) and len(os.listdir(path)) > 0: |
59 try: |
59 try: |
60 self.repo = hg.repository(self.ui, path) |
60 self.repo = hg.repository(self.ui, path) |
61 if not self.repo.local(): |
61 if not self.repo.local(): |
62 raise NoRepo( |
62 raise NoRepo( |
63 _('%s is not a local Mercurial repository') % path |
63 _(b'%s is not a local Mercurial repository') % path |
64 ) |
64 ) |
65 except error.RepoError as err: |
65 except error.RepoError as err: |
66 ui.traceback() |
66 ui.traceback() |
67 raise NoRepo(err.args[0]) |
67 raise NoRepo(err.args[0]) |
68 else: |
68 else: |
69 try: |
69 try: |
70 ui.status(_('initializing destination %s repository\n') % path) |
70 ui.status(_(b'initializing destination %s repository\n') % path) |
71 self.repo = hg.repository(self.ui, path, create=True) |
71 self.repo = hg.repository(self.ui, path, create=True) |
72 if not self.repo.local(): |
72 if not self.repo.local(): |
73 raise NoRepo( |
73 raise NoRepo( |
74 _('%s is not a local Mercurial repository') % path |
74 _(b'%s is not a local Mercurial repository') % path |
75 ) |
75 ) |
76 self.created.append(path) |
76 self.created.append(path) |
77 except error.RepoError: |
77 except error.RepoError: |
78 ui.traceback() |
78 ui.traceback() |
79 raise NoRepo( |
79 raise NoRepo( |
80 _("could not create hg repository %s as sink") % path |
80 _(b"could not create hg repository %s as sink") % path |
81 ) |
81 ) |
82 self.lock = None |
82 self.lock = None |
83 self.wlock = None |
83 self.wlock = None |
84 self.filemapmode = False |
84 self.filemapmode = False |
85 self.subrevmaps = {} |
85 self.subrevmaps = {} |
86 |
86 |
87 def before(self): |
87 def before(self): |
88 self.ui.debug('run hg sink pre-conversion action\n') |
88 self.ui.debug(b'run hg sink pre-conversion action\n') |
89 self.wlock = self.repo.wlock() |
89 self.wlock = self.repo.wlock() |
90 self.lock = self.repo.lock() |
90 self.lock = self.repo.lock() |
91 |
91 |
92 def after(self): |
92 def after(self): |
93 self.ui.debug('run hg sink post-conversion action\n') |
93 self.ui.debug(b'run hg sink post-conversion action\n') |
94 if self.lock: |
94 if self.lock: |
95 self.lock.release() |
95 self.lock.release() |
96 if self.wlock: |
96 if self.wlock: |
97 self.wlock.release() |
97 self.wlock.release() |
98 |
98 |
99 def revmapfile(self): |
99 def revmapfile(self): |
100 return self.repo.vfs.join("shamap") |
100 return self.repo.vfs.join(b"shamap") |
101 |
101 |
102 def authorfile(self): |
102 def authorfile(self): |
103 return self.repo.vfs.join("authormap") |
103 return self.repo.vfs.join(b"authormap") |
104 |
104 |
105 def setbranch(self, branch, pbranches): |
105 def setbranch(self, branch, pbranches): |
106 if not self.clonebranches: |
106 if not self.clonebranches: |
107 return |
107 return |
108 |
108 |
109 setbranch = branch != self.lastbranch |
109 setbranch = branch != self.lastbranch |
110 self.lastbranch = branch |
110 self.lastbranch = branch |
111 if not branch: |
111 if not branch: |
112 branch = 'default' |
112 branch = b'default' |
113 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches] |
113 pbranches = [(b[0], b[1] and b[1] or b'default') for b in pbranches] |
114 |
114 |
115 branchpath = os.path.join(self.path, branch) |
115 branchpath = os.path.join(self.path, branch) |
116 if setbranch: |
116 if setbranch: |
117 self.after() |
117 self.after() |
118 try: |
118 try: |
133 if missings: |
133 if missings: |
134 self.after() |
134 self.after() |
135 for pbranch, heads in sorted(missings.iteritems()): |
135 for pbranch, heads in sorted(missings.iteritems()): |
136 pbranchpath = os.path.join(self.path, pbranch) |
136 pbranchpath = os.path.join(self.path, pbranch) |
137 prepo = hg.peer(self.ui, {}, pbranchpath) |
137 prepo = hg.peer(self.ui, {}, pbranchpath) |
138 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch)) |
138 self.ui.note( |
|
139 _(b'pulling from %s into %s\n') % (pbranch, branch) |
|
140 ) |
139 exchange.pull( |
141 exchange.pull( |
140 self.repo, prepo, [prepo.lookup(h) for h in heads] |
142 self.repo, prepo, [prepo.lookup(h) for h in heads] |
141 ) |
143 ) |
142 self.before() |
144 self.before() |
143 |
145 |
144 def _rewritetags(self, source, revmap, data): |
146 def _rewritetags(self, source, revmap, data): |
145 fp = stringio() |
147 fp = stringio() |
146 for line in data.splitlines(): |
148 for line in data.splitlines(): |
147 s = line.split(' ', 1) |
149 s = line.split(b' ', 1) |
148 if len(s) != 2: |
150 if len(s) != 2: |
149 self.ui.warn(_('invalid tag entry: "%s"\n') % line) |
151 self.ui.warn(_(b'invalid tag entry: "%s"\n') % line) |
150 fp.write('%s\n' % line) # Bogus, but keep for hash stability |
152 fp.write(b'%s\n' % line) # Bogus, but keep for hash stability |
151 continue |
153 continue |
152 revid = revmap.get(source.lookuprev(s[0])) |
154 revid = revmap.get(source.lookuprev(s[0])) |
153 if not revid: |
155 if not revid: |
154 if s[0] == nodemod.nullhex: |
156 if s[0] == nodemod.nullhex: |
155 revid = s[0] |
157 revid = s[0] |
156 else: |
158 else: |
157 # missing, but keep for hash stability |
159 # missing, but keep for hash stability |
158 self.ui.warn(_('missing tag entry: "%s"\n') % line) |
160 self.ui.warn(_(b'missing tag entry: "%s"\n') % line) |
159 fp.write('%s\n' % line) |
161 fp.write(b'%s\n' % line) |
160 continue |
162 continue |
161 fp.write('%s %s\n' % (revid, s[1])) |
163 fp.write(b'%s %s\n' % (revid, s[1])) |
162 return fp.getvalue() |
164 return fp.getvalue() |
163 |
165 |
164 def _rewritesubstate(self, source, data): |
166 def _rewritesubstate(self, source, data): |
165 fp = stringio() |
167 fp = stringio() |
166 for line in data.splitlines(): |
168 for line in data.splitlines(): |
167 s = line.split(' ', 1) |
169 s = line.split(b' ', 1) |
168 if len(s) != 2: |
170 if len(s) != 2: |
169 continue |
171 continue |
170 |
172 |
171 revid = s[0] |
173 revid = s[0] |
172 subpath = s[1] |
174 subpath = s[1] |
173 if revid != nodemod.nullhex: |
175 if revid != nodemod.nullhex: |
174 revmap = self.subrevmaps.get(subpath) |
176 revmap = self.subrevmaps.get(subpath) |
175 if revmap is None: |
177 if revmap is None: |
176 revmap = mapfile( |
178 revmap = mapfile( |
177 self.ui, self.repo.wjoin(subpath, '.hg/shamap') |
179 self.ui, self.repo.wjoin(subpath, b'.hg/shamap') |
178 ) |
180 ) |
179 self.subrevmaps[subpath] = revmap |
181 self.subrevmaps[subpath] = revmap |
180 |
182 |
181 # It is reasonable that one or more of the subrepos don't |
183 # It is reasonable that one or more of the subrepos don't |
182 # need to be converted, in which case they can be cloned |
184 # need to be converted, in which case they can be cloned |
183 # into place instead of converted. Therefore, only warn |
185 # into place instead of converted. Therefore, only warn |
184 # once. |
186 # once. |
185 msg = _('no ".hgsubstate" updates will be made for "%s"\n') |
187 msg = _(b'no ".hgsubstate" updates will be made for "%s"\n') |
186 if len(revmap) == 0: |
188 if len(revmap) == 0: |
187 sub = self.repo.wvfs.reljoin(subpath, '.hg') |
189 sub = self.repo.wvfs.reljoin(subpath, b'.hg') |
188 |
190 |
189 if self.repo.wvfs.exists(sub): |
191 if self.repo.wvfs.exists(sub): |
190 self.ui.warn(msg % subpath) |
192 self.ui.warn(msg % subpath) |
191 |
193 |
192 newid = revmap.get(revid) |
194 newid = revmap.get(revid) |
193 if not newid: |
195 if not newid: |
194 if len(revmap) > 0: |
196 if len(revmap) > 0: |
195 self.ui.warn( |
197 self.ui.warn( |
196 _("%s is missing from %s/.hg/shamap\n") |
198 _(b"%s is missing from %s/.hg/shamap\n") |
197 % (revid, subpath) |
199 % (revid, subpath) |
198 ) |
200 ) |
199 else: |
201 else: |
200 revid = newid |
202 revid = newid |
201 |
203 |
202 fp.write('%s %s\n' % (revid, subpath)) |
204 fp.write(b'%s %s\n' % (revid, subpath)) |
203 |
205 |
204 return fp.getvalue() |
206 return fp.getvalue() |
205 |
207 |
206 def _calculatemergedfiles(self, source, p1ctx, p2ctx): |
208 def _calculatemergedfiles(self, source, p1ctx, p2ctx): |
207 """Calculates the files from p2 that we need to pull in when merging p1 |
209 """Calculates the files from p2 that we need to pull in when merging p1 |
230 # since it will be covered by the existing fileset. |
232 # since it will be covered by the existing fileset. |
231 continue |
233 continue |
232 |
234 |
233 # If the file requires actual merging, abort. We don't have enough |
235 # If the file requires actual merging, abort. We don't have enough |
234 # context to resolve merges correctly. |
236 # context to resolve merges correctly. |
235 if action in ['m', 'dm', 'cd', 'dc']: |
237 if action in [b'm', b'dm', b'cd', b'dc']: |
236 raise error.Abort( |
238 raise error.Abort( |
237 _( |
239 _( |
238 "unable to convert merge commit " |
240 b"unable to convert merge commit " |
239 "since target parents do not merge cleanly (file " |
241 b"since target parents do not merge cleanly (file " |
240 "%s, parents %s and %s)" |
242 b"%s, parents %s and %s)" |
241 ) |
243 ) |
242 % (file, p1ctx, p2ctx) |
244 % (file, p1ctx, p2ctx) |
243 ) |
245 ) |
244 elif action == 'k': |
246 elif action == b'k': |
245 # 'keep' means nothing changed from p1 |
247 # 'keep' means nothing changed from p1 |
246 continue |
248 continue |
247 else: |
249 else: |
248 # Any other change means we want to take the p2 version |
250 # Any other change means we want to take the p2 version |
249 yield file |
251 yield file |
308 if newrev is not None: |
310 if newrev is not None: |
309 text = text.replace(sha1, newrev[: len(sha1)]) |
311 text = text.replace(sha1, newrev[: len(sha1)]) |
310 |
312 |
311 extra = commit.extra.copy() |
313 extra = commit.extra.copy() |
312 |
314 |
313 sourcename = self.repo.ui.config('convert', 'hg.sourcename') |
315 sourcename = self.repo.ui.config(b'convert', b'hg.sourcename') |
314 if sourcename: |
316 if sourcename: |
315 extra['convert_source'] = sourcename |
317 extra[b'convert_source'] = sourcename |
316 |
318 |
317 for label in ( |
319 for label in ( |
318 'source', |
320 b'source', |
319 'transplant_source', |
321 b'transplant_source', |
320 'rebase_source', |
322 b'rebase_source', |
321 'intermediate-source', |
323 b'intermediate-source', |
322 ): |
324 ): |
323 node = extra.get(label) |
325 node = extra.get(label) |
324 |
326 |
325 if node is None: |
327 if node is None: |
326 continue |
328 continue |
327 |
329 |
328 # Only transplant stores its reference in binary |
330 # Only transplant stores its reference in binary |
329 if label == 'transplant_source': |
331 if label == b'transplant_source': |
330 node = nodemod.hex(node) |
332 node = nodemod.hex(node) |
331 |
333 |
332 newrev = revmap.get(node) |
334 newrev = revmap.get(node) |
333 if newrev is not None: |
335 if newrev is not None: |
334 if label == 'transplant_source': |
336 if label == b'transplant_source': |
335 newrev = nodemod.bin(newrev) |
337 newrev = nodemod.bin(newrev) |
336 |
338 |
337 extra[label] = newrev |
339 extra[label] = newrev |
338 |
340 |
339 if self.branchnames and commit.branch: |
341 if self.branchnames and commit.branch: |
340 extra['branch'] = commit.branch |
342 extra[b'branch'] = commit.branch |
341 if commit.rev and commit.saverev: |
343 if commit.rev and commit.saverev: |
342 extra['convert_revision'] = commit.rev |
344 extra[b'convert_revision'] = commit.rev |
343 |
345 |
344 while parents: |
346 while parents: |
345 p1 = p2 |
347 p1 = p2 |
346 p2 = parents.pop(0) |
348 p2 = parents.pop(0) |
347 p1ctx = self.repo[p1] |
349 p1ctx = self.repo[p1] |
394 if ctx.phase() < phases.draft: |
396 if ctx.phase() < phases.draft: |
395 phases.registernew( |
397 phases.registernew( |
396 self.repo, tr, phases.draft, [ctx.node()] |
398 self.repo, tr, phases.draft, [ctx.node()] |
397 ) |
399 ) |
398 |
400 |
399 text = "(octopus merge fixup)\n" |
401 text = b"(octopus merge fixup)\n" |
400 p2 = node |
402 p2 = node |
401 |
403 |
402 if self.filemapmode and nparents == 1: |
404 if self.filemapmode and nparents == 1: |
403 man = self.repo.manifestlog.getstorage(b'') |
405 man = self.repo.manifestlog.getstorage(b'') |
404 mnode = self.repo.changelog.read(nodemod.bin(p2))[0] |
406 mnode = self.repo.changelog.read(nodemod.bin(p2))[0] |
405 closed = 'close' in commit.extra |
407 closed = b'close' in commit.extra |
406 if not closed and not man.cmp(m1node, man.revision(mnode)): |
408 if not closed and not man.cmp(m1node, man.revision(mnode)): |
407 self.ui.status(_("filtering out empty revision\n")) |
409 self.ui.status(_(b"filtering out empty revision\n")) |
408 self.repo.rollback(force=True) |
410 self.repo.rollback(force=True) |
409 return parent |
411 return parent |
410 return p2 |
412 return p2 |
411 |
413 |
412 def puttags(self, tags): |
414 def puttags(self, tags): |
414 tagparent = tagparent or nodemod.nullid |
416 tagparent = tagparent or nodemod.nullid |
415 |
417 |
416 oldlines = set() |
418 oldlines = set() |
417 for branch, heads in self.repo.branchmap().iteritems(): |
419 for branch, heads in self.repo.branchmap().iteritems(): |
418 for h in heads: |
420 for h in heads: |
419 if '.hgtags' in self.repo[h]: |
421 if b'.hgtags' in self.repo[h]: |
420 oldlines.update( |
422 oldlines.update( |
421 set(self.repo[h]['.hgtags'].data().splitlines(True)) |
423 set(self.repo[h][b'.hgtags'].data().splitlines(True)) |
422 ) |
424 ) |
423 oldlines = sorted(list(oldlines)) |
425 oldlines = sorted(list(oldlines)) |
424 |
426 |
425 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags]) |
427 newlines = sorted([(b"%s %s\n" % (tags[tag], tag)) for tag in tags]) |
426 if newlines == oldlines: |
428 if newlines == oldlines: |
427 return None, None |
429 return None, None |
428 |
430 |
429 # if the old and new tags match, then there is nothing to update |
431 # if the old and new tags match, then there is nothing to update |
430 oldtags = set() |
432 oldtags = set() |
431 newtags = set() |
433 newtags = set() |
432 for line in oldlines: |
434 for line in oldlines: |
433 s = line.strip().split(' ', 1) |
435 s = line.strip().split(b' ', 1) |
434 if len(s) != 2: |
436 if len(s) != 2: |
435 continue |
437 continue |
436 oldtags.add(s[1]) |
438 oldtags.add(s[1]) |
437 for line in newlines: |
439 for line in newlines: |
438 s = line.strip().split(' ', 1) |
440 s = line.strip().split(b' ', 1) |
439 if len(s) != 2: |
441 if len(s) != 2: |
440 continue |
442 continue |
441 if s[1] not in oldtags: |
443 if s[1] not in oldtags: |
442 newtags.add(s[1].strip()) |
444 newtags.add(s[1].strip()) |
443 |
445 |
444 if not newtags: |
446 if not newtags: |
445 return None, None |
447 return None, None |
446 |
448 |
447 data = "".join(newlines) |
449 data = b"".join(newlines) |
448 |
450 |
449 def getfilectx(repo, memctx, f): |
451 def getfilectx(repo, memctx, f): |
450 return context.memfilectx(repo, memctx, f, data, False, False, None) |
452 return context.memfilectx(repo, memctx, f, data, False, False, None) |
451 |
453 |
452 self.ui.status(_("updating tags\n")) |
454 self.ui.status(_(b"updating tags\n")) |
453 date = "%d 0" % int(time.mktime(time.gmtime())) |
455 date = b"%d 0" % int(time.mktime(time.gmtime())) |
454 extra = {'branch': self.tagsbranch} |
456 extra = {b'branch': self.tagsbranch} |
455 ctx = context.memctx( |
457 ctx = context.memctx( |
456 self.repo, |
458 self.repo, |
457 (tagparent, None), |
459 (tagparent, None), |
458 "update tags", |
460 b"update tags", |
459 [".hgtags"], |
461 [b".hgtags"], |
460 getfilectx, |
462 getfilectx, |
461 "convert-repo", |
463 b"convert-repo", |
462 date, |
464 date, |
463 extra, |
465 extra, |
464 ) |
466 ) |
465 node = self.repo.commitctx(ctx) |
467 node = self.repo.commitctx(ctx) |
466 return nodemod.hex(node), nodemod.hex(tagparent) |
468 return nodemod.hex(node), nodemod.hex(tagparent) |
493 |
495 |
494 def hascommitforsplicemap(self, rev): |
496 def hascommitforsplicemap(self, rev): |
495 if rev not in self.repo and self.clonebranches: |
497 if rev not in self.repo and self.clonebranches: |
496 raise error.Abort( |
498 raise error.Abort( |
497 _( |
499 _( |
498 'revision %s not found in destination ' |
500 b'revision %s not found in destination ' |
499 'repository (lookups with clonebranches=true ' |
501 b'repository (lookups with clonebranches=true ' |
500 'are not implemented)' |
502 b'are not implemented)' |
501 ) |
503 ) |
502 % rev |
504 % rev |
503 ) |
505 ) |
504 return rev in self.repo |
506 return rev in self.repo |
505 |
507 |
506 |
508 |
507 class mercurial_source(common.converter_source): |
509 class mercurial_source(common.converter_source): |
508 def __init__(self, ui, repotype, path, revs=None): |
510 def __init__(self, ui, repotype, path, revs=None): |
509 common.converter_source.__init__(self, ui, repotype, path, revs) |
511 common.converter_source.__init__(self, ui, repotype, path, revs) |
510 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors') |
512 self.ignoreerrors = ui.configbool(b'convert', b'hg.ignoreerrors') |
511 self.ignored = set() |
513 self.ignored = set() |
512 self.saverev = ui.configbool('convert', 'hg.saverev') |
514 self.saverev = ui.configbool(b'convert', b'hg.saverev') |
513 try: |
515 try: |
514 self.repo = hg.repository(self.ui, path) |
516 self.repo = hg.repository(self.ui, path) |
515 # try to provoke an exception if this isn't really a hg |
517 # try to provoke an exception if this isn't really a hg |
516 # repo, but some other bogus compatible-looking url |
518 # repo, but some other bogus compatible-looking url |
517 if not self.repo.local(): |
519 if not self.repo.local(): |
518 raise error.RepoError |
520 raise error.RepoError |
519 except error.RepoError: |
521 except error.RepoError: |
520 ui.traceback() |
522 ui.traceback() |
521 raise NoRepo(_("%s is not a local Mercurial repository") % path) |
523 raise NoRepo(_(b"%s is not a local Mercurial repository") % path) |
522 self.lastrev = None |
524 self.lastrev = None |
523 self.lastctx = None |
525 self.lastctx = None |
524 self._changescache = None, None |
526 self._changescache = None, None |
525 self.convertfp = None |
527 self.convertfp = None |
526 # Restrict converted revisions to startrev descendants |
528 # Restrict converted revisions to startrev descendants |
527 startnode = ui.config('convert', 'hg.startrev') |
529 startnode = ui.config(b'convert', b'hg.startrev') |
528 hgrevs = ui.config('convert', 'hg.revs') |
530 hgrevs = ui.config(b'convert', b'hg.revs') |
529 if hgrevs is None: |
531 if hgrevs is None: |
530 if startnode is not None: |
532 if startnode is not None: |
531 try: |
533 try: |
532 startnode = self.repo.lookup(startnode) |
534 startnode = self.repo.lookup(startnode) |
533 except error.RepoError: |
535 except error.RepoError: |
534 raise error.Abort( |
536 raise error.Abort( |
535 _('%s is not a valid start revision') % startnode |
537 _(b'%s is not a valid start revision') % startnode |
536 ) |
538 ) |
537 startrev = self.repo.changelog.rev(startnode) |
539 startrev = self.repo.changelog.rev(startnode) |
538 children = {startnode: 1} |
540 children = {startnode: 1} |
539 for r in self.repo.changelog.descendants([startrev]): |
541 for r in self.repo.changelog.descendants([startrev]): |
540 children[self.repo.changelog.node(r)] = 1 |
542 children[self.repo.changelog.node(r)] = 1 |
694 |
699 |
695 return ma + r |
700 return ma + r |
696 |
701 |
697 def converted(self, rev, destrev): |
702 def converted(self, rev, destrev): |
698 if self.convertfp is None: |
703 if self.convertfp is None: |
699 self.convertfp = open(self.repo.vfs.join('shamap'), 'ab') |
704 self.convertfp = open(self.repo.vfs.join(b'shamap'), b'ab') |
700 self.convertfp.write(util.tonativeeol('%s %s\n' % (destrev, rev))) |
705 self.convertfp.write(util.tonativeeol(b'%s %s\n' % (destrev, rev))) |
701 self.convertfp.flush() |
706 self.convertfp.flush() |
702 |
707 |
703 def before(self): |
708 def before(self): |
704 self.ui.debug('run hg source pre-conversion action\n') |
709 self.ui.debug(b'run hg source pre-conversion action\n') |
705 |
710 |
706 def after(self): |
711 def after(self): |
707 self.ui.debug('run hg source post-conversion action\n') |
712 self.ui.debug(b'run hg source post-conversion action\n') |
708 |
713 |
709 def hasnativeorder(self): |
714 def hasnativeorder(self): |
710 return True |
715 return True |
711 |
716 |
712 def hasnativeclose(self): |
717 def hasnativeclose(self): |