Splitting up hgweb so it's easier to change.
authorEric Hopper <hopper@omnifarious.org>
Wed, 31 May 2006 08:03:29 -0700
changeset 2355 eb08fb4d41e1
parent 2352 61909dfb316d
child 2356 2db831b33e8f
Splitting up hgweb so it's easier to change.
mercurial/commands.py
mercurial/hgweb/__init__.py
mercurial/hgweb/request.py
mercurial/hgweb/server.py
--- a/mercurial/commands.py	Mon May 29 16:46:31 2006 +0800
+++ b/mercurial/commands.py	Wed May 31 08:03:29 2006 -0700
@@ -2542,7 +2542,7 @@
         os._exit(0)
 
     try:
-        httpd = hgweb.create_server(ui, repo)
+        httpd = hgweb.create_server(ui, repo, hgweb.hgwebdir, hgweb.hgweb)
     except socket.error, inst:
         raise util.Abort(_('cannot start server: ') + inst.args[1])
 
--- a/mercurial/hgweb/__init__.py	Mon May 29 16:46:31 2006 +0800
+++ b/mercurial/hgweb/__init__.py	Wed May 31 08:03:29 2006 -0700
@@ -10,23 +10,12 @@
 import mimetypes
 from mercurial.demandload import demandload
 demandload(globals(), "time re socket zlib errno ConfigParser tempfile")
-demandload(globals(), "StringIO BaseHTTPServer SocketServer urllib")
 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater")
+demandload(globals(), "mercurial.hgweb.request:hgrequest")
+demandload(globals(), "mercurial.hgweb.server:create_server")
 from mercurial.node import *
 from mercurial.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
@@ -69,39 +58,6 @@
         # illegal fname or unreadable file
         return ""
 
-class hgrequest(object):
-    def __init__(self, inp=None, out=None, env=None):
-        self.inp = inp or sys.stdin
-        self.out = out or sys.stdout
-        self.env = env or os.environ
-        self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)
-
-    def write(self, *things):
-        for thing in things:
-            if hasattr(thing, "__iter__"):
-                for part in thing:
-                    self.write(part)
-            else:
-                try:
-                    self.out.write(str(thing))
-                except socket.error, inst:
-                    if inst[0] != errno.ECONNRESET:
-                        raise
-
-    def header(self, headers=[('Content-type','text/html')]):
-        for header in headers:
-            self.out.write("%s: %s\r\n" % header)
-        self.out.write("\r\n")
-
-    def httphdr(self, type, file="", size=0):
-
-        headers = [('Content-type', type)]
-        if file:
-            headers.append(('Content-disposition', 'attachment; filename=%s' % file))
-        if size > 0:
-            headers.append(('Content-length', str(size)))
-        self.header(headers)
-
 class hgweb(object):
     def __init__(self, repo, name=None):
         if type(repo) == type(""):
@@ -893,117 +849,6 @@
         else:
             req.write(self.t("error"))
 
-def create_server(ui, repo):
-    use_threads = True
-
-    def openlog(opt, default):
-        if opt and opt != '-':
-            return open(opt, 'w')
-        return default
-
-    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
-
-    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):
-            if self.address_family is None:
-                raise hg.RepoError(_('IPv6 not available on this system'))
-            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(),
-                                                 format % args))
-
-        def log_message(self, format, *args):
-            accesslog.write("%s - - [%s] %s\n" % (self.address_string(),
-                                                  self.log_date_time_string(),
-                                                  format % args))
-
-        def do_POST(self):
-            try:
-                self.do_hgweb()
-            except socket.error, inst:
-                if inst[0] != errno.EPIPE:
-                    raise
-
-        def do_GET(self):
-            self.do_POST()
-
-        def do_hgweb(self):
-            path_info, query = splitURI(self.path)
-
-            env = {}
-            env['GATEWAY_INTERFACE'] = 'CGI/1.1'
-            env['REQUEST_METHOD'] = self.command
-            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()
-            if host != self.client_address[0]:
-                env['REMOTE_HOST'] = host
-                env['REMOTE_ADDR'] = self.client_address[0]
-
-            if self.headers.typeheader is None:
-                env['CONTENT_TYPE'] = self.headers.type
-            else:
-                env['CONTENT_TYPE'] = self.headers.typeheader
-            length = self.headers.getheader('content-length')
-            if length:
-                env['CONTENT_LENGTH'] = length
-            accept = []
-            for line in self.headers.getallmatchingheaders('accept'):
-                if line[:1] in "\t\n\r ":
-                    accept.append(line.strip())
-                else:
-                    accept = accept + line[7:].split(',')
-            env['HTTP_ACCEPT'] = ','.join(accept)
-
-            req = hgrequest(self.rfile, self.wfile, env)
-            self.send_response(200, "Script output follows")
-
-            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 MercurialHTTPServer((address, port), hgwebhandler)
-
 # This is a stopgap
 class hgwebdir(object):
     def __init__(self, config):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/hgweb/request.py	Wed May 31 08:03:29 2006 -0700
