Edgewall Software

Ticket #199: python.patch

File python.patch, 11.1 KB (added by agr30@…, 4 years ago)

New "anydiff" module

  • trac/Anydiff.py

    diff -ruN /opt/trac.bak/trac/Anydiff.py trac/Anydiff.py
    old new  
     1# -*- coding: iso8859-1 -*- 
     2# 
     3# Copyright (C) 2003, 2004 Edgewall Software 
     4# Copyright (C) 2003, 2004 Jonas Borgstr�jonas@edgewall.com> 
     5# 
     6# Trac is free software; you can redistribute it and/or 
     7# modify it under the terms of the GNU General Public License as 
     8# published by the Free Software Foundation; either version 2 of the 
     9# License, or (at your option) any later version. 
     10# 
     11# Trac is distributed in the hope that it will be useful, 
     12# but WITHOUT ANY WARRANTY; without even the implied warranty of 
     13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
     14# General Public License for more details. 
     15# 
     16# You should have received a copy of the GNU General Public License 
     17# along with this program; if not, write to the Free Software 
     18# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
     19# 
     20# Author: Jonas Borgstr�jonas@edgewall.com> 
     21 
     22import time 
     23 
     24import util 
     25import Diff 
     26import perm 
     27import Module 
     28from WikiFormatter import wiki_to_html 
     29 
     30import svn.delta 
     31import svn 
     32 
     33class HtmlDiffEditor (svn.delta.Editor): 
     34    """ 
     35    generates a htmlized unified diff of the changes for a given changeset. 
     36    the output is written to stdout. 
     37    """ 
     38    def __init__(self, old_root, new_root, rev, req, args, env, authzperm): 
     39        self.old_root = old_root 
     40        self.new_root = new_root 
     41        self.rev = rev 
     42        self.req = req 
     43        self.args = args 
     44        self.env = env 
     45        self.authzperm = authzperm 
     46        self.fileno = 0 
     47 
     48    def print_diff (self, old_path, new_path, pool): 
     49        if not old_path or not new_path: 
     50            return 
     51 
     52        old_rev = svn.fs.node_created_rev(self.old_root, old_path, pool) 
     53        new_rev = svn.fs.node_created_rev(self.new_root, new_path, pool) 
     54 
     55        options = Diff.get_options(self.env, self.req, self.args, 1) 
     56 
     57        # Make sure we have permission to view this diff 
     58        if not self.authzperm.has_permission(new_path): 
     59            return 
     60 
     61        # Try to figure out the charset used. We assume that both the old 
     62        # and the new version uses the same charset, not always the case 
     63        # but that's all we can do... 
     64        mime_type = svn.fs.node_prop (self.new_root, new_path, 
     65                                      svn.util.SVN_PROP_MIME_TYPE, 
     66                                      pool) 
     67        # We don't have to guess if the charset is specified in the 
     68        # svn:mime-type property 
     69        ctpos = mime_type and mime_type.find('charset=') or -1 
     70        if ctpos >= 0: 
     71            charset = mime_type[ctpos + 8:] 
     72            self.env.log.debug("Charset %s selected" % charset) 
     73        else: 
     74            charset = self.env.get_config('trac', 'default_charset', 'iso-8859-15') 
     75 
     76        # Start up the diff process 
     77        differ = svn.fs.FileDiff(self.old_root, old_path, self.new_root, 
     78                                 new_path, pool, options) 
     79        differ.get_files() 
     80        pobj = differ.get_pipe() 
     81        prefix = 'changeset.diff.files.%d' % (self.fileno) 
     82        self.req.hdf.setValue(prefix + '.browser_href.old', 
     83                              self.env.href.file(old_path, old_rev)) 
     84        self.req.hdf.setValue(prefix + '.browser_href.new', 
     85                              self.env.href.file(new_path, new_rev)) 
     86        tabwidth = int(self.env.get_config('diff', 'tab_width', '8')) 
     87        builder = Diff.HDFBuilder(self.req.hdf, prefix, tabwidth) 
     88        self.fileno += 1 
     89        builder.writeline('header %s %s | %s %s redaeh' % (old_path, old_rev, 
     90                                                           new_path, new_rev)) 
     91        while 1: 
     92            line = pobj.readline() 
     93            if not line: 
     94                break 
     95            builder.writeline(util.to_utf8(line, charset)) 
     96        builder.close() 
     97 
     98    def add_file(self, path, parent_baton, copyfrom_path, 
     99                 copyfrom_revision, file_pool): 
     100        return [None, path, file_pool] 
     101 
     102    def open_file(self, path, parent_baton, base_revision, file_pool): 
     103        return [path, path, file_pool] 
     104 
     105    def apply_textdelta(self, file_baton, base_checksum): 
     106        self.print_diff (*file_baton) 
     107 
     108 
     109class UnifiedDiffEditor(HtmlDiffEditor): 
     110    """ 
     111    generates a unified diff of the changes for a given changeset. 
     112    the output is written to stdout. 
     113    """ 
     114 
     115    def __init__(self, old_root, new_root, rev, req, args, env, authzperm): 
     116        HtmlDiffEditor.__init__(self, old_root, new_root, rev, req, args, env, authzperm) 
     117        self.output = req 
     118 
     119    def print_diff (self, old_path, new_path, pool): 
     120        options = ['-u'] 
     121        options.append('-L') 
     122        options.append("%s\t(revision %d)" % (old_path, self.rev-1)) 
     123        options.append('-L') 
     124        options.append("%s\t(revision %d)" % (new_path, self.rev)) 
     125 
     126        differ = svn.fs.FileDiff(self.old_root, old_path, 
     127                             self.new_root, new_path, pool, options) 
     128        differ.get_files() 
     129        pobj = differ.get_pipe() 
     130        line = pobj.readline() 
     131        while line: 
     132            self.output.write(line) 
     133            line = pobj.readline() 
     134 
     135 
     136class Anydiff (Module.Module): 
     137    template_name = 'anydiff.cs' 
     138    perm = None 
     139    fs_ptr = None 
     140    pool = None 
     141 
     142    def get_changeset_info (self, rev): 
     143        cursor = self.db.cursor () 
     144        cursor.execute ('SELECT time, author, message FROM revision ' + 
     145                        'WHERE rev=%d', rev) 
     146        row = cursor.fetchone() 
     147        if not row: 
     148            raise util.TracError('Anydiff %d does not exist.' % rev, 
     149                            'Invalid Changset') 
     150        return row 
     151 
     152    def get_change_info (self, rev): 
     153        cursor = self.db.cursor () 
     154        cursor.execute ('SELECT name, change FROM node_change ' + 
     155                        'WHERE rev=%d', rev) 
     156        info = [] 
     157        while 1: 
     158            row = cursor.fetchone() 
     159            if not row: 
     160                break 
     161            info.append({'name': row['name'], 
     162                         'change': row['change'], 
     163                         'browser_href': self.env.href.browser(row['name'], rev), 
     164                         'log_href': self.env.href.log(row['name'])}) 
     165        return info 
     166 
     167    def render (self): 
     168        self.perm.assert_permission (perm.CHANGESET_VIEW) 
     169 
     170        self.add_link('alternate', '?format=diff', 'Unified Diff', 
     171            'text/plain', 'diff') 
     172 
     173        if self.args.has_key('rev'): 
     174            self.rev = int(self.args.get('rev')) 
     175        else: 
     176            self.rev = svn.fs.youngest_rev(self.fs_ptr, self.pool) 
     177 
     178        change_info = self.get_change_info (self.rev) 
     179        changeset_info = self.get_changeset_info (self.rev) 
     180 
     181        self.req.hdf.setValue('changeset.time', 
     182                              time.asctime (time.localtime(int(changeset_info['time'])))) 
     183        author = changeset_info['author'] or 'anonymous' 
     184        self.req.hdf.setValue('changeset.author', util.escape(author)) 
     185        self.req.hdf.setValue('changeset.message', 
     186                              wiki_to_html(util.wiki_escape_newline(changeset_info['message']), 
     187                                           self.req.hdf, self.env, self.db)) 
     188        self.req.hdf.setValue('changeset.revision', str(self.rev)) 
     189        util.add_dictlist_to_hdf(change_info, self.req.hdf, 'changeset.changes') 
     190        self.req.hdf.setValue('anydiff.href',  
     191                                self.env.href.anydiff(self.args.get('path', '/'), self.args.get('a'), self.args.get('b'))) 
     192        self.req.hdf.setValue('title', '[%d] (changeset)' % self.rev) 
     193 
     194    def render_diffs(self, editor_class=HtmlDiffEditor): 
     195        """ 
     196        generates a unified diff of the changes for a given changeset. 
     197        the output is written to stdout. 
     198        """ 
     199        try: 
     200            old_root = svn.fs.revision_root(self.fs_ptr, int(self.args.get('a')), self.pool) 
     201            new_root = svn.fs.revision_root(self.fs_ptr, int(self.args.get('b')), self.pool) 
     202        except svn.core.SubversionException: 
     203            raise util.TracError('Invalid revision number: %d' % int(self.rev)) 
     204 
     205        editor = editor_class(old_root, new_root, int(self.rev), self.req, 
     206                              self.args, self.env, self.authzperm) 
     207        e_ptr, e_baton = svn.delta.make_editor(editor, self.pool) 
     208 
     209        def authz_cb(root, path, pool): return 1 
     210        path = self.args.get('path', '/')[1:] 
     211 
     212        svn.repos.svn_repos_dir_delta(old_root, "", path, 
     213                                      new_root, path, e_ptr, e_baton, authz_cb, 
     214                                      0, 1, 0, 1, self.pool) 
     215    def display(self): 
     216        """Pretty HTML view of the changeset""" 
     217        self.render_diffs() 
     218        Module.Module.display(self) 
     219 
     220    def display_hdf(self): 
     221        self.render_diffs() 
     222        Module.Module.display_hdf(self) 
     223 
     224    def display_diff (self): 
     225        """Raw Unified Diff version""" 
     226        self.req.send_response(200) 
     227        self.req.send_header('Content-Type', 'text/plain;charset=utf-8') 
     228        self.req.end_headers() 
     229        self.render_diffs(UnifiedDiffEditor) 
  • trac/core.py

    diff -ruN /opt/trac.bak/trac/core.py trac/core.py
    old new  
    5454    'browser'     : ('Browser', 'Browser', 1), 
    5555    'timeline'    : ('Timeline', 'Timeline', 1), 
    5656    'changeset'   : ('Changeset', 'Changeset', 1), 
     57    'anydiff'        : ('Anydiff', 'Anydiff', 1), 
    5758    'newticket'   : ('Ticket', 'NewticketModule', 0), 
    5859    'query'       : ('Query', 'QueryModule', 0), 
    5960    'attachment'  : ('File', 'Attachment', 0), 
     
    103104        if match.group(2): 
    104105            set_if_missing(args, 'id', match.group(2)) 
    105106        return args 
    106     match = re.search('^/(browser|log|file)(?:(/.*))?', path_info) 
     107    match = re.search('^/(browser|log|file|anydiff)(?:(/.*))?', path_info) 
    107108    if match: 
    108109        set_if_missing(args, 'mode', match.group(1)) 
    109110        if match.group(2): 
  • trac/Href.py

    diff -ruN /opt/trac.bak/trac/Href.py trac/Href.py
    old new  
    5454        else: 
    5555            return href_join(self.base, 'browser', path) 
    5656 
     57    def anydiff(self, path=None, revA=None, revB=None): 
     58        if path and revA and revB: 
     59                return href_join(self.base, 'anydiff', path) + "?a=" + str(revA) + "&b=" + str(revB) 
     60        elif path: 
     61                return href_join(self.base, 'anydiff', path) 
     62         
     63        else:    
     64                return href_join(self.base, 'anydiff') 
     65 
    5766    def login(self): 
    5867        return href_join(self.base, 'login') 
    5968 
  • trac/Log.py

    diff -ruN /opt/trac.bak/trac/Log.py trac/Log.py
    old new  
    115115            'application/rss+xml', 'rss') 
    116116 
    117117        self.path = self.args.get('path', '/') 
     118        self.req.hdf.setValue('log.href.anydiff', self.env.href.anydiff(self.path)) 
     119         
    118120        if self.args.has_key('rev'): 
    119121            try: 
    120122                rev = int(self.args.get('rev'))