##// END OF EJS Templates
merge: make in-memory changes visible to external update hooks...
merge: make in-memory changes visible to external update hooks 51844b8b5017 (while 3.4 code-freeze) made all 'update' hooks run after releasing wlock for visibility of in-memory dirstate changes. But this breaks paired invocation of 'preupdate' and 'update' hooks. For example, 'hg backout --merge' for TARGET revision, which isn't parent of CURRENT, consists of steps below: 1. update from CURRENT to TARGET 2. commit BACKOUT revision, which backs TARGET out 3. update from BACKOUT to CURRENT 4. merge TARGET into CURRENT Then, we expects hooks to run in the order below: - 'preupdate' on CURRENT for (1) - 'update' on TARGET for (1) - 'preupdate' on BACKOUT for (3) - 'update' on CURRENT for (3) - 'preupdate' on TARGET for (4) - 'update' on CURRENT/TARGET for (4) But hooks actually run in the order below: - 'preupdate' on CURRENT for (1) - 'preupdate' on BACKOUT for (3) - 'preupdate' on TARGET for (4) - 'update' on TARGET for (1), but actually on CURRENT/TARGET - 'update' on CURRENT for (3), but actually on CURRENT/TARGET - 'update' on CURRENT for (4), but actually on CURRENT/TARGET Root cause of the issue focused by 51844b8b5017 is that external 'update' hook process can't view in-memory changes (especially, of dirstate), because they aren't written out until the end of transaction (or wlock). Now, hooks can be invoked just after updating, because previous patches made in-memory changes visible to external process. This patch may break backward compatibility from the point of view of "scheduling hook execution", but should be reasonable because 'update' hooks had been executed in this order before 3.4. This patch tests "hg backout" and "hg unshelve", because the former activates the transaction before 'update' hook invocation, but the former doesn't.

File last commit:

