Please review my first extension

gideon voldermort at hotmail.com
Mon Dec 3 12:10:45 CST 2012


Bryan O'Sullivan wrote
> You probably won't get any reviews unless you send a patch to this list
> using "hg email".

It's an extension, not a patch. Code follows for those who'd prefer it in
the email.


"""Rename named branches.

To start renaming branches, create a file called .hgbranches in the root of
the working directory.
Each line in .hgbranches consists of a space-delimited pair such as
oldBranch newBranch.
If the branch name contains spaces, it should be quoted.
Renamings can be kept local by putting them in .hg/.hgbranches.

.. container:: verbose

    Mutable-branches merges the most recent .hgbranches from each head in
the repository.
    In case of conflict, the most recent head wins. .hg/.hgbranches always
overrides the repository .hgbranches.
"""

import os, shlex
from mercurial import extensions, commands, changelog, localrepo, util
from mercurial.node import hex

def uisetup(ui):
    extensions.wrapcommand(commands.table, 'branch', branch_wrapper)

def _parse(lines):
    _deserialise(_hgbranches, lines)

def _serialise(hgbranches):
    return '\n'.join('"%s" "%s"' % (old,new) for old, new in
hgbranches.items())

def _deserialise(hgbranches, lines):
    for line in lines:
        items = shlex.split(line)
        hgbranches[items[0]] = items[1]

def reposetup(ui, repo):
    #only interested in local repositories
    if not isinstance(repo, localrepo.localrepository): return

    global _hgbranches
    _hgbranches = {}

    #attempt to read .hgbranches from cache
    if repo.vfs.exists("cache/hgbranches"):
        try:
            cache = repo.vfs("cache/hgbranches").read().splitlines()
            if cache[0] == hex(repo.changelog.tip()): _parse(cache[1:])
        except Exception as e:
            ui.debug('"%s" reading hgbranches cache\n' % e[0])
            ui.warn("hgbranches cache corrupt, it will be recreated\n")
            os.remove(repo.vfs.join("cache/hgbranches"))

    #otherwise read .hgbranches from repo
    #conflicting renames from newer heads overwrite older heads
    if not _hgbranches:
        for head in reversed(repo.heads()):
            if '.hgbranches' in repo[head]:
                try:
                    _parse(repo[head]['.hgbranches'].data().splitlines())
                except Exception as e:
                    ui.warn('"%s" reading .hgbranches\n' % e[0])
                    raise util.Abort(".hgbranches is corrupt.\n"
                    "Please disable mutable-branches and fix it.")
        #write .hgbranches cache
        try:
            with repo.vfs("cache/hgbranches", 'w') as cache:
                cache.write(hex(repo.changelog.tip()) + '\n')
                cache.write(_serialise(_hgbranches))
        except Exception as e:
            ui.debug('"%s" writing hgbranches cache\n' % e[0])
            ui.warn("The hgbranches cache could not be written.\n")

    #read .hg/.hgbranches
    if repo.vfs.exists(".hgbranches"):
        try:
            _parse(repo.vfs(".hgbranches"))
        except Exception as e:
            ui.warn('"%s" reading local .hgbranches\n' % e[0])
            raise util.Abort("local .hgbranches is corrupt")

    #build a list of changes from the last run
    if repo.vfs.exists("hgbranches-prev"):
        changes = {}
        previous = {}
        try:
            _deserialise(previous, repo.vfs("hgbranches-prev"))
        except Exception as e:
            ui.warn('"%s" reading .hg/.hgbranches-prev\n' % e[0])
            raise util.Abort(".hg/hgbranches-prev is corrupt.\n"
            "If you delete it, .hg/cache/branchheads should also be
deleted.\n"
            "You may also need to reset the current branch.")

        for old, new in _hgbranches.items():
            if old in previous:
                #has a previous renaming changed?
                if previous[old] != new: changes[previous[old]] = new
            else:
                #new renaming
                changes[old] = new

        #check for deleted renamings
        for old in previous:
            if not old in _hgbranches:
                changes[previous[old]] = old
    else:
        changes = _hgbranches

    if changes:
        repo.vfs.write("hgbranches-prev", _serialise(_hgbranches))

    #update dirstate
    dirstate = repo.dirstate
    branch = dirstate.branch()
    if branch in changes:
        dirstate.setbranch(changes[branch])

    #update branchheads
    if repo.vfs.exists("cache/branchheads"):
        new = []
        with repo.vfs("cache/branchheads") as old:
            new.append(old.next()) #tip tracker
            for line in old:
                node, branch = line.strip().split(" ", 1)
                if branch in changes: branch = changes[branch]
                new.append(node + " " + branch + "\n")
        repo.vfs.write("cache/branchheads", "".join(new))

    #wrap changelog methods
    extensions.wrapfunction(changelog.changelog, 'add', add_wrapper)
    extensions.wrapfunction(changelog.changelog, 'read', read_wrapper)

def branch_wrapper(orig, ui, *args, **kwargs):
    """Remove the "branches are permanent and global" warning from branch's
output."""
    if len(args) > 1 and args[1] in _hgbranches:
        raise util.Abort("branch " + args[1] + " has been renamed to " +
_hgbranches[args[1]])
    ui.pushbuffer()
    ret = orig(ui, *args, **kwargs)
    lines = ui.popbuffer().splitlines(True)
    if lines[-1].startswith("(branches are permanent and global"):
lines.pop()
    ui.write(''.join(lines))
    return ret

def add_wrapper(orig, ui, *args, **kwargs):
    branch = args[8]['branch']
    #map renamed branch to canonical name
    for old, new in _hgbranches.items():
        if branch == new:
            args[8]['branch'] = old
            break
    return orig(ui, *args, **kwargs)

def read_wrapper(orig, ui, *args, **kwargs):
    ret = orig(ui, *args, **kwargs)
    branch = ret[5]['branch']
    #rename branch
    if branch in _hgbranches: ret[5]['branch'] = _hgbranches[branch]
    return ret

testedwith = '2.3 2.4'
buglink = 'http://code.accursoft.com/mutable-branches/issues'



--
View this message in context: http://mercurial.808500.n3.nabble.com/Please-review-my-first-extension-tp3995437p3995446.html
Sent from the Development mailing list archive at Nabble.com.


More information about the Mercurial-devel mailing list