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