##// END OF EJS Templates
further simplify stringify
further simplify stringify

File last commit:

r3557:f7dee427 default
r3647:734e337c default
Show More
hgwebdir_mod.py
211 lines | 8.8 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# 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
Alexis S. L. Carvalho
Use a case-sensitive version of SafeConfigParser everywhere...
r3425 demandload(globals(), "mimetools cStringIO")
Eric Hopper
Final stage of the hgweb split up....
r2356 demandload(globals(), "mercurial:ui,hg,util,templater")
TK Soh
hgweb: fix tracebacks on both index and repo pages
r2360 demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
Thomas Arendsen Hein
hgweb: Search templates in templatepath/style/map, too, using a common function....
r3276 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
Eric Hopper
Final stage of the hgweb split up....
r2356 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 = ""
Edouard Gomez
Add style support to hgwebdir
r3221 self.style = ""
Eric Hopper
Final stage of the hgweb split up....
r2356 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:
Alexis S. L. Carvalho
Use a case-sensitive version of SafeConfigParser everywhere...
r3425 cp = util.configparser()
Eric Hopper
Final stage of the hgweb split up....
r2356 cp.read(config)
self.repos = []
Edouard Gomez
Add style support to hgwebdir
r3221 if cp.has_section('web'):
if cp.has_option('web', 'motd'):
self.motd = cp.get('web', 'motd')
if cp.has_option('web', 'style'):
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223 self.style = cp.get('web', 'style')
Eric Hopper
Final stage of the hgweb split up....
r2356 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()
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 def run(self):
Eric Hopper
Cleanup hgweb and hgwebdir's run method a bit.
r2538 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 raise RuntimeError("This function is only intended to be called while running as a CGI script.")
import mercurial.hgweb.wsgicgi as wsgicgi
from request import wsgiapplication
def make_web_app():
Eric Hopper
Cleanup hgweb and hgwebdir's run method a bit.
r2538 return self
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 wsgicgi.launch(wsgiapplication(make_web_app))
def run_wsgi(self, req):
Eric Hopper
Final stage of the hgweb split up....
r2356 def header(**map):
Eric Hopper
Really fix http headers for web UI and issue 254....
r2514 header_file = cStringIO.StringIO(''.join(tmpl("header", **map)))
msg = mimetools.Message(header_file, 0)
req.header(msg.items())
yield header_file.read()
Eric Hopper
Final stage of the hgweb split up....
r2356
def footer(**map):
Thomas Arendsen Hein
Fix "templater object got multiple values for keyword argument 'motd'"...
r3479 yield tmpl("footer", **map)
Eric Hopper
Final stage of the hgweb split up....
r2356
Alexis S. L. Carvalho
hgweb: make #motd# available for all templates
r3488 def motd(**map):
yield self.motd
Brendan Cully
Add base URL to hgwebdir templater (fixes index page when the URL does not have a trailing /)
r3328 url = req.env['REQUEST_URI'].split('?')[0]
if not url.endswith('/'):
url += '/'
Edouard Gomez
Add style support to hgwebdir
r3221 style = self.style
if req.form.has_key('style'):
style = req.form['style'][0]
Thomas Arendsen Hein
hgweb: Search templates in templatepath/style/map, too, using a common function....
r3276 mapfile = style_map(templater.templatepath(), style)
tmpl = templater.templater(mapfile, templater.common_filters,
Eric Hopper
Final stage of the hgweb split up....
r2356 defaults={"header": header,
Brendan Cully
Add base URL to hgwebdir templater (fixes index page when the URL does not have a trailing /)
r3328 "footer": footer,
Alexis S. L. Carvalho
hgweb: make #motd# available for all templates
r3488 "motd": motd,
Brendan Cully
Add base URL to hgwebdir templater (fixes index page when the URL does not have a trailing /)
r3328 "url": url})
Eric Hopper
Final stage of the hgweb split up....
r2356
def archivelist(ui, nodeid, url):
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 allowed = ui.configlist("web", "allow_archive", untrusted=True)
Brendan Cully
Teach hgwebdir about new interface
r3262 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
untrusted=True):
Brendan Cully
Teach hgwebdir about new interface
r3262 yield {"type" : i[0], "extension": i[1],
"node": nodeid, "url": url}
Eric Hopper
Final stage of the hgweb split up....
r2356
def entries(sortcolumn="", descending=False, **map):
Thomas Arendsen Hein
Keep session variables when linking from hgwebdir's index to repositories.
r3365 def sessionvars(**map):
fields = []
if req.form.has_key('style'):
style = req.form['style'][0]
if style != get('web', 'style', ''):
fields.append(('style', style))
separator = url[-1] == '?' and ';' or '?'
for name, value in fields:
yield dict(name=name, value=value, separator=separator)
separator = ';'
Eric Hopper
Final stage of the hgweb split up....
r2356 rows = []
parity = 0
for name, path in self.repos:
Thomas Arendsen Hein
Turn of "Not trusting file" logging when running hgweb and hgwebdir...
r3557 u = ui.ui(report_untrusted=False)
Eric Hopper
Final stage of the hgweb split up....
r2356 try:
u.readconfig(os.path.join(path, '.hg', 'hgrc'))
except IOError:
pass
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 def get(section, name, default=None):
return u.config(section, name, default, untrusted=True)
Eric Hopper
Final stage of the hgweb split up....
r2356
url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
Brendan Cully
Teach hgwebdir about new interface
r3262 .replace("//", "/")) + '/'
Eric Hopper
Final stage of the hgweb split up....
r2356
# 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],
Thomas Arendsen Hein
Keep session variables when linking from hgwebdir's index to repositories.
r3365 sessionvars=sessionvars,
Eric Hopper
Final stage of the hgweb split up....
r2356 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('/')
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 if virtual.startswith('static/'):
static = os.path.join(templater.templatepath(), 'static')
fname = virtual[7:]
req.write(staticfile(static, fname, req) or
tmpl('error', error='%r not found' % fname))
elif virtual:
Brendan Cully
Teach hgwebdir about new interface
r3262 while virtual:
real = dict(self.repos).get(virtual)
if real:
break
up = virtual.rfind('/')
if up < 0:
break
virtual = virtual[:up]
Eric Hopper
Final stage of the hgweb split up....
r2356 if real:
Brendan Cully
Teach hgwebdir about new interface
r3262 req.env['REPO_NAME'] = virtual
Eric Hopper
Final stage of the hgweb split up....
r2356 try:
Eric Hopper
Fix hgwebdir to run hgweb using run_wsgi.
r2537 hgweb(real).run_wsgi(req)
Eric Hopper
Final stage of the hgweb split up....
r2356 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]
Eric Hopper
Really fix http headers for web UI and issue 254....
r2514 req.write(staticfile(static, fname, req)
Eric Hopper
Final stage of the hgweb split up....
r2356 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)))