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