comparison rhodecode/controllers/files.py @ 1789:17caf4efe15c beta

implements #308 rewrote diffs to enable displaying full diff on each file - fixed escaping of html special chars in file editor
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 19 Dec 2011 00:11:20 +0200
parents 5610fd9b6803
children ef0066e95be5
comparison
equal deleted inserted replaced
1788:ef0613584ced 1789:17caf4efe15c
25 25
26 import os 26 import os
27 import logging 27 import logging
28 import traceback 28 import traceback
29 29
30 from os.path import join as jn 30 from pylons import request, response, tmpl_context as c, url
31
32 from pylons import request, response, session, tmpl_context as c, url
33 from pylons.i18n.translation import _ 31 from pylons.i18n.translation import _
34 from pylons.controllers.util import redirect 32 from pylons.controllers.util import redirect
35 from pylons.decorators import jsonify 33 from pylons.decorators import jsonify
36 34
37 from vcs.conf import settings 35 from vcs.conf import settings
38 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ 36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
39 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError 37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \
40 from vcs.nodes import FileNode, NodeKind 38 NodeAlreadyExistsError
41 39 from vcs.nodes import FileNode
42 40
41 from rhodecode.lib.compat import OrderedDict
43 from rhodecode.lib import convert_line_endings, detect_mode, safe_str 42 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
44 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator 43 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
45 from rhodecode.lib.base import BaseRepoController, render 44 from rhodecode.lib.base import BaseRepoController, render
46 from rhodecode.lib.utils import EmptyChangeset 45 from rhodecode.lib.utils import EmptyChangeset
47 from rhodecode.lib import diffs 46 from rhodecode.lib import diffs
48 import rhodecode.lib.helpers as h 47 import rhodecode.lib.helpers as h
49 from rhodecode.model.repo import RepoModel 48 from rhodecode.model.repo import RepoModel
49 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
50 _context_url, get_line_ctx, get_ignore_ws
51 from rhodecode.lib.diffs import wrapped_diff
50 52
51 log = logging.getLogger(__name__) 53 log = logging.getLogger(__name__)
52 54
53 55
54 class FilesController(BaseRepoController): 56 class FilesController(BaseRepoController):
103 redirect(h.url('files_home', repo_name=repo_name, 105 redirect(h.url('files_home', repo_name=repo_name,
104 revision=cs.raw_id)) 106 revision=cs.raw_id))
105 107
106 return file_node 108 return file_node
107 109
108
109 def __get_paths(self, changeset, starting_path): 110 def __get_paths(self, changeset, starting_path):
110 """recursive walk in root dir and return a set of all path in that dir 111 """recursive walk in root dir and return a set of all path in that dir
111 based on repository walk function 112 based on repository walk function
112 """ 113 """
113 _files = list() 114 _files = list()
126 return _dirs, _files 127 return _dirs, _files
127 128
128 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 129 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
129 'repository.admin') 130 'repository.admin')
130 def index(self, repo_name, revision, f_path): 131 def index(self, repo_name, revision, f_path):
131 #reditect to given revision from form if given 132 # redirect to given revision from form if given
132 post_revision = request.POST.get('at_rev', None) 133 post_revision = request.POST.get('at_rev', None)
133 if post_revision: 134 if post_revision:
134 cs = self.__get_cs_or_redirect(post_revision, repo_name) 135 cs = self.__get_cs_or_redirect(post_revision, repo_name)
135 redirect(url('files_home', repo_name=c.repo_name, 136 redirect(url('files_home', repo_name=c.repo_name,
136 revision=cs.raw_id, f_path=f_path)) 137 revision=cs.raw_id, f_path=f_path))
139 c.branch = request.GET.get('branch', None) 140 c.branch = request.GET.get('branch', None)
140 c.f_path = f_path 141 c.f_path = f_path
141 142
142 cur_rev = c.changeset.revision 143 cur_rev = c.changeset.revision
143 144
144 #prev link 145 # prev link
145 try: 146 try:
146 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch) 147 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
147 c.url_prev = url('files_home', repo_name=c.repo_name, 148 c.url_prev = url('files_home', repo_name=c.repo_name,
148 revision=prev_rev.raw_id, f_path=f_path) 149 revision=prev_rev.raw_id, f_path=f_path)
149 if c.branch: 150 if c.branch:
150 c.url_prev += '?branch=%s' % c.branch 151 c.url_prev += '?branch=%s' % c.branch
151 except (ChangesetDoesNotExistError, VCSError): 152 except (ChangesetDoesNotExistError, VCSError):
152 c.url_prev = '#' 153 c.url_prev = '#'
153 154
154 #next link 155 # next link
155 try: 156 try:
156 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch) 157 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
157 c.url_next = url('files_home', repo_name=c.repo_name, 158 c.url_next = url('files_home', repo_name=c.repo_name,
158 revision=next_rev.raw_id, f_path=f_path) 159 revision=next_rev.raw_id, f_path=f_path)
159 if c.branch: 160 if c.branch:
160 c.url_next += '?branch=%s' % c.branch 161 c.url_next += '?branch=%s' % c.branch
161 except (ChangesetDoesNotExistError, VCSError): 162 except (ChangesetDoesNotExistError, VCSError):
162 c.url_next = '#' 163 c.url_next = '#'
163 164
164 #files or dirs 165 # files or dirs
165 try: 166 try:
166 c.file = c.changeset.get_node(f_path) 167 c.file = c.changeset.get_node(f_path)
167 168
168 if c.file.is_file(): 169 if c.file.is_file():
169 c.file_history = self._get_node_history(c.changeset, f_path) 170 c.file_history = self._get_node_history(c.changeset, f_path)
405 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 406 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
406 'repository.admin') 407 'repository.admin')
407 def diff(self, repo_name, f_path): 408 def diff(self, repo_name, f_path):
408 ignore_whitespace = request.GET.get('ignorews') == '1' 409 ignore_whitespace = request.GET.get('ignorews') == '1'
409 line_context = request.GET.get('context', 3) 410 line_context = request.GET.get('context', 3)
410 diff1 = request.GET.get('diff1') 411 diff1 = request.GET.get('diff1', '')
411 diff2 = request.GET.get('diff2') 412 diff2 = request.GET.get('diff2', '')
412 c.action = request.GET.get('diff') 413 c.action = request.GET.get('diff')
413 c.no_changes = diff1 == diff2 414 c.no_changes = diff1 == diff2
414 c.f_path = f_path 415 c.f_path = f_path
415 c.big_diff = False 416 c.big_diff = False
416 417 c.anchor_url = anchor_url
418 c.ignorews_url = _ignorews_url
419 c.context_url = _context_url
420 c.changes = OrderedDict()
421 c.changes[diff2] = []
417 try: 422 try:
418 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: 423 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
419 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) 424 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
420 node1 = c.changeset_1.get_node(f_path) 425 node1 = c.changeset_1.get_node(f_path)
421 else: 426 else:
427 node2 = c.changeset_2.get_node(f_path) 432 node2 = c.changeset_2.get_node(f_path)
428 else: 433 else:
429 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) 434 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
430 node2 = FileNode('.', '', changeset=c.changeset_2) 435 node2 = FileNode('.', '', changeset=c.changeset_2)
431 except RepositoryError: 436 except RepositoryError:
432 return redirect(url('files_home', 437 return redirect(url('files_home', repo_name=c.repo_name,
433 repo_name=c.repo_name, f_path=f_path)) 438 f_path=f_path))
434 439
435 if c.action == 'download': 440 if c.action == 'download':
436 _diff = diffs.get_gitdiff(node1, node2, 441 _diff = diffs.get_gitdiff(node1, node2,
437 ignore_whitespace=ignore_whitespace, 442 ignore_whitespace=ignore_whitespace,
438 context=line_context) 443 context=line_context)
439 diff = diffs.DiffProcessor(_diff,format='gitdiff') 444 diff = diffs.DiffProcessor(_diff, format='gitdiff')
440 445
441 diff_name = '%s_vs_%s.diff' % (diff1, diff2) 446 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
442 response.content_type = 'text/plain' 447 response.content_type = 'text/plain'
443 response.content_disposition = 'attachment; filename=%s' \ 448 response.content_disposition = 'attachment; filename=%s' \
444 % diff_name 449 % diff_name
446 451
447 elif c.action == 'raw': 452 elif c.action == 'raw':
448 _diff = diffs.get_gitdiff(node1, node2, 453 _diff = diffs.get_gitdiff(node1, node2,
449 ignore_whitespace=ignore_whitespace, 454 ignore_whitespace=ignore_whitespace,
450 context=line_context) 455 context=line_context)
451 diff = diffs.DiffProcessor(_diff,format='gitdiff') 456 diff = diffs.DiffProcessor(_diff, format='gitdiff')
452 response.content_type = 'text/plain' 457 response.content_type = 'text/plain'
453 return diff.raw_diff() 458 return diff.raw_diff()
454 459
455 elif c.action == 'diff':
456 if node1.is_binary or node2.is_binary:
457 c.cur_diff = _('Binary file')
458 elif node1.size > self.cut_off_limit or \
459 node2.size > self.cut_off_limit:
460 c.cur_diff = ''
461 c.big_diff = True
462 else:
463 _diff = diffs.get_gitdiff(node1, node2,
464 ignore_whitespace=ignore_whitespace,
465 context=line_context)
466 diff = diffs.DiffProcessor(_diff,format='gitdiff')
467 c.cur_diff = diff.as_html()
468 else: 460 else:
469 461 fid = h.FID(diff2, node2.path)
470 #default option 462 line_context_lcl = get_line_ctx(fid, request.GET)
471 if node1.is_binary or node2.is_binary: 463 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
472 c.cur_diff = _('Binary file') 464
473 elif node1.size > self.cut_off_limit or \ 465 lim = request.GET.get('fulldiff') or self.cut_off_limit
474 node2.size > self.cut_off_limit: 466 _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1,
475 c.cur_diff = '' 467 filenode_new=node2,
476 c.big_diff = True 468 cut_off_limit=lim,
477 469 ignore_whitespace=ign_whitespace_lcl,
478 else: 470 line_context=line_context_lcl,
479 _diff = diffs.get_gitdiff(node1, node2, 471 enable_comments=False)
480 ignore_whitespace=ignore_whitespace, 472
481 context=line_context) 473 c.changes = [('', node2, diff, cs1, cs2, st,)]
482 diff = diffs.DiffProcessor(_diff,format='gitdiff') 474
483 c.cur_diff = diff.as_html()
484
485 if not c.cur_diff and not c.big_diff:
486 c.no_changes = True
487 return render('files/file_diff.html') 475 return render('files/file_diff.html')
488 476
489 def _get_node_history(self, cs, f_path): 477 def _get_node_history(self, cs, f_path):
490 changesets = cs.get_file_history(f_path) 478 changesets = cs.get_file_history(f_path)
491 hist_l = [] 479 hist_l = []
499 changesets_group[0].append((chs.raw_id, n_desc,)) 487 changesets_group[0].append((chs.raw_id, n_desc,))
500 488
501 hist_l.append(changesets_group) 489 hist_l.append(changesets_group)
502 490
503 for name, chs in c.rhodecode_repo.branches.items(): 491 for name, chs in c.rhodecode_repo.branches.items():
504 #chs = chs.split(':')[-1]
505 branches_group[0].append((chs, name),) 492 branches_group[0].append((chs, name),)
506 hist_l.append(branches_group) 493 hist_l.append(branches_group)
507 494
508 for name, chs in c.rhodecode_repo.tags.items(): 495 for name, chs in c.rhodecode_repo.tags.items():
509 #chs = chs.split(':')[-1]
510 tags_group[0].append((chs, name),) 496 tags_group[0].append((chs, name),)
511 hist_l.append(tags_group) 497 hist_l.append(tags_group)
512 498
513 return hist_l 499 return hist_l
514 500