# -*- coding: iso8859-1 -*- # # Copyright (C) 2003, 2004 Edgewall Software # Copyright (C) 2003, 2004 Jonas Borgström # # Trac is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # Trac is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Jonas Borgström from util import * from Module import Module from Href import href from Wiki import wiki_to_html import db import perm from xml.sax.saxutils import escape import sys from cStringIO import StringIO import re import string from svn import fs, util, delta, repos line_re = re.compile('@@ [+-]([0-9]+),([0-9]+) [+-]([0-9]+),([0-9]+) @@') space_re = re.compile(' ') class DiffColorizer: def __init__(self): self.count = 0 self.block = [] self.type = None self.p_block = [] self.p_type = None print '' def writeadd (self, text): print ('' '' % text) def writeremove (self, text): print ('' '' % text) def writeunmodified (self, text): print ('' '' % (text, text)) def writemodified (self, old, new): print ('' '' % (old, new)) def print_block (self): if self.p_type == '-' and self.type == '+': self.writemodified(string.join(self.p_block, '
'), string.join(self.block, '
')) elif self.type == '+': self.writeadd(string.join(self.block, '
')) elif self.type == '-': self.writeremove(string.join(self.block, '
')) elif self.type == ' ': self.writeunmodified(string.join(self.block, '
')) self.block = self.p_block = [] def writeline(self, text): self.count = self.count + 1 if self.count < 3: return match = line_re.search(text) if match: self.print_block() print ('' '' % (match.group(1), match.group(3))) return type = text[0] text = text[1:] text = space_re.sub ('  ', text.expandtabs(8)) if type == self.type: self.block.append(text) else: if type == '+' and self.type == '-': self.p_block = self.block self.p_type = self.type else: self.print_block() self.block = [text] self.type = type def close(self): self.print_block() print '
' '%s
%s
%s%s
%s%s
line %sline %s
' class DiffEditor (delta.Editor): """ generates a unified diff of the changes for a given changeset. the output is written to stdout. """ def __init__(self, old_root, new_root): self.old_root = old_root self.new_root = new_root self._drender = '' def print_diff (self, old_path, new_path, pool): old_root = new_root = None if old_path: old_root = self.old_root name = old_path if new_path: new_root = self.new_root name = new_path differ = fs.FileDiff(old_root, old_path, new_root, new_path, pool, ['-u']) differ.get_files() pobj = differ.get_pipe() print '
' print '

%s

' % name filter = DiffColorizer() while 1: line = pobj.readline() if not line: break filter.writeline(escape(line)) filter.close() print '
' def add_file(self, path, parent_baton, copyfrom_path, copyfrom_revision, file_pool): return [None, path, file_pool] def open_file(self, path, parent_baton, base_revision, file_pool): return [path, path, file_pool] def apply_textdelta(self, file_baton, base_checksum): self.print_diff (*file_baton) def render_diffs(fs_ptr, rev, pool): """ generates a unified diff of the changes for a given changeset. the output is written to stdout. """ old_root = fs.revision_root(fs_ptr, rev - 1, pool) new_root = fs.revision_root(fs_ptr, rev, pool) output = StringIO() s_o = sys.stdout sys.stdout = output editor = DiffEditor(old_root, new_root) e_ptr, e_baton = delta.make_editor(editor, pool) repos.svn_repos_dir_delta(old_root, '', '', new_root, '', e_ptr, e_baton, None, None, 0, 1, 0, 1, pool) sys.stdout = s_o return output.getvalue() class Changeset (Module): template_name = 'changeset.cs' def get_changeset_info (self, rev): cnx = db.get_connection() cursor = cnx.cursor () cursor.execute ('SELECT time, author, message FROM revision ' + 'WHERE rev=%d' % rev) return cursor.fetchone() def get_change_info (self, rev): cnx = db.get_connection() cursor = cnx.cursor () cursor.execute ('SELECT name, change FROM node_change ' + 'WHERE rev=%d' % rev) info = [] while 1: row = cursor.fetchone() if not row: break info.append({'name': row['name'], 'change': row['change'], 'log_href': href.log(row['name'])}) return info def render (self): perm.assert_permission (perm.CHANGESET_VIEW) if self.args.has_key('rev'): self.rev = int(self.args['rev']) else: self.rev = fs.youngest_rev(self.fs_ptr, self.pool) change_info = self.get_change_info (self.rev) for item in change_info: item['log_href'] = href.log(item['name']) changeset_info = self.get_changeset_info (self.rev) self.cgi.hdf.setValue('changeset.time', time.asctime (time.localtime(int(changeset_info['time'])))) self.cgi.hdf.setValue('changeset.author', changeset_info['author']) self.cgi.hdf.setValue('changeset.message', wiki_to_html(changeset_info['message'])) self.cgi.hdf.setValue('changeset.revision', str(self.rev)) add_dictlist_to_hdf(change_info, self.cgi.hdf, 'changeset.changes') self.cgi.hdf.setValue('title', 'Changeset [%d]' % self.rev) def apply_template (self): difftext = render_diffs(self.fs_ptr, int(self.rev), self.pool) self.cgi.hdf.setValue('changeset.diff_output', difftext) Module.apply_template(self)