Mercurial > evolve
view hgext/pushexperiment.py @ 1209:fa35aeb64d32 stable
evolve: prevent a crash in httpclient_pushobsmarkers() when pushing
I've been running into a crash when pushing from my hg repo in a Fedora 16 VM to
Win7 running 'hg serve', even with extensions disabled on both sides:
../hg push -r . pc
pushing to http://192.168.1.4:8000/
searching for changes
no changes found
pushing 2 obsolescence markers (263 bytes)
** unknown exception encountered, please report by visiting
...
File "hg-evolve/hgext/evolve.py", line 2482, in _pushobsolete
remote.evoext_pushobsmarkers_0(obsdata)
File "hg-evolve/hgext/evolve.py", line 2522, in httpclient_pushobsmarkers
ret, output = self._call('evoext_pushobsmarkers_0', data=obsfile)
ValueError: too many values to unpack
I'm not sure how this repo differs from the one in the test suite, so I'm not
sure how to craft a test for this. The failure occurs even when there _are_
csets to push. There was no crash if no obsolete markers needed to be pushed.
At any rate, this code was stolen from httppeer._callpush(), where it calls
self._call(). The socket exception handling wasn't necessary to fix the crash,
but the calling code might as well be duplicated in its entirety.
A successful push with this patch looks like this. Note the final line is _not_
in the output of the http push in test-simple4server.t:
../hg push -r . pc
pushing to http://192.168.1.4:8000/
searching for changes
remote has heads on branch 'default' that are not known locally: 3af110194a0c
56000e3ae44d 57ac6e51d290 7da4355c21b8 and 8 others
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 0 changes to 1 files (+1 heads)
pushing 4 obsolescence markers (525 bytes)
remote: 2 obsolescence markers added
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Thu, 05 Mar 2015 20:02:07 -0500 |
parents | 05ec92d8150d |
children | 196c650d5ba9 |
line wrap: on
line source
"""Small extension altering some push behavior - Add a new wire protocol command to exchange obsolescence markers. Sending the raw file as a binary instead of using pushkey hack. - Add a "push done" notification - Push obsolescence marker before anything else (This works around the lack of global transaction) """ 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'): return # already pushed before changeset 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 augmented_push(orig, repo, remote, *args, **kwargs): """push wrapped that call the wire protocol command""" if not remote.canpush(): raise util.Abort(_("destination does not support push")) if (obsolete._enabled and repo.obsstore and remote.capable('_push_experiment_pushobsmarkers_0')): # push marker early to limit damage of pushing too early. try: obsfp = repo.sopener('obsstore') except IOError as e: if e.errno != errno.ENOENT: raise else: remote.push_experiment_pushobsmarkers_0(obsfp) 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', augmented_push)