Source

RhodeCode / rhodecode / controllers / files.py

Marcin Kuzminski 30ad41c 



Marcin Kuzminski 1e757ac 
Marcin Kuzminski 30ad41c 
Marcin Kuzminski 6832ef6 
Marcin Kuzminski 30ad41c 

Marcin Kuzminski 89efeda 
Marcin Kuzminski 30ad41c 

Marcin Kuzminski a671db5 



Marcin Kuzminski 6832ef6 
Marcin Kuzminski 1e757ac 



Marcin Kuzminski 6832ef6 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski a671db5 
Marcin Kuzminski 982d8a8 
Marcin Kuzminski 3ecaa17 
Marcin Kuzminski 30ad41c 
Marcin Kuzminski 166317d 
Marcin Kuzminski b872bc1 
Marcin Kuzminski 30ad41c 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski 8585fbf 
Marcin Kuzminski 30ad41c 
Marcin Kuzminski 8ecfed1 

Marcin Kuzminski 1d1ccb8 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 4c7cc3a 

Marcin Kuzminski 166317d 

Marcin Kuzminski 2b6939a 
Marcin Kuzminski 8ecfed1 





Marcin Kuzminski 166317d 
Marcin Kuzminski 8ecfed1 
Marcin Kuzminski 95800da 
Marcin Kuzminski 8ecfed1 
Marcin Kuzminski 17caf4e 

Marcin Kuzminski 8ecfed1 
Marcin Kuzminski 166317d 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski 1dc5d16 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski e8b5be2 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 7b67b0d 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski 82344ce 

Marcin Kuzminski 6832ef6 
Marcin Kuzminski 3fc9183 






Marcin Kuzminski 7b67b0d 



Marcin Kuzminski 269905f 
Marcin Kuzminski 2df8982 
Takumi IINO 94ae02c 
Marcin Kuzminski 7b67b0d 
Marcin Kuzminski 3fc9183 





Marcin Kuzminski a4e1b95 



Marcin Kuzminski 6832ef6 
Marcin Kuzminski a4e1b95 















Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski ee07357 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 82344ce 

Marcin Kuzminski e76833c 
Marcin Kuzminski 82344ce 

Marcin Kuzminski ffd0739 
Marcin Kuzminski 82344ce 


Marcin Kuzminski ee07357 
Marcin Kuzminski 82344ce 

Marcin Kuzminski 17caf4e 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 82344ce 






Marcin Kuzminski 322b53b 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 82344ce 







Marcin Kuzminski 322b53b 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 82344ce 
Marcin Kuzminski 61eda8b 
Marcin Kuzminski 0d7a127 
Marcin Kuzminski 61eda8b 
Marcin Kuzminski f3b913b 
Marcin Kuzminski a01c599 
Marcin Kuzminski f3b913b 
Marcin Kuzminski 51b203e 


Marcin Kuzminski 0d7a127 
Marcin Kuzminski 51b203e 
Marcin Kuzminski c8bd0e6 

Marcin Kuzminski 82344ce 
Marcin Kuzminski aaa4173 
Marcin Kuzminski c8bd0e6 
Marcin Kuzminski 269c6e0 


Marcin Kuzminski 1e757ac 

Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski 1e757ac 
Marcin Kuzminski 82344ce 
Marcin Kuzminski a4e1b95 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski a4e1b95 
Marcin Kuzminski 95800da 
Marcin Kuzminski a4e1b95 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski 015a42e 
Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski 1e757ac 
Marcin Kuzminski 82344ce 
Marcin Kuzminski a4e1b95 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski ed52705 

























Marcin Kuzminski 5f2fbab 



Marcin Kuzminski ed52705 



Marcin Kuzminski b7563ad 
Marcin Kuzminski ed52705 


Marcin Kuzminski 1e757ac 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski 5899fe0 








Marcin Kuzminski 166317d 




Marcin Kuzminski 856be61 



Marcin Kuzminski 166317d 