@@ -0,0 +1,44 @@
+# hgweb.py - web interface to a mercurial repository
+#
+# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
+# Copyright 2005 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from mercurial.demandload import demandload
+demandload(globals(), "socket sys cgi os")
+from mercurial.i18n import gettext as _
+
+class hgrequest(object):
+    def __init__(self, inp=None, out=None, env=None):
+        self.inp = inp or sys.stdin
+        self.out = out or sys.stdout
+        self.env = env or os.environ
+        self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)
+
+    def write(self, *things):
+        for thing in things:
+            if hasattr(thing, "__iter__"):
+                for part in thing:
+                    self.write(part)
+            else:
+                try:
+                    self.out.write(str(thing))
+                except socket.error, inst:
+                    if inst[0] != errno.ECONNRESET:
+                        raise
+
+    def header(self, headers=[('Content-type','text/html')]):
+        for header in headers:
+            self.out.write("%s: %s\r\n" % header)
+        self.out.write("\r\n")
+
+    def httphdr(self, type, file="", size=0):
+
+        headers = [('Content-type', type)]
+        if file:
+            headers.append(('Content-disposition', 'attachment; filename=%s' % file))
+        if size > 0:
+            headers.append(('Content-length', str(size)))
+        self.header(headers)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/hgweb/server.py	Wed May 31 08:03:29 2006 -0700
@@ -0,0 +1,150 @@
+# hgweb.py - web interface to a mercurial repository
+#
+# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
+# Copyright 2005 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from mercurial.demandload import demandload
+import os, sys, errno
+demandload(globals(), "urllib BaseHTTPServer socket SocketServer")
+demandload(globals(), "mercurial:ui,hg,util,templater")
+demandload(globals(), "mercurial.hgweb.request:hgrequest")
+from mercurial.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
+
+class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
+    def __init__(self, *args, **kargs):
+        BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
+
+    def log_error(self, format, *args):
+        errorlog = self.server.errorlog
+        errorlog.write("%s - - [%s] %s\n" % (self.address_string(),
+                                             self.log_date_time_string(),
+                                             format % args))
+
+    def log_message(self, format, *args):
+        accesslog = self.server.accesslog
+        accesslog.write("%s - - [%s] %s\n" % (self.address_string(),
+                                              self.log_date_time_string(),
+                                              format % args))
+
+    def do_POST(self):
+        try:
+            self.do_hgweb()
+        except socket.error, inst:
+            if inst[0] != errno.EPIPE:
+                raise
+
+    def do_GET(self):
+        self.do_POST()
+
+    def do_hgweb(self):
+        path_info, query = _splitURI(self.path)
+
+        env = {}
+        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
+        env['REQUEST_METHOD'] = self.command
+        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()
+        if host != self.client_address[0]:
+            env['REMOTE_HOST'] = host
+            env['REMOTE_ADDR'] = self.client_address[0]
+
+        if self.headers.typeheader is None:
+            env['CONTENT_TYPE'] = self.headers.type
+        else:
+            env['CONTENT_TYPE'] = self.headers.typeheader
+        length = self.headers.getheader('content-length')
+        if length:
+            env['CONTENT_LENGTH'] = length
+        accept = []
+        for line in self.headers.getallmatchingheaders('accept'):
+            if line[:1] in "\t\n\r ":
+                accept.append(line.strip())
+            else:
+                accept = accept + line[7:].split(',')
+        env['HTTP_ACCEPT'] = ','.join(accept)
+
+        req = hgrequest(self.rfile, self.wfile, env)
+        self.send_response(200, "Script output follows")
+        self.server.make_and_run_handler(req)
+
+def create_server(ui, repo, webdirmaker, repoviewmaker):
+    use_threads = True
+
+    def openlog(opt, default):
+        if opt and opt != '-':
+            return open(opt, 'w')
+        return default
+
+    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
+
+    if use_threads:
+        _mixin = SocketServer.ThreadingMixIn
+    else:
+        if hasattr(os, "fork"):
+            _mixin = SocketServer.ForkingMixIn
+        else:
+            class _mixin: pass
+
+    class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
+        def __init__(self, *args, **kargs):
+            BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs)
+            self.accesslog = accesslog
+            self.errorlog = errorlog
+            self.repo = repo
+            self.webdir_conf = webdir_conf
+            self.webdirmaker = webdirmaker
+            self.repoviewmaker = repoviewmaker
+
+        def make_and_run_handler(self, req):
+            if self.webdir_conf:
+                hgwebobj = self.webdirmaker(self.server.webdir_conf)
+            elif self.repo is not None:
+                hgwebobj = self.repoviewmaker(repo.__class__(repo.ui,
+                                                             repo.origroot))
+            else:
+                raise hg.RepoError(_('no repo found'))
+            hgwebobj.run(req)
+
+    class IPv6HTTPServer(MercurialHTTPServer):
+        address_family = getattr(socket, 'AF_INET6', None)
+
+        def __init__(self, *args, **kwargs):
+            if self.address_family is None:
+                raise hg.RepoError(_('IPv6 not available on this system'))
+            super(IPv6HTTPServer, self).__init__(*args, **kargs)
+
+    if use_ipv6:
+        return IPv6HTTPServer((address, port), _hgwebhandler)
+    else:
+        return MercurialHTTPServer((address, port), _hgwebhandler)