Ticket #2028: trac-diff-for-0.9.patch
| File trac-diff-for-0.9.patch, 91.6 KB (added by cboos, 3 years ago) |
|---|
-
htdocs/css/changeset.css
26 26 27 27 .diff ul.props { font-size: 90%; list-style: disc; margin: .5em 0 0; padding: 0 .5em 1em 2em } 28 28 .diff ul.props li { margin: 0; padding: 0 } 29 30 31 #title dl { 32 display: inline; 33 font-size: 110% 34 } 35 #title dt { 36 font-size: 110%; 37 font-weight: bold; 38 display: inline; 39 margin-left: 3em; 40 } 41 #title dd { 42 display: inline; 43 margin-left: 0.4em; 44 } -
htdocs/css/browser.css
46 46 #dirlist td.rev { text-align: right } 47 47 #dirlist td.change { font-size: 85%; vertical-align: middle; white-space: nowrap } 48 48 49 /* Log */ 50 tr.diff input { 51 padding: 0 1em 0 1em; 52 margin: 0; 53 } 54 55 div.buttons { 56 clear: left; 57 } 58 59 #anydiff { 60 margin: 0 0 1em; 61 float: left; 62 } 63 #anydiff form, #anydiff div, #anydiff h2 { 64 display: inline; 65 } 66 #anydiff input { 67 vertical-align: baseline; 68 margin: 0 -0.5em 0 1em; 69 } 70 71 49 72 /* Styles for the revision log table 50 73 (extends the styles for "table.listing") */ 51 74 #chglist { margin-top: 0 } -
wiki-default/WikiStart
1 = Welcome to Trac 0.9 =2 3 Trac is a '''minimalistic''' approach to '''web-based''' management of 4 '''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress. 5 6 All aspects of Trac have been designed with the single goal to 7 '''help developers write great software''' while '''staying out of the way''' 8 and imposing as little as possible on a team's established process and 9 culture. 10 11 As all Wiki pages, this page is editable, this means that you can 12 modify the contents of this page simply by using your 13 web-browser. Simply click on the "Edit this page" link at the bottom 14 of the page. WikiFormatting will give you a detailed description of 15 available Wiki formatting commands. 16 17 "[wiki:TracAdmin trac-admin] ''yourenvdir'' initenv" created 18 a new Trac environment, containing a default set of wiki pages and some sample 19 data. This newly created environment also contains 20 [wiki:TracGuide documentation] to help you get started with your project. 21 22 You can use [wiki:TracAdmin trac-admin] to configure 23 [http://trac.edgewall.com/ Trac] to better fit your project, especially in 24 regard to ''components'', ''versions'' and ''milestones''. 25 26 27 TracGuide is a good place to start. 28 29 Enjoy! [[BR]] 30 ''The Trac Team'' 31 32 == Starting Points == 33 34 * TracGuide -- Built-in Documentation 35 * [http://projects.edgewall.com/trac/ The Trac project] -- Trac Open Source Project 36 * [http://projects.edgewall.com/trac/wiki/TracFaq Trac FAQ] -- Frequently Asked Questions 37 * TracSupport -- Trac Support 38 39 For a complete list of local wiki pages, see TitleIndex. 40 41 Trac is brought to you by [http://www.edgewall.com/ Edgewall Software], 42 providing professional Linux and software development services to clients 43 worldwide. Visit http://www.edgewall.com/ for more information. 1 = Welcome to Trac 0.9-trac-diff = 2 3 Trac is a '''minimalistic''' approach to '''web-based''' management of 4 '''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress. 5 6 All aspects of Trac have been designed with the single goal to 7 '''help developers write great software''' while '''staying out of the way''' 8 and imposing as little as possible on a team's established process and 9 culture. 10 11 As all Wiki pages, this page is editable, this means that you can 12 modify the contents of this page simply by using your 13 web-browser. Simply click on the "Edit this page" link at the bottom 14 of the page. WikiFormatting will give you a detailed description of 15 available Wiki formatting commands. 16 17 "[wiki:TracAdmin trac-admin] ''yourenvdir'' initenv" created 18 a new Trac environment, containing a default set of wiki pages and some sample 19 data. This newly created environment also contains 20 [wiki:TracGuide documentation] to help you get started with your project. 21 22 You can use [wiki:TracAdmin trac-admin] to configure 23 [http://trac.edgewall.com/ Trac] to better fit your project, especially in 24 regard to ''components'', ''versions'' and ''milestones''. 25 26 27 TracGuide is a good place to start. 28 29 Enjoy! [[BR]] 30 ''The Trac Team'' 31 32 == Starting Points == 33 34 * TracGuide -- Built-in Documentation 35 * [http://projects.edgewall.com/trac/ The Trac project] -- Trac Open Source Project 36 * [http://projects.edgewall.com/trac/wiki/TracFaq Trac FAQ] -- Frequently Asked Questions 37 * TracSupport -- Trac Support 38 39 For a complete list of local wiki pages, see TitleIndex. 40 41 Trac is brought to you by [http://www.edgewall.com/ Edgewall Software], 42 providing professional Linux and software development services to clients 43 worldwide. Visit http://www.edgewall.com/ for more information. -
trac/__init__.py
10 10 """ 11 11 __docformat__ = 'epytext en' 12 12 13 __version__ = '0.9 '13 __version__ = '0.9-trac-diff' 14 14 __url__ = 'http://trac.edgewall.com/' 15 15 __copyright__ = '(C) 2003-2005 Edgewall Software' 16 16 __license__ = 'BSD' -
trac/versioncontrol/diff.py
217 217 ignore_space_changes) 218 218 for group in _group_opcodes(opcodes, context): 219 219 i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] 220 if i1 == 0 and i2 == 0: 221 i1, i2 = -1, -1 # support for 'A'dd changes 220 222 yield '@@ -%d,%d +%d,%d @@' % (i1 + 1, i2 - i1, j1 + 1, j2 - j1) 221 223 for tag, i1, i2, j1, j2 in group: 222 224 if tag == 'equal': -
trac/versioncontrol/api.py
122 122 'None' is a valid revision value and represents the youngest revision. 123 123 """ 124 124 return NotImplementedError 125 126 125 126 def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=1): 127 """ 128 Generator that yields change tuples (old_node, new_node, kind, change) 129 for each node change between the two arbitrary (path,rev) pairs. 130 131 The old_node is assumed to be None when the change is an ADD, 132 the new_node is assumed to be None when the change is a DELETE. 133 """ 134 raise NotImplementedError 135 136 127 137 class Node(object): 128 138 """ 129 139 Represents a directory or file in the repository. … … 164 174 """ 165 175 raise NotImplementedError 166 176 177 def get_previous(self): 178 """ 179 Return the (path, rev, chg) tuple corresponding to the previous 180 revision for that node. 181 """ 182 skip = True 183 for p in self.get_history(2): 184 if skip: 185 skip = False 186 else: 187 return p 188 167 189 def get_properties(self): 168 190 """ 169 191 Returns a dictionary containing the properties (meta-data) of the node. -
trac/versioncontrol/tests/svn_fs.py
219 219 self.assertEqual(('tags/v1', 7, 'unknown'), history.next()) 220 220 self.assertRaises(StopIteration, history.next) 221 221 222 # Diffs 223 224 def _cmp_diff(self, expected, got): 225 if expected[0]: 226 old = self.repos.get_node(*expected[0]) 227 self.assertEqual((old.path, old.rev), (got[0].path, got[0].rev)) 228 if expected[1]: 229 new = self.repos.get_node(*expected[1]) 230 self.assertEqual((new.path, new.rev), (got[1].path, got[1].rev)) 231 self.assertEqual(expected[2], (got[2], got[3])) 232 233 def test_diff_file_different_revs(self): 234 diffs = self.repos.get_changes('trunk/README.txt', 2, 'trunk/README.txt', 3) 235 self._cmp_diff((('trunk/README.txt', 2), 236 ('trunk/README.txt', 3), 237 (Node.FILE, Changeset.EDIT)), diffs.next()) 238 self.assertRaises(StopIteration, diffs.next) 239 240 def test_diff_file_different_files(self): 241 diffs = self.repos.get_changes('branches/v1x/README.txt', 12, 242 'branches/v1x/README2.txt', 12) 243 self._cmp_diff((('branches/v1x/README.txt', 12), 244 ('branches/v1x/README2.txt', 12), 245 (Node.FILE, Changeset.EDIT)), diffs.next()) 246 self.assertRaises(StopIteration, diffs.next) 247 248 def test_diff_file_no_change(self): 249 diffs = self.repos.get_changes('trunk/README.txt', 7, 250 'tags/v1/README.txt', 7) 251 self.assertRaises(StopIteration, diffs.next) 252 253 def test_diff_dir_different_revs(self): 254 diffs = self.repos.get_changes('trunk', 4, 'trunk', 8) 255 self._cmp_diff((None, ('trunk/dir1/dir2', 8), 256 (Node.DIRECTORY, Changeset.ADD)), diffs.next()) 257 self._cmp_diff((None, ('trunk/dir1/dir3', 8), 258 (Node.DIRECTORY, Changeset.ADD)), diffs.next()) 259 self._cmp_diff((None, ('trunk/README2.txt', 6), 260 (Node.FILE, Changeset.ADD)), diffs.next()) 261 self._cmp_diff((('trunk/dir2', 4), None, 262 (Node.DIRECTORY, Changeset.DELETE)), diffs.next()) 263 self._cmp_diff((('trunk/dir3', 4), None, 264 (Node.DIRECTORY, Changeset.DELETE)), diffs.next()) 265 self.assertRaises(StopIteration, diffs.next) 266 267 def test_diff_dir_different_dirs(self): 268 diffs = self.repos.get_changes('trunk', 1, 'branches/v1x', 12) 269 self._cmp_diff((None, ('branches/v1x/dir1', 12), 270 (Node.DIRECTORY, Changeset.ADD)), diffs.next()) 271 self._cmp_diff((None, ('branches/v1x/dir1/dir2', 12), 272 (Node.DIRECTORY, Changeset.ADD)), diffs.next()) 273 self._cmp_diff((None, ('branches/v1x/dir1/dir3', 12), 274 (Node.DIRECTORY, Changeset.ADD)), diffs.next()) 275 self._cmp_diff((None, ('branches/v1x/README.txt', 12), 276 (Node.FILE, Changeset.ADD)), diffs.next()) 277 self._cmp_diff((None, ('branches/v1x/README2.txt', 12), 278 (Node.FILE, Changeset.ADD)), diffs.next()) 279 self.assertRaises(StopIteration, diffs.next) 280 281 def test_diff_dir_no_change(self): 282 diffs = self.repos.get_changes('trunk', 7, 283 'tags/v1', 7) 284 self.assertRaises(StopIteration, diffs.next) 285 286 # Changesets 287 222 288 def test_changeset_repos_creation(self): 223 289 chgset = self.repos.get_changeset(0) 224 290 self.assertEqual(0, chgset.rev) -
trac/versioncontrol/svn_fs.py
349 349 expect_deletion = True 350 350 rev = self.previous_rev(rev) 351 351 352 def get_changes(self, old_path, old_rev, new_path, new_rev, 353 ignore_ancestry=0): 354 old_node = new_node = None 355 old_rev = self.normalize_rev(old_rev) 356 new_rev = self.normalize_rev(new_rev) 357 if self.has_node(old_path, old_rev): 358 old_node = self.get_node(old_path, old_rev) 359 else: 360 raise TracError, ('The Base for Diff is invalid: path %s' 361 ' doesn\'t exist in revision %s' \ 362 % (old_path, old_rev)) 363 if self.has_node(new_path, new_rev): 364 new_node = self.get_node(new_path, new_rev) 365 else: 366 raise TracError, ('The Target for Diff is invalid: path %s' 367 ' doesn\'t exist in revision %s' \ 368 % (new_path, new_rev)) 369 if new_node.kind != old_node.kind: 370 raise TracError, ('Diff mismatch: Base is a %s (%s in revision %s) ' 371 'and Target is a %s (%s in revision %s).' \ 372 % (old_node.kind, old_path, old_rev, 373 new_node.kind, new_path, new_rev)) 374 subpool = Pool(self.pool) 375 if new_node.isdir: 376 editor = DiffChangeEditor() 377 e_ptr, e_baton = delta.make_editor(editor, subpool()) 378 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) 379 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) 380 def authz_cb(root, path, pool): return 1 381 text_deltas = 0 # as this is anyway re-done in Diff.py... 382 entry_props = 0 # "... typically used only for working copy updates" 383 repos.svn_repos_dir_delta(old_root, 384 (self.scope + old_path).strip('/'), '', 385 new_root, 386 (self.scope + new_path).strip('/'), 387 e_ptr, e_baton, authz_cb, 388 text_deltas, 389 1, # directory 390 entry_props, 391 ignore_ancestry, 392 subpool()) 393 for path, kind, change in editor.deltas: 394 old_node = new_node = None 395 if change != Changeset.ADD: 396 old_node = self.get_node(posixpath.join(old_path, path), 397 old_rev) 398 if change != Changeset.DELETE: 399 new_node = self.get_node(posixpath.join(new_path, path), 400 new_rev) 401 else: 402 kind = _kindmap[fs.check_path(old_root, 403 self.scope + old_node.path, 404 subpool())] 405 yield (old_node, new_node, kind, change) 406 else: 407 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool()) 408 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool()) 409 if fs.contents_changed(old_root, self.scope + old_path, 410 new_root, self.scope + new_path, 411 subpool()): 412 yield (old_node, new_node, Node.FILE, Changeset.EDIT) 352 413 414 353 415 class SubversionNode(Node): 354 416 355 417 def __init__(self, path, rev, authz, scope, fs_ptr, pool=None): … … 371 433 self.pool()) 372 434 self.created_path = fs.node_created_path(self.root, self.scoped_path, 373 435 self.pool()) 374 # 'created_path' differs from 'path' if the last operation is a copy, 375 # and furthermore, 'path' might not exist at 'create_rev' 436 # Note: 'created_path' differs from 'path' if the last change was a copy, 437 # and furthermore, 'path' might not exist at 'create_rev'. 438 # The only guarantees are: 439 # * this node exists at (path,rev) 440 # * the node existed at (created_path,created_rev) 441 # TODO: check node id 376 442 self.rev = self.created_rev 377 443 378 444 Node.__init__(self, path, self.rev, _kindmap[node_type]) … … 417 483 if newer: 418 484 yield newer 419 485 486 # def get_previous(self): 487 # # FIXME: redo it with fs.node_history 488 420 489 def get_properties(self): 421 490 props = fs.node_proplist(self.root, self.scoped_path, self.pool()) 422 491 for name,value in props.items(): … … 506 575 507 576 def _get_prop(self, name): 508 577 return fs.revision_prop(self.fs_ptr, self.rev, name, self.pool()) 578 579 580 # 581 # Delta editor for diffs between arbitrary nodes 582 # 583 # Note 1: the 'copyfrom_path' and 'copyfrom_rev' information is not used 584 # because 'repos.svn_repos_dir_delta' *doesn't* provide it. 585 # 586 # Note 2: the 'dir_baton' is the path of the parent directory 587 # 588 589 class DiffChangeEditor(delta.Editor): 590 591 def __init__(self): 592 self.deltas = [] 593 594 # -- svn.delta.Editor callbacks 595 596 def open_root(self, base_revision, dir_pool): 597 return ('/', Changeset.EDIT) 598 599 def add_directory(self, path, dir_baton, copyfrom_path, copyfrom_rev, 600 dir_pool): 601 self.deltas.append((path, Node.DIRECTORY, Changeset.ADD)) 602 return (path, Changeset.ADD) 603 604 def open_directory(self, path, dir_baton, base_revision, dir_pool): 605 return (path, dir_baton[1]) 606 607 def change_dir_prop(self, dir_baton, name, value, pool): 608 path, change = dir_baton 609 if change != Changeset.ADD: 610 self.deltas.append((path, Node.DIRECTORY, change)) 611 612 def delete_entry(self, path, revision, dir_baton, pool): 613 self.deltas.append((path, None, Changeset.DELETE)) 614 615 def add_file(self, path, dir_baton, copyfrom_path, copyfrom_revision, 616 dir_pool): 617 self.deltas.append((path, Node.FILE, Changeset.ADD)) 618 619 def open_file(self, path, dir_baton, dummy_rev, file_pool): 620 self.deltas.append((path, Node.FILE, Changeset.EDIT)) 621 -
trac/versioncontrol/cache.py
125 125 def normalize_rev(self, rev): 126 126 return self.repos.normalize_rev(rev) 127 127 128 def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=1): 129 return self.repos.get_changes(old_path, old_rev, new_path, new_rev, ignore_ancestry) 128 130 131 129 132 class CachedChangeset(Changeset): 130 133 131 134 def __init__(self, rev, db, authz): -
trac/versioncontrol/web_ui/diff.py
1 # -*- coding: iso-8859-1 -*- 2 # 3 # Copyright (C) 2003-2005 Edgewall Software 4 # Copyright (C) 2003-2005 Jonas Borgstr�jonas@edgewall.com> 5 # Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de> 6 # All rights reserved. 7 # 8 # This software is licensed as described in the file COPYING, which 9 # you should have received as part of this distribution. The terms 10 # are also available at http://trac.edgewall.com/license.html. 11 # 12 # This software consists of voluntary contributions made by many 13 # individuals. For the exact contribution history, see the revision 14 # history and logs, available at http://projects.edgewall.com/trac/. 15 # 16 # Author: Jonas Borgstr�jonas@edgewall.com> 17 # Christopher Lenz <cmlenz@gmx.de> 18 # Christian Boos <cboos@neuf.fr> 19 20 import time 21 import re 22 import posixpath 23 from urllib import urlencode 24 25 from trac import mimeview, util 26 from trac.core import * 27 from trac.perm import IPermissionRequestor 28 from trac.versioncontrol import Changeset, Node 29 from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diff 30 from trac.versioncontrol.svn_authz import SubversionAuthorizer 31 from trac.web import IRequestHandler 32 from trac.web.chrome import add_link, add_stylesheet 33 from trac.wiki import wiki_to_html, IWikiSyntaxProvider 34 35 class DiffArgs(dict): 36 def __getattr__(self,str): 37 return self[str] 38 39 40 class ChangesPermission(Component): 41 """Simple permission provider for changes related modules.""" 42 43 implements(IPermissionRequestor) 44 45 def get_permission_actions(self): 46 return ['CHANGESET_VIEW'] 47 48 49 class AbstractDiffModule(Component): 50 """Provide flexible functionality for showing sets of differences. 51 52 If the differences shown are coming from a specific changeset, 53 then that changeset informations can be shown too. 54 55 In addition, it is possible to show only a subset of the changeset: 56 Only the changes affecting a given path will be shown. 57 This is called the ''restricted'' changeset. 58 59 But the differences can also be computed in a more general way, 60 between two arbitrary paths and/or between two arbitrary revisions. 61 In that case, there's no changeset information displayed. 62 """ 63 64 abstract = True 65 66 implements(IRequestHandler) 67 68 # IRequestHandler methods 69 70 def match_request(self, req): 71 raise NotImplementedError 72 73 def process_request(self, req): 74 """The appropriate mode of operation is inferred from 75 the request parameters: 76 * If `old` and `new` parameters are given, it will be an 77 arbitrary set of differences: `chgset` is False. 78 * If `old_path` is given and is different from `path`, 79 it's a generalized diff, from `old_path@old` 80 to `path@new`: `restricted` is False. 81 * Otherwise those are differences between two arbitrary revisions 82 of a given path: `restricted` is True. 83 * Otherwise, we are dealing with a changeset only: `chgset` is True. 84 * If the `path` is not empty or not the root, then only 85 the changes affecting that path (i.e. itself, children or 86 ancestors) will be considered: `restricted` is True. 87 * Otherwise, it's the full changeset: `restricted` is False. 88 89 In any case, the given path@rev pair must exist. 90 """ 91 req.perm.assert_permission('CHANGESET_VIEW') 92 93 # -- retrieve arguments 94 path = req.args.get('path') 95 rev = req.args.get('rev') 96 old = req.args.get('old') 97 new = req.args.get('new') 98 old_path = req.args.get('old_path') 99 100 # -- normalize and check for special case 101 repos = self.env.get_repository(req.authname) 102 path = repos.normalize_path(path) 103 rev = repos.normalize_rev(rev) 104 if old_path: # Note: normalize_path now returns '/' if given 'None' 105 old_path = repos.normalize_path(old_path) 106 107 authzperm = SubversionAuthorizer(self.env, req.authname) 108 authzperm.assert_permission_for_changeset(rev) 109 110 if old_path == path and old and old == new: # revert to Changeset 111 rev = old 112 old_path = old = new = None 113 114 diff_options = get_diff_options(req) 115 116 # -- setup the `chgset` and `restricted` flags, see docstring above. 117 chgset = not old and not new and not old_path 118 if chgset: 119 restricted = path != '' and path != '/' # (subset or not) 120 else: 121 restricted = old_path == path # (same path or not) 122 123 # -- redirect if changing the diff options 124 if req.args.has_key('update'): 125 if chgset: 126 if restricted: 127 req.redirect(self.env.href.diff(path, rev=rev)) 128 else: 129 req.redirect(self.env.href.changeset(rev)) 130 else: 131 req.redirect(self.env.href.diff(path, new=new, 132 old_path=old_path, old=old)) 133 134 # -- preparing the diff arguments 135 if chgset: 136 prev = repos.get_node(path, rev).get_previous() 137 if prev: 138 prev_path, prev_rev = prev[:2] 139 else: 140 prev_path, prev_rev = path, repos.previous_rev(rev) 141 diff_args = DiffArgs(old_path=prev_path, old_rev=prev_rev, 142 new_path=path, new_rev=rev) 143 else: 144 if not new: 145 new = repos.youngest_rev 146 elif not old: 147 old = repos.youngest_rev 148 if not old_path: 149 old_path = path 150 diff_args = DiffArgs(old_path=old_path, old_rev=old, 151 new_path=path, new_rev=new) 152 if chgset: 153 chgset = repos.get_changeset(rev) 154 req.check_modified(chgset.date, 155 diff_options[0] + ''.join(diff_options[1])) 156 else: 157 pass # FIXME: what date should we choose for a diff? 158 159 req.hdf['diff'] = diff_args 160 161 format = req.args.get('format') 162 163 if format in ['diff', 'zip']: 164 # choosing an appropriate filename 165 rpath = path.replace('/','_') 166 if chgset: 167 if restricted: 168 filename = 'changeset_%s_r%s' % (rpath, rev) 169 else: 170 filename = 'changeset_r%s' % rev 171 else: 172 if restricted: 173 filename = 'diff-%s-from-r%s-to-r%s' \ 174 % (rpath, old, new) 175 elif old_path == '/': # special case for download (#238) 176 filename = '%s-r%s' % (rpath, old) 177 else: 178 filename = 'diff-from-%s-r%s-to-%s-r%s' \ 179 % (old_path.replace('/','_'), old, rpath, new) 180 if format == 'diff': 181 self._render_diff(req, filename, repos, diff_args, 182 diff_options) 183 return 184 elif format == 'zip': 185 self._render_zip(req, filename, repos, diff_args) 186 return 187 188 # -- HTML format 189 self._render_html(req, repos, chgset, restricted, 190 diff_args, diff_options) 191 if chgset: 192 diff_params = 'rev=%s' % rev 193 else: 194 diff_params = urlencode({'path': path, 195 'new': new, 196 'old_path': old_path, 197 'old': old}) 198 add_link(req, 'alternate', '?format=diff&'+diff_params, 'Unified Diff', 199 'text/plain', 'diff') 200 add_link(req, 'alternate', '?format=zip&'+diff_params, 'Zip Archive', 201 'application/zip', 'zip') 202 add_stylesheet(req, 'common/css/changeset.css') 203 add_stylesheet(req, 'common/css/diff.css') 204 add_stylesheet(req, 'common/css/code.css') 205 return 'diff.cs', None 206 207 208 # Internal methods 209 210 def _render_html(self, req, repos, chgset, restricted, diff, diff_options): 211 """ 212 HTML version 213 """ 214 req.hdf['diff'] = { 215 'chgset': chgset and True, 216 'restricted': restricted, 217 'href': { 'new_rev': self.env.href.changeset(diff.new_rev), 218 'old_rev': self.env.href.changeset(diff.old_rev), 219 'new_path': self.env.href.browser(diff.new_path, 220 rev=diff.new_rev), 221 'old_path': self.env.href.browser(diff.old_path, 222 rev=diff.old_rev) 223 } 224 } 225 226 if chgset: # Changeset Mode (possibly restricted on a path) 227 path, rev = diff.new_path, diff.new_rev 228 229 # -- getting the change summary from the Changeset.get_changes method 230 def get_changes(): 231 old_node = new_node = None 232 for npath, kind, change, opath, orev in chgset.get_changes(): 233 if restricted and \ 234 not (npath.startswith(path) # npath is below 235 or path.startswith(npath)): # npath is above 236 continue 237 if change != Changeset.ADD: 238 old_node = repos.get_node(opath, orev) 239 if change != Changeset.DELETE: 240 new_node = repos.get_node(npath, rev) 241 yield old_node, new_node, kind, change 242 243 def _changeset_title(rev): 244 if restricted: 245 return 'Changeset %s for %s' % (rev, path) 246 else: 247 return 'Changeset %s' % rev 248 249 title = _changeset_title(rev) 250 req.hdf['changeset'] = { 251 'revision': chgset.rev, 252 'time': util.format_datetime(chgset.date), 253 'author': util.escape(chgset.author or 'anonymous'), 254 'message': wiki_to_html(chgset.message or '--', self.env, req, 255 escape_newlines=True) 256 } 257 oldest_rev = repos.oldest_rev
