##// END OF EJS Templates
fixes issue #856 file upload >1000 bytes on windows throws exception....
marcink -
r4072:bf5c2c75 default
parent child Browse files
Show More
@@ -1,731 +1,735 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 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, action_logger
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 from rhodecode.lib.exceptions import NonRelativePathError, IMCCommitError
61 61
62 62
63 63 log = logging.getLogger(__name__)
64 64
65 65
66 66 class FilesController(BaseRepoController):
67 67
68 68 def __before__(self):
69 69 super(FilesController, self).__before__()
70 70 c.cut_off_limit = self.cut_off_limit
71 71
72 72 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
73 73 """
74 74 Safe way to get changeset if error occur it redirects to tip with
75 75 proper message
76 76
77 77 :param rev: revision to fetch
78 78 :param repo_name: repo name to redirect after
79 79 """
80 80
81 81 try:
82 82 return c.rhodecode_repo.get_changeset(rev)
83 83 except EmptyRepositoryError, e:
84 84 if not redirect_after:
85 85 return None
86 86 url_ = url('files_add_home',
87 87 repo_name=c.repo_name,
88 88 revision=0, f_path='')
89 89 add_new = h.link_to(_('Click here to add new file'), url_)
90 90 h.flash(h.literal(_('There are no files yet %s') % add_new),
91 91 category='warning')
92 92 redirect(h.url('summary_home', repo_name=repo_name))
93 93
94 94 except RepositoryError, e: # including ChangesetDoesNotExistError
95 95 h.flash(str(e), category='error')
96 96 raise HTTPNotFound()
97 97
98 98 def __get_filenode_or_redirect(self, repo_name, cs, path):
99 99 """
100 100 Returns file_node, if error occurs or given path is directory,
101 101 it'll redirect to top level path
102 102
103 103 :param repo_name: repo_name
104 104 :param cs: given changeset
105 105 :param path: path to lookup
106 106 """
107 107
108 108 try:
109 109 file_node = cs.get_node(path)
110 110 if file_node.is_dir():
111 111 raise RepositoryError('given path is a directory')
112 112 except RepositoryError, e:
113 113 h.flash(str(e), category='error')
114 114 raise HTTPNotFound()
115 115
116 116 return file_node
117 117
118 118 @LoginRequired()
119 119 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
120 120 'repository.admin')
121 121 def index(self, repo_name, revision, f_path, annotate=False):
122 122 # redirect to given revision from form if given
123 123 post_revision = request.POST.get('at_rev', None)
124 124 if post_revision:
125 125 cs = self.__get_cs_or_redirect(post_revision, repo_name)
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='error')
179 179 raise HTTPNotFound()
180 180
181 181 if request.environ.get('HTTP_X_PARTIAL_XHR'):
182 182 return render('files/files_ypjax.html')
183 183
184 184 return render('files/files.html')
185 185
186 186 @LoginRequired()
187 187 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
188 188 'repository.admin')
189 189 def history(self, repo_name, revision, f_path, annotate=False):
190 190 if request.environ.get('HTTP_X_PARTIAL_XHR'):
191 191 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
192 192 c.f_path = f_path
193 193 c.annotate = annotate
194 194 c.file = c.changeset.get_node(f_path)
195 195 if c.file.is_file():
196 196 file_last_cs = c.file.last_changeset
197 197 c.file_changeset = (c.changeset
198 198 if c.changeset.revision < file_last_cs.revision
199 199 else file_last_cs)
200 200 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
201 201 c.authors = []
202 202 for a in set([x.author for x in _hist]):
203 203 c.authors.append((h.email(a), h.person(a)))
204 204 return render('files/files_history_box.html')
205 205
206 206 @LoginRequired()
207 207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
208 208 'repository.admin')
209 209 def rawfile(self, repo_name, revision, f_path):
210 210 cs = self.__get_cs_or_redirect(revision, repo_name)
211 211 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
212 212
213 213 response.content_disposition = 'attachment; filename=%s' % \
214 214 safe_str(f_path.split(Repository.url_sep())[-1])
215 215
216 216 response.content_type = file_node.mimetype
217 217 return file_node.content
218 218
219 219 @LoginRequired()
220 220 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
221 221 'repository.admin')
222 222 def raw(self, repo_name, revision, f_path):
223 223 cs = self.__get_cs_or_redirect(revision, repo_name)
224 224 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
225 225
226 226 raw_mimetype_mapping = {
227 227 # map original mimetype to a mimetype used for "show as raw"
228 228 # you can also provide a content-disposition to override the
229 229 # default "attachment" disposition.
230 230 # orig_type: (new_type, new_dispo)
231 231
232 232 # show images inline:
233 233 'image/x-icon': ('image/x-icon', 'inline'),
234 234 'image/png': ('image/png', 'inline'),
235 235 'image/gif': ('image/gif', 'inline'),
236 236 'image/jpeg': ('image/jpeg', 'inline'),
237 237 'image/svg+xml': ('image/svg+xml', 'inline'),
238 238 }
239 239
240 240 mimetype = file_node.mimetype
241 241 try:
242 242 mimetype, dispo = raw_mimetype_mapping[mimetype]
243 243 except KeyError:
244 244 # we don't know anything special about this, handle it safely
245 245 if file_node.is_binary:
246 246 # do same as download raw for binary files
247 247 mimetype, dispo = 'application/octet-stream', 'attachment'
248 248 else:
249 249 # do not just use the original mimetype, but force text/plain,
250 250 # otherwise it would serve text/html and that might be unsafe.
251 251 # Note: underlying vcs library fakes text/plain mimetype if the
252 252 # mimetype can not be determined and it thinks it is not
253 253 # binary.This might lead to erroneous text display in some
254 254 # cases, but helps in other cases, like with text files
255 255 # without extension.
256 256 mimetype, dispo = 'text/plain', 'inline'
257 257
258 258 if dispo == 'attachment':
259 259 dispo = 'attachment; filename=%s' % \
260 260 safe_str(f_path.split(os.sep)[-1])
261 261
262 262 response.content_disposition = dispo
263 263 response.content_type = mimetype
264 264 return file_node.content
265 265
266 266 @LoginRequired()
267 267 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
268 268 def edit(self, repo_name, revision, f_path):
269 269 repo = c.rhodecode_db_repo
270 270 if repo.enable_locking and repo.locked[0]:
271 271 h.flash(_('This repository is has been locked by %s on %s')
272 272 % (h.person_by_id(repo.locked[0]),
273 273 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
274 274 'warning')
275 275 return redirect(h.url('files_home',
276 276 repo_name=repo_name, revision='tip'))
277 277
278 278 # check if revision is a branch identifier- basically we cannot
279 279 # create multiple heads via file editing
280 280 _branches = repo.scm_instance.branches
281 281 # check if revision is a branch name or branch hash
282 282 if revision not in _branches.keys() + _branches.values():
283 283 h.flash(_('You can only edit files with revision '
284 284 'being a valid branch '), category='warning')
285 285 return redirect(h.url('files_home',
286 286 repo_name=repo_name, revision='tip',
287 287 f_path=f_path))
288 288
289 289 r_post = request.POST
290 290
291 291 c.cs = self.__get_cs_or_redirect(revision, repo_name)
292 292 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
293 293
294 294 if c.file.is_binary:
295 295 return redirect(url('files_home', repo_name=c.repo_name,
296 296 revision=c.cs.raw_id, f_path=f_path))
297 297 c.default_message = _('Edited file %s via RhodeCode') % (f_path)
298 298 c.f_path = f_path
299 299
300 300 if r_post:
301 301
302 302 old_content = c.file.content
303 303 sl = old_content.splitlines(1)
304 304 first_line = sl[0] if sl else ''
305 305 # modes: 0 - Unix, 1 - Mac, 2 - DOS
306 306 mode = detect_mode(first_line, 0)
307 307 content = convert_line_endings(r_post.get('content', ''), mode)
308 308
309 309 message = r_post.get('message') or c.default_message
310 310 author = self.rhodecode_user.full_contact
311 311
312 312 if content == old_content:
313 313 h.flash(_('No changes'), category='warning')
314 314 return redirect(url('changeset_home', repo_name=c.repo_name,
315 315 revision='tip'))
316 316 try:
317 317 self.scm_model.commit_change(repo=c.rhodecode_repo,
318 318 repo_name=repo_name, cs=c.cs,
319 319 user=self.rhodecode_user.user_id,
320 320 author=author, message=message,
321 321 content=content, f_path=f_path)
322 322 h.flash(_('Successfully committed to %s') % f_path,
323 323 category='success')
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 filename = r_post.get('filename')
359 359 location = r_post.get('location', '')
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 if hasattr(content, 'file'):
367 # non posix systems store real file under file attr
368 content = content.file
369
366 370 if not content:
367 371 h.flash(_('No content'), category='warning')
368 372 return redirect(url('changeset_home', repo_name=c.repo_name,
369 373 revision='tip'))
370 374 if not filename:
371 375 h.flash(_('No filename'), category='warning')
372 376 return redirect(url('changeset_home', repo_name=c.repo_name,
373 377 revision='tip'))
374 378 #strip all crap out of file, just leave the basename
375 379 filename = os.path.basename(filename)
376 380 node_path = os.path.join(location, filename)
377 381 author = self.rhodecode_user.full_contact
378 382
379 383 try:
380 384 nodes = {
381 385 node_path: {
382 386 'content': content
383 387 }
384 388 }
385 389 self.scm_model.create_nodes(
386 390 user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo,
387 391 message=message,
388 392 nodes=nodes,
389 393 parent_cs=c.cs,
390 394 author=author,
391 395 )
392 396
393 397 h.flash(_('Successfully committed to %s') % node_path,
394 398 category='success')
395 399 except NonRelativePathError, e:
396 400 h.flash(_('Location must be relative path and must not '
397 401 'contain .. in path'), category='warning')
398 402 return redirect(url('changeset_home', repo_name=c.repo_name,
399 403 revision='tip'))
400 404 except (NodeError, NodeAlreadyExistsError), e:
401 405 h.flash(_(e), category='error')
402 406 except Exception:
403 407 log.error(traceback.format_exc())
404 408 h.flash(_('Error occurred during commit'), category='error')
405 409 return redirect(url('changeset_home',
406 410 repo_name=c.repo_name, revision='tip'))
407 411
408 412 return render('files/files_add.html')
409 413
410 414 @LoginRequired()
411 415 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
412 416 'repository.admin')
413 417 def archivefile(self, repo_name, fname):
414 418
415 419 fileformat = None
416 420 revision = None
417 421 ext = None
418 422 subrepos = request.GET.get('subrepos') == 'true'
419 423
420 424 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
421 425 archive_spec = fname.split(ext_data[1])
422 426 if len(archive_spec) == 2 and archive_spec[1] == '':
423 427 fileformat = a_type or ext_data[1]
424 428 revision = archive_spec[0]
425 429 ext = ext_data[1]
426 430
427 431 try:
428 432 dbrepo = RepoModel().get_by_repo_name(repo_name)
429 433 if not dbrepo.enable_downloads:
430 434 return _('Downloads disabled')
431 435
432 436 if c.rhodecode_repo.alias == 'hg':
433 437 # patch and reset hooks section of UI config to not run any
434 438 # hooks on fetching archives with subrepos
435 439 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
436 440 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
437 441
438 442 cs = c.rhodecode_repo.get_changeset(revision)
439 443 content_type = settings.ARCHIVE_SPECS[fileformat][0]
440 444 except ChangesetDoesNotExistError:
441 445 return _('Unknown revision %s') % revision
442 446 except EmptyRepositoryError:
443 447 return _('Empty repository')
444 448 except (ImproperArchiveTypeError, KeyError):
445 449 return _('Unknown archive type')
446 450 # archive cache
447 451 from rhodecode import CONFIG
448 452 rev_name = cs.raw_id[:12]
449 453 archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
450 454 safe_str(rev_name), ext)
451 455
452 456 use_cached_archive = False # defines if we use cached version of archive
453 457 archive_cache_enabled = CONFIG.get('archive_cache_dir')
454 458 if not subrepos and archive_cache_enabled:
455 459 #check if we it's ok to write
456 460 if not os.path.isdir(CONFIG['archive_cache_dir']):
457 461 os.makedirs(CONFIG['archive_cache_dir'])
458 462 cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
459 463 if os.path.isfile(cached_archive_path):
460 464 log.debug('Found cached archive in %s' % cached_archive_path)
461 465 fd, archive = None, cached_archive_path
462 466 use_cached_archive = True
463 467 else:
464 468 log.debug('Archive %s is not yet cached' % (archive_name))
465 469
466 470 if not use_cached_archive:
467 471 #generate new archive
468 472 try:
469 473 fd, archive = tempfile.mkstemp()
470 474 t = open(archive, 'wb')
471 475 log.debug('Creating new temp archive in %s' % archive)
472 476 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
473 477 if archive_cache_enabled:
474 478 #if we generated the archive and use cache rename that
475 479 log.debug('Storing new archive in %s' % cached_archive_path)
476 480 shutil.move(archive, cached_archive_path)
477 481 archive = cached_archive_path
478 482 finally:
479 483 t.close()
480 484
481 485 def get_chunked_archive(archive):
482 486 stream = open(archive, 'rb')
483 487 while True:
484 488 data = stream.read(16 * 1024)
485 489 if not data:
486 490 stream.close()
487 491 if fd: # fd means we used temporary file
488 492 os.close(fd)
489 493 if not archive_cache_enabled:
490 494 log.debug('Destroing temp archive %s' % archive)
491 495 os.remove(archive)
492 496 break
493 497 yield data
494 498 # store download action
495 499 action_logger(user=c.rhodecode_user,
496 500 action='user_downloaded_archive:%s' % (archive_name),
497 501 repo=repo_name, ipaddr=self.ip_addr, commit=True)
498 502 response.content_disposition = str('attachment; filename=%s' % (archive_name))
499 503 response.content_type = str(content_type)
500 504 return get_chunked_archive(archive)
501 505
502 506 @LoginRequired()
503 507 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
504 508 'repository.admin')
505 509 def diff(self, repo_name, f_path):
506 510 ignore_whitespace = request.GET.get('ignorews') == '1'
507 511 line_context = request.GET.get('context', 3)
508 512 diff1 = request.GET.get('diff1', '')
509 513 diff2 = request.GET.get('diff2', '')
510 514 c.action = request.GET.get('diff')
511 515 c.no_changes = diff1 == diff2
512 516 c.f_path = f_path
513 517 c.big_diff = False
514 518 c.anchor_url = anchor_url
515 519 c.ignorews_url = _ignorews_url
516 520 c.context_url = _context_url
517 521 c.changes = OrderedDict()
518 522 c.changes[diff2] = []
519 523
520 524 #special case if we want a show rev only, it's impl here
521 525 #to reduce JS and callbacks
522 526
523 527 if request.GET.get('show_rev'):
524 528 if str2bool(request.GET.get('annotate', 'False')):
525 529 _url = url('files_annotate_home', repo_name=c.repo_name,
526 530 revision=diff1, f_path=c.f_path)
527 531 else:
528 532 _url = url('files_home', repo_name=c.repo_name,
529 533 revision=diff1, f_path=c.f_path)
530 534
531 535 return redirect(_url)
532 536 try:
533 537 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
534 538 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
535 539 try:
536 540 node1 = c.changeset_1.get_node(f_path)
537 541 if node1.is_dir():
538 542 raise NodeError('%s path is a %s not a file'
539 543 % (node1, type(node1)))
540 544 except NodeDoesNotExistError:
541 545 c.changeset_1 = EmptyChangeset(cs=diff1,
542 546 revision=c.changeset_1.revision,
543 547 repo=c.rhodecode_repo)
544 548 node1 = FileNode(f_path, '', changeset=c.changeset_1)
545 549 else:
546 550 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
547 551 node1 = FileNode(f_path, '', changeset=c.changeset_1)
548 552
549 553 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
550 554 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
551 555 try:
552 556 node2 = c.changeset_2.get_node(f_path)
553 557 if node2.is_dir():
554 558 raise NodeError('%s path is a %s not a file'
555 559 % (node2, type(node2)))
556 560 except NodeDoesNotExistError:
557 561 c.changeset_2 = EmptyChangeset(cs=diff2,
558 562 revision=c.changeset_2.revision,
559 563 repo=c.rhodecode_repo)
560 564 node2 = FileNode(f_path, '', changeset=c.changeset_2)
561 565 else:
562 566 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
563 567 node2 = FileNode(f_path, '', changeset=c.changeset_2)
564 568 except (RepositoryError, NodeError):
565 569 log.error(traceback.format_exc())
566 570 return redirect(url('files_home', repo_name=c.repo_name,
567 571 f_path=f_path))
568 572
569 573 if c.action == 'download':
570 574 _diff = diffs.get_gitdiff(node1, node2,
571 575 ignore_whitespace=ignore_whitespace,
572 576 context=line_context)
573 577 diff = diffs.DiffProcessor(_diff, format='gitdiff')
574 578
575 579 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
576 580 response.content_type = 'text/plain'
577 581 response.content_disposition = (
578 582 'attachment; filename=%s' % diff_name
579 583 )
580 584 return diff.as_raw()
581 585
582 586 elif c.action == 'raw':
583 587 _diff = diffs.get_gitdiff(node1, node2,
584 588 ignore_whitespace=ignore_whitespace,
585 589 context=line_context)
586 590 diff = diffs.DiffProcessor(_diff, format='gitdiff')
587 591 response.content_type = 'text/plain'
588 592 return diff.as_raw()
589 593
590 594 else:
591 595 fid = h.FID(diff2, node2.path)
592 596 line_context_lcl = get_line_ctx(fid, request.GET)
593 597 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
594 598
595 599 lim = request.GET.get('fulldiff') or self.cut_off_limit
596 600 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
597 601 filenode_new=node2,
598 602 cut_off_limit=lim,
599 603 ignore_whitespace=ign_whitespace_lcl,
600 604 line_context=line_context_lcl,
601 605 enable_comments=False)
602 606 op = ''
603 607 filename = node1.path
604 608 cs_changes = {
605 609 'fid': [cs1, cs2, op, filename, diff, st]
606 610 }
607 611 c.changes = cs_changes
608 612
609 613 return render('files/file_diff.html')
610 614
611 615 @LoginRequired()
612 616 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
613 617 'repository.admin')
614 618 def diff_2way(self, repo_name, f_path):
615 619 diff1 = request.GET.get('diff1', '')
616 620 diff2 = request.GET.get('diff2', '')
617 621 try:
618 622 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
619 623 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
620 624 try:
621 625 node1 = c.changeset_1.get_node(f_path)
622 626 if node1.is_dir():
623 627 raise NodeError('%s path is a %s not a file'
624 628 % (node1, type(node1)))
625 629 except NodeDoesNotExistError:
626 630 c.changeset_1 = EmptyChangeset(cs=diff1,
627 631 revision=c.changeset_1.revision,
628 632 repo=c.rhodecode_repo)
629 633 node1 = FileNode(f_path, '', changeset=c.changeset_1)
630 634 else:
631 635 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
632 636 node1 = FileNode(f_path, '', changeset=c.changeset_1)
633 637
634 638 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
635 639 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
636 640 try:
637 641 node2 = c.changeset_2.get_node(f_path)
638 642 if node2.is_dir():
639 643 raise NodeError('%s path is a %s not a file'
640 644 % (node2, type(node2)))
641 645 except NodeDoesNotExistError:
642 646 c.changeset_2 = EmptyChangeset(cs=diff2,
643 647 revision=c.changeset_2.revision,
644 648 repo=c.rhodecode_repo)
645 649 node2 = FileNode(f_path, '', changeset=c.changeset_2)
646 650 else:
647 651 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
648 652 node2 = FileNode(f_path, '', changeset=c.changeset_2)
649 653 except (RepositoryError, NodeError):
650 654 log.error(traceback.format_exc())
651 655 return redirect(url('files_home', repo_name=c.repo_name,
652 656 f_path=f_path))
653 657 if node2.is_binary:
654 658 node2_content = 'binary file'
655 659 else:
656 660 node2_content = node2.content
657 661
658 662 if node1.is_binary:
659 663 node1_content = 'binary file'
660 664 else:
661 665 node1_content = node1.content
662 666
663 667 html_escape_table = {
664 668 "&": "\u0026",
665 669 '"': "\u0022",
666 670 "'": "\u0027",
667 671 ">": "\u003e",
668 672 "<": "\u003c",
669 673 '\\': "\u005c",
670 674 '\n': '\\n'
671 675 }
672 676
673 677 c.orig1 = h.html_escape((node1_content), html_escape_table)
674 678 c.orig2 = h.html_escape((node2_content), html_escape_table)
675 679 c.node1 = node1
676 680 c.node2 = node2
677 681 c.cs1 = c.changeset_1
678 682 c.cs2 = c.changeset_2
679 683
680 684 return render('files/diff_2way.html')
681 685
682 686 def _get_node_history(self, cs, f_path, changesets=None):
683 687 """
684 688 get changesets history for given node
685 689
686 690 :param cs: changeset to calculate history
687 691 :param f_path: path for node to calculate history for
688 692 :param changesets: if passed don't calculate history and take
689 693 changesets defined in this list
690 694 """
691 695 # calculate history based on tip
692 696 tip_cs = c.rhodecode_repo.get_changeset()
693 697 if changesets is None:
694 698 try:
695 699 changesets = tip_cs.get_file_history(f_path)
696 700 except (NodeDoesNotExistError, ChangesetError):
697 701 #this node is not present at tip !
698 702 changesets = cs.get_file_history(f_path)
699 703 hist_l = []
700 704
701 705 changesets_group = ([], _("Changesets"))
702 706 branches_group = ([], _("Branches"))
703 707 tags_group = ([], _("Tags"))
704 708 _hg = cs.repository.alias == 'hg'
705 709 for chs in changesets:
706 710 #_branch = '(%s)' % chs.branch if _hg else ''
707 711 _branch = chs.branch
708 712 n_desc = 'r%s:%s (%s)' % (chs.revision, chs.short_id, _branch)
709 713 changesets_group[0].append((chs.raw_id, n_desc,))
710 714 hist_l.append(changesets_group)
711 715
712 716 for name, chs in c.rhodecode_repo.branches.items():
713 717 branches_group[0].append((chs, name),)
714 718 hist_l.append(branches_group)
715 719
716 720 for name, chs in c.rhodecode_repo.tags.items():
717 721 tags_group[0].append((chs, name),)
718 722 hist_l.append(tags_group)
719 723
720 724 return hist_l, changesets
721 725
722 726 @LoginRequired()
723 727 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
724 728 'repository.admin')
725 729 @jsonify
726 730 def nodelist(self, repo_name, revision, f_path):
727 731 if request.environ.get('HTTP_X_PARTIAL_XHR'):
728 732 cs = self.__get_cs_or_redirect(revision, repo_name)
729 733 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
730 734 flat=False)
731 735 return {'nodes': _d + _f}
General Comments 0
You need to be logged in to leave comments. Login now