##// END OF EJS Templates
Keep session variables when linking from hgwebdir's index to repositories.
Thomas Arendsen Hein -
r3365:cf680c9a default
parent child Browse files
Show More
@@ -1,192 +1,205
1 1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 2 #
3 3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 5 #
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 9 import os
10 10 from mercurial.demandload import demandload
11 11 demandload(globals(), "ConfigParser mimetools cStringIO")
12 12 demandload(globals(), "mercurial:ui,hg,util,templater")
13 13 demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
14 14 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
15 15 from mercurial.i18n import gettext as _
16 16
17 17 # This is a stopgap
18 18 class hgwebdir(object):
19 19 def __init__(self, config):
20 20 def cleannames(items):
21 21 return [(name.strip(os.sep), path) for name, path in items]
22 22
23 23 self.motd = ""
24 24 self.style = ""
25 25 self.repos_sorted = ('name', False)
26 26 if isinstance(config, (list, tuple)):
27 27 self.repos = cleannames(config)
28 28 self.repos_sorted = ('', False)
29 29 elif isinstance(config, dict):
30 30 self.repos = cleannames(config.items())
31 31 self.repos.sort()
32 32 else:
33 33 cp = ConfigParser.SafeConfigParser()
34 34 cp.read(config)
35 35 self.repos = []
36 36 if cp.has_section('web'):
37 37 if cp.has_option('web', 'motd'):
38 38 self.motd = cp.get('web', 'motd')
39 39 if cp.has_option('web', 'style'):
40 40 self.style = cp.get('web', 'style')
41 41 if cp.has_section('paths'):
42 42 self.repos.extend(cleannames(cp.items('paths')))
43 43 if cp.has_section('collections'):
44 44 for prefix, root in cp.items('collections'):
45 45 for path in util.walkrepos(root):
46 46 repo = os.path.normpath(path)
47 47 name = repo
48 48 if name.startswith(prefix):
49 49 name = name[len(prefix):]
50 50 self.repos.append((name.lstrip(os.sep), repo))
51 51 self.repos.sort()
52 52
53 53 def run(self):
54 54 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
55 55 raise RuntimeError("This function is only intended to be called while running as a CGI script.")
56 56 import mercurial.hgweb.wsgicgi as wsgicgi
57 57 from request import wsgiapplication
58 58 def make_web_app():
59 59 return self
60 60 wsgicgi.launch(wsgiapplication(make_web_app))
61 61
62 62 def run_wsgi(self, req):
63 63 def header(**map):
64 64 header_file = cStringIO.StringIO(''.join(tmpl("header", **map)))
65 65 msg = mimetools.Message(header_file, 0)
66 66 req.header(msg.items())
67 67 yield header_file.read()
68 68
69 69 def footer(**map):
70 70 yield tmpl("footer", motd=self.motd, **map)
71 71
72 72 url = req.env['REQUEST_URI'].split('?')[0]
73 73 if not url.endswith('/'):
74 74 url += '/'
75 75
76 76 style = self.style
77 77 if req.form.has_key('style'):
78 78 style = req.form['style'][0]
79 79 mapfile = style_map(templater.templatepath(), style)
80 80 tmpl = templater.templater(mapfile, templater.common_filters,
81 81 defaults={"header": header,
82 82 "footer": footer,
83 83 "url": url})
84 84
85 85 def archivelist(ui, nodeid, url):
86 86 allowed = ui.configlist("web", "allow_archive")
87 87 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
88 88 if i[0] in allowed or ui.configbool("web", "allow" + i[0]):
89 89 yield {"type" : i[0], "extension": i[1],
90 90 "node": nodeid, "url": url}
91 91
92 92 def entries(sortcolumn="", descending=False, **map):
93 def sessionvars(**map):
94 fields = []
95 if req.form.has_key('style'):
96 style = req.form['style'][0]
97 if style != get('web', 'style', ''):
98 fields.append(('style', style))
99
100 separator = url[-1] == '?' and ';' or '?'
101 for name, value in fields:
102 yield dict(name=name, value=value, separator=separator)
103 separator = ';'
104
93 105 rows = []
94 106 parity = 0
95 107 for name, path in self.repos:
96 108 u = ui.ui()
97 109 try:
98 110 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
99 111 except IOError:
100 112 pass
101 113 get = u.config
102 114
103 115 url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
104 116 .replace("//", "/")) + '/'
105 117
106 118 # update time with local timezone
107 119 try:
108 120 d = (get_mtime(path), util.makedate()[1])
109 121 except OSError:
110 122 continue
111 123
112 124 contact = (get("ui", "username") or # preferred
113 125 get("web", "contact") or # deprecated
114 126 get("web", "author", "")) # also
115 127 description = get("web", "description", "")
116 128 name = get("web", "name", name)
117 129 row = dict(contact=contact or "unknown",
118 130 contact_sort=contact.upper() or "unknown",
119 131 name=name,
120 132 name_sort=name,
121 133 url=url,
122 134 description=description or "unknown",
123 135 description_sort=description.upper() or "unknown",
124 136 lastchange=d,
125 137 lastchange_sort=d[1]-d[0],
138 sessionvars=sessionvars,
126 139 archives=archivelist(u, "tip", url))
127 140 if (not sortcolumn
128 141 or (sortcolumn, descending) == self.repos_sorted):
129 142 # fast path for unsorted output
130 143 row['parity'] = parity
131 144 parity = 1 - parity
132 145 yield row
133 146 else:
134 147 rows.append((row["%s_sort" % sortcolumn], row))
135 148 if rows:
136 149 rows.sort()
137 150 if descending:
138 151 rows.reverse()
139 152 for key, row in rows:
140 153 row['parity'] = parity
141 154 parity = 1 - parity
142 155 yield row
143 156
144 157 virtual = req.env.get("PATH_INFO", "").strip('/')
145 158 if virtual.startswith('static/'):
146 159 static = os.path.join(templater.templatepath(), 'static')
147 160 fname = virtual[7:]
148 161 req.write(staticfile(static, fname, req) or
149 162 tmpl('error', error='%r not found' % fname))
150 163 elif virtual:
151 164 while virtual:
152 165 real = dict(self.repos).get(virtual)
153 166 if real:
154 167 break
155 168 up = virtual.rfind('/')
156 169 if up < 0:
157 170 break
158 171 virtual = virtual[:up]
159 172 if real:
160 173 req.env['REPO_NAME'] = virtual
161 174 try:
162 175 hgweb(real).run_wsgi(req)
163 176 except IOError, inst:
164 177 req.write(tmpl("error", error=inst.strerror))
165 178 except hg.RepoError, inst:
166 179 req.write(tmpl("error", error=str(inst)))
167 180 else:
168 181 req.write(tmpl("notfound", repo=virtual))
169 182 else:
170 183 if req.form.has_key('static'):
171 184 static = os.path.join(templater.templatepath(), "static")
172 185 fname = req.form['static'][0]
173 186 req.write(staticfile(static, fname, req)
174 187 or tmpl("error", error="%r not found" % fname))
175 188 else:
176 189 sortable = ["name", "description", "contact", "lastchange"]
177 190 sortcolumn, descending = self.repos_sorted
178 191 if req.form.has_key('sort'):
179 192 sortcolumn = req.form['sort'][0]
180 193 descending = sortcolumn.startswith('-')
181 194 if descending:
182 195 sortcolumn = sortcolumn[1:]
183 196 if sortcolumn not in sortable:
184 197 sortcolumn = ""
185 198
186 199 sort = [("sort_%s" % column,
187 200 "%s%s" % ((not descending and column == sortcolumn)
188 201 and "-" or "", column))
189 202 for column in sortable]
190 203 req.write(tmpl("index", entries=entries,
191 204 sortcolumn=sortcolumn, descending=descending,
192 205 **dict(sort)))
@@ -1,55 +1,55
1 1 default = 'summary'
2 2 header = header.tmpl
3 3 footer = footer.tmpl
4 4 search = search.tmpl
5 5 changelog = changelog.tmpl
6 6 summary = summary.tmpl
7 7 error = error.tmpl
8 8 naventry = '<a href="#url#log/#rev#{sessionvars%urlparameter}">#label|escape#</a> '
9 9 navshortentry = '<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">#label|escape#</a> '
10 10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
11 11 filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a></td></tr>'
12 12 fileellipses = '...'
13 13 changelogentry = changelogentry.tmpl
14 14 searchentry = changelogentry.tmpl
15 15 changeset = changeset.tmpl
16 16 manifest = manifest.tmpl
17 17 manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#/</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a></td></tr>'
18 18 manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a></td></tr>'
19 19 filerevision = filerevision.tmpl
20 20 fileannotate = fileannotate.tmpl
21 21 filediff = filediff.tmpl
22 22 filelog = filelog.tmpl
23 23 fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>'
24 24 annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
25 25 difflineplus = '<div style="color:#008800;">#line|escape#</div>'
26 26 difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
27 27 difflineat = '<div style="color:#990099;">#line|escape#</div>'
28 28 diffline = '<div>#line|escape#</div>'
29 29 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
30 30 changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
31 31 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
32 32 filerename = '<tr><td class="metatag">parent:</td><td><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#@#node|short#</a></td></tr>'
33 33 filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">base</a>'
34 34 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
35 35 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
36 36 changesetchild = '<tr><td>child</td><td style="font-family:monospace"><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
37 37 filerevchild = '<tr><td class="metatag">child:</td><td><a href="{url}file/{node|short}#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
38 38 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
39 39 tags = tags.tmpl
40 40 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/#node|short#{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
41 41 diffblock = '<pre>#lines#</pre>'
42 42 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
43 43 changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>'
44 44 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
45 45 filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
46 46 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
47 47 filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
48 48 shortlog = shortlog.tmpl
49 49 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
50 50 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <!-- FIXME: <a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | --> <a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
51 51 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
52 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
52 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
53 53 index = index.tmpl
54 54 urlparameter = '#separator##name#=#value|urlescape#'
55 55 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
@@ -1,55 +1,55
1 1 default = 'changelog'
2 2 header = header.tmpl
3 3 footer = footer.tmpl
4 4 search = search.tmpl
5 5 changelog = changelog.tmpl
6 6 shortlog = shortlog.tmpl
7 7 shortlogentry = shortlogentry.tmpl
8 8 naventry = '<a href="#url#log/#rev#{sessionvars%urlparameter}">#label|escape#</a> '
9 9 navshortentry = '<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">#label|escape#</a> '
10 10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
11 11 filenodelink = '<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
12 12 fileellipses = '...'
13 13 changelogentry = changelogentry.tmpl
14 14 searchentry = changelogentry.tmpl
15 15 changeset = changeset.tmpl
16 16 manifest = manifest.tmpl
17 17 manifestdirentry = '<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td>&nbsp;<td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#/</a>'
18 18 manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td align=right><tt>#size#</tt>&nbsp;<td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a>'
19 19 filerevision = filerevision.tmpl
20 20 fileannotate = fileannotate.tmpl
21 21 filediff = filediff.tmpl
22 22 filelog = filelog.tmpl
23 23 fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
24 24 filelogentry = filelogentry.tmpl
25 25 annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
26 26 difflineplus = '<span class="plusline">#line|escape#</span>'
27 27 difflineminus = '<span class="minusline">#line|escape#</span>'
28 28 difflineat = '<span class="atline">#line|escape#</span>'
29 29 diffline = '#line|escape#'
30 30 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
31 31 changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
32 32 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
33 33 filerename = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#@#node|short#</a></td></tr>'
34 34 filelogrename = '<tr><th>base:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#@#node|short#</a></td></tr>'
35 35 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
36 36 changesetchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
37 37 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
38 38 filerevchild = '<tr><td class="metatag">child:</td><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
39 39 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
40 40 tags = tags.tmpl
41 41 tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="#url#rev/#node|short#{sessionvars%urlparameter}">#tag|escape#</a></li>'
42 42 diffblock = '<pre class="parity#parity#">#lines#</pre>'
43 43 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
44 44 changesettag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
45 45 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
46 46 filelogparent = '<tr><th>parent #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
47 47 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
48 48 filelogchild = '<tr><th>child #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
49 indexentry = '<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
49 indexentry = '<tr class="parity#parity#"><td><a href="#url#{sessionvars%urlparameter}">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
50 50 index = index.tmpl
51 51 archiveentry = '<a href="#url#archive/#node|short##extension|urlescape#">#type|escape#</a> '
52 52 notfound = notfound.tmpl
53 53 error = error.tmpl
54 54 urlparameter = '#separator##name#=#value|urlescape#'
55 55 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
General Comments 0
You need to be logged in to leave comments. Login now