# # # add_file "diff.psp" # content [5ecbb7f72740996923bedbd99d320455d8454b15] # # patch "TODO" # from [4c936ee41b3775920b24300ec4645bb8f88f1a6b] # to [7eb87016ebe9a380be615df2f60a7d270b9441c6] # # patch "common.py" # from [326b759a8cc797fb5f57b12c7c5531fe90c2a010] # to [e8e82ca9c5ed76b31f076d37c83a9baf87d91ed8] # # patch "file.psp" # from [9cafbcda1e0ea426893d5fc02adfed2af5bc8c4e] # to [4577435a443e0b52f428b215c5856853f631b76d] # ============================================================ --- diff.psp 5ecbb7f72740996923bedbd99d320455d8454b15 +++ diff.psp 5ecbb7f72740996923bedbd99d320455d8454b15 @@ -0,0 +1,63 @@ +<% + +import mimetypes +import datetime +import monotone +import common +import config +import urllib +import pipes +import time +import os +from enscriptlangs import enscript_langs +from html import get_icon, TableWriter +from utility import run_command +from common import colourise_code + +# file.psp ; provide information about a file +# if possible, display it (with syntax highlighting, etc.) +# provide a download link + +psp.set_error_page("error.psp") + +if not form.has_key('id1') and not form.has_key('id2'): + raise Exception("Revision IDs not specified.") + +id1, id2 = form['id1'], form['id2'] +if not monotone.is_valid_id(id1) or not monotone.is_valid_id(id2): + raise Exception("Specified revision IDs are not valid.") + +# should support diffing more than one file eventually +fname = form.get('fname', None) +if fname != None: + title = 'of file %s ' % hq(fname) +else: + title = '' + +title = 'Diff %sbetween revisions [%s..] and [%s..]' % (title, hq(id1[:8]), hq(id2[:8])) + +info = { 'title' : title } +req.write(template.header(info)) + +if fname != None: + file_str = 'of file ' + link("file", [id2, fname], fname) + ' ' +else: + file_str = '' +req.write('

The unified diff %sbetween revisions %s and %s is displayed below.

' % (file_str, + link("revision", id1), + link("revision", id2))) + +if fname != None: + req.write('

You might wish to view the %s between these revisions, without the restriction to this particular file.

' % link('diff', [id1, id2], 'diff')) + +req.write('

You can also %s this diff verbatim.

