##// END OF EJS Templates
Added extra check for very large diffs in changesets, sometimes for very large diffs the diff parser could kill CPU.
marcink -
r1274:7a0004ef beta
parent child Browse files
Show More
@@ -1,239 +1,254 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) 2009-2011 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
29 29 from pylons import tmpl_context as c, url, request, response
30 30 from pylons.i18n.translation import _
31 31 from pylons.controllers.util import redirect
32 32
33 33 import rhodecode.lib.helpers as h
34 34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 35 from rhodecode.lib.base import BaseRepoController, render
36 36 from rhodecode.lib.utils import EmptyChangeset
37 37
38 38 from vcs.exceptions import RepositoryError, ChangesetError, \
39 39 ChangesetDoesNotExistError
40 40 from vcs.nodes import FileNode
41 41 from vcs.utils import diffs as differ
42 42 from vcs.utils.ordered_dict import OrderedDict
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class ChangesetController(BaseRepoController):
48 48
49 49 @LoginRequired()
50 50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 51 'repository.admin')
52 52 def __before__(self):
53 53 super(ChangesetController, self).__before__()
54 54 c.affected_files_cut_off = 60
55 55
56 56 def index(self, revision):
57 57
58 58 def wrap_to_table(str):
59 59
60 60 return '''<table class="code-difftable">
61 61 <tr class="line">
62 62 <td class="lineno new"></td>
63 63 <td class="code"><pre>%s</pre></td>
64 64 </tr>
65 65 </table>''' % str
66 66
67 67 #get ranges of revisions if preset
68 68 rev_range = revision.split('...')[:2]
69 69
70 70 try:
71 71 if len(rev_range) == 2:
72 72 rev_start = rev_range[0]
73 73 rev_end = rev_range[1]
74 74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
75 75 end=rev_end)
76 76 else:
77 77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
78 78
79 79 c.cs_ranges = list(rev_ranges)
80 80
81 81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
82 82 log.error(traceback.format_exc())
83 83 h.flash(str(e), category='warning')
84 84 return redirect(url('home'))
85 85
86 86 c.changes = OrderedDict()
87 87 c.sum_added = 0
88 88 c.sum_removed = 0
89 89 c.lines_added = 0
90 90 c.lines_deleted = 0
91 c.cut_off = False
91 c.cut_off = False # defines if cut off limit is reached
92 92
93 # Iterate over ranges (default changeset view is always one changeset)
93 94 for changeset in c.cs_ranges:
94 95 c.changes[changeset.raw_id] = []
95 96 try:
96 97 changeset_parent = changeset.parents[0]
97 98 except IndexError:
98 99 changeset_parent = None
99 100
100 101 #==================================================================
101 102 # ADDED FILES
102 103 #==================================================================
103 104 for node in changeset.added:
105
104 106 filenode_old = FileNode(node.path, '', EmptyChangeset())
105 107 if filenode_old.is_binary or node.is_binary:
106 108 diff = wrap_to_table(_('binary file'))
107 109 st = (0, 0)
108 110 else:
111 # in this case node.size is good parameter since those are
112 # added nodes and their size defines how many changes were
113 # made
109 114 c.sum_added += node.size
110 115 if c.sum_added < self.cut_off_limit:
111 116 f_gitdiff = differ.get_gitdiff(filenode_old, node)
112 117 d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
118
119 st = d.stat()
113 120 diff = d.as_html()
114 st = d.stat()
121
115 122 else:
116 123 diff = wrap_to_table(_('Changeset is to big and '
117 124 'was cut off, see raw '
118 125 'changeset instead'))
119 126 c.cut_off = True
120 127 break
121 128
122 129 cs1 = None
123 130 cs2 = node.last_changeset.raw_id
124 131 c.lines_added += st[0]
125 132 c.lines_deleted += st[1]
126 133 c.changes[changeset.raw_id].append(('added', node, diff,
127 134 cs1, cs2, st))
128 135
129 136 #==================================================================
130 137 # CHANGED FILES
131 138 #==================================================================
132 139 if not c.cut_off:
133 140 for node in changeset.changed:
134 141 try:
135 142 filenode_old = changeset_parent.get_node(node.path)
136 143 except ChangesetError:
144 log.warning('Unable to fetch parent node for diff')
137 145 filenode_old = FileNode(node.path, '',
138 146 EmptyChangeset())
139 147
140 148 if filenode_old.is_binary or node.is_binary:
141 149 diff = wrap_to_table(_('binary file'))
142 150 st = (0, 0)
143 151 else:
144 152
145 153 if c.sum_removed < self.cut_off_limit:
146 154 f_gitdiff = differ.get_gitdiff(filenode_old, node)
147 155 d = differ.DiffProcessor(f_gitdiff,
148 156 format='gitdiff')
149 diff = d.as_html()
150 157 st = d.stat()
158 if (st[0] + st[1]) * 256 > self.cut_off_limit:
159 diff = wrap_to_table(_('Diff is to big '
160 'and was cut off, see '
161 'raw diff instead'))
162 else:
163 diff = d.as_html()
164
165
151 166 if diff:
152 167 c.sum_removed += len(diff)
153 168 else:
154 169 diff = wrap_to_table(_('Changeset is to big and '
155 170 'was cut off, see raw '
156 171 'changeset instead'))
157 172 c.cut_off = True
158 173 break
159 174
160 175 cs1 = filenode_old.last_changeset.raw_id
161 176 cs2 = node.last_changeset.raw_id
162 177 c.lines_added += st[0]
163 178 c.lines_deleted += st[1]
164 179 c.changes[changeset.raw_id].append(('changed', node, diff,
165 180 cs1, cs2, st))
166 181
167 182 #==================================================================
168 183 # REMOVED FILES
169 184 #==================================================================
170 185 if not c.cut_off:
171 186 for node in changeset.removed:
172 187 c.changes[changeset.raw_id].append(('removed', node, None,
173 188 None, None, (0, 0)))
174 189
175 190 if len(c.cs_ranges) == 1:
176 191 c.changeset = c.cs_ranges[0]
177 192 c.changes = c.changes[c.changeset.raw_id]
178 193
179 194 return render('changeset/changeset.html')
180 195 else:
181 196 return render('changeset/changeset_range.html')
182 197
183 198 def raw_changeset(self, revision):
184 199
185 200 method = request.GET.get('diff', 'show')
186 201 try:
187 202 c.scm_type = c.rhodecode_repo.alias
188 203 c.changeset = c.rhodecode_repo.get_changeset(revision)
189 204 except RepositoryError:
190 205 log.error(traceback.format_exc())
191 206 return redirect(url('home'))
192 207 else:
193 208 try:
194 209 c.changeset_parent = c.changeset.parents[0]
195 210 except IndexError:
196 211 c.changeset_parent = None
197 212 c.changes = []
198 213
199 214 for node in c.changeset.added:
200 215 filenode_old = FileNode(node.path, '')
201 216 if filenode_old.is_binary or node.is_binary:
202 217 diff = _('binary file') + '\n'
203 218 else:
204 219 f_gitdiff = differ.get_gitdiff(filenode_old, node)
205 220 diff = differ.DiffProcessor(f_gitdiff,
206 221 format='gitdiff').raw_diff()
207 222
208 223 cs1 = None
209 224 cs2 = node.last_changeset.raw_id
210 225 c.changes.append(('added', node, diff, cs1, cs2))
211 226
212 227 for node in c.changeset.changed:
213 228 filenode_old = c.changeset_parent.get_node(node.path)
214 229 if filenode_old.is_binary or node.is_binary:
215 230 diff = _('binary file')
216 231 else:
217 232 f_gitdiff = differ.get_gitdiff(filenode_old, node)
218 233 diff = differ.DiffProcessor(f_gitdiff,
219 234 format='gitdiff').raw_diff()
220 235
221 236 cs1 = filenode_old.last_changeset.raw_id
222 237 cs2 = node.last_changeset.raw_id
223 238 c.changes.append(('changed', node, diff, cs1, cs2))
224 239
225 240 response.content_type = 'text/plain'
226 241
227 242 if method == 'download':
228 243 response.content_disposition = 'attachment; filename=%s.patch' \
229 244 % revision
230 245
231 246 parent = True if len(c.changeset.parents) > 0 else False
232 247 c.parent_tmpl = 'Parent %s' \
233 248 % c.changeset.parents[0].raw_id if parent else ''
234 249
235 250 c.diffs = ''
236 251 for x in c.changes:
237 252 c.diffs += x[2]
238 253
239 254 return render('changeset/raw_changeset.html')
General Comments 0
You need to be logged in to leave comments. Login now