Mercurial > hg
view mercurial/sshserver.py @ 29610:754f63671229 stable
rebase: turn rebase revs into set before filtering obsolete
When the inhibit extension from mutable-history is enabled, it attempts to
iterate over the rebaseset to prevent the nodes being rebased from being
marked obsolete. This happens at the same time as rebase's
_filterobsoleterevs function trying to iterate over the rebaseset to figure
out which ones are obsolete. The two of these iterating over the same
revset generatorset cause a 'generator already executing' exception. This is
probably a flaw in the revset implementation, since iterating over the same
set twice should be supported.
This regression was introduced in 5d16ebe7b14, since it changed
_filterobsoleterevs to be called before the rebaseset was turned into a
set(). For now let’s just make the rebaseset an actual set again before
calling that function. This was caught by the inhibit tests.
The relevant call stack from test-inhibit.t:
File "/tmp/hgtests.jgjrN5/install/lib/python/hgext/rebase.py", line 285, in _preparenewrebase
obsrevs = _filterobsoleterevs(self.repo, rebaseset)
File "/data/hgbuild/facebook-hg-rpms/mutable-history/hgext/inhibit.py", line 197, in _filterobsoleterevswrap
r = orig(repo, rebasesetrevs, *args, **kwargs)
File "/tmp/hgtests.jgjrN5/install/lib/python/hgext/rebase.py", line 1380, in _filterobsoleterevs
return set(r for r in revs if repo[r].obsolete())
File "/tmp/hgtests.jgjrN5/install/lib/python/hgext/rebase.py", line 1380, in <genexpr>
return set(r for r in revs if repo[r].obsolete())
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3079, in _iterordered
val2 = next(iter2)
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3417, in gen
yield nextrev()
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3424, in _consumegen
for item in self._gen:
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 71, in iterate
cl = repo.changelog
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/repoview.py", line 319, in changelog
revs = filterrevs(unfi, self.filtername)
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/repoview.py", line 261, in filterrevs
repo.filteredrevcache[filtername] = func(repo.unfiltered())
File "/data/hgbuild/facebook-hg-rpms/mutable-history/hgext/directaccess.py", line 65, in _computehidden
hidden = repoview.filterrevs(repo, 'visible')
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/repoview.py", line 261, in filterrevs
repo.filteredrevcache[filtername] = func(repo.unfiltered())
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/repoview.py", line 175, in computehidden
hideable = hideablerevs(repo)
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/repoview.py", line 33, in hideablerevs
return obsolete.getrevs(repo, 'obsolete')
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/obsolete.py", line 1097, in getrevs
repo.obsstore.caches[name] = cachefuncs[name](repo)
File "/data/hgbuild/facebook-hg-rpms/mutable-history/hgext/inhibit.py", line 255, in _computeobsoleteset
if getrev(n) not in blacklist:
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3264, in __contains__
return x in self._r1 or x in self._r2
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3348, in __contains__
for l in self._consumegen():
File "/tmp/hgtests.jgjrN5/install/lib/python/mercurial/revset.py", line 3424, in _consumegen
for item in self._gen:
ValueError: generator already executing
author | Simon Farnsworth <simonfar@fb.com> |
---|---|
date | Tue, 19 Jul 2016 03:29:53 -0700 |
parents | 98e8313dcd9e |
children | 1a29db79a98d |
line wrap: on
line source
# sshserver.py - ssh protocol server support for mercurial # # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from __future__ import absolute_import import os import sys from .i18n import _ from . import ( error, hook, util, wireproto, ) class sshserver(wireproto.abstractserverproto): def __init__(self, ui, repo): self.ui = ui self.repo = repo self.lock = None self.fin = ui.fin self.fout = ui.fout hook.redirect(True) ui.fout = repo.ui.fout = ui.ferr # Prevent insertion/deletion of CRs util.setbinary(self.fin) util.setbinary(self.fout) def getargs(self, args): data = {} keys = args.split() for n in xrange(len(keys)): argline = self.fin.readline()[:-1] arg, l = argline.split() if arg not in keys: raise error.Abort(_("unexpected parameter %r") % arg) if arg == '*': star = {} for k in xrange(int(l)): argline = self.fin.readline()[:-1] arg, l = argline.split() val = self.fin.read(int(l)) star[arg] = val data['*'] = star else: val = self.fin.read(int(l)) data[arg] = val return [data[k] for k in keys] def getarg(self, name): return self.getargs(name)[0] def getfile(self, fpout): self.sendresponse('') count = int(self.fin.readline()) while count: fpout.write(self.fin.read(count)) count = int(self.fin.readline()) def redirect(self): pass def groupchunks(self, changegroup): while True: d = changegroup.read(4096) if not d: break yield d def sendresponse(self, v): self.fout.write("%d\n" % len(v)) self.fout.write(v) self.fout.flush() def sendstream(self, source): write = self.fout.write for chunk in source.gen: write(chunk) self.fout.flush() def sendpushresponse(self, rsp): self.sendresponse('') self.sendresponse(str(rsp.res)) def sendpusherror(self, rsp): self.sendresponse(rsp.res) def sendooberror(self, rsp): self.ui.ferr.write('%s\n-\n' % rsp.message) self.ui.ferr.flush() self.fout.write('\n') self.fout.flush() def serve_forever(self): try: while self.serve_one(): pass finally: if self.lock is not None: self.lock.release() sys.exit(0) handlers = { str: sendresponse, wireproto.streamres: sendstream, wireproto.pushres: sendpushresponse, wireproto.pusherr: sendpusherror, wireproto.ooberror: sendooberror, } def serve_one(self): cmd = self.fin.readline()[:-1] if cmd and cmd in wireproto.commands: rsp = wireproto.dispatch(self.repo, self, cmd) self.handlers[rsp.__class__](self, rsp) elif cmd: impl = getattr(self, 'do_' + cmd, None) if impl: r = impl() if r is not None: self.sendresponse(r) else: self.sendresponse("") return cmd != '' def _client(self): client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0] return 'remote:ssh:' + client