##// END OF EJS Templates
compare: single file mode will now show start and end commit range for this particular files instead of the last commit
marcink -
r3711:6a5b530d new-ui
parent child Browse files
Show More
@@ -1,317 +1,317 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2019 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 from rhodecode.apps._base import RepoAppView
30 30
31 31 from rhodecode.lib import helpers as h
32 32 from rhodecode.lib import diffs, codeblocks
33 33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 34 from rhodecode.lib.utils import safe_str
35 35 from rhodecode.lib.utils2 import safe_unicode, str2bool
36 36 from rhodecode.lib.view_utils import parse_path_ref, get_commit_from_ref_name
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 c.rhodecode_repo = self.rhodecode_vcs_repo
49 49 return c
50 50
51 51 def _get_commit_or_redirect(
52 52 self, ref, ref_type, repo, redirect_after=True, partial=False):
53 53 """
54 54 This is a safe way to get a commit. If an error occurs it
55 55 redirects to a commit with a proper message. If partial is set
56 56 then it does not do redirect raise and throws an exception instead.
57 57 """
58 58 _ = self.request.translate
59 59 try:
60 60 return get_commit_from_ref_name(repo, safe_str(ref), ref_type)
61 61 except EmptyRepositoryError:
62 62 if not redirect_after:
63 63 return repo.scm_instance().EMPTY_COMMIT
64 64 h.flash(h.literal(_('There are no commits yet')),
65 65 category='warning')
66 66 if not partial:
67 67 raise HTTPFound(
68 68 h.route_path('repo_summary', repo_name=repo.repo_name))
69 69 raise HTTPBadRequest()
70 70
71 71 except RepositoryError as e:
72 72 log.exception(safe_str(e))
73 73 h.flash(safe_str(h.escape(e)), category='warning')
74 74 if not partial:
75 75 raise HTTPFound(
76 76 h.route_path('repo_summary', repo_name=repo.repo_name))
77 77 raise HTTPBadRequest()
78 78
79 79 @LoginRequired()
80 80 @HasRepoPermissionAnyDecorator(
81 81 'repository.read', 'repository.write', 'repository.admin')
82 82 @view_config(
83 83 route_name='repo_compare_select', request_method='GET',
84 84 renderer='rhodecode:templates/compare/compare_diff.mako')
85 85 def compare_select(self):
86 86 _ = self.request.translate
87 87 c = self.load_default_context()
88 88
89 89 source_repo = self.db_repo_name
90 90 target_repo = self.request.GET.get('target_repo', source_repo)
91 91 c.source_repo = Repository.get_by_repo_name(source_repo)
92 92 c.target_repo = Repository.get_by_repo_name(target_repo)
93 93
94 94 if c.source_repo is None or c.target_repo is None:
95 95 raise HTTPNotFound()
96 96
97 97 c.compare_home = True
98 98 c.commit_ranges = []
99 99 c.collapse_all_commits = False
100 100 c.diffset = None
101 101 c.limited_diff = False
102 102 c.source_ref = c.target_ref = _('Select commit')
103 103 c.source_ref_type = ""
104 104 c.target_ref_type = ""
105 105 c.commit_statuses = ChangesetStatus.STATUSES
106 106 c.preview_mode = False
107 107 c.file_path = None
108 108
109 109 return self._get_template_context(c)
110 110
111 111 @LoginRequired()
112 112 @HasRepoPermissionAnyDecorator(
113 113 'repository.read', 'repository.write', 'repository.admin')
114 114 @view_config(
115 115 route_name='repo_compare', request_method='GET',
116 116 renderer=None)
117 117 def compare(self):
118 118 _ = self.request.translate
119 119 c = self.load_default_context()
120 120
121 121 source_ref_type = self.request.matchdict['source_ref_type']
122 122 source_ref = self.request.matchdict['source_ref']
123 123 target_ref_type = self.request.matchdict['target_ref_type']
124 124 target_ref = self.request.matchdict['target_ref']
125 125
126 126 # source_ref will be evaluated in source_repo
127 127 source_repo_name = self.db_repo_name
128 128 source_path, source_id = parse_path_ref(source_ref)
129 129
130 130 # target_ref will be evaluated in target_repo
131 131 target_repo_name = self.request.GET.get('target_repo', source_repo_name)
132 132 target_path, target_id = parse_path_ref(
133 133 target_ref, default_path=self.request.GET.get('f_path', ''))
134 134
135 135 # if merge is True
136 136 # Show what changes since the shared ancestor commit of target/source
137 137 # the source would get if it was merged with target. Only commits
138 138 # which are in target but not in source will be shown.
139 139 merge = str2bool(self.request.GET.get('merge'))
140 140 # if merge is False
141 141 # Show a raw diff of source/target refs even if no ancestor exists
142 142
143 143 # c.fulldiff disables cut_off_limit
144 144 c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
145 145
146 146 # fetch global flags of ignore ws or context lines
147 147 diff_context = diffs.get_diff_context(self.request)
148 148 hide_whitespace_changes = diffs.get_diff_whitespace_flag(self.request)
149 149
150 150 c.file_path = target_path
151 151 c.commit_statuses = ChangesetStatus.STATUSES
152 152
153 153 # if partial, returns just compare_commits.html (commits log)
154 154 partial = self.request.is_xhr
155 155
156 156 # swap url for compare_diff page
157 157 c.swap_url = h.route_path(
158 158 'repo_compare',
159 159 repo_name=target_repo_name,
160 160 source_ref_type=target_ref_type,
161 161 source_ref=target_ref,
162 162 target_repo=source_repo_name,
163 163 target_ref_type=source_ref_type,
164 164 target_ref=source_ref,
165 165 _query=dict(merge=merge and '1' or '', f_path=target_path))
166 166
167 167 source_repo = Repository.get_by_repo_name(source_repo_name)
168 168 target_repo = Repository.get_by_repo_name(target_repo_name)
169 169
170 170 if source_repo is None:
171 171 log.error('Could not find the source repo: {}'
172 172 .format(source_repo_name))
173 173 h.flash(_('Could not find the source repo: `{}`')
174 174 .format(h.escape(source_repo_name)), category='error')
175 175 raise HTTPFound(
176 176 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
177 177
178 178 if target_repo is None:
179 179 log.error('Could not find the target repo: {}'
180 180 .format(source_repo_name))
181 181 h.flash(_('Could not find the target repo: `{}`')
182 182 .format(h.escape(target_repo_name)), category='error')
183 183 raise HTTPFound(
184 184 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
185 185
186 186 source_scm = source_repo.scm_instance()
187 187 target_scm = target_repo.scm_instance()
188 188
189 189 source_alias = source_scm.alias
190 190 target_alias = target_scm.alias
191 191 if source_alias != target_alias:
192 192 msg = _('The comparison of two different kinds of remote repos '
193 193 'is not available')
194 194 log.error(msg)
195 195 h.flash(msg, category='error')
196 196 raise HTTPFound(
197 197 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
198 198
199 199 source_commit = self._get_commit_or_redirect(
200 200 ref=source_id, ref_type=source_ref_type, repo=source_repo,
201 201 partial=partial)
202 202 target_commit = self._get_commit_or_redirect(
203 203 ref=target_id, ref_type=target_ref_type, repo=target_repo,
204 204 partial=partial)
205 205
206 206 c.compare_home = False
207 207 c.source_repo = source_repo
208 208 c.target_repo = target_repo
209 209 c.source_ref = source_ref
210 210 c.target_ref = target_ref
211 211 c.source_ref_type = source_ref_type
212 212 c.target_ref_type = target_ref_type
213 213
214 214 pre_load = ["author", "branch", "date", "message"]
215 215 c.ancestor = None
216 216
217 217 if c.file_path:
218 218 if source_commit == target_commit:
219 219 c.commit_ranges = []
220 220 else:
221 c.commit_ranges = [target_commit]
221 c.commit_ranges = [source_commit, target_commit]
222 222 else:
223 223 try:
224 224 c.commit_ranges = source_scm.compare(
225 225 source_commit.raw_id, target_commit.raw_id,
226 226 target_scm, merge, pre_load=pre_load)
227 227 if merge:
228 228 c.ancestor = source_scm.get_common_ancestor(
229 229 source_commit.raw_id, target_commit.raw_id, target_scm)
230 230 except RepositoryRequirementError:
231 231 msg = _('Could not compare repos with different '
232 232 'large file settings')
233 233 log.error(msg)
234 234 if partial:
235 235 return Response(msg)
236 236 h.flash(msg, category='error')
237 237 raise HTTPFound(
238 238 h.route_path('repo_compare_select',
239 239 repo_name=self.db_repo_name))
240 240
241 241 c.statuses = self.db_repo.statuses(
242 242 [x.raw_id for x in c.commit_ranges])
243 243
244 244 # auto collapse if we have more than limit
245 245 collapse_limit = diffs.DiffProcessor._collapse_commits_over
246 246 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
247 247
248 248 if partial: # for PR ajax commits loader
249 249 if not c.ancestor:
250 250 return Response('') # cannot merge if there is no ancestor
251 251
252 252 html = render(
253 253 'rhodecode:templates/compare/compare_commits.mako',
254 254 self._get_template_context(c), self.request)
255 255 return Response(html)
256 256
257 257 if c.ancestor:
258 258 # case we want a simple diff without incoming commits,
259 259 # previewing what will be merged.
260 260 # Make the diff on target repo (which is known to have target_ref)
261 261 log.debug('Using ancestor %s as source_ref instead of %s',
262 262 c.ancestor, source_ref)
263 263 source_repo = target_repo
264 264 source_commit = target_repo.get_commit(commit_id=c.ancestor)
265 265
266 266 # diff_limit will cut off the whole diff if the limit is applied
267 267 # otherwise it will just hide the big files from the front-end
268 268 diff_limit = c.visual.cut_off_limit_diff
269 269 file_limit = c.visual.cut_off_limit_file
270 270
271 271 log.debug('calculating diff between '
272 272 'source_ref:%s and target_ref:%s for repo `%s`',
273 273 source_commit, target_commit,
274 274 safe_unicode(source_repo.scm_instance().path))
275 275
276 276 if source_commit.repository != target_commit.repository:
277 277 msg = _(
278 278 "Repositories unrelated. "
279 279 "Cannot compare commit %(commit1)s from repository %(repo1)s "
280 280 "with commit %(commit2)s from repository %(repo2)s.") % {
281 281 'commit1': h.show_id(source_commit),
282 282 'repo1': source_repo.repo_name,
283 283 'commit2': h.show_id(target_commit),
284 284 'repo2': target_repo.repo_name,
285 285 }
286 286 h.flash(msg, category='error')
287 287 raise HTTPFound(
288 288 h.route_path('repo_compare_select',
289 289 repo_name=self.db_repo_name))
290 290
291 291 txt_diff = source_repo.scm_instance().get_diff(
292 292 commit1=source_commit, commit2=target_commit,
293 293 path=target_path, path1=source_path,
294 294 ignore_whitespace=hide_whitespace_changes, context=diff_context)
295 295
296 296 diff_processor = diffs.DiffProcessor(
297 297 txt_diff, format='newdiff', diff_limit=diff_limit,
298 298 file_limit=file_limit, show_full_diff=c.fulldiff)
299 299 _parsed = diff_processor.prepare()
300 300
301 301 diffset = codeblocks.DiffSet(
302 302 repo_name=source_repo.repo_name,
303 303 source_node_getter=codeblocks.diffset_node_getter(source_commit),
304 304 target_repo_name=self.db_repo_name,
305 305 target_node_getter=codeblocks.diffset_node_getter(target_commit),
306 306 )
307 307 c.diffset = self.path_filter.render_patchset_filtered(
308 308 diffset, _parsed, source_ref, target_ref)
309 309
310 310 c.preview_mode = merge
311 311 c.source_commit = source_commit
312 312 c.target_commit = target_commit
313 313
314 314 html = render(
315 315 'rhodecode:templates/compare/compare_diff.mako',
316 316 self._get_template_context(c), self.request)
317 317 return Response(html) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now