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