##// END OF EJS Templates
merge: don't try to merge subrepos twice (issue4988)...
merge: don't try to merge subrepos twice (issue4988) In my patch series ending with rev 25e4b2f000c5 I switched most change/delete conflicts to be handled at the resolve layer. .hgsubstate was the one file that we weren't able to handle, so we kept the old code path around for it. The old code path added .hgsubstate to one of the other lists as the user specifies, including possibly the 'g' list. Now since we did this check after converting the actions from being keyed by file to being keyed by action type, there was nothing that actually removed .hgsubstate from the 'cd' or 'dc' lists. This meant that the file would eventually make its way into the 'mergeactions' list, now freshly augmented with 'cd' and 'dc' actions. We call subrepo.submerge for both 'g' actions and merge actions. This means that if the resolution to an .hgsubstate change/delete conflict was to add it to the 'g' list, subrepo.submerge would be called twice. It turns out that this doesn't cause any adverse effects on Linux due to caching, but apparently breaks on other operating systems including Windows. The fix here moves this to before we convert the actions over. This ensures that it .hgsubstate doesn't make its way into multiple lists. The real fix here is going to be: (1) move .hgsubstate conflict resolution into the resolve layer, and (2) use a real data structure for the actions rather than shuffling data around between lists and dictionaries: we need a hash (or prefix-based) index by file and a list index by action type. There's a very tiny behavior change here: collision detection on case-insensitive systems will happen after this is resolved, not before. I think this is the right change -- .hgsubstate could theoretically collide with other files -- but in any case it makes no practical difference. Thanks to Yuya Nishihara for investigating this.

File last commit:

r27046:37fcfe52 default
r27951:6bce6d92 stable
Show More
protocol.py
110 lines | 3.2 KiB | text/x-python | PythonLexer
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.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 cStringIO
import cgi
import urllib
import zlib
from .common import (
HTTP_OK,
)
from .. import (
util,
wireproto,
)
HGTYPE = 'application/mercurial-0.1'
HGERRTYPE = 'application/hg-error'
class webproto(wireproto.abstractserverproto):
def __init__(self, req, ui):
self.req = req
self.response = ''
self.ui = ui
def getargs(self, args):
knownargs = self._args()
data = {}
keys = args.split()
for k in keys:
if k == '*':
star = {}
for key in knownargs.keys():
if key != 'cmd' and key not in keys:
star[key] = knownargs[key][0]
data['*'] = star
else:
data[k] = knownargs[k][0]
return [data[k] for k in keys]
def _args(self):
args = self.req.form.copy()
chunks = []
i = 1
while True:
h = self.req.env.get('HTTP_X_HGARG_' + str(i))
if h is None:
break
chunks += [h]
i += 1
args.update(cgi.parse_qs(''.join(chunks), keep_blank_values=True))
return args
def getfile(self, fp):
length = int(self.req.env['CONTENT_LENGTH'])
for s in util.filechunkiter(self.req, limit=length):
fp.write(s)
def redirect(self):
self.oldio = self.ui.fout, self.ui.ferr
self.ui.ferr = self.ui.fout = cStringIO.StringIO()
def restore(self):
val = self.ui.fout.getvalue()
self.ui.ferr, self.ui.fout = self.oldio
return val
def groupchunks(self, cg):
z = zlib.compressobj()
while True:
chunk = cg.read(4096)
if not chunk:
break
yield z.compress(chunk)
yield z.flush()
def _client(self):
return 'remote:%s:%s:%s' % (
self.req.env.get('wsgi.url_scheme') or 'http',
urllib.quote(self.req.env.get('REMOTE_HOST', '')),
urllib.quote(self.req.env.get('REMOTE_USER', '')))
def iscmd(cmd):
return cmd in wireproto.commands
def call(repo, req, cmd):
p = webproto(req, repo.ui)
rsp = wireproto.dispatch(repo, p, cmd)
if isinstance(rsp, str):
req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
elif isinstance(rsp, wireproto.streamres):
req.respond(HTTP_OK, HGTYPE)
return rsp.gen
elif isinstance(rsp, wireproto.pushres):
val = p.restore()
rsp = '%d\n%s' % (rsp.res, val)
req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
elif isinstance(rsp, wireproto.pusherr):
# drain the incoming bundle
req.drain()
p.restore()
rsp = '0\n%s\n' % rsp.res
req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
elif isinstance(rsp, wireproto.ooberror):
rsp = rsp.message
req.respond(HTTP_OK, HGERRTYPE, body=rsp)
return []