##// END OF EJS Templates
compare: make sure to not do any redirects for XHR requests types....
marcink -
r2050:e9bc65ad default
parent child Browse files
Show More
@@ -1,323 +1,325 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import logging
23 23
24 24 from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPFound
25 25 from pyramid.view import view_config
26 26 from pyramid.renderers import render
27 27 from pyramid.response import Response
28 28
29 29
30 30 from rhodecode.apps._base import RepoAppView
31 31 from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name
32 32 from rhodecode.lib import helpers as h
33 33 from rhodecode.lib import diffs, codeblocks
34 34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 35 from rhodecode.lib.utils import safe_str
36 36 from rhodecode.lib.utils2 import safe_unicode, str2bool
37 37 from rhodecode.lib.vcs.exceptions import (
38 38 EmptyRepositoryError, RepositoryError, RepositoryRequirementError,
39 39 NodeDoesNotExistError)
40 40 from rhodecode.model.db import Repository, ChangesetStatus
41 41
42 42 log = logging.getLogger(__name__)
43 43
44 44
45 45 class RepoCompareView(RepoAppView):
46 46 def load_default_context(self):
47 47 c = self._get_local_tmpl_context(include_app_defaults=True)
48 48
49 49 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
50 50 c.repo_info = self.db_repo
51 51 c.rhodecode_repo = self.rhodecode_vcs_repo
52 52
53 53 self._register_global_c(c)
54 54 return c
55 55
56 56 def _get_commit_or_redirect(
57 57 self, ref, ref_type, repo, redirect_after=True, partial=False):
58 58 """
59 59 This is a safe way to get a commit. If an error occurs it
60 60 redirects to a commit with a proper message. If partial is set
61 61 then it does not do redirect raise and throws an exception instead.
62 62 """
63 63 _ = self.request.translate
64 64 try:
65 65 return get_commit_from_ref_name(repo, safe_str(ref), ref_type)
66 66 except EmptyRepositoryError:
67 67 if not redirect_after:
68 68 return repo.scm_instance().EMPTY_COMMIT
69 69 h.flash(h.literal(_('There are no commits yet')),
70 70 category='warning')
71 raise HTTPFound(
72 h.route_path('repo_summary', repo_name=repo.repo_name))
71 if not partial:
72 raise HTTPFound(
73 h.route_path('repo_summary', repo_name=repo.repo_name))
74 raise HTTPBadRequest()
73 75
74 76 except RepositoryError as e:
75 77 log.exception(safe_str(e))
76 78 h.flash(safe_str(h.escape(e)), category='warning')
77 79 if not partial:
78 80 raise HTTPFound(
79 81 h.route_path('repo_summary', repo_name=repo.repo_name))
80 82 raise HTTPBadRequest()
81 83
82 84 @LoginRequired()
83 85 @HasRepoPermissionAnyDecorator(
84 86 'repository.read', 'repository.write', 'repository.admin')
85 87 @view_config(
86 88 route_name='repo_compare_select', request_method='GET',
87 89 renderer='rhodecode:templates/compare/compare_diff.mako')
88 90 def compare_select(self):
89 91 _ = self.request.translate
90 92 c = self.load_default_context()
91 93
92 94 source_repo = self.db_repo_name
93 95 target_repo = self.request.GET.get('target_repo', source_repo)
94 96 c.source_repo = Repository.get_by_repo_name(source_repo)
95 97 c.target_repo = Repository.get_by_repo_name(target_repo)
96 98
97 99 if c.source_repo is None or c.target_repo is None:
98 100 raise HTTPNotFound()
99 101
100 102 c.compare_home = True
101 103 c.commit_ranges = []
102 104 c.collapse_all_commits = False
103 105 c.diffset = None
104 106 c.limited_diff = False
105 107 c.source_ref = c.target_ref = _('Select commit')
106 108 c.source_ref_type = ""
107 109 c.target_ref_type = ""
108 110 c.commit_statuses = ChangesetStatus.STATUSES
109 111 c.preview_mode = False
110 112 c.file_path = None
111 113
112 114 return self._get_template_context(c)
113 115
114 116 @LoginRequired()
115 117 @HasRepoPermissionAnyDecorator(
116 118 'repository.read', 'repository.write', 'repository.admin')
117 119 @view_config(
118 120 route_name='repo_compare', request_method='GET',
119 121 renderer=None)
120 122 def compare(self):
121 123 _ = self.request.translate
122 124 c = self.load_default_context()
123 125
124 126 source_ref_type = self.request.matchdict['source_ref_type']
125 127 source_ref = self.request.matchdict['source_ref']
126 128 target_ref_type = self.request.matchdict['target_ref_type']
127 129 target_ref = self.request.matchdict['target_ref']
128 130
129 131 # source_ref will be evaluated in source_repo
130 132 source_repo_name = self.db_repo_name
131 133 source_path, source_id = parse_path_ref(source_ref)
132 134
133 135 # target_ref will be evaluated in target_repo
134 136 target_repo_name = self.request.GET.get('target_repo', source_repo_name)
135 137 target_path, target_id = parse_path_ref(
136 138 target_ref, default_path=self.request.GET.get('f_path', ''))
137 139
138 140 # if merge is True
139 141 # Show what changes since the shared ancestor commit of target/source
140 142 # the source would get if it was merged with target. Only commits
141 143 # which are in target but not in source will be shown.
142 144 merge = str2bool(self.request.GET.get('merge'))
143 145 # if merge is False
144 146 # Show a raw diff of source/target refs even if no ancestor exists
145 147
146 148 # c.fulldiff disables cut_off_limit
147 149 c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
148 150
149 151 c.file_path = target_path
150 152 c.commit_statuses = ChangesetStatus.STATUSES
151 153
152 154 # if partial, returns just compare_commits.html (commits log)
153 155 partial = self.request.is_xhr
154 156
155 157 # swap url for compare_diff page
156 158 c.swap_url = h.route_path(
157 159 'repo_compare',
158 160 repo_name=target_repo_name,
159 161 source_ref_type=target_ref_type,
160 162 source_ref=target_ref,
161 163 target_repo=source_repo_name,
162 164 target_ref_type=source_ref_type,
163 165 target_ref=source_ref,
164 166 _query=dict(merge=merge and '1' or '', f_path=target_path))
165 167
166 168 source_repo = Repository.get_by_repo_name(source_repo_name)
167 169 target_repo = Repository.get_by_repo_name(target_repo_name)
168 170
169 171 if source_repo is None:
170 172 log.error('Could not find the source repo: {}'
171 173 .format(source_repo_name))
172 174 h.flash(_('Could not find the source repo: `{}`')
173 175 .format(h.escape(source_repo_name)), category='error')
174 176 raise HTTPFound(
175 177 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
176 178
177 179 if target_repo is None:
178 180 log.error('Could not find the target repo: {}'
179 181 .format(source_repo_name))
180 182 h.flash(_('Could not find the target repo: `{}`')
181 183 .format(h.escape(target_repo_name)), category='error')
182 184 raise HTTPFound(
183 185 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
184 186
185 187 source_scm = source_repo.scm_instance()
186 188 target_scm = target_repo.scm_instance()
187 189
188 190 source_alias = source_scm.alias
189 191 target_alias = target_scm.alias
190 192 if source_alias != target_alias:
191 193 msg = _('The comparison of two different kinds of remote repos '
192 194 'is not available')
193 195 log.error(msg)
194 196 h.flash(msg, category='error')
195 197 raise HTTPFound(
196 198 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
197 199
198 200 source_commit = self._get_commit_or_redirect(
199 201 ref=source_id, ref_type=source_ref_type, repo=source_repo,
200 202 partial=partial)
201 203 target_commit = self._get_commit_or_redirect(
202 204 ref=target_id, ref_type=target_ref_type, repo=target_repo,
203 205 partial=partial)
204 206
205 207 c.compare_home = False
206 208 c.source_repo = source_repo
207 209 c.target_repo = target_repo
208 210 c.source_ref = source_ref
209 211 c.target_ref = target_ref
210 212 c.source_ref_type = source_ref_type
211 213 c.target_ref_type = target_ref_type
212 214
213 215 pre_load = ["author", "branch", "date", "message"]
214 216 c.ancestor = None
215 217
216 218 if c.file_path:
217 219 if source_commit == target_commit:
218 220 c.commit_ranges = []
219 221 else:
220 222 c.commit_ranges = [target_commit]
221 223 else:
222 224 try:
223 225 c.commit_ranges = source_scm.compare(
224 226 source_commit.raw_id, target_commit.raw_id,
225 227 target_scm, merge, pre_load=pre_load)
226 228 if merge:
227 229 c.ancestor = source_scm.get_common_ancestor(
228 230 source_commit.raw_id, target_commit.raw_id, target_scm)
229 231 except RepositoryRequirementError:
230 232 msg = _('Could not compare repos with different '
231 233 'large file settings')
232 234 log.error(msg)
233 235 if partial:
234 236 return Response(msg)
235 237 h.flash(msg, category='error')
236 238 raise HTTPFound(
237 239 h.route_path('repo_compare_select',
238 240 repo_name=self.db_repo_name))
239 241
240 242 c.statuses = self.db_repo.statuses(
241 243 [x.raw_id for x in c.commit_ranges])
242 244
243 245 # auto collapse if we have more than limit
244 246 collapse_limit = diffs.DiffProcessor._collapse_commits_over
245 247 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
246 248
247 249 if partial: # for PR ajax commits loader
248 250 if not c.ancestor:
249 251 return Response('') # cannot merge if there is no ancestor
250 252
251 253 html = render(
252 254 'rhodecode:templates/compare/compare_commits.mako',
253 255 self._get_template_context(c), self.request)
254 256 return Response(html)
255 257
256 258 if c.ancestor:
257 259 # case we want a simple diff without incoming commits,
258 260 # previewing what will be merged.
259 261 # Make the diff on target repo (which is known to have target_ref)
260 262 log.debug('Using ancestor %s as source_ref instead of %s'
261 263 % (c.ancestor, source_ref))
262 264 source_repo = target_repo
263 265 source_commit = target_repo.get_commit(commit_id=c.ancestor)
264 266
265 267 # diff_limit will cut off the whole diff if the limit is applied
266 268 # otherwise it will just hide the big files from the front-end
267 269 diff_limit = c.visual.cut_off_limit_diff
268 270 file_limit = c.visual.cut_off_limit_file
269 271
270 272 log.debug('calculating diff between '
271 273 'source_ref:%s and target_ref:%s for repo `%s`',
272 274 source_commit, target_commit,
273 275 safe_unicode(source_repo.scm_instance().path))
274 276
275 277 if source_commit.repository != target_commit.repository:
276 278 msg = _(
277 279 "Repositories unrelated. "
278 280 "Cannot compare commit %(commit1)s from repository %(repo1)s "
279 281 "with commit %(commit2)s from repository %(repo2)s.") % {
280 282 'commit1': h.show_id(source_commit),
281 283 'repo1': source_repo.repo_name,
282 284 'commit2': h.show_id(target_commit),
283 285 'repo2': target_repo.repo_name,
284 286 }
285 287 h.flash(msg, category='error')
286 288 raise HTTPFound(
287 289 h.route_path('repo_compare_select',
288 290 repo_name=self.db_repo_name))
289 291
290 292 txt_diff = source_repo.scm_instance().get_diff(
291 293 commit1=source_commit, commit2=target_commit,
292 294 path=target_path, path1=source_path)
293 295
294 296 diff_processor = diffs.DiffProcessor(
295 297 txt_diff, format='newdiff', diff_limit=diff_limit,
296 298 file_limit=file_limit, show_full_diff=c.fulldiff)
297 299 _parsed = diff_processor.prepare()
298 300
299 301 def _node_getter(commit):
300 302 """ Returns a function that returns a node for a commit or None """
301 303 def get_node(fname):
302 304 try:
303 305 return commit.get_node(fname)
304 306 except NodeDoesNotExistError:
305 307 return None
306 308 return get_node
307 309
308 310 diffset = codeblocks.DiffSet(
309 311 repo_name=source_repo.repo_name,
310 312 source_node_getter=_node_getter(source_commit),
311 313 target_node_getter=_node_getter(target_commit),
312 314 )
313 315 c.diffset = diffset.render_patchset(
314 316 _parsed, source_ref, target_ref)
315 317
316 318 c.preview_mode = merge
317 319 c.source_commit = source_commit
318 320 c.target_commit = target_commit
319 321
320 322 html = render(
321 323 'rhodecode:templates/compare/compare_diff.mako',
322 324 self._get_template_context(c), self.request)
323 325 return Response(html) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now