r26200:461e7b70 default
r26752:949e8c62 default
Show More
request.py
140 lines | 5.2 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/request.py - An http request from either CGI or the standalone server.
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Benoit Boissinot
remove various unused import
r3963 import socket, cgi, errno
Dirkjan Ochtman
hgweb: be sure to drain request data even in early error conditions...
r7180 from mercurial import util
Augie Fackler
hgweb: don't send a body or illegal headers during 304 response...
r12739 from common import ErrorResponse, statusmessage, HTTP_NOT_MODIFIED
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Dirkjan Ochtman
hgweb: move shortcut expansion to request instantiation
r6774 shortcuts = {
'cl': [('cmd', ['changelog']), ('rev', None)],
'sl': [('cmd', ['shortlog']), ('rev', None)],
'cs': [('cmd', ['changeset']), ('node', None)],
'f': [('cmd', ['file']), ('filenode', None)],
'fl': [('cmd', ['filelog']), ('filenode', None)],
'fd': [('cmd', ['filediff']), ('node', None)],
'fa': [('cmd', ['annotate']), ('filenode', None)],
'mf': [('cmd', ['manifest']), ('manifest', None)],
'ca': [('cmd', ['archive']), ('node', None)],
'tags': [('cmd', ['tags'])],
'tip': [('cmd', ['changeset']), ('node', ['tip'])],
'static': [('cmd', ['static']), ('file', None)]
}
Nicolas Dumazet
hgweb: request: strip() form values...
r10261 def normalize(form):
# first expand the shortcuts
Dirkjan Ochtman
hgweb: move shortcut expansion to request instantiation
r6774 for k in shortcuts.iterkeys():
if k in form:
for name, value in shortcuts[k]:
if value is None:
value = form[k]
form[name] = value
del form[k]
Nicolas Dumazet
hgweb: request: strip() form values...
r10261 # And strip the values
for k, v in form.iteritems():
form[k] = [i.strip() for i in v]
Dirkjan Ochtman
hgweb: move shortcut expansion to request instantiation
r6774 return form
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 class wsgirequest(object):
Gregory Szorc
hgweb: add some documentation...
r26132 """Higher-level API for a WSGI request.
WSGI applications are invoked with 2 arguments. They are used to
instantiate instances of this class, which provides higher-level APIs
for obtaining request parameters, writing HTTP output, etc.
"""
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 def __init__(self, wsgienv, start_response):
Eric Hopper
This patch make several WSGI related alterations....
r2506 version = wsgienv['wsgi.version']
Thomas Arendsen Hein
white space and line break cleanups
r3673 if (version < (1, 0)) or (version >= (2, 0)):
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 raise RuntimeError("Unknown and unsupported WSGI version %d.%d"
Eric Hopper
This patch make several WSGI related alterations....
r2506 % version)
self.inp = wsgienv['wsgi.input']
self.err = wsgienv['wsgi.errors']
self.threaded = wsgienv['wsgi.multithread']
self.multiprocess = wsgienv['wsgi.multiprocess']
self.run_once = wsgienv['wsgi.run_once']
self.env = wsgienv
Nicolas Dumazet
hgweb: request: strip() form values...
r10261 self.form = normalize(cgi.parse(self.inp,
self.env,
keep_blank_values=1))
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888 self._start_response = start_response
Dirkjan Ochtman
hgweb: explicit response status
r5993 self.server_write = None
Eric Hopper
This patch make several WSGI related alterations....
r2506 self.headers = []
def __iter__(self):
return iter([])
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Vadim Gelfer
push over http: server support....
r2464 def read(self, count=-1):
return self.inp.read(count)
Dirkjan Ochtman
hgweb: be sure to drain request data even in early error conditions...
r7180 def drain(self):
'''need to read all data from request, httplib is half-duplex'''
Dirkjan Ochtman
hgweb: pmezard thinks one default is enough
r13600 length = int(self.env.get('CONTENT_LENGTH') or 0)
Dirkjan Ochtman
hgweb: be sure to drain request data even in early error conditions...
r7180 for s in util.filechunkiter(self.inp, limit=length):
pass
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 def respond(self, status, type, filename=None, body=None):
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888 if self._start_response is not None:
Mads Kiilerich
hgweb: simplify wsgirequest header handling...
r18348 self.headers.append(('Content-Type', type))
if filename:
filename = (filename.split('/')[-1]
.replace('\\', '\\\\').replace('"', '\\"'))
self.headers.append(('Content-Disposition',
'inline; filename="%s"' % filename))
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 if body is not None:
self.headers.append(('Content-Length', str(len(body))))
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888
Dirkjan Ochtman
hgweb: be sure to send a valid content-type for raw files
r5926 for k, v in self.headers:
if not isinstance(v, str):
Mads Kiilerich
hgweb: simplify wsgirequest header handling...
r18348 raise TypeError('header value must be string: %r' % (v,))
Dirkjan Ochtman
hgweb: be sure to send a valid content-type for raw files
r5926
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888 if isinstance(status, ErrorResponse):
Mads Kiilerich
hgweb: simplify wsgirequest header handling...
r18348 self.headers.extend(status.headers)
Augie Fackler
hgweb: don't send a body or illegal headers during 304 response...
r12739 if status.code == HTTP_NOT_MODIFIED:
# RFC 2616 Section 10.3.5: 304 Not Modified has cases where
# it MUST NOT include any headers other than these and no
# body
self.headers = [(k, v) for (k, v) in self.headers if
k in ('Date', 'ETag', 'Expires',
'Cache-Control', 'Vary')]
timeless@mozdev.org
hgweb: remove ErrorResponse.message...
r26200 status = statusmessage(status.code, str(status))
Dirkjan Ochtman
hgweb: explicit response status
r5993 elif status == 200:
status = '200 Script output follows'
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888 elif isinstance(status, int):
status = statusmessage(status)
self.server_write = self._start_response(status, self.headers)
self._start_response = None
self.headers = []
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 if body is not None:
self.write(body)
self.server_write = None
Dirkjan Ochtman
hgweb: separate out start_response() calling
r5888
Dirkjan Ochtman
hgweb: explicit response status
r5993 def write(self, thing):
Mads Kiilerich
hgweb: don't pass empty response chunks on...
r18351 if thing:
try:
self.server_write(thing)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except socket.error as inst:
Mads Kiilerich
hgweb: don't pass empty response chunks on...
r18351 if inst[0] != errno.ECONNRESET:
raise
Eric Hopper
Splitting up hgweb so it's easier to change.
r2355
Alexis S. L. Carvalho
avoid _wsgioutputfile <-> _wsgirequest circular reference...
r4246 def writelines(self, lines):
for line in lines:
self.write(line)
def flush(self):
return None
def close(self):
return None
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 def wsgiapplication(app_maker):
Dirkjan Ochtman
hgweb: return iterable, add deprecation note
r5887 '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir()
can and should now be used as a WSGI application.'''
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760 application = app_maker()
def run_wsgi(env, respond):
Dirkjan Ochtman
hgweb: return iterable, add deprecation note
r5887 return application(env, respond)
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760 return run_wsgi