##// END OF EJS Templates
Added show as raw into big diff
marcink -
r1273:64cb9612 beta
parent child Browse files
Show More
@@ -1,335 +1,339 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.files
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Files controller for RhodeCode
7 7
8 8 :created_on: Apr 21, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import mimetypes
29 29 import rhodecode.lib.helpers as h
30 30
31 31 from pylons import request, response, session, tmpl_context as c, url
32 32 from pylons.i18n.translation import _
33 33 from pylons.controllers.util import redirect
34 34
35 35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 36 from rhodecode.lib.base import BaseRepoController, render
37 37 from rhodecode.lib.utils import EmptyChangeset
38 38 from rhodecode.model.repo import RepoModel
39 39
40 40 from vcs.backends import ARCHIVE_SPECS
41 41 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
42 42 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
43 43 from vcs.nodes import FileNode, NodeKind
44 44 from vcs.utils import diffs as differ
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class FilesController(BaseRepoController):
50 50
51 51 @LoginRequired()
52 52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 53 'repository.admin')
54 54 def __before__(self):
55 55 super(FilesController, self).__before__()
56 56 c.cut_off_limit = self.cut_off_limit
57 57
58 58 def __get_cs_or_redirect(self, rev, repo_name):
59 59 """
60 60 Safe way to get changeset if error occur it redirects to tip with
61 61 proper message
62 62
63 63 :param rev: revision to fetch
64 64 :param repo_name: repo name to redirect after
65 65 """
66 66
67 67 try:
68 68 return c.rhodecode_repo.get_changeset(rev)
69 69 except EmptyRepositoryError, e:
70 70 h.flash(_('There are no files yet'), category='warning')
71 71 redirect(h.url('summary_home', repo_name=repo_name))
72 72
73 73 except RepositoryError, e:
74 74 h.flash(str(e), category='warning')
75 75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
76 76
77 77 def __get_filenode_or_redirect(self, repo_name, cs, path):
78 78 """
79 79 Returns file_node, if error occurs or given path is directory,
80 80 it'll redirect to top level path
81 81
82 82 :param repo_name: repo_name
83 83 :param cs: given changeset
84 84 :param path: path to lookup
85 85 """
86 86
87 87 try:
88 88 file_node = cs.get_node(path)
89 89 if file_node.is_dir():
90 90 raise RepositoryError('given path is a directory')
91 91 except RepositoryError, e:
92 92 h.flash(str(e), category='warning')
93 93 redirect(h.url('files_home', repo_name=repo_name,
94 94 revision=cs.raw_id))
95 95
96 96 return file_node
97 97
98 98 def index(self, repo_name, revision, f_path):
99 99 #reditect to given revision from form if given
100 100 post_revision = request.POST.get('at_rev', None)
101 101 if post_revision:
102 102 cs = self.__get_cs_or_redirect(post_revision, repo_name)
103 103 redirect(url('files_home', repo_name=c.repo_name,
104 104 revision=cs.raw_id, f_path=f_path))
105 105
106 106 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
107 107 c.branch = request.GET.get('branch', None)
108 108 c.f_path = f_path
109 109
110 110 cur_rev = c.changeset.revision
111 111
112 112 #prev link
113 113 try:
114 114 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
115 115 c.url_prev = url('files_home', repo_name=c.repo_name,
116 116 revision=prev_rev.raw_id, f_path=f_path)
117 117 if c.branch:
118 118 c.url_prev += '?branch=%s' % c.branch
119 119 except (ChangesetDoesNotExistError, VCSError):
120 120 c.url_prev = '#'
121 121
122 122 #next link
123 123 try:
124 124 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
125 125 c.url_next = url('files_home', repo_name=c.repo_name,
126 126 revision=next_rev.raw_id, f_path=f_path)
127 127 if c.branch:
128 128 c.url_next += '?branch=%s' % c.branch
129 129 except (ChangesetDoesNotExistError, VCSError):
130 130 c.url_next = '#'
131 131
132 132 #files or dirs
133 133 try:
134 134 c.files_list = c.changeset.get_node(f_path)
135 135
136 136 if c.files_list.is_file():
137 137 c.file_history = self._get_node_history(c.changeset, f_path)
138 138 else:
139 139 c.file_history = []
140 140 except RepositoryError, e:
141 141 h.flash(str(e), category='warning')
142 142 redirect(h.url('files_home', repo_name=repo_name,
143 143 revision=revision))
144 144
145 145 return render('files/files.html')
146 146
147 147 def rawfile(self, repo_name, revision, f_path):
148 148 cs = self.__get_cs_or_redirect(revision, repo_name)
149 149 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
150 150
151 151 response.content_disposition = 'attachment; filename=%s' % \
152 152 f_path.split(os.sep)[-1].encode('utf8', 'replace')
153 153
154 154 response.content_type = file_node.mimetype
155 155 return file_node.content
156 156
157 157 def raw(self, repo_name, revision, f_path):
158 158 cs = self.__get_cs_or_redirect(revision, repo_name)
159 159 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
160 160
161 161 raw_mimetype_mapping = {
162 162 # map original mimetype to a mimetype used for "show as raw"
163 163 # you can also provide a content-disposition to override the
164 164 # default "attachment" disposition.
165 165 # orig_type: (new_type, new_dispo)
166 166
167 167 # show images inline:
168 168 'image/x-icon': ('image/x-icon', 'inline'),
169 169 'image/png': ('image/png', 'inline'),
170 170 'image/gif': ('image/gif', 'inline'),
171 171 'image/jpeg': ('image/jpeg', 'inline'),
172 172 'image/svg+xml': ('image/svg+xml', 'inline'),
173 173 }
174 174
175 175 mimetype = file_node.mimetype
176 176 try:
177 177 mimetype, dispo = raw_mimetype_mapping[mimetype]
178 178 except KeyError:
179 179 # we don't know anything special about this, handle it safely
180 180 if file_node.is_binary:
181 181 # do same as download raw for binary files
182 182 mimetype, dispo = 'application/octet-stream', 'attachment'
183 183 else:
184 184 # do not just use the original mimetype, but force text/plain,
185 185 # otherwise it would serve text/html and that might be unsafe.
186 186 # Note: underlying vcs library fakes text/plain mimetype if the
187 187 # mimetype can not be determined and it thinks it is not
188 188 # binary.This might lead to erroneous text display in some
189 189 # cases, but helps in other cases, like with text files
190 190 # without extension.
191 191 mimetype, dispo = 'text/plain', 'inline'
192 192
193 193 if dispo == 'attachment':
194 194 dispo = 'attachment; filename=%s' % \
195 195 f_path.split(os.sep)[-1].encode('utf8', 'replace')
196 196
197 197 response.content_disposition = dispo
198 198 response.content_type = mimetype
199 199 return file_node.content
200 200
201 201 def annotate(self, repo_name, revision, f_path):
202 202 c.cs = self.__get_cs_or_redirect(revision, repo_name)
203 203 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
204 204
205 205 c.file_history = self._get_node_history(c.cs, f_path)
206 206 c.f_path = f_path
207 207 return render('files/files_annotate.html')
208 208
209 209 def archivefile(self, repo_name, fname):
210 210
211 211 fileformat = None
212 212 revision = None
213 213 ext = None
214 214
215 215 for a_type, ext_data in ARCHIVE_SPECS.items():
216 216 archive_spec = fname.split(ext_data[1])
217 217 if len(archive_spec) == 2 and archive_spec[1] == '':
218 218 fileformat = a_type or ext_data[1]
219 219 revision = archive_spec[0]
220 220 ext = ext_data[1]
221 221
222 222 try:
223 223 dbrepo = RepoModel().get_by_repo_name(repo_name)
224 224 if dbrepo.enable_downloads is False:
225 225 return _('downloads disabled')
226 226
227 227 cs = c.rhodecode_repo.get_changeset(revision)
228 228 content_type = ARCHIVE_SPECS[fileformat][0]
229 229 except ChangesetDoesNotExistError:
230 230 return _('Unknown revision %s') % revision
231 231 except EmptyRepositoryError:
232 232 return _('Empty repository')
233 233 except (ImproperArchiveTypeError, KeyError):
234 234 return _('Unknown archive type')
235 235
236 236 response.content_type = content_type
237 237 response.content_disposition = 'attachment; filename=%s-%s%s' \
238 238 % (repo_name, revision, ext)
239 239
240 240 return cs.get_chunked_archive(stream=None, kind=fileformat)
241 241
242 242 def diff(self, repo_name, f_path):
243 243 diff1 = request.GET.get('diff1')
244 244 diff2 = request.GET.get('diff2')
245 245 c.action = request.GET.get('diff')
246 246 c.no_changes = diff1 == diff2
247 247 c.f_path = f_path
248 c.big_diff = False
248 249
249 250 try:
250 251 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
251 252 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
252 253 node1 = c.changeset_1.get_node(f_path)
253 254 else:
254 255 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
255 256 node1 = FileNode('.', '', changeset=c.changeset_1)
256 257
257 258 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
258 259 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
259 260 node2 = c.changeset_2.get_node(f_path)
260 261 else:
261 262 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
262 263 node2 = FileNode('.', '', changeset=c.changeset_2)
263 264 except RepositoryError:
264 265 return redirect(url('files_home',
265 266 repo_name=c.repo_name, f_path=f_path))
266 267
267 268 if c.action == 'download':
268 269 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
269 270 format='gitdiff')
270 271
271 272 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
272 273 response.content_type = 'text/plain'
273 274 response.content_disposition = 'attachment; filename=%s' \
274 275 % diff_name
275 276 return diff.raw_diff()
276 277
277 278 elif c.action == 'raw':
278 279 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
279 280 format='gitdiff')
280 281 response.content_type = 'text/plain'
281 282 return diff.raw_diff()
282 283
283 284 elif c.action == 'diff':
284 285
285 286 if node1.is_binary or node2.is_binary:
286 287 c.cur_diff = _('Binary file')
287 288 elif node1.size > self.cut_off_limit or \
288 289 node2.size > self.cut_off_limit:
289 c.cur_diff = _('Diff is too big to display')
290 c.cur_diff = ''
291 c.big_diff = True
290 292 else:
291 293 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
292 294 format='gitdiff')
293 295 c.cur_diff = diff.as_html()
294 296 else:
295 297
296 298 #default option
297 299 if node1.is_binary or node2.is_binary:
298 300 c.cur_diff = _('Binary file')
299 301 elif node1.size > self.cut_off_limit or \
300 302 node2.size > self.cut_off_limit:
301 c.cur_diff = _('Diff is too big to display')
303 c.cur_diff = ''
304 c.big_diff = True
305
302 306 else:
303 307 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
304 308 format='gitdiff')
305 309 c.cur_diff = diff.as_html()
306 310
307 if not c.cur_diff:
311 if not c.cur_diff and not c.big_diff:
308 312 c.no_changes = True
309 313 return render('files/file_diff.html')
310 314
311 315 def _get_node_history(self, cs, f_path):
312 316 changesets = cs.get_file_history(f_path)
313 317 hist_l = []
314 318
315 319 changesets_group = ([], _("Changesets"))
316 320 branches_group = ([], _("Branches"))
317 321 tags_group = ([], _("Tags"))
318 322
319 323 for chs in changesets:
320 324 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
321 325 changesets_group[0].append((chs.raw_id, n_desc,))
322 326
323 327 hist_l.append(changesets_group)
324 328
325 329 for name, chs in c.rhodecode_repo.branches.items():
326 330 #chs = chs.split(':')[-1]
327 331 branches_group[0].append((chs, name),)
328 332 hist_l.append(branches_group)
329 333
330 334 for name, chs in c.rhodecode_repo.tags.items():
331 335 #chs = chs.split(':')[-1]
332 336 tags_group[0].append((chs, name),)
333 337 hist_l.append(tags_group)
334 338
335 339 return hist_l
@@ -1,50 +1,53 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('File diff')} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('File diff')} r${c.changeset_1.revision}:${h.short_id(c.changeset_1.raw_id)} &rarr; r${c.changeset_2.revision}:${h.short_id(c.changeset_2.raw_id)}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('files')}
17 17 </%def>
18 18 <%def name="main()">
19 19 <div class="box">
20 20 <!-- box / title -->
21 21 <div class="title">
22 22 ${self.breadcrumbs()}
23 23 </div>
24 24 <div class="table">
25 25 <div id="body" class="diffblock">
26 26 <div class="code-header">
27 27 <div class="changeset_header">
28 28 <span class="changeset_file">${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
29 29 revision=c.changeset_2.raw_id,f_path=c.f_path))}</span>
30 30 &raquo; <span>${h.link_to(_('diff'),
31 31 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='diff'))}</span>
32 32 &raquo; <span>${h.link_to(_('raw diff'),
33 33 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}</span>
34 34 &raquo; <span>${h.link_to(_('download diff'),
35 35 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='download'))}</span>
36 36 </div>
37 37 </div>
38 38 <div class="code-body">
39 39 %if c.no_changes:
40 40 ${_('No changes')}
41 %elif c.big_diff:
42 ${_('Diff is to big to display')} ${h.link_to(_('raw diff'),
43 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}
41 44 %else:
42 45 ${c.cur_diff|n}
43 46 %endif
44 47 </div>
45 48 </div>
46 49 </div>
47 50 </div>
48 51 </%def>
49 52
50 53 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now