##// END OF EJS Templates
use cs get history instead of node.history, node history have to much reference calls
marcink -
r1190:0d7a127e beta
parent child Browse files
Show More
@@ -1,305 +1,303 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
77
78 def __get_filenode_or_redirect(self, repo_name, cs, path):
78 def __get_filenode_or_redirect(self, repo_name, cs, path):
79 """
79 """
80 Returns file_node, if error occurs or given path is directory,
80 Returns file_node, if error occurs or given path is directory,
81 it'll redirect to top level path
81 it'll redirect to top level path
82
82
83 :param repo_name: repo_name
83 :param repo_name: repo_name
84 :param cs: given changeset
84 :param cs: given changeset
85 :param path: path to lookup
85 :param path: path to lookup
86 """
86 """
87
87
88
88
89 try:
89 try:
90 file_node = cs.get_node(path)
90 file_node = cs.get_node(path)
91 if file_node.is_dir():
91 if file_node.is_dir():
92 raise RepositoryError('given path is a directory')
92 raise RepositoryError('given path is a directory')
93 except RepositoryError, e:
93 except RepositoryError, e:
94 h.flash(str(e), category='warning')
94 h.flash(str(e), category='warning')
95 redirect(h.url('files_home', repo_name=repo_name,
95 redirect(h.url('files_home', repo_name=repo_name,
96 revision=cs.raw_id))
96 revision=cs.raw_id))
97
97
98 return file_node
98 return file_node
99
99
100 def index(self, repo_name, revision, f_path):
100 def index(self, repo_name, revision, f_path):
101 #reditect to given revision from form if given
101 #reditect to given revision from form if given
102 post_revision = request.POST.get('at_rev', None)
102 post_revision = request.POST.get('at_rev', None)
103 if post_revision:
103 if post_revision:
104 cs = self.__get_cs_or_redirect(revision, repo_name)
104 cs = self.__get_cs_or_redirect(revision, repo_name)
105 redirect(url('files_home', repo_name=c.repo_name,
105 redirect(url('files_home', repo_name=c.repo_name,
106 revision=cs.raw_id, f_path=f_path))
106 revision=cs.raw_id, f_path=f_path))
107
107
108
108
109 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
109 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
110 c.branch = request.GET.get('branch', None)
110 c.branch = request.GET.get('branch', None)
111 c.f_path = f_path
111 c.f_path = f_path
112
112
113 cur_rev = c.changeset.revision
113 cur_rev = c.changeset.revision
114
114
115 #prev link
115 #prev link
116 try:
116 try:
117 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)
118 c.url_prev = url('files_home', repo_name=c.repo_name,
118 c.url_prev = url('files_home', repo_name=c.repo_name,
119 revision=prev_rev.raw_id, f_path=f_path)
119 revision=prev_rev.raw_id, f_path=f_path)
120 if c.branch:
120 if c.branch:
121 c.url_prev += '?branch=%s' % c.branch
121 c.url_prev += '?branch=%s' % c.branch
122 except (ChangesetDoesNotExistError, VCSError):
122 except (ChangesetDoesNotExistError, VCSError):
123 c.url_prev = '#'
123 c.url_prev = '#'
124
124
125 #next link
125 #next link
126 try:
126 try:
127 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)
128 c.url_next = url('files_home', repo_name=c.repo_name,
128 c.url_next = url('files_home', repo_name=c.repo_name,
129 revision=next_rev.raw_id, f_path=f_path)
129 revision=next_rev.raw_id, f_path=f_path)
130 if c.branch:
130 if c.branch:
131 c.url_next += '?branch=%s' % c.branch
131 c.url_next += '?branch=%s' % c.branch
132 except (ChangesetDoesNotExistError, VCSError):
132 except (ChangesetDoesNotExistError, VCSError):
133 c.url_next = '#'
133 c.url_next = '#'
134
134
135 #files or dirs
135 #files or dirs
136 try:
136 try:
137 c.files_list = c.changeset.get_node(f_path)
137 c.files_list = c.changeset.get_node(f_path)
138 c.file_history = self._get_history(c.rhodecode_repo,
138
139 c.files_list, f_path)
139 if c.files_list.is_file():
140 c.file_history = self._get_node_history(c.changeset, f_path)
141 else:
142 c.file_history = []
140 except RepositoryError, e:
143 except RepositoryError, e:
141 h.flash(str(e), category='warning')
144 h.flash(str(e), category='warning')
142 redirect(h.url('files_home', repo_name=repo_name,
145 redirect(h.url('files_home', repo_name=repo_name,
143 revision=revision))
146 revision=revision))
144
147
145
148
146 return render('files/files.html')
149 return render('files/files.html')
147
150
148 def rawfile(self, repo_name, revision, f_path):
151 def rawfile(self, repo_name, revision, f_path):
149 cs = self.__get_cs_or_redirect(revision, repo_name)
152 cs = self.__get_cs_or_redirect(revision, repo_name)
150 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
153 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
151
154
152 response.content_disposition = 'attachment; filename=%s' % \
155 response.content_disposition = 'attachment; filename=%s' % \
153 f_path.split('/')[-1].encode('utf8', 'replace')
156 f_path.split('/')[-1].encode('utf8', 'replace')
154
157
155 response.content_type = file_node.mimetype
158 response.content_type = file_node.mimetype
156 return file_node.content
159 return file_node.content
157
160
158 def raw(self, repo_name, revision, f_path):
161 def raw(self, repo_name, revision, f_path):
159 cs = self.__get_cs_or_redirect(revision, repo_name)
162 cs = self.__get_cs_or_redirect(revision, repo_name)
160 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
163 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
161
164
162 response.content_type = 'text/plain'
165 response.content_type = 'text/plain'
163 return file_node.content
166 return file_node.content
164
167
165 def annotate(self, repo_name, revision, f_path):
168 def annotate(self, repo_name, revision, f_path):
166 cs = self.__get_cs_or_redirect(revision, repo_name)
169 c.cs = self.__get_cs_or_redirect(revision, repo_name)
167 c.file = self.__get_filenode_or_redirect(repo_name, cs, f_path)
170 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
168
171
169 c.file_history = self._get_history(c.rhodecode_repo,
172 c.file_history = self._get_node_history(c.cs, f_path)
170 c.file, f_path)
171 c.cs = cs
172 c.f_path = f_path
173 c.f_path = f_path
173
174 return render('files/files_annotate.html')
174 return render('files/files_annotate.html')
175
175
176 def archivefile(self, repo_name, fname):
176 def archivefile(self, repo_name, fname):
177
177
178 fileformat = None
178 fileformat = None
179 revision = None
179 revision = None
180 ext = None
180 ext = None
181
181
182 for a_type, ext_data in ARCHIVE_SPECS.items():
182 for a_type, ext_data in ARCHIVE_SPECS.items():
183 archive_spec = fname.split(ext_data[1])
183 archive_spec = fname.split(ext_data[1])
184 if len(archive_spec) == 2 and archive_spec[1] == '':
184 if len(archive_spec) == 2 and archive_spec[1] == '':
185 fileformat = a_type or ext_data[1]
185 fileformat = a_type or ext_data[1]
186 revision = archive_spec[0]
186 revision = archive_spec[0]
187 ext = ext_data[1]
187 ext = ext_data[1]
188
188
189 try:
189 try:
190 dbrepo = RepoModel().get_by_repo_name(repo_name)
190 dbrepo = RepoModel().get_by_repo_name(repo_name)
191 if dbrepo.enable_downloads is False:
191 if dbrepo.enable_downloads is False:
192 return _('downloads disabled')
192 return _('downloads disabled')
193
193
194 cs = c.rhodecode_repo.get_changeset(revision)
194 cs = c.rhodecode_repo.get_changeset(revision)
195 content_type = ARCHIVE_SPECS[fileformat][0]
195 content_type = ARCHIVE_SPECS[fileformat][0]
196 except ChangesetDoesNotExistError:
196 except ChangesetDoesNotExistError:
197 return _('Unknown revision %s') % revision
197 return _('Unknown revision %s') % revision
198 except EmptyRepositoryError:
198 except EmptyRepositoryError:
199 return _('Empty repository')
199 return _('Empty repository')
200 except (ImproperArchiveTypeError, KeyError):
200 except (ImproperArchiveTypeError, KeyError):
201 return _('Unknown archive type')
201 return _('Unknown archive type')
202
202
203 response.content_type = content_type
203 response.content_type = content_type
204 response.content_disposition = 'attachment; filename=%s-%s%s' \
204 response.content_disposition = 'attachment; filename=%s-%s%s' \
205 % (repo_name, revision, ext)
205 % (repo_name, revision, ext)
206
206
207 return cs.get_chunked_archive(stream=None, kind=fileformat)
207 return cs.get_chunked_archive(stream=None, kind=fileformat)
208
208
209
209
210 def diff(self, repo_name, f_path):
210 def diff(self, repo_name, f_path):
211 diff1 = request.GET.get('diff1')
211 diff1 = request.GET.get('diff1')
212 diff2 = request.GET.get('diff2')
212 diff2 = request.GET.get('diff2')
213 c.action = request.GET.get('diff')
213 c.action = request.GET.get('diff')
214 c.no_changes = diff1 == diff2
214 c.no_changes = diff1 == diff2
215 c.f_path = f_path
215 c.f_path = f_path
216
216
217 try:
217 try:
218 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
218 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
219 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
219 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
220 node1 = c.changeset_1.get_node(f_path)
220 node1 = c.changeset_1.get_node(f_path)
221 else:
221 else:
222 c.changeset_1 = EmptyChangeset()
222 c.changeset_1 = EmptyChangeset()
223 node1 = FileNode('.', '', changeset=c.changeset_1)
223 node1 = FileNode('.', '', changeset=c.changeset_1)
224
224
225 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
225 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
226 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
226 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
227 node2 = c.changeset_2.get_node(f_path)
227 node2 = c.changeset_2.get_node(f_path)
228 else:
228 else:
229 c.changeset_2 = EmptyChangeset()
229 c.changeset_2 = EmptyChangeset()
230 node2 = FileNode('.', '', changeset=c.changeset_2)
230 node2 = FileNode('.', '', changeset=c.changeset_2)
231 except RepositoryError:
231 except RepositoryError:
232 return redirect(url('files_home',
232 return redirect(url('files_home',
233 repo_name=c.repo_name, f_path=f_path))
233 repo_name=c.repo_name, f_path=f_path))
234
234
235
235
236 if c.action == 'download':
236 if c.action == 'download':
237 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
237 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
238 format='gitdiff')
238 format='gitdiff')
239
239
240 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
240 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
241 response.content_type = 'text/plain'
241 response.content_type = 'text/plain'
242 response.content_disposition = 'attachment; filename=%s' \
242 response.content_disposition = 'attachment; filename=%s' \
243 % diff_name
243 % diff_name
244 return diff.raw_diff()
244 return diff.raw_diff()
245
245
246 elif c.action == 'raw':
246 elif c.action == 'raw':
247 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
247 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
248 format='gitdiff')
248 format='gitdiff')
249 response.content_type = 'text/plain'
249 response.content_type = 'text/plain'
250 return diff.raw_diff()
250 return diff.raw_diff()
251
251
252 elif c.action == 'diff':
252 elif c.action == 'diff':
253
253
254 if node1.is_binary or node2.is_binary:
254 if node1.is_binary or node2.is_binary:
255 c.cur_diff = _('Binary file')
255 c.cur_diff = _('Binary file')
256 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:
257 c.cur_diff = _('Diff is too big to display')
257 c.cur_diff = _('Diff is too big to display')
258 else:
258 else:
259 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
259 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
260 format='gitdiff')
260 format='gitdiff')
261 c.cur_diff = diff.as_html()
261 c.cur_diff = diff.as_html()
262 else:
262 else:
263
263
264 #default option
264 #default option
265 if node1.is_binary or node2.is_binary:
265 if node1.is_binary or node2.is_binary:
266 c.cur_diff = _('Binary file')
266 c.cur_diff = _('Binary file')
267 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:
268 c.cur_diff = _('Diff is too big to display')
268 c.cur_diff = _('Diff is too big to display')
269 else:
269 else:
270 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
270 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
271 format='gitdiff')
271 format='gitdiff')
272 c.cur_diff = diff.as_html()
272 c.cur_diff = diff.as_html()
273
273
274 if not c.cur_diff:
274 if not c.cur_diff:
275 c.no_changes = True
275 c.no_changes = True
276 return render('files/file_diff.html')
276 return render('files/file_diff.html')
277
277
278 def _get_history(self, repo, node, f_path):
278 def _get_node_history(self, cs, f_path):
279 if not node.is_file():
279 changesets = cs.get_file_history(f_path)
280 return []
281 changesets = node.history
282 hist_l = []
280 hist_l = []
283
281
284 changesets_group = ([], _("Changesets"))
282 changesets_group = ([], _("Changesets"))
285 branches_group = ([], _("Branches"))
283 branches_group = ([], _("Branches"))
286 tags_group = ([], _("Tags"))
284 tags_group = ([], _("Tags"))
287
285
288 for chs in changesets:
286 for chs in changesets:
289 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
287 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
290 changesets_group[0].append((chs.raw_id, n_desc,))
288 changesets_group[0].append((chs.raw_id, n_desc,))
291
289
292 hist_l.append(changesets_group)
290 hist_l.append(changesets_group)
293
291
294 for name, chs in c.rhodecode_repo.branches.items():
292 for name, chs in c.rhodecode_repo.branches.items():
295 #chs = chs.split(':')[-1]
293 #chs = chs.split(':')[-1]
296 branches_group[0].append((chs, name),)
294 branches_group[0].append((chs, name),)
297 hist_l.append(branches_group)
295 hist_l.append(branches_group)
298
296
299 for name, chs in c.rhodecode_repo.tags.items():
297 for name, chs in c.rhodecode_repo.tags.items():
300 #chs = chs.split(':')[-1]
298 #chs = chs.split(':')[-1]
301 tags_group[0].append((chs, name),)
299 tags_group[0].append((chs, name),)
302 hist_l.append(tags_group)
300 hist_l.append(tags_group)
303
301
304 return hist_l
302 return hist_l
305
303
General Comments 0
You need to be logged in to leave comments. Login now