Marcin Kuzminski 6e1d245 

Marcin Kuzminski 166317d 
Marcin Kuzminski 6e1d245 
Marcin Kuzminski 166317d 
Marcin Kuzminski 6e1d245 
Marcin Kuzminski 166317d 

Marcin Kuzminski 6705eee 
Marcin Kuzminski 166317d 



Marcin Kuzminski 6e1d245 


Marcin Kuzminski 166317d 
Marcin Kuzminski 6705eee 

Marcin Kuzminski 70a5a9a 
Marcin Kuzminski 6705eee 

Takumi IINO 94ae02c 
Marcin Kuzminski 166317d 
Marcin Kuzminski 6e1d245 
Marcin Kuzminski 6705eee 
Marcin Kuzminski 166317d 






Marcin Kuzminski 01e005c 
Marcin Kuzminski 7b67b0d 

Marcin Kuzminski 5899fe0 









Marcin Kuzminski 7b67b0d 
Marcin Kuzminski 269905f 
Marcin Kuzminski 7b67b0d 













Marcin Kuzminski 269905f 





Marcin Kuzminski 7b67b0d 






Marcin Kuzminski 1db451a 


Marcin Kuzminski 269905f 
Marcin Kuzminski 7b67b0d 


Marcin Kuzminski 31ebf70 



Takumi IINO 94ae02c 
Marcin Kuzminski 7b67b0d 
Marcin Kuzminski 269905f 

Marcin Kuzminski 7b67b0d 







Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski b956e6f 
Marcin Kuzminski 05b59c4 
Marcin Kuzminski 32318ec 

Marcin Kuzminski 85ee0ea 
Marcin Kuzminski 2a8bf2a 
Marcin Kuzminski 05b59c4 
Marcin Kuzminski daa29da 
Marcin Kuzminski 85ee0ea 


Marcin Kuzminski 32318ec 
Marcin Kuzminski 85ee0ea 
Marcin Kuzminski b956e6f 

Marcin Kuzminski 3fc9183 
Marcin Kuzminski 5554aa9 
Marcin Kuzminski 72f008e 

Marcin Kuzminski ef0066e 




Marcin Kuzminski 6538691 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski daa29da 
Marcin Kuzminski b956e6f 

Marcin Kuzminski 05b59c4 

Marcin Kuzminski 840ca74 
Marcin Kuzminski 85ee0ea 
Marcin Kuzminski b956e6f 
Marcin Kuzminski 058e274 



Marcin Kuzminski 982d8a8 
Marcin Kuzminski 058e274 









Marcin Kuzminski ffd0739 
Marcin Kuzminski 058e274 



Marcin Kuzminski ffd0739 
Marcin Kuzminski 01e005c 
Marcin Kuzminski 166317d 

Marcin Kuzminski 1e757ac 
Marcin Kuzminski f28dc03 
Marcin Kuzminski 5610fd9 
Marcin Kuzminski 17caf4e 

Marcin Kuzminski 1e757ac 


Marcin Kuzminski 64cb961 
Marcin Kuzminski 17caf4e 




Marcin Kuzminski 4c7cc3a 











Marcin Kuzminski 1e757ac 

Marcin Kuzminski 3fc9183 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski e76833c 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 3fc9183 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski e76833c 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski cf51bbf 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski 1d1ccb8 
Marcin Kuzminski 5610fd9 

Marcin Kuzminski 17caf4e 
Marcin Kuzminski f3402cb 
Marcin Kuzminski 1e757ac 

Marcin Kuzminski 6011513 


Marcin Kuzminski 1e757ac 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 1d1ccb8 
Marcin Kuzminski 5610fd9 

Marcin Kuzminski 17caf4e 
Marcin Kuzminski 3765f0f 

Marcin Kuzminski 373ee70 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 17caf4e 


Marcin Kuzminski d162de1 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski 8ecfed1 
Marcin Kuzminski 17caf4e 




