##// END OF EJS Templates
move the existing changeset checks bellow other checks else it can throw exceptions for non...
marcink -
r3615:50927aed beta
parent child Browse files
Show More
@@ -1,188 +1,188 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.compare
3 rhodecode.controllers.compare
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 compare controller for pylons showing differences between two
6 compare controller for pylons showing differences between two
7 repos, branches, bookmarks or tips
7 repos, branches, bookmarks or tips
8
8
9 :created_on: May 6, 2012
9 :created_on: May 6, 2012
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 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 webob.exc import HTTPNotFound
29 from webob.exc import HTTPNotFound
30 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, session, tmpl_context as c, url
31 from pylons.controllers.util import abort, redirect
31 from pylons.controllers.util import abort, redirect
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
34 from rhodecode.lib.vcs.exceptions import EmptyRepositoryError, RepositoryError
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib import diffs
38 from rhodecode.lib import diffs
39
39
40 from rhodecode.model.db import Repository
40 from rhodecode.model.db import Repository
41 from rhodecode.model.pull_request import PullRequestModel
41 from rhodecode.model.pull_request import PullRequestModel
42 from webob.exc import HTTPBadRequest
42 from webob.exc import HTTPBadRequest
43 from rhodecode.lib.diffs import LimitedDiffContainer
43 from rhodecode.lib.diffs import LimitedDiffContainer
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class CompareController(BaseRepoController):
49 class CompareController(BaseRepoController):
50
50
51 @LoginRequired()
51 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
53 'repository.admin')
54 def __before__(self):
54 def __before__(self):
55 super(CompareController, self).__before__()
55 super(CompareController, self).__before__()
56
56
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
58 partial=False):
58 partial=False):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to changeset with
60 Safe way to get changeset if error occur it redirects to changeset with
61 proper message. If partial is set then don't do redirect raise Exception
61 proper message. If partial is set then don't do redirect raise Exception
62 instead
62 instead
63
63
64 :param rev: revision to fetch
64 :param rev: revision to fetch
65 :param repo: repo instance
65 :param repo: repo instance
66 """
66 """
67
67
68 try:
68 try:
69 type_, rev = rev
69 type_, rev = rev
70 return repo.scm_instance.get_changeset(rev)
70 return repo.scm_instance.get_changeset(rev)
71 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
72 if not redirect_after:
72 if not redirect_after:
73 return None
73 return None
74 h.flash(h.literal(_('There are no changesets yet')),
74 h.flash(h.literal(_('There are no changesets yet')),
75 category='warning')
75 category='warning')
76 redirect(url('summary_home', repo_name=repo.repo_name))
76 redirect(url('summary_home', repo_name=repo.repo_name))
77
77
78 except RepositoryError, e:
78 except RepositoryError, e:
79 log.error(traceback.format_exc())
79 log.error(traceback.format_exc())
80 h.flash(str(e), category='warning')
80 h.flash(str(e), category='warning')
81 if not partial:
81 if not partial:
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
83 raise HTTPBadRequest()
83 raise HTTPBadRequest()
84
84
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
85 def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
86 # org_ref will be evaluated in org_repo
86 # org_ref will be evaluated in org_repo
87 org_repo = c.rhodecode_db_repo.repo_name
87 org_repo = c.rhodecode_db_repo.repo_name
88 org_ref = (org_ref_type, org_ref)
88 org_ref = (org_ref_type, org_ref)
89 # other_ref will be evaluated in other_repo
89 # other_ref will be evaluated in other_repo
90 other_ref = (other_ref_type, other_ref)
90 other_ref = (other_ref_type, other_ref)
91 other_repo = request.GET.get('other_repo', org_repo)
91 other_repo = request.GET.get('other_repo', org_repo)
92 # If merge is True:
92 # If merge is True:
93 # Show what org would get if merged with other:
93 # Show what org would get if merged with other:
94 # List changesets that are ancestors of other but not of org.
94 # List changesets that are ancestors of other but not of org.
95 # New changesets in org is thus ignored.
95 # New changesets in org is thus ignored.
96 # Diff will be from common ancestor, and merges of org to other will thus be ignored.
96 # Diff will be from common ancestor, and merges of org to other will thus be ignored.
97 # If merge is False:
97 # If merge is False:
98 # Make a raw diff from org to other, no matter if related or not.
98 # Make a raw diff from org to other, no matter if related or not.
99 # Changesets in one and not in the other will be ignored
99 # Changesets in one and not in the other will be ignored
100 merge = bool(request.GET.get('merge'))
100 merge = bool(request.GET.get('merge'))
101 # fulldiff disables cut_off_limit
101 # fulldiff disables cut_off_limit
102 c.fulldiff = request.GET.get('fulldiff')
102 c.fulldiff = request.GET.get('fulldiff')
103 # partial uses compare_cs.html template directly
103 # partial uses compare_cs.html template directly
104 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
104 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
105 # as_form puts hidden input field with changeset revisions
105 # as_form puts hidden input field with changeset revisions
106 c.as_form = partial and request.GET.get('as_form')
106 c.as_form = partial and request.GET.get('as_form')
107 # swap url for compare_diff page - never partial and never as_form
107 # swap url for compare_diff page - never partial and never as_form
108 c.swap_url = h.url('compare_url',
108 c.swap_url = h.url('compare_url',
109 repo_name=other_repo,
109 repo_name=other_repo,
110 org_ref_type=other_ref[0], org_ref=other_ref[1],
110 org_ref_type=other_ref[0], org_ref=other_ref[1],
111 other_repo=org_repo,
111 other_repo=org_repo,
112 other_ref_type=org_ref[0], other_ref=org_ref[1],
112 other_ref_type=org_ref[0], other_ref=org_ref[1],
113 merge=merge or '')
113 merge=merge or '')
114
114
115 org_repo = Repository.get_by_repo_name(org_repo)
115 org_repo = Repository.get_by_repo_name(org_repo)
116 other_repo = Repository.get_by_repo_name(other_repo)
116 other_repo = Repository.get_by_repo_name(other_repo)
117
117
118 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
119 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
120
121 if org_repo is None:
118 if org_repo is None:
122 log.error('Could not find org repo %s' % org_repo)
119 log.error('Could not find org repo %s' % org_repo)
123 raise HTTPNotFound
120 raise HTTPNotFound
124 if other_repo is None:
121 if other_repo is None:
125 log.error('Could not find other repo %s' % other_repo)
122 log.error('Could not find other repo %s' % other_repo)
126 raise HTTPNotFound
123 raise HTTPNotFound
127
124
128 if org_repo != other_repo and h.is_git(org_repo):
125 if org_repo != other_repo and h.is_git(org_repo):
129 log.error('compare of two remote repos not available for GIT REPOS')
126 log.error('compare of two remote repos not available for GIT REPOS')
130 raise HTTPNotFound
127 raise HTTPNotFound
131
128
132 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
129 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
133 log.error('compare of two different kind of remote repos not available')
130 log.error('compare of two different kind of remote repos not available')
134 raise HTTPNotFound
131 raise HTTPNotFound
135
132
133 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
134 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
135
136 c.org_repo = org_repo
136 c.org_repo = org_repo
137 c.other_repo = other_repo
137 c.other_repo = other_repo
138 c.org_ref = org_ref[1]
138 c.org_ref = org_ref[1]
139 c.other_ref = other_ref[1]
139 c.other_ref = other_ref[1]
140 c.org_ref_type = org_ref[0]
140 c.org_ref_type = org_ref[0]
141 c.other_ref_type = other_ref[0]
141 c.other_ref_type = other_ref[0]
142
142
143 c.cs_ranges, c.ancestor = PullRequestModel().get_compare_data(
143 c.cs_ranges, c.ancestor = PullRequestModel().get_compare_data(
144 org_repo, org_ref, other_repo, other_ref, merge)
144 org_repo, org_ref, other_repo, other_ref, merge)
145
145
146 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
146 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
147 c.cs_ranges])
147 c.cs_ranges])
148 if partial:
148 if partial:
149 assert c.ancestor
149 assert c.ancestor
150 return render('compare/compare_cs.html')
150 return render('compare/compare_cs.html')
151
151
152 if c.ancestor:
152 if c.ancestor:
153 assert merge
153 assert merge
154 # case we want a simple diff without incoming changesets,
154 # case we want a simple diff without incoming changesets,
155 # previewing what will be merged.
155 # previewing what will be merged.
156 # Make the diff on the other repo (which is known to have other_ref)
156 # Make the diff on the other repo (which is known to have other_ref)
157 log.debug('Using ancestor %s as org_ref instead of %s'
157 log.debug('Using ancestor %s as org_ref instead of %s'
158 % (c.ancestor, org_ref))
158 % (c.ancestor, org_ref))
159 org_ref = ('rev', c.ancestor)
159 org_ref = ('rev', c.ancestor)
160 org_repo = other_repo
160 org_repo = other_repo
161
161
162 diff_limit = self.cut_off_limit if not c.fulldiff else None
162 diff_limit = self.cut_off_limit if not c.fulldiff else None
163
163
164 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
164 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
165
165
166 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
166 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
167 diff_limit=diff_limit)
167 diff_limit=diff_limit)
168 _parsed = diff_processor.prepare()
168 _parsed = diff_processor.prepare()
169
169
170 c.limited_diff = False
170 c.limited_diff = False
171 if isinstance(_parsed, LimitedDiffContainer):
171 if isinstance(_parsed, LimitedDiffContainer):
172 c.limited_diff = True
172 c.limited_diff = True
173
173
174 c.files = []
174 c.files = []
175 c.changes = {}
175 c.changes = {}
176 c.lines_added = 0
176 c.lines_added = 0
177 c.lines_deleted = 0
177 c.lines_deleted = 0
178 for f in _parsed:
178 for f in _parsed:
179 st = f['stats']
179 st = f['stats']
180 if st[0] != 'b':
180 if st[0] != 'b':
181 c.lines_added += st[0]
181 c.lines_added += st[0]
182 c.lines_deleted += st[1]
182 c.lines_deleted += st[1]
183 fid = h.FID('', f['filename'])
183 fid = h.FID('', f['filename'])
184 c.files.append([fid, f['operation'], f['filename'], f['stats']])
184 c.files.append([fid, f['operation'], f['filename'], f['stats']])
185 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
185 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
186 c.changes[fid] = [f['operation'], f['filename'], diff]
186 c.changes[fid] = [f['operation'], f['filename'], diff]
187
187
188 return render('compare/compare_diff.html')
188 return render('compare/compare_diff.html')
General Comments 0
You need to be logged in to leave comments. Login now