##// END OF EJS Templates
fixes #217 Seperate Parents on Raw-changeset page
marcink -
r1402:edfbf3ee beta
parent child Browse files
Show More
@@ -1,253 +1,252 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changeset
3 rhodecode.controllers.changeset
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changeset controller for pylons showoing changes beetween
6 changeset controller for pylons showoing changes beetween
7 revisions
7 revisions
8
8
9 :created_on: Apr 25, 2010
9 :created_on: Apr 25, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons import tmpl_context as c, url, request, response
29 from pylons import tmpl_context as c, url, request, response
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect
32
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
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.lib.odict import OrderedDict
37 from rhodecode.lib.odict import OrderedDict
38
38
39 from vcs.exceptions import RepositoryError, ChangesetError, \
39 from vcs.exceptions import RepositoryError, ChangesetError, \
40 ChangesetDoesNotExistError
40 ChangesetDoesNotExistError
41 from vcs.nodes import FileNode
41 from vcs.nodes import FileNode
42 from vcs.utils import diffs as differ
42 from vcs.utils import diffs as differ
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class ChangesetController(BaseRepoController):
47 class ChangesetController(BaseRepoController):
48
48
49 @LoginRequired()
49 @LoginRequired()
50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 'repository.admin')
51 'repository.admin')
52 def __before__(self):
52 def __before__(self):
53 super(ChangesetController, self).__before__()
53 super(ChangesetController, self).__before__()
54 c.affected_files_cut_off = 60
54 c.affected_files_cut_off = 60
55
55
56 def index(self, revision):
56 def index(self, revision):
57
57
58 def wrap_to_table(str):
58 def wrap_to_table(str):
59
59
60 return '''<table class="code-difftable">
60 return '''<table class="code-difftable">
61 <tr class="line">
61 <tr class="line">
62 <td class="lineno new"></td>
62 <td class="lineno new"></td>
63 <td class="code"><pre>%s</pre></td>
63 <td class="code"><pre>%s</pre></td>
64 </tr>
64 </tr>
65 </table>''' % str
65 </table>''' % str
66
66
67 #get ranges of revisions if preset
67 #get ranges of revisions if preset
68 rev_range = revision.split('...')[:2]
68 rev_range = revision.split('...')[:2]
69
69
70 try:
70 try:
71 if len(rev_range) == 2:
71 if len(rev_range) == 2:
72 rev_start = rev_range[0]
72 rev_start = rev_range[0]
73 rev_end = rev_range[1]
73 rev_end = rev_range[1]
74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
75 end=rev_end)
75 end=rev_end)
76 else:
76 else:
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
78
78
79 c.cs_ranges = list(rev_ranges)
79 c.cs_ranges = list(rev_ranges)
80
80
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
82 log.error(traceback.format_exc())
82 log.error(traceback.format_exc())
83 h.flash(str(e), category='warning')
83 h.flash(str(e), category='warning')
84 return redirect(url('home'))
84 return redirect(url('home'))
85
85
86 c.changes = OrderedDict()
86 c.changes = OrderedDict()
87 c.sum_added = 0
87 c.sum_added = 0
88 c.sum_removed = 0
88 c.sum_removed = 0
89 c.lines_added = 0
89 c.lines_added = 0
90 c.lines_deleted = 0
90 c.lines_deleted = 0
91 c.cut_off = False # defines if cut off limit is reached
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 # Iterate over ranges (default changeset view is always one changeset)
94 for changeset in c.cs_ranges:
94 for changeset in c.cs_ranges:
95 c.changes[changeset.raw_id] = []
95 c.changes[changeset.raw_id] = []
96 try:
96 try:
97 changeset_parent = changeset.parents[0]
97 changeset_parent = changeset.parents[0]
98 except IndexError:
98 except IndexError:
99 changeset_parent = None
99 changeset_parent = None
100
100
101 #==================================================================
101 #==================================================================
102 # ADDED FILES
102 # ADDED FILES
103 #==================================================================
103 #==================================================================
104 for node in changeset.added:
104 for node in changeset.added:
105
105
106 filenode_old = FileNode(node.path, '', EmptyChangeset())
106 filenode_old = FileNode(node.path, '', EmptyChangeset())
107 if filenode_old.is_binary or node.is_binary:
107 if filenode_old.is_binary or node.is_binary:
108 diff = wrap_to_table(_('binary file'))
108 diff = wrap_to_table(_('binary file'))
109 st = (0, 0)
109 st = (0, 0)
110 else:
110 else:
111 # in this case node.size is good parameter since those are
111 # in this case node.size is good parameter since those are
112 # added nodes and their size defines how many changes were
112 # added nodes and their size defines how many changes were
113 # made
113 # made
114 c.sum_added += node.size
114 c.sum_added += node.size
115 if c.sum_added < self.cut_off_limit:
115 if c.sum_added < self.cut_off_limit:
116 f_gitdiff = differ.get_gitdiff(filenode_old, node)
116 f_gitdiff = differ.get_gitdiff(filenode_old, node)
117 d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
117 d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
118
118
119 st = d.stat()
119 st = d.stat()
120 diff = d.as_html()
120 diff = d.as_html()
121
121
122 else:
122 else:
123 diff = wrap_to_table(_('Changeset is to big and '
123 diff = wrap_to_table(_('Changeset is to big and '
124 'was cut off, see raw '
124 'was cut off, see raw '
125 'changeset instead'))
125 'changeset instead'))
126 c.cut_off = True
126 c.cut_off = True
127 break
127 break
128
128
129 cs1 = None
129 cs1 = None
130 cs2 = node.last_changeset.raw_id
130 cs2 = node.last_changeset.raw_id
131 c.lines_added += st[0]
131 c.lines_added += st[0]
132 c.lines_deleted += st[1]
132 c.lines_deleted += st[1]
133 c.changes[changeset.raw_id].append(('added', node, diff,
133 c.changes[changeset.raw_id].append(('added', node, diff,
134 cs1, cs2, st))
134 cs1, cs2, st))
135
135
136 #==================================================================
136 #==================================================================
137 # CHANGED FILES
137 # CHANGED FILES
138 #==================================================================
138 #==================================================================
139 if not c.cut_off:
139 if not c.cut_off:
140 for node in changeset.changed:
140 for node in changeset.changed:
141 try:
141 try:
142 filenode_old = changeset_parent.get_node(node.path)
142 filenode_old = changeset_parent.get_node(node.path)
143 except ChangesetError:
143 except ChangesetError:
144 log.warning('Unable to fetch parent node for diff')
144 log.warning('Unable to fetch parent node for diff')
145 filenode_old = FileNode(node.path, '',
145 filenode_old = FileNode(node.path, '',
146 EmptyChangeset())
146 EmptyChangeset())
147
147
148 if filenode_old.is_binary or node.is_binary:
148 if filenode_old.is_binary or node.is_binary:
149 diff = wrap_to_table(_('binary file'))
149 diff = wrap_to_table(_('binary file'))
150 st = (0, 0)
150 st = (0, 0)
151 else:
151 else:
152
152
153 if c.sum_removed < self.cut_off_limit:
153 if c.sum_removed < self.cut_off_limit:
154 f_gitdiff = differ.get_gitdiff(filenode_old, node)
154 f_gitdiff = differ.get_gitdiff(filenode_old, node)
155 d = differ.DiffProcessor(f_gitdiff,
155 d = differ.DiffProcessor(f_gitdiff,
156 format='gitdiff')
156 format='gitdiff')
157 st = d.stat()
157 st = d.stat()
158 if (st[0] + st[1]) * 256 > self.cut_off_limit:
158 if (st[0] + st[1]) * 256 > self.cut_off_limit:
159 diff = wrap_to_table(_('Diff is to big '
159 diff = wrap_to_table(_('Diff is to big '
160 'and was cut off, see '
160 'and was cut off, see '
161 'raw diff instead'))
161 'raw diff instead'))
162 else:
162 else:
163 diff = d.as_html()
163 diff = d.as_html()
164
164
165 if diff:
165 if diff:
166 c.sum_removed += len(diff)
166 c.sum_removed += len(diff)
167 else:
167 else:
168 diff = wrap_to_table(_('Changeset is to big and '
168 diff = wrap_to_table(_('Changeset is to big and '
169 'was cut off, see raw '
169 'was cut off, see raw '
170 'changeset instead'))
170 'changeset instead'))
171 c.cut_off = True
171 c.cut_off = True
172 break
172 break
173
173
174 cs1 = filenode_old.last_changeset.raw_id
174 cs1 = filenode_old.last_changeset.raw_id
175 cs2 = node.last_changeset.raw_id
175 cs2 = node.last_changeset.raw_id
176 c.lines_added += st[0]
176 c.lines_added += st[0]
177 c.lines_deleted += st[1]
177 c.lines_deleted += st[1]
178 c.changes[changeset.raw_id].append(('changed', node, diff,
178 c.changes[changeset.raw_id].append(('changed', node, diff,
179 cs1, cs2, st))
179 cs1, cs2, st))
180
180
181 #==================================================================
181 #==================================================================
182 # REMOVED FILES
182 # REMOVED FILES
183 #==================================================================
183 #==================================================================
184 if not c.cut_off:
184 if not c.cut_off:
185 for node in changeset.removed:
185 for node in changeset.removed:
186 c.changes[changeset.raw_id].append(('removed', node, None,
186 c.changes[changeset.raw_id].append(('removed', node, None,
187 None, None, (0, 0)))
187 None, None, (0, 0)))
188
188
189 if len(c.cs_ranges) == 1:
189 if len(c.cs_ranges) == 1:
190 c.changeset = c.cs_ranges[0]
190 c.changeset = c.cs_ranges[0]
191 c.changes = c.changes[c.changeset.raw_id]
191 c.changes = c.changes[c.changeset.raw_id]
192
192
193 return render('changeset/changeset.html')
193 return render('changeset/changeset.html')
194 else:
194 else:
195 return render('changeset/changeset_range.html')
195 return render('changeset/changeset_range.html')
196
196
197 def raw_changeset(self, revision):
197 def raw_changeset(self, revision):
198
198
199 method = request.GET.get('diff', 'show')
199 method = request.GET.get('diff', 'show')
200 try:
200 try:
201 c.scm_type = c.rhodecode_repo.alias
201 c.scm_type = c.rhodecode_repo.alias
202 c.changeset = c.rhodecode_repo.get_changeset(revision)
202 c.changeset = c.rhodecode_repo.get_changeset(revision)
203 except RepositoryError:
203 except RepositoryError:
204 log.error(traceback.format_exc())
204 log.error(traceback.format_exc())
205 return redirect(url('home'))
205 return redirect(url('home'))
206 else:
206 else:
207 try:
207 try:
208 c.changeset_parent = c.changeset.parents[0]
208 c.changeset_parent = c.changeset.parents[0]
209 except IndexError:
209 except IndexError:
210 c.changeset_parent = None
210 c.changeset_parent = None
211 c.changes = []
211 c.changes = []
212
212
213 for node in c.changeset.added:
213 for node in c.changeset.added:
214 filenode_old = FileNode(node.path, '')
214 filenode_old = FileNode(node.path, '')
215 if filenode_old.is_binary or node.is_binary:
215 if filenode_old.is_binary or node.is_binary:
216 diff = _('binary file') + '\n'
216 diff = _('binary file') + '\n'
217 else:
217 else:
218 f_gitdiff = differ.get_gitdiff(filenode_old, node)
218 f_gitdiff = differ.get_gitdiff(filenode_old, node)
219 diff = differ.DiffProcessor(f_gitdiff,
219 diff = differ.DiffProcessor(f_gitdiff,
220 format='gitdiff').raw_diff()
220 format='gitdiff').raw_diff()
221
221
222 cs1 = None
222 cs1 = None
223 cs2 = node.last_changeset.raw_id
223 cs2 = node.last_changeset.raw_id
224 c.changes.append(('added', node, diff, cs1, cs2))
224 c.changes.append(('added', node, diff, cs1, cs2))
225
225
226 for node in c.changeset.changed:
226 for node in c.changeset.changed:
227 filenode_old = c.changeset_parent.get_node(node.path)
227 filenode_old = c.changeset_parent.get_node(node.path)
228 if filenode_old.is_binary or node.is_binary:
228 if filenode_old.is_binary or node.is_binary:
229 diff = _('binary file')
229 diff = _('binary file')
230 else:
230 else:
231 f_gitdiff = differ.get_gitdiff(filenode_old, node)
231 f_gitdiff = differ.get_gitdiff(filenode_old, node)
232 diff = differ.DiffProcessor(f_gitdiff,
232 diff = differ.DiffProcessor(f_gitdiff,
233 format='gitdiff').raw_diff()
233 format='gitdiff').raw_diff()
234
234
235 cs1 = filenode_old.last_changeset.raw_id
235 cs1 = filenode_old.last_changeset.raw_id
236 cs2 = node.last_changeset.raw_id
236 cs2 = node.last_changeset.raw_id
237 c.changes.append(('changed', node, diff, cs1, cs2))
237 c.changes.append(('changed', node, diff, cs1, cs2))
238
238
239 response.content_type = 'text/plain'
239 response.content_type = 'text/plain'
240
240
241 if method == 'download':
241 if method == 'download':
242 response.content_disposition = 'attachment; filename=%s.patch' \
242 response.content_disposition = 'attachment; filename=%s.patch' \
243 % revision
243 % revision
244
244
245 parent = True if len(c.changeset.parents) > 0 else False
245 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in
246 c.parent_tmpl = 'Parent %s' \
246 c.changeset.parents])
247 % c.changeset.parents[0].raw_id if parent else ''
248
247
249 c.diffs = ''
248 c.diffs = ''
250 for x in c.changes:
249 for x in c.changes:
251 c.diffs += x[2]
250 c.diffs += x[2]
252
251
253 return render('changeset/raw_changeset.html')
252 return render('changeset/raw_changeset.html')
@@ -1,8 +1,8 b''
1 # ${c.scm_type} changeset patch
1 # ${c.scm_type.upper()} changeset patch
2 # User ${c.changeset.author|n}
2 # User ${c.changeset.author|n}
3 # Date ${c.changeset.date}
3 # Date ${c.changeset.date}
4 # Node ID ${c.changeset.raw_id}
4 # Node ID ${c.changeset.raw_id}
5 # ${c.parent_tmpl}
5 ${c.parent_tmpl}
6 ${c.changeset.message}
6 ${c.changeset.message}
7
7
8 ${c.diffs|n} No newline at end of file
8 ${c.diffs|n}
General Comments 0
You need to be logged in to leave comments. Login now