mercurial/hgweb/hgwebdir_mod.py
changeset 2356 2db831b33e8f
parent 2355 eb08fb4d41e1
child 2358 8819fc1dcf4b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/hgweb/hgwebdir_mod.py	Wed May 31 10:42:44 2006 -0700
@@ -0,0 +1,152 @@
+# 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.
+
+import os
+from mercurial.demandload import demandload
+demandload(globals(), "ConfigParser")
+demandload(globals(), "mercurial:ui,hg,util,templater")
+demandload(globals(), "mercurial.hgweb.request:hgrequest")
+from mercurial.i18n import gettext as _
+
+# This is a stopgap
+class hgwebdir(object):
+    def __init__(self, config):
+        def cleannames(items):
+            return [(name.strip(os.sep), path) for name, path in items]
+
+        self.motd = ""
+        self.repos_sorted = ('name', False)
+        if isinstance(config, (list, tuple)):
+            self.repos = cleannames(config)
+            self.repos_sorted = ('', False)
+        elif isinstance(config, dict):
+            self.repos = cleannames(config.items())
+            self.repos.sort()
+        else:
+            cp = ConfigParser.SafeConfigParser()
+            cp.read(config)
+            self.repos = []
+            if cp.has_section('web') and cp.has_option('web', 'motd'):
+                self.motd = cp.get('web', 'motd')
+            if cp.has_section('paths'):
+                self.repos.extend(cleannames(cp.items('paths')))
+            if cp.has_section('collections'):
+                for prefix, root in cp.items('collections'):
+                    for path in util.walkrepos(root):
+                        repo = os.path.normpath(path)
+                        name = repo
+                        if name.startswith(prefix):
+                            name = name[len(prefix):]
+                        self.repos.append((name.lstrip(os.sep), repo))
+            self.repos.sort()
+
+    def run(self, req=hgrequest()):
+        def header(**map):
+            yield tmpl("header", **map)
+
+        def footer(**map):
+            yield tmpl("footer", motd=self.motd, **map)
+
+        m = os.path.join(templater.templatepath(), "map")
+        tmpl = templater.templater(m, templater.common_filters,
+                                   defaults={"header": header,
+                                             "footer": footer})
+
+        def archivelist(ui, nodeid, url):
+            for i in ['zip', 'gz', 'bz2']:
+                if ui.configbool("web", "allow" + i, False):
+                    yield {"type" : i, "node": nodeid, "url": url}
+
+        def entries(sortcolumn="", descending=False, **map):
+            rows = []
+            parity = 0
+            for name, path in self.repos:
+                u = ui.ui()
+                try:
+                    u.readconfig(os.path.join(path, '.hg', 'hgrc'))
+                except IOError:
+                    pass
+                get = u.config
+
+                url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
+                       .replace("//", "/"))
+
+                # update time with local timezone
+                try:
+                    d = (get_mtime(path), util.makedate()[1])
+                except OSError:
+                    continue
+
+                contact = (get("ui", "username") or # preferred
+                           get("web", "contact") or # deprecated
+                           get("web", "author", "")) # also
+                description = get("web", "description", "")
+                name = get("web", "name", name)
+                row = dict(contact=contact or "unknown",
+                           contact_sort=contact.upper() or "unknown",
+                           name=name,
+                           name_sort=name,
+                           url=url,
+                           description=description or "unknown",
+                           description_sort=description.upper() or "unknown",
+                           lastchange=d,
+                           lastchange_sort=d[1]-d[0],
+                           archives=archivelist(u, "tip", url))
+                if (not sortcolumn
+                    or (sortcolumn, descending) == self.repos_sorted):
+                    # fast path for unsorted output
+                    row['parity'] = parity
+                    parity = 1 - parity
+                    yield row
+                else:
+                    rows.append((row["%s_sort" % sortcolumn], row))
+            if rows:
+                rows.sort()
+                if descending:
+                    rows.reverse()
+                for key, row in rows:
+                    row['parity'] = parity
+                    parity = 1 - parity
+                    yield row
+
+        virtual = req.env.get("PATH_INFO", "").strip('/')
+        if virtual:
+            real = dict(self.repos).get(virtual)
+            if real:
+                try:
+                    hgweb(real).run(req)
+                except IOError, inst:
+                    req.write(tmpl("error", error=inst.strerror))
+                except hg.RepoError, inst:
+                    req.write(tmpl("error", error=str(inst)))
+            else:
+                req.write(tmpl("notfound", repo=virtual))
+        else:
+            if req.form.has_key('static'):
+                static = os.path.join(templater.templatepath(), "static")
+                fname = req.form['static'][0]
+                req.write(staticfile(static, fname)
+                          or tmpl("error", error="%r not found" % fname))
+            else:
+                sortable = ["name", "description", "contact", "lastchange"]
+                sortcolumn, descending = self.repos_sorted
+                if req.form.has_key('sort'):
+                    sortcolumn = req.form['sort'][0]
+                    descending = sortcolumn.startswith('-')
+                    if descending:
+                        sortcolumn = sortcolumn[1:]
+                    if sortcolumn not in sortable:
+                        sortcolumn = ""
+
+                sort = [("sort_%s" % column,
+                         "%s%s" % ((not descending and column == sortcolumn)
+                                   and "-" or "", column))
+                        for column in sortable]
+                req.write(tmpl("index", entries=entries,
+                               sortcolumn=sortcolumn, descending=descending,
+                               **dict(sort)))