##// END OF EJS Templates
white space cleanup
marcink -
r2188:56e96d4e beta
parent child Browse files
Show More
@@ -1,391 +1,392 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.changeset
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 changeset controller for pylons showoing changes beetween
7 7 revisions
8 8
9 9 :created_on: Apr 25, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26 import logging
27 27 import traceback
28 28 from collections import defaultdict
29 29 from webob.exc import HTTPForbidden
30 30
31 31 from pylons import tmpl_context as c, url, request, response
32 32 from pylons.i18n.translation import _
33 33 from pylons.controllers.util import redirect
34 34 from pylons.decorators import jsonify
35 35
36 36 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
37 37 ChangesetDoesNotExistError
38 38 from rhodecode.lib.vcs.nodes import FileNode
39 39
40 40 import rhodecode.lib.helpers as h
41 41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 42 from rhodecode.lib.base import BaseRepoController, render
43 43 from rhodecode.lib.utils import EmptyChangeset
44 44 from rhodecode.lib.compat import OrderedDict
45 45 from rhodecode.lib import diffs
46 46 from rhodecode.model.db import ChangesetComment
47 47 from rhodecode.model.comment import ChangesetCommentsModel
48 48 from rhodecode.model.meta import Session
49 49 from rhodecode.lib.diffs import wrapped_diff
50 50
51 51 log = logging.getLogger(__name__)
52 52
53 53
54 54 def _update_with_GET(params, GET):
55 55 for k in ['diff1', 'diff2', 'diff']:
56 56 params[k] += GET.getall(k)
57 57
58 58
59 59 def anchor_url(revision, path, GET):
60 60 fid = h.FID(revision, path)
61 61 return h.url.current(anchor=fid, **dict(GET))
62 62
63 63
64 64 def get_ignore_ws(fid, GET):
65 65 ig_ws_global = GET.get('ignorews')
66 66 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
67 67 if ig_ws:
68 68 try:
69 69 return int(ig_ws[0].split(':')[-1])
70 70 except:
71 71 pass
72 72 return ig_ws_global
73 73
74 74
75 75 def _ignorews_url(GET, fileid=None):
76 76 fileid = str(fileid) if fileid else None
77 77 params = defaultdict(list)
78 78 _update_with_GET(params, GET)
79 79 lbl = _('show white space')
80 80 ig_ws = get_ignore_ws(fileid, GET)
81 81 ln_ctx = get_line_ctx(fileid, GET)
82 82 # global option
83 83 if fileid is None:
84 84 if ig_ws is None:
85 85 params['ignorews'] += [1]
86 86 lbl = _('ignore white space')
87 87 ctx_key = 'context'
88 88 ctx_val = ln_ctx
89 89 # per file options
90 90 else:
91 91 if ig_ws is None:
92 92 params[fileid] += ['WS:1']
93 93 lbl = _('ignore white space')
94 94
95 95 ctx_key = fileid
96 96 ctx_val = 'C:%s' % ln_ctx
97 97 # if we have passed in ln_ctx pass it along to our params
98 98 if ln_ctx:
99 99 params[ctx_key] += [ctx_val]
100 100
101 101 params['anchor'] = fileid
102 102 img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
103 103 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
104 104
105 105
106 106 def get_line_ctx(fid, GET):
107 107 ln_ctx_global = GET.get('context')
108 108 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
109 109
110 110 if ln_ctx:
111 111 retval = ln_ctx[0].split(':')[-1]
112 112 else:
113 113 retval = ln_ctx_global
114 114
115 115 try:
116 116 return int(retval)
117 117 except:
118 118 return
119 119
120 120
121 121 def _context_url(GET, fileid=None):
122 122 """
123 123 Generates url for context lines
124 124
125 125 :param fileid:
126 126 """
127 127
128 128 fileid = str(fileid) if fileid else None
129 129 ig_ws = get_ignore_ws(fileid, GET)
130 130 ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
131 131
132 132 params = defaultdict(list)
133 133 _update_with_GET(params, GET)
134 134
135 135 # global option
136 136 if fileid is None:
137 137 if ln_ctx > 0:
138 138 params['context'] += [ln_ctx]
139 139
140 140 if ig_ws:
141 141 ig_ws_key = 'ignorews'
142 142 ig_ws_val = 1
143 143
144 144 # per file option
145 145 else:
146 146 params[fileid] += ['C:%s' % ln_ctx]
147 147 ig_ws_key = fileid
148 148 ig_ws_val = 'WS:%s' % 1
149 149
150 150 if ig_ws:
151 151 params[ig_ws_key] += [ig_ws_val]
152 152
153 153 lbl = _('%s line context') % ln_ctx
154 154
155 155 params['anchor'] = fileid
156 156 img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
157 157 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
158 158
159 159
160 160 class ChangesetController(BaseRepoController):
161 161
162 162 @LoginRequired()
163 163 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
164 164 'repository.admin')
165 165 def __before__(self):
166 166 super(ChangesetController, self).__before__()
167 167 c.affected_files_cut_off = 60
168 168
169 169 def index(self, revision):
170 170
171 171 c.anchor_url = anchor_url
172 172 c.ignorews_url = _ignorews_url
173 173 c.context_url = _context_url
174 174 limit_off = request.GET.get('fulldiff')
175 175 #get ranges of revisions if preset
176 176 rev_range = revision.split('...')[:2]
177 177 enable_comments = True
178 178 try:
179 179 if len(rev_range) == 2:
180 180 enable_comments = False
181 181 rev_start = rev_range[0]
182 182 rev_end = rev_range[1]
183 183 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
184 184 end=rev_end)
185 185 else:
186 186 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
187 187
188 188 c.cs_ranges = list(rev_ranges)
189 189 if not c.cs_ranges:
190 190 raise RepositoryError('Changeset range returned empty result')
191 191
192 192 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
193 193 log.error(traceback.format_exc())
194 194 h.flash(str(e), category='warning')
195 195 return redirect(url('home'))
196 196
197 197 c.changes = OrderedDict()
198 198
199 199 c.lines_added = 0 # count of lines added
200 200 c.lines_deleted = 0 # count of lines removes
201 201
202 202 cumulative_diff = 0
203 203 c.cut_off = False # defines if cut off limit is reached
204 204
205 205 c.comments = []
206 206 c.inline_comments = []
207 207 c.inline_cnt = 0
208 208 # Iterate over ranges (default changeset view is always one changeset)
209 209 for changeset in c.cs_ranges:
210 210 c.comments.extend(ChangesetCommentsModel()\
211 211 .get_comments(c.rhodecode_db_repo.repo_id,
212 212 changeset.raw_id))
213 213 inlines = ChangesetCommentsModel()\
214 214 .get_inline_comments(c.rhodecode_db_repo.repo_id,
215 215 changeset.raw_id)
216 216 c.inline_comments.extend(inlines)
217 217 c.changes[changeset.raw_id] = []
218 218 try:
219 219 changeset_parent = changeset.parents[0]
220 220 except IndexError:
221 221 changeset_parent = None
222 222
223 223 #==================================================================
224 224 # ADDED FILES
225 225 #==================================================================
226 226 for node in changeset.added:
227 227 fid = h.FID(revision, node.path)
228 228 line_context_lcl = get_line_ctx(fid, request.GET)
229 229 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
230 230 lim = self.cut_off_limit
231 231 if cumulative_diff > self.cut_off_limit:
232 232 lim = -1 if limit_off is None else None
233 233 size, cs1, cs2, diff, st = wrapped_diff(
234 234 filenode_old=None,
235 235 filenode_new=node,
236 236 cut_off_limit=lim,
237 237 ignore_whitespace=ign_whitespace_lcl,
238 238 line_context=line_context_lcl,
239 239 enable_comments=enable_comments
240 240 )
241 241 cumulative_diff += size
242 242 c.lines_added += st[0]
243 243 c.lines_deleted += st[1]
244 244 c.changes[changeset.raw_id].append(
245 245 ('added', node, diff, cs1, cs2, st)
246 246 )
247 247
248 248 #==================================================================
249 249 # CHANGED FILES
250 250 #==================================================================
251 251 for node in changeset.changed:
252 252 try:
253 253 filenode_old = changeset_parent.get_node(node.path)
254 254 except ChangesetError:
255 255 log.warning('Unable to fetch parent node for diff')
256 256 filenode_old = FileNode(node.path, '', EmptyChangeset())
257 257
258 258 fid = h.FID(revision, node.path)
259 259 line_context_lcl = get_line_ctx(fid, request.GET)
260 260 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
261 261 lim = self.cut_off_limit
262 262 if cumulative_diff > self.cut_off_limit:
263 263 lim = -1 if limit_off is None else None
264 264 size, cs1, cs2, diff, st = wrapped_diff(
265 265 filenode_old=filenode_old,
266 266 filenode_new=node,
267 267 cut_off_limit=lim,
268 268 ignore_whitespace=ign_whitespace_lcl,
269 269 line_context=line_context_lcl,
270 270 enable_comments=enable_comments
271 271 )
272 272 cumulative_diff += size
273 273 c.lines_added += st[0]
274 274 c.lines_deleted += st[1]
275 275 c.changes[changeset.raw_id].append(
276 276 ('changed', node, diff, cs1, cs2, st)
277 277 )
278 278 #==================================================================
279 279 # REMOVED FILES
280 280 #==================================================================
281 281 for node in changeset.removed:
282 282 c.changes[changeset.raw_id].append(
283 283 ('removed', node, None, None, None, (0, 0))
284 284 )
285 285
286 286 # count inline comments
287 287 for path, lines in c.inline_comments:
288 288 for comments in lines.values():
289 289 c.inline_cnt += len(comments)
290 290
291 291 if len(c.cs_ranges) == 1:
292 292 c.changeset = c.cs_ranges[0]
293 293 c.changes = c.changes[c.changeset.raw_id]
294 294
295 295 return render('changeset/changeset.html')
296 296 else:
297 297 return render('changeset/changeset_range.html')
298 298
299 299 def raw_changeset(self, revision):
300 300
301 301 method = request.GET.get('diff', 'show')
302 302 ignore_whitespace = request.GET.get('ignorews') == '1'
303 303 line_context = request.GET.get('context', 3)
304 304 try:
305 305 c.scm_type = c.rhodecode_repo.alias
306 306 c.changeset = c.rhodecode_repo.get_changeset(revision)
307 307 except RepositoryError:
308 308 log.error(traceback.format_exc())
309 309 return redirect(url('home'))
310 310 else:
311 311 try:
312 312 c.changeset_parent = c.changeset.parents[0]
313 313 except IndexError:
314 314 c.changeset_parent = None
315 315 c.changes = []
316 316
317 317 for node in c.changeset.added:
318 318 filenode_old = FileNode(node.path, '')
319 319 if filenode_old.is_binary or node.is_binary:
320 320 diff = _('binary file') + '\n'
321 321 else:
322 322 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
323 323 ignore_whitespace=ignore_whitespace,
324 324 context=line_context)
325 325 diff = diffs.DiffProcessor(f_gitdiff,
326 326 format='gitdiff').raw_diff()
327 327
328 328 cs1 = None
329 329 cs2 = node.changeset.raw_id
330 330 c.changes.append(('added', node, diff, cs1, cs2))
331 331
332 332 for node in c.changeset.changed:
333 333 filenode_old = c.changeset_parent.get_node(node.path)
334 334 if filenode_old.is_binary or node.is_binary:
335 335 diff = _('binary file')
336 336 else:
337 337 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
338 338 ignore_whitespace=ignore_whitespace,
339 339 context=line_context)
340 340 diff = diffs.DiffProcessor(f_gitdiff,
341 341 format='gitdiff').raw_diff()
342 342
343 343 cs1 = filenode_old.changeset.raw_id
344 344 cs2 = node.changeset.raw_id
345 345 c.changes.append(('changed', node, diff, cs1, cs2))
346 346
347 347 response.content_type = 'text/plain'
348 348
349 349 if method == 'download':
350 350 response.content_disposition = 'attachment; filename=%s.patch' \
351 351 % revision
352 352
353 353 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id
354 354 for x in c.changeset.parents])
355 355
356 356 c.diffs = ''
357 357 for x in c.changes:
358 358 c.diffs += x[2]
359 359
360 360 return render('changeset/raw_changeset.html')
361 361
362 362 @jsonify
363 363 def comment(self, repo_name, revision):
364 364 comm = ChangesetCommentsModel().create(
365 365 text=request.POST.get('text'),
366 366 repo_id=c.rhodecode_db_repo.repo_id,
367 367 user_id=c.rhodecode_user.user_id,
368 368 revision=revision,
369 369 f_path=request.POST.get('f_path'),
370 370 line_no=request.POST.get('line')
371 371 )
372 372 Session.commit()
373 373 data = {
374 374 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
375 375 }
376 376 if comm:
377 377 c.co = comm
378 378 data.update(comm.get_dict())
379 data.update({'rendered_text': render('changeset/changeset_comment_block.html')})
379 data.update({'rendered_text':
380 render('changeset/changeset_comment_block.html')})
380 381 return data
381 382
382 383 @jsonify
383 384 def delete_comment(self, repo_name, comment_id):
384 385 co = ChangesetComment.get(comment_id)
385 386 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
386 387 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
387 388 ChangesetCommentsModel().delete(comment=co)
388 389 Session.commit()
389 390 return True
390 391 else:
391 392 raise HTTPForbidden()
@@ -1,2 +1,2 b''
1 1 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
2 ${comment.comment_block(c.co)} No newline at end of file
2 ${comment.comment_block(c.co)}
General Comments 0
You need to be logged in to leave comments. Login now