Marcin Kuzminski 64cb961 
Marcin Kuzminski 17caf4e 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski ffd0739 
Marcin Kuzminski 51b203e 
Marcin Kuzminski f3b913b 


Marcin Kuzminski 51b203e 

Marcin Kuzminski f3b913b 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski c47152c 



Marcin Kuzminski 4e1e265 
Marcin Kuzminski 1e757ac 
Marcin Kuzminski 4e1e265 

Marcin Kuzminski c47152c 



Marcin Kuzminski 3fc9183 
Marcin Kuzminski c47152c 


Marcin Kuzminski 3fc9183 
Marcin Kuzminski c47152c 


Marcin Kuzminski 1e757ac 
Marcin Kuzminski 8585fbf 
Marcin Kuzminski 01e005c 
Marcin Kuzminski 8585fbf 

Marcin Kuzminski 01e005c 
Marcin Kuzminski 8585fbf 


Marcin Kuzminski 203af05 

Marcin Kuzminski 530bd12 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
# -*- coding: utf-8 -*-
"""
    rhodecode.controllers.files
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Files controller for RhodeCode

    :created_on: Apr 21, 2010
    :author: marcink
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
    :license: GPLv3, see COPYING for more details.
"""
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import with_statement
import os
import logging
import traceback
import tempfile

from pylons import request, response, tmpl_context as c, url
from pylons.i18n.translation import _
from pylons.controllers.util import redirect
from pylons.decorators import jsonify

from rhodecode.lib import diffs
from rhodecode.lib import helpers as h

from rhodecode.lib.compat import OrderedDict
from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
    str2bool
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.vcs.backends.base import EmptyChangeset
from rhodecode.lib.vcs.conf import settings
from rhodecode.lib.vcs.exceptions import RepositoryError, \
    ChangesetDoesNotExistError, EmptyRepositoryError, \
    ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
from rhodecode.lib.vcs.nodes import FileNode

from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel
from rhodecode.model.db import Repository

from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
    _context_url, get_line_ctx, get_ignore_ws


log = logging.getLogger(__name__)


