hgext/pushexperiment.py
author Pierre-Yves David <pierre-yves.david@logilab.fr>
Mon, 03 Jun 2013 14:57:39 +0200
changeset 728 5d368ae3d5a0
parent 727 cb907cf3b556
child 729 2e46caeb2890
permissions -rw-r--r--
add notification at the end of push We have a dedicated hook to know when a push is done.

"""Small extension altering some push behavior

- Add a new wire protocol command to exchange obsolescence marker. Sending the
  raw file as a binary instead of using pushkey hack.
- Add a "push done" notification

"""

import errno
from StringIO import StringIO

from mercurial.i18n import _
from mercurial import extensions
from mercurial import wireproto
from mercurial import obsolete
from mercurial import localrepo


def client_pushobsmarkers(self, obsfile):
    """wireprotocol peer method"""
    self.requirecap('_push_experiment_pushobsmarkers_0',
                    _('push obsolete markers faster'))
    ret, output = self._callpush('push_experiment_pushobsmarkers_0', obsfile)
    for l in output.splitlines(True):
        self.ui.status(_('remote: '), l)
    return ret


def srv_pushobsmarkers(repo, proto):
    """wireprotocol command"""
    fp = StringIO()
    proto.redirect()
    proto.getfile(fp)
    data = fp.getvalue()
    fp.close()
    lock = repo.lock()
    try:
        tr = repo.transaction('pushkey: obsolete markers')
        try:
            repo.obsstore.mergemarkers(tr, data)
            tr.close()
        finally:
            tr.release()
    finally:
        lock.release()
    return wireproto.pushres(0)


def syncpush(orig, repo, remote):
    """wraper for obsolete.syncpush to use the fast way if possible"""
    if not (obsolete._enabled and repo.obsstore):
        return
    if remote.capable('_push_experiment_pushobsmarkers_0'):
        try:
            obsfp = repo.sopener('obsstore')
        except IOError as e:
            if e.errno != errno.ENOENT:
                raise
            return
        remote.push_experiment_pushobsmarkers_0(obsfp)
        return
    return orig(repo, remote)


def client_notifypushend(self):
    """wire peer  command to notify a push is done"""
    self.requirecap('_push_experiment_notifypushend_0', _('hook once push is all done'))
    return self._call('push_experiment_notifypushend_0')


def srv_notifypushend(repo, proto):
    """wire protocol command to notify a push is done"""
    proto.redirect()
    repo.hook('notifypushend')
    return wireproto.pushres(0)


def notifiedpush(orig, repo, remote, *args, **kwargs):
    """push wrapped that call the wire protocol command"""
    ret = orig(repo, remote, *args, **kwargs)
    if remote.capable('_push_experiment_notifypushend_0'):
        remote.push_experiment_notifypushend_0()
    return ret


def capabilities(orig, repo, proto):
    """wrapper to advertise new capability"""
    caps = orig(repo, proto)
    if obsolete._enabled:
        caps += ' _push_experiment_pushobsmarkers_0'
    caps += ' _push_experiment_notifypushend_0'
    return caps


def extsetup(ui):
    wireproto.wirepeer.push_experiment_pushobsmarkers_0 = client_pushobsmarkers
    wireproto.wirepeer.push_experiment_notifypushend_0 = client_notifypushend
    wireproto.commands['push_experiment_pushobsmarkers_0'] = (srv_pushobsmarkers, '')
    wireproto.commands['push_experiment_notifypushend_0'] = (srv_notifypushend, '')
    extensions.wrapfunction(wireproto, 'capabilities', capabilities)
    extensions.wrapfunction(obsolete, 'syncpush', syncpush)
    extensions.wrapfunction(localrepo.localrepository, 'push', notifiedpush)