diff -r 3dfc88c06378 -r 32306ee32806 hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py Fri Sep 01 17:53:14 2017 +0200 +++ b/hgext3rd/topic/__init__.py Fri Sep 01 18:02:50 2017 +0200 @@ -57,6 +57,7 @@ from mercurial.i18n import _ from mercurial import ( + bookmarks, cmdutil, commands, context, @@ -439,6 +440,82 @@ branch = repo[None].branch() return stack.showstack(ui, repo, branch=branch, topic=topic, opts=opts) +@command('debugcb|debugconvertbookmark', [ + ('b', 'bookmark', '', _('bookmark to convert to topic')), + ('', 'all', None, _('convert all bookmarks to topics')), + ], + _('[-b BOOKMARK] [--all]')) +def debugconvertbookmark(ui, repo, **opts): + """Converts a bookmark to a topic with the same name. + """ + + bookmark = opts.get('bookmark') + convertall = opts.get('all') + + if convertall and bookmark: + raise error.Abort(_("cannot use '--all' and '-b' together")) + if not (convertall or bookmark): + raise error.Abort(_("you must specify either '--all' or '-b'")) + + bmstore = repo._bookmarks + lock = wlock = tr = None + + if bookmark: + try: + node = bmstore[bookmark] + except KeyError: + raise error.Abort(_("no such bookmark exists: '%s'") % bookmark) + + revnum = repo[node].rev() + try: + wlock = repo.wlock() + lock = repo.lock() + tr = repo.transaction('debugconvertbookmark') + _convertbmarktopic(ui, repo, revnum, bookmark, tr) + tr.close() + finally: + lockmod.release(tr, lock, wlock) + + elif convertall: + # deletion of bookmark will result in change in size of bmstore during + # iteration, so let's make a copy to iterate + storecopy = bmstore.copy() + try: + wlock = repo.wlock() + lock = repo.lock() + tr = repo.transaction('debugconvertbookmark') + for bmark, revnode in sorted(storecopy.iteritems()): + if bmark == '@': + continue + _convertbmarktopic(ui, repo, repo[revnode].rev(), bmark, tr) + tr.close() + finally: + lockmod.release(tr, lock, wlock) + +def _convertbmarktopic(ui, repo, rev, bmark, tr): + """Sets a topic as same as bname to all the changesets under the bookmark + and delete the bookmark, if topic is set to any changeset + + rev is the revision on which bookmark bmark is and tr is transaction object. + """ + + # copied from mercurial.repair.stripbmrevset + bookrevset = ("ancestors(bookmark(%s)) - ancestors(head() and not " + "bookmark(%s)) - ancestors(bookmark() and not " + "bookmark(%s))") + touchedrevs = repo.revs(bookrevset, bmark, bmark, bmark) + rewrote = _changetopics(ui, repo, touchedrevs, bmark) + # We didn't changed topic to any changesets because the revset + # returned an empty set of revisions, so let's skip deleting the + # bookmark corresponding to which we didn't put a topic on any + # changeset + if rewrote == 0: + return + ui.status(_('changed topic to "%s" on %d revisions\n') % (bmark, + rewrote)) + ui.debug('removing bookmark "%s" from "%d"' % (bmark, rev)) + bookmarks.delete(repo, tr, [bmark]) + def _changecurrenttopic(repo, newtopic): """changes the current topic."""