author Bobby Holley <>
Mon, 12 Jul 2010 14:35:24 -0400
changeset 2 8723e06e57c8
parent 1 688a8124af29
permissions -rw-r--r--
added the frk extension

# Mercurial extension to integrate the bookmark and rebase extensions
# Copyright 2010 Bobby Holley <>
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

'''Makes hg bookmarks and rebase play nicely together.'''

from mercurial import util, extensions, commands, cmdutil

# Hook called to let us set up the repo structure. We dynamically subclass the
# repository object to modify the 'commit' method, as described in
def reposetup(ui, repo):
    class pprepo(repo.__class__):

        def commit(self, text="", user=None, date=None, match=None, force=False,
                   editor=False, extra={}):

            # Call the real function
            newrev = super(pprepo, self).commit(text, user, date, match, force,
                                                editor, extra)

            # If our state variable is set and there's data from the snooper
            # function, add an entry to the node mapper
            if hasattr(repo, '_peacepipemap') and ('oldhash' in extra):
                repo._peacepipemap[extra.get('oldhash')] = newrev

            # Return the new revision
            return newrev

    # The magic
    repo.__class__ = pprepo

# Our wrapper command around the vanilla 'rebase' command
def pprebase(orig, ui, repo, **opts):

    # Access the bookmarks extension. If it's not there, there's no wrapping
    # to do. Just pass control straight to the original commmand.
    bookmarksext = None
        bookmarksext = extensions.find('bookmarks')
    except KeyError:
        ui.write("\nWarning - Peacepipe extension enabled, but bookmarks extension "
                 "not enabled. Peacepipe will not be active.\n\n")
        orig(ui, repo, **opts)

    # If we're tracking the current bookmark, we have to handle it as a special
    # case, because it gets moved around during the rebase
    currMark = repo._bookmarkcurrent

    # Store our own copy of the pristine bookmarks
    oldmarks = repo._bookmarks.copy()

    # Add our state variable, making sure we aren't tromping on anyone else's data.
    # This is a dictionary mapping from old->new revision hashes
    if hasattr(repo, "_peacepipemap"):
        raise util.Abort("somebody else is using our state variable!")
    repo._peacepipemap = {}

    # Add our snooping 'extra' function to peep at rebase's internals
    if 'extrafn' in opts:
        def ppextra(ctx, extra):
            opts['extrafn'](ctx, extra)
            extra['oldhash'] = ctx.node()
        def ppextra(ctx, extra):
           extra['oldhash'] = ctx.node()
    opts['extrafn'] = ppextra

    # call rebase proper
    orig(ui, repo, **opts)

    # Find all the old bookmarks that were mapped to a different commit,
    # and put the appropriate mapping in the bookmarks structure
    for bname, oldsha in oldmarks.iteritems():

        # If the bookmarked commit got mapped during the rebase process
        if oldsha in repo._peacepipemap:
            repo._bookmarks[bname] = repo._peacepipemap[oldsha]

        # If this was the 'current' bookmark, it probably got moved around
        # anyway. Put it back where it belongs.
        elif bname == currMark:
            repo._bookmarks[bname] = oldsha

    # Remove our state variable
    del repo._peacepipemap

    # Write the new bookmarks to disk

    # If we had a current bookmark, go back to it
    if currMark:
        aliases, entry = cmdutil.findcmd('update', commands.table)
        entry[0](ui, repo, rev=currMark)

def extsetup(ui):
        rebaseext = extensions.find('rebase')
        entry = extensions.wrapcommand(rebaseext.cmdtable, 'rebase', pprebase)
    except KeyError:
        ui.write("\nWarning - Peacepipe extension enabled, but rebase extension "
                 "not enabled. Peacepipe will not be active.\n\n")