Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb/hgwebdir_mod.py @ 2356:2db831b33e8f
Final stage of the hgweb split up.
hgweb and hgwebdir now have their own modules.
author | Eric Hopper <hopper@omnifarious.org> |
---|---|
date | Wed, 31 May 2006 10:42:44 -0700 |
parents | mercurial/hgweb/__init__.py@eb08fb4d41e1 |
children | 8819fc1dcf4b |
comparison
equal
deleted
inserted
replaced
2355:eb08fb4d41e1 | 2356:2db831b33e8f |
---|---|
1 # hgweb.py - web interface to a mercurial repository | |
2 # | |
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
5 # | |
6 # This software may be used and distributed according to the terms | |
7 # of the GNU General Public License, incorporated herein by reference. | |
8 | |
9 import os | |
10 from mercurial.demandload import demandload | |
11 demandload(globals(), "ConfigParser") | |
12 demandload(globals(), "mercurial:ui,hg,util,templater") | |
13 demandload(globals(), "mercurial.hgweb.request:hgrequest") | |
14 from mercurial.i18n import gettext as _ | |
15 | |
16 # This is a stopgap | |
17 class hgwebdir(object): | |
18 def __init__(self, config): | |
19 def cleannames(items): | |
20 return [(name.strip(os.sep), path) for name, path in items] | |
21 | |
22 self.motd = "" | |
23 self.repos_sorted = ('name', False) | |
24 if isinstance(config, (list, tuple)): | |
25 self.repos = cleannames(config) | |
26 self.repos_sorted = ('', False) | |
27 elif isinstance(config, dict): | |
28 self.repos = cleannames(config.items()) | |
29 self.repos.sort() | |
30 else: | |
31 cp = ConfigParser.SafeConfigParser() | |
32 cp.read(config) | |
33 self.repos = [] | |
34 if cp.has_section('web') and cp.has_option('web', 'motd'): | |
35 self.motd = cp.get('web', 'motd') | |
36 if cp.has_section('paths'): | |
37 self.repos.extend(cleannames(cp.items('paths'))) | |
38 if cp.has_section('collections'): | |
39 for prefix, root in cp.items('collections'): | |
40 for path in util.walkrepos(root): | |
41 repo = os.path.normpath(path) | |
42 name = repo | |
43 if name.startswith(prefix): | |
44 name = name[len(prefix):] | |
45 self.repos.append((name.lstrip(os.sep), repo)) | |
46 self.repos.sort() | |
47 | |
48 def run(self, req=hgrequest()): | |
49 def header(**map): | |
50 yield tmpl("header", **map) | |
51 | |
52 def footer(**map): | |
53 yield tmpl("footer", motd=self.motd, **map) | |
54 | |
55 m = os.path.join(templater.templatepath(), "map") | |
56 tmpl = templater.templater(m, templater.common_filters, | |
57 defaults={"header": header, | |
58 "footer": footer}) | |
59 | |
60 def archivelist(ui, nodeid, url): | |
61 for i in ['zip', 'gz', 'bz2']: | |
62 if ui.configbool("web", "allow" + i, False): | |
63 yield {"type" : i, "node": nodeid, "url": url} | |
64 | |
65 def entries(sortcolumn="", descending=False, **map): | |
66 rows = [] | |
67 parity = 0 | |
68 for name, path in self.repos: | |
69 u = ui.ui() | |
70 try: | |
71 u.readconfig(os.path.join(path, '.hg', 'hgrc')) | |
72 except IOError: | |
73 pass | |
74 get = u.config | |
75 | |
76 url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name]) | |
77 .replace("//", "/")) | |
78 | |
79 # update time with local timezone | |
80 try: | |
81 d = (get_mtime(path), util.makedate()[1]) | |
82 except OSError: | |
83 continue | |
84 | |
85 contact = (get("ui", "username") or # preferred | |
86 get("web", "contact") or # deprecated | |
87 get("web", "author", "")) # also | |
88 description = get("web", "description", "") | |
89 name = get("web", "name", name) | |
90 row = dict(contact=contact or "unknown", | |
91 contact_sort=contact.upper() or "unknown", | |
92 name=name, | |
93 name_sort=name, | |
94 url=url, | |
95 description=description or "unknown", | |
96 description_sort=description.upper() or "unknown", | |
97 lastchange=d, | |
98 lastchange_sort=d[1]-d[0], | |
99 archives=archivelist(u, "tip", url)) | |
100 if (not sortcolumn | |
101 or (sortcolumn, descending) == self.repos_sorted): | |
102 # fast path for unsorted output | |
103 row['parity'] = parity | |
104 parity = 1 - parity | |
105 yield row | |
106 else: | |
107 rows.append((row["%s_sort" % sortcolumn], row)) | |
108 if rows: | |
109 rows.sort() | |
110 if descending: | |
111 rows.reverse() | |
112 for key, row in rows: | |
113 row['parity'] = parity | |
114 parity = 1 - parity | |
115 yield row | |
116 | |
117 virtual = req.env.get("PATH_INFO", "").strip('/') | |
118 if virtual: | |
119 real = dict(self.repos).get(virtual) | |
120 if real: | |
121 try: | |
122 hgweb(real).run(req) | |
123 except IOError, inst: | |
124 req.write(tmpl("error", error=inst.strerror)) | |
125 except hg.RepoError, inst: | |
126 req.write(tmpl("error", error=str(inst))) | |
127 else: | |
128 req.write(tmpl("notfound", repo=virtual)) | |
129 else: | |
130 if req.form.has_key('static'): | |
131 static = os.path.join(templater.templatepath(), "static") | |
132 fname = req.form['static'][0] | |
133 req.write(staticfile(static, fname) | |
134 or tmpl("error", error="%r not found" % fname)) | |
135 else: | |
136 sortable = ["name", "description", "contact", "lastchange"] | |
137 sortcolumn, descending = self.repos_sorted | |
138 if req.form.has_key('sort'): | |
139 sortcolumn = req.form['sort'][0] | |
140 descending = sortcolumn.startswith('-') | |
141 if descending: | |
142 sortcolumn = sortcolumn[1:] | |
143 if sortcolumn not in sortable: | |
144 sortcolumn = "" | |
145 | |
146 sort = [("sort_%s" % column, | |
147 "%s%s" % ((not descending and column == sortcolumn) | |
148 and "-" or "", column)) | |
149 for column in sortable] | |
150 req.write(tmpl("index", entries=entries, | |
151 sortcolumn=sortcolumn, descending=descending, | |
152 **dict(sort))) |