##// END OF EJS Templates
fixed #96 redirect loop on files
marcink -
r915:35e701dc beta
parent child Browse files
Show More
@@ -1,268 +1,273 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 import tempfile
27 import tempfile
28 import logging
28 import logging
29 import rhodecode.lib.helpers as h
29 import rhodecode.lib.helpers as h
30
30
31 from mercurial import archival
31 from mercurial import archival
32
32
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36
36
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib.base import BaseController, render
38 from rhodecode.lib.base import BaseController, render
39 from rhodecode.lib.utils import EmptyChangeset
39 from rhodecode.lib.utils import EmptyChangeset
40 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.scm import ScmModel
41
41
42 from vcs.exceptions import RepositoryError, ChangesetError, ChangesetDoesNotExistError
42 from vcs.exceptions import RepositoryError, ChangesetError, \
43 ChangesetDoesNotExistError, EmptyRepositoryError
43 from vcs.nodes import FileNode
44 from vcs.nodes import FileNode
44 from vcs.utils import diffs as differ
45 from vcs.utils import diffs as differ
45
46
46 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
47
48
48 class FilesController(BaseController):
49 class FilesController(BaseController):
49
50
50 @LoginRequired()
51 @LoginRequired()
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 'repository.admin')
53 'repository.admin')
53 def __before__(self):
54 def __before__(self):
54 super(FilesController, self).__before__()
55 super(FilesController, self).__before__()
55 c.cut_off_limit = self.cut_off_limit
56 c.cut_off_limit = self.cut_off_limit
56
57
57 def index(self, repo_name, revision, f_path):
58 def index(self, repo_name, revision, f_path):
58 hg_model = ScmModel()
59 hg_model = ScmModel()
59 c.repo = hg_model.get_repo(c.repo_name)
60 c.repo = hg_model.get_repo(c.repo_name)
60
61
61 try:
62 try:
62 #reditect to given revision from form
63 #reditect to given revision from form
63 post_revision = request.POST.get('at_rev', None)
64 post_revision = request.POST.get('at_rev', None)
64 if post_revision:
65 if post_revision:
65 post_revision = c.repo.get_changeset(post_revision).raw_id
66 post_revision = c.repo.get_changeset(post_revision).raw_id
66 redirect(url('files_home', repo_name=c.repo_name,
67 redirect(url('files_home', repo_name=c.repo_name,
67 revision=post_revision, f_path=f_path))
68 revision=post_revision, f_path=f_path))
68
69
69 c.branch = request.GET.get('branch', None)
70 c.branch = request.GET.get('branch', None)
70
71
71 c.f_path = f_path
72 c.f_path = f_path
72
73
73 c.changeset = c.repo.get_changeset(revision)
74 c.changeset = c.repo.get_changeset(revision)
74 cur_rev = c.changeset.revision
75 cur_rev = c.changeset.revision
75
76
76 #prev link
77 #prev link
77 try:
78 try:
78 prev_rev = c.repo.get_changeset(cur_rev).prev(c.branch).raw_id
79 prev_rev = c.repo.get_changeset(cur_rev).prev(c.branch).raw_id
79 c.url_prev = url('files_home', repo_name=c.repo_name,
80 c.url_prev = url('files_home', repo_name=c.repo_name,
80 revision=prev_rev, f_path=f_path)
81 revision=prev_rev, f_path=f_path)
81 if c.branch:
82 if c.branch:
82 c.url_prev += '?branch=%s' % c.branch
83 c.url_prev += '?branch=%s' % c.branch
83 except ChangesetDoesNotExistError:
84 except ChangesetDoesNotExistError:
84 c.url_prev = '#'
85 c.url_prev = '#'
85
86
86 #next link
87 #next link
87 try:
88 try:
88 next_rev = c.repo.get_changeset(cur_rev).next(c.branch).raw_id
89 next_rev = c.repo.get_changeset(cur_rev).next(c.branch).raw_id
89 c.url_next = url('files_home', repo_name=c.repo_name,
90 c.url_next = url('files_home', repo_name=c.repo_name,
90 revision=next_rev, f_path=f_path)
91 revision=next_rev, f_path=f_path)
91 if c.branch:
92 if c.branch:
92 c.url_next += '?branch=%s' % c.branch
93 c.url_next += '?branch=%s' % c.branch
93 except ChangesetDoesNotExistError:
94 except ChangesetDoesNotExistError:
94 c.url_next = '#'
95 c.url_next = '#'
95
96
96 #files
97 #files
97 try:
98 try:
98 c.files_list = c.changeset.get_node(f_path)
99 c.files_list = c.changeset.get_node(f_path)
99 c.file_history = self._get_history(c.repo, c.files_list, f_path)
100 c.file_history = self._get_history(c.repo, c.files_list, f_path)
100 except RepositoryError, e:
101 except RepositoryError, e:
101 h.flash(str(e), category='warning')
102 h.flash(str(e), category='warning')
102 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
103 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
103
104
105 except EmptyRepositoryError, e:
106 h.flash(_('There are no files yet'), category='warning')
107 redirect(h.url('summary_home', repo_name=repo_name))
108
104 except RepositoryError, e:
109 except RepositoryError, e:
105 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
106 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
111 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
107
112
108
113
109
114
110 return render('files/files.html')
115 return render('files/files.html')
111
116
112 def rawfile(self, repo_name, revision, f_path):
117 def rawfile(self, repo_name, revision, f_path):
113 hg_model = ScmModel()
118 hg_model = ScmModel()
114 c.repo = hg_model.get_repo(c.repo_name)
119 c.repo = hg_model.get_repo(c.repo_name)
115 file_node = c.repo.get_changeset(revision).get_node(f_path)
120 file_node = c.repo.get_changeset(revision).get_node(f_path)
116 response.content_type = file_node.mimetype
121 response.content_type = file_node.mimetype
117 response.content_disposition = 'attachment; filename=%s' \
122 response.content_disposition = 'attachment; filename=%s' \
118 % f_path.split('/')[-1]
123 % f_path.split('/')[-1]
119 return file_node.content
124 return file_node.content
120
125
121 def raw(self, repo_name, revision, f_path):
126 def raw(self, repo_name, revision, f_path):
122 hg_model = ScmModel()
127 hg_model = ScmModel()
123 c.repo = hg_model.get_repo(c.repo_name)
128 c.repo = hg_model.get_repo(c.repo_name)
124 file_node = c.repo.get_changeset(revision).get_node(f_path)
129 file_node = c.repo.get_changeset(revision).get_node(f_path)
125 response.content_type = 'text/plain'
130 response.content_type = 'text/plain'
126
131
127 return file_node.content
132 return file_node.content
128
133
129 def annotate(self, repo_name, revision, f_path):
134 def annotate(self, repo_name, revision, f_path):
130 hg_model = ScmModel()
135 hg_model = ScmModel()
131 c.repo = hg_model.get_repo(c.repo_name)
136 c.repo = hg_model.get_repo(c.repo_name)
132
137
133 try:
138 try:
134 c.cs = c.repo.get_changeset(revision)
139 c.cs = c.repo.get_changeset(revision)
135 c.file = c.cs.get_node(f_path)
140 c.file = c.cs.get_node(f_path)
136 except RepositoryError, e:
141 except RepositoryError, e:
137 h.flash(str(e), category='warning')
142 h.flash(str(e), category='warning')
138 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
143 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
139
144
140 c.file_history = self._get_history(c.repo, c.file, f_path)
145 c.file_history = self._get_history(c.repo, c.file, f_path)
141
146
142 c.f_path = f_path
147 c.f_path = f_path
143
148
144 return render('files/files_annotate.html')
149 return render('files/files_annotate.html')
145
150
146 def archivefile(self, repo_name, fname):
151 def archivefile(self, repo_name, fname):
147 info = fname.split('.')
152 info = fname.split('.')
148 revision, fileformat = info[0], '.' + '.'.join(info[1:])
153 revision, fileformat = info[0], '.' + '.'.join(info[1:])
149 archive_specs = {
154 archive_specs = {
150 '.tar.bz2': ('application/x-tar', 'tbz2'),
155 '.tar.bz2': ('application/x-tar', 'tbz2'),
151 '.tar.gz': ('application/x-tar', 'tgz'),
156 '.tar.gz': ('application/x-tar', 'tgz'),
152 '.zip': ('application/zip', 'zip'),
157 '.zip': ('application/zip', 'zip'),
153 }
158 }
154 if not archive_specs.has_key(fileformat):
159 if not archive_specs.has_key(fileformat):
155 return _('Unknown archive type %s') % fileformat
160 return _('Unknown archive type %s') % fileformat
156
161
157 repo = ScmModel().get_repo(repo_name)
162 repo = ScmModel().get_repo(repo_name)
158
163
159 try:
164 try:
160 repo.get_changeset(revision)
165 repo.get_changeset(revision)
161 except ChangesetDoesNotExistError:
166 except ChangesetDoesNotExistError:
162 return _('Unknown revision %s') % revision
167 return _('Unknown revision %s') % revision
163
168
164 archive = tempfile.TemporaryFile()
169 archive = tempfile.TemporaryFile()
165 localrepo = repo.repo
170 localrepo = repo.repo
166 fname = '%s-%s%s' % (repo_name, revision, fileformat)
171 fname = '%s-%s%s' % (repo_name, revision, fileformat)
167 archival.archive(localrepo, archive, revision, archive_specs[fileformat][1],
172 archival.archive(localrepo, archive, revision, archive_specs[fileformat][1],
168 prefix='%s-%s' % (repo_name, revision))
173 prefix='%s-%s' % (repo_name, revision))
169 response.content_type = archive_specs[fileformat][0]
174 response.content_type = archive_specs[fileformat][0]
170 response.content_disposition = 'attachment; filename=%s' % fname
175 response.content_disposition = 'attachment; filename=%s' % fname
171 archive.seek(0)
176 archive.seek(0)
172
177
173 def read_in_chunks(file_object, chunk_size=1024 * 40):
178 def read_in_chunks(file_object, chunk_size=1024 * 40):
174 """Lazy function (generator) to read a file piece by piece.
179 """Lazy function (generator) to read a file piece by piece.
175 Default chunk size: 40k."""
180 Default chunk size: 40k."""
176 while True:
181 while True:
177 data = file_object.read(chunk_size)
182 data = file_object.read(chunk_size)
178 if not data:
183 if not data:
179 break
184 break
180 yield data
185 yield data
181
186
182 return read_in_chunks(archive)
187 return read_in_chunks(archive)
183
188
184 def diff(self, repo_name, f_path):
189 def diff(self, repo_name, f_path):
185 hg_model = ScmModel()
190 hg_model = ScmModel()
186 diff1 = request.GET.get('diff1')
191 diff1 = request.GET.get('diff1')
187 diff2 = request.GET.get('diff2')
192 diff2 = request.GET.get('diff2')
188 c.action = request.GET.get('diff')
193 c.action = request.GET.get('diff')
189 c.no_changes = diff1 == diff2
194 c.no_changes = diff1 == diff2
190 c.f_path = f_path
195 c.f_path = f_path
191 c.repo = hg_model.get_repo(c.repo_name)
196 c.repo = hg_model.get_repo(c.repo_name)
192
197
193 try:
198 try:
194 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
199 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
195 c.changeset_1 = c.repo.get_changeset(diff1)
200 c.changeset_1 = c.repo.get_changeset(diff1)
196 node1 = c.changeset_1.get_node(f_path)
201 node1 = c.changeset_1.get_node(f_path)
197 else:
202 else:
198 c.changeset_1 = EmptyChangeset()
203 c.changeset_1 = EmptyChangeset()
199 node1 = FileNode('.', '', changeset=c.changeset_1)
204 node1 = FileNode('.', '', changeset=c.changeset_1)
200
205
201 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
206 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
202 c.changeset_2 = c.repo.get_changeset(diff2)
207 c.changeset_2 = c.repo.get_changeset(diff2)
203 node2 = c.changeset_2.get_node(f_path)
208 node2 = c.changeset_2.get_node(f_path)
204 else:
209 else:
205 c.changeset_2 = EmptyChangeset()
210 c.changeset_2 = EmptyChangeset()
206 node2 = FileNode('.', '', changeset=c.changeset_2)
211 node2 = FileNode('.', '', changeset=c.changeset_2)
207 except RepositoryError:
212 except RepositoryError:
208 return redirect(url('files_home',
213 return redirect(url('files_home',
209 repo_name=c.repo_name, f_path=f_path))
214 repo_name=c.repo_name, f_path=f_path))
210
215
211 f_udiff = differ.get_udiff(node1, node2)
216 f_udiff = differ.get_udiff(node1, node2)
212 diff = differ.DiffProcessor(f_udiff)
217 diff = differ.DiffProcessor(f_udiff)
213
218
214 if c.action == 'download':
219 if c.action == 'download':
215 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
220 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
216 response.content_type = 'text/plain'
221 response.content_type = 'text/plain'
217 response.content_disposition = 'attachment; filename=%s' \
222 response.content_disposition = 'attachment; filename=%s' \
218 % diff_name
223 % diff_name
219 return diff.raw_diff()
224 return diff.raw_diff()
220
225
221 elif c.action == 'raw':
226 elif c.action == 'raw':
222 response.content_type = 'text/plain'
227 response.content_type = 'text/plain'
223 return diff.raw_diff()
228 return diff.raw_diff()
224
229
225 elif c.action == 'diff':
230 elif c.action == 'diff':
226 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
231 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
227 c.cur_diff = _('Diff is to big to display')
232 c.cur_diff = _('Diff is to big to display')
228 else:
233 else:
229 c.cur_diff = diff.as_html()
234 c.cur_diff = diff.as_html()
230 else:
235 else:
231 #default option
236 #default option
232 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
237 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
233 c.cur_diff = _('Diff is to big to display')
238 c.cur_diff = _('Diff is to big to display')
234 else:
239 else:
235 c.cur_diff = diff.as_html()
240 c.cur_diff = diff.as_html()
236
241
237 if not c.cur_diff: c.no_changes = True
242 if not c.cur_diff: c.no_changes = True
238 return render('files/file_diff.html')
243 return render('files/file_diff.html')
239
244
240 def _get_history(self, repo, node, f_path):
245 def _get_history(self, repo, node, f_path):
241 from vcs.nodes import NodeKind
246 from vcs.nodes import NodeKind
242 if not node.kind is NodeKind.FILE:
247 if not node.kind is NodeKind.FILE:
243 return []
248 return []
244 changesets = node.history
249 changesets = node.history
245 hist_l = []
250 hist_l = []
246
251
247 changesets_group = ([], _("Changesets"))
252 changesets_group = ([], _("Changesets"))
248 branches_group = ([], _("Branches"))
253 branches_group = ([], _("Branches"))
249 tags_group = ([], _("Tags"))
254 tags_group = ([], _("Tags"))
250
255
251 for chs in changesets:
256 for chs in changesets:
252 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
257 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
253 changesets_group[0].append((chs.raw_id, n_desc,))
258 changesets_group[0].append((chs.raw_id, n_desc,))
254
259
255 hist_l.append(changesets_group)
260 hist_l.append(changesets_group)
256
261
257 for name, chs in c.repository_branches.items():
262 for name, chs in c.repository_branches.items():
258 #chs = chs.split(':')[-1]
263 #chs = chs.split(':')[-1]
259 branches_group[0].append((chs, name),)
264 branches_group[0].append((chs, name),)
260 hist_l.append(branches_group)
265 hist_l.append(branches_group)
261
266
262 for name, chs in c.repository_tags.items():
267 for name, chs in c.repository_tags.items():
263 #chs = chs.split(':')[-1]
268 #chs = chs.split(':')[-1]
264 tags_group[0].append((chs, name),)
269 tags_group[0].append((chs, name),)
265 hist_l.append(tags_group)
270 hist_l.append(tags_group)
266
271
267 return hist_l
272 return hist_l
268
273
General Comments 0
You need to be logged in to leave comments. Login now