hgext/pushexperiment.py
branchmercurial-3.9
changeset 2110 f1ffd093ef30
parent 1816 bb665c99562a
parent 2109 90ab79764ce4
child 2111 ec04eb4d2c6e
child 2261 3e339f6717c7
equal deleted inserted replaced
1816:bb665c99562a 2110:f1ffd093ef30
     1 """Small extension altering some push behavior
       
     2 
       
     3 - Add a new wire protocol command to exchange obsolescence markers. Sending the
       
     4   raw file as a binary instead of using pushkey hack.
       
     5 - Add a "push done" notification
       
     6 - Push obsolescence marker before anything else (This works around the lack
       
     7 of global transaction)
       
     8 
       
     9 """
       
    10 
       
    11 import errno
       
    12 from StringIO import StringIO
       
    13 
       
    14 from mercurial.i18n import _
       
    15 from mercurial import error
       
    16 from mercurial import extensions
       
    17 from mercurial import wireproto
       
    18 from mercurial import obsolete
       
    19 from mercurial import localrepo
       
    20 
       
    21 
       
    22 def client_pushobsmarkers(self, obsfile):
       
    23     """wireprotocol peer method"""
       
    24     self.requirecap('_push_experiment_pushobsmarkers_0',
       
    25                     _('push obsolete markers faster'))
       
    26     ret, output = self._callpush('push_experiment_pushobsmarkers_0', obsfile)
       
    27     for l in output.splitlines(True):
       
    28         self.ui.status(_('remote: '), l)
       
    29     return ret
       
    30 
       
    31 
       
    32 def srv_pushobsmarkers(repo, proto):
       
    33     """wireprotocol command"""
       
    34     fp = StringIO()
       
    35     proto.redirect()
       
    36     proto.getfile(fp)
       
    37     data = fp.getvalue()
       
    38     fp.close()
       
    39     lock = repo.lock()
       
    40     try:
       
    41         tr = repo.transaction('pushkey: obsolete markers')
       
    42         try:
       
    43             repo.obsstore.mergemarkers(tr, data)
       
    44             tr.close()
       
    45         finally:
       
    46             tr.release()
       
    47     finally:
       
    48         lock.release()
       
    49     return wireproto.pushres(0)
       
    50 
       
    51 
       
    52 def syncpush(orig, repo, remote):
       
    53     """wraper for obsolete.syncpush to use the fast way if possible"""
       
    54     if not (obsolete.isenabled(repo, obsolete.exchangeopt) and
       
    55             repo.obsstore):
       
    56         return
       
    57     if remote.capable('_push_experiment_pushobsmarkers_0'):
       
    58         return # already pushed before changeset
       
    59         remote.push_experiment_pushobsmarkers_0(obsfp)
       
    60         return
       
    61     return orig(repo, remote)
       
    62 
       
    63 
       
    64 def client_notifypushend(self):
       
    65     """wire peer  command to notify a push is done"""
       
    66     self.requirecap('_push_experiment_notifypushend_0',
       
    67                     _('hook once push is all done'))
       
    68     return self._call('push_experiment_notifypushend_0')
       
    69 
       
    70 
       
    71 def srv_notifypushend(repo, proto):
       
    72     """wire protocol command to notify a push is done"""
       
    73     proto.redirect()
       
    74     repo.hook('notifypushend')
       
    75     return wireproto.pushres(0)
       
    76 
       
    77 
       
    78 def augmented_push(orig, repo, remote, *args, **kwargs):
       
    79     """push wrapped that call the wire protocol command"""
       
    80     if not remote.canpush():
       
    81         raise error.Abort(_("destination does not support push"))
       
    82     if (obsolete.isenabled(repo, obsolete.exchangeopt) and repo.obsstore
       
    83         and remote.capable('_push_experiment_pushobsmarkers_0')):
       
    84         # push marker early to limit damage of pushing too early.
       
    85         try:
       
    86             obsfp = repo.svfs('obsstore')
       
    87         except IOError as e:
       
    88             if e.errno != errno.ENOENT:
       
    89                 raise
       
    90         else:
       
    91             remote.push_experiment_pushobsmarkers_0(obsfp)
       
    92     ret = orig(repo, remote, *args, **kwargs)
       
    93     if remote.capable('_push_experiment_notifypushend_0'):
       
    94         remote.push_experiment_notifypushend_0()
       
    95     return ret
       
    96 
       
    97 
       
    98 def capabilities(orig, repo, proto):
       
    99     """wrapper to advertise new capability"""
       
   100     caps = orig(repo, proto)
       
   101     if obsolete.isenabled(repo, obsolete.exchangeopt):
       
   102         caps += ' _push_experiment_pushobsmarkers_0'
       
   103     caps += ' _push_experiment_notifypushend_0'
       
   104     return caps
       
   105 
       
   106 
       
   107 def extsetup(ui):
       
   108     wireproto.wirepeer.push_experiment_pushobsmarkers_0 = client_pushobsmarkers
       
   109     wireproto.wirepeer.push_experiment_notifypushend_0 = client_notifypushend
       
   110     wireproto.commands['push_experiment_pushobsmarkers_0'] = \
       
   111         (srv_pushobsmarkers, '')
       
   112     wireproto.commands['push_experiment_notifypushend_0'] = \
       
   113         (srv_notifypushend, '')
       
   114     extensions.wrapfunction(wireproto, 'capabilities', capabilities)
       
   115     extensions.wrapfunction(obsolete, 'syncpush', syncpush)
       
   116     extensions.wrapfunction(localrepo.localrepository, 'push', augmented_push)
       
   117 
       
   118