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