Sun Nov 13 11:23:24 UTC 2011 pinterface <pix@kepibu.org>
* Add support for calling an external program to generate README markup
{
hunk ./config.py.sample 87
+ # If you'd like a wider range of README file types than darcsweb
+ # provides, set readme_converter to a program which takes a single
+ # argument--the name of the readme file--and outputs HTML.
+ #readme_converter = 'ruby -rubygems /var/lib/gems/1.8/gems/github-markup-0.5.3/bin/github-markup'
hunk ./darcsweb.cgi 1094
+def get_readme():
+ import glob
+ readmes = glob.glob("README*")
+ if len(readmes) == 0: return False, False
+ import re
+ for p in readmes:
+ file = os.path.basename(p)
+ if re.search('\.(md|markdown)$', p):
+ import codecs
+ import markdown
+ f = codecs.open(p, encoding=config.repoencoding[0])
+ str = f.read()
+ html = markdown.markdown(str, ['extra', 'codehilite(css_class=page_body)'])
+ return file, fixu8(html)
+ elif re.search('README$', p):
+ f = open(p)
+ str = f.read()
+ return file, '<pre>%s</pre>' % fixu8(escape(str))
+ # We can't handle this ourselves, try shelling out
+ if not config.readme_converter: return False, False
+ cmd = '%s "%s"' % (config.readme_converter, readmes[0])
+ inf, outf = os.popen2(cmd, 't')
+ return os.path.basename(readmes[0]), fixu8(outf.read())
hunk ./darcsweb.cgi 1248
-# FIXME: shell out to github-markup to avoid duplicating that effort here?
hunk ./darcsweb.cgi 1249
- real = False
- for p in ["README", "README.md", "README.markdown"]:
- p = realpath(p)
- if p and os.path.isfile(p):
- real = p
- break
- if not real: return
-
- print '<div class="title">%s</div>' % os.path.basename(real)
-
- import re
- if re.search('\.(md|markdown)$', real):
- import codecs
- import markdown
- f = codecs.open(real, encoding=config.repoencoding[0])
- str = f.read()
- html = markdown.markdown(str, ['extra', 'codehilite(css_class=page_body)'])
- print '<section>%s</section>' % fixu8(html)
- else:
- f = open(real)
- str = f.read()
- print '<section><pre>%s</pre></section>' % fixu8(escape(str))
+ head, body = get_readme()
+ if not head: return False
+ print '<div class="title">%s</div>' % head
+ print '<section>%s</section' % body
hunk ./darcsweb.cgi 2566
+ if "readme_converter" in dir(base):
+ config.readme_converter = base.readme_converter
+ else:
+ config.readme_converter = False
+
}
Sun Nov 13 11:07:41 UTC 2011 pinterface <pix@kepibu.org>
* minidom chokes on form feed character
hunk ./darcsweb.cgi 1002
- s += fixu8(i)
+ s += fixu8(i).replace('[_^L_]', '^L')
Sat Nov 5 10:18:50 UTC 2011 pinterface <pix@kepibu.org>
* Show README in summary view, if it exists
Blatantly stealing the idea from Github, but not as fully implemented.
{
hunk ./darcsweb.cgi 1225
+# FIXME: shell out to github-markup to avoid duplicating that effort here?
+def print_readme():
+ real = False
+ for p in ["README", "README.md", "README.markdown"]:
+ p = realpath(p)
+ if p and os.path.isfile(p):
+ real = p
+ break
+ if not real: return
+
+ print '<div class="title">%s</div>' % os.path.basename(real)
+
+ import re
+ if re.search('\.(md|markdown)$', real):
+ import codecs
+ import markdown
+ f = codecs.open(real, encoding=config.repoencoding[0])
+ str = f.read()
+ html = markdown.markdown(str, ['extra', 'codehilite(css_class=page_body)'])
+ print '<section>%s</section>' % fixu8(html)
+ else:
+ f = open(real)
+ str = f.read()
+ print '<section><pre>%s</pre></section>' % fixu8(escape(str))
+
+
hunk ./darcsweb.cgi 1523
+ print_readme()
}
Tue Nov 1 10:19:57 UTC 2011 pinterface <pix@kepibu.org>
* Add Owner and Last Change columns to repo listing
This is a little ugly due to the global config object. Boo.
{
hunk ./darcsweb.cgi 2247
+<th>Owner</th>
+<th>Last Change</th>
hunk ./darcsweb.cgi 2273
+ try: orig_repodir = config.repodir
+ except: orig_repodir = None
+ config.repodir = c.repodir
hunk ./darcsweb.cgi 2279
+<td>%(owner)s</td>
+<td>%(lastchange)s</td>
hunk ./darcsweb.cgi 2291
- 'desc': shorten_str(desc, 60)
+ 'desc': shorten_str(desc, 60),
+ 'owner': escape(repo_get_owner() or ''),
+ 'lastchange': how_old(os.stat(c.repodir + '/_darcs/patches').st_mtime),
hunk ./darcsweb.cgi 2295
+ config.repodir = orig_repodir
}
Tue Nov 1 09:54:21 UTC 2011 pinterface <pix@kepibu.org>
* Skip comments and blank lines in the author file
{
hunk ./darcsweb.cgi 634
- author = fd.readlines()[0].strip()
+ for line in fd:
+ line = line.strip()
+ if line != "" and line[0] != "#":
+ return line.strip()
hunk ./darcsweb.cgi 639
- author = None
- return author
+ return None
}
Tue Nov 1 08:30:12 UTC 2011 pinterface <pix@kepibu.org>
* Add ability to specify a mailing list URL for repositories
{
hunk ./darcsweb.cgi 1488
+ if config.repolisturl:
+ print ' <tr><td>mailing list url</td>'
+ print ' <td><a href="%(url)s">%(url)s</a></td></tr>' % \
+ { 'url': config.repolisturl }
hunk ./darcsweb.cgi 2378
+ if 'autolisturl' in dir(c) and c.autolisturl:
+ dpath = fulldir + \
+ '/_darcs/third_party/darcsweb/listurl'
+ if os.access(dpath, os.R_OK):
+ listurl = open(dpath).readline().rstrip("\n")
+ elif 'repolisturl' in dir(c):
+ listurl = c.repolisturl % rep_dict
+ else:
+ listurl = None
+ elif 'repolisturl' in dir(c):
+ listurl = c.repolisturl % rep_dict
+ else:
+ listurl = None
+
hunk ./darcsweb.cgi 2400
+ repolisturl = listurl
hunk ./darcsweb.cgi 2463
+ config.repolisturl = None
+ if 'repolisturl' in dir(c):
+ config.repolisturl = c.repolisturl
+
}
Tue Nov 1 08:12:39 UTC 2011 pinterface <pix@kepibu.org>
* Don't require myurl be specified when cachedir is in use
hunk ./darcsweb.cgi 2417
- if 'myurl' not in dir(base) and 'cachedir' not in dir(base):
+ if 'myurl' not in dir(base):
Wed Nov 24 15:52:33 UTC 2010 Alberto Bertogli <albertito@blitiri.com.ar>
tagged 1.2-rc1
{
}
Fri Oct 15 12:55:46 UTC 2010 Dave Love <fx@gnu.org>
* Use diff --quiet.
Prevents `Copying pristine' messages in output with darcs pre-2.5.
{
hunk ./darcsweb.cgi 685
- params = 'diff -u --match "hash %s"' % self.hash
+ params = 'diff --quiet -u --match "hash %s"' % self.hash
hunk ./darcsweb.cgi 931
- return run_darcs('diff -u --match "hash %s"' % hash)
+ return run_darcs('diff --quiet -u --match "hash %s"' % hash)
hunk ./darcsweb.cgi 934
- return run_darcs('diff -u --match "hash %s" "%s"' % (hash, fname))
+ return run_darcs('diff --quiet -u --match "hash %s" "%s"' % (hash, fname))
hunk ./darcsweb.cgi 937
- return run_darcs('diff -u --from-match "hash %s" "%s"' % (hash, fname))
+ return run_darcs('diff --quiet -u --from-match "hash %s" "%s"' % (hash, fname))
hunk ./darcsweb.cgi 940
- return run_darcs('diff -u --from-match "hash %s"' % hash)
+ return run_darcs('diff --quiet -u --from-match "hash %s"' % hash)
}
Fri Jun 25 00:32:55 UTC 2010 Alberto Bertogli <albertito@blitiri.com.ar>
* Do not use string exceptions
String exceptions are deprecated and will soon no longer be supported at all.
Most of the instances of string exceptions in our code were not meant to be
catched, but just to get meaningful backtraces.
This patch replaces them with appropriate, usually generic, exceptions that
serve the same purpose.
{
hunk ./darcsweb.cgi 82
- raise 'FilterFile FAILED'
+ raise Exception, 'FilterFile FAILED'
hunk ./darcsweb.cgi 119
- raise 'DecodingError', config.repoencoding
+ raise UnicodeDecodeError, config.repoencoding
hunk ./darcsweb.cgi 2407
- raise "RepoNotFound", name
+ raise Exception, "Repo not found: " + repr(name)
}
Sun Mar 28 18:21:44 UTC 2010 Simon Michael <simon@joyful.com>
* log view: display the patch name just once, tighten up whitespace
hunk ./darcsweb.cgi 1253
- %(desc)s<br/>
- <br/>
Sun Mar 28 16:40:18 UTC 2010 Simon Michael <simon@joyful.com>
* allow custom "last" value in url, eg to view all patches on one page
{
hunk ./darcsweb.cgi 26
+PATCHES_PER_PAGE = 50
+
hunk ./darcsweb.cgi 1149
-def print_shortlog(last = 50, topi = 0, fname = None):
+def print_shortlog(last = PATCHES_PER_PAGE, topi = 0, fname = None):
hunk ./darcsweb.cgi 1223
-def print_log(last = 50, topi = 0):
+def print_log(last = PATCHES_PER_PAGE, topi = 0):
hunk ./darcsweb.cgi 1988
-def do_shortlog(topi):
+def do_shortlog(topi, last=PATCHES_PER_PAGE):
hunk ./darcsweb.cgi 1991
- print_shortlog(topi = topi)
+ print_shortlog(topi = topi, last = last)
hunk ./darcsweb.cgi 1994
-def do_filehistory(topi, f):
+def do_filehistory(topi, f, last=PATCHES_PER_PAGE):
hunk ./darcsweb.cgi 1997
- print_shortlog(topi = topi, fname = fname)
+ print_shortlog(topi = topi, fname = fname, last = last)
hunk ./darcsweb.cgi 2000
-def do_log(topi):
+def do_log(topi, last=PATCHES_PER_PAGE):
hunk ./darcsweb.cgi 2003
- print_log(topi = topi)
+ print_log(topi = topi, last = last)
hunk ./darcsweb.cgi 2537
- params = ['r', 'a', 'f', 'h', 'topi']
+ params = ['r', 'a', 'f', 'h', 'topi', 'last']
hunk ./darcsweb.cgi 2642
- do_shortlog(topi)
+ if form.has_key("last"):
+ last = int(filter_num(form["last"].value))
+ else:
+ last = PATCHES_PER_PAGE
+ do_shortlog(topi=topi,last=last)
hunk ./darcsweb.cgi 2654
- do_filehistory(topi, fname)
+ if form.has_key("last"):
+ last = int(filter_num(form["last"].value))
+ else:
+ last = PATCHES_PER_PAGE
+ do_filehistory(topi, fname, last=last)
hunk ./darcsweb.cgi 2665
- do_log(topi)
+ if form.has_key("last"):
+ last = int(filter_num(form["last"].value))
+ else:
+ last = PATCHES_PER_PAGE
+ do_log(topi, last=last)
}
Sun Mar 28 16:37:55 UTC 2010 Simon Michael <simon@joyful.com>
* hide darcs' Ignore-this: metadata in log view
{
hunk ./darcsweb.cgi 193
+def strip_ignore_this(s):
+ """Strip out darcs' Ignore-this: metadata if present."""
+ import re
+ return re.sub(r'^Ignore-this:[^\n]*\n?','',s)
hunk ./darcsweb.cgi 848
- self.db[self.current].comment = fixu8(self.cur_val)
+ self.db[self.current].comment = fixu8(strip_ignore_this(self.cur_val))
}
Sun Mar 28 18:57:50 UTC 2010 Simon Michael <simon@joyful.com>
* more robust timestamp parsing
With this, darcsweb can list the full darcs repo log.
{
hunk ./darcsweb.cgi 305
- # "Wed May 21 19:39:10 CEST 2003"
- # we can't parse the "CEST" part reliably, so we leave it out
+ # "Wed May 21 19:39:10 CEST 2003" or even:
+ # "Sun Sep 21 07:23:57 Pacific Daylight Time 2003"
+ # we can't parse the time zone part reliably, so we ignore it
hunk ./darcsweb.cgi 310
- ns = ' '.join(parts[0:4]) + ' ' + parts[5]
+ ns = ' '.join(parts[0:4]) + ' ' + parts[-1]
}
Thu Mar 26 19:58:42 UTC 2009 gaetan.lehmann@jouy.inra.fr
* add the year in the date field if the patch wasn't made in the current year
hunk ./darcsweb.cgi 131
- s = time.strftime("%d %b %H:%M", t)
+ currentYear = time.localtime()[0]
+ if t[0] == currentYear:
+ s = time.strftime("%d %b %H:%M", t)
+ else:
+ s = time.strftime("%d %b %Y %H:%M", t)
Tue Oct 28 15:44:36 UTC 2008 Alberto Bertogli <albertito@blitiri.com.ar>
tagged 1.1
{
}
Tue Oct 28 15:43:41 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Update my email address
{
hunk ./README 3
-Alberto Bertogli (albertito@gmail.com)
-----------------------------------------
+Alberto Bertogli (albertito@blitiri.com.ar)
+---------------------------------------------
hunk ./darcsweb.cgi 5
-Alberto Bertogli (albertito@gmail.com)
+Alberto Bertogli (albertito@blitiri.com.ar)
hunk ./darcsweb.cgi 322
- Alberto Bertogli (albertito@gmail.com).
+ Alberto Bertogli (albertito@blitiri.com.ar).
hunk ./style.css 3
- * Alberto Bertogli (albertito@gmail.com)
+ * Alberto Bertogli (albertito@blitiri.com.ar)
}
Tue Aug 12 09:50:07 UTC 2008 Alexandre Rossi <alexandre.rossi@gmail.com>
* fix pygments disaligned linenos and code when using windows fonts (pygments>0.7 only)
{
hunk ./darcsweb.cgi 1327
- formatter = pygments.formatters.HtmlFormatter(linenos=True,
+
+ pygments_version = map(int, pygments.__version__.split('.'))
+ if pygments_version >= [0, 7]:
+ linenos_method = 'inline'
+ else:
+ linenos_method = True
+ formatter = pygments.formatters.HtmlFormatter(linenos=linenos_method,
hunk ./darcsweb.cgi 1335
+
}
Tue Oct 14 21:18:42 UTC 2008 Alberto Bertogli <albertito@gmail.com>
tagged 1.1-rc1
{
}
Tue Oct 14 21:18:29 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Update HTML version number
hunk ./darcsweb.cgi 321
-<!-- darcsweb 1.0
+<!-- darcsweb 1.1
Sun Oct 5 15:53:16 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Import pygments only when needed
Otherwise, we pay for the pygments import (which is noticeable) on every
darcsweb page view.
This follows the lazy module loading that is already being done for other
costly modules (i.e. 're').
{
hunk ./darcsweb.cgi 22
-try:
- import pygments
- import pygments.lexers
- import pygments.formatters
-except ImportError:
- pygments = False
-
hunk ./darcsweb.cgi 1273
+ try:
+ import pygments
+ except ImportError:
+ pygments = False
+
hunk ./darcsweb.cgi 1316
+ import pygments
+ import pygments.lexers
+ import pygments.formatters
+
}
Sun Oct 5 15:48:31 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Ignore broken multidir directories
When a multidir directory is not really a directory or a valid symlink to one,
we want to skip it instead of exploding.
This patch fixes that by doing a simple sanity check while processing the
configured multidirs.
Thanks to Ralph Giles <giles@ghostscript.com> for the report and the patch.
hunk ./darcsweb.cgi 2278
+ if not os.path.isdir(c.multidir):
+ continue
+
Thu Aug 7 05:31:41 UTC 2008 Alexandre Rossi <alexandre.rossi@gmail.com>
* optional source headblob syntax highlighting using python-pygments
{
hunk ./darcsweb.cgi 22
+try:
+ import pygments
+ import pygments.lexers
+ import pygments.formatters
+except ImportError:
+ pygments = False
+
hunk ./darcsweb.cgi 1272
- print '<div class="page_body">'
hunk ./darcsweb.cgi 1274
+<div class="page_body">
hunk ./darcsweb.cgi 1280
+ if not pygments:
+ print_blob_simple(fname)
+ return
+ else:
+ try:
+ print_blob_highlighted(fname)
+ except ValueError:
+ # pygments couldn't guess a lexer to highlight the code, try
+ # another method with sampling the file contents.
+ try:
+ print_blob_highlighted(fname, sample_code=True)
+ except ValueError:
+ # pygments really could not find any lexer for this file.
+ print_blob_simple(fname)
+
+def print_blob_simple(fname):
+ print '<div class="page_body">'
+
hunk ./darcsweb.cgi 1317
+def print_blob_highlighted(fname, sample_code=False):
+ code = open(realpath(fname), 'r').read()
+ if sample_code:
+ lexer = pygments.lexers.guess_lexer(code[:200],
+ encoding=config.repoencoding[0])
+ else:
+ lexer = pygments.lexers.guess_lexer_for_filename(fname, code[:200],
+ encoding=config.repoencoding[0])
+ formatter = pygments.formatters.HtmlFormatter(linenos=True,
+ cssclass='page_body')
+ print pygments.highlight(code, lexer, formatter)
+
hunk ./style.css 223
-a.linenr {
+a.linenr, .linenos {
hunk ./style.css 266
+/* Syntax highlighting related styles. This is highly dependent on what
+ * python-pygments generates.
+ * This was generated using the following commands in a python interpreter and
+ * slightly modified after.
+ * >>> import pygments
+ * >>> pygments.formatters.HtmlFormatter().get_style_defs('.page_body')
+ */
+.page_body table { margin: 0; padding: 0;}
+.page_body pre { margin : 0; padding: 0; }
+.page_body .c { color: #008800; font-style: italic } /* Comment */
+.page_body .err { border: 1px solid #FF0000 } /* Error */
+.page_body .k { color: #AA22FF; font-weight: bold } /* Keyword */
+.page_body .o { color: #666666 } /* Operator */
+.page_body .cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.page_body .cp { color: #008800 } /* Comment.Preproc */
+.page_body .c1 { color: #008800; font-style: italic } /* Comment.Single */
+.page_body .gd { color: #A00000 } /* Generic.Deleted */
+.page_body .ge { font-style: italic } /* Generic.Emph */
+.page_body .gr { color: #FF0000 } /* Generic.Error */
+.page_body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.page_body .gi { color: #00A000 } /* Generic.Inserted */
+.page_body .go { color: #808080 } /* Generic.Output */
+.page_body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.page_body .gs { font-weight: bold } /* Generic.Strong */
+.page_body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.page_body .gt { color: #0040D0 } /* Generic.Traceback */
+.page_body .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
+.page_body .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
+.page_body .kp { color: #AA22FF } /* Keyword.Pseudo */
+.page_body .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
+.page_body .kt { color: #AA22FF; font-weight: bold } /* Keyword.Type */
+.page_body .m { color: #666666 } /* Literal.Number */
+.page_body .s { color: #BB4444 } /* Literal.String */
+.page_body .na { color: #BB4444 } /* Name.Attribute */
+.page_body .nb { color: #AA22FF } /* Name.Builtin */
+.page_body .nc { color: #0000FF } /* Name.Class */
+.page_body .no { color: #880000 } /* Name.Constant */
+.page_body .nd { color: #AA22FF } /* Name.Decorator */
+.page_body .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.page_body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.page_body .nf { color: #00A000 } /* Name.Function */
+.page_body .nl { color: #A0A000 } /* Name.Label */
+.page_body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.page_body .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.page_body .nv { color: #B8860B } /* Name.Variable */
+.page_body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.page_body .mf { color: #666666 } /* Literal.Number.Float */
+.page_body .mh { color: #666666 } /* Literal.Number.Hex */
+.page_body .mi { color: #666666 } /* Literal.Number.Integer */
+.page_body .mo { color: #666666 } /* Literal.Number.Oct */
+.page_body .sb { color: #BB4444 } /* Literal.String.Backtick */
+.page_body .sc { color: #BB4444 } /* Literal.String.Char */
+.page_body .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
+.page_body .s2 { color: #BB4444 } /* Literal.String.Double */
+.page_body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.page_body .sh { color: #BB4444 } /* Literal.String.Heredoc */
+.page_body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.page_body .sx { color: #008000 } /* Literal.String.Other */
+.page_body .sr { color: #BB6688 } /* Literal.String.Regex */
+.page_body .s1 { color: #BB4444 } /* Literal.String.Single */
+.page_body .ss { color: #B8860B } /* Literal.String.Symbol */
+.page_body .bp { color: #AA22FF } /* Name.Builtin.Pseudo */
+.page_body .vc { color: #B8860B } /* Name.Variable.Class */
+.page_body .vg { color: #B8860B } /* Name.Variable.Global */
+.page_body .vi { color: #B8860B } /* Name.Variable.Instance */
+.page_body .il { color: #666666 } /* Literal.Number.Integer.Long */
+
}
Thu Aug 7 04:41:45 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Handle old date formats
Very old darcs commits use a different time format, that leaks out in some
operations like annotate. This patch makes darcsweb able to handle it.
Thanks to Simon Michael <simon@joyful.com> for the report and the help.
{
hunk ./darcsweb.cgi 295
+def parse_darcs_time(s):
+ "Try to convert a darcs' time string into a Python time tuple."
+ try:
+ return time.strptime(s, "%Y%m%d%H%M%S")
+ except ValueError:
+ # very old darcs commits use a different format, for example:
+ # "Wed May 21 19:39:10 CEST 2003"
+ # we can't parse the "CEST" part reliably, so we leave it out
+ fmt = "%a %b %d %H:%M:%S %Y"
+ parts = s.split()
+ ns = ' '.join(parts[0:4]) + ' ' + parts[5]
+ return time.strptime(ns, fmt)
+
+
+
hunk ./darcsweb.cgi 751
- td = time.strptime(attrs.get('date', None),
- "%Y%m%d%H%M%S")
+ td = parse_darcs_time(attrs.get('date', None))
hunk ./darcsweb.cgi 1011
- lastdate = lastpatch.getAttribute("date")
- lastdate = time.strptime(lastdate, "%Y%m%d%H%M%S")
+ lastdate = parse_darcs_time(lastpatch.getAttribute("date"))
hunk ./darcsweb.cgi 1033
- pdate = time.strptime(pdate, "%Y%m%d%H%M%S")
+ pdate = parse_darcs_time(pdate)
}
Sun Aug 3 15:04:07 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Fix typo in annotate output
{
hunk ./darcsweb.cgi 1255
-<i>This is a binary file and it's contents will not be displayed.</i>
+<i>This is a binary file and its contents will not be displayed.</i>
hunk ./darcsweb.cgi 1283
-<i>This is a binary file and it's contents will not be displayed.</i>
+<i>This is a binary file and its contents will not be displayed.</i>
}
Sun Aug 3 15:03:41 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Simplify annotate code
A very simple change, makes the code more straightforward.
{
hunk ./darcsweb.cgi 1053
+ if config.disable_annotate:
+ return None
+
hunk ./darcsweb.cgi 1065
- if not config.disable_annotate:
- out = run_darcs(cmd)
- else:
- return None
- return parse_annotate(out)
+
+ return parse_annotate(run_darcs(cmd))
}
Sun Aug 3 15:02:56 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Fix annotate so it works with darcs 2
darcs 2 doesn't like files beginning with / as parameters for annotate. Since
darcs 1 doesn't care, remove the '/' before running darcs.
hunk ./darcsweb.cgi 1056
+
+ if fname.startswith('/'):
+ # darcs 2 doesn't like files starting with /, and darcs 1
+ # doesn't really care
+ fname = fname[1:]
Sun Aug 3 15:00:34 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Use _darcs/patches instead of _darcs/inventory
In darcs 2, there is no _darcs/inventory, so use the patches directory to find
out the last modification time of the repository.
Thanks to Patrick Waugh (ptwaugh@gmail.com) for providing (and testing) this
fix.
{
hunk ./darcsweb.cgi 546
- inv = config.repodir + '/_darcs/inventory'
+ inv = config.repodir + '/_darcs/patches'
hunk ./darcsweb.cgi 1934
- inv = config.repodir + '/_darcs/inventory'
+ inv = config.repodir + '/_darcs/patches'
}
Tue Apr 8 00:11:05 UTC 2008 Alberto Bertogli <albertito@gmail.com>
tagged 1.0
{
}
Tue Apr 8 00:10:21 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Version 1.0
hunk ./darcsweb.cgi 306
-<!-- darcsweb 0.15
+<!-- darcsweb 1.0
Thu Mar 27 01:06:42 UTC 2008 Alberto Bertogli <albertito@gmail.com>
tagged 1.0-rc2
{
}
Thu Mar 27 01:02:58 UTC 2008 Alberto Bertogli <albertito@gmail.com>
* Add an option to change the display name of the repository
It can be used to avoid clashes in multidir entries.
Thanks to Dan Muller for the idea and alternative implementation.
{
hunk ./config.py.sample 147
-# "%(name)s" gets expanded to the it.
+# "%(name)s" gets expanded to the it. If displayname is set, "%(dname)s" gets
+# expanded to it; otherwise it's the same as "%(name)s".
hunk ./config.py.sample 164
+ # if you want to change the display name of the repositories (i.e. the
+ # name it will have on the listings, urls, etc.), you can set it here.
+ # You can use "%(name)s" expansion, see above.
+ #displayname = "local/%(name)s"
+
hunk ./darcsweb.cgi 2249
+ # set the display name at the beginning, so it can be
+ # used by the other replaces
+ if 'displayname' in dir(c):
+ dname = c.displayname % { 'name': name }
+ else:
+ dname = name
+
+ rep_dict = { 'name': name, 'dname': dname }
+
hunk ./darcsweb.cgi 2270
- desc = c.repodesc % { 'name': name }
+ desc = c.repodesc % rep_dict
hunk ./darcsweb.cgi 2272
- desc = c.repodesc % { 'name': name }
+ desc = c.repodesc % rep_dict
hunk ./darcsweb.cgi 2280
- url = c.repourl % { 'name': name }
+ url = c.repourl % rep_dict
hunk ./darcsweb.cgi 2282
- url = c.repourl % { 'name': name }
+ url = c.repourl % rep_dict
hunk ./darcsweb.cgi 2290
- projurl = c.repoprojurl % {'name': name}
+ projurl = c.repoprojurl % rep_dict
hunk ./darcsweb.cgi 2294
- projurl = c.repoprojurl % { 'name': name }
+ projurl = c.repoprojurl % rep_dict
hunk ./darcsweb.cgi 2300
- reponame = name
+ reponame = dname
hunk ./darcsweb.cgi 2310
- config.__setattr__(name, tmp_config)
+ # index by display name to avoid clashes
+ config.__setattr__(dname, tmp_config)
}
Mon Mar 24 17:31:17 UTC 2008 Miklos Vajna <vmiklos@frugalware.org>
* add support for the DARCSWEB_CONFPATH env var
- useful when hosting multiple darcsweb sites via vhost
hunk ./darcsweb.cgi 33
+
+# Similarly, when hosting multiple darcsweb instrances on the same
+# server, you can just 'SetEnv DARCSWEB_CONFPATH' in the httpd config,
+# and this will have a bigger priority than the system-wide
+# configuration file.
+if 'DARCSWEB_CONFPATH' in os.environ:
+ sys.path.insert(1, os.environ['DARCSWEB_CONFPATH'])
Sun Oct 14 15:48:26 UTC 2007 Alberto Bertogli <albertito@gmail.com>
tagged 1.0-rc1
{
}
Sun Oct 14 15:42:34 UTC 2007 Alberto Bertogli <albertito@gmail.com>
* Add /etc/darcsweb after '.' in sys.path.
Add it second place, so it goes after '.' but before the normal path. This
allows per-directory config files (desirable for multiple darcsweb
installations on the same machin), and avoids name clashing if there's a
config.py in the standard path.
This was reported by Philipp Kern <pkern@debian.org> in Debian bug 399751
(http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=399751).
hunk ./darcsweb.cgi 28
-# default configuration there.
-sys.path.append('/etc/darcsweb')
+# default configuration there. Add it second place, so it goes after '.' but
+# before the normal path. This allows per-directory config files (desirable
+# for multiple darcsweb installations on the same machin), and avoids name
+# clashing if there's a config.py in the standard path.
+sys.path.insert(1, '/etc/darcsweb')
Fri Jun 22 09:30:21 UTC 2007 Peter Colberg <peterco@gmx.net>
* Adjust URI scheme according to CGI environment variable HTTPS.
This patch fixes RSS feed links when browsing darcsweb via SSL.
{
hunk ./darcsweb.cgi 2325
- if p == '80':
+ u = os.environ.get('HTTPS', 'off') in ('on', '1')
+ if not u and p == '80' or u and p == '443':
hunk ./darcsweb.cgi 2330
- config.myurl = 'http://%s%s%s' % (n, p, s)
+ config.myurl = 'http%s://%s%s%s' % (u and 's' or '', n, p, s)
}
Wed May 16 09:48:24 UTC 2007 Jonathan Buchanan <jonathan.buchanan@gmail.com>
* Fixed bad links in RSS feed when darcsweb URL is automatically detected
When the darcsweb URL is automatically detected, the script name is included in the URL - this results in bad links in RSS feeds like /darcsweb.cgi/darcsweb.cgi?r=projname.
hunk ./darcsweb.cgi 2324
- s = os.environ['SCRIPT_NAME']
+ s = os.path.dirname(os.environ['SCRIPT_NAME'])
Wed May 16 09:46:25 UTC 2007 Jonathan Buchanan <jonathan.buchanan@gmail.com>
* Fixed a path problem when running on Windows
Repositories in subdirectories have backslashes in their path when running on Windows, which results in bad URLS - replaced these with forward slashes.
hunk ./darcsweb.cgi 2230
+ name = name.replace('\\', '/')
Thu May 3 16:18:30 UTC 2007 VMiklos <vmiklos@frugalware.org>
* display the size of the files in tree view
{
hunk ./darcsweb.cgi 226
+def fsize(fname):
+ s = os.stat(fname)[stat.ST_SIZE]
+ if s < 1024:
+ return "%s" % s
+ elif s < 1048576:
+ return "%sK" % (s / 1024)
+ elif s < 1073741824:
+ return "%sM" % (s / 1048576)
hunk ./darcsweb.cgi 1792
+ print '<td style="font-family:monospace">', fsize(realfile),
+ print '</td>'
}
Mon Apr 16 19:06:18 UTC 2007 Alberto Bertogli <albertito@gmail.com>
* Soften some colors in commitdiff.
hunk ./darcsweb.cgi 1070
- color = 'style="color:#990099; border-top:dashed; border-width:1px;"'
+ color = 'style="color:#990099; '
+ color += 'border: solid #ffe0ff; '
+ color += 'border-width: 1px 0px 0px 0px; '
+ color += 'margin-top: 2px;"'
Mon Apr 16 09:13:34 UTC 2007 Alexandre Rossi <alexandre.rossi@gmail.com>
* only read the first line of _darcs/third_party/darcsweb/* files
{
hunk ./darcsweb.cgi 2235
- desc = open(dpath).read()
+ desc = open(dpath).readline().rstrip("\n")
hunk ./darcsweb.cgi 2245
- url = open(dpath).read()
+ url = open(dpath).readline().rstrip("\n")
hunk ./darcsweb.cgi 2255
- projurl = open(dpath).read()
+ projurl = open(dpath).readline().rstrip("\n")
}
Mon Apr 16 09:11:29 UTC 2007 Alexandre Rossi <alexandre.rossi@gmail.com>
* make color commitdiff more readable when parts of a file are skipped
hunk ./darcsweb.cgi 1070
- color = 'style="color:#990099;"'
+ color = 'style="color:#990099; border-top:dashed; border-width:1px;"'
Fri Mar 16 19:27:14 UTC 2007 VMiklos <vmiklos@frugalware.org>
* new optional config varuable: disable_annotate
* the annotate feature is still enabled by default
* this can be useful on slow machines
{
hunk ./config.py.sample 81
+
+ # If you want to disable the annotate feature (for performance reasons,
+ # the http connection will time out on slow machines), uncomment this
+ # option.
+ #disable_annotate = True
hunk ./darcsweb.cgi 1039
- out = run_darcs(cmd)
+ if not config.disable_annotate:
+ out = run_darcs(cmd)
+ else:
+ return None
hunk ./darcsweb.cgi 1857
+ if not ann:
+ print """
+<i>The annotate feature has been disabled</i>
+</div>
+ """
+ print_footer()
+ return
hunk ./darcsweb.cgi 2384
+ if "disable_annotate" in dir(base):
+ config.disable_annotate = base.disable_annotate
+ else:
+ config.disable_annotate = False
}
Wed Apr 4 15:09:32 UTC 2007 Alexandre Rossi <alexandre.rossi@gmail.com>
* closing <a> tag in project url link
hunk ./darcsweb.cgi 1389
- print ' <td><a href="%(url)s">%(url)s</td></tr>' % \
+ print ' <td><a href="%(url)s">%(url)s</a></td></tr>' % \
Wed Apr 4 12:15:12 UTC 2007 Alexandre Rossi <alexandre.rossi@gmail.com>
* typo in sample config autoprojurl description
hunk ./config.py.sample 181
- # file named "_darcs/third_party/darcsweb/extdoc" (one line only), set
+ # file named "_darcs/third_party/darcsweb/projurl" (one line only), set
Thu Feb 1 17:30:50 UTC 2007 VMiklos <vmiklos@frugalware.org>
* new optional config varuable: author_links
it is disabled by default and an example for cia is included
{
hunk ./config.py.sample 77
+
+ # If you want to generate links from patch author names, define the url
+ # here. Example for CIA:
+ #author_links = "http://cia.navi.cx/stats/author/%(author)s"
+
hunk ./darcsweb.cgi 487
+def gen_authorlink(author, shortauthor=None):
+ if not config.author_links:
+ if shortauthor:
+ return shortauthor
+ else:
+ return author
+ if not shortauthor:
+ shortauthor = author
+ return '<a href="' + config.author_links % { 'author': author } + '">%s</a>' % shortauthor
hunk ./darcsweb.cgi 1149
- 'author': shorten_str(p.shortauthor, 26),
+ 'author': gen_authorlink(p.author, shorten_str(p.shortauthor, 26)),
hunk ./darcsweb.cgi 1209
- 'author': p.shortauthor,
+ 'author': gen_authorlink(p.author, p.shortauthor),
hunk ./darcsweb.cgi 1619
- 'author': p.author,
+ 'author': gen_authorlink(p.author),
hunk ./darcsweb.cgi 2082
- 'author': shorten_str(p.shortauthor, 26),
+ 'author': gen_authorlink(p.author, shorten_str(p.shortauthor, 26)),
hunk ./darcsweb.cgi 2370
+ if "author_links" in dir(base):
+ config.author_links = base.author_links
+ else:
+ config.author_links = None
}
Wed Jan 24 23:38:07 UTC 2007 Alberto Bertogli <albertito@gmail.com>
* Check python version before running darcsweb.
This patch adds a check to verify that the python version is >= 2.3, so the
user doesn't get strange errors when using older python interpreters.
Thanks to Mark Stosberg for the suggestion.
hunk ./darcsweb.cgi 2367
+
+if sys.version_info < (2, 3):
+ print "Sorry, but Python 2.3 or above is required to run darcsweb."
+ sys.exit(1)
Wed Jan 17 23:02:12 UTC 2007 jonathan.buchanan@gmail.com
* The DARCS_DONT_ESCAPE_8BIT environment variable is now set using os.environ before running darcs and restored to its original state after running darcs - makes darcsweb work on Windows
{
hunk ./darcsweb.cgi 590
- cmd = 'DARCS_DONT_ESCAPE_8BIT=1 ' + config.darcspath + "darcs " + params
+ try:
+ original_8bit_setting = os.environ['DARCS_DONT_ESCAPE_8BIT']
+ except KeyError:
+ original_8bit_setting = None
+ os.environ['DARCS_DONT_ESCAPE_8BIT'] = '1'
+ cmd = config.darcspath + "darcs " + params
hunk ./darcsweb.cgi 598
+ if original_8bit_setting == None:
+ del(os.environ['DARCS_DONT_ESCAPE_8BIT'])
+ else:
+ os.environ['DARCS_DONT_ESCAPE_8BIT'] = original_8bit_setting
}
Mon Dec 25 22:18:20 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Add support for regexp-based replacing.
Add an option to replace text in the summary, using regexps. This allows you
to configure darcsweb to automatically detect and put links to other commits
or bug numbers.
This patch is heavily based on the one written by Kirill Smelkov
(kirr@mns.spb.ru).
{
hunk ./config.py.sample 57
+
+ # If you want darcsweb to automatically detect embedded URLs,
+ # define them here, using python-style regexps like the examples
+ # below. They will be replaced in summaries, logs, and commits.
+ # The following variables are replaced:
+ # myreponame: repository link (darcsweb.cgi?r=repo)
+ # reponame: repository name (repo)
+ #
+ #url_links = (
+ # Format is: (regexp, replacement)
+ # Some examples:
+ #
+ # Detect '#NNN' as a reference to bug database
+ #(r'#([0-9]+)',
+ # r'<a href="/bugs/show_bug.cgi?id=\1">#\1</a>'),
+ #
+ # Replace hashes with commit-links.
+ #(r'(\d{14}-[0-9a-f]{5}-[0-9a-f]{40}\.gz)',
+ # r'<a href="%(myreponame)s;a=commit;h=\1">\1</a>'),
+ #)
hunk ./darcsweb.cgi 164
+def replace_links(s):
+ """Replace user defined strings with links, as specified in the
+ configuration file."""
+ import re
+
+ vardict = {
+ "myreponame": config.myreponame,
+ "reponame": config.reponame,
+ }
+
+ for link_pat, link_dst in config.url_links:
+ s = re.sub(link_pat, link_dst % vardict, s)
+
+ return s
+
+
hunk ./darcsweb.cgi 1165
- comment = escape(p.comment)
+ comment = replace_links(escape(p.comment))
hunk ./darcsweb.cgi 1608
- comment = escape(p.comment)
+ comment = replace_links(escape(p.comment))
hunk ./darcsweb.cgi 1611
- print escape(p.name), '<br/><br/>'
+ print replace_links(escape(p.name)), '<br/><br/>'
hunk ./darcsweb.cgi 2340
+ if "url_links" in dir(base):
+ config.url_links = base.url_links
+ else:
+ config.url_links = ()
+
}
Thu Nov 30 09:37:41 UTC 2006 Kirill Smelkov <kirr@mns.spb.ru>
* string.join is deprecated
{
hunk ./darcsweb.cgi 53
- return string.join(l, "")
+ return ''.join(l)
hunk ./darcsweb.cgi 59
- return string.join(l, "")
+ return ''.join(l)
hunk ./darcsweb.cgi 65
- return string.join(l, "")
+ return ''.join(l)
hunk ./darcsweb.cgi 86
- print string.join(params), '<br/>'
+ print ' '.join(params), '<br/>'
hunk ./darcsweb.cgi 97
- return string.join(n, '\n')
+ return '\n'.join(n)
hunk ./darcsweb.cgi 208
- return string.join(s, '')
+ return ''.join(s)
}
Mon Dec 25 21:43:36 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Change my email address.
{
hunk ./README 3
-Alberto Bertogli (albertogli@telpin.com.ar)
--------------------------------------------
+Alberto Bertogli (albertito@gmail.com)
+----------------------------------------
hunk ./darcsweb.cgi 5
-Alberto Bertogli (albertogli@telpin.com.ar)
+Alberto Bertogli (albertito@gmail.com)
hunk ./darcsweb.cgi 273
- Alberto Bertogli (albertogli@telpin.com.ar).
+ Alberto Bertogli (albertito@gmail.com).
hunk ./style.css 3
- * Alberto Bertogli (albertogli@telpin.com.ar)
+ * Alberto Bertogli (albertito@gmail.com)
}
Tue Oct 10 03:04:21 UTC 2006 Alberto Bertogli <albertito@gmail.com>
tagged 0.16
{
}
Wed Aug 9 17:54:30 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Handle empty lines in print_darcs_diff().
A "setpref" patch can output empty lines when seen with darcs_diff. Handle
that case by ignoring them.
Thanks to VMiklos from reporting it.
hunk ./darcsweb.cgi 1050
+ if not l:
+ continue
Mon Jul 31 05:29:33 UTC 2006 Alberto Bertogli <albertito@gmail.com>
tagged 0.16-rc1
{
}
Mon Jul 31 05:28:34 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Remove some unnecessary newlines in html output.
{
hunk ./darcsweb.cgi 1206
-</div>
+</div>\
hunk ./darcsweb.cgi 1310
-</div>
+</div>\
}
Mon Jul 31 05:10:03 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Make browsing files in tree root easier.
This patch makes it easier to browse files in the root of the tree, by making
it simpler to return to the root tree view.
{
hunk ./darcsweb.cgi 1779
- print """
- <div class="title"><b>
- """
hunk ./darcsweb.cgi 1780
- # and the linked, with links
- parts = filepath.split('/')
- print '/ '
- sofar = '/'
- for p in parts:
- if not p: continue
- sofar += '/' + p
- print '<a href="%s;a=tree;f=%s">%s</a> /' % \
- (config.myreponame, sofar, p)
+ if filepath == '/':
+ print '<div><a class="title" href="%s;a=tree">/</a></div>' % \
+ (config.myreponame)
+ else:
+ print '<div class="title"><b>'
hunk ./darcsweb.cgi 1786
- print '</b></div>'
+ # and the linked, with links
+ parts = filepath.split('/')
+ print '/ '
+ sofar = '/'
+ for p in parts:
+ if not p: continue
+ sofar += '/' + p
+ print '<a href="%s;a=tree;f=%s">%s</a> /' % \
+ (config.myreponame, sofar, p)
+
+ print '</b></div>'
}
Mon Jul 31 04:54:05 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Allow projects to link to external sites.
Add a 'repoprojurl' configuration option to put a reference to an external
project site. It appears in the project summary, just like url.
It also supports multidir, both automatic detection in the third_party
directory, and static construction.
Thanks to Alexandre Rossi for the idea and preliminary patch.
{
hunk ./config.py.sample 98
+ # Each repository may show a link to some website associated with it.
+ # This is typically useful if you've got a website describing the
+ # software in your repository.
+ #repoprojurl = 'http://example.com/projects/repo1/'
+
hunk ./config.py.sample 133
+ # optional, see above
+ #repoprojurl = 'http://example.com/projects/%(name)s/'
+
hunk ./config.py.sample 155
+ # if you want the projects urls to be picked up automatically from the
+ # file named "_darcs/third_party/darcsweb/extdoc" (one line only), set
+ # this to True. It defaults to False.
+ #autoprojurl = True
+
hunk ./darcsweb.cgi 1351
+ if config.repoprojurl:
+ print ' <tr><td>project url</td>'
+ print ' <td><a href="%(url)s">%(url)s</td></tr>' % \
+ { 'url': config.repoprojurl }
hunk ./darcsweb.cgi 2202
+ if 'autoprojurl' in dir(c) and c.autoprojurl:
+ dpath = fulldir + \
+ '/_darcs/third_party/darcsweb/projurl'
+ if os.access(dpath, os.R_OK):
+ projurl = open(dpath).read()
+ elif 'repoprojurl' in dir(c):
+ projurl = c.repoprojurl % {'name': name}
+ else:
+ projurl = None
+ elif 'repoprojurl' in dir(c):
+ projurl = c.repoprojurl % { 'name': name }
+ else:
+ projurl = None
+
hunk ./darcsweb.cgi 2223
+ repoprojurl = projurl
hunk ./darcsweb.cgi 2227
+
hunk ./darcsweb.cgi 2279
+
+ config.repoprojurl = None
+ if 'repoprojurl' in dir(c):
+ config.repoprojurl = c.repoprojurl
+
}
Mon Jul 31 04:24:50 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Convert remaining auriga references to example.com.
{
hunk ./config.py.sample 80
- repourl = 'http://auriga.wearlab.de/~alb/repos/repo1/'
+ repourl = 'http://example.com/repos/repo1/'
hunk ./config.py.sample 103
- repourl = 'http://auriga.wearlab.de/~alb/repos/repo2/'
+ repourl = 'http://example.com/repos/repo2/'
hunk ./config.py.sample 125
- repourl = 'http://auriga.wearlab.de/~alb/repos/%(name)s/'
+ repourl = 'http://example.com/repos/%(name)s/'
}
Mon Jul 31 04:10:20 UTC 2006 Alberto Bertogli <albertito@gmail.com>
* Implement url and scriptname autodetection.
This patch implements autodetection of the url and scriptname of darcsweb.
It's based on a suggestion from Tobias Gruetzmacher.
It relies on variables according to the CGI/1.1 standard, and works only if
cache is not enabled. If it is, the variables must be set manually as before.
The problem with the cache is multi-host access: if a page not in the cache is
accesed as http://hosta/dw/..., then the cached page will reference "hosta".
If then it's accessed from hostb, there will be a reference to hosta that it's
possibly broken. It's actually a quite common case when you have localhost and
external access.
{
hunk ./config.py.sample 4
- # this script's name, usually just "darcsweb.cgi" unless you rename it
- myname = "darcsweb.cgi"
-
- # our url, used only to generate RSS links, without the script name
- myurl = "http://example.com/darcsweb"
-
hunk ./config.py.sample 13
+ # this script's name, usually just "darcsweb.cgi" unless you rename
+ # it; if you leave this commented it will be detected automatically
+ #myname = "darcsweb.cgi"
+
+ # our url, used only to generate RSS links, without the script name;
+ # if you leave this commented it will be detected automatically
+ #myurl = "http://example.com/darcsweb"
+
hunk ./config.py.sample 43
+ # If you use this option you must set the "myname" and "myurl"
+ # variables.
hunk ./darcsweb.cgi 2060
+ expand_multi_config(all_configs)
hunk ./darcsweb.cgi 2104
- expand_multi_config(all_configs)
hunk ./darcsweb.cgi 2126
- 'myname': all_configs.base.myname,
+ 'myname': config.myname,
hunk ./darcsweb.cgi 2232
- config.myname = base.myname
- config.myurl = base.myurl
+ if 'myname' not in dir(base):
+ # SCRIPT_NAME has the full path, we only take the file name
+ config.myname = os.path.basename(os.environ['SCRIPT_NAME'])
+ else:
+ config.myname = base.myname
+
+ if 'myurl' not in dir(base) and 'cachedir' not in dir(base):
+ n = os.environ['SERVER_NAME']
+ p = os.environ['SERVER_PORT']
+ s = os.environ['SCRIPT_NAME']
+ if p == '80':
+ p = ''
+ else:
+ p = ':' + p
+ config.myurl = 'http://%s%s%s' % (n, p, s)
+ else:
+ config.myurl = base.myurl
+
hunk ./darcsweb.cgi 2254
- config.myreponame = base.myname + '?r=' + urllib.quote(name)
+ config.myreponame = config.myname + '?r=' + urllib.quote(name)
}
Fri Jul 14 19:27:30 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Add autourl support for multidir.
This patch adds a new option for multidir config entries, named "autourl". If
set, it will take the contents of "_darcs/third_party/darcsweb/url" and use it
as repourl.
Thanks to Marco Baringer for suggestion and preliminary patch.
{
hunk ./config.py.sample 138
+ # if you want urls to be picked up automatically from the file named
+ # "_darcs/third_party/darcsweb/url" (one line only), set this to
+ # True. It defaults to False.
+ #autourl = True
hunk ./darcsweb.cgi 2188
+ if 'autourl' in dir(c) and c.autourl:
+ dpath = fulldir + \
+ '/_darcs/third_party/darcsweb/url'
+ if os.access(dpath, os.R_OK):
+ url = open(dpath).read()
+ else:
+ url = c.repourl % { 'name': name }
+ else:
+ url = c.repourl % { 'name': name }
+
hunk ./darcsweb.cgi 2199
- url = c.repourl % { 'name': name }
}
Fri Jul 14 18:09:52 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Use example.com for url examples.
hunk ./config.py.sample 8
- myurl = "http://albertito.homeip.net:8026/darcsweb"
+ myurl = "http://example.com/darcsweb"
Thu Jul 6 17:04:59 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Put directories in blue on tree view.
To make directories easy to spot, make them blue and with a "/" at the end.
Then they become obvious, but not too distracting.
Thanks to Dan Pescu for all the suggestions.
hunk ./darcsweb.cgi 1741
- <td><a class="list" href="%(myrname)s;a=tree;f=%(fullf)s">%(f)s</a></td>
+ <td>
+ <a class="link" href="%(myrname)s;a=tree;f=%(fullf)s">%(f)s/</a>
+ </td>
Mon May 29 15:04:37 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Escape repository descriptions.
Escape all repository descriptions, because they might contain unfrendly
characters for XML (including HTML, ATOM and RSS).
Thanks to Clive Crous for the report and a slightly different patch.
{
hunk ./darcsweb.cgi 1342
- print ' <tr><td>description</td><td>%s</td></tr>' % config.repodesc
+ print ' <tr><td>description</td><td>%s</td></tr>' % \
+ escape(config.repodesc)
hunk ./darcsweb.cgi 1874
- 'desc': config.repodesc,
+ 'desc': escape(config.repodesc),
hunk ./darcsweb.cgi 1948
- 'desc': config.repodesc,
+ 'desc': escape(config.repodesc),
}
Sat May 13 23:23:21 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Support the new pristine directory.
darcs 1.0.7 uses a new name for the pristine directory, "pristine", instead of
the classic "current".
This patch adds support for that directory, without dropping "current" because
it's still heavily used in existing repositories.
{
hunk ./darcsweb.cgi 221
+ realf = filter_file(config.repodir + '/_darcs/pristine/' + fname)
+ if os.path.exists(realf):
+ return realf
hunk ./darcsweb.cgi 225
- if not os.path.exists(realf):
- realf = filter_file(config.repodir + '/' + fname)
+ if os.path.exists(realf):
+ return realf
+ realf = filter_file(config.repodir + '/' + fname)
}
Wed Mar 8 02:13:19 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.15
{
}
Wed Mar 8 02:13:01 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Version 0.15.
hunk ./darcsweb.cgi 268
-<!-- darcsweb 0.10
+<!-- darcsweb 0.15
Fri Feb 24 01:43:41 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.15-rc1
{
}
Fri Feb 24 01:37:00 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Fix repoencoding, this time for real (I hope).
{
hunk ./darcsweb.cgi 2188
-
- # repoencoding must be a tuple
- if isinstance(c.repoencoding, str):
- repoencoding = (c.repoencoding, )
- else:
- repoencoding = c.repoencoding
+ repoencoding = c.repoencoding
hunk ./darcsweb.cgi 2227
- config.repoencoding = c.repoencoding
+ # repoencoding must be a tuple
+ if isinstance(c.repoencoding, str):
+ config.repoencoding = (c.repoencoding, )
+ else:
+ config.repoencoding = c.repoencoding
}
Fri Feb 24 00:54:19 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Fix to allow having a single repoencoding.
hunk ./darcsweb.cgi 2190
- if c.repoencoding is str:
+ if isinstance(c.repoencoding, str):
Fri Feb 24 00:31:28 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Rewrite encoding handling.
This patch rewrites fixu8() and affects a couple of places where decode() was
used directly.
It has the benefit of removing the ugly previous function, replacing it
with... well, another ugly function, but with a different kind of uglyness.
It also supports multiple encodings, so if the first one fails, a second one
is tried (and so on).
There still are some corner cases with file named in alternative encodings,
but should work much better than the older code.
{
hunk ./config.py.sample 83
+ # You can, optionally, specify multiple encodings; they're tried in
+ # order, and if one fails to decode a string, the next one is tried.
+ # Example: repoencoding = "utf8", "latin1"
hunk ./darcsweb.cgi 91
- openpos = s.find('[_')
- if openpos < 0:
- # small optimization to avoid the conversion to utf8 and
- # entering the loop
- if type(s) == unicode:
- # workaround for python < 2.4
- return s.encode('utf8')
- else:
- return s.decode(config.repoencoding).encode('utf8')
-
- s = s.encode(config.repoencoding).decode('raw_unicode_escape')
- while openpos >= 0:
- closepos = s.find('_]', openpos)
- if closepos < 0:
- # not closed, probably just luck
- break
-
- # middle should be something like 'c3', so we get it by
- # removing the first three characters ("[_\")
- middle = s[openpos + 3:closepos]
- if len(middle) == 2:
- # now we turn middle into the character "\xc3"
- char = chr(int(middle, 16))
+ """Calls _fixu8(), which does the real work, line by line. Otherwise
+ we choose the wrong encoding for big buffers and end up messing
+ output."""
+ n = []
+ for i in s.split('\n'):
+ n.append(_fixu8(i))
+ return string.join(n, '\n')
hunk ./darcsweb.cgi 99
- # finally, replace s with our new improved string, and
- # repeat the ugly procedure
- char = char.decode(config.repoencoding)
- mn = '[_\\' + middle + '_]'
- s = s.replace(mn, char, 1)
- openpos = s.find('[_', openpos + 1)
+def _fixu8(s):
+ if type(s) == unicode:
+ return s.encode('utf8', 'replace')
+ for e in config.repoencoding:
+ try:
+ return s.decode(e).encode('utf8', 'replace')
+ except UnicodeDecodeError:
+ pass
+ raise 'DecodingError', config.repoencoding
hunk ./darcsweb.cgi 109
- if config.repoencoding != 'utf8':
- s = s.encode('utf8')
- else:
- s = s.encode('raw_unicode_escape', 'replace')
- return s
hunk ./darcsweb.cgi 570
- cmd = config.darcspath + "darcs " + params
+ cmd = 'DARCS_DONT_ESCAPE_8BIT=1 ' + config.darcspath + "darcs " + params
hunk ./darcsweb.cgi 628
+class XmlInputWrapper:
+ def __init__(self, fd):
+ self.fd = fd
+ self.times = 0
+ self._read = self.read
+
+ def read(self, *args, **kwargs):
+ self.times += 1
+ if self.times == 1:
+ return '<?xml version="1.0" encoding="utf-8"?>\n'
+ s = self.fd.read(*args, **kwargs)
+ if not s:
+ return s
+ return fixu8(s)
+
+ def close(self, *args, **kwargs):
+ return self.fd.close(*args, **kwargs)
+
hunk ./darcsweb.cgi 815
- parser.parse(xmlf)
+ parser.parse(XmlInputWrapper(xmlf))
hunk ./darcsweb.cgi 1012
- l = l.decode(config.repoencoding, 'replace').encode('utf-8')
+ l = fixu8(l)
hunk ./darcsweb.cgi 1038
- l = l.decode(config.repoencoding, 'replace').encode('utf-8')
+ l = fixu8(l)
hunk ./darcsweb.cgi 2188
- repoencoding = c.repoencoding
+
+ # repoencoding must be a tuple
+ if c.repoencoding is str:
+ repoencoding = (c.repoencoding, )
+ else:
+ repoencoding = c.repoencoding
+
}
Thu Feb 23 19:47:31 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Include the repository in log_times() output.
{
hunk ./darcsweb.cgi 244
-def log_times(cache_hit, event = None):
+def log_times(cache_hit, repo = None, event = None):
hunk ./darcsweb.cgi 254
- s = """\
-%s
+ s = '%s\n' % event
+
+ if repo:
+ s += '\trepo: %s\n' % repo
+
+ s += """\
hunk ./darcsweb.cgi 262
- imports: %.3f\n""" % (event, time_total, processing, time_imports)
+ imports: %.3f\n""" % (time_total, processing, time_imports)
hunk ./darcsweb.cgi 2305
- log_times(cache_hit = 1)
+ log_times(cache_hit = 1, repo = config.reponame)
hunk ./darcsweb.cgi 2458
-log_times(cache_hit = 0)
+log_times(cache_hit = 0, repo = config.reponame)
}
Thu Feb 23 18:51:21 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Quote filenames in several places.
There were several places using filenames in URLs without quoting them
properly, this fixes them.
Thanks to VMiklos for the report.
{
hunk ./darcsweb.cgi 358
+ f = urllib.quote(f)
hunk ./darcsweb.cgi 1611
- %(file)s</a>
+ %(fname)s</a>
hunk ./darcsweb.cgi 1616
- 'file': f
+ 'file': urllib.quote(f),
+ 'fname': escape(f),
hunk ./darcsweb.cgi 1667
- 'file': f
+ 'file': urllib.quote(f)
hunk ./darcsweb.cgi 1692
- (config.myreponame, escape(sofar), p)
+ (config.myreponame, urllib.quote(sofar), p)
hunk ./darcsweb.cgi 1726
+ fullf = filter_file(dname + '/' + f)
hunk ./darcsweb.cgi 1732
- <td><a class="list" href="%(myrname)s;a=tree;f=%(newf)s">%(f)s</a></td>
+ <td><a class="list" href="%(myrname)s;a=tree;f=%(fullf)s">%(f)s</a></td>
hunk ./darcsweb.cgi 1734
- <a href="%(myrname)s;a=filehistory;f=%(newf)s">history</a> |
- <a href="%(myrname)s;a=tree;f=%(newf)s">tree</a>
+ <a href="%(myrname)s;a=filehistory;f=%(fullf)s">history</a> |
+ <a href="%(myrname)s;a=tree;f=%(fullf)s">tree</a>
hunk ./darcsweb.cgi 1740
- 'newf': filter_file(dname + '/' + f),
+ 'fullf': urllib.quote(fullf),
hunk ./darcsweb.cgi 1753
- 'fullf': filter_file(dname + '/' + f),
+ 'fullf': urllib.quote(fullf),
}
Thu Feb 23 18:34:51 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Filter '"' in filenames.
For security, don't allow '"' in filenames.
If there is high demand, some alternative workaround could be implemented.
hunk ./darcsweb.cgi 69
- if '..' in s:
+ if '..' in s or '"' in s:
Thu Feb 23 17:21:30 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Add /etc/darcsweb to the module lookup path.
This allows darcsweb's configuration to be in /etc/darcsweb instead of the
current directory. It's mostly wanted by distributions which want to isolate
the config file to keep things clean.
A similar patch was sent by Gaetan Lehmann (Mandriva), VMiklos (Frugalware)
and Fabian Linzberger (Debian).
hunk ./darcsweb.cgi 26
+# In order to be able to store the config file in /etc/darcsweb, it has to be
+# added to sys.path. It's mainly used by distributions, which place the
+# default configuration there.
+sys.path.append('/etc/darcsweb')
+
Wed Feb 22 04:47:15 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Move some one-time used imports to the user location.
As a minor but noticeable optimization to darcsweb's load time, move the
importing of sha and email.Utils modules to the place where they're used (only
one in both cases).
This takes the time spent on imports from 0.027s to 0.021s, which will
probably be slightly noticeable on slower machines, reducing the time taken by
a cache hit from 0.030s to 0.024s (on misses it doesn't make a difference).
{
hunk ./darcsweb.cgi 17
-import sha
hunk ./darcsweb.cgi 22
-import email.Utils
hunk ./darcsweb.cgi 482
+ import sha
hunk ./darcsweb.cgi 1870
+ import email.Utils
}
Tue Feb 21 21:24:30 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Begin with alt = True in listings.
I think it looks better if we start a listing with alt = True (the dark one).
{
hunk ./darcsweb.cgi 1076
- alt = False
+ alt = True
hunk ./darcsweb.cgi 1588
- alt = False
+ alt = True
hunk ./darcsweb.cgi 1696
- alt = False
+ alt = True
hunk ./darcsweb.cgi 1993
- alt = False
+ alt = True
hunk ./darcsweb.cgi 2083
- alt = False
+ alt = True
}
Mon Feb 20 03:23:19 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Implement time logging.
This record adds an option to log the time it took darcsweb to present a
page. Unfortunately, because of the way it's implemented, it's impossible to
isolate the time it takes to call darcs; however, every darcs invocation is
logged too, to allow independant measures.
{
hunk ./config.py.sample 48
+
+ # If you want to log the times it took darcsweb to present a page,
+ # uncomment this option. The value should be a file writeable by
+ # darcsweb.
+ #logtimes = "/tmp/darcsweb_times"
hunk ./darcsweb.cgi 11
+import time
+time_begin = time.time()
hunk ./darcsweb.cgi 16
-import time
hunk ./darcsweb.cgi 24
+time_imports = time.time() - time_begin
hunk ./darcsweb.cgi 32
+# list of run_darcs() invocations, for performance measures
+darcs_runs = []
+
hunk ./darcsweb.cgi 241
+def log_times(cache_hit, event = None):
+ if not config.logtimes:
+ return
+
+ time_total = time.time() - time_begin
+ processing = time_total - time_imports
+ if not event:
+ event = action
+ if cache_hit:
+ event = event + " (hit)"
+ s = """\
+%s
+ total: %.3f
+ processing: %.3f
+ imports: %.3f\n""" % (event, time_total, processing, time_imports)
+
+ if darcs_runs:
+ s += "\truns:\n"
+ for params in darcs_runs:
+ s += '\t\t%s\n' % params
+ s += '\n'
+
+ lf = open(config.logtimes, 'a')
+ lf.write(s)
+ lf.close()
+
hunk ./darcsweb.cgi 581
+ darcs_runs.append(params)
hunk ./darcsweb.cgi 2240
+ if "logtimes" in dir(base):
+ config.logtimes = base.logtimes
+ else:
+ config.logtimes = None
+
hunk ./darcsweb.cgi 2265
+ log_times(cache_hit = 0, event = 'index')
hunk ./darcsweb.cgi 2293
+ log_times(cache_hit = 1)
hunk ./darcsweb.cgi 2446
+log_times(cache_hit = 0)
+
+
}
Sun Feb 19 17:42:23 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Change cache file permissions 600.
Change cache file permissions to 600. This should work on Windows too because
the bits are ignored, according to python's documentation.
hunk ./darcsweb.cgi 470
+ os.chmod(fname, stat.S_IRUSR | stat.S_IWUSR)
Thu Jan 12 23:52:34 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Fix typos in the BOLA license.
{
hunk ./LICENSE 5
-so I'm placing darcsweb under the following license, so you feel guilty if you
-don't ;)
+so I'm placing darcsweb under the following license, to make you feel guilty
+if you don't ;)
hunk ./LICENSE 27
- non-renovable resources. Extra points if you discover or invent something
+ non-renewable resources. Extra points if you discover or invent something
}
Mon Jan 9 22:25:04 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.14
{
}
Mon Jan 9 05:58:01 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Fix cache behaviour on uncaught exceptions.
This patch make darcsweb cancel the cache when there is an uncaught exception,
avoiding leaving dot-files around the cache directory.
Also minimize DoS by not taking into account unused form parameters, and make
the hash independant of the position. This doesn't eliminate all the
opportunities for DoS, but reduces them significatively.
{
hunk ./darcsweb.cgi 30
+# exception handling
+def exc_handle(t, v, tb):
+ try:
+ cache.cancel()
+ except:
+ pass
+ cgitb.handler((t, v, tb))
+sys.excepthook = exc_handle
hunk ./darcsweb.cgi 455
- self.fname = sha.sha(url).hexdigest()
+ self.fname = sha.sha(repr(url)).hexdigest()
hunk ./darcsweb.cgi 2243
+ # create a string representation of the request, ignoring all the
+ # unused parameters to avoid DoS
+ params = ['r', 'a', 'f', 'h', 'topi']
+ params = [ x for x in form.keys() if x in params ]
+ url_request = [ (x, form[x].value) for x in params ]
+ url_request.sort()
}
Mon Jan 9 05:27:44 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Replace the darcs logo with a smaller one.
Now that we have a search box, the logo becomes really big and distractive.
Replace it with a smaller version, only with the ball.
binary ./darcs.png
Mon Jan 9 05:24:26 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Implement a search box.
This implements a small search box that appears on the right top besides the
logo (which will be changed to a small version in a following patch).
{
hunk ./config.py.sample 42
+
+ # By default, darcsweb's search looks in the last 100 commits; you can
+ # change that number by specifying it here.
+ # Note that search are not cached, so if you have tons of commits and
+ # set the limit to a very high number, they will take time.
+ #searchlimit = 100
hunk ./darcsweb.cgi 166
+def highlight(s, l):
+ "Highlights appearences of s in l"
+ import re
+ # build the regexp by leaving "(s)", replacing '(' and ') first
+ s = s.replace('\\', '\\\\')
+ s = s.replace('(', '\\(')
+ s = s.replace(')', '\\)')
+ s = '(' + escape(s) + ')'
+ try:
+ pat = re.compile(s, re.I)
+ repl = '<span style="color:#e00000">\\1</span>'
+ l = re.sub(pat, repl, l)
+ except:
+ pass
+ return l
+
hunk ./darcsweb.cgi 261
-<a href="http://darcs.net" title="darcs">
-<img src="%(logo)s" alt="darcs logo" style="float:right; border-width:0px;"/>
-</a>
+ <div class="search_box">
+ <form action="%(myname)s" method="get"><div>
+ <input type="hidden" name="r" value="%(reponame)s"/>
+ <input type="hidden" name="a" value="search"/>
+ <input type="text" name="s" size="20" class="search_text"/>
+ <input type="submit" value="search" class="search_button"/>
+ <a href="http://darcs.net" title="darcs">
+ <img src="%(logo)s" alt="darcs logo" class="logo"/>
+ </a>
+ </div></form>
+ </div>
+ <a href="%(myname)s">repos</a> /
+ <a href="%(myreponame)s;a=summary">%(reponame)s</a> /
+ %(action)s
+</div>
hunk ./darcsweb.cgi 282
+ 'myname': config.myname,
+ 'myreponame': config.myreponame,
+ 'action': action
hunk ./darcsweb.cgi 286
- print '<a href="%s">repos</a> /' % config.myname
- print '<a href="%s;a=summary">%s</a>' % (config.myreponame,
- config.reponame),
- print '/ ' + action
- print "</div>"
hunk ./darcsweb.cgi 575
+ def matches(self, s):
+ "Defines if the patch matches a given string"
+ if s.lower() in self.comment.lower():
+ return self.comment
+ elif s.lower() in self.name.lower():
+ return self.name
+ elif s.lower() in self.author.lower():
+ return self.author
+ elif s == self.hash:
+ return self.hash
+
+ s = s.lower()
+ for l in (self.adds, self.removes, self.modifies,
+ self.diradds, self.dirremoves,
+ self.replaces.keys(), self.moves.keys(),
+ self.moves.keys() ):
+ for i in l:
+ if s in i.lower():
+ return i
+ return ''
+
hunk ./darcsweb.cgi 1943
+def do_search(s):
+ print_header()
+ print_navbar()
+ ps = get_last_patches(config.searchlimit)
+
+ print '<div class="title">Search last %d commits for "%s"</div>' \
+ % (config.searchlimit, escape(s))
+ print '<table cellspacing="0">'
+
+ alt = False
+ for p in ps:
+ match = p.matches(s)
+ if not match:
+ continue
+
+ if alt:
+ print '<tr class="dark">'
+ else:
+ print '<tr class="light">'
+ alt = not alt
+
+ print """
+ <td><i>%(age)s</i></td>
+ <td>%(author)s</td>
+ <td>
+ <a class="list" title="%(fullname)s" href="%(myrname)s;a=commit;h=%(hash)s">
+ <b>%(name)s</b>
+ </a><br/>
+ %(match)s
+ </td>
+ <td class="link">
+ <a href="%(myrname)s;a=commit;h=%(hash)s">commit</a> |
+ <a href="%(myrname)s;a=commitdiff;h=%(hash)s">commitdiff</a>
+ </td>
+ """ % {
+ 'age': how_old(p.local_date),
+ 'author': shorten_str(p.shortauthor, 26),
+ 'myrname': config.myreponame,
+ 'hash': p.hash,
+ 'name': escape(shorten_str(p.name)),
+ 'fullname': escape(p.name),
+ 'match': highlight(s, shorten_str(match)),
+ }
+ print "</tr>"
+
+ print '</table>'
+ print_footer()
+
+
hunk ./darcsweb.cgi 2194
+ if "searchlimit" in dir(base):
+ config.searchlimit = base.searchlimit
+ else:
+ config.searchlimit = 100
+
hunk ./darcsweb.cgi 2373
+elif action == 'search':
+ if form.has_key('s'):
+ s = form["s"].value
+ else:
+ s = ''
+ do_search(s)
+ if config.cachedir:
+ cache.cancel()
+
hunk ./style.css 72
+div.search_box {
+ float:right;
+ text-align:right;
+}
+
+input.search_text {
+ font-size:xx-small;
+ background-color: #edece6;
+ vertical-align: top;
+}
+
+input.search_button {
+ font-size:xx-small;
+ vertical-align: top;
+}
+
hunk ./style.css 155
- clear:both;
+ /*clear:both;*/
hunk ./style.css 257
+
+img.logo {
+ border-width:0px;
+ vertical-align:top;
+ margin-left:12pt;
+ margin-right:5pt;
+}
}
Sun Jan 8 01:45:32 UTC 2006 Alberto Bertogli <albertogli@telpin.com.ar>
* Add the BOLA license.
darcsweb has been too long without an explicit license, it's time to add one.
Enjoy!
{
addfile ./LICENSE
hunk ./LICENSE 1
+
+I don't like licenses, because I don't like having to worry about all this
+legal stuff just for a simple piece of software I don't really mind anyone
+using. But I also believe that it's important that people share and give back;
+so I'm placing darcsweb under the following license, so you feel guilty if you
+don't ;)
+
+
+BOLA - Buena Onda License Agreement
+-----------------------------------
+
+This work is provided 'as-is', without any express or implied warranty. In no
+event will the authors be held liable for any damages arising from the use of
+this work.
+
+To all effects and purposes, this work is to be considered Public Domain.
+
+
+However, if you want to be "Buena onda", you should:
+
+1. Not take credit for it, and give proper recognition to the authors.
+2. Share your modifications, so everybody benefits from them.
+4. Do something nice for the authors.
+5. Help someone who needs it: sign up for some volunteer work or help your
+ neighbour paint the house.
+6. Don't waste. Anything, but specially energy that comes from natural
+ non-renovable resources. Extra points if you discover or invent something
+ to replace them.
+7. Be tolerant. Everything that's good in nature comes from cooperation.
+
+The order is important, and the further you go the more "Buena onda" you are.
+Make the world a better place: be "Buena onda".
+
+
}
Sat Dec 31 04:16:51 UTC 2005 Leandro Lucarella <luca@llucax.hn.org>
* Silly changes to avoid HTTP redirects.
{
hunk ./config.py.sample 65
- repourl = 'http://auriga.wearlab.de/~alb/repos/repo1'
+ repourl = 'http://auriga.wearlab.de/~alb/repos/repo1/'
hunk ./config.py.sample 85
- repourl = 'http://auriga.wearlab.de/~alb/repos/repo2'
+ repourl = 'http://auriga.wearlab.de/~alb/repos/repo2/'
hunk ./config.py.sample 107
- repourl = 'http://auriga.wearlab.de/~alb/repos/%(name)s'
+ repourl = 'http://auriga.wearlab.de/~alb/repos/%(name)s/'
}
Fri Dec 30 23:44:19 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Add autodesc and autoexclude options.
This patch implements two optional options for multidir repos: autodesc and
autoexclude.
If autodesc is enabled, the description will be taken from the file named
"_darcs/third_party/darcsweb/desc", inside the repository. If it doesn't
exist, the default will be used.
If autoexclude is enabled, only repositories with a directory named
"_darcs/third_party/darcsweb/" will be listed.
The path "_darcs/third_party/darcsweb/" for darcsweb-exclusive preferences was
chosen following a suggestion by David Roundy in the mail with Subject
"[darcs-users] darcsweb 0.12 and some questions", Message-ID
20051109123238.GB17288@abridgegame.org, date "9 Nov 2005 07:32:44".
{
hunk ./config.py.sample 113
+
+ # if you want the descriptions to be picked up automatically from the
+ # file named "_darcs/third_party/darcsweb/desc" (one line only), set
+ # this to True. It defaults to False
+ #autodesc = True
+
+ # if you want to exclude all the repositories which do NOT have a
+ # directory named "_darcs/third_party/darcsweb/" inside, set this to
+ # True. It defaults to False.
+ #autoexclude = True
hunk ./darcsweb.cgi 2016
+ if 'autoexclude' in dir(c) and c.autoexclude:
+ dpath = fulldir + \
+ '/_darcs/third_party/darcsweb'
+ if not os.path.isdir(dpath):
+ continue
+
+ if 'autodesc' in dir(c) and c.autodesc:
+ dpath = fulldir + \
+ '/_darcs/third_party/darcsweb/desc'
+ if os.access(dpath, os.R_OK):
+ desc = open(dpath).read()
+ else:
+ desc = c.repodesc % { 'name': name }
+ else:
+ desc = c.repodesc % { 'name': name }
+
hunk ./darcsweb.cgi 2033
- desc = c.repodesc % { 'name': name }
}
Fri Dec 30 21:08:43 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Escape filenames, just in case.
In the same spirit as the last patch, add escape() around prints of file
names. It's highly improbable, but it could happen for weird cases and it
seems worth the effort.
{
hunk ./darcsweb.cgi 738
- s = "-s " + fname
+ s = '-s "%s"' % fname
hunk ./darcsweb.cgi 903
- cmd += ' %s' % fname
+ cmd += ' "%s"' % fname
hunk ./darcsweb.cgi 965
- title += 'History for path %s' % fname
+ title += 'History for path %s' % escape(fname)
hunk ./darcsweb.cgi 1085
- print '<div class="page_path"><b>%s</b></div>' % fname
+ print '<div class="page_path"><b>%s</b></div>' % escape(fname)
hunk ./darcsweb.cgi 1372
- 'fname': fname,
+ 'fname': escape(fname),
hunk ./darcsweb.cgi 1397
- 'fname': fname,
+ 'fname': escape(fname),
hunk ./darcsweb.cgi 1420
- 'fname': fname,
+ 'fname': escape(fname),
hunk ./darcsweb.cgi 1446
- 'fname': fname,
+ 'fname': escape(fname),
hunk ./darcsweb.cgi 1484
- c = p.comment.replace('\n', '<br/>\n')
+ comment = escape(p.comment)
+ c = comment.replace('\n', '<br/>\n')
hunk ./darcsweb.cgi 1598
- (config.myreponame, sofar, p)
+ (config.myreponame, escape(sofar), p)
hunk ./darcsweb.cgi 1644
- 'f': f,
+ 'f': escape(f),
hunk ./darcsweb.cgi 1657
- 'f': f,
+ 'f': escape(f),
}
Tue Dec 27 03:19:14 UTC 2005 Michael Allan <mike@zelea.com>
* Escape patch names.
When patch names used in HTML, escape characters like '<'.
{
hunk ./darcsweb.cgi 1015
- 'name': shorten_str(p.name),
+ 'name': escape(shorten_str(p.name)),
hunk ./darcsweb.cgi 1266
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1290
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1319
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1344
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1371
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1396
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1419
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1445
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1481
- 'name': p.name,
+ 'name': escape(p.name),
hunk ./darcsweb.cgi 1486
- print p.name, '<br/><br/>'
+ print escape(p.name), '<br/><br/>'
}
Sat Dec 24 15:06:57 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Move the mimetypes import to the function.
While it's a nice practise to put all imports above, in darcsweb's case it
also increases startup latency.
Because the mimetypes module is only used inside print_binary_header(), move
the import inside the function.
{
hunk ./darcsweb.cgi 23
-import mimetypes
hunk ./darcsweb.cgi 399
+ import mimetypes
}
Wed Dec 21 22:24:47 UTC 2005 gaetan.lehmann@jouy.inra.fr
* enhance mime type for binary files
{
hunk ./darcsweb.cgi 23
+import mimetypes
hunk ./darcsweb.cgi 400
- print "Content-type: application/octet-stream"
+ if fname :
+ (mime, enc) = mimetypes.guess_type(fname)
+ else :
+ mime = None
+ if mime :
+ print "Content-type: %s" % mime
+ else :
+ print "Content-type: application/octet-stream"
}
Wed Dec 21 15:00:33 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Identify binary files in plainblob.
If we want to do a plainblob of a binary file, it's better to offer a proper
download than to display it as text/plain.
This patch identifies binary files (looking at darcs' information) and offers
them for download with the proper name.
{
hunk ./darcsweb.cgi 398
+def print_binary_header(fname = None):
+ print "Content-type: application/octet-stream"
+ if fname:
+ print "Content-Disposition:attachment;filename=%s" % fname
+ print
hunk ./darcsweb.cgi 1681
- print_plain_header()
hunk ./darcsweb.cgi 1682
- for l in f:
- sys.stdout.write(fixu8(l))
+
+ if isbinary(fname):
+ print_binary_header(os.path.basename(fname))
+ for l in f:
+ sys.stdout.write(l)
+ else:
+ print_plain_header()
+ for l in f:
+ sys.stdout.write(fixu8(l))
}
Wed Dec 21 14:29:46 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Indentation and comment changes to multidir_deep.
{
hunk ./config.py.sample 96
-# If you set multidir_deep to True then all subdirectories are searched
-# for darcs repositories. Subdirectories starting with a dot (.) are not
-# searched. This may be slow, if huge directory trees must be searched.
+# If you set multidir_deep to True (note the capitalization) then all
+# subdirectories are searched for darcs repositories. Subdirectories starting
+# with a dot (.) are not searched. This may be slow, if huge directory trees
+# must be searched. It's unnecesary unless you have a multidir with several
+# nested repositories. It defaults to False, and it's optional.
hunk ./config.py.sample 105
- multidir_deep = False
+ #multidir_deep = False
hunk ./darcsweb.cgi 1976
- for (root, dirs, files) in os.walk(c.multidir):
- # do not visit hidden directories
- dirs[:] = [d for d in dirs if not d.startswith('.')]
- if '_darcs' in dirs:
- entries.append(root[1+len(c.multidir):])
+ for (root, dirs, files) in os.walk(c.multidir):
+ # do not visit hidden directories
+ dirs[:] = [d for d in dirs \
+ if not d.startswith('.')]
+ if '_darcs' in dirs:
+ p = root[1 + len(c.multidir):]
+ entries.append(p)
hunk ./darcsweb.cgi 1984
- entries = os.listdir(c.multidir)
+ entries = os.listdir(c.multidir)
}
Tue Dec 20 16:30:22 UTC 2005 nils@ndecker.de
* Add deep recursion option to multidir configuration
{
hunk ./config.py.sample 96
+# If you set multidir_deep to True then all subdirectories are searched
+# for darcs repositories. Subdirectories starting with a dot (.) are not
+# searched. This may be slow, if huge directory trees must be searched.
+#
hunk ./config.py.sample 103
+ multidir_deep = False
hunk ./darcsweb.cgi 1973
- entries = os.listdir(c.multidir)
+
+ entries = []
+ if 'multidir_deep' in dir(c) and c.multidir_deep:
+ for (root, dirs, files) in os.walk(c.multidir):
+ # do not visit hidden directories
+ dirs[:] = [d for d in dirs if not d.startswith('.')]
+ if '_darcs' in dirs:
+ entries.append(root[1+len(c.multidir):])
+ else:
+ entries = os.listdir(c.multidir)
+
}
Wed Dec 21 13:47:50 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Indentation changes to the uncompression patch.
hunk ./darcsweb.cgi 756
- file = open(realf, 'rb')
- if file.read(2) == '\x1f\x8b':
- # file begins with gzip magic
- file.close()
- dsrc = gzip.open(realf)
- else:
- file.seek(0)
- dsrc = file
+ file = open(realf, 'rb')
+ if file.read(2) == '\x1f\x8b':
+ # file begins with gzip magic
+ file.close()
+ dsrc = gzip.open(realf)
+ else:
+ file.seek(0)
+ dsrc = file
Tue Dec 20 11:36:01 UTC 2005 nils@ndecker.de
* show raw for noncompressed patches
hunk ./darcsweb.cgi 756
- dsrc = gzip.open(realf)
+ file = open(realf, 'rb')
+ if file.read(2) == '\x1f\x8b':
+ # file begins with gzip magic
+ file.close()
+ dsrc = gzip.open(realf)
+ else:
+ file.seek(0)
+ dsrc = file
Mon Dec 19 17:42:02 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.13
{
}
Mon Dec 19 17:30:50 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Shorten the author string in shortlog.
hunk ./darcsweb.cgi 992
- 'author': p.shortauthor,
+ 'author': shorten_str(p.shortauthor, 26),
Tue Dec 13 14:12:44 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Small changes to do_atom(), make it validate.
{
hunk ./darcsweb.cgi 22
+import email.Utils
hunk ./darcsweb.cgi 237
+<link rel="alternate" title="%(reponame)s" href="%(url)s;a=atom"
+ type='application/atom+xml'/>
hunk ./darcsweb.cgi 1727
- print """<feed xmlns="http://www.w3.org/2005/Atom">
+ str_lastmod = time.strftime(iso_datetime,
+ time.localtime(repo_lastmod))
+
+ print """
+<feed xmlns="http://www.w3.org/2005/Atom">
hunk ./darcsweb.cgi 1734
- <link rel="self" type="application/atom+xml" href="%(url)s/%(reponame)s;a=atom"/>
+ <link rel="self" type="application/atom+xml" href="%(url)s;a=atom"/>
hunk ./darcsweb.cgi 1744
- 'lastmod': time.strftime(iso_datetime, time.localtime(repo_lastmod))}
+ 'lastmod': str_lastmod,
+ }
+
hunk ./darcsweb.cgi 1756
+ addr, author = email.Utils.parseaddr(p.author)
+ if not addr:
+ addr = "unknown_email@example.com"
+ if not author:
+ author = addr
+
hunk ./darcsweb.cgi 1765
- <author><name>%(author)s</name><!-- TODO: parse it to get the email. Not obvious, darcs authors can be anything --></author>
+ <author>
+ <name>%(author)s</name>
+ <email>%(email)s</email>
+ </author>
hunk ./darcsweb.cgi 1770
- <id>%(url)s/%(pname)s</id> <!-- TODO: find a better <id>, see RFC 4151 -->
+ <id>%(link)s</id>
hunk ./darcsweb.cgi 1773
+ <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
hunk ./darcsweb.cgi 1776
- 'author': p.author,
+ 'author': author,
+ 'email': addr,
hunk ./darcsweb.cgi 1780
+ 'myrname': config.myreponame,
+ 'hash': p.hash,
hunk ./darcsweb.cgi 1786
+
hunk ./darcsweb.cgi 1788
- print ' <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>'
hunk ./darcsweb.cgi 1802
-[_^I_][_$_]
+
}
Thu Dec 1 22:07:08 UTC 2005 stephane@sources.org
* ATOM support for syndication
{
hunk ./darcsweb.cgi 23
+iso_datetime = '%Y-%m-%dT%H:%M:%SZ'
hunk ./darcsweb.cgi 1719
+def do_atom():
+ print "Content-type: application/atom+xml; charset=utf-8\n"
+ print '<?xml version="1.0" encoding="utf-8"?>'
+ inv = config.repodir + '/_darcs/inventory'
+ repo_lastmod = os.stat(inv).st_mtime
+ print """<feed xmlns="http://www.w3.org/2005/Atom">
+ <title>%(reponame)s darcs repository</title>
+ <link rel="alternate" type="text/html" href="%(url)s"/>
+ <link rel="self" type="application/atom+xml" href="%(url)s/%(reponame)s;a=atom"/>
+ <id>%(url)s</id> <!-- TODO: find a better <id>, see RFC 4151 -->
+ <author><name>darcs repository (several authors)</name></author>
+ <generator>darcsweb.cgi</generator>
+ <updated>%(lastmod)s</updated> [_$_]
+ <subtitle>%(desc)s</subtitle>
+ """ % {
+ 'reponame': config.reponame,
+ 'url': config.myurl + '/' + config.myreponame,
+ 'desc': config.repodesc,
+ 'lastmod': time.strftime(iso_datetime, time.localtime(repo_lastmod))}
+ ps = get_last_patches(20)
+ for p in ps:
+ title = time.strftime('%d %b %H:%M', time.localtime(p.date))
+ title += ' - ' + p.name
+ pdate = time.strftime(iso_datetime,
+ time.localtime(p.date))
+ link = '%s/%s;a=commit;h=%s' % (config.myurl,
+ config.myreponame, p.hash)
hunk ./darcsweb.cgi 1747
+ print """
+ <entry>
+ <title>%(title)s</title>
+ <author><name>%(author)s</name><!-- TODO: parse it to get the email. Not obvious, darcs authors can be anything --></author>
+ <updated>%(pdate)s</updated>
+ <id>%(url)s/%(pname)s</id> <!-- TODO: find a better <id>, see RFC 4151 -->
+ <link rel="alternate" href="%(link)s"/>
+ <summary>%(desc)s</summary>
+ """ % {
+ 'title': escape(title),
+ 'author': p.author,
+ 'url': config.myurl + '/' + config.myreponame,
+ 'pdate': pdate,
+ 'pname': escape(p.name),
+ 'link': link,
+ 'desc': escape(p.name),
+ }
+ # TODO: allow to get plain text, not HTML?
+ print ' <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>'
+ print escape(p.name) + '<br/>'
+ if p.comment:
+ print '<br/>'
+ print escape(p.comment).replace('\n', '<br/>\n')
+ print '<br/>'
+ print '<br/>'
+ changed = p.adds + p.removes + p.modifies.keys() + \
+ p.moves.keys() + p.diradds + p.dirremoves + \
+ p.replaces.keys()
+ for i in changed: # TODO: link to the file [_$_]
+ print '<code>%s</code><br/>' % i
+ print '</p></div>'
+ print '</content></entry>'
+ print '</feed>'
+[_^I_][_$_]
hunk ./darcsweb.cgi 2192
+
+elif action == 'atom':
+ do_atom()
}
Tue Dec 13 13:28:49 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Use darcsweb.cgi's modification time to invalidate cache entries.
Besides the repository inventory modification time, we also want to check the
script's modification time, so if we make changes to darcsweb (updating it,
for instance), there's no possibility of serving stale pages if the user
forgets to clean the cache. You still need to clean it for configuration
changes.
{
hunk ./darcsweb.cgi 428
+ dw_lastmod = os.stat(sys.argv[0]).st_mtime
hunk ./darcsweb.cgi 430
- if repo_lastmod > cache_lastmod:
+ if repo_lastmod > cache_lastmod or dw_lastmod > cache_lastmod:
}
Wed Nov 30 11:36:26 UTC 2005 Kirill Smelkov <kirr@mns.spb.ru>
* fixu8: honour config.repoencoding when decoding characters like [_\e3]
hunk ./darcsweb.cgi 99
- char = char.decode('raw_unicode_escape')
+ char = char.decode(config.repoencoding)
Sat Nov 12 23:59:16 UTC 2005 Alexandre Rossi <niol@sousmonlit.dyndns.org>
* another basic validation issue
The issue was that there was an empty line before the XML declaration, which
is not valid.
hunk ./darcsweb.cgi 216
- print "Content-type: text/html; charset=utf-8\n"
+ print "Content-type: text/html; charset=utf-8"
Thu Nov 17 14:41:33 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Make how_old() return a fixed date when caching is enabled.
how_old() becomes a problem when we have a cache, because the relative dates
will get stalled in the cache.
This is makes a workaround by making how_old() return a string containing the
fixed date, which isn't quite nice but it will do the trick until a better
solution comes up.
hunk ./darcsweb.cgi 116
+ if config.cachedir:
+ # when we have a cache, the how_old() becomes a problem since
+ # the cached entries will have old data; so in this case just
+ # return a nice string
+ t = time.localtime(epoch)
+ s = time.strftime("%d %b %H:%M", t)
+ return s
Thu Nov 17 14:40:27 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Don't close the file in a cache miss.
hunk ./darcsweb.cgi 424
- close(self.file)
Thu Nov 17 03:27:57 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Call cache.cancel() only if we have a cache.
hunk ./darcsweb.cgi 2127
- cache.cancel()
+ if config.cachedir:
+ cache.cancel()
Thu Nov 17 03:10:28 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Implement a simple cache.
This patch implements a very simple but effective cache, so darcsweb can avoid
regenerating everything all the time.
Based on an idea from Alexandre Rossi.
{
hunk ./config.py.sample 32
+ # It is possible to have a cache where darcsweb will store the pages
+ # it generates; entries are automatically updated when the repository
+ # changes. This will speed things up significatively, specially for
+ # popular sites.
+ # It's recommended that you clean the directory with some regularity,
+ # to avoid having too many unused files. A simple rm will do just
+ # fine.
+ # If you leave the entry commented, no cache will be ever used;
+ # otherwise the directory is assumed to exist and be writeable.
+ #cachedir = '/tmp/darcsweb-cache'
+
hunk ./darcsweb.cgi 16
+import sha
hunk ./darcsweb.cgi 386
+
+
+
+#
+# basic caching
+#
+
+class Cache:
+ def __init__(self, basedir, url):
+ self.basedir = basedir
+ self.url = url
+ self.fname = sha.sha(url).hexdigest()
+ self.file = None
+ self.mode = None
+ self.real_stdout = sys.stdout
+
+ def open(self):
+ "Returns 1 on hit, 0 on miss"
+ fname = self.basedir + '/' + self.fname
+
+ if not os.access(fname, os.R_OK):
+ # the file doesn't exist, direct miss
+ pid = str(os.getpid())
+ fname = self.basedir + '/.' + self.fname + '-' + pid
+ self.file = open(fname, 'w')
+ self.mode = 'w'
+
+ # step over stdout so when "print" tries to write
+ # output, we get it first
+ sys.stdout = self
+ return 0
+
+ inv = config.repodir + '/_darcs/inventory'
+ cache_lastmod = os.stat(fname).st_mtime
+ repo_lastmod = os.stat(inv).st_mtime
+
+ if repo_lastmod > cache_lastmod:
+ # the entry is too old, remove it and return a miss
+ close(self.file)
+ os.unlink(fname)
+
+ pid = str(os.getpid())
+ fname = self.basedir + '/.' + self.fname + '-' + pid
+ self.file = open(fname, 'w')
+ self.mode = 'w'
+ sys.stdout = self
+ return 0
+
+ # the entry is still valid, hit!
+ self.file = open(fname, 'r')
+ self.mode = 'r'
+ return 1
+
+
+ def dump(self):
+ for l in self.file:
+ self.real_stdout.write(l)
+
+ def write(self, s):
+ # this gets called from print, because we replaced stdout with
+ # ourselves
+ self.file.write(s)
+ self.real_stdout.write(s)
+
+ def close(self):
+ if self.file:
+ self.file.close()
+ sys.stdout = self.real_stdout
+ if self.mode == 'w':
+ pid = str(os.getpid())
+ fname1 = self.basedir + '/.' + self.fname + '-' + pid
+ fname2 = self.basedir + '/' + self.fname
+ os.rename(fname1, fname2)
+ self.mode = 'c'
+
+ def cancel(self):
+ "Like close() but don't save the entry."
+ if self.file:
+ self.file.close()
+ sys.stdout = self.real_stdout
+ if self.mode == 'w':
+ pid = str(os.getpid())
+ fname = self.basedir + '/.' + self.fname + '-' + pid
+ os.unlink(fname)
+ self.mode = 'c'
hunk ./darcsweb.cgi 1782
- sys.exit(1)
hunk ./darcsweb.cgi 1947
+
+ if "cachedir" in dir(base):
+ config.cachedir = base.cachedir
+ else:
+ config.cachedir = None
hunk ./darcsweb.cgi 1960
+
hunk ./darcsweb.cgi 1985
+
+# check if we have the page in the cache
+if config.cachedir:
+ url_request = os.environ['QUERY_STRING']
+ cache = Cache(config.cachedir, url_request)
+ if cache.open():
+ # we have a hit, dump and run
+ cache.dump()
+ cache.close()
+ sys.exit(0)
+ # if there is a miss, the cache will step over stdout, intercepting
+ # all "print"s and writing them to the cache file automatically
hunk ./darcsweb.cgi 2127
+ cache.cancel()
hunk ./darcsweb.cgi 2130
+if config.cachedir:
+ cache.close()
}
Thu Nov 10 15:22:39 UTC 2005 Leandro Lucarella <luca@llucax.hn.org>
* Use a more human-friendly format por list configuration variables.
hunk ./config.py.sample 94
- #exclude = [ 'dir1', 'dir2' ]
+ #exclude = 'dir1', 'dir2'
Thu Nov 10 00:34:34 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Highlight tags in the shortlog/summary.
{
hunk ./darcsweb.cgi 873
- if alt:
+ if p.name.startswith("TAG "):
+ print '<tr class="tag">'
+ elif alt:
hunk ./style.css 161
+.tag {
+ background-color:#f0f0ff;
+}
+
+.tag:hover {
+ background-color:#e0e0ff;
+}
+
}
Wed Nov 9 23:59:47 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Add exclusion lists to multidir configuration.
{
hunk ./config.py.sample 92
+ # if you want to exclude some directories, add them to this list (note
+ # they're relative to multidir, not absolute)
+ #exclude = [ 'dir1', 'dir2' ]
+
hunk ./darcsweb.cgi 1786
+ if 'exclude' not in dir(c):
+ c.exclude = []
hunk ./darcsweb.cgi 1795
+ continue
+ if name in c.exclude:
}
Wed Nov 9 01:10:31 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.12
{
}
Wed Nov 9 00:57:34 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Consider only directories with "_darcs" inside for multidir entries.
In multidir configuration entries, skip all the directories that don't have a
"_darcs" inside.
hunk ./darcsweb.cgi 1792
- if not os.path.isdir(fulldir):
+ if not os.path.isdir(fulldir + '/_darcs'):
Wed Nov 9 00:43:55 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Extend escape() to escape '"' too.
{
hunk ./darcsweb.cgi 20
-from xml.sax.saxutils import escape
+from xml.sax.saxutils import escape as xml_escape
hunk ./darcsweb.cgi 109
+def escape(s):
+ s = xml_escape(s)
+ s = s.replace('"', '"')
+ return s
hunk ./darcsweb.cgi 897
- 'fullname': p.name,
+ 'fullname': escape(p.name),
}
Wed Nov 9 00:30:02 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Don't show the owner if there is none
{
hunk ./darcsweb.cgi 392
- author = "Unknown owner <unknown@example.org>"
+ author = None
hunk ./darcsweb.cgi 1119
- print ' <tr><td>owner</td><td>%s</td></tr>' % escape(owner)
+ if owner:
+ print ' <tr><td>owner</td><td>%s</td></tr>' % escape(owner)
}
Wed Nov 9 00:23:06 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Add some checks to the multidir handling.
Check if the entry is a directory and doesn't begin with a dot.
Besides, sort it so the listing appears in predictable order.
{
hunk ./darcsweb.cgi 1782
+ entries.sort()
hunk ./darcsweb.cgi 1784
- rdir = c.multidir + '/' + name
+ if name.startswith('.'):
+ continue
+ fulldir = c.multidir + '/' + name
+ if not os.path.isdir(fulldir):
+ continue
+
+ rdir = fulldir
}
Wed Nov 9 00:17:31 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Implement "multidir" configuration entries.
This patch implements a special configuration entry called "multidir" that can
be useful when you have a lot of repositories in the same directory and don't
want to create an entry for each one.
{
hunk ./config.py.sample 78
+#
+# If you have several repositories in a single directory and don't want to
+# create a configuration entry for each one, you can use a "multidir" entry,
+# which serves as a "template" for all the repositories in that directory.
+# The name is taken from the directory, and inside the variables the string
+# "%(name)s" gets expanded to the it.
+#
+
+class multi1:
+ multidir = '/usr/local/src'
+ repodesc = 'Repository for %(name)s'
+ repourl = 'http://auriga.wearlab.de/~alb/repos/%(name)s'
+ repoencoding = 'latin1'
+
+
hunk ./darcsweb.cgi 1737
+ expand_multi_config(all_configs)
hunk ./darcsweb.cgi 1768
+def expand_multi_config(config):
+ """Expand configuration entries that serve as "template" to others;
+ this make it easier to have a single directory with all the repos,
+ because they don't need specific entries in the configuration anymore.
+ """
+
+ for conf in dir(config):
+ if conf.startswith('__'):
+ continue
+ c = config.__getattribute__(conf)
+ if 'multidir' not in dir(c):
+ continue
+
+ entries = os.listdir(c.multidir)
+ for name in entries:
+ rdir = c.multidir + '/' + name
+ desc = c.repodesc % { 'name': name }
+ url = c.repourl % { 'name': name }
+ class tmp_config:
+ reponame = name
+ repodir = rdir
+ repodesc = desc
+ repourl = url
+ repoencoding = c.repoencoding
+ if 'footer' in dir(c):
+ footer = c.footer
+ config.__setattr__(name, tmp_config)
+
hunk ./darcsweb.cgi 1798
+ expand_multi_config(all_configs)
}
Mon Oct 31 10:24:23 UTC 2005 Michal Sojka <sojkam1@fel.cvut.cz>
* Fix for an error that appears when run on empty repository.
hunk ./darcsweb.cgi 1120
- print ' <tr><td>last change</td><td>%s</td></tr>' % \
+ if len(ps) > 0:
+ print ' <tr><td>last change</td><td>%s</td></tr>' % \
Sun Nov 6 23:48:38 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Show the patch name in the description in do_commit().
hunk ./darcsweb.cgi 1359
- c = p.comment.replace('\n', '<br/>')
- print '<div class="page_body">', c, '</div>'
+ c = p.comment.replace('\n', '<br/>\n')
+ print '<div class="page_body">'
+ print p.name, '<br/><br/>'
+ print c
+ print '</div>'
Mon Oct 31 00:11:03 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Simplify the "Verbose Annotate Sidebar" patch.
This patch makes it simpler, because it skips displaying the full author name
and how long ago the changes were made; besides some simple fixes.
The rationale behind this is purely aesthetic: the author is already available
in the tooltip (and you should be able to tell anyway by its nickname), and
the "how long ago" was a bit distracting. All this is completely subjective, I
know, but I think these are "safe" settings.
{
hunk ./darcsweb.cgi 1072
- if (style == "shade" or style == "zebra") and line == 1:
- ptime = " " + time.strftime("%H:%M:%S", l.pdate)
- newblock = False
- desc = "%12.12s" % how_old(time.mktime(l.pdate)) [_$_]
- date = "%-10.10s" % ptime
- line = 2
- elif line == 2:
- desc = "%22.22s" % l.pauthor
- date = ""
- line = 3
- elif line == 3:
- desc = "%12.12s" % ""
- date = "%-10.10s" % ""
+ if line == 1 and style in ["shade", "zebra"]:
+ t = "%s " % time.strftime("%H:%M:%S", l.pdate)
+ desc = "%12.12s" % "'"
+ date = "%-10.10s" % t
hunk ./darcsweb.cgi 1079
+ line += 1
}
Thu Sep 29 22:09:49 UTC 2005 Max Battcher <me@worldmaker.net>
* Verbose Annotate Sidebar
In shade or zebra annotate modes, this patch displays a second
and third line of information in a contiguous single patch code block.
:First Line: ``DATE AUTHOR_SHORT_NAME`` (Same as before)
:Second Line: ``TIME RELATIVE_TIME``
:Third Line: ``FULL_AUTHOR_EMAIL``
All following lines in the code block are blank.
{
hunk ./darcsweb.cgi 1067
- desc = "%12.12s" % escape(shortau)
+ desc = "%12.12s" % shortau
hunk ./darcsweb.cgi 1070
+ line = 1
hunk ./darcsweb.cgi 1072
- desc = "%12.12s" % "'"
- date = "%-10.10s" % ""
+ if (style == "shade" or style == "zebra") and line == 1:
+ ptime = " " + time.strftime("%H:%M:%S", l.pdate)
+ newblock = False
+ desc = "%12.12s" % how_old(time.mktime(l.pdate)) [_$_]
+ date = "%-10.10s" % ptime
+ line = 2
+ elif line == 2:
+ desc = "%22.22s" % l.pauthor
+ date = ""
+ line = 3
+ elif line == 3:
+ desc = "%12.12s" % ""
+ date = "%-10.10s" % ""
+ else:
+ desc = "%12.12s" % "'"
+ date = "%-10.10s" % ""
hunk ./darcsweb.cgi 1099
- 'desc': desc,
+ 'desc': escape(desc),
}
Sun Oct 30 23:23:47 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Include a list of changed files in each RSS description.
hunk ./darcsweb.cgi 1661
+ print '<br/>'
+ print '<br/>'
+ changed = p.adds + p.removes + p.modifies.keys() + \
+ p.moves.keys() + p.diradds + p.dirremoves + \
+ p.replaces.keys()
+ for i in changed:
+ print '%s<br/>' % i
Sun Oct 30 21:54:41 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Add full name as a tooltip in shortlog.
{
hunk ./darcsweb.cgi 879
- <a class="list" href="%(myrname)s;a=commit;h=%(hash)s"><b>%(name)s</b></a>
+ <a class="list" title="%(fullname)s" href="%(myrname)s;a=commit;h=%(hash)s">
+ <b>%(name)s</b>
+ </a>
hunk ./darcsweb.cgi 893
+ 'fullname': p.name,
}
Thu Oct 27 10:02:09 UTC 2005 Alexandre Rossi <niol@sousmonlit.dyndns.org>
* css: cleared table to avoid cell wrap due to logo
hunk ./style.css 139
+ clear:both;
Wed Oct 26 12:28:15 UTC 2005 Alexandre Rossi <niol@sousmonlit.dyndns.org>
* fixed small validation issue in XML header
{
hunk ./darcsweb.cgi 1676
+ print '<?xml version="1.0" encoding="utf-8"?>'
hunk ./darcsweb.cgi 1678
-<?xml version="1.0" encoding="utf-8"?>
}
Mon Oct 3 04:57:19 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Put a '/' after the path in do_tree().
hunk ./darcsweb.cgi 1467
- path = realpath(dname)
+ path = realpath(dname) + '/'
Mon Oct 3 04:51:44 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Make shade the default annotate style.
{
hunk ./darcsweb.cgi 277
-| <a href="%(myreponame)s;a=annotate;f=%(fname)s;h=%(hash)s">annotate</a>
+| <a href="%(myreponame)s;a=annotate_shade;f=%(fname)s;h=%(hash)s">annotate</a>
hunk ./darcsweb.cgi 285
-| <a href="%(myreponame)s;a=annotate;f=%(fname)s">annotate</a>
+| <a href="%(myreponame)s;a=annotate_shade;f=%(fname)s">annotate</a>
hunk ./darcsweb.cgi 366
-<a href="%(myreponame)s;a=annotate;f=%(fname)s;h=%(hash)s">normal</a>
+<a href="%(myreponame)s;a=annotate_normal;f=%(fname)s;h=%(hash)s">normal</a>
hunk ./darcsweb.cgi 1429
- <a href="%(myreponame)s;a=annotate;h=%(hash)s;f=%(file)s">annotate</a>
+ <a href="%(myreponame)s;a=annotate_shade;h=%(hash)s;f=%(file)s">annotate</a>
hunk ./darcsweb.cgi 1514
- <a href="%(myrname)s;a=annotate;f=%(fullf)s">annotate</a>
+ <a href="%(myrname)s;a=annotate_shade;f=%(fullf)s">annotate</a>
hunk ./darcsweb.cgi 1883
-elif action == "annotate":
+elif action == "annotate_normal":
}
Mon Oct 3 04:47:34 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Use the real file if there's no pristine directory available.
{
hunk ./darcsweb.cgi 192
+def realpath(fname):
+ realf = filter_file(config.repodir + '/_darcs/current/' + fname)
+ if not os.path.exists(realf):
+ realf = filter_file(config.repodir + '/' + fname)
+ return realf
hunk ./darcsweb.cgi 198
+
hunk ./darcsweb.cgi 263
+| <a href="%(myreponame)s;a=tree">tree</a>
hunk ./darcsweb.cgi 266
- if os.path.isdir(config.repodir + '/_darcs/current/'):
- # the current directory is missing if the --no-pristine-tree
- # option was used in darcs get, so we only show the link if
- # the directory exists
- print '| <a href="%s;a=tree">tree</a>' % config.myreponame
-
hunk ./darcsweb.cgi 273
- realf = filter_file(config.repodir + '/_darcs/current/' + f)
+ realf = realpath(f)
hunk ./darcsweb.cgi 968
- f = open(config.repodir + '/_darcs/current/' + fname, 'r')
+ f = open(realpath(fname), 'r')
hunk ./darcsweb.cgi 1467
- realpath = config.repodir + '/_darcs/current/' + dname + '/'
+ path = realpath(dname)
+
hunk ./darcsweb.cgi 1470
- files = os.listdir(realpath)
+ files = os.listdir(path)
hunk ./darcsweb.cgi 1477
- realfile = realpath + f
+ if f == "_darcs":
+ continue
+ realfile = path + f
hunk ./darcsweb.cgi 1492
- realfile = realpath + f
+ realfile = path + f
hunk ./darcsweb.cgi 1552
- f = open(config.repodir + '/_darcs/current/' + fname, 'r')
+ f = open(realpath(fname), 'r')
}
Wed Sep 21 18:36:17 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Handle plain emails in annotate's author parsing.
hunk ./darcsweb.cgi 1058
+ elif right != -1:
+ shortau = l.pauthor[:right]
Wed Sep 21 18:24:58 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Shade and zebra styles for annotate.
This patch adds two more annotate styles: zebra and shade.
Zebra alternates the line background colour according to the patch, just like
most CVS viewers do.
Shade is a lot more fun: it gives each patch a shade of a colour, the newer
the brighter, so newer patches (which are often the ones you're intrested in)
are easier to spot. It could use a little tuning on some constants to make it
look better, but it's pretty usable as is, and it can be done later if needed.
Thanks to Max Battcher for the idea.
{
hunk ./darcsweb.cgi 361
- elif f and h and action == "annotate":
+
+ elif f and h and action.startswith("annotate"):
hunk ./darcsweb.cgi 365
-<a href="%(myreponame)s;a=annotate_plain;f=%(fname)s;h=%(hash)s">plain</a>
+<a href="%(myreponame)s;a=annotate;f=%(fname)s;h=%(hash)s">normal</a>
+| <a href="%(myreponame)s;a=annotate_plain;f=%(fname)s;h=%(hash)s">plain</a>
+| <a href="%(myreponame)s;a=annotate_shade;f=%(fname)s;h=%(hash)s">shade</a>
+| <a href="%(myreponame)s;a=annotate_zebra;f=%(fname)s;h=%(hash)s">zebra</a>
hunk ./darcsweb.cgi 986
-def print_annotate(ann):
+def print_annotate(ann, style):
hunk ./darcsweb.cgi 995
+ if style == 'shade':
+ # here's the idea: we will assign to each patch a shade of
+ # color from its date (newer gets darker)
+ max = 0xff
+ min = max - 80
+
+ # to do that, we need to get a list of the patch hashes
+ # ordered by their dates
+ l = [ (date, hash) for (hash, date) in ann.patches.items() ]
+ l.sort()
+ l = [ hash for (date, hash) in l ]
+
+ # now we have to map each element to a number in the range
+ # min-max, with max being close to l[0] and min l[len(l) - 1]
+ lenn = max - min
+ lenl = len(l)
+ shadetable = {}
+ for i in range(0, lenl):
+ hash = l[i]
+ n = float(i * lenn) / lenl
+ n = max - int(round(n))
+ shadetable[hash] = n
+ elif style == "zebra":
+ lineclass = 'dark'
+
hunk ./darcsweb.cgi 1034
+ if style == "shade":
+ linestyle = 'style="background-color:#ffff%.2x"' % \
+ shadetable[l.phash]
+ lineclass = ''
+ elif style == "zebra":
+ linestyle = ''
+ if l.phash != prevhash:
+ if lineclass == 'dark':
+ lineclass = 'light'
+ else:
+ lineclass = 'dark'
+ else:
+ linestyle = ''
+ lineclass = ''
+
hunk ./darcsweb.cgi 1069
-<div class="pre">\
+<div class="pre %(class)s" %(style)s>\
hunk ./darcsweb.cgi 1075
+ 'class': lineclass,
+ 'style': linestyle,
hunk ./darcsweb.cgi 1551
-def do_annotate(fname, phash):
+def do_annotate(fname, phash, style):
hunk ./darcsweb.cgi 1570
- print_annotate(ann)
+ print_annotate(ann, style)
hunk ./darcsweb.cgi 1883
- do_annotate(fname, phash)
+ do_annotate(fname, phash, "normal")
hunk ./darcsweb.cgi 1891
+elif action == "annotate_zebra":
+ fname = filter_file(form["f"].value)
+ if form.has_key("h"):
+ phash = filter_hash(form["h"].value)
+ else:
+ phash = None
+ do_annotate(fname, phash, "zebra")
+elif action == "annotate_shade":
+ fname = filter_file(form["f"].value)
+ if form.has_key("h"):
+ phash = filter_hash(form["h"].value)
+ else:
+ phash = None
+ do_annotate(fname, phash, "shade")
hunk ./style.css 148
-tr.light:hover {
+.light:hover {
hunk ./style.css 152
-tr.dark {
+.dark {
hunk ./style.css 156
-tr.dark:hover {
+.dark:hover {
}
Wed Sep 21 05:51:22 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Gather more information from annotate parsing.
Add a list of patches with their dates to the annotate object, because we'll
want to use them in patches to come. Also store the date in tuple format and
let the users do the conversion to text as they need to.
{
hunk ./darcsweb.cgi 674
+ self.lastchange_date = None
+ self.firstdate = None
+ self.lastdate = None
hunk ./darcsweb.cgi 678
+ self.patches = {}
hunk ./darcsweb.cgi 685
+ self.pdate = None
hunk ./darcsweb.cgi 720
- lastdate = time.strftime("%Y-%m-%d %H:%M:%S", lastdate)
- annotate.lastchange_date = fixu8(lastdate)
+ annotate.lastchange_date = lastdate
+
+ annotate.patches[annotate.lastchange_hash] = annotate.lastchange_date
+
+ # these will be overriden by the real dates later
+ annotate.firstdate = lastdate
+ annotate.lastdate = 0
hunk ./darcsweb.cgi 742
- pdate = time.strftime("%Y-%m-%d %H:%M:%S", pdate)
hunk ./darcsweb.cgi 762
- line.pdate = fixu8(pdate)
+ line.pdate = pdate
hunk ./darcsweb.cgi 764
+ annotate.patches[line.phash] = line.pdate
+
+ if pdate > annotate.lastdate:
+ annotate.lastdate = pdate
+ if pdate < annotate.firstdate:
+ annotate.firstdate = pdate
hunk ./darcsweb.cgi 997
- title = "%s by %s" % (l.pdate, escape(l.pauthor) )
+ plongdate = time.strftime("%Y-%m-%d %H:%M:%S", l.pdate)
+ title = "%s by %s" % (plongdate, escape(l.pauthor) )
hunk ./darcsweb.cgi 1006
- pdate = time.strptime(l.pdate, "%Y-%m-%d %H:%M:%S")
- pdate = time.strftime("%Y-%m-%d", pdate)
+ pdate = time.strftime("%Y-%m-%d", l.pdate)
}
Tue Sep 20 18:46:54 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
tagged 0.11
{
}
Tue Sep 20 18:13:33 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Indent a comment.
Yeah, I feel stupid creating a patch just for this, but my 80-column terminal
just hurts when I look at this line.
hunk ./darcsweb.cgi 96
- # finally, replace s with our new improved string, and repeat
- # the ugly procedure
+ # finally, replace s with our new improved string, and
+ # repeat the ugly procedure
Tue Sep 20 07:40:25 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Add patch description to print_annotate().
Add a column to the left of the annotate output, just before the line number,
to show the date (but not time) and author (in a short form).
{
hunk ./darcsweb.cgi 977
+ prevhash = None
hunk ./darcsweb.cgi 988
+
+ if l.phash != prevhash:
+ pdate = time.strptime(l.pdate, "%Y-%m-%d %H:%M:%S")
+ pdate = time.strftime("%Y-%m-%d", pdate)
+
+ left = l.pauthor.find('<')
+ right = l.pauthor.find('@')
+ if left != -1 and right != -1:
+ shortau = l.pauthor[left + 1:right]
+ elif l.pauthor.find(" ") != -1:
+ shortau = l.pauthor[:l.pauthor.find(" ")]
+ else:
+ shortau = l.pauthor
+
+ desc = "%12.12s" % escape(shortau)
+ date = "%-10.10s" % pdate
+ prevhash = l.phash
+ else:
+ desc = "%12.12s" % "'"
+ date = "%-10.10s" % ""
+
hunk ./darcsweb.cgi 1011
+<a href="%(link)s" title="%(title)s" class="annotate_desc">%(date)s %(desc)s</a> \
hunk ./darcsweb.cgi 1016
+ 'date': date,
+ 'desc': desc,
hunk ./style.css 195
- right:12px
+ right:12px;
hunk ./style.css 200
- text-decoration:none
+ text-decoration:none;
+}
+
+a.annotate_desc {
+ color:#999999;
+ text-decoration:none;
+ font-size:11px;
+}
+
+a.annotate_desc:hover {
+ color:#880000;
}
Tue Sep 20 07:31:31 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Replace tabs in annotate output.
hunk ./darcsweb.cgi 980
+ text = replace_tabs(text)
Tue Sep 20 07:01:50 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Replace tabs with spaces for nicer output.
Tabs need to be replaced with spaces to avoid problems displaying lines that
begin with tabs.
This patch implements a very simple function to do so, and modifices
print_blob() to use it.
{
hunk ./darcsweb.cgi 142
+def replace_tabs(s):
+ pos = s.find("\t")
+ while pos != -1:
+ count = 8 - (pos % 8)
+ if count:
+ spaces = ' ' * count
+ s = s.replace('\t', spaces, 1)
+ pos = s.find("\t")
+ return s
+
hunk ./darcsweb.cgi 954
+ l = replace_tabs(l)
}
Mon Sep 19 06:30:38 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Use UTF8 for plain output.
Make the plain outputs use UTF8 too, as it's the only sane option.
{
hunk ./darcsweb.cgi 365
- print "Content-type: text/plain\n"
+ print "Content-type: text/plain; charset=utf-8\n"
hunk ./darcsweb.cgi 1041
- sys.stdout.write(l)
+ sys.stdout.write(fixu8(l))
hunk ./darcsweb.cgi 1094
- sys.stdout.write(l)
+ sys.stdout.write(fixu8(l))
hunk ./darcsweb.cgi 1146
- sys.stdout.write(l)
+ sys.stdout.write(fixu8(l))
hunk ./darcsweb.cgi 1194
- sys.stdout.write(l)
+ sys.stdout.write(fixu8(l))
hunk ./darcsweb.cgi 1450
- sys.stdout.write(l)
+ sys.stdout.write(fixu8(l))
}
Mon Sep 19 06:20:23 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Fix some UTF8 handling in annotate, and add tooltips.
This patch fixes some of the UTF8 handling in different annotate parts.
Accidentally, it also includes a small modification to show for each line of
the annotate the last modification time, date and author as a tooltip. It'd be
nice to put this in a different patch.
{
hunk ./darcsweb.cgi 686
- annotate.fname = file.getAttribute("name")
+ annotate.fname = fixu8(file.getAttribute("name"))
hunk ./darcsweb.cgi 689
- annotate.created_as = createinfo.getAttribute("original_name")
+ annotate.created_as = fixu8(createinfo.getAttribute("original_name"))
hunk ./darcsweb.cgi 692
- annotate.creator_hash = creator.getAttribute("hash")
+ annotate.creator_hash = fixu8(creator.getAttribute("hash"))
hunk ./darcsweb.cgi 696
- annotate.lastchange_hash = lastpatch.getAttribute("hash")
- annotate.lastchange_author = lastpatch.getAttribute("author")
+ annotate.lastchange_hash = fixu8(lastpatch.getAttribute("hash"))
+ annotate.lastchange_author = fixu8(lastpatch.getAttribute("author"))
hunk ./darcsweb.cgi 701
- annotate.lastchange_name = lastname
+ annotate.lastchange_name = fixu8(lastname)
+
+ lastdate = lastpatch.getAttribute("date")
+ lastdate = time.strptime(lastdate, "%Y%m%d%H%M%S")
+ lastdate = time.strftime("%Y-%m-%d %H:%M:%S", lastdate)
+ annotate.lastchange_date = fixu8(lastdate)
hunk ./darcsweb.cgi 720
+ pdate = patch.getAttribute("date")
+ pdate = time.strptime(pdate, "%Y%m%d%H%M%S")
+ pdate = time.strftime("%Y-%m-%d %H:%M:%S", pdate)
hunk ./darcsweb.cgi 728
+ pdate = annotate.lastchange_date
hunk ./darcsweb.cgi 740
- line.text = text
- line.phash = phash
- line.pauthor = pauthor
+ line.text = fixu8(text)
+ line.phash = fixu8(phash)
+ line.pauthor = fixu8(pauthor)
+ line.pdate = fixu8(pdate)
hunk ./darcsweb.cgi 967
- text = fixu8(escape(l.text))
+ text = escape(l.text)
hunk ./darcsweb.cgi 969
+ title = "%s by %s" % (l.pdate, escape(l.pauthor) )
hunk ./darcsweb.cgi 977
-<a href="%(link)s" class="linenr">%(c)4d</a> \
-<a href="%(link)s" class="line">%(text)s</a>\
+<a href="%(link)s" title="%(title)s" class="linenr">%(c)4d</a> \
+<a href="%(link)s" title="%(title)s" class="line">%(text)s</a>\
hunk ./darcsweb.cgi 983
+ 'title': title,
hunk ./darcsweb.cgi 1457
-
hunk ./darcsweb.cgi 1468
- 'name': ann.lastchange_name,
- 'fname': fname,
+ 'name': escape(ann.lastchange_name),
+ 'fname': escape(fname),
}
Mon Sep 19 03:19:14 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Convert the annotate source to UTF8 before parsing.
hunk ./darcsweb.cgi 676
- dom = xml.dom.minidom.parse(src)
+
+ # FIXME: convert the source to UTF8; it _has_ to be a way to let
+ # minidom know the source encoding
+ s = ""
+ for i in src:
+ s += fixu8(i)
+
+ dom = xml.dom.minidom.parseString(s)
Mon Sep 12 13:13:54 UTC 2005 Toni Timonen <ttimonen@movial.fi>
* Fix validity problem with rss feeds and unknown email addresses.
hunk ./darcsweb.cgi 1515
- author = "%s <unknown@email>" % p.author
+ author = "%s <unknown@email>" % p.author
Mon Sep 19 02:50:04 UTC 2005 Alberto Bertogli <albertogli@telpin.com.ar>
* Implement annotate.
Finally!
{
hunk ./darcsweb.cgi 264
+ if f and h:
+ print """
+| <a href="%(myreponame)s;a=annotate;f=%(fname)s;h=%(hash)s">annotate</a>
+ """ % {
+ 'myreponame': config.myreponame,
+ 'hash': h,
+ 'fname': f
+ }
+ elif f:
+ print """
+| <a href="%(myreponame)s;a=annotate;f=%(fname)s">annotate</a>
+ """ % { "myreponame": config.myreponame, 'fname': f }
+
hunk ./darcsweb.cgi 281
- # TODO: annotate, when it's implemented
hunk ./darcsweb.cgi 351
+ elif f and h and action == "annotate":
+ # same for annotate
+ print """
+<a href="%(myreponame)s;a=annotate_plain;f=%(fname)s;h=%(hash)s">plain</a>
+ """ % {
+ "myreponame": config.myreponame,
+ "fname": f,
+ "hash": h
+ }
hunk ./darcsweb.cgi 655
+
+class Annotate:
+ def __init__(self):
+ self.fname = ""
+ self.creator_hash = ""
+ self.created_as = ""
+ self.lastchange_hash = ""
+ self.lastchange_author = ""
+ self.lastchange_name = ""
+ self.lines = []
+
+ class Line:
+ def __init__(self):
+ self.text = ""
+ self.phash = None
+ self.pauthor = None
+
+def parse_annotate(src):
+ import xml.dom.minidom
+
+ annotate = Annotate()
+ dom = xml.dom.minidom.parse(src)
+
+ file = dom.getElementsByTagName("file")[0]
+ annotate.fname = file.getAttribute("name")
+
+ createinfo = dom.getElementsByTagName("created_as")[0]
+ annotate.created_as = createinfo.getAttribute("original_name")
+
+ creator = createinfo.getElementsByTagName("patch")[0]
+ annotate.creator_hash = creator.getAttribute("hash")
+
+ mod = dom.getElementsByTagName("modified")[0]
+ lastpatch = mod.getElementsByTagName("patch")[0]
+ annotate.lastchange_hash = lastpatch.getAttribute("hash")
+ annotate.lastchange_author = lastpatch.getAttribute("author")
+
+ lastname = lastpatch.getElementsByTagName("name")[0]
+ lastname = lastname.childNodes[0].wholeText
+ annotate.lastchange_name = lastname
+
+ file = dom.getElementsByTagName("file")[0]
+
+ for l in file.childNodes:
+ # we're only intrested in normal and added lines
+ if l.nodeName not in ["normal_line", "added_line"]:
+ continue
+ line = Annotate.Line()
+
+ if l.nodeName == "normal_line":
+ patch = l.getElementsByTagName("patch")[0]
+ phash = patch.getAttribute("hash")
+ pauthor = patch.getAttribute("author")
+ else:
+ # added lines inherit the creation from the annotate
+ # patch
+ phash = annotate.lastchange_hash
+ pauthor = annotate.lastchange_author
+
+ text = ""
+ for node in l.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ text += node.wholeText
+
+ # strip all "\n"s at the beginning; because the way darcs
+ # formats the xml output it makes the DOM parser to add "\n"s
+ # in front of it
+ text = text.lstrip("\n")
+
+ line.text = text
+ line.phash = phash
+ line.pauthor = pauthor
+ annotate.lines.append(line)
+
+ return annotate
+
+def get_annotate(fname, hash = None):
+ cmd = 'annotate --xml-output'
+ if hash:
+ cmd += ' --match="hash %s"' % hash
+ cmd += ' %s' % fname
+ out = run_darcs(cmd)
+ return parse_annotate(out)
+
+
+
hunk ./darcsweb.cgi 939
+def print_annotate(ann):
+ print '<div class="page_body">'
+ if isbinary(ann.fname):
+ print """
+<i>This is a binary file and it's contents will not be displayed.</i>
+</div>
+ """
+ return
+
+ count = 1
+ for l in ann.lines:
+ text = fixu8(escape(l.text))
+ text = text.rstrip()
+
+ link = "%(myrname)s;a=commit;h=%(hash)s" % {
+ 'myrname': config.myreponame,
+ 'hash': l.phash
+ }
+ print """\
+<div class="pre">\
+<a href="%(link)s" class="linenr">%(c)4d</a> \
+<a href="%(link)s" class="line">%(text)s</a>\
+</div>
+ """ % {
+ 'c': count,
+ 'text': text,
+ 'link': link
+ }
+
+ count += 1
+
+ print '</div>'
+
hunk ./darcsweb.cgi 1308
- <a href="%(myreponame)s;a=filehistory;f=%(file)s">history</a>
+ <a href="%(myreponame)s;a=filehistory;f=%(file)s">history</a> |
+ <a href="%(myreponame)s;a=annotate;h=%(hash)s;f=%(file)s">annotate</a>
hunk ./darcsweb.cgi 1390
- <a href="%(myrname)s;a=headblob;f=%(fullf)s">headblob</a>
+ <a href="%(myrname)s;a=headblob;f=%(fullf)s">headblob</a> |
+ <a href="%(myrname)s;a=annotate;f=%(fullf)s">annotate</a>
hunk ./darcsweb.cgi 1423
- # TODO: when we have annotate, put some links around here.
hunk ./darcsweb.cgi 1432
+
+
+def do_annotate(fname, phash):
+ print_header()
+ ann = get_annotate(fname, phash)
+ print_navbar(f = fname, h = ann.lastchange_hash)
+
+
+ print """
+<div>
+ <a class="title" href="%(myreponame)s;a=commit;h=%(hash)s">%(name)s</a>
+</div>
+<div class="page_path"><b>
+ Annotate for file %(fname)s
+</b></div>
+ """ % {
+ 'myreponame': config.myreponame,
+ 'hash': ann.lastchange_hash,
+ 'name': ann.lastchange_name,
+ 'fname': fname,
+ }
+
+ print_annotate(ann)
+ print_footer()
+
+def do_annotate_plain(fname, phash):
+ print_plain_header()
+ ann = get_annotate(fname, phash)
+ for l in ann.lines:
+ sys.stdout.write(l.text)
hunk ./darcsweb.cgi 1761
+elif action == "annotate":
+ fname = filter_file(form["f"].value)
+ if form.has_key("h"):
+ phash = filter_hash(form["h"].value)
+ else:
+ phash = None
+ do_annotate(fname, phash)
+elif action == "annotate_plain":
+ fname = filter_file(form["f"].value)
+ if form.has_key("h"):
+ phash = filter_hash(form["h"].value)
+ else:
+ phash = None
+ do_annotate_plain(fname, phash)
hunk ./darcsweb.cgi 1819
+
hunk ./style.css 128
+a.line {
+ text-decoration:none;
+ color:#000000;
+}
+
+a.line:hover {
+ text-decoration:none;
+ color:#880000;
+}
+
}