##// END OF EJS Templates
fixes for rawfile, annotation, download. It will check now if it's a filenode....
marcink -
r1189:a4e1b955 beta
parent child Browse files
Show More
@@ -1,297 +1,305 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import rhodecode.lib.helpers as h
29 import rhodecode.lib.helpers as h
30
30
31 from pylons import request, response, session, tmpl_context as c, url
31 from pylons import request, response, session, 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
34
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.utils import EmptyChangeset
37 from rhodecode.lib.utils import EmptyChangeset
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
39
39
40 from vcs.backends import ARCHIVE_SPECS
40 from vcs.backends import ARCHIVE_SPECS
41 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
41 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
42 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
42 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
43 from vcs.nodes import FileNode, NodeKind
43 from vcs.nodes import FileNode, NodeKind
44 from vcs.utils import diffs as differ
44 from vcs.utils import diffs as differ
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class FilesController(BaseRepoController):
49 class FilesController(BaseRepoController):
50
50
51 @LoginRequired()
51 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
53 'repository.admin')
54 def __before__(self):
54 def __before__(self):
55 super(FilesController, self).__before__()
55 super(FilesController, self).__before__()
56 c.cut_off_limit = self.cut_off_limit
56 c.cut_off_limit = self.cut_off_limit
57
57
58 def __get_cs_or_redirect(self, rev, repo_name):
58 def __get_cs_or_redirect(self, rev, repo_name):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to tip with
60 Safe way to get changeset if error occur it redirects to tip with
61 proper message
61 proper message
62
62
63 :param rev: revision to fetch
63 :param rev: revision to fetch
64 :param repo_name: repo name to redirect after
64 :param repo_name: repo name to redirect after
65 """
65 """
66
66
67 try:
67 try:
68 return c.rhodecode_repo.get_changeset(rev)
68 return c.rhodecode_repo.get_changeset(rev)
69 except EmptyRepositoryError, e:
69 except EmptyRepositoryError, e:
70 h.flash(_('There are no files yet'), category='warning')
70 h.flash(_('There are no files yet'), category='warning')
71 redirect(h.url('summary_home', repo_name=repo_name))
71 redirect(h.url('summary_home', repo_name=repo_name))
72
72
73 except RepositoryError, e:
73 except RepositoryError, e:
74 h.flash(str(e), category='warning')
74 h.flash(str(e), category='warning')
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
76
76
77
78 def __get_filenode_or_redirect(self, repo_name, cs, path):
79 """
80 Returns file_node, if error occurs or given path is directory,
81 it'll redirect to top level path
82
83 :param repo_name: repo_name
84 :param cs: given changeset
85 :param path: path to lookup
86 """
87
88
89 try:
90 file_node = cs.get_node(path)
91 if file_node.is_dir():
92 raise RepositoryError('given path is a directory')
93 except RepositoryError, e:
94 h.flash(str(e), category='warning')
95 redirect(h.url('files_home', repo_name=repo_name,
96 revision=cs.raw_id))
97
98 return file_node
99
77 def index(self, repo_name, revision, f_path):
100 def index(self, repo_name, revision, f_path):
78 #reditect to given revision from form if given
101 #reditect to given revision from form if given
79 post_revision = request.POST.get('at_rev', None)
102 post_revision = request.POST.get('at_rev', None)
80 if post_revision:
103 if post_revision:
81 cs = self.__get_cs_or_redirect(revision, repo_name)
104 cs = self.__get_cs_or_redirect(revision, repo_name)
82 redirect(url('files_home', repo_name=c.repo_name,
105 redirect(url('files_home', repo_name=c.repo_name,
83 revision=cs.raw_id, f_path=f_path))
106 revision=cs.raw_id, f_path=f_path))
84
107
85
108
86 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
109 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
87 c.branch = request.GET.get('branch', None)
110 c.branch = request.GET.get('branch', None)
88 c.f_path = f_path
111 c.f_path = f_path
89
112
90 cur_rev = c.changeset.revision
113 cur_rev = c.changeset.revision
91
114
92 #prev link
115 #prev link
93 try:
116 try:
94 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
117 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
95 c.url_prev = url('files_home', repo_name=c.repo_name,
118 c.url_prev = url('files_home', repo_name=c.repo_name,
96 revision=prev_rev.raw_id, f_path=f_path)
119 revision=prev_rev.raw_id, f_path=f_path)
97 if c.branch:
120 if c.branch:
98 c.url_prev += '?branch=%s' % c.branch
121 c.url_prev += '?branch=%s' % c.branch
99 except (ChangesetDoesNotExistError, VCSError):
122 except (ChangesetDoesNotExistError, VCSError):
100 c.url_prev = '#'
123 c.url_prev = '#'
101
124
102 #next link
125 #next link
103 try:
126 try:
104 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
127 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
105 c.url_next = url('files_home', repo_name=c.repo_name,
128 c.url_next = url('files_home', repo_name=c.repo_name,
106 revision=next_rev.raw_id, f_path=f_path)
129 revision=next_rev.raw_id, f_path=f_path)
107 if c.branch:
130 if c.branch:
108 c.url_next += '?branch=%s' % c.branch
131 c.url_next += '?branch=%s' % c.branch
109 except (ChangesetDoesNotExistError, VCSError):
132 except (ChangesetDoesNotExistError, VCSError):
110 c.url_next = '#'
133 c.url_next = '#'
111
134
112 #files
135 #files or dirs
113 try:
136 try:
114 c.files_list = c.changeset.get_node(f_path)
137 c.files_list = c.changeset.get_node(f_path)
115 c.file_history = self._get_history(c.rhodecode_repo,
138 c.file_history = self._get_history(c.rhodecode_repo,
116 c.files_list, f_path)
139 c.files_list, f_path)
117 except RepositoryError, e:
140 except RepositoryError, e:
118 h.flash(str(e), category='warning')
141 h.flash(str(e), category='warning')
119 redirect(h.url('files_home', repo_name=repo_name,
142 redirect(h.url('files_home', repo_name=repo_name,
120 revision=revision))
143 revision=revision))
121
144
122
145
123 return render('files/files.html')
146 return render('files/files.html')
124
147
125 def rawfile(self, repo_name, revision, f_path):
148 def rawfile(self, repo_name, revision, f_path):
126 cs = self.__get_cs_or_redirect(revision, repo_name)
149 cs = self.__get_cs_or_redirect(revision, repo_name)
127 try:
150 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
128 file_node = cs.get_node(f_path)
129 except RepositoryError, e:
130 h.flash(str(e), category='warning')
131 redirect(h.url('files_home', repo_name=repo_name,
132 revision=cs.raw_id))
133
151
134 fname = f_path.split('/')[-1].encode('utf8', 'replace')
152 response.content_disposition = 'attachment; filename=%s' % \
153 f_path.split('/')[-1].encode('utf8', 'replace')
154
135 response.content_type = file_node.mimetype
155 response.content_type = file_node.mimetype
136 response.content_disposition = 'attachment; filename=%s' % fname
137 return file_node.content
156 return file_node.content
138
157
139 def raw(self, repo_name, revision, f_path):
158 def raw(self, repo_name, revision, f_path):
140 cs = self.__get_cs_or_redirect(revision, repo_name)
159 cs = self.__get_cs_or_redirect(revision, repo_name)
141 try:
160 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
142 file_node = cs.get_node(f_path)
143 except RepositoryError, e:
144 h.flash(str(e), category='warning')
145 redirect(h.url('files_home', repo_name=repo_name,
146 revision=cs.raw_id))
147
161
148 response.content_type = 'text/plain'
162 response.content_type = 'text/plain'
149
150 return file_node.content
163 return file_node.content
151
164
152 def annotate(self, repo_name, revision, f_path):
165 def annotate(self, repo_name, revision, f_path):
153 cs = self.__get_cs_or_redirect(revision, repo_name)
166 cs = self.__get_cs_or_redirect(revision, repo_name)
154 try:
167 c.file = self.__get_filenode_or_redirect(repo_name, cs, f_path)
155 c.file = cs.get_node(f_path)
156 except RepositoryError, e:
157 h.flash(str(e), category='warning')
158 redirect(h.url('files_home', repo_name=repo_name,
159 revision=cs.raw_id))
160
168
161 c.file_history = self._get_history(c.rhodecode_repo,
169 c.file_history = self._get_history(c.rhodecode_repo,
162 c.file, f_path)
170 c.file, f_path)
163 c.cs = cs
171 c.cs = cs
164 c.f_path = f_path
172 c.f_path = f_path
165
173
166 return render('files/files_annotate.html')
174 return render('files/files_annotate.html')
167
175
168 def archivefile(self, repo_name, fname):
176 def archivefile(self, repo_name, fname):
169
177
170 fileformat = None
178 fileformat = None
171 revision = None
179 revision = None
172 ext = None
180 ext = None
173
181
174 for a_type, ext_data in ARCHIVE_SPECS.items():
182 for a_type, ext_data in ARCHIVE_SPECS.items():
175 archive_spec = fname.split(ext_data[1])
183 archive_spec = fname.split(ext_data[1])
176 if len(archive_spec) == 2 and archive_spec[1] == '':
184 if len(archive_spec) == 2 and archive_spec[1] == '':
177 fileformat = a_type or ext_data[1]
185 fileformat = a_type or ext_data[1]
178 revision = archive_spec[0]
186 revision = archive_spec[0]
179 ext = ext_data[1]
187 ext = ext_data[1]
180
188
181 try:
189 try:
182 dbrepo = RepoModel().get_by_repo_name(repo_name)
190 dbrepo = RepoModel().get_by_repo_name(repo_name)
183 if dbrepo.enable_downloads is False:
191 if dbrepo.enable_downloads is False:
184 return _('downloads disabled')
192 return _('downloads disabled')
185
193
186 cs = c.rhodecode_repo.get_changeset(revision)
194 cs = c.rhodecode_repo.get_changeset(revision)
187 content_type = ARCHIVE_SPECS[fileformat][0]
195 content_type = ARCHIVE_SPECS[fileformat][0]
188 except ChangesetDoesNotExistError:
196 except ChangesetDoesNotExistError:
189 return _('Unknown revision %s') % revision
197 return _('Unknown revision %s') % revision
190 except EmptyRepositoryError:
198 except EmptyRepositoryError:
191 return _('Empty repository')
199 return _('Empty repository')
192 except (ImproperArchiveTypeError, KeyError):
200 except (ImproperArchiveTypeError, KeyError):
193 return _('Unknown archive type')
201 return _('Unknown archive type')
194
202
195 response.content_type = content_type
203 response.content_type = content_type
196 response.content_disposition = 'attachment; filename=%s-%s%s' \
204 response.content_disposition = 'attachment; filename=%s-%s%s' \
197 % (repo_name, revision, ext)
205 % (repo_name, revision, ext)
198
206
199 return cs.get_chunked_archive(stream=None, kind=fileformat)
207 return cs.get_chunked_archive(stream=None, kind=fileformat)
200
208
201
209
202 def diff(self, repo_name, f_path):
210 def diff(self, repo_name, f_path):
203 diff1 = request.GET.get('diff1')
211 diff1 = request.GET.get('diff1')
204 diff2 = request.GET.get('diff2')
212 diff2 = request.GET.get('diff2')
205 c.action = request.GET.get('diff')
213 c.action = request.GET.get('diff')
206 c.no_changes = diff1 == diff2
214 c.no_changes = diff1 == diff2
207 c.f_path = f_path
215 c.f_path = f_path
208
216
209 try:
217 try:
210 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
218 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
211 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
219 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
212 node1 = c.changeset_1.get_node(f_path)
220 node1 = c.changeset_1.get_node(f_path)
213 else:
221 else:
214 c.changeset_1 = EmptyChangeset()
222 c.changeset_1 = EmptyChangeset()
215 node1 = FileNode('.', '', changeset=c.changeset_1)
223 node1 = FileNode('.', '', changeset=c.changeset_1)
216
224
217 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
225 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
218 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
226 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
219 node2 = c.changeset_2.get_node(f_path)
227 node2 = c.changeset_2.get_node(f_path)
220 else:
228 else:
221 c.changeset_2 = EmptyChangeset()
229 c.changeset_2 = EmptyChangeset()
222 node2 = FileNode('.', '', changeset=c.changeset_2)
230 node2 = FileNode('.', '', changeset=c.changeset_2)
223 except RepositoryError:
231 except RepositoryError:
224 return redirect(url('files_home',
232 return redirect(url('files_home',
225 repo_name=c.repo_name, f_path=f_path))
233 repo_name=c.repo_name, f_path=f_path))
226
234
227
235
228 if c.action == 'download':
236 if c.action == 'download':
229 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
237 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
230 format='gitdiff')
238 format='gitdiff')
231
239
232 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
240 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
233 response.content_type = 'text/plain'
241 response.content_type = 'text/plain'
234 response.content_disposition = 'attachment; filename=%s' \
242 response.content_disposition = 'attachment; filename=%s' \
235 % diff_name
243 % diff_name
236 return diff.raw_diff()
244 return diff.raw_diff()
237
245
238 elif c.action == 'raw':
246 elif c.action == 'raw':
239 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
247 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
240 format='gitdiff')
248 format='gitdiff')
241 response.content_type = 'text/plain'
249 response.content_type = 'text/plain'
242 return diff.raw_diff()
250 return diff.raw_diff()
243
251
244 elif c.action == 'diff':
252 elif c.action == 'diff':
245
253
246 if node1.is_binary or node2.is_binary:
254 if node1.is_binary or node2.is_binary:
247 c.cur_diff = _('Binary file')
255 c.cur_diff = _('Binary file')
248 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
256 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
249 c.cur_diff = _('Diff is too big to display')
257 c.cur_diff = _('Diff is too big to display')
250 else:
258 else:
251 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
259 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
252 format='gitdiff')
260 format='gitdiff')
253 c.cur_diff = diff.as_html()
261 c.cur_diff = diff.as_html()
254 else:
262 else:
255
263
256 #default option
264 #default option
257 if node1.is_binary or node2.is_binary:
265 if node1.is_binary or node2.is_binary:
258 c.cur_diff = _('Binary file')
266 c.cur_diff = _('Binary file')
259 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
267 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
260 c.cur_diff = _('Diff is too big to display')
268 c.cur_diff = _('Diff is too big to display')
261 else:
269 else:
262 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
270 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
263 format='gitdiff')
271 format='gitdiff')
264 c.cur_diff = diff.as_html()
272 c.cur_diff = diff.as_html()
265
273
266 if not c.cur_diff:
274 if not c.cur_diff:
267 c.no_changes = True
275 c.no_changes = True
268 return render('files/file_diff.html')
276 return render('files/file_diff.html')
269
277
270 def _get_history(self, repo, node, f_path):
278 def _get_history(self, repo, node, f_path):
271 if not node.kind is NodeKind.FILE:
279 if not node.is_file():
272 return []
280 return []
273 changesets = node.history
281 changesets = node.history
274 hist_l = []
282 hist_l = []
275
283
276 changesets_group = ([], _("Changesets"))
284 changesets_group = ([], _("Changesets"))
277 branches_group = ([], _("Branches"))
285 branches_group = ([], _("Branches"))
278 tags_group = ([], _("Tags"))
286 tags_group = ([], _("Tags"))
279
287
280 for chs in changesets:
288 for chs in changesets:
281 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
289 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
282 changesets_group[0].append((chs.raw_id, n_desc,))
290 changesets_group[0].append((chs.raw_id, n_desc,))
283
291
284 hist_l.append(changesets_group)
292 hist_l.append(changesets_group)
285
293
286 for name, chs in c.rhodecode_repo.branches.items():
294 for name, chs in c.rhodecode_repo.branches.items():
287 #chs = chs.split(':')[-1]
295 #chs = chs.split(':')[-1]
288 branches_group[0].append((chs, name),)
296 branches_group[0].append((chs, name),)
289 hist_l.append(branches_group)
297 hist_l.append(branches_group)
290
298
291 for name, chs in c.rhodecode_repo.tags.items():
299 for name, chs in c.rhodecode_repo.tags.items():
292 #chs = chs.split(':')[-1]
300 #chs = chs.split(':')[-1]
293 tags_group[0].append((chs, name),)
301 tags_group[0].append((chs, name),)
294 hist_l.append(tags_group)
302 hist_l.append(tags_group)
295
303
296 return hist_l
304 return hist_l
297
305
General Comments 0
You need to be logged in to leave comments. Login now