# # # patch "TODO" # from [e0ea26c666b37c5f98ccf80cb933d021ee55c593] # to [8caff57c44359cf5d6371175966a89f2bab498ab] # # patch "common.py" # from [1e086f49256b4f4372e6ce1cb9cc53cc5564c9d2] # to [13c75961de7952e45b67d1597b2314ba086fd383] # # patch "html.py" # from [6121f3a3831136e182b9e1b9df342231675839dc] # to [7bdf3c99d6d466df0211e2b097657a897e921de3] # # patch "manifest.psp" # from [9244015efc03153b4837b17ac05570426213e9ad] # to [b0c6066cebce291626dfcaf0864ddf34a96e0ca0] # # patch "monotone.py" # from [04e570747e50d80629f0f191fd01b641f203bcad] # to [6561b7646cb0a5ab3b4deb399df10ae49a0d3eb5] # # patch "viewmtn.css" # from [8d04b3fc352a860b0e3240dcb539c1193705398f] # to [8f34d3d1b7b375830bfbf12ae362a575b2a79385] # ============================================================ --- TODO e0ea26c666b37c5f98ccf80cb933d021ee55c593 +++ TODO 8caff57c44359cf5d6371175966a89f2bab498ab @@ -7,6 +7,8 @@ * getfile.py is setting the wrong content-disposition header + * some sort of double escaping with " in changelogs + TODO: * Use monotone automate graph to do the ancestry graphing, and show some ============================================================ --- common.py 1e086f49256b4f4372e6ce1cb9cc53cc5564c9d2 +++ common.py 13c75961de7952e45b67d1597b2314ba086fd383 @@ -12,6 +12,13 @@ else: return e(x) +# +# FIXME +# +# make these links use the mt instance (stricly Automate only) +# to add extra information when the user hovers on a link +# + def link(mt, link_type, link_to, description = None): hq = html_escape() if link_type == "revision": ============================================================ --- html.py 6121f3a3831136e182b9e1b9df342231675839dc +++ html.py 7bdf3c99d6d466df0211e2b097657a897e921de3 @@ -9,17 +9,37 @@ hq = common.html_escape() -def get_icon(filename, mime_type=None): - if mime_type == None: - mime_type = mimetypes.guess_type(filename)[0] - if not mime_type: - mime_type = "text" - icon = 'gnome-mime-' + mime_type.replace('/', '-') + '.png' - if os.access(os.path.join(config.gnome_mimetype_icon_path, icon), os.R_OK): - return icon +def get_icon(filename, mime_type=None, is_directory=False): + if config.gnome_mimetype_icon_path == None: + return None + if is_directory: + filename = 'gnome-fs-directory.png' + else: + if mime_type == None: + mime_type = mimetypes.guess_type(filename)[0] + if not mime_type: + mime_type = "text" + filename = 'gnome-mime-' + mime_type.replace('/', '-') + '.png' + + if os.access(os.path.join(config.gnome_mimetype_icon_path, filename), os.R_OK): + return '/'.join([config.gnome_mimetype_uri, filename]) else: return None +class TableWriter: + def __init__(self, req): + self.req = req + self.odd = False + def start(self): + self.req.write('') + def write(self, row): + if self.odd: c = 'odd' + else: c = 'even' + self.odd = not self.odd + self.req.write('' % (c) + row + '\n') + def stop(self): + self.req.write('
') + class Template: def header(self, info): if not info.has_key("title"): info['title'] = "untitled" ============================================================ --- manifest.psp 9244015efc03153b4837b17ac05570426213e9ad +++ manifest.psp b0c6066cebce291626dfcaf0864ddf34a96e0ca0 @@ -5,7 +5,8 @@ import monotone import common import urllib -from html import get_icon +import sets +from html import get_icon, TableWriter # # manifest.psp @@ -24,6 +25,13 @@ if not monotone.is_valid_id(id): raise Exception("Specified revision ID is not valid.") +if not form.has_key('path'): + path = '' +else: + path = form['path'] +if path.startswith('/'): path = path[1:] +if path.endswith('/'): path = path[-1:] + revision = mt.revision(id) if not revision.has_key('new_manifest'): raise Exception("There is no manifest in this revision ID.") @@ -31,17 +39,14 @@ manifest = mt.manifest(manifest_id) info = { - 'title' : "Manifest of revision %s" % (hq(id)), + 'title' : "/%s in revision %s" % (hq(path), hq(id)), } req.write(template.header(info)) - -manifest = mt.manifest(manifest_id) - %>

