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