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