##// END OF EJS Templates
fixes issue with mercurial 2.0 and archival of subrepos....
marcink -
r1664:65386911 beta
parent child Browse files
Show More
@@ -1,507 +1,512 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) 2009-2011 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 #reditect 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 # patch and reset hooks section of UI config to not run any
371 # hooks on fetching archives with subrepos
372 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
373 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
374
370 cs = c.rhodecode_repo.get_changeset(revision)
375 cs = c.rhodecode_repo.get_changeset(revision)
371 content_type = settings.ARCHIVE_SPECS[fileformat][0]
376 content_type = settings.ARCHIVE_SPECS[fileformat][0]
372 except ChangesetDoesNotExistError:
377 except ChangesetDoesNotExistError:
373 return _('Unknown revision %s') % revision
378 return _('Unknown revision %s') % revision
374 except EmptyRepositoryError:
379 except EmptyRepositoryError:
375 return _('Empty repository')
380 return _('Empty repository')
376 except (ImproperArchiveTypeError, KeyError):
381 except (ImproperArchiveTypeError, KeyError):
377 return _('Unknown archive type')
382 return _('Unknown archive type')
378
383
379 response.content_type = content_type
384 response.content_type = content_type
380 response.content_disposition = 'attachment; filename=%s-%s%s' \
385 response.content_disposition = 'attachment; filename=%s-%s%s' \
381 % (repo_name, revision, ext)
386 % (repo_name, revision, ext)
382
387
383 import tempfile
388 import tempfile
384 archive = tempfile.mkstemp()[1]
389 archive = tempfile.mkstemp()[1]
385 t = open(archive, 'wb')
390 t = open(archive, 'wb')
386 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
391 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
387
392
388 def get_chunked_archive(archive):
393 def get_chunked_archive(archive):
389 stream = open(archive, 'rb')
394 stream = open(archive, 'rb')
390 while True:
395 while True:
391 data = stream.read(4096)
396 data = stream.read(4096)
392 if not data:
397 if not data:
393 os.remove(archive)
398 os.remove(archive)
394 break
399 break
395 yield data
400 yield data
396
401
397 return get_chunked_archive(archive)
402 return get_chunked_archive(archive)
398
403
399 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
404 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
400 'repository.admin')
405 'repository.admin')
401 def diff(self, repo_name, f_path):
406 def diff(self, repo_name, f_path):
402 diff1 = request.GET.get('diff1')
407 diff1 = request.GET.get('diff1')
403 diff2 = request.GET.get('diff2')
408 diff2 = request.GET.get('diff2')
404 c.action = request.GET.get('diff')
409 c.action = request.GET.get('diff')
405 c.no_changes = diff1 == diff2
410 c.no_changes = diff1 == diff2
406 c.f_path = f_path
411 c.f_path = f_path
407 c.big_diff = False
412 c.big_diff = False
408
413
409 try:
414 try:
410 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
415 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
411 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
416 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
412 node1 = c.changeset_1.get_node(f_path)
417 node1 = c.changeset_1.get_node(f_path)
413 else:
418 else:
414 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
419 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
415 node1 = FileNode('.', '', changeset=c.changeset_1)
420 node1 = FileNode('.', '', changeset=c.changeset_1)
416
421
417 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
422 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
418 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
423 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
419 node2 = c.changeset_2.get_node(f_path)
424 node2 = c.changeset_2.get_node(f_path)
420 else:
425 else:
421 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
426 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
422 node2 = FileNode('.', '', changeset=c.changeset_2)
427 node2 = FileNode('.', '', changeset=c.changeset_2)
423 except RepositoryError:
428 except RepositoryError:
424 return redirect(url('files_home',
429 return redirect(url('files_home',
425 repo_name=c.repo_name, f_path=f_path))
430 repo_name=c.repo_name, f_path=f_path))
426
431
427 if c.action == 'download':
432 if c.action == 'download':
428 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
433 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
429 format='gitdiff')
434 format='gitdiff')
430
435
431 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
436 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
432 response.content_type = 'text/plain'
437 response.content_type = 'text/plain'
433 response.content_disposition = 'attachment; filename=%s' \
438 response.content_disposition = 'attachment; filename=%s' \
434 % diff_name
439 % diff_name
435 return diff.raw_diff()
440 return diff.raw_diff()
436
441
437 elif c.action == 'raw':
442 elif c.action == 'raw':
438 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
443 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
439 format='gitdiff')
444 format='gitdiff')
440 response.content_type = 'text/plain'
445 response.content_type = 'text/plain'
441 return diff.raw_diff()
446 return diff.raw_diff()
442
447
443 elif c.action == 'diff':
448 elif c.action == 'diff':
444 if node1.is_binary or node2.is_binary:
449 if node1.is_binary or node2.is_binary:
445 c.cur_diff = _('Binary file')
450 c.cur_diff = _('Binary file')
446 elif node1.size > self.cut_off_limit or \
451 elif node1.size > self.cut_off_limit or \
447 node2.size > self.cut_off_limit:
452 node2.size > self.cut_off_limit:
448 c.cur_diff = ''
453 c.cur_diff = ''
449 c.big_diff = True
454 c.big_diff = True
450 else:
455 else:
451 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
456 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
452 format='gitdiff')
457 format='gitdiff')
453 c.cur_diff = diff.as_html()
458 c.cur_diff = diff.as_html()
454 else:
459 else:
455
460
456 #default option
461 #default option
457 if node1.is_binary or node2.is_binary:
462 if node1.is_binary or node2.is_binary:
458 c.cur_diff = _('Binary file')
463 c.cur_diff = _('Binary file')
459 elif node1.size > self.cut_off_limit or \
464 elif node1.size > self.cut_off_limit or \
460 node2.size > self.cut_off_limit:
465 node2.size > self.cut_off_limit:
461 c.cur_diff = ''
466 c.cur_diff = ''
462 c.big_diff = True
467 c.big_diff = True
463
468
464 else:
469 else:
465 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
470 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
466 format='gitdiff')
471 format='gitdiff')
467 c.cur_diff = diff.as_html()
472 c.cur_diff = diff.as_html()
468
473
469 if not c.cur_diff and not c.big_diff:
474 if not c.cur_diff and not c.big_diff:
470 c.no_changes = True
475 c.no_changes = True
471 return render('files/file_diff.html')
476 return render('files/file_diff.html')
472
477
473 def _get_node_history(self, cs, f_path):
478 def _get_node_history(self, cs, f_path):
474 changesets = cs.get_file_history(f_path)
479 changesets = cs.get_file_history(f_path)
475 hist_l = []
480 hist_l = []
476
481
477 changesets_group = ([], _("Changesets"))
482 changesets_group = ([], _("Changesets"))
478 branches_group = ([], _("Branches"))
483 branches_group = ([], _("Branches"))
479 tags_group = ([], _("Tags"))
484 tags_group = ([], _("Tags"))
480
485
481 for chs in changesets:
486 for chs in changesets:
482 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
487 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
483 changesets_group[0].append((chs.raw_id, n_desc,))
488 changesets_group[0].append((chs.raw_id, n_desc,))
484
489
485 hist_l.append(changesets_group)
490 hist_l.append(changesets_group)
486
491
487 for name, chs in c.rhodecode_repo.branches.items():
492 for name, chs in c.rhodecode_repo.branches.items():
488 #chs = chs.split(':')[-1]
493 #chs = chs.split(':')[-1]
489 branches_group[0].append((chs, name),)
494 branches_group[0].append((chs, name),)
490 hist_l.append(branches_group)
495 hist_l.append(branches_group)
491
496
492 for name, chs in c.rhodecode_repo.tags.items():
497 for name, chs in c.rhodecode_repo.tags.items():
493 #chs = chs.split(':')[-1]
498 #chs = chs.split(':')[-1]
494 tags_group[0].append((chs, name),)
499 tags_group[0].append((chs, name),)
495 hist_l.append(tags_group)
500 hist_l.append(tags_group)
496
501
497 return hist_l
502 return hist_l
498
503
499 @jsonify
504 @jsonify
500 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
505 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
501 'repository.admin')
506 'repository.admin')
502 def nodelist(self, repo_name, revision, f_path):
507 def nodelist(self, repo_name, revision, f_path):
503 if request.environ.get('HTTP_X_PARTIAL_XHR'):
508 if request.environ.get('HTTP_X_PARTIAL_XHR'):
504 cs = self.__get_cs_or_redirect(revision, repo_name)
509 cs = self.__get_cs_or_redirect(revision, repo_name)
505 _d, _f = self.__get_paths(cs, f_path)
510 _d, _f = self.__get_paths(cs, f_path)
506 return _d + _f
511 return _d + _f
507
512
General Comments 0
You need to be logged in to leave comments. Login now