559 ui.note(_('creating directory: %s\n') % origbackupdir) |
562 ui.note(_('creating directory: %s\n') % origbackupdir) |
560 util.makedirs(origbackupdir) |
563 util.makedirs(origbackupdir) |
561 |
564 |
562 return fullorigpath + ".orig" |
565 return fullorigpath + ".orig" |
563 |
566 |
|
567 def cleanupnodes(repo, mapping, operation): |
|
568 """do common cleanups when old nodes are replaced by new nodes |
|
569 |
|
570 That includes writing obsmarkers or stripping nodes, and moving bookmarks. |
|
571 (we might also want to move working directory parent in the future) |
|
572 |
|
573 mapping is {oldnode: [newnode]} or a iterable of nodes if they do not have |
|
574 replacements. operation is a string, like "rebase". |
|
575 """ |
|
576 if not util.safehasattr(mapping, 'items'): |
|
577 mapping = {n: () for n in mapping} |
|
578 |
|
579 with repo.transaction('cleanup') as tr: |
|
580 # Move bookmarks |
|
581 bmarks = repo._bookmarks |
|
582 bmarkchanged = False |
|
583 for oldnode, newnodes in mapping.items(): |
|
584 oldbmarks = repo.nodebookmarks(oldnode) |
|
585 if not oldbmarks: |
|
586 continue |
|
587 bmarkchanged = True |
|
588 if len(newnodes) > 1: |
|
589 heads = list(repo.set('heads(%ln)', newnodes)) |
|
590 if len(heads) != 1: |
|
591 raise error.ProgrammingError( |
|
592 'cannot figure out bookmark movement') |
|
593 newnode = heads[0].node() |
|
594 elif len(newnodes) == 0: |
|
595 # move bookmark backwards |
|
596 roots = list(repo.set('max((::%n) - %ln)', oldnode, |
|
597 list(mapping))) |
|
598 if roots: |
|
599 newnode = roots[0].node() |
|
600 else: |
|
601 newnode = nullid |
|
602 else: |
|
603 newnode = newnodes[0] |
|
604 repo.ui.debug('moving bookmarks %r from %s to %s\n' % |
|
605 (oldbmarks, hex(oldnode), hex(newnode))) |
|
606 for name in oldbmarks: |
|
607 bmarks[name] = newnode |
|
608 if bmarkchanged: |
|
609 bmarks.recordchange(tr) |
|
610 |
|
611 # Obsolete or strip nodes |
|
612 if obsolete.isenabled(repo, obsolete.createmarkersopt): |
|
613 # If a node is already obsoleted, and we want to obsolete it |
|
614 # without a successor, skip that obssolete request since it's |
|
615 # unnecessary. That's the "if s or not isobs(n)" check below. |
|
616 # Also sort the node in topology order, that might be useful for |
|
617 # some obsstore logic. |
|
618 # NOTE: the filtering and sorting might belong to createmarkers. |
|
619 isobs = repo.obsstore.successors.__contains__ |
|
620 sortfunc = lambda ns: repo.changelog.rev(ns[0]) |
|
621 rels = [(repo[n], (repo[m] for m in s)) |
|
622 for n, s in sorted(mapping.items(), key=sortfunc) |
|
623 if s or not isobs(n)] |
|
624 obsolete.createmarkers(repo, rels, operation=operation) |
|
625 else: |
|
626 from . import repair # avoid import cycle |
|
627 repair.delayedstrip(repo.ui, repo, list(mapping), operation) |
|
628 |
564 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): |
629 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): |
565 if opts is None: |
630 if opts is None: |
566 opts = {} |
631 opts = {} |
567 m = matcher |
632 m = matcher |
568 if dry_run is None: |
633 if dry_run is None: |