changeset 941:4cf418c2a013

Add a multi-repository server This merges a bunch of the ideas for a multi-repository CGI script and simplifies things a bit. It uses PATH_INFO so it generally wants paths of the form: http://host/hg.cgi/virtualpath This gets mapped via a simple config file to the real path. All info about the repo is read from the repo's hgrc.
author mpm@selenic.com
date Fri, 19 Aug 2005 16:38:25 -0800
parents 1300271ba8de
children ffb0665028f0
files hgwebdir.cgi mercurial/hgweb.py templates/index.tmpl templates/map
diffstat 4 files changed, 105 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgwebdir.cgi	Fri Aug 19 16:38:25 2005 -0800
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+#
+# An example CGI script to export multiple hgweb repos, edit as necessary
+
+import cgi, cgitb, os, sys, ConfigParser
+cgitb.enable()
+
+# sys.path.insert(0, "/path/to/python/lib") # if not a system-wide install
+from mercurial import hgweb
+
+# The config file looks like this:
+# [paths]
+# virtual/path = /real/path
+# virtual/path = /real/path
+
+h = hgweb.hgwebdir("hgweb.config")
+h.run()
--- a/mercurial/hgweb.py	Wed Aug 17 18:52:27 2005 -0800
+++ b/mercurial/hgweb.py	Fri Aug 19 16:38:25 2005 -0800
@@ -114,29 +114,29 @@
 def rfc822date(x):
     return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(x))
 
+common_filters = {
+    "escape": cgi.escape,
+    "age": age,
+    "date": (lambda x: time.asctime(time.gmtime(x))),
+    "addbreaks": nl2br,
+    "obfuscate": obfuscate,
+    "short": (lambda x: x[:12]),
+    "firstline": (lambda x: x.splitlines(1)[0]),
+    "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
+    "rfc822date": rfc822date,
+    }
+
 class hgweb:
     maxchanges = 10
     maxfiles = 10
 
-    def __init__(self, path, name, templates = ""):
+    def __init__(self, path, name=None, templates=""):
         self.templates = templates
         self.reponame = name
         self.path = path
         self.mtime = -1
         self.viewonly = 0
 
-        self.filters = {
-            "escape": cgi.escape,
-            "age": age,
-            "date": (lambda x: time.asctime(time.gmtime(x))),
-            "addbreaks": nl2br,
-            "obfuscate": obfuscate,
-            "short": (lambda x: x[:12]),
-            "firstline": (lambda x: x.splitlines(1)[0]),
-            "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
-            "rfc822date": rfc822date,
-            }
-
     def refresh(self):
         s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
         if s.st_mtime != self.mtime:
@@ -619,7 +619,7 @@
 
         name = self.reponame or self.repo.ui.config("web", "name", os.getcwd())
 
-        self.t = templater(m, self.filters,
+        self.t = templater(m, common_filters,
                            {"url":url,
                             "repo":name,
                             "header":header,
@@ -818,3 +818,57 @@
     httpd = create_server(path, name, templates, address, port, use_ipv6,
                           accesslog, errorlog)
     httpd.serve_forever()
+
+# This is a stopgap
+class hgwebdir:
+    def __init__(self, config):
+        self.cp = ConfigParser.SafeConfigParser()
+        self.cp.read(config)
+
+    def run(self):
+        try:
+            virtual = os.environ["PATH_INFO"]
+        except:
+            virtual = ""
+
+        if virtual:
+            real = self.cp.get("paths", virtual[1:])
+            h = hgweb.hgweb(real)
+            h.run()
+            return
+
+        def header(**map):
+            yield tmpl("header", **map)
+
+        def footer(**map):
+            yield tmpl("footer", **map)
+
+        templates = templatepath()
+        m = os.path.join(templates, "map")
+        tmpl = templater(m, common_filters,
+                         {"header": header, "footer": footer})
+
+        def entries(**map):
+            parity = 0
+            for v,r in self.cp.items("paths"):
+                cp2 = ConfigParser.SafeConfigParser()
+                cp2.read(os.path.join(r, ".hg", "hgrc"))
+
+                def get(sec, val, default):
+                    try:
+                        return cp2.get(sec, val)
+                    except:
+                        return default
+
+                yield tmpl("indexentry",
+                           author = get("web", "author", "unknown"),
+                           name = get("web", "name", v),
+                           url = os.environ["REQUEST_URI"] + "/" + v,
+                           parity = parity,
+                           shortdesc = get("web", "description", "unknown"),
+                           lastupdate = os.stat(os.path.join(r, ".hg",
+                                                "00changelog.d")).st_mtime)
+
+                parity = 1 - parity
+
+        write(tmpl("index", entries = entries))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/index.tmpl	Fri Aug 19 16:38:25 2005 -0800
@@ -0,0 +1,18 @@
+#header#
+<title>Mercurial repositories index</title>
+</head>
+<body>
+
+<h2>Mercurial Repositories</h2>
+
+<table>
+    <tr>
+        <td>Name</td>
+        <td>Description</td>
+        <td>Author</td>
+        <td>Last change</td>
+    <tr>
+    #entries#
+</table>
+
+#footer#
--- a/templates/map	Wed Aug 17 18:52:27 2005 -0800
+++ b/templates/map	Fri Aug 19 16:38:25 2005 -0800
@@ -35,3 +35,5 @@
 changesettag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
 filediffparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
 filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?cmd=file;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
+indexentry = "<tr class="parity#parity#"><td><a  href="#url#">#name#</a></td><td>#shortdesc#</td><td>#author# <i>#email|obfuscate#</i></td><td>#lastupdate|age# ago</td></tr>"
+index = index.tmpl