# HG changeset patch # User Pierre-Yves David # Date 1500783930 -7200 # Node ID 83ad13719e26834d1842c8d67b71d49d4a03d5f7 # Parent 8a2e1aac6b41973f5d23c0590d9e33d961991835 commands: move 'prune' to the 'evocommands' module diff -r 8a2e1aac6b41 -r 83ad13719e26 hgext3rd/evolve/__init__.py --- a/hgext3rd/evolve/__init__.py Sun Jul 23 06:14:09 2017 +0200 +++ b/hgext3rd/evolve/__init__.py Sun Jul 23 06:25:30 2017 +0200 @@ -877,12 +877,6 @@ ### new command ############################# -metadataopts = [ - ('d', 'date', '', - _('record the specified date in metadata'), _('DATE')), - ('u', 'user', '', - _('record the specified user in metadata'), _('USER')), -] @eh.uisetup def _installimportobsolete(ui): @@ -2110,202 +2104,6 @@ finally: lockmod.release(wlock) -def _getmetadata(**opts): - metadata = {} - date = opts.get('date') - user = opts.get('user') - if date: - metadata['date'] = '%i %i' % util.parsedate(date) - if user: - metadata['user'] = user - return metadata - -@eh.command( - '^prune|obsolete', - [('n', 'new', [], _("successor changeset (DEPRECATED)")), - ('s', 'succ', [], _("successor changeset")), - ('r', 'rev', [], _("revisions to prune")), - ('k', 'keep', None, _("does not modify working copy during prune")), - ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")), - ('', 'fold', False, - _("record a fold (multiple precursors, one successors)")), - ('', 'split', False, - _("record a split (on precursor, multiple successors)")), - ('B', 'bookmark', [], _("remove revs only reachable from given" - " bookmark"))] + metadataopts, - _('[OPTION] [-r] REV...')) -# XXX -U --noupdate option to prevent wc update and or bookmarks update ? -def cmdprune(ui, repo, *revs, **opts): - """hide changesets by marking them obsolete - - Pruned changesets are obsolete with no successors. If they also have no - descendants, they are hidden (invisible to all commands). - - Non-obsolete descendants of pruned changesets become "unstable". Use :hg:`evolve` - to handle this situation. - - When you prune the parent of your working copy, Mercurial updates the working - copy to a non-obsolete parent. - - You can use ``--succ`` to tell Mercurial that a newer version (successor) of the - pruned changeset exists. Mercurial records successor revisions in obsolescence - markers. - - You can use the ``--biject`` option to specify a 1-1 mapping (bijection) between - revisions to pruned (precursor) and successor changesets. This option may be - removed in a future release (with the functionality provided automatically). - - If you specify multiple revisions in ``--succ``, you are recording a "split" and - must acknowledge it by passing ``--split``. Similarly, when you prune multiple - changesets with a single successor, you must pass the ``--fold`` option. - """ - revs = scmutil.revrange(repo, list(revs) + opts.get('rev')) - succs = opts['new'] + opts['succ'] - bookmarks = set(opts.get('bookmark')) - metadata = _getmetadata(**opts) - biject = opts.get('biject') - fold = opts.get('fold') - split = opts.get('split') - - options = [o for o in ('biject', 'fold', 'split') if opts.get(o)] - if 1 < len(options): - raise error.Abort(_("can only specify one of %s") % ', '.join(options)) - - if bookmarks: - reachablefrombookmark = rewriteutil.reachablefrombookmark - repomarks, revs = reachablefrombookmark(repo, revs, bookmarks) - if not revs: - # no revisions to prune - delete bookmark immediately - rewriteutil.deletebookmark(repo, repomarks, bookmarks) - - if not revs: - raise error.Abort(_('nothing to prune')) - - wlock = lock = tr = None - try: - wlock = repo.wlock() - lock = repo.lock() - tr = repo.transaction('prune') - # defines pruned changesets - precs = [] - revs.sort() - for p in revs: - cp = repo[p] - if not cp.mutable(): - # note: createmarkers() would have raised something anyway - raise error.Abort('cannot prune immutable changeset: %s' % cp, - hint="see 'hg help phases' for details") - precs.append(cp) - if not precs: - raise error.Abort('nothing to prune') - - if rewriteutil.disallowednewunstable(repo, revs): - raise error.Abort(_("cannot prune in the middle of a stack"), - hint=_("new unstable changesets are not allowed")) - - # defines successors changesets - sucs = scmutil.revrange(repo, succs) - sucs.sort() - sucs = tuple(repo[n] for n in sucs) - if not biject and len(sucs) > 1 and len(precs) > 1: - msg = "Can't use multiple successors for multiple precursors" - hint = _("use --biject to mark a series as a replacement" - " for another") - raise error.Abort(msg, hint=hint) - elif biject and len(sucs) != len(precs): - msg = "Can't use %d successors for %d precursors" \ - % (len(sucs), len(precs)) - raise error.Abort(msg) - elif (len(precs) == 1 and len(sucs) > 1) and not split: - msg = "please add --split if you want to do a split" - raise error.Abort(msg) - elif len(sucs) == 1 and len(precs) > 1 and not fold: - msg = "please add --fold if you want to do a fold" - raise error.Abort(msg) - elif biject: - relations = [(p, (s,)) for p, s in zip(precs, sucs)] - else: - relations = [(p, sucs) for p in precs] - - wdp = repo['.'] - - if len(sucs) == 1 and len(precs) == 1 and wdp in precs: - # '.' killed, so update to the successor - newnode = sucs[0] - else: - # update to an unkilled parent - newnode = wdp - - while newnode in precs or newnode.obsolete(): - newnode = newnode.parents()[0] - - if newnode.node() != wdp.node(): - if opts.get('keep', False): - # This is largely the same as the implementation in - # strip.stripcmd(). We might want to refactor this somewhere - # common at some point. - - # only reset the dirstate for files that would actually change - # between the working context and uctx - descendantrevs = repo.revs("%d::." % newnode.rev()) - changedfiles = [] - for rev in descendantrevs: - # blindly reset the files, regardless of what actually - # changed - changedfiles.extend(repo[rev].files()) - - # reset files that only changed in the dirstate too - dirstate = repo.dirstate - dirchanges = [f for f in dirstate if dirstate[f] != 'n'] - changedfiles.extend(dirchanges) - repo.dirstate.rebuild(newnode.node(), newnode.manifest(), - changedfiles) - dirstate.write(tr) - else: - bookactive = repo._activebookmark - # Active bookmark that we don't want to delete (with -B option) - # we deactivate and move it before the update and reactivate it - # after - movebookmark = bookactive and not bookmarks - if movebookmark: - bookmarksmod.deactivate(repo) - bmchanges = [(bookactive, newnode.node())] - compat.bookmarkapplychanges(repo, tr, bmchanges) - commands.update(ui, repo, newnode.rev()) - ui.status(_('working directory now at %s\n') - % ui.label(str(newnode), 'evolve.node')) - if movebookmark: - bookmarksmod.activate(repo, bookactive) - - # update bookmarks - if bookmarks: - rewriteutil.deletebookmark(repo, repomarks, bookmarks) - - # create markers - obsolete.createmarkers(repo, relations, metadata=metadata) - - # informs that changeset have been pruned - ui.status(_('%i changesets pruned\n') % len(precs)) - - for ctx in repo.unfiltered().set('bookmark() and %ld', precs): - # used to be: - # - # ldest = list(repo.set('max((::%d) - obsolete())', ctx)) - # if ldest: - # c = ldest[0] - # - # but then revset took a lazy arrow in the knee and became much - # slower. The new forms makes as much sense and a much faster. - for dest in ctx.ancestors(): - if not dest.obsolete(): - updatebookmarks = _bookmarksupdater(repo, ctx.node(), tr) - updatebookmarks(dest.node()) - break - - tr.close() - finally: - lockmod.release(tr, lock, wlock) - @eh.wrapcommand('commit') def commitwrapper(orig, ui, repo, *arg, **kwargs): tr = None @@ -2366,7 +2164,7 @@ kwargs['new'] = [] kwargs['succ'] = [] kwargs['biject'] = False - return cmdprune(ui, repo, *revs, **kwargs) + return evocommands.cmdprune(ui, repo, *revs, **kwargs) @eh.wrapcommand('graft') def graftwrapper(orig, ui, repo, *revs, **kwargs): diff -r 8a2e1aac6b41 -r 83ad13719e26 hgext3rd/evolve/evocommands.py --- a/hgext3rd/evolve/evocommands.py Sun Jul 23 06:14:09 2017 +0200 +++ b/hgext3rd/evolve/evocommands.py Sun Jul 23 06:25:30 2017 +0200 @@ -549,6 +549,210 @@ finally: lockmod.release(lock, wlock) +metadataopts = [ + ('d', 'date', '', + _('record the specified date in metadata'), _('DATE')), + ('u', 'user', '', + _('record the specified user in metadata'), _('USER')), +] + +def _getmetadata(**opts): + metadata = {} + date = opts.get('date') + user = opts.get('user') + if date: + metadata['date'] = '%i %i' % util.parsedate(date) + if user: + metadata['user'] = user + return metadata + +@eh.command( + '^prune|obsolete', + [('n', 'new', [], _("successor changeset (DEPRECATED)")), + ('s', 'succ', [], _("successor changeset")), + ('r', 'rev', [], _("revisions to prune")), + ('k', 'keep', None, _("does not modify working copy during prune")), + ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")), + ('', 'fold', False, + _("record a fold (multiple precursors, one successors)")), + ('', 'split', False, + _("record a split (on precursor, multiple successors)")), + ('B', 'bookmark', [], _("remove revs only reachable from given" + " bookmark"))] + metadataopts, + _('[OPTION] [-r] REV...')) +# XXX -U --noupdate option to prevent wc update and or bookmarks update ? +def cmdprune(ui, repo, *revs, **opts): + """hide changesets by marking them obsolete + + Pruned changesets are obsolete with no successors. If they also have no + descendants, they are hidden (invisible to all commands). + + Non-obsolete descendants of pruned changesets become "unstable". Use :hg:`evolve` + to handle this situation. + + When you prune the parent of your working copy, Mercurial updates the working + copy to a non-obsolete parent. + + You can use ``--succ`` to tell Mercurial that a newer version (successor) of the + pruned changeset exists. Mercurial records successor revisions in obsolescence + markers. + + You can use the ``--biject`` option to specify a 1-1 mapping (bijection) between + revisions to pruned (precursor) and successor changesets. This option may be + removed in a future release (with the functionality provided automatically). + + If you specify multiple revisions in ``--succ``, you are recording a "split" and + must acknowledge it by passing ``--split``. Similarly, when you prune multiple + changesets with a single successor, you must pass the ``--fold`` option. + """ + revs = scmutil.revrange(repo, list(revs) + opts.get('rev')) + succs = opts['new'] + opts['succ'] + bookmarks = set(opts.get('bookmark')) + metadata = _getmetadata(**opts) + biject = opts.get('biject') + fold = opts.get('fold') + split = opts.get('split') + + options = [o for o in ('biject', 'fold', 'split') if opts.get(o)] + if 1 < len(options): + raise error.Abort(_("can only specify one of %s") % ', '.join(options)) + + if bookmarks: + reachablefrombookmark = rewriteutil.reachablefrombookmark + repomarks, revs = reachablefrombookmark(repo, revs, bookmarks) + if not revs: + # no revisions to prune - delete bookmark immediately + rewriteutil.deletebookmark(repo, repomarks, bookmarks) + + if not revs: + raise error.Abort(_('nothing to prune')) + + wlock = lock = tr = None + try: + wlock = repo.wlock() + lock = repo.lock() + tr = repo.transaction('prune') + # defines pruned changesets + precs = [] + revs.sort() + for p in revs: + cp = repo[p] + if not cp.mutable(): + # note: createmarkers() would have raised something anyway + raise error.Abort('cannot prune immutable changeset: %s' % cp, + hint="see 'hg help phases' for details") + precs.append(cp) + if not precs: + raise error.Abort('nothing to prune') + + if rewriteutil.disallowednewunstable(repo, revs): + raise error.Abort(_("cannot prune in the middle of a stack"), + hint=_("new unstable changesets are not allowed")) + + # defines successors changesets + sucs = scmutil.revrange(repo, succs) + sucs.sort() + sucs = tuple(repo[n] for n in sucs) + if not biject and len(sucs) > 1 and len(precs) > 1: + msg = "Can't use multiple successors for multiple precursors" + hint = _("use --biject to mark a series as a replacement" + " for another") + raise error.Abort(msg, hint=hint) + elif biject and len(sucs) != len(precs): + msg = "Can't use %d successors for %d precursors" \ + % (len(sucs), len(precs)) + raise error.Abort(msg) + elif (len(precs) == 1 and len(sucs) > 1) and not split: + msg = "please add --split if you want to do a split" + raise error.Abort(msg) + elif len(sucs) == 1 and len(precs) > 1 and not fold: + msg = "please add --fold if you want to do a fold" + raise error.Abort(msg) + elif biject: + relations = [(p, (s,)) for p, s in zip(precs, sucs)] + else: + relations = [(p, sucs) for p in precs] + + wdp = repo['.'] + + if len(sucs) == 1 and len(precs) == 1 and wdp in precs: + # '.' killed, so update to the successor + newnode = sucs[0] + else: + # update to an unkilled parent + newnode = wdp + + while newnode in precs or newnode.obsolete(): + newnode = newnode.parents()[0] + + if newnode.node() != wdp.node(): + if opts.get('keep', False): + # This is largely the same as the implementation in + # strip.stripcmd(). We might want to refactor this somewhere + # common at some point. + + # only reset the dirstate for files that would actually change + # between the working context and uctx + descendantrevs = repo.revs("%d::." % newnode.rev()) + changedfiles = [] + for rev in descendantrevs: + # blindly reset the files, regardless of what actually + # changed + changedfiles.extend(repo[rev].files()) + + # reset files that only changed in the dirstate too + dirstate = repo.dirstate + dirchanges = [f for f in dirstate if dirstate[f] != 'n'] + changedfiles.extend(dirchanges) + repo.dirstate.rebuild(newnode.node(), newnode.manifest(), + changedfiles) + dirstate.write(tr) + else: + bookactive = repo._activebookmark + # Active bookmark that we don't want to delete (with -B option) + # we deactivate and move it before the update and reactivate it + # after + movebookmark = bookactive and not bookmarks + if movebookmark: + bookmarksmod.deactivate(repo) + bmchanges = [(bookactive, newnode.node())] + compat.bookmarkapplychanges(repo, tr, bmchanges) + commands.update(ui, repo, newnode.rev()) + ui.status(_('working directory now at %s\n') + % ui.label(str(newnode), 'evolve.node')) + if movebookmark: + bookmarksmod.activate(repo, bookactive) + + # update bookmarks + if bookmarks: + rewriteutil.deletebookmark(repo, repomarks, bookmarks) + + # create markers + obsolete.createmarkers(repo, relations, metadata=metadata) + + # informs that changeset have been pruned + ui.status(_('%i changesets pruned\n') % len(precs)) + + for ctx in repo.unfiltered().set('bookmark() and %ld', precs): + # used to be: + # + # ldest = list(repo.set('max((::%d) - obsolete())', ctx)) + # if ldest: + # c = ldest[0] + # + # but then revset took a lazy arrow in the knee and became much + # slower. The new forms makes as much sense and a much faster. + for dest in ctx.ancestors(): + if not dest.obsolete(): + bookmarksupdater = rewriteutil.bookmarksupdater + updatebookmarks = bookmarksupdater(repo, ctx.node(), tr) + updatebookmarks(dest.node()) + break + + tr.close() + finally: + lockmod.release(tr, lock, wlock) + @eh.command( '^split', [('r', 'rev', [], _("revision to split")), diff -r 8a2e1aac6b41 -r 83ad13719e26 hgext3rd/evolve/hack/inhibit.py --- a/hgext3rd/evolve/hack/inhibit.py Sun Jul 23 06:14:09 2017 +0200 +++ b/hgext3rd/evolve/hack/inhibit.py Sun Jul 23 06:25:30 2017 +0200 @@ -106,7 +106,7 @@ 'keep': None, 'biject': False, } - evolve.cmdprune(ui, repo, **optsdict) + evolve.evocommands.cmdprune(ui, repo, **optsdict) # obsolescence inhibitor ########################