# HG changeset patch # User Thomas Arendsen Hein # Date 1145986725 -7200 # Node ID 150208e0d94b56c3ebdd27f450d676c3a117a73d # Parent 8a85dbbadddf41a68639da2d1cce4cb1418f58ca# Parent e296dee1cd9abc6a23a61a68f5b773be88c01c8a Merge with crew diff --git a/CONTRIBUTORS b/CONTRIBUTORS --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -21,6 +21,7 @@ Vicent SeguĂ­ Pascual Sean Perry Nguyen Anh Quynh Ollivier Robert +Alexander Schremmer Arun Sharma Josef "Jeff" Sipek Kevin Smith diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -2495,6 +2495,8 @@ def serve(ui, repo, **opts): """ if opts["stdio"]: + if repo is None: + raise hg.RepoError(_('no repo found')) fin, fout = sys.stdin, sys.stdout sys.stdout = sys.stderr @@ -2566,11 +2568,15 @@ def serve(ui, repo, **opts): r = repo.addchangegroup(fin) respond(str(r)) - optlist = "name templates style address port ipv6 accesslog errorlog" + optlist = ("name templates style address port ipv6" + " accesslog errorlog webdir_conf") for o in optlist.split(): if opts[o]: ui.setconfig("web", o, opts[o]) + if repo is None and not ui.config("web", "webdir_conf"): + raise hg.RepoError(_('no repo found')) + if opts['daemon'] and not opts['daemon_pipefds']: rfd, wfd = os.pipe() args = sys.argv[:] @@ -2582,7 +2588,7 @@ def serve(ui, repo, **opts): os._exit(0) try: - httpd = hgweb.create_server(repo) + httpd = hgweb.create_server(ui, repo) except socket.error, inst: raise util.Abort(_('cannot start server: ') + inst.args[1]) @@ -2997,8 +3003,8 @@ table = { "import|patch": (import_, [('p', 'strip', 1, - _('directory strip option for patch. This has the same\n') + - _('meaning as the corresponding patch option')), + _('directory strip option for patch. This has the same\n' + 'meaning as the corresponding patch option')), ('b', 'base', '', _('base path')), ('f', 'force', None, _('skip check for outstanding uncommitted changes'))], @@ -3127,6 +3133,8 @@ table = { ('a', 'address', '', _('address to use')), ('n', 'name', '', _('name to show in web pages (default: working dir)')), + ('', 'webdir-conf', '', _('name of the webdir config file' + ' (serve more than one repo)')), ('', 'pid-file', '', _('name of file to write process ID to')), ('', 'stdio', None, _('for remote clients')), ('t', 'templates', '', _('web templates to use')), @@ -3199,7 +3207,7 @@ globalopts = [ norepo = ("clone init version help debugancestor debugcomplete debugdata" " debugindex debugindexdot") -optionalrepo = ("paths debugconfig") +optionalrepo = ("paths serve debugconfig") def findpossible(cmd): """ diff --git a/mercurial/hgweb.py b/mercurial/hgweb.py --- a/mercurial/hgweb.py +++ b/mercurial/hgweb.py @@ -10,11 +10,23 @@ import os, cgi, sys import mimetypes from demandload import demandload demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser") -demandload(globals(), "tempfile StringIO BaseHTTPServer util") -demandload(globals(), "archival mimetypes templater") +demandload(globals(), "tempfile StringIO BaseHTTPServer util SocketServer") +demandload(globals(), "archival mimetypes templater urllib") from node import * from i18n import gettext as _ +def splitURI(uri): + """ Return path and query splited from uri + + Just like CGI environment, the path is unquoted, the query is + not. + """ + if '?' in uri: + path, query = uri.split('?', 1) + else: + path, query = uri, '' + return urllib.unquote(path), query + def up(p): if p[0] != "/": p = "/" + p @@ -776,54 +788,54 @@ class hgweb(object): if not req.form.has_key('cmd'): req.form['cmd'] = [self.t.cache['default'],] - if req.form['cmd'][0] == 'changelog': - c = self.repo.changelog.count() - 1 - hi = c + cmd = req.form['cmd'][0] + if cmd == 'changelog': + hi = self.repo.changelog.count() - 1 if req.form.has_key('rev'): hi = req.form['rev'][0] try: hi = self.repo.changelog.rev(self.repo.lookup(hi)) except hg.RepoError: - req.write(self.search(hi)) + req.write(self.search(hi)) # XXX redirect to 404 page? return req.write(self.changelog(hi)) - elif req.form['cmd'][0] == 'changeset': + elif cmd == 'changeset': req.write(self.changeset(req.form['node'][0])) - elif req.form['cmd'][0] == 'manifest': + elif cmd == 'manifest': req.write(self.manifest(req.form['manifest'][0], clean(req.form['path'][0]))) - elif req.form['cmd'][0] == 'tags': + elif cmd == 'tags': req.write(self.tags()) - elif req.form['cmd'][0] == 'summary': + elif cmd == 'summary': req.write(self.summary()) - elif req.form['cmd'][0] == 'filediff': + elif cmd == 'filediff': req.write(self.filediff(clean(req.form['file'][0]), req.form['node'][0])) - elif req.form['cmd'][0] == 'file': + elif cmd == 'file': req.write(self.filerevision(clean(req.form['file'][0]), req.form['filenode'][0])) - elif req.form['cmd'][0] == 'annotate': + elif cmd == 'annotate': req.write(self.fileannotate(clean(req.form['file'][0]), req.form['filenode'][0])) - elif req.form['cmd'][0] == 'filelog': + elif cmd == 'filelog': req.write(self.filelog(clean(req.form['file'][0]), req.form['filenode'][0])) - elif req.form['cmd'][0] == 'heads': + elif cmd == 'heads': req.httphdr("application/mercurial-0.1") h = self.repo.heads() req.write(" ".join(map(hex, h)) + "\n") - elif req.form['cmd'][0] == 'branches': + elif cmd == 'branches': req.httphdr("application/mercurial-0.1") nodes = [] if req.form.has_key('nodes'): @@ -831,7 +843,7 @@ class hgweb(object): for b in self.repo.branches(nodes): req.write(" ".join(map(hex, b)) + "\n") - elif req.form['cmd'][0] == 'between': + elif cmd == 'between': req.httphdr("application/mercurial-0.1") nodes = [] if req.form.has_key('pairs'): @@ -840,7 +852,7 @@ class hgweb(object): for b in self.repo.between(pairs): req.write(" ".join(map(hex, b)) + "\n") - elif req.form['cmd'][0] == 'changegroup': + elif cmd == 'changegroup': req.httphdr("application/mercurial-0.1") nodes = [] if not self.allowpull: @@ -859,7 +871,7 @@ class hgweb(object): req.write(z.flush()) - elif req.form['cmd'][0] == 'archive': + elif cmd == 'archive': changeset = self.repo.lookup(req.form['node'][0]) type = req.form['type'][0] if (type in self.archives and @@ -869,7 +881,7 @@ class hgweb(object): req.write(self.t("error")) - elif req.form['cmd'][0] == 'static': + elif cmd == 'static': fname = req.form['file'][0] req.write(staticfile(static, fname) or self.t("error", error="%r not found" % fname)) @@ -877,20 +889,39 @@ class hgweb(object): else: req.write(self.t("error")) -def create_server(repo): +def create_server(ui, repo): + use_threads = True def openlog(opt, default): if opt and opt != '-': return open(opt, 'w') return default - address = repo.ui.config("web", "address", "") - port = int(repo.ui.config("web", "port", 8000)) - use_ipv6 = repo.ui.configbool("web", "ipv6") - accesslog = openlog(repo.ui.config("web", "accesslog", "-"), sys.stdout) - errorlog = openlog(repo.ui.config("web", "errorlog", "-"), sys.stderr) + address = ui.config("web", "address", "") + port = int(ui.config("web", "port", 8000)) + use_ipv6 = ui.configbool("web", "ipv6") + webdir_conf = ui.config("web", "webdir_conf") + accesslog = openlog(ui.config("web", "accesslog", "-"), sys.stdout) + errorlog = openlog(ui.config("web", "errorlog", "-"), sys.stderr) + + if use_threads: + try: + from threading import activeCount + except ImportError: + use_threads = False - class IPv6HTTPServer(BaseHTTPServer.HTTPServer): + if use_threads: + _mixin = SocketServer.ThreadingMixIn + else: + if hasattr(os, "fork"): + _mixin = SocketServer.ForkingMixIn + else: + class _mixin: pass + + class MercurialHTTPServer(_mixin, BaseHTTPServer.HTTPServer): + pass + + class IPv6HTTPServer(MercurialHTTPServer): address_family = getattr(socket, 'AF_INET6', None) def __init__(self, *args, **kwargs): @@ -899,6 +930,7 @@ def create_server(repo): BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs) class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler): + def log_error(self, format, *args): errorlog.write("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), @@ -920,11 +952,7 @@ def create_server(repo): self.do_POST() def do_hgweb(self): - query = "" - p = self.path.find("?") - if p: - query = self.path[p + 1:] - query = query.replace('+', ' ') + path_info, query = splitURI(self.path) env = {} env['GATEWAY_INTERFACE'] = 'CGI/1.1' @@ -932,6 +960,7 @@ def create_server(repo): env['SERVER_NAME'] = self.server.server_name env['SERVER_PORT'] = str(self.server.server_port) env['REQUEST_URI'] = "/" + env['PATH_INFO'] = path_info if query: env['QUERY_STRING'] = query host = self.address_string() @@ -956,13 +985,20 @@ def create_server(repo): req = hgrequest(self.rfile, self.wfile, env) self.send_response(200, "Script output follows") - hg.run(req) - hg = hgweb(repo) + if webdir_conf: + hgwebobj = hgwebdir(webdir_conf) + elif repo is not None: + hgwebobj = hgweb(repo.__class__(repo.ui, repo.origroot)) + else: + raise hg.RepoError(_('no repo found')) + hgwebobj.run(req) + + if use_ipv6: return IPv6HTTPServer((address, port), hgwebhandler) else: - return BaseHTTPServer.HTTPServer((address, port), hgwebhandler) + return MercurialHTTPServer((address, port), hgwebhandler) # This is a stopgap class hgwebdir(object): diff --git a/templates/header-gitweb.tmpl b/templates/header-gitweb.tmpl --- a/templates/header-gitweb.tmpl +++ b/templates/header-gitweb.tmpl @@ -7,5 +7,5 @@ Content-type: text/html - + diff --git a/templates/header.tmpl b/templates/header.tmpl --- a/templates/header.tmpl +++ b/templates/header.tmpl @@ -5,4 +5,4 @@ Content-type: text/html - +