##// END OF EJS Templates
Prevent type exception on concatenation if diffstat returns None....
Prevent type exception on concatenation if diffstat returns None. This will most often occur if diffstat is not installed in the target platform, though may also happen in other cases where diffstat fails to execute. Signed-off-by: Sean Dague <sean@dague.net>

File last commit:

r4051:02205626 default
r4077:1305ba7d default
Show More
hgwebdir_mod.py
212 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):
Thomas Arendsen Hein
Set charset encoding for hgwebdir, too....
r3882 header_file = cStringIO.StringIO(
''.join(tmpl("header", encoding=util._encoding, **map)))
Eric Hopper
Really fix http headers for web UI and issue 254....
r2514 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)))