14 # |
14 # |
15 # * Using "--config convert.hg.saverev=true" will make the source |
15 # * Using "--config convert.hg.saverev=true" will make the source |
16 # identifier to be stored in the converted revision. This will cause |
16 # identifier to be stored in the converted revision. This will cause |
17 # the converted revision to have a different identity than the |
17 # the converted revision to have a different identity than the |
18 # source. |
18 # source. |
19 |
19 from __future__ import absolute_import |
20 |
20 |
21 import os, time, cStringIO |
21 import cStringIO |
|
22 import os |
|
23 import re |
|
24 import time |
|
25 |
|
26 from mercurial import ( |
|
27 bookmarks, |
|
28 context, |
|
29 error, |
|
30 exchange, |
|
31 hg, |
|
32 lock as lockmod, |
|
33 merge as mergemod, |
|
34 node as nodemod, |
|
35 phases, |
|
36 scmutil, |
|
37 util, |
|
38 ) |
22 from mercurial.i18n import _ |
39 from mercurial.i18n import _ |
23 from mercurial.node import bin, hex, nullid |
40 from . import common |
24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange |
41 mapfile = common.mapfile |
25 from mercurial import phases |
42 NoRepo = common.NoRepo |
26 from mercurial import lock as lockmod |
43 |
27 from mercurial import merge as mergemod |
|
28 |
|
29 from common import NoRepo, commit, converter_source, converter_sink, mapfile |
|
30 |
|
31 import re |
|
32 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b') |
44 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b') |
33 |
45 |
34 class mercurial_sink(converter_sink): |
46 class mercurial_sink(common.converter_sink): |
35 def __init__(self, ui, path): |
47 def __init__(self, ui, path): |
36 converter_sink.__init__(self, ui, path) |
48 common.converter_sink.__init__(self, ui, path) |
37 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True) |
49 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True) |
38 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False) |
50 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False) |
39 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default') |
51 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default') |
40 self.lastbranch = None |
52 self.lastbranch = None |
41 if os.path.isdir(path) and len(os.listdir(path)) > 0: |
53 if os.path.isdir(path) and len(os.listdir(path)) > 0: |
146 if len(s) != 2: |
158 if len(s) != 2: |
147 continue |
159 continue |
148 |
160 |
149 revid = s[0] |
161 revid = s[0] |
150 subpath = s[1] |
162 subpath = s[1] |
151 if revid != hex(nullid): |
163 if revid != nodemod.nullhex: |
152 revmap = self.subrevmaps.get(subpath) |
164 revmap = self.subrevmaps.get(subpath) |
153 if revmap is None: |
165 if revmap is None: |
154 revmap = mapfile(self.ui, |
166 revmap = mapfile(self.ui, |
155 self.repo.wjoin(subpath, '.hg/shamap')) |
167 self.repo.wjoin(subpath, '.hg/shamap')) |
156 self.subrevmaps[subpath] = revmap |
168 self.subrevmaps[subpath] = revmap |
248 if p not in pl: |
260 if p not in pl: |
249 pl.append(p) |
261 pl.append(p) |
250 parents = pl |
262 parents = pl |
251 nparents = len(parents) |
263 nparents = len(parents) |
252 if self.filemapmode and nparents == 1: |
264 if self.filemapmode and nparents == 1: |
253 m1node = self.repo.changelog.read(bin(parents[0]))[0] |
265 m1node = self.repo.changelog.read(nodemod.bin(parents[0]))[0] |
254 parent = parents[0] |
266 parent = parents[0] |
255 |
267 |
256 if len(parents) < 2: |
268 if len(parents) < 2: |
257 parents.append(nullid) |
269 parents.append(nodemod.nullid) |
258 if len(parents) < 2: |
270 if len(parents) < 2: |
259 parents.append(nullid) |
271 parents.append(nodemod.nullid) |
260 p2 = parents.pop(0) |
272 p2 = parents.pop(0) |
261 |
273 |
262 text = commit.desc |
274 text = commit.desc |
263 |
275 |
264 sha1s = re.findall(sha1re, text) |
276 sha1s = re.findall(sha1re, text) |
281 if node is None: |
293 if node is None: |
282 continue |
294 continue |
283 |
295 |
284 # Only transplant stores its reference in binary |
296 # Only transplant stores its reference in binary |
285 if label == 'transplant_source': |
297 if label == 'transplant_source': |
286 node = hex(node) |
298 node = nodemod.hex(node) |
287 |
299 |
288 newrev = revmap.get(node) |
300 newrev = revmap.get(node) |
289 if newrev is not None: |
301 if newrev is not None: |
290 if label == 'transplant_source': |
302 if label == 'transplant_source': |
291 newrev = bin(newrev) |
303 newrev = nodemod.bin(newrev) |
292 |
304 |
293 extra[label] = newrev |
305 extra[label] = newrev |
294 |
306 |
295 if self.branchnames and commit.branch: |
307 if self.branchnames and commit.branch: |
296 extra['branch'] = commit.branch |
308 extra['branch'] = commit.branch |
322 # commit, so copy the source's phase for now. |
334 # commit, so copy the source's phase for now. |
323 self.repo.ui.setconfig('phases', 'new-commit', |
335 self.repo.ui.setconfig('phases', 'new-commit', |
324 phases.phasenames[commit.phase], 'convert') |
336 phases.phasenames[commit.phase], 'convert') |
325 |
337 |
326 with self.repo.transaction("convert") as tr: |
338 with self.repo.transaction("convert") as tr: |
327 node = hex(self.repo.commitctx(ctx)) |
339 node = nodemod.hex(self.repo.commitctx(ctx)) |
328 |
340 |
329 # If the node value has changed, but the phase is lower than |
341 # If the node value has changed, but the phase is lower than |
330 # draft, set it back to draft since it hasn't been exposed |
342 # draft, set it back to draft since it hasn't been exposed |
331 # anywhere. |
343 # anywhere. |
332 if commit.rev != node: |
344 if commit.rev != node: |
338 text = "(octopus merge fixup)\n" |
350 text = "(octopus merge fixup)\n" |
339 p2 = node |
351 p2 = node |
340 |
352 |
341 if self.filemapmode and nparents == 1: |
353 if self.filemapmode and nparents == 1: |
342 man = self.repo.manifest |
354 man = self.repo.manifest |
343 mnode = self.repo.changelog.read(bin(p2))[0] |
355 mnode = self.repo.changelog.read(nodemod.bin(p2))[0] |
344 closed = 'close' in commit.extra |
356 closed = 'close' in commit.extra |
345 if not closed and not man.cmp(m1node, man.revision(mnode)): |
357 if not closed and not man.cmp(m1node, man.revision(mnode)): |
346 self.ui.status(_("filtering out empty revision\n")) |
358 self.ui.status(_("filtering out empty revision\n")) |
347 self.repo.rollback(force=True) |
359 self.repo.rollback(force=True) |
348 return parent |
360 return parent |
352 try: |
364 try: |
353 parentctx = self.repo[self.tagsbranch] |
365 parentctx = self.repo[self.tagsbranch] |
354 tagparent = parentctx.node() |
366 tagparent = parentctx.node() |
355 except error.RepoError: |
367 except error.RepoError: |
356 parentctx = None |
368 parentctx = None |
357 tagparent = nullid |
369 tagparent = nodemod.nullid |
358 |
370 |
359 oldlines = set() |
371 oldlines = set() |
360 for branch, heads in self.repo.branchmap().iteritems(): |
372 for branch, heads in self.repo.branchmap().iteritems(): |
361 for h in heads: |
373 for h in heads: |
362 if '.hgtags' in self.repo[h]: |
374 if '.hgtags' in self.repo[h]: |
395 extra = {'branch': self.tagsbranch} |
407 extra = {'branch': self.tagsbranch} |
396 ctx = context.memctx(self.repo, (tagparent, None), "update tags", |
408 ctx = context.memctx(self.repo, (tagparent, None), "update tags", |
397 [".hgtags"], getfilectx, "convert-repo", date, |
409 [".hgtags"], getfilectx, "convert-repo", date, |
398 extra) |
410 extra) |
399 node = self.repo.commitctx(ctx) |
411 node = self.repo.commitctx(ctx) |
400 return hex(node), hex(tagparent) |
412 return nodemod.hex(node), nodemod.hex(tagparent) |
401 |
413 |
402 def setfilemapmode(self, active): |
414 def setfilemapmode(self, active): |
403 self.filemapmode = active |
415 self.filemapmode = active |
404 |
416 |
405 def putbookmarks(self, updatedbookmark): |
417 def putbookmarks(self, updatedbookmark): |
411 lock = self.repo.lock() |
423 lock = self.repo.lock() |
412 tr = self.repo.transaction('bookmark') |
424 tr = self.repo.transaction('bookmark') |
413 self.ui.status(_("updating bookmarks\n")) |
425 self.ui.status(_("updating bookmarks\n")) |
414 destmarks = self.repo._bookmarks |
426 destmarks = self.repo._bookmarks |
415 for bookmark in updatedbookmark: |
427 for bookmark in updatedbookmark: |
416 destmarks[bookmark] = bin(updatedbookmark[bookmark]) |
428 destmarks[bookmark] = nodemod.bin(updatedbookmark[bookmark]) |
417 destmarks.recordchange(tr) |
429 destmarks.recordchange(tr) |
418 tr.close() |
430 tr.close() |
419 finally: |
431 finally: |
420 lockmod.release(lock, wlock, tr) |
432 lockmod.release(lock, wlock, tr) |
421 |
433 |
428 raise error.Abort(_('revision %s not found in destination ' |
440 raise error.Abort(_('revision %s not found in destination ' |
429 'repository (lookups with clonebranches=true ' |
441 'repository (lookups with clonebranches=true ' |
430 'are not implemented)') % rev) |
442 'are not implemented)') % rev) |
431 return rev in self.repo |
443 return rev in self.repo |
432 |
444 |
433 class mercurial_source(converter_source): |
445 class mercurial_source(common.converter_source): |
434 def __init__(self, ui, path, revs=None): |
446 def __init__(self, ui, path, revs=None): |
435 converter_source.__init__(self, ui, path, revs) |
447 common.converter_source.__init__(self, ui, path, revs) |
436 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False) |
448 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False) |
437 self.ignored = set() |
449 self.ignored = set() |
438 self.saverev = ui.configbool('convert', 'hg.saverev', False) |
450 self.saverev = ui.configbool('convert', 'hg.saverev', False) |
439 try: |
451 try: |
440 self.repo = hg.repository(self.ui, path) |
452 self.repo = hg.repository(self.ui, path) |
491 |
503 |
492 def _parents(self, ctx): |
504 def _parents(self, ctx): |
493 return [p for p in ctx.parents() if p and self.keep(p.node())] |
505 return [p for p in ctx.parents() if p and self.keep(p.node())] |
494 |
506 |
495 def getheads(self): |
507 def getheads(self): |
496 return [hex(h) for h in self._heads if self.keep(h)] |
508 return [nodemod.hex(h) for h in self._heads if self.keep(h)] |
497 |
509 |
498 def getfile(self, name, rev): |
510 def getfile(self, name, rev): |
499 try: |
511 try: |
500 fctx = self._changectx(rev)[name] |
512 fctx = self._changectx(rev)[name] |
501 return fctx.data(), fctx.flags() |
513 return fctx.data(), fctx.flags() |
570 def getcommit(self, rev): |
582 def getcommit(self, rev): |
571 ctx = self._changectx(rev) |
583 ctx = self._changectx(rev) |
572 parents = [p.hex() for p in self._parents(ctx)] |
584 parents = [p.hex() for p in self._parents(ctx)] |
573 crev = rev |
585 crev = rev |
574 |
586 |
575 return commit(author=ctx.user(), |
587 return common.commit(author=ctx.user(), |
576 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'), |
588 date=util.datestr(ctx.date(), |
577 desc=ctx.description(), rev=crev, parents=parents, |
589 '%Y-%m-%d %H:%M:%S %1%2'), |
578 branch=ctx.branch(), extra=ctx.extra(), |
590 desc=ctx.description(), |
579 sortkey=ctx.rev(), saverev=self.saverev, |
591 rev=crev, |
580 phase=ctx.phase()) |
592 parents=parents, |
|
593 branch=ctx.branch(), |
|
594 extra=ctx.extra(), |
|
595 sortkey=ctx.rev(), |
|
596 saverev=self.saverev, |
|
597 phase=ctx.phase()) |
581 |
598 |
582 def gettags(self): |
599 def gettags(self): |
583 # This will get written to .hgtags, filter non global tags out. |
600 # This will get written to .hgtags, filter non global tags out. |
584 tags = [t for t in self.repo.tagslist() |
601 tags = [t for t in self.repo.tagslist() |
585 if self.repo.tagtype(t[0]) == 'global'] |
602 if self.repo.tagtype(t[0]) == 'global'] |
586 return dict([(name, hex(node)) for name, node in tags |
603 return dict([(name, nodemod.hex(node)) for name, node in tags |
587 if self.keep(node)]) |
604 if self.keep(node)]) |
588 |
605 |
589 def getchangedfiles(self, rev, i): |
606 def getchangedfiles(self, rev, i): |
590 ctx = self._changectx(rev) |
607 ctx = self._changectx(rev) |
591 parents = self._parents(ctx) |
608 parents = self._parents(ctx) |
620 def hasnativeclose(self): |
637 def hasnativeclose(self): |
621 return True |
638 return True |
622 |
639 |
623 def lookuprev(self, rev): |
640 def lookuprev(self, rev): |
624 try: |
641 try: |
625 return hex(self.repo.lookup(rev)) |
642 return nodemod.hex(self.repo.lookup(rev)) |
626 except (error.RepoError, error.LookupError): |
643 except (error.RepoError, error.LookupError): |
627 return None |
644 return None |
628 |
645 |
629 def getbookmarks(self): |
646 def getbookmarks(self): |
630 return bookmarks.listbookmarks(self.repo) |
647 return bookmarks.listbookmarks(self.repo) |