--- /dev/null
+#!/usr/bin/env python
+
+from optparse import OptionParser
+from os import path
+from urllib import urlencode
+
+import cherrypy
+from jinja2 import Environment, FileSystemLoader
+
+from dirtag import Dirtag, Tree, dir_tree
+
+
+class WebInterface:
+ """The web interface to Dirtag.
+ """
+ def __init__(self, dirtag, template_dir, repository_name='Dirtag'):
+ """Initialize the bug repository for this web interface."""
+ self.dirtag = dirtag
+ self.env = Environment(loader=FileSystemLoader(template_dir))
+ self.repository_name = repository_name
+ self.rdf_root = 'http://dirtag.com/'
+
+ @cherrypy.expose
+ def index(self):
+ template = self.env.get_template('dirtag.xul')
+ cherrypy.response.headers['Content-Type'] = \
+ 'application/vnd.mozilla.xul+xml'
+ return template.render(repository_name=self.repository_name)
+
+ @cherrypy.expose
+ def raw_rdf(self):
+ return self.tree_rdf(self.dirtag.raw_dir, 'raw')
+
+ @cherrypy.expose
+ def tag_rdf(self):
+ return self.tree_rdf(self.dirtag.tag_dir, 'tag', with_files=False)
+
+ def tree_rdf(self, root_dir, name, with_files=True):
+ cherrypy.response.headers['Content-Type'] = \
+ 'application/rdf+xml'
+ tree = dir_tree(root_dir)
+ lines = [
+ '<?xml version="1.0"?>',
+ '',
+ '<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"',
+ ' xmlns:FILES="%srdf#">' % self.rdf_root,
+ ]
+ if with_files == True:
+ nodes = tree.traverse(depth=1, dirtag=self.dirtag)
+ else:
+ nodes = tree.traverse(depth=1, type='dirs', dirtag=self.dirtag)
+ for node in nodes:
+ lines.extend([
+ ' <RDF:Description RDF:about="%s%s">'
+ % (self.rdf_root, '/'.join([name]+node)),
+ ' <FILES:name>%s</FILES:name>' % node[-1],
+ ])
+ if node.type == 'file':
+ lines.append(' <FILES:tags>%s</FILES:tags>'
+ % ','.join(['/'.join(t) for t in node.tags]))
+ lines.append(' </RDF:Description>')
+
+ lines.append(' <RDF:Seq RDF:about="%s%s/files">'
+ % (self.rdf_root, name))
+ stack = []
+ for node in tree.traverse(depth=1,):
+ while (len(stack) > 0 and
+ not self.list_startswith(stack[-1], node[:-1])):
+ lines.extend([
+ ' '*(4*len(stack)+2) + '</RDF:Seq>',
+ ' '*(4*len(stack)) + '</RDF:li>',
+ ])
+ stack.pop()
+ assert len(node) == len(stack)+1, (
+ 'Floating %s -> %s (%d -> %d)'
+ % (stack[-1], node, len(stack), len(node)))
+ stack.append(node)
+ if node.type == 'file':
+ raw_node = self.dirtag.raw_node(node)
+ lines.append(' '*(4*len(stack))
+ + '<RDF:li RDF:resource="%s%s"/>'
+ % (self.rdf_root, '/'.join(['raw']+raw_node)))
+ stack.pop()
+ else:
+ lines.extend([
+ ' '*(4*len(stack)) + '<RDF:li>',
+ ' '*(4*len(stack)+2) + '<RDF:Seq RDF:about="%s%s">'
+ % (self.rdf_root, '/'.join([name]+node)),
+ ])
+ while len(stack) > 0:
+ lines.extend([
+ ' '*(4*len(stack)+2) + '</RDF:Seq>',
+ ' '*(4*len(stack)) + '</RDF:li>',
+ ])
+ stack.pop()
+ lines.extend([
+ ' </RDF:Seq>',
+ '',
+ '</RDF:RDF>',
+ '',
+ ])
+ return '\n'.join(lines)
+
+ def list_startswith(self, a, b):
+ """
+ >>> x = WebInterface(None, 'template')
+ >>> x.list_startswith([1, 2, 3], [1, 2, 3, 4])
+ True
+ >>> x.list_startswith([1, 2, 3], [1, 2, 3])
+ True
+ >>> x.list_startswith([1, 2, 3], [1, 2])
+ False
+ >>> x.list_startswith([1, 2, 3], [2, 2, 3])
+ False
+ """
+ return len([x for x,y in zip(a,b) if x==y]) == len(a)
+
+ #raise cherrypy.HTTPRedirect('/static/dirtag.xul', status=302)
+
+if __name__ == '__main__':
+ parser = OptionParser('%prog [options]', epilog=WebInterface.__doc__)
+ parser.add_option('-r', '--raw-dir', dest='raw_dir', metavar='DIR',
+ default='raw',
+ help='Location of raw files (%default)')
+ parser.add_option('-t', '--tag-dir', dest='tag_dir', metavar='DIR',
+ default='tag',
+ help='Location of tag links (%default)')
+ parser.add_option('-T', '--template-dir', dest='template_dir',
+ metavar='DIR', default='template',
+ help='Location of template files (%default)')
+ parser.add_option('-s', '--static-dir', dest='static_dir', metavar='DIR',
+ default='static',
+ help='Location of static files (%default)')
+ parser.add_option('-n', '--name', dest='name', metavar='STRING',
+ default='dirtag',
+ help='Name of the dirtag repository')
+ parser.add_option('--test', dest='test', default=False,
+ action='store_true',
+ help='Run unittests and exit')
+ options,args = parser.parse_args()
+
+ if options.test:
+ import doctest, sys
+ doctest.testmod()
+ sys.exit(0)
+
+ d = Dirtag(raw_dir=options.raw_dir, tag_dir=options.tag_dir)
+ w = WebInterface(
+ d, template_dir=options.template_dir, repository_name=options.name)
+ cherrypy.config.update({
+ 'tools.encode.on': True,
+ 'tools.encode.encoding': 'utf8',
+ })
+ app_config = {
+ '/static': {
+ 'tools.staticdir.on': True,
+ 'tools.staticdir.dir': path.abspath(options.static_dir),
+ }
+ }
+ cherrypy.quickstart(w, '/', app_config)