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