# # # 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(''''): + 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('''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(''''): - 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('''