##// END OF EJS Templates
added missing perms check on history call
marcink -
r3755:f5b20478 default
parent child Browse files
Show More
@@ -1,647 +1,650
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.files
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Files controller for RhodeCode
7 7
8 8 :created_on: Apr 21, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 from __future__ import with_statement
26 26 import os
27 27 import logging
28 28 import traceback
29 29 import tempfile
30 30 import shutil
31 31
32 32 from pylons import request, response, tmpl_context as c, url
33 33 from pylons.i18n.translation import _
34 34 from pylons.controllers.util import redirect
35 35 from rhodecode.lib.utils import jsonify
36 36
37 37 from rhodecode.lib import diffs
38 38 from rhodecode.lib import helpers as h
39 39
40 40 from rhodecode.lib.compat import OrderedDict
41 41 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
42 42 str2bool
43 43 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
44 44 from rhodecode.lib.base import BaseRepoController, render
45 45 from rhodecode.lib.vcs.backends.base import EmptyChangeset
46 46 from rhodecode.lib.vcs.conf import settings
47 47 from rhodecode.lib.vcs.exceptions import RepositoryError, \
48 48 ChangesetDoesNotExistError, EmptyRepositoryError, \
49 49 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
50 50 NodeDoesNotExistError, ChangesetError, NodeError
51 51 from rhodecode.lib.vcs.nodes import FileNode
52 52
53 53 from rhodecode.model.repo import RepoModel
54 54 from rhodecode.model.scm import ScmModel
55 55 from rhodecode.model.db import Repository
56 56
57 57 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
58 58 _context_url, get_line_ctx, get_ignore_ws
59 59 from webob.exc import HTTPNotFound
60 60
61 61
62 62 log = logging.getLogger(__name__)
63 63
64 64
65 65 class FilesController(BaseRepoController):
66 66
67 67 def __before__(self):
68 68 super(FilesController, self).__before__()
69 69 c.cut_off_limit = self.cut_off_limit
70 70
71 71 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
72 72 """
73 73 Safe way to get changeset if error occur it redirects to tip with
74 74 proper message
75 75
76 76 :param rev: revision to fetch
77 77 :param repo_name: repo name to redirect after
78 78 """
79 79
80 80 try:
81 81 return c.rhodecode_repo.get_changeset(rev)
82 82 except EmptyRepositoryError, e:
83 83 if not redirect_after:
84 84 return None
85 85 url_ = url('files_add_home',
86 86 repo_name=c.repo_name,
87 87 revision=0, f_path='')
88 88 add_new = h.link_to(_('Click here to add new file'), url_)
89 89 h.flash(h.literal(_('There are no files yet %s') % add_new),
90 90 category='warning')
91 91 redirect(h.url('summary_home', repo_name=repo_name))
92 92
93 93 except RepositoryError, e: # including ChangesetDoesNotExistError
94 94 h.flash(str(e), category='error')
95 95 raise HTTPNotFound()
96 96
97 97 def __get_filenode_or_redirect(self, repo_name, cs, path):
98 98 """
99 99 Returns file_node, if error occurs or given path is directory,
100 100 it'll redirect to top level path
101 101
102 102 :param repo_name: repo_name
103 103 :param cs: given changeset
104 104 :param path: path to lookup
105 105 """
106 106
107 107 try:
108 108 file_node = cs.get_node(path)
109 109 if file_node.is_dir():
110 110 raise RepositoryError('given path is a directory')
111 111 except RepositoryError, e:
112 112 h.flash(str(e), category='error')
113 113 raise HTTPNotFound()
114 114
115 115 return file_node
116 116
117 117 @LoginRequired()
118 118 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
119 119 'repository.admin')
120 120 def index(self, repo_name, revision, f_path, annotate=False):
121 121 # redirect to given revision from form if given
122 122 post_revision = request.POST.get('at_rev', None)
123 123 if post_revision:
124 124 cs = self.__get_cs_or_redirect(post_revision, repo_name)
125 125
126 126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 127 c.branch = request.GET.get('branch', None)
128 128 c.f_path = f_path
129 129 c.annotate = annotate
130 130 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
131 131 cur_rev = c.changeset.revision
132 132
133 133 # prev link
134 134 try:
135 135 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
136 136 c.url_prev = url('files_home', repo_name=c.repo_name,
137 137 revision=prev_rev.raw_id, f_path=f_path)
138 138 if c.branch:
139 139 c.url_prev += '?branch=%s' % c.branch
140 140 except (ChangesetDoesNotExistError, VCSError):
141 141 c.url_prev = '#'
142 142
143 143 # next link
144 144 try:
145 145 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
146 146 c.url_next = url('files_home', repo_name=c.repo_name,
147 147 revision=next_rev.raw_id, f_path=f_path)
148 148 if c.branch:
149 149 c.url_next += '?branch=%s' % c.branch
150 150 except (ChangesetDoesNotExistError, VCSError):
151 151 c.url_next = '#'
152 152
153 153 # files or dirs
154 154 try:
155 155 c.file = c.changeset.get_node(f_path)
156 156
157 157 if c.file.is_file():
158 158 c.load_full_history = False
159 159 file_last_cs = c.file.last_changeset
160 160 c.file_changeset = (c.changeset
161 161 if c.changeset.revision < file_last_cs.revision
162 162 else file_last_cs)
163 163 #determine if we're on branch head
164 164 _branches = c.rhodecode_repo.branches
165 165 c.on_branch_head = revision in _branches.keys() + _branches.values()
166 166 _hist = []
167 167 c.file_history = []
168 168 if c.load_full_history:
169 169 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
170 170
171 171 c.authors = []
172 172 for a in set([x.author for x in _hist]):
173 173 c.authors.append((h.email(a), h.person(a)))
174 174 else:
175 175 c.authors = c.file_history = []
176 176 except RepositoryError, e:
177 177 h.flash(str(e), category='error')
178 178 raise HTTPNotFound()
179 179
180 180 if request.environ.get('HTTP_X_PARTIAL_XHR'):
181 181 return render('files/files_ypjax.html')
182 182
183 183 return render('files/files.html')
184 184
185 @LoginRequired()
186 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
187 'repository.admin')
185 188 def history(self, repo_name, revision, f_path, annotate=False):
186 189 if request.environ.get('HTTP_X_PARTIAL_XHR'):
187 190 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
188 191 c.f_path = f_path
189 192 c.annotate = annotate
190 193 c.file = c.changeset.get_node(f_path)
191 194 if c.file.is_file():
192 195 file_last_cs = c.file.last_changeset
193 196 c.file_changeset = (c.changeset
194 197 if c.changeset.revision < file_last_cs.revision
195 198 else file_last_cs)
196 199 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
197 200 c.authors = []
198 201 for a in set([x.author for x in _hist]):
199 202 c.authors.append((h.email(a), h.person(a)))
200 203 return render('files/files_history_box.html')
201 204
202 205 @LoginRequired()
203 206 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
204 207 'repository.admin')
205 208 def rawfile(self, repo_name, revision, f_path):
206 209 cs = self.__get_cs_or_redirect(revision, repo_name)
207 210 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
208 211
209 212 response.content_disposition = 'attachment; filename=%s' % \
210 213 safe_str(f_path.split(Repository.url_sep())[-1])
211 214
212 215 response.content_type = file_node.mimetype
213 216 return file_node.content
214 217
215 218 @LoginRequired()
216 219 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
217 220 'repository.admin')
218 221 def raw(self, repo_name, revision, f_path):
219 222 cs = self.__get_cs_or_redirect(revision, repo_name)
220 223 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
221 224
222 225 raw_mimetype_mapping = {
223 226 # map original mimetype to a mimetype used for "show as raw"
224 227 # you can also provide a content-disposition to override the
225 228 # default "attachment" disposition.
226 229 # orig_type: (new_type, new_dispo)
227 230
228 231 # show images inline:
229 232 'image/x-icon': ('image/x-icon', 'inline'),
230 233 'image/png': ('image/png', 'inline'),
231 234 'image/gif': ('image/gif', 'inline'),
232 235 'image/jpeg': ('image/jpeg', 'inline'),
233 236 'image/svg+xml': ('image/svg+xml', 'inline'),
234 237 }
235 238
236 239 mimetype = file_node.mimetype
237 240 try:
238 241 mimetype, dispo = raw_mimetype_mapping[mimetype]
239 242 except KeyError:
240 243 # we don't know anything special about this, handle it safely
241 244 if file_node.is_binary:
242 245 # do same as download raw for binary files
243 246 mimetype, dispo = 'application/octet-stream', 'attachment'
244 247 else:
245 248 # do not just use the original mimetype, but force text/plain,
246 249 # otherwise it would serve text/html and that might be unsafe.
247 250 # Note: underlying vcs library fakes text/plain mimetype if the
248 251 # mimetype can not be determined and it thinks it is not
249 252 # binary.This might lead to erroneous text display in some
250 253 # cases, but helps in other cases, like with text files
251 254 # without extension.
252 255 mimetype, dispo = 'text/plain', 'inline'
253 256
254 257 if dispo == 'attachment':
255 258 dispo = 'attachment; filename=%s' % \
256 259 safe_str(f_path.split(os.sep)[-1])
257 260
258 261 response.content_disposition = dispo
259 262 response.content_type = mimetype
260 263 return file_node.content
261 264
262 265 @LoginRequired()
263 266 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
264 267 def edit(self, repo_name, revision, f_path):
265 268 repo = c.rhodecode_db_repo
266 269 if repo.enable_locking and repo.locked[0]:
267 270 h.flash(_('This repository is has been locked by %s on %s')
268 271 % (h.person_by_id(repo.locked[0]),
269 272 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
270 273 'warning')
271 274 return redirect(h.url('files_home',
272 275 repo_name=repo_name, revision='tip'))
273 276
274 277 # check if revision is a branch identifier- basically we cannot
275 278 # create multiple heads via file editing
276 279 _branches = repo.scm_instance.branches
277 280 # check if revision is a branch name or branch hash
278 281 if revision not in _branches.keys() + _branches.values():
279 282 h.flash(_('You can only edit files with revision '
280 283 'being a valid branch '), category='warning')
281 284 return redirect(h.url('files_home',
282 285 repo_name=repo_name, revision='tip',
283 286 f_path=f_path))
284 287
285 288 r_post = request.POST
286 289
287 290 c.cs = self.__get_cs_or_redirect(revision, repo_name)
288 291 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
289 292
290 293 if c.file.is_binary:
291 294 return redirect(url('files_home', repo_name=c.repo_name,
292 295 revision=c.cs.raw_id, f_path=f_path))
293 296 c.default_message = _('Edited file %s via RhodeCode') % (f_path)
294 297 c.f_path = f_path
295 298
296 299 if r_post:
297 300
298 301 old_content = c.file.content
299 302 sl = old_content.splitlines(1)
300 303 first_line = sl[0] if sl else ''
301 304 # modes: 0 - Unix, 1 - Mac, 2 - DOS
302 305 mode = detect_mode(first_line, 0)
303 306 content = convert_line_endings(r_post.get('content'), mode)
304 307
305 308 message = r_post.get('message') or c.default_message
306 309 author = self.rhodecode_user.full_contact
307 310
308 311 if content == old_content:
309 312 h.flash(_('No changes'), category='warning')
310 313 return redirect(url('changeset_home', repo_name=c.repo_name,
311 314 revision='tip'))
312 315 try:
313 316 self.scm_model.commit_change(repo=c.rhodecode_repo,
314 317 repo_name=repo_name, cs=c.cs,
315 318 user=self.rhodecode_user.user_id,
316 319 author=author, message=message,
317 320 content=content, f_path=f_path)
318 321 h.flash(_('Successfully committed to %s') % f_path,
319 322 category='success')
320 323
321 324 except Exception:
322 325 log.error(traceback.format_exc())
323 326 h.flash(_('Error occurred during commit'), category='error')
324 327 return redirect(url('changeset_home',
325 328 repo_name=c.repo_name, revision='tip'))
326 329
327 330 return render('files/files_edit.html')
328 331
329 332 @LoginRequired()
330 333 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
331 334 def add(self, repo_name, revision, f_path):
332 335
333 336 repo = Repository.get_by_repo_name(repo_name)
334 337 if repo.enable_locking and repo.locked[0]:
335 338 h.flash(_('This repository is has been locked by %s on %s')
336 339 % (h.person_by_id(repo.locked[0]),
337 340 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
338 341 'warning')
339 342 return redirect(h.url('files_home',
340 343 repo_name=repo_name, revision='tip'))
341 344
342 345 r_post = request.POST
343 346 c.cs = self.__get_cs_or_redirect(revision, repo_name,
344 347 redirect_after=False)
345 348 if c.cs is None:
346 349 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
347 350 c.default_message = (_('Added file via RhodeCode'))
348 351 c.f_path = f_path
349 352
350 353 if r_post:
351 354 unix_mode = 0
352 355 content = convert_line_endings(r_post.get('content'), unix_mode)
353 356
354 357 message = r_post.get('message') or c.default_message
355 358 filename = r_post.get('filename')
356 359 location = r_post.get('location')
357 360 file_obj = r_post.get('upload_file', None)
358 361
359 362 if file_obj is not None and hasattr(file_obj, 'filename'):
360 363 filename = file_obj.filename
361 364 content = file_obj.file
362 365
363 366 if not content:
364 367 h.flash(_('No content'), category='warning')
365 368 return redirect(url('changeset_home', repo_name=c.repo_name,
366 369 revision='tip'))
367 370 if not filename:
368 371 h.flash(_('No filename'), category='warning')
369 372 return redirect(url('changeset_home', repo_name=c.repo_name,
370 373 revision='tip'))
371 374 if location.startswith('/') or location.startswith('.') or '../' in location:
372 375 h.flash(_('Location must be relative path and must not '
373 376 'contain .. in path'), category='warning')
374 377 return redirect(url('changeset_home', repo_name=c.repo_name,
375 378 revision='tip'))
376 379 if location:
377 380 location = os.path.normpath(location)
378 381 filename = os.path.basename(filename)
379 382 node_path = os.path.join(location, filename)
380 383 author = self.rhodecode_user.full_contact
381 384
382 385 try:
383 386 self.scm_model.create_node(repo=c.rhodecode_repo,
384 387 repo_name=repo_name, cs=c.cs,
385 388 user=self.rhodecode_user.user_id,
386 389 author=author, message=message,
387 390 content=content, f_path=node_path)
388 391 h.flash(_('Successfully committed to %s') % node_path,
389 392 category='success')
390 393 except (NodeError, NodeAlreadyExistsError), e:
391 394 h.flash(_(e), category='error')
392 395 except Exception:
393 396 log.error(traceback.format_exc())
394 397 h.flash(_('Error occurred during commit'), category='error')
395 398 return redirect(url('changeset_home',
396 399 repo_name=c.repo_name, revision='tip'))
397 400
398 401 return render('files/files_add.html')
399 402
400 403 @LoginRequired()
401 404 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
402 405 'repository.admin')
403 406 def archivefile(self, repo_name, fname):
404 407
405 408 fileformat = None
406 409 revision = None
407 410 ext = None
408 411 subrepos = request.GET.get('subrepos') == 'true'
409 412
410 413 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
411 414 archive_spec = fname.split(ext_data[1])
412 415 if len(archive_spec) == 2 and archive_spec[1] == '':
413 416 fileformat = a_type or ext_data[1]
414 417 revision = archive_spec[0]
415 418 ext = ext_data[1]
416 419
417 420 try:
418 421 dbrepo = RepoModel().get_by_repo_name(repo_name)
419 422 if not dbrepo.enable_downloads:
420 423 return _('Downloads disabled')
421 424
422 425 if c.rhodecode_repo.alias == 'hg':
423 426 # patch and reset hooks section of UI config to not run any
424 427 # hooks on fetching archives with subrepos
425 428 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
426 429 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
427 430
428 431 cs = c.rhodecode_repo.get_changeset(revision)
429 432 content_type = settings.ARCHIVE_SPECS[fileformat][0]
430 433 except ChangesetDoesNotExistError:
431 434 return _('Unknown revision %s') % revision
432 435 except EmptyRepositoryError:
433 436 return _('Empty repository')
434 437 except (ImproperArchiveTypeError, KeyError):
435 438 return _('Unknown archive type')
436 439 # archive cache
437 440 from rhodecode import CONFIG
438 441 rev_name = cs.raw_id[:12]
439 442 archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
440 443 safe_str(rev_name), ext)
441 444
442 445 use_cached_archive = False # defines if we use cached version of archive
443 446 archive_cache_enabled = CONFIG.get('archive_cache_dir')
444 447 if not subrepos and archive_cache_enabled:
445 448 #check if we it's ok to write
446 449 if not os.path.isdir(CONFIG['archive_cache_dir']):
447 450 os.makedirs(CONFIG['archive_cache_dir'])
448 451 cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
449 452 if os.path.isfile(cached_archive_path):
450 453 log.debug('Found cached archive in %s' % cached_archive_path)
451 454 fd, archive = None, cached_archive_path
452 455 use_cached_archive = True
453 456 else:
454 457 log.debug('Archive %s is not yet cached' % (archive_name))
455 458
456 459 if not use_cached_archive:
457 460 #generate new archive
458 461 try:
459 462 fd, archive = tempfile.mkstemp()
460 463 t = open(archive, 'wb')
461 464 log.debug('Creating new temp archive in %s' % archive)
462 465 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
463 466 if archive_cache_enabled:
464 467 #if we generated the archive and use cache rename that
465 468 log.debug('Storing new archive in %s' % cached_archive_path)
466 469 shutil.move(archive, cached_archive_path)
467 470 archive = cached_archive_path
468 471 finally:
469 472 t.close()
470 473
471 474 def get_chunked_archive(archive):
472 475 stream = open(archive, 'rb')
473 476 while True:
474 477 data = stream.read(16 * 1024)
475 478 if not data:
476 479 stream.close()
477 480 if fd: # fd means we used temporary file
478 481 os.close(fd)
479 482 if not archive_cache_enabled:
480 483 log.debug('Destroing temp archive %s' % archive)
481 484 os.remove(archive)
482 485 break
483 486 yield data
484 487
485 488 response.content_disposition = str('attachment; filename=%s' % (archive_name))
486 489 response.content_type = str(content_type)
487 490 return get_chunked_archive(archive)
488 491
489 492 @LoginRequired()
490 493 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
491 494 'repository.admin')
492 495 def diff(self, repo_name, f_path):
493 496 ignore_whitespace = request.GET.get('ignorews') == '1'
494 497 line_context = request.GET.get('context', 3)
495 498 diff1 = request.GET.get('diff1', '')
496 499 diff2 = request.GET.get('diff2', '')
497 500 c.action = request.GET.get('diff')
498 501 c.no_changes = diff1 == diff2
499 502 c.f_path = f_path
500 503 c.big_diff = False
501 504 c.anchor_url = anchor_url
502 505 c.ignorews_url = _ignorews_url
503 506 c.context_url = _context_url
504 507 c.changes = OrderedDict()
505 508 c.changes[diff2] = []
506 509
507 510 #special case if we want a show rev only, it's impl here
508 511 #to reduce JS and callbacks
509 512
510 513 if request.GET.get('show_rev'):
511 514 if str2bool(request.GET.get('annotate', 'False')):
512 515 _url = url('files_annotate_home', repo_name=c.repo_name,
513 516 revision=diff1, f_path=c.f_path)
514 517 else:
515 518 _url = url('files_home', repo_name=c.repo_name,
516 519 revision=diff1, f_path=c.f_path)
517 520
518 521 return redirect(_url)
519 522 try:
520 523 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
521 524 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
522 525 try:
523 526 node1 = c.changeset_1.get_node(f_path)
524 527 if node1.is_dir():
525 528 raise NodeError('%s path is a %s not a file'
526 529 % (node1, type(node1)))
527 530 except NodeDoesNotExistError:
528 531 c.changeset_1 = EmptyChangeset(cs=diff1,
529 532 revision=c.changeset_1.revision,
530 533 repo=c.rhodecode_repo)
531 534 node1 = FileNode(f_path, '', changeset=c.changeset_1)
532 535 else:
533 536 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
534 537 node1 = FileNode(f_path, '', changeset=c.changeset_1)
535 538
536 539 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
537 540 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
538 541 try:
539 542 node2 = c.changeset_2.get_node(f_path)
540 543 if node2.is_dir():
541 544 raise NodeError('%s path is a %s not a file'
542 545 % (node2, type(node2)))
543 546 except NodeDoesNotExistError:
544 547 c.changeset_2 = EmptyChangeset(cs=diff2,
545 548 revision=c.changeset_2.revision,
546 549 repo=c.rhodecode_repo)
547 550 node2 = FileNode(f_path, '', changeset=c.changeset_2)
548 551 else:
549 552 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
550 553 node2 = FileNode(f_path, '', changeset=c.changeset_2)
551 554 except (RepositoryError, NodeError):
552 555 log.error(traceback.format_exc())
553 556 return redirect(url('files_home', repo_name=c.repo_name,
554 557 f_path=f_path))
555 558
556 559 if c.action == 'download':
557 560 _diff = diffs.get_gitdiff(node1, node2,
558 561 ignore_whitespace=ignore_whitespace,
559 562 context=line_context)
560 563 diff = diffs.DiffProcessor(_diff, format='gitdiff')
561 564
562 565 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
563 566 response.content_type = 'text/plain'
564 567 response.content_disposition = (
565 568 'attachment; filename=%s' % diff_name
566 569 )
567 570 return diff.as_raw()
568 571
569 572 elif c.action == 'raw':
570 573 _diff = diffs.get_gitdiff(node1, node2,
571 574 ignore_whitespace=ignore_whitespace,
572 575 context=line_context)
573 576 diff = diffs.DiffProcessor(_diff, format='gitdiff')
574 577 response.content_type = 'text/plain'
575 578 return diff.as_raw()
576 579
577 580 else:
578 581 fid = h.FID(diff2, node2.path)
579 582 line_context_lcl = get_line_ctx(fid, request.GET)
580 583 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
581 584
582 585 lim = request.GET.get('fulldiff') or self.cut_off_limit
583 586 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
584 587 filenode_new=node2,
585 588 cut_off_limit=lim,
586 589 ignore_whitespace=ign_whitespace_lcl,
587 590 line_context=line_context_lcl,
588 591 enable_comments=False)
589 592 op = ''
590 593 filename = node1.path
591 594 cs_changes = {
592 595 'fid': [cs1, cs2, op, filename, diff, st]
593 596 }
594 597 c.changes = cs_changes
595 598
596 599 return render('files/file_diff.html')
597 600
598 601 def _get_node_history(self, cs, f_path, changesets=None):
599 602 """
600 603 get changesets history for given node
601 604
602 605 :param cs: changeset to calculate history
603 606 :param f_path: path for node to calculate history for
604 607 :param changesets: if passed don't calculate history and take
605 608 changesets defined in this list
606 609 """
607 610 # calculate history based on tip
608 611 tip_cs = c.rhodecode_repo.get_changeset()
609 612 if changesets is None:
610 613 try:
611 614 changesets = tip_cs.get_file_history(f_path)
612 615 except (NodeDoesNotExistError, ChangesetError):
613 616 #this node is not present at tip !
614 617 changesets = cs.get_file_history(f_path)
615 618 hist_l = []
616 619
617 620 changesets_group = ([], _("Changesets"))
618 621 branches_group = ([], _("Branches"))
619 622 tags_group = ([], _("Tags"))
620 623 _hg = cs.repository.alias == 'hg'
621 624 for chs in changesets:
622 625 #_branch = '(%s)' % chs.branch if _hg else ''
623 626 _branch = chs.branch
624 627 n_desc = 'r%s:%s (%s)' % (chs.revision, chs.short_id, _branch)
625 628 changesets_group[0].append((chs.raw_id, n_desc,))
626 629 hist_l.append(changesets_group)
627 630
628 631 for name, chs in c.rhodecode_repo.branches.items():
629 632 branches_group[0].append((chs, name),)
630 633 hist_l.append(branches_group)
631 634
632 635 for name, chs in c.rhodecode_repo.tags.items():
633 636 tags_group[0].append((chs, name),)
634 637 hist_l.append(tags_group)
635 638
636 639 return hist_l, changesets
637 640
638 641 @LoginRequired()
639 642 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
640 643 'repository.admin')
641 644 @jsonify
642 645 def nodelist(self, repo_name, revision, f_path):
643 646 if request.environ.get('HTTP_X_PARTIAL_XHR'):
644 647 cs = self.__get_cs_or_redirect(revision, repo_name)
645 648 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
646 649 flat=False)
647 650 return {'nodes': _d + _f}
General Comments 0
You need to be logged in to leave comments. Login now