class FilesController(BaseRepoController):

    def __before__(self):
        super(FilesController, self).__before__()
        c.cut_off_limit = self.cut_off_limit

    def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
        """
        Safe way to get changeset if error occur it redirects to tip with
        proper message

        :param rev: revision to fetch
        :param repo_name: repo name to redirect after
        """

        try:
            return c.rhodecode_repo.get_changeset(rev)
        except EmptyRepositoryError, e:
            if not redirect_after:
                return None
            url_ = url('files_add_home',
                       repo_name=c.repo_name,
                       revision=0, f_path='')
            add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
            h.flash(h.literal(_('There are no files yet %s') % add_new),
                    category='warning')
            redirect(h.url('summary_home', repo_name=repo_name))

        except RepositoryError, e:
            h.flash(str(e), category='warning')
            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))

    def __get_filenode_or_redirect(self, repo_name, cs, path):
        """
        Returns file_node, if error occurs or given path is directory,
        it'll redirect to top level path

        :param repo_name: repo_name
        :param cs: given changeset
        :param path: path to lookup
        """

        try:
            file_node = cs.get_node(path)
            if file_node.is_dir():
                raise RepositoryError('given path is a directory')
        except RepositoryError, e:
            h.flash(str(e), category='warning')
            redirect(h.url('files_home', repo_name=repo_name,
                           revision=cs.raw_id))

        return file_node

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def index(self, repo_name, revision, f_path, annotate=False):
        # redirect to given revision from form if given
        post_revision = request.POST.get('at_rev', None)
        if post_revision:
            cs = self.__get_cs_or_redirect(post_revision, repo_name)
            redirect(url('files_home', repo_name=c.repo_name,
                         revision=cs.raw_id, f_path=f_path))

        c.changeset = self.__get_cs_or_redirect(revision, repo_name)
        c.branch = request.GET.get('branch', None)
        c.f_path = f_path
        c.annotate = annotate
        cur_rev = c.changeset.revision

        # prev link
        try:
            prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
            c.url_prev = url('files_home', repo_name=c.repo_name,
                         revision=prev_rev.raw_id, f_path=f_path)
            if c.branch:
                c.url_prev += '?branch=%s' % c.branch
        except (ChangesetDoesNotExistError, VCSError):
            c.url_prev = '#'

        # next link
        try:
            next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
            c.url_next = url('files_home', repo_name=c.repo_name,
                     revision=next_rev.raw_id, f_path=f_path)
            if c.branch:
                c.url_next += '?branch=%s' % c.branch
        except (ChangesetDoesNotExistError, VCSError):
            c.url_next = '#'

        # files or dirs
        try:
            c.file = c.changeset.get_node(f_path)

            if c.file.is_file():
                _hist = c.rhodecode_repo.get_changeset().get_file_history(f_path)
                c.file_changeset = c.changeset if c.changeset.revision < _hist[0].revision else _hist[0]
                c.file_history = self._get_node_history(None, f_path, _hist)
                c.authors = []
                for a in set([x.author for x in _hist]):
                    c.authors.append((h.email(a), h.person(a)))
            else:
                c.authors = c.file_history = []
        except RepositoryError, e:
            h.flash(str(e), category='warning')
            redirect(h.url('files_home', repo_name=repo_name,
                           revision='tip'))

        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            return render('files/files_ypjax.html')

        return render('files/files.html')

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def rawfile(self, repo_name, revision, f_path):
        cs = self.__get_cs_or_redirect(revision, repo_name)
        file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)

        response.content_disposition = 'attachment; filename=%s' % \
            safe_str(f_path.split(Repository.url_sep())[-1])

        response.content_type = file_node.mimetype
        return file_node.content

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def raw(self, repo_name, revision, f_path):
        cs = self.__get_cs_or_redirect(revision, repo_name)
        file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)

        raw_mimetype_mapping = {
            # map original mimetype to a mimetype used for "show as raw"
            # you can also provide a content-disposition to override the
            # default "attachment" disposition.
            # orig_type: (new_type, new_dispo)

            # show images inline:
            'image/x-icon': ('image/x-icon', 'inline'),
            'image/png': ('image/png', 'inline'),
            'image/gif': ('image/gif', 'inline'),
            'image/jpeg': ('image/jpeg', 'inline'),
            'image/svg+xml': ('image/svg+xml', 'inline'),
        }

        mimetype = file_node.mimetype
        try:
            mimetype, dispo = raw_mimetype_mapping[mimetype]
        except KeyError:
            # we don't know anything special about this, handle it safely
            if file_node.is_binary:
                # do same as download raw for binary files
                mimetype, dispo = 'application/octet-stream', 'attachment'
            else:
                # do not just use the original mimetype, but force text/plain,
                # otherwise it would serve text/html and that might be unsafe.
                # Note: underlying vcs library fakes text/plain mimetype if the
                # mimetype can not be determined and it thinks it is not
                # binary.This might lead to erroneous text display in some
                # cases, but helps in other cases, like with text files
                # without extension.
                mimetype, dispo = 'text/plain', 'inline'

        if dispo == 'attachment':
            dispo = 'attachment; filename=%s' % \
                        safe_str(f_path.split(os.sep)[-1])

        response.content_disposition = dispo
        response.content_type = mimetype
        return file_node.content

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
    def edit(self, repo_name, revision, f_path):
        repo = Repository.get_by_repo_name(repo_name)
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository is has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                  'warning')
            return redirect(h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        r_post = request.POST

        c.cs = self.__get_cs_or_redirect(revision, repo_name)
        c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)

        if c.file.is_binary:
            return redirect(url('files_home', repo_name=c.repo_name,
                         revision=c.cs.raw_id, f_path=f_path))

        c.f_path = f_path

        if r_post:

            old_content = c.file.content
            sl = old_content.splitlines(1)
            first_line = sl[0] if sl else ''
            # modes:  0 - Unix, 1 - Mac, 2 - DOS
            mode = detect_mode(first_line, 0)
            content = convert_line_endings(r_post.get('content'), mode)

            message = r_post.get('message') or (_('Edited %s via RhodeCode')
                                                % (f_path))
            author = self.rhodecode_user.full_contact

            if content == old_content:
                h.flash(_('No changes'),
                    category='warning')
                return redirect(url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))

            try:
                self.scm_model.commit_change(repo=c.rhodecode_repo,
                                             repo_name=repo_name, cs=c.cs,
                                             user=self.rhodecode_user,
                                             author=author, message=message,
                                             content=content, f_path=f_path)
                h.flash(_('Successfully committed to %s') % f_path,
                        category='success')

            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            return redirect(url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_edit.html')

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
    def add(self, repo_name, revision, f_path):

        repo = Repository.get_by_repo_name(repo_name)
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository is has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                  'warning')
            return redirect(h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        r_post = request.POST
        c.cs = self.__get_cs_or_redirect(revision, repo_name,
                                         redirect_after=False)
        if c.cs is None:
            c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)

        c.f_path = f_path

        if r_post:
            unix_mode = 0
            content = convert_line_endings(r_post.get('content'), unix_mode)

            message = r_post.get('message') or (_('Added %s via RhodeCode')
                                                % (f_path))
            location = r_post.get('location')
            filename = r_post.get('filename')
            file_obj = r_post.get('upload_file', None)

            if file_obj is not None and hasattr(file_obj, 'filename'):
                filename = file_obj.filename
                content = file_obj.file

            node_path = os.path.join(location, filename)
            author = self.rhodecode_user.full_contact

            if not content:
                h.flash(_('No content'), category='warning')
                return redirect(url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            if not filename:
                h.flash(_('No filename'), category='warning')
                return redirect(url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))

            try:
                self.scm_model.create_node(repo=c.rhodecode_repo,
                                           repo_name=repo_name, cs=c.cs,
                                           user=self.rhodecode_user,
                                           author=author, message=message,
                                           content=content, f_path=node_path)
                h.flash(_('Successfully committed to %s') % node_path,
                        category='success')
            except NodeAlreadyExistsError, e:
                h.flash(_(e), category='error')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            return redirect(url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_add.html')

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def archivefile(self, repo_name, fname):

        fileformat = None
        revision = None
        ext = None
        subrepos = request.GET.get('subrepos') == 'true'

        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
            archive_spec = fname.split(ext_data[1])
            if len(archive_spec) == 2 and archive_spec[1] == '':
                fileformat = a_type or ext_data[1]
                revision = archive_spec[0]
                ext = ext_data[1]

        try:
            dbrepo = RepoModel().get_by_repo_name(repo_name)
            if dbrepo.enable_downloads is False:
                return _('downloads disabled')

            if c.rhodecode_repo.alias == 'hg':
                # patch and reset hooks section of UI config to not run any
                # hooks on fetching archives with subrepos
                for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
                    c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)

            cs = c.rhodecode_repo.get_changeset(revision)
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
        except ChangesetDoesNotExistError:
            return _('Unknown revision %s') % revision
        except EmptyRepositoryError:
            return _('Empty repository')
        except (ImproperArchiveTypeError, KeyError):
            return _('Unknown archive type')

        fd, archive = tempfile.mkstemp()
        t = open(archive, 'wb')
        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
        t.close()

        def get_chunked_archive(archive):
            stream = open(archive, 'rb')
            while True:
                data = stream.read(16 * 1024)
                if not data:
                    stream.close()
                    os.close(fd)
                    os.remove(archive)
                    break
                yield data

        response.content_disposition = str('attachment; filename=%s-%s%s' \
                                           % (repo_name, revision[:12], ext))
        response.content_type = str(content_type)
        return get_chunked_archive(archive)

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    def diff(self, repo_name, f_path):
        ignore_whitespace = request.GET.get('ignorews') == '1'
        line_context = request.GET.get('context', 3)
        diff1 = request.GET.get('diff1', '')
        diff2 = request.GET.get('diff2', '')
        c.action = request.GET.get('diff')
        c.no_changes = diff1 == diff2
        c.f_path = f_path
        c.big_diff = False
        c.anchor_url = anchor_url
        c.ignorews_url = _ignorews_url
        c.context_url = _context_url
        c.changes = OrderedDict()
        c.changes[diff2] = []

        #special case if we want a show rev only, it's impl here
        #to reduce JS and callbacks
        if request.GET.get('show_rev'):
            if str2bool(request.GET.get('annotate', 'False')):
                _url = url('files_annotate_home', repo_name=c.repo_name,
                           revision=diff1, f_path=c.f_path)
            else:
                _url = url('files_home', repo_name=c.repo_name,
                           revision=diff1, f_path=c.f_path)

            return redirect(_url)
        try:
            if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
                c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
                node1 = c.changeset_1.get_node(f_path)
            else:
                c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
                node1 = FileNode('.', '', changeset=c.changeset_1)

            if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
                c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
                node2 = c.changeset_2.get_node(f_path)
            else:
                c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
                node2 = FileNode('.', '', changeset=c.changeset_2)
        except RepositoryError:
            return redirect(url('files_home', repo_name=c.repo_name,
                                f_path=f_path))

        if c.action == 'download':
            _diff = diffs.get_gitdiff(node1, node2,
                                      ignore_whitespace=ignore_whitespace,
                                      context=line_context)
            diff = diffs.DiffProcessor(_diff, format='gitdiff')

            diff_name = '%s_vs_%s.diff' % (diff1, diff2)
            response.content_type = 'text/plain'
            response.content_disposition = (
                'attachment; filename=%s' % diff_name
            )
            return diff.raw_diff()

        elif c.action == 'raw':
            _diff = diffs.get_gitdiff(node1, node2,
                                      ignore_whitespace=ignore_whitespace,
                                      context=line_context)
            diff = diffs.DiffProcessor(_diff, format='gitdiff')
            response.content_type = 'text/plain'
            return diff.raw_diff()

        else:
            fid = h.FID(diff2, node2.path)
            line_context_lcl = get_line_ctx(fid, request.GET)
            ign_whitespace_lcl = get_ignore_ws(fid, request.GET)

            lim = request.GET.get('fulldiff') or self.cut_off_limit
            _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
                                         filenode_new=node2,
                                         cut_off_limit=lim,
                                         ignore_whitespace=ign_whitespace_lcl,
                                         line_context=line_context_lcl,
                                         enable_comments=False)

            c.changes = [('', node2, diff, cs1, cs2, st,)]

        return render('files/file_diff.html')

    def _get_node_history(self, cs, f_path, changesets=None):
        if cs is None:
            # if we pass empty CS calculate history based on tip
            cs = c.rhodecode_repo.get_changeset()
        if changesets is None:
            changesets = cs.get_file_history(f_path)

        hist_l = []

        changesets_group = ([], _("Changesets"))
        branches_group = ([], _("Branches"))
        tags_group = ([], _("Tags"))
        _hg = cs.repository.alias == 'hg'
        for chs in changesets:
            _branch = '(%s)' % chs.branch if _hg else ''
            n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
            changesets_group[0].append((chs.raw_id, n_desc,))

        hist_l.append(changesets_group)

        for name, chs in c.rhodecode_repo.branches.items():
            branches_group[0].append((chs, name),)
        hist_l.append(branches_group)

        for name, chs in c.rhodecode_repo.tags.items():
            tags_group[0].append((chs, name),)
        hist_l.append(tags_group)

        return hist_l

    @LoginRequired()
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                   'repository.admin')
    @jsonify
    def nodelist(self, repo_name, revision, f_path):
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
            cs = self.__get_cs_or_redirect(revision, repo_name)
            _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
                                          flat=False)
            return {'nodes': _d + _f}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.