' % link("download_diff", [id1, id2, fname], "download")) + +### FIXME FIXME +### this means having _the entire file_ in memory +### which is pointless and dumb. +contents = mt.diff(id1, id2, [fname]) +colourise_code(req, hq, 'a.diff', contents, filter='diffu') + +req.write(template.footer(info)) + +%> ============================================================ --- TODO 4c936ee41b3775920b24300ec4645bb8f88f1a6b +++ TODO 7eb87016ebe9a380be615df2f60a7d270b9441c6 @@ -30,21 +30,13 @@ * Show information when mousing over long hex strings. - * Colour and format diffs (files are already done). - * Magically make http:// ftp:// etc links inside files clickable - * In the file diff view, link to the both revisions and to the general - diff of those revisions (all changes.) - * In the file diff view for multiple files, show the same change set information that is available in the revision view - this will help explain what's happened. For bonus points, index into the diff so you can click on a file that changed and jump to that section in the diff. - * Patch lines in revision.psp, "Patch file ChangeLog from ..." make - "ChangeLog" a link to the file. - * Improve the file listing; use data from the new rosters branch to get a better idea of when a given file was last touched. @@ -52,8 +44,6 @@ was recently changed. Include in the list a link to diff with each revision. - * actually do commit messages / ChangeLog formally. - * generally clean up table formatting code; things like list_of_branches() list_of_tags() @@ -61,13 +51,6 @@ revision_details() use a generic method to output the tables - * the revision details links in "revision.psp" need review. The data could - perhaps be shown in a more intelligent way; either way the links themselves - are wrong. - - * rewrite the basic_io parser; make sure code outside of Monotone.py - isn't accessing those structures directly. - * from [mrb] support for multiple databases (perhaps some sort of dropdown to say which database you want to look in) - perhaps also make the branches page show the ============================================================ --- common.py 326b759a8cc797fb5f57b12c7c5531fe90c2a010 +++ common.py e8e82ca9c5ed76b31f076d37c83a9baf87d91ed8 @@ -29,9 +29,13 @@ rv += '' if description == None: rv = '[' + rv + ']' return rv - elif link_type == "diff": + elif link_type == "diff" or link_type == "download_diff": link_to = map(urllib.quote, link_to) - uri = 'getdiff.py?id1=%s&id2=%s' % (link_to[0], link_to[1]) + if link_type == "diff": + handler = "diff.psp" + else: + handler = "getdiff.py" + uri = '%s?id1=%s&id2=%s' % (handler, link_to[0], link_to[1]) if len(link_to) == 3: uri += '&fname=%s' % (link_to[2]) rv = '' @@ -88,3 +92,84 @@ "returns a function stolen from pydoc that can be used to escape HTML" return lambda x: type_wrapper(escape_function, x) +from enscriptlangs import enscript_langs +from utility import run_command +import mimetypes +import config +import pipes + +# is it binary? +def is_binary(str): + nontext_chars = "\x01\x02\x03\x04\x05\x06\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1c\x1d\x1e\x1f" + check = {} + for char in nontext_chars: + check[char] = True + for i in str: + if check.has_key(i): return True + return False + +# hm, later on might make this be some javascript that does an call back to the server. +# then could have a pull down to let people choose which enscript encoding to use, and +# just update the DOM with the new data. +def colourise_code(req, hq, path, contents, filter=None): + mime_type = mimetypes.guess_type(path)[0] + if mime_type == None: mime_type = 'text/plain' + if mime_type == 'image/png' or mime_type == 'image/jpeg' or mime_type == 'image/gif': + display_as_image = True + else: display_as_image = False + + # okay; can we guess a valid enscript filter to run this through? + tsp = mime_type.split('/', 1) + if filter == None and tsp[0] == 'text': + candidate = tsp[1] + if candidate.startswith('x-'): candidate = candidate[2:] + if candidate.endswith('src'): candidate = candidate[:-3] + if candidate.endswith('hdr'): candidate = candidate[:-3] + if candidate == 'c++': candidate = 'cpp' # ugly + if candidate in enscript_langs: filter = candidate + if filter == None: + # heh, will at least work for lua files + last_dot = path.rfind('.') + if last_dot == -1: last_dot = 0 + candidate = path[last_dot:] + if candidate in enscript_langs: filter = candidate + + # if no filter then let's check if it's binary or not; if not binary + # we'll just treat it as text; otherwise display a warning and a download + # link + if filter == None and not is_binary(contents): + filter = 'text' + + req.write('''
''') + if display_as_image: + req.write('''') + def stop_code(): + req.write('') + def text(): + start_code() + req.write(hq(contents)) + stop_code() + def enscript(): + command = config.enscript_path + ' -o - --color --language=html' + command += ' --highlight=%s' % (pipes.quote(filter)) + result = run_command(command, to_child=contents) + if result['exitcode'] != 0: + raise Exception('Error running enscript (%s) : "%s".' % (hq(command), hq(result['childerr']))) + in_contents = False + for line in result['fromchild'].split('\n'): + if line.startswith('
'):
+		    in_contents = True
+		    start_code()
+		elif line.startswith('
'): + in_contents = False + stop_code() + elif in_contents: + req.write(line + '\r\n') + if filter == "text": text() + else: enscript() + else: + req.write('''

This file seems to binary and not suitable for display in the browser. You must %s the file and use a suitable viewer.

''' % (link("download", [matching_file_id, path], "download"))) + req.write('''
''') ============================================================ --- file.psp 9cafbcda1e0ea426893d5fc02adfed2af5bc8c4e +++ file.psp 4577435a443e0b52f428b215c5856853f631b76d @@ -12,6 +12,7 @@ from enscriptlangs import enscript_langs from html import get_icon, TableWriter from utility import run_command +from common import colourise_code # file.psp ; provide information about a file # if possible, display it (with syntax highlighting, etc.) @@ -49,87 +50,15 @@ } req.write(template.header(info)) -contents = mt.file(matching_file_id) - -%> - -<% - -# is it binary? -def is_binary(): - nontext_chars = "\x01\x02\x03\x04\x05\x06\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1c\x1d\x1e\x1f" - check = {} - for char in nontext_chars: - check[char] = True - for i in contents: - if check.has_key(i): return True - return False - -mime_type = mimetypes.guess_type(path)[0] -if mime_type == None: mime_type = 'text/plain' -if mime_type == 'image/png' or mime_type == 'image/jpeg' or mime_type == 'image/gif': - display_as_image = True -else: display_as_image = False -# okay; can we guess a valid enscript filter to run this through? -tsp = mime_type.split('/', 1) -filter = None -if tsp[0] == 'text': - candidate = tsp[1] - if candidate.startswith('x-'): candidate = candidate[2:] - if candidate.endswith('src'): candidate = candidate[:-3] - if candidate.endswith('hdr'): candidate = candidate[:-3] - if candidate == 'c++': candidate = 'cpp' # ugly - if candidate in enscript_langs: filter = candidate -if filter == None: - # heh, will at least work for lua files - last_dot = path.rfind('.') - if last_dot == -1: last_dot = 0 - candidate = path[last_dot:] - if candidate in enscript_langs: filter = candidate - -# if no filter then let's check if it's binary or not; if not binary -# we'll just treat it as text; otherwise display a warning and a download -# link -if filter == None and not is_binary(): - filter = 'text' - req.write('

For more information about the revision containing this file, see its %s page. For other files contained in this revision, see the %s.

' % (link("revision", id, "revision"), link("manifest", id, "manifest"))) req.write('

You can also %s the file verbatim.

' % link("download", [matching_file_id, path], "download")) -req.write('''
''') -if display_as_image: - req.write('''') - def stop_code(): - req.write('') - def text(): - start_code() - req.write(hq(contents)) - stop_code() - def enscript(): - command = config.enscript_path + ' -o - --color --language=html' - command += ' --highlight=%s' % (pipes.quote(filter)) - result = run_command(command, to_child=contents) - if result['exitcode'] != 0: - raise Exception('Error running enscript (%s) : "%s".' % (hq(command), hq(result['childerr']))) - in_contents = False - for line in result['fromchild'].split('\n'): - if line.startswith('
'):
-                in_contents = True
-                start_code()
-            elif line.startswith('
'): - in_contents = False - stop_code() - elif in_contents: - req.write(line + '\r\n') - if filter == "text": text() - else: enscript() -else: - req.write('''

This file seems to binary and not suitable for display in the browser. You must %s the file and use a suitable viewer.

''' % (link("download", [matching_file_id, path], "download"))) -req.write('''
''') +### FIXME FIXME +### this means having _the entire file_ in memory +### which is pointless and dumb. +contents = mt.file(matching_file_id) +colourise_code(req, hq, path, contents) req.write(template.footer(info))