Mercurial > hg
changeset 6793:c64f35a96448
merge with main
author | Dirkjan Ochtman <dirkjan@ochtman.nl> |
---|---|
date | Wed, 02 Jul 2008 09:31:13 +0200 |
parents | b2c4be19d7b1 (diff) e81d2bd66908 (current diff) |
children | c228ae4bc89c |
files | |
diffstat | 27 files changed, 287 insertions(+), 232 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/win32/mercurial.iss Fri Jun 27 21:45:16 2008 -0500 +++ b/contrib/win32/mercurial.iss Wed Jul 02 09:31:13 2008 +0200 @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] -AppCopyright=Copyright 2005-2007 Matt Mackall and others +AppCopyright=Copyright 2005-2008 Matt Mackall and others AppName=Mercurial AppVerName=Mercurial snapshot InfoAfterFile=contrib/win32/postinstall.txt @@ -18,7 +18,7 @@ DefaultDirName={pf}\Mercurial SourceDir=..\.. VersionInfoDescription=Mercurial distributed SCM -VersionInfoCopyright=Copyright 2005-2007 Matt Mackall and others +VersionInfoCopyright=Copyright 2005-2008 Matt Mackall and others VersionInfoCompany=Matt Mackall and others InternalCompressLevel=max SolidCompression=true
--- a/mercurial/hgweb/hgweb_mod.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/hgweb/hgweb_mod.py Wed Jul 02 09:31:13 2008 +0200 @@ -10,25 +10,17 @@ from mercurial.node import hex, nullid from mercurial.repo import RepoError from mercurial import mdiff, ui, hg, util, patch, hook -from mercurial import revlog, templater, templatefilters, changegroup +from mercurial import revlog, templater, templatefilters from common import get_mtime, style_map, paritygen, countgen, ErrorResponse from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR from request import wsgirequest import webcommands, protocol, webutil -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)] +perms = { + 'changegroup': 'pull', + 'changegroupsubset': 'pull', + 'unbundle': 'push', + 'stream_out': 'pull', } class hgweb(object): @@ -44,7 +36,6 @@ self.reponame = name self.archives = 'zip', 'gz', 'bz2' self.stripecount = 1 - self._capabilities = None # a repo owner may set web.templates in .hg/hgrc to get any file # readable by the user running the CGI script self.templatepath = self.config("web", "templates", @@ -76,18 +67,6 @@ self.maxfiles = int(self.config("web", "maxfiles", 10)) self.allowpull = self.configbool("web", "allowpull", True) self.encoding = self.config("web", "encoding", util._encoding) - self._capabilities = None - - def capabilities(self): - if self._capabilities is not None: - return self._capabilities - caps = ['lookup', 'changegroupsubset'] - if self.configbool('server', 'uncompressed'): - caps.append('stream=%d' % self.repo.changelog.version) - if changegroup.bundlepriority: - caps.append('unbundle=%s' % ','.join(changegroup.bundlepriority)) - self._capabilities = caps - return caps def run(self): if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."): @@ -97,22 +76,22 @@ def __call__(self, env, respond): req = wsgirequest(env, respond) - self.run_wsgi(req) - return req + return self.run_wsgi(req) def run_wsgi(self, req): self.refresh() - # expand form shortcuts + # process this if it's a protocol request + # protocol bits don't need to create any URLs + # and the clients always use the old URL structure - for k in shortcuts.iterkeys(): - if k in req.form: - for name, value in shortcuts[k]: - if value is None: - value = req.form[k] - req.form[name] = value - del req.form[k] + cmd = req.form.get('cmd', [''])[0] + if cmd and cmd in protocol.__all__: + if cmd in perms and not self.check_perm(req, perms[cmd]): + return [] + method = getattr(protocol, cmd) + return method(self.repo, req) # work with CGI variables to create coherent structure # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME @@ -145,8 +124,10 @@ cmd = cmd[style+1:] # avoid accepting e.g. style parameter as command - if hasattr(webcommands, cmd) or hasattr(protocol, cmd): + if hasattr(webcommands, cmd): req.form['cmd'] = [cmd] + else: + cmd = '' if args and args[0]: node = args.pop(0) @@ -164,14 +145,6 @@ req.form['node'] = [fn[:-len(ext)]] req.form['type'] = [type_] - # process this if it's a protocol request - - cmd = req.form.get('cmd', [''])[0] - if cmd in protocol.__all__: - method = getattr(protocol, cmd) - method(self, req) - return - # process the web interface request try: @@ -196,19 +169,20 @@ req.write(content) del tmpl + return ''.join(content), except revlog.LookupError, err: req.respond(HTTP_NOT_FOUND, ctype) msg = str(err) if 'manifest' not in msg: msg = 'revision not found: %s' % err.name - req.write(tmpl('error', error=msg)) + return ''.join(tmpl('error', error=msg)), except (RepoError, revlog.RevlogError), inst: req.respond(HTTP_SERVER_ERROR, ctype) - req.write(tmpl('error', error=str(inst))) + return ''.join(tmpl('error', error=str(inst))), except ErrorResponse, inst: req.respond(inst.code, ctype) - req.write(tmpl('error', error=inst.message)) + return ''.join(tmpl('error', error=inst.message)), def templater(self, req): @@ -364,16 +338,39 @@ 'zip': ('application/zip', 'zip', '.zip', None), } - def check_perm(self, req, op, default): - '''check permission for operation based on user auth. - return true if op allowed, else false. - default is policy to use if no config given.''' + def check_perm(self, req, op): + '''Check permission for operation based on request data (including + authentication info. Return true if op allowed, else false.''' + + def error(status, message): + req.respond(status, protocol.HGTYPE) + req.write('0\n%s\n' % message) + + if op == 'pull': + return self.allowpull + + # enforce that you can only push using POST requests + if req.env['REQUEST_METHOD'] != 'POST': + error('405 Method Not Allowed', 'push requires POST request') + return False + + # require ssl by default for pushing, auth info cannot be sniffed + # and replayed + scheme = req.env.get('wsgi.url_scheme') + if self.configbool('web', 'push_ssl', True) and scheme != 'https': + error(HTTP_OK, 'ssl required') + return False user = req.env.get('REMOTE_USER') - deny = self.configlist('web', 'deny_' + op) + deny = self.configlist('web', 'deny_push') if deny and (not user or deny == ['*'] or user in deny): + error('401 Unauthorized', 'push not authorized') return False - allow = self.configlist('web', 'allow_' + op) - return (allow and (allow == ['*'] or user in allow)) or default + allow = self.configlist('web', 'allow_push') + result = allow and (allow == ['*'] or user in allow) + if not result: + error('401 Unauthorized', 'push not authorized') + + return result
--- a/mercurial/hgweb/hgwebdir_mod.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/hgweb/hgwebdir_mod.py Wed Jul 02 09:31:13 2008 +0200 @@ -70,8 +70,7 @@ def __call__(self, env, respond): req = wsgirequest(env, respond) - self.run_wsgi(req) - return req + return self.run_wsgi(req) def run_wsgi(self, req): @@ -90,14 +89,12 @@ fname = virtual[7:] else: fname = req.form['static'][0] - req.write(staticfile(static, fname, req)) - return + return staticfile(static, fname, req), # top-level index elif not virtual: req.respond(HTTP_OK, ctype) - req.write(self.makeindex(req, tmpl)) - return + return ''.join(self.makeindex(req, tmpl)), # nested indexes and hgwebs @@ -108,8 +105,7 @@ req.env['REPO_NAME'] = virtual try: repo = hg.repository(self.parentui, real) - hgweb(repo).run_wsgi(req) - return + return hgweb(repo).run_wsgi(req) except IOError, inst: msg = inst.strerror raise ErrorResponse(HTTP_SERVER_ERROR, msg) @@ -120,8 +116,7 @@ subdir = virtual + '/' if [r for r in repos if r.startswith(subdir)]: req.respond(HTTP_OK, ctype) - req.write(self.makeindex(req, tmpl, subdir)) - return + return ''.join(self.makeindex(req, tmpl, subdir)), up = virtual.rfind('/') if up < 0: @@ -130,11 +125,11 @@ # prefixes not found req.respond(HTTP_NOT_FOUND, ctype) - req.write(tmpl("notfound", repo=virtual)) + return ''.join(tmpl("notfound", repo=virtual)), except ErrorResponse, err: req.respond(err.code, ctype) - req.write(tmpl('error', error=err.message or '')) + return ''.join(tmpl('error', error=err.message or '')), finally: tmpl = None
--- a/mercurial/hgweb/protocol.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/hgweb/protocol.py Wed Jul 02 09:31:13 2008 +0200 @@ -21,69 +21,65 @@ HGTYPE = 'application/mercurial-0.1' -def lookup(web, req): +def lookup(repo, req): try: - r = hex(web.repo.lookup(req.form['key'][0])) + r = hex(repo.lookup(req.form['key'][0])) success = 1 except Exception,inst: r = str(inst) success = 0 resp = "%s %s\n" % (success, r) req.respond(HTTP_OK, HGTYPE, length=len(resp)) - req.write(resp) + yield resp -def heads(web, req): - resp = " ".join(map(hex, web.repo.heads())) + "\n" +def heads(repo, req): + resp = " ".join(map(hex, repo.heads())) + "\n" req.respond(HTTP_OK, HGTYPE, length=len(resp)) - req.write(resp) + yield resp -def branches(web, req): +def branches(repo, req): nodes = [] if 'nodes' in req.form: nodes = map(bin, req.form['nodes'][0].split(" ")) resp = cStringIO.StringIO() - for b in web.repo.branches(nodes): + for b in repo.branches(nodes): resp.write(" ".join(map(hex, b)) + "\n") resp = resp.getvalue() req.respond(HTTP_OK, HGTYPE, length=len(resp)) - req.write(resp) + yield resp -def between(web, req): +def between(repo, req): if 'pairs' in req.form: pairs = [map(bin, p.split("-")) for p in req.form['pairs'][0].split(" ")] resp = cStringIO.StringIO() - for b in web.repo.between(pairs): + for b in repo.between(pairs): resp.write(" ".join(map(hex, b)) + "\n") resp = resp.getvalue() req.respond(HTTP_OK, HGTYPE, length=len(resp)) - req.write(resp) + yield resp -def changegroup(web, req): +def changegroup(repo, req): req.respond(HTTP_OK, HGTYPE) nodes = [] - if not web.allowpull: - return if 'roots' in req.form: nodes = map(bin, req.form['roots'][0].split(" ")) z = zlib.compressobj() - f = web.repo.changegroup(nodes, 'serve') + f = repo.changegroup(nodes, 'serve') while 1: chunk = f.read(4096) if not chunk: break - req.write(z.compress(chunk)) + yield z.compress(chunk) - req.write(z.flush()) + yield z.flush() -def changegroupsubset(web, req): +def changegroupsubset(repo, req): req.respond(HTTP_OK, HGTYPE) bases = [] heads = [] - if not web.allowpull: - return if 'bases' in req.form: bases = [bin(x) for x in req.form['bases'][0].split(' ')] @@ -91,67 +87,44 @@ heads = [bin(x) for x in req.form['heads'][0].split(' ')] z = zlib.compressobj() - f = web.repo.changegroupsubset(bases, heads, 'serve') + f = repo.changegroupsubset(bases, heads, 'serve') while 1: chunk = f.read(4096) if not chunk: break - req.write(z.compress(chunk)) + yield z.compress(chunk) - req.write(z.flush()) + yield z.flush() -def capabilities(web, req): - resp = ' '.join(web.capabilities()) - req.respond(HTTP_OK, HGTYPE, length=len(resp)) - req.write(resp) +def capabilities(repo, req): + caps = ['lookup', 'changegroupsubset'] + if repo.ui.configbool('server', 'uncompressed', untrusted=True): + caps.append('stream=%d' % repo.changelog.version) + if changegroupmod.bundlepriority: + caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) + rsp = ' '.join(caps) + req.respond(HTTP_OK, HGTYPE, length=len(rsp)) + yield rsp -def unbundle(web, req): +def unbundle(repo, req): + + errorfmt = '0\n%s\n' + proto = req.env.get('wsgi.url_scheme') or 'http' + their_heads = req.form['heads'][0].split(' ') - def bail(response, headers={}): + def check_heads(): + heads = map(hex, repo.heads()) + return their_heads == [hex('force')] or their_heads == heads + + # fail early if possible + if not check_heads(): length = int(req.env.get('CONTENT_LENGTH', 0)) for s in util.filechunkiter(req, limit=length): # drain incoming bundle, else client will not see # response when run outside cgi script pass - - status = headers.pop('status', HTTP_OK) - req.header(headers.items()) - req.respond(status, HGTYPE) - req.write('0\n') - req.write(response) - - # enforce that you can only unbundle with POST requests - if req.env['REQUEST_METHOD'] != 'POST': - headers = {'status': '405 Method Not Allowed'} - bail('unbundle requires POST request\n', headers) - return - - # require ssl by default, auth info cannot be sniffed and - # replayed - ssl_req = web.configbool('web', 'push_ssl', True) - if ssl_req: - if req.env.get('wsgi.url_scheme') != 'https': - bail('ssl required\n') - return - proto = 'https' - else: - proto = 'http' - - # do not allow push unless explicitly allowed - if not web.check_perm(req, 'push', False): - bail('push not authorized\n', headers={'status': '401 Unauthorized'}) - return - - their_heads = req.form['heads'][0].split(' ') - - def check_heads(): - heads = map(hex, web.repo.heads()) - return their_heads == [hex('force')] or their_heads == heads - - # fail early if possible - if not check_heads(): - bail('unsynced changes\n') - return + req.respond(HTTP_OK, HGTYPE) + return errorfmt % 'unsynced changes', req.respond(HTTP_OK, HGTYPE) @@ -166,12 +139,10 @@ fp.write(s) try: - lock = web.repo.lock() + lock = repo.lock() try: if not check_heads(): - req.write('0\n') - req.write('unsynced changes\n') - return + return errorfmt % 'unsynced changes', fp.seek(0) header = fp.read(6) @@ -190,26 +161,23 @@ url = 'remote:%s:%s' % (proto, req.env.get('REMOTE_HOST', '')) try: - ret = web.repo.addchangegroup(gen, 'serve', url) + ret = repo.addchangegroup(gen, 'serve', url) except util.Abort, inst: sys.stdout.write("abort: %s\n" % inst) ret = 0 finally: val = sys.stdout.getvalue() sys.stdout, sys.stderr = oldio - req.write('%d\n' % ret) - req.write(val) + return '%d\n%s' % (ret, val), finally: del lock except ValueError, inst: - req.write('0\n') - req.write(str(inst) + '\n') + return errorfmt % inst, except (OSError, IOError), inst: - req.write('0\n') filename = getattr(inst, 'filename', '') # Don't send our filesystem layout to the client - if filename.startswith(web.repo.root): - filename = filename[len(web.repo.root)+1:] + if filename.startswith(repo.root): + filename = filename[len(repo.root)+1:] else: filename = '' error = getattr(inst, 'strerror', 'Unknown error') @@ -218,13 +186,11 @@ else: code = HTTP_SERVER_ERROR req.respond(code) - req.write('%s: %s\n' % (error, filename)) + return '0\n%s: %s\n' % (error, filename), finally: fp.close() os.unlink(tempname) -def stream_out(web, req): - if not web.allowpull: - return +def stream_out(repo, req): req.respond(HTTP_OK, HGTYPE) - streamclone.stream_out(web.repo, req, untrusted=True) + return streamclone.stream_out(repo, untrusted=True)
--- a/mercurial/hgweb/request.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/hgweb/request.py Wed Jul 02 09:31:13 2008 +0200 @@ -9,6 +9,31 @@ import socket, cgi, errno from common import ErrorResponse, statusmessage +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)] +} + +def expand(form): + 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] + return form + class wsgirequest(object): def __init__(self, wsgienv, start_response): version = wsgienv['wsgi.version'] @@ -21,7 +46,7 @@ self.multiprocess = wsgienv['wsgi.multiprocess'] self.run_once = wsgienv['wsgi.run_once'] self.env = wsgienv - self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) + self.form = expand(cgi.parse(self.inp, self.env, keep_blank_values=1)) self._start_response = start_response self.server_write = None self.headers = []
--- a/mercurial/hgweb/server.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/hgweb/server.py Wed Jul 02 09:31:13 2008 +0200 @@ -122,7 +122,8 @@ self.saved_headers = [] self.sent_headers = False self.length = None - self.server.application(env, self._start_response) + for chunk in self.server.application(env, self._start_response): + self._write(chunk) def send_headers(self): if not self.saved_status:
--- a/mercurial/httprepo.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/httprepo.py Wed Jul 02 09:31:13 2008 +0200 @@ -268,6 +268,7 @@ # 1.0 here is the _protocol_ version opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] + opener.addheaders.append(('Accept', 'application/mercurial-0.1')) urllib2.install_opener(opener) def url(self):
--- a/mercurial/sshserver.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/sshserver.py Wed Jul 02 09:31:13 2008 +0200 @@ -204,4 +204,6 @@ os.unlink(tempname) def do_stream_out(self): - streamclone.stream_out(self.repo, self.fout) + for chunk in streamclone.stream_out(self.repo): + self.fout.write(chunk) + self.fout.flush()
--- a/mercurial/streamclone.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/streamclone.py Wed Jul 02 09:31:13 2008 +0200 @@ -51,12 +51,12 @@ # # server writes out raw file data. -def stream_out(repo, fileobj, untrusted=False): +def stream_out(repo, untrusted=False): '''stream out all metadata files in repository. writes to file-like object, must support write() and optional flush().''' if not repo.ui.configbool('server', 'uncompressed', untrusted=untrusted): - fileobj.write('1\n') + yield '1\n' return # get consistent snapshot of repo. lock during scan so lock not @@ -67,10 +67,10 @@ repolock = repo.lock() except (lock.LockHeld, lock.LockUnavailable), inst: repo.ui.warn('locking the repository failed: %s\n' % (inst,)) - fileobj.write('2\n') + yield '2\n' return - fileobj.write('0\n') + yield '0\n' repo.ui.debug('scanning\n') entries = [] total_bytes = 0 @@ -83,11 +83,9 @@ repo.ui.debug('%d files, %d bytes to transfer\n' % (len(entries), total_bytes)) - fileobj.write('%d %d\n' % (len(entries), total_bytes)) + yield '%d %d\n' % (len(entries), total_bytes) for name, size in entries: repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) - fileobj.write('%s\0%d\n' % (name, size)) + yield '%s\0%d\n' % (name, size) for chunk in util.filechunkiter(repo.sopener(name), limit=size): - fileobj.write(chunk) - flush = getattr(fileobj, 'flush', None) - if flush: flush() + yield chunk
--- a/mercurial/templater.py Fri Jun 27 21:45:16 2008 -0500 +++ b/mercurial/templater.py Wed Jul 02 09:31:13 2008 +0200 @@ -81,18 +81,18 @@ def __contains__(self, key): return key in self.cache or key in self.map - def __call__(self, t, **map): - '''perform expansion. - t is name of map element to expand. - map is added elements to use during expansion.''' + def _template(self, t): + '''Get the template for the given template name. Use a local cache.''' if not t in self.cache: try: self.cache[t] = file(self.map[t]).read() except IOError, inst: raise IOError(inst.args[0], _('template file %s: %s') % (self.map[t], inst.args[1])) - tmpl = self.cache[t] + return self.cache[t] + def _process(self, tmpl, map): + '''Render a template. Returns a generator.''' while tmpl: m = self.template_re.search(tmpl) if not m: @@ -119,13 +119,34 @@ lm = map.copy() for i in v: lm.update(i) - yield self(format, **lm) + t = self._template(format) + yield self._process(t, lm) else: if fl: for f in fl.split("|")[1:]: v = self.filters[f](v) yield v + def __call__(self, t, **map): + '''Perform expansion. t is name of map element to expand. map contains + added elements for use during expansion. Is a generator.''' + tmpl = self._template(t) + iters = [self._process(tmpl, map)] + while iters: + try: + item = iters[0].next() + except StopIteration: + iters.pop(0) + continue + if isinstance(item, str): + yield item + elif item is None: + yield '' + elif hasattr(item, '__iter__'): + iters.insert(0, iter(item)) + else: + yield str(item) + def templatepath(name=None): '''return location of template file or directory (if no name). returns None if not found.'''
--- a/setup.py Fri Jun 27 21:45:16 2008 -0500 +++ b/setup.py Wed Jul 02 09:31:13 2008 +0200 @@ -129,7 +129,7 @@ [os.path.join(root, file_) for file_ in files]) for root, dirs, files in os.walk('templates')], cmdclass=cmdclass, - options=dict(py2exe=dict(packages=['hgext']), + options=dict(py2exe=dict(packages=['hgext', 'email']), bdist_mpkg=dict(zipdist=True, license='COPYING', readme='contrib/macosx/Readme.html',
--- a/templates/coal/changeset.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/changeset.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -9,8 +9,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> - <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li> - <li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li> + <li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> + <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/templates/coal/fileannotate.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/fileannotate.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -10,8 +10,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li> -<li><a href="{url}graph/{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul>
--- a/templates/coal/filediff.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/filediff.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -10,8 +10,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li> -<li><a href="{url}graph/{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/templates/coal/filelog.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/filelog.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -15,8 +15,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li> -<li><a href="{url}graph/{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/templates/coal/filerevision.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/filerevision.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -10,8 +10,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li> -<li><a href="{url}graph/{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/templates/coal/graph.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/graph.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -15,7 +15,7 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> <li class="active">graph</li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul>
--- a/templates/coal/manifest.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/manifest.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -10,8 +10,8 @@ <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a> </div> <ul> -<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li> -<li><a href="{url}graph/{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/templates/coal/shortlog.tmpl Fri Jun 27 21:45:16 2008 -0500 +++ b/templates/coal/shortlog.tmpl Wed Jul 02 09:31:13 2008 +0200 @@ -15,7 +15,7 @@ </div> <ul> <li class="active">log</li> -<li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li> +<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li> <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li> </ul> <ul>
--- a/tests/test-hgweb-commands Fri Jun 27 21:45:16 2008 -0500 +++ b/tests/test-hgweb-commands Wed Jul 02 09:31:13 2008 +0200 @@ -34,21 +34,22 @@ echo % Overviews "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/tags/?style=atom' | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//" "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/summary/?style=gitweb' | sed "s/[0-9]* years ago/long ago/g" +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/?style=gitweb' | sed "s/[0-9]* years/long/g" echo % capabilities -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/capabilities' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities' echo % heads -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/heads' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=heads' echo % lookup -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/lookup/1' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=lookup&node=1' echo % branches -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/branches' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=branches' echo % changegroup -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/changegroup' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=changegroup' echo % stream_out -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/stream_out' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=stream_out' echo % failing unbundle, requires POST request -"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/unbundle' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=unbundle' echo % Static files "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/static/style.css'
--- a/tests/test-hgweb-no-path-info Fri Jun 27 21:45:16 2008 -0500 +++ b/tests/test-hgweb-no-path-info Wed Jul 02 09:31:13 2008 +0200 @@ -43,15 +43,17 @@ output = StringIO() env['QUERY_STRING'] = 'style=atom' -hgweb('.', name = 'repo')(env, startrsp) -print output.getvalue() +content = hgweb('.', name = 'repo')(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() output = StringIO() env['QUERY_STRING'] = 'style=raw' -hgwebdir({'repo': '.'})(env, startrsp) -print output.getvalue() +content = hgwebdir({'repo': '.'})(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() EOF
--- a/tests/test-hgweb-no-path-info.out Fri Jun 27 21:45:16 2008 -0500 +++ b/tests/test-hgweb-no-path-info.out Wed Jul 02 09:31:13 2008 +0200 @@ -35,7 +35,6 @@ </entry> </feed> - ---- ERRORS ---- HEADERS @@ -45,6 +44,5 @@ repo/ - ---- ERRORS
--- a/tests/test-hgweb-no-request-uri Fri Jun 27 21:45:16 2008 -0500 +++ b/tests/test-hgweb-no-request-uri Wed Jul 02 09:31:13 2008 +0200 @@ -44,32 +44,36 @@ output = StringIO() env['PATH_INFO'] = '/' env['QUERY_STRING'] = 'style=atom' -hgweb('.', name = 'repo')(env, startrsp) -print output.getvalue() +content = hgweb('.', name = 'repo')(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() output = StringIO() env['PATH_INFO'] = '/file/tip/' env['QUERY_STRING'] = 'style=raw' -hgweb('.', name = 'repo')(env, startrsp) -print output.getvalue() +content = hgweb('.', name = 'repo')(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() output = StringIO() env['PATH_INFO'] = '/' env['QUERY_STRING'] = 'style=raw' -hgwebdir({'repo': '.'})(env, startrsp) -print output.getvalue() +content = hgwebdir({'repo': '.'})(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() output = StringIO() env['PATH_INFO'] = '/repo/file/tip/' env['QUERY_STRING'] = 'style=raw' -hgwebdir({'repo': '.'})(env, startrsp) -print output.getvalue() +content = hgwebdir({'repo': '.'})(env, startrsp) +sys.stdout.write(output.getvalue()) +sys.stdout.write(''.join(content)) print '---- ERRORS' print errors.getvalue() EOF
--- a/tests/test-hgweb-no-request-uri.out Fri Jun 27 21:45:16 2008 -0500 +++ b/tests/test-hgweb-no-request-uri.out Wed Jul 02 09:31:13 2008 +0200 @@ -35,6 +35,24 @@ </entry> </feed> +---- ERRORS + +---- HEADERS +200 Script output follows +---- DATA +[('Content-Type', 'text/plain; charset=ascii')] + +-rw-r--r-- 4 bar + + +---- ERRORS + +---- HEADERS +200 Script output follows +---- DATA +[('Content-Type', 'text/plain; charset=ascii')] + +/repo/ ---- ERRORS @@ -46,27 +64,5 @@ -rw-r--r-- 4 bar - ---- ERRORS ----- HEADERS -200 Script output follows ----- DATA -[('Content-Type', 'text/plain; charset=ascii')] - -/repo/ - - ----- ERRORS - ----- HEADERS -200 Script output follows ----- DATA -[('Content-Type', 'text/plain; charset=ascii')] - --rw-r--r-- 4 bar - - - ----- ERRORS -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-pull-http Wed Jul 02 09:31:13 2008 +0200 @@ -0,0 +1,36 @@ +#!/bin/sh + +cp "$TESTDIR"/printenv.py . + +hg init test +cd test +echo a > a +hg ci -Ama -d '0 0' + +cd .. +hg clone test test2 +cd test2 +echo a >> a +hg ci -mb -d '0 0' + +echo % expect error, cloning not allowed +echo '[web]' > .hg/hgrc +echo 'allowpull = false' >> .hg/hgrc +hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log +cat hg.pid >> $DAEMON_PIDS +hg clone http://localhost:$HGPORT/ test3 | sed -e 's,:[0-9][0-9]*/,/,' +kill `cat hg.pid` +echo % serve errors +cat errors.log + +req() { + hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log + cat hg.pid >> $DAEMON_PIDS + hg --cwd ../test pull http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,' + kill `cat hg.pid` + echo % serve errors + cat errors.log +} + +echo % expect error, pulling not allowed +req
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-pull-http.out Wed Jul 02 09:31:13 2008 +0200 @@ -0,0 +1,12 @@ +adding a +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% expect error, cloning not allowed +abort: error: +requesting all changes +% serve errors +% expect error, pulling not allowed +abort: error: +pulling from http://localhost/ +searching for changes +% serve errors