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