##// END OF EJS Templates
backported fix from beta to disable hooks, on archive with subrepos
marcink -
r1943:bab80d14 default
parent child Browse files
Show More
@@ -1,507 +1,513 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) 2009-2011 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
25
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29
29
30 from os.path import join as jn
30 from os.path import join as jn
31
31
32 from pylons import request, response, session, tmpl_context as c, url
32 from pylons import request, response, session, 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 pylons.decorators import jsonify
35 from pylons.decorators import jsonify
36
36
37 from vcs.conf import settings
37 from vcs.conf import settings
38 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
38 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
39 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
39 EmptyRepositoryError, ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
40 from vcs.nodes import FileNode, NodeKind
40 from vcs.nodes import FileNode, NodeKind
41 from vcs.utils import diffs as differ
41 from vcs.utils import diffs as differ
42
42
43 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
43 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
44 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
44 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
45 from rhodecode.lib.base import BaseRepoController, render
45 from rhodecode.lib.base import BaseRepoController, render
46 from rhodecode.lib.utils import EmptyChangeset
46 from rhodecode.lib.utils import EmptyChangeset
47 import rhodecode.lib.helpers as h
47 import rhodecode.lib.helpers as h
48 from rhodecode.model.repo import RepoModel
48 from rhodecode.model.repo import RepoModel
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class FilesController(BaseRepoController):
53 class FilesController(BaseRepoController):
54
54
55 @LoginRequired()
55 @LoginRequired()
56 def __before__(self):
56 def __before__(self):
57 super(FilesController, self).__before__()
57 super(FilesController, self).__before__()
58 c.cut_off_limit = self.cut_off_limit
58 c.cut_off_limit = self.cut_off_limit
59
59
60 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
60 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
61 """
61 """
62 Safe way to get changeset if error occur it redirects to tip with
62 Safe way to get changeset if error occur it redirects to tip with
63 proper message
63 proper message
64
64
65 :param rev: revision to fetch
65 :param rev: revision to fetch
66 :param repo_name: repo name to redirect after
66 :param repo_name: repo name to redirect after
67 """
67 """
68
68
69 try:
69 try:
70 return c.rhodecode_repo.get_changeset(rev)
70 return c.rhodecode_repo.get_changeset(rev)
71 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
72 if not redirect_after:
72 if not redirect_after:
73 return None
73 return None
74 url_ = url('files_add_home',
74 url_ = url('files_add_home',
75 repo_name=c.repo_name,
75 repo_name=c.repo_name,
76 revision=0, f_path='')
76 revision=0, f_path='')
77 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
77 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
78 h.flash(h.literal(_('There are no files yet %s' % add_new)),
78 h.flash(h.literal(_('There are no files yet %s' % add_new)),
79 category='warning')
79 category='warning')
80 redirect(h.url('summary_home', repo_name=repo_name))
80 redirect(h.url('summary_home', repo_name=repo_name))
81
81
82 except RepositoryError, e:
82 except RepositoryError, e:
83 h.flash(str(e), category='warning')
83 h.flash(str(e), category='warning')
84 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
84 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
85
85
86 def __get_filenode_or_redirect(self, repo_name, cs, path):
86 def __get_filenode_or_redirect(self, repo_name, cs, path):
87 """
87 """
88 Returns file_node, if error occurs or given path is directory,
88 Returns file_node, if error occurs or given path is directory,
89 it'll redirect to top level path
89 it'll redirect to top level path
90
90
91 :param repo_name: repo_name
91 :param repo_name: repo_name
92 :param cs: given changeset
92 :param cs: given changeset
93 :param path: path to lookup
93 :param path: path to lookup
94 """
94 """
95
95
96 try:
96 try:
97 file_node = cs.get_node(path)
97 file_node = cs.get_node(path)
98 if file_node.is_dir():
98 if file_node.is_dir():
99 raise RepositoryError('given path is a directory')
99 raise RepositoryError('given path is a directory')
100 except RepositoryError, e:
100 except RepositoryError, e:
101 h.flash(str(e), category='warning')
101 h.flash(str(e), category='warning')
102 redirect(h.url('files_home', repo_name=repo_name,
102 redirect(h.url('files_home', repo_name=repo_name,
103 revision=cs.raw_id))
103 revision=cs.raw_id))
104
104
105 return file_node
105 return file_node
106
106
107
107
108 def __get_paths(self, changeset, starting_path):
108 def __get_paths(self, changeset, starting_path):
109 """recursive walk in root dir and return a set of all path in that dir
109 """recursive walk in root dir and return a set of all path in that dir
110 based on repository walk function
110 based on repository walk function
111 """
111 """
112 _files = list()
112 _files = list()
113 _dirs = list()
113 _dirs = list()
114
114
115 try:
115 try:
116 tip = changeset
116 tip = changeset
117 for topnode, dirs, files in tip.walk(starting_path):
117 for topnode, dirs, files in tip.walk(starting_path):
118 for f in files:
118 for f in files:
119 _files.append(f.path)
119 _files.append(f.path)
120 for d in dirs:
120 for d in dirs:
121 _dirs.append(d.path)
121 _dirs.append(d.path)
122 except RepositoryError, e:
122 except RepositoryError, e:
123 log.debug(traceback.format_exc())
123 log.debug(traceback.format_exc())
124 pass
124 pass
125 return _dirs, _files
125 return _dirs, _files
126
126
127 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
127 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
128 'repository.admin')
128 'repository.admin')
129 def index(self, repo_name, revision, f_path):
129 def index(self, repo_name, revision, f_path):
130 #reditect to given revision from form if given
130 # redirect to given revision from form if given
131 post_revision = request.POST.get('at_rev', None)
131 post_revision = request.POST.get('at_rev', None)
132 if post_revision:
132 if post_revision:
133 cs = self.__get_cs_or_redirect(post_revision, repo_name)
133 cs = self.__get_cs_or_redirect(post_revision, repo_name)
134 redirect(url('files_home', repo_name=c.repo_name,
134 redirect(url('files_home', repo_name=c.repo_name,
135 revision=cs.raw_id, f_path=f_path))
135 revision=cs.raw_id, f_path=f_path))
136
136
137 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
137 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
138 c.branch = request.GET.get('branch', None)
138 c.branch = request.GET.get('branch', None)
139 c.f_path = f_path
139 c.f_path = f_path
140
140
141 cur_rev = c.changeset.revision
141 cur_rev = c.changeset.revision
142
142
143 #prev link
143 # prev link
144 try:
144 try:
145 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
145 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
146 c.url_prev = url('files_home', repo_name=c.repo_name,
146 c.url_prev = url('files_home', repo_name=c.repo_name,
147 revision=prev_rev.raw_id, f_path=f_path)
147 revision=prev_rev.raw_id, f_path=f_path)
148 if c.branch:
148 if c.branch:
149 c.url_prev += '?branch=%s' % c.branch
149 c.url_prev += '?branch=%s' % c.branch
150 except (ChangesetDoesNotExistError, VCSError):
150 except (ChangesetDoesNotExistError, VCSError):
151 c.url_prev = '#'
151 c.url_prev = '#'
152
152
153 #next link
153 # next link
154 try:
154 try:
155 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
155 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
156 c.url_next = url('files_home', repo_name=c.repo_name,
156 c.url_next = url('files_home', repo_name=c.repo_name,
157 revision=next_rev.raw_id, f_path=f_path)
157 revision=next_rev.raw_id, f_path=f_path)
158 if c.branch:
158 if c.branch:
159 c.url_next += '?branch=%s' % c.branch
159 c.url_next += '?branch=%s' % c.branch
160 except (ChangesetDoesNotExistError, VCSError):
160 except (ChangesetDoesNotExistError, VCSError):
161 c.url_next = '#'
161 c.url_next = '#'
162
162
163 #files or dirs
163 # files or dirs
164 try:
164 try:
165 c.files_list = c.changeset.get_node(f_path)
165 c.files_list = c.changeset.get_node(f_path)
166
166
167 if c.files_list.is_file():
167 if c.files_list.is_file():
168 c.file_history = self._get_node_history(c.changeset, f_path)
168 c.file_history = self._get_node_history(c.changeset, f_path)
169 else:
169 else:
170 c.file_history = []
170 c.file_history = []
171 except RepositoryError, e:
171 except RepositoryError, e:
172 h.flash(str(e), category='warning')
172 h.flash(str(e), category='warning')
173 redirect(h.url('files_home', repo_name=repo_name,
173 redirect(h.url('files_home', repo_name=repo_name,
174 revision=revision))
174 revision=revision))
175
175
176 return render('files/files.html')
176 return render('files/files.html')
177
177
178 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
178 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 'repository.admin')
179 'repository.admin')
180 def rawfile(self, repo_name, revision, f_path):
180 def rawfile(self, repo_name, revision, f_path):
181 cs = self.__get_cs_or_redirect(revision, repo_name)
181 cs = self.__get_cs_or_redirect(revision, repo_name)
182 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
182 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
183
183
184 response.content_disposition = 'attachment; filename=%s' % \
184 response.content_disposition = 'attachment; filename=%s' % \
185 safe_str(f_path.split(os.sep)[-1])
185 safe_str(f_path.split(os.sep)[-1])
186
186
187 response.content_type = file_node.mimetype
187 response.content_type = file_node.mimetype
188 return file_node.content
188 return file_node.content
189
189
190 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
190 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
191 'repository.admin')
191 'repository.admin')
192 def raw(self, repo_name, revision, f_path):
192 def raw(self, repo_name, revision, f_path):
193 cs = self.__get_cs_or_redirect(revision, repo_name)
193 cs = self.__get_cs_or_redirect(revision, repo_name)
194 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
194 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
195
195
196 raw_mimetype_mapping = {
196 raw_mimetype_mapping = {
197 # map original mimetype to a mimetype used for "show as raw"
197 # map original mimetype to a mimetype used for "show as raw"
198 # you can also provide a content-disposition to override the
198 # you can also provide a content-disposition to override the
199 # default "attachment" disposition.
199 # default "attachment" disposition.
200 # orig_type: (new_type, new_dispo)
200 # orig_type: (new_type, new_dispo)
201
201
202 # show images inline:
202 # show images inline:
203 'image/x-icon': ('image/x-icon', 'inline'),
203 'image/x-icon': ('image/x-icon', 'inline'),
204 'image/png': ('image/png', 'inline'),
204 'image/png': ('image/png', 'inline'),
205 'image/gif': ('image/gif', 'inline'),
205 'image/gif': ('image/gif', 'inline'),
206 'image/jpeg': ('image/jpeg', 'inline'),
206 'image/jpeg': ('image/jpeg', 'inline'),
207 'image/svg+xml': ('image/svg+xml', 'inline'),
207 'image/svg+xml': ('image/svg+xml', 'inline'),
208 }
208 }
209
209
210 mimetype = file_node.mimetype
210 mimetype = file_node.mimetype
211 try:
211 try:
212 mimetype, dispo = raw_mimetype_mapping[mimetype]
212 mimetype, dispo = raw_mimetype_mapping[mimetype]
213 except KeyError:
213 except KeyError:
214 # we don't know anything special about this, handle it safely
214 # we don't know anything special about this, handle it safely
215 if file_node.is_binary:
215 if file_node.is_binary:
216 # do same as download raw for binary files
216 # do same as download raw for binary files
217 mimetype, dispo = 'application/octet-stream', 'attachment'
217 mimetype, dispo = 'application/octet-stream', 'attachment'
218 else:
218 else:
219 # do not just use the original mimetype, but force text/plain,
219 # do not just use the original mimetype, but force text/plain,
220 # otherwise it would serve text/html and that might be unsafe.
220 # otherwise it would serve text/html and that might be unsafe.
221 # Note: underlying vcs library fakes text/plain mimetype if the
221 # Note: underlying vcs library fakes text/plain mimetype if the
222 # mimetype can not be determined and it thinks it is not
222 # mimetype can not be determined and it thinks it is not
223 # binary.This might lead to erroneous text display in some
223 # binary.This might lead to erroneous text display in some
224 # cases, but helps in other cases, like with text files
224 # cases, but helps in other cases, like with text files
225 # without extension.
225 # without extension.
226 mimetype, dispo = 'text/plain', 'inline'
226 mimetype, dispo = 'text/plain', 'inline'
227
227
228 if dispo == 'attachment':
228 if dispo == 'attachment':
229 dispo = 'attachment; filename=%s' % \
229 dispo = 'attachment; filename=%s' % \
230 safe_str(f_path.split(os.sep)[-1])
230 safe_str(f_path.split(os.sep)[-1])
231
231
232 response.content_disposition = dispo
232 response.content_disposition = dispo
233 response.content_type = mimetype
233 response.content_type = mimetype
234 return file_node.content
234 return file_node.content
235
235
236 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
236 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
237 'repository.admin')
237 'repository.admin')
238 def annotate(self, repo_name, revision, f_path):
238 def annotate(self, repo_name, revision, f_path):
239 c.cs = self.__get_cs_or_redirect(revision, repo_name)
239 c.cs = self.__get_cs_or_redirect(revision, repo_name)
240 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
240 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
241
241
242 c.file_history = self._get_node_history(c.cs, f_path)
242 c.file_history = self._get_node_history(c.cs, f_path)
243 c.f_path = f_path
243 c.f_path = f_path
244 return render('files/files_annotate.html')
244 return render('files/files_annotate.html')
245
245
246 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
246 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
247 def edit(self, repo_name, revision, f_path):
247 def edit(self, repo_name, revision, f_path):
248 r_post = request.POST
248 r_post = request.POST
249
249
250 c.cs = self.__get_cs_or_redirect(revision, repo_name)
250 c.cs = self.__get_cs_or_redirect(revision, repo_name)
251 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
251 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
252
252
253 if c.file.is_binary:
253 if c.file.is_binary:
254 return redirect(url('files_home', repo_name=c.repo_name,
254 return redirect(url('files_home', repo_name=c.repo_name,
255 revision=c.cs.raw_id, f_path=f_path))
255 revision=c.cs.raw_id, f_path=f_path))
256
256
257 c.f_path = f_path
257 c.f_path = f_path
258
258
259 if r_post:
259 if r_post:
260
260
261 old_content = c.file.content
261 old_content = c.file.content
262 sl = old_content.splitlines(1)
262 sl = old_content.splitlines(1)
263 first_line = sl[0] if sl else ''
263 first_line = sl[0] if sl else ''
264 # modes: 0 - Unix, 1 - Mac, 2 - DOS
264 # modes: 0 - Unix, 1 - Mac, 2 - DOS
265 mode = detect_mode(first_line, 0)
265 mode = detect_mode(first_line, 0)
266 content = convert_line_endings(r_post.get('content'), mode)
266 content = convert_line_endings(r_post.get('content'), mode)
267
267
268 message = r_post.get('message') or (_('Edited %s via RhodeCode')
268 message = r_post.get('message') or (_('Edited %s via RhodeCode')
269 % (f_path))
269 % (f_path))
270 author = self.rhodecode_user.full_contact
270 author = self.rhodecode_user.full_contact
271
271
272 if content == old_content:
272 if content == old_content:
273 h.flash(_('No changes'),
273 h.flash(_('No changes'),
274 category='warning')
274 category='warning')
275 return redirect(url('changeset_home', repo_name=c.repo_name,
275 return redirect(url('changeset_home', repo_name=c.repo_name,
276 revision='tip'))
276 revision='tip'))
277
277
278 try:
278 try:
279 self.scm_model.commit_change(repo=c.rhodecode_repo,
279 self.scm_model.commit_change(repo=c.rhodecode_repo,
280 repo_name=repo_name, cs=c.cs,
280 repo_name=repo_name, cs=c.cs,
281 user=self.rhodecode_user,
281 user=self.rhodecode_user,
282 author=author, message=message,
282 author=author, message=message,
283 content=content, f_path=f_path)
283 content=content, f_path=f_path)
284 h.flash(_('Successfully committed to %s' % f_path),
284 h.flash(_('Successfully committed to %s' % f_path),
285 category='success')
285 category='success')
286
286
287 except Exception:
287 except Exception:
288 log.error(traceback.format_exc())
288 log.error(traceback.format_exc())
289 h.flash(_('Error occurred during commit'), category='error')
289 h.flash(_('Error occurred during commit'), category='error')
290 return redirect(url('changeset_home',
290 return redirect(url('changeset_home',
291 repo_name=c.repo_name, revision='tip'))
291 repo_name=c.repo_name, revision='tip'))
292
292
293 return render('files/files_edit.html')
293 return render('files/files_edit.html')
294
294
295 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
295 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
296 def add(self, repo_name, revision, f_path):
296 def add(self, repo_name, revision, f_path):
297 r_post = request.POST
297 r_post = request.POST
298 c.cs = self.__get_cs_or_redirect(revision, repo_name,
298 c.cs = self.__get_cs_or_redirect(revision, repo_name,
299 redirect_after=False)
299 redirect_after=False)
300 if c.cs is None:
300 if c.cs is None:
301 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
301 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
302
302
303 c.f_path = f_path
303 c.f_path = f_path
304
304
305 if r_post:
305 if r_post:
306 unix_mode = 0
306 unix_mode = 0
307 content = convert_line_endings(r_post.get('content'), unix_mode)
307 content = convert_line_endings(r_post.get('content'), unix_mode)
308
308
309 message = r_post.get('message') or (_('Added %s via RhodeCode')
309 message = r_post.get('message') or (_('Added %s via RhodeCode')
310 % (f_path))
310 % (f_path))
311 location = r_post.get('location')
311 location = r_post.get('location')
312 filename = r_post.get('filename')
312 filename = r_post.get('filename')
313 file_obj = r_post.get('upload_file', None)
313 file_obj = r_post.get('upload_file', None)
314
314
315 if file_obj is not None and hasattr(file_obj, 'filename'):
315 if file_obj is not None and hasattr(file_obj, 'filename'):
316 filename = file_obj.filename
316 filename = file_obj.filename
317 content = file_obj.file
317 content = file_obj.file
318
318
319 node_path = os.path.join(location, filename)
319 node_path = os.path.join(location, filename)
320 author = self.rhodecode_user.full_contact
320 author = self.rhodecode_user.full_contact
321
321
322 if not content:
322 if not content:
323 h.flash(_('No content'), category='warning')
323 h.flash(_('No content'), category='warning')
324 return redirect(url('changeset_home', repo_name=c.repo_name,
324 return redirect(url('changeset_home', repo_name=c.repo_name,
325 revision='tip'))
325 revision='tip'))
326 if not filename:
326 if not filename:
327 h.flash(_('No filename'), category='warning')
327 h.flash(_('No filename'), category='warning')
328 return redirect(url('changeset_home', repo_name=c.repo_name,
328 return redirect(url('changeset_home', repo_name=c.repo_name,
329 revision='tip'))
329 revision='tip'))
330
330
331 try:
331 try:
332 self.scm_model.create_node(repo=c.rhodecode_repo,
332 self.scm_model.create_node(repo=c.rhodecode_repo,
333 repo_name=repo_name, cs=c.cs,
333 repo_name=repo_name, cs=c.cs,
334 user=self.rhodecode_user,
334 user=self.rhodecode_user,
335 author=author, message=message,
335 author=author, message=message,
336 content=content, f_path=node_path)
336 content=content, f_path=node_path)
337 h.flash(_('Successfully committed to %s' % node_path),
337 h.flash(_('Successfully committed to %s' % node_path),
338 category='success')
338 category='success')
339 except NodeAlreadyExistsError, e:
339 except NodeAlreadyExistsError, e:
340 h.flash(_(e), category='error')
340 h.flash(_(e), category='error')
341 except Exception:
341 except Exception:
342 log.error(traceback.format_exc())
342 log.error(traceback.format_exc())
343 h.flash(_('Error occurred during commit'), category='error')
343 h.flash(_('Error occurred during commit'), category='error')
344 return redirect(url('changeset_home',
344 return redirect(url('changeset_home',
345 repo_name=c.repo_name, revision='tip'))
345 repo_name=c.repo_name, revision='tip'))
346
346
347 return render('files/files_add.html')
347 return render('files/files_add.html')
348
348
349 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
349 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
350 'repository.admin')
350 'repository.admin')
351 def archivefile(self, repo_name, fname):
351 def archivefile(self, repo_name, fname):
352
352
353 fileformat = None
353 fileformat = None
354 revision = None
354 revision = None
355 ext = None
355 ext = None
356 subrepos = request.GET.get('subrepos') == 'true'
356 subrepos = request.GET.get('subrepos') == 'true'
357
357
358 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
358 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
359 archive_spec = fname.split(ext_data[1])
359 archive_spec = fname.split(ext_data[1])
360 if len(archive_spec) == 2 and archive_spec[1] == '':
360 if len(archive_spec) == 2 and archive_spec[1] == '':
361 fileformat = a_type or ext_data[1]
361 fileformat = a_type or ext_data[1]
362 revision = archive_spec[0]
362 revision = archive_spec[0]
363 ext = ext_data[1]
363 ext = ext_data[1]
364
364
365 try:
365 try:
366 dbrepo = RepoModel().get_by_repo_name(repo_name)
366 dbrepo = RepoModel().get_by_repo_name(repo_name)
367 if dbrepo.enable_downloads is False:
367 if dbrepo.enable_downloads is False:
368 return _('downloads disabled')
368 return _('downloads disabled')
369
369
370 if c.rhodecode_repo.alias == 'hg':
371 # patch and reset hooks section of UI config to not run any
372 # hooks on fetching archives with subrepos
373 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
374 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
375
370 cs = c.rhodecode_repo.get_changeset(revision)
376 cs = c.rhodecode_repo.get_changeset(revision)
371 content_type = settings.ARCHIVE_SPECS[fileformat][0]
377 content_type = settings.ARCHIVE_SPECS[fileformat][0]
372 except ChangesetDoesNotExistError:
378 except ChangesetDoesNotExistError:
373 return _('Unknown revision %s') % revision
379 return _('Unknown revision %s') % revision
374 except EmptyRepositoryError:
380 except EmptyRepositoryError:
375 return _('Empty repository')
381 return _('Empty repository')
376 except (ImproperArchiveTypeError, KeyError):
382 except (ImproperArchiveTypeError, KeyError):
377 return _('Unknown archive type')
383 return _('Unknown archive type')
378
384
379 response.content_type = content_type
385 response.content_type = content_type
380 response.content_disposition = 'attachment; filename=%s-%s%s' \
386 response.content_disposition = 'attachment; filename=%s-%s%s' \
381 % (repo_name, revision, ext)
387 % (repo_name, revision, ext)
382
388
383 import tempfile
389 import tempfile
384 archive = tempfile.mkstemp()[1]
390 archive = tempfile.mkstemp()[1]
385 t = open(archive, 'wb')
391 t = open(archive, 'wb')
386 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
392 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
387
393
388 def get_chunked_archive(archive):
394 def get_chunked_archive(archive):
389 stream = open(archive, 'rb')
395 stream = open(archive, 'rb')
390 while True:
396 while True:
391 data = stream.read(4096)
397 data = stream.read(4096)
392 if not data:
398 if not data:
393 os.remove(archive)
399 os.remove(archive)
394 break
400 break
395 yield data
401 yield data
396
402
397 return get_chunked_archive(archive)
403 return get_chunked_archive(archive)
398
404
399 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
405 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
400 'repository.admin')
406 'repository.admin')
401 def diff(self, repo_name, f_path):
407 def diff(self, repo_name, f_path):
402 diff1 = request.GET.get('diff1')
408 diff1 = request.GET.get('diff1')
403 diff2 = request.GET.get('diff2')
409 diff2 = request.GET.get('diff2')
404 c.action = request.GET.get('diff')
410 c.action = request.GET.get('diff')
405 c.no_changes = diff1 == diff2
411 c.no_changes = diff1 == diff2
406 c.f_path = f_path
412 c.f_path = f_path
407 c.big_diff = False
413 c.big_diff = False
408
414
409 try:
415 try:
410 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
416 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
411 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
417 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
412 node1 = c.changeset_1.get_node(f_path)
418 node1 = c.changeset_1.get_node(f_path)
413 else:
419 else:
414 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
420 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
415 node1 = FileNode('.', '', changeset=c.changeset_1)
421 node1 = FileNode('.', '', changeset=c.changeset_1)
416
422
417 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
423 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
418 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
424 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
419 node2 = c.changeset_2.get_node(f_path)
425 node2 = c.changeset_2.get_node(f_path)
420 else:
426 else:
421 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
427 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
422 node2 = FileNode('.', '', changeset=c.changeset_2)
428 node2 = FileNode('.', '', changeset=c.changeset_2)
423 except RepositoryError:
429 except RepositoryError:
424 return redirect(url('files_home',
430 return redirect(url('files_home',
425 repo_name=c.repo_name, f_path=f_path))
431 repo_name=c.repo_name, f_path=f_path))
426
432
427 if c.action == 'download':
433 if c.action == 'download':
428 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
434 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
429 format='gitdiff')
435 format='gitdiff')
430
436
431 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
437 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
432 response.content_type = 'text/plain'
438 response.content_type = 'text/plain'
433 response.content_disposition = 'attachment; filename=%s' \
439 response.content_disposition = 'attachment; filename=%s' \
434 % diff_name
440 % diff_name
435 return diff.raw_diff()
441 return diff.raw_diff()
436
442
437 elif c.action == 'raw':
443 elif c.action == 'raw':
438 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
444 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
439 format='gitdiff')
445 format='gitdiff')
440 response.content_type = 'text/plain'
446 response.content_type = 'text/plain'
441 return diff.raw_diff()
447 return diff.raw_diff()
442
448
443 elif c.action == 'diff':
449 elif c.action == 'diff':
444 if node1.is_binary or node2.is_binary:
450 if node1.is_binary or node2.is_binary:
445 c.cur_diff = _('Binary file')
451 c.cur_diff = _('Binary file')
446 elif node1.size > self.cut_off_limit or \
452 elif node1.size > self.cut_off_limit or \
447 node2.size > self.cut_off_limit:
453 node2.size > self.cut_off_limit:
448 c.cur_diff = ''
454 c.cur_diff = ''
449 c.big_diff = True
455 c.big_diff = True
450 else:
456 else:
451 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
457 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
452 format='gitdiff')
458 format='gitdiff')
453 c.cur_diff = diff.as_html()
459 c.cur_diff = diff.as_html()
454 else:
460 else:
455
461
456 #default option
462 #default option
457 if node1.is_binary or node2.is_binary:
463 if node1.is_binary or node2.is_binary:
458 c.cur_diff = _('Binary file')
464 c.cur_diff = _('Binary file')
459 elif node1.size > self.cut_off_limit or \
465 elif node1.size > self.cut_off_limit or \
460 node2.size > self.cut_off_limit:
466 node2.size > self.cut_off_limit:
461 c.cur_diff = ''
467 c.cur_diff = ''
462 c.big_diff = True
468 c.big_diff = True
463
469
464 else:
470 else:
465 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
471 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
466 format='gitdiff')
472 format='gitdiff')
467 c.cur_diff = diff.as_html()
473 c.cur_diff = diff.as_html()
468
474
469 if not c.cur_diff and not c.big_diff:
475 if not c.cur_diff and not c.big_diff:
470 c.no_changes = True
476 c.no_changes = True
471 return render('files/file_diff.html')
477 return render('files/file_diff.html')
472
478
473 def _get_node_history(self, cs, f_path):
479 def _get_node_history(self, cs, f_path):
474 changesets = cs.get_file_history(f_path)
480 changesets = cs.get_file_history(f_path)
475 hist_l = []
481 hist_l = []
476
482
477 changesets_group = ([], _("Changesets"))
483 changesets_group = ([], _("Changesets"))
478 branches_group = ([], _("Branches"))
484 branches_group = ([], _("Branches"))
479 tags_group = ([], _("Tags"))
485 tags_group = ([], _("Tags"))
480
486
481 for chs in changesets:
487 for chs in changesets:
482 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
488 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
483 changesets_group[0].append((chs.raw_id, n_desc,))
489 changesets_group[0].append((chs.raw_id, n_desc,))
484
490
485 hist_l.append(changesets_group)
491 hist_l.append(changesets_group)
486
492
487 for name, chs in c.rhodecode_repo.branches.items():
493 for name, chs in c.rhodecode_repo.branches.items():
488 #chs = chs.split(':')[-1]
494 #chs = chs.split(':')[-1]
489 branches_group[0].append((chs, name),)
495 branches_group[0].append((chs, name),)
490 hist_l.append(branches_group)
496 hist_l.append(branches_group)
491
497
492 for name, chs in c.rhodecode_repo.tags.items():
498 for name, chs in c.rhodecode_repo.tags.items():
493 #chs = chs.split(':')[-1]
499 #chs = chs.split(':')[-1]
494 tags_group[0].append((chs, name),)
500 tags_group[0].append((chs, name),)
495 hist_l.append(tags_group)
501 hist_l.append(tags_group)
496
502
497 return hist_l
503 return hist_l
498
504
499 @jsonify
505 @jsonify
500 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
506 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
501 'repository.admin')
507 'repository.admin')
502 def nodelist(self, repo_name, revision, f_path):
508 def nodelist(self, repo_name, revision, f_path):
503 if request.environ.get('HTTP_X_PARTIAL_XHR'):
509 if request.environ.get('HTTP_X_PARTIAL_XHR'):
504 cs = self.__get_cs_or_redirect(revision, repo_name)
510 cs = self.__get_cs_or_redirect(revision, repo_name)
505 _d, _f = self.__get_paths(cs, f_path)
511 _d, _f = self.__get_paths(cs, f_path)
506 return _d + _f
512 return _d + _f
507
513
General Comments 0
You need to be logged in to leave comments. Login now