-For more information about this revision, see its page: <%= link("revision", id) %>. -below to view it. +This page shows files contained within a particular revision; for more information +about that revision see its page: <%= link("revision", id) %>.

@@ -49,23 +54,49 @@

<% -# display the manifest broken into some columns. -n_columns = 3 -offset = 0 -req.write('') -for i in range(n_columns): - size = len(manifest) / n_columns; - spillage = len(manifest) % n_columns; - if spillage > 0 and i < spillage: size += 1 - req.write('\n') - offset += size -req.write('
\n') - for id, filename in manifest[offset:offset+size]: - icon = get_icon(filename) - if icon != None: req.write('' % icon) - req.write('%s
\n' % (link("file", [id, filename], filename))) - req.write('
') +# filter this list of files into two lists; +# subdirectories of 'path' +# files in 'path' +# each will contain entries relative to 'path' +# +# NB: the following code will break (perhaps) if monotone ever supports +# empty subdirectories. +subdirs, files, last_dir = [], [], None +# root dir is depth 0, subdir of that 1, .. +if path == '': + sp = [] +else: + sp = path.split('/') +depth = len(sp) + +for file_id, filename in manifest: + parts = filename.split('/') + + if len(parts) < depth or parts[:depth] != sp[:depth]: + continue + + if len(parts) > depth + 1 and parts[depth] != last_dir: + subdirs.append((parts[depth], '/'.join(parts[:depth+1]))) + last_dir = parts[depth] + elif len(parts) == depth + 1: + files.append((parts[-1], file_id, filename)) + +if depth != 0: + subdirs = [('..', '/'.join(sp[:-1]))] + subdirs +# req.write("%s %s %s
" % (str(sp), str(parts), depth)) + +tr = TableWriter(req) +tr.start() +tr.write('NameRevAgeAuthorLast log entry') +icon_uri = get_icon('', is_directory=True) +for name, subdir in subdirs: + tr.write('%s' % (icon_uri, urllib.quote(id), urllib.quote(subdir), hq(name))) +for name, file_id, file in files: + icon_uri = get_icon(file) + tr.write('%s' % (icon_uri, link("file", [file_id, file], name))) +tr.stop() + %> ============================================================ --- monotone.py 04e570747e50d80629f0f191fd01b641f203bcad +++ monotone.py 6561b7646cb0a5ab3b4deb399df10ae49a0d3eb5 @@ -122,12 +122,12 @@ for c in str[1:]: if in_escape: if c != '\\' and c != '\"': - raise Exception("basic_io parse error; expected \" or \\") + raise Exception(r'basic_io parse error; expected \" or \\') rv += c in_escape = False else: if c == '\\': in_escape = True - if c == '"': + elif c == '"': if is_terminated: raise Exception("basic_io parse error; string ends twice!") is_terminated = True ============================================================ --- viewmtn.css 8d04b3fc352a860b0e3240dcb539c1193705398f +++ viewmtn.css 8f34d3d1b7b375830bfbf12ae362a575b2a79385 @@ -37,6 +37,14 @@ border-color: black; } +TR.odd { + background-color: #eeeeee; +} + +TR.even { + background-color: #ffffff; +} + TABLE.pretty TH { /* background-color: black;*/ color: blue;