##// END OF EJS Templates
rev_start for compare should use parents only if there are present
marcink -
r3386:934f1fd5 beta
parent child Browse files
Show More
@@ -1,191 +1,192
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
45
45 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
46
47
47
48
48 class CompareController(BaseRepoController):
49 class CompareController(BaseRepoController):
49
50
50 @LoginRequired()
51 @LoginRequired()
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 'repository.admin')
53 'repository.admin')
53 def __before__(self):
54 def __before__(self):
54 super(CompareController, self).__before__()
55 super(CompareController, self).__before__()
55
56
56 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 def __get_cs_or_redirect(self, rev, repo, redirect_after=True,
57 partial=False):
58 partial=False):
58 """
59 """
59 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
60 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
61 instead
62 instead
62
63
63 :param rev: revision to fetch
64 :param rev: revision to fetch
64 :param repo: repo instance
65 :param repo: repo instance
65 """
66 """
66
67
67 try:
68 try:
68 type_, rev = rev
69 type_, rev = rev
69 return repo.scm_instance.get_changeset(rev)
70 return repo.scm_instance.get_changeset(rev)
70 except EmptyRepositoryError, e:
71 except EmptyRepositoryError, e:
71 if not redirect_after:
72 if not redirect_after:
72 return None
73 return None
73 h.flash(h.literal(_('There are no changesets yet')),
74 h.flash(h.literal(_('There are no changesets yet')),
74 category='warning')
75 category='warning')
75 redirect(url('summary_home', repo_name=repo.repo_name))
76 redirect(url('summary_home', repo_name=repo.repo_name))
76
77
77 except RepositoryError, e:
78 except RepositoryError, e:
78 log.error(traceback.format_exc())
79 log.error(traceback.format_exc())
79 h.flash(str(e), category='warning')
80 h.flash(str(e), category='warning')
80 if not partial:
81 if not partial:
81 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 redirect(h.url('summary_home', repo_name=repo.repo_name))
82 raise HTTPBadRequest()
83 raise HTTPBadRequest()
83
84
84 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):
85
86
86 org_repo = c.rhodecode_db_repo.repo_name
87 org_repo = c.rhodecode_db_repo.repo_name
87 org_ref = (org_ref_type, org_ref)
88 org_ref = (org_ref_type, org_ref)
88 other_ref = (other_ref_type, other_ref)
89 other_ref = (other_ref_type, other_ref)
89 other_repo = request.GET.get('other_repo', org_repo)
90 other_repo = request.GET.get('other_repo', org_repo)
90 c.fulldiff = fulldiff = request.GET.get('fulldiff')
91 c.fulldiff = fulldiff = request.GET.get('fulldiff')
91 rev_start = request.GET.get('rev_start')
92 rev_start = request.GET.get('rev_start')
92 rev_end = request.GET.get('rev_end')
93 rev_end = request.GET.get('rev_end')
93
94
94 c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
95 c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
95 repo_name=other_repo,
96 repo_name=other_repo,
96 org_ref_type=other_ref[0], org_ref=other_ref[1],
97 org_ref_type=other_ref[0], org_ref=other_ref[1],
97 other_repo=org_repo,
98 other_repo=org_repo,
98 other_ref_type=org_ref[0], other_ref=org_ref[1])
99 other_ref_type=org_ref[0], other_ref=org_ref[1])
99
100
100 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
101 partial = request.environ.get('HTTP_X_PARTIAL_XHR')
101
102
102 org_repo = Repository.get_by_repo_name(org_repo)
103 org_repo = Repository.get_by_repo_name(org_repo)
103 other_repo = Repository.get_by_repo_name(other_repo)
104 other_repo = Repository.get_by_repo_name(other_repo)
104
105
105 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
106 self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
106 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
107 self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
107
108
108 if org_repo is None:
109 if org_repo is None:
109 log.error('Could not find org repo %s' % org_repo)
110 log.error('Could not find org repo %s' % org_repo)
110 raise HTTPNotFound
111 raise HTTPNotFound
111 if other_repo is None:
112 if other_repo is None:
112 log.error('Could not find other repo %s' % other_repo)
113 log.error('Could not find other repo %s' % other_repo)
113 raise HTTPNotFound
114 raise HTTPNotFound
114
115
115 if org_repo != other_repo and h.is_git(org_repo):
116 if org_repo != other_repo and h.is_git(org_repo):
116 log.error('compare of two remote repos not available for GIT REPOS')
117 log.error('compare of two remote repos not available for GIT REPOS')
117 raise HTTPNotFound
118 raise HTTPNotFound
118
119
119 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
120 if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
120 log.error('compare of two different kind of remote repos not available')
121 log.error('compare of two different kind of remote repos not available')
121 raise HTTPNotFound
122 raise HTTPNotFound
122
123
123 c.org_repo = org_repo
124 c.org_repo = org_repo
124 c.other_repo = other_repo
125 c.other_repo = other_repo
125 c.org_ref = org_ref[1]
126 c.org_ref = org_ref[1]
126 c.other_ref = other_ref[1]
127 c.other_ref = other_ref[1]
127 c.org_ref_type = org_ref[0]
128 c.org_ref_type = org_ref[0]
128 c.other_ref_type = other_ref[0]
129 c.other_ref_type = other_ref[0]
129
130
130 if rev_start and rev_end:
131 if rev_start and rev_end:
131 # swap revs with cherry picked ones, save them for display
132 # swap revs with cherry picked ones, save them for display
132 #org_ref = ('rev', rev_start)
133 #org_ref = ('rev', rev_start)
133 #other_ref = ('rev', rev_end)
134 #other_ref = ('rev', rev_end)
134 c.org_ref = rev_start[:12]
135 c.org_ref = rev_start[:12]
135 c.other_ref = rev_end[:12]
136 c.other_ref = rev_end[:12]
136 # get parent of
137 # get parent of
137 # rev start to include it in the diff
138 # rev start to include it in the diff
138 _cs = other_repo.scm_instance.get_changeset(rev_start)
139 _cs = other_repo.scm_instance.get_changeset(rev_start)
139 rev_start = _cs.parents[0].raw_id
140 rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset()
140 org_ref = ('rev', rev_start)
141 org_ref = ('rev', rev_start)
141 other_ref = ('rev', rev_end)
142 other_ref = ('rev', rev_end)
142 #if we cherry pick it's not remote, make the other_repo org_repo
143 #if we cherry pick it's not remote, make the other_repo org_repo
143 org_repo = other_repo
144 org_repo = other_repo
144
145
145 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
146 c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
146 org_repo, org_ref, other_repo, other_ref)
147 org_repo, org_ref, other_repo, other_ref)
147
148
148 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
149 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
149 c.cs_ranges])
150 c.cs_ranges])
150 # defines that we need hidden inputs with changesets
151 # defines that we need hidden inputs with changesets
151 c.as_form = request.GET.get('as_form', False)
152 c.as_form = request.GET.get('as_form', False)
152 if partial:
153 if partial:
153 return render('compare/compare_cs.html')
154 return render('compare/compare_cs.html')
154
155
155 if ancestor and org_repo != other_repo:
156 if ancestor and org_repo != other_repo:
156 # case we want a simple diff without incoming changesets,
157 # case we want a simple diff without incoming changesets,
157 # previewing what will be merged.
158 # previewing what will be merged.
158 # Make the diff on the forked repo, with
159 # Make the diff on the forked repo, with
159 # revision that is common ancestor
160 # revision that is common ancestor
160 log.debug('Using ancestor %s as org_ref instead of %s'
161 log.debug('Using ancestor %s as org_ref instead of %s'
161 % (ancestor, org_ref))
162 % (ancestor, org_ref))
162 org_ref = ('rev', ancestor)
163 org_ref = ('rev', ancestor)
163 org_repo = other_repo
164 org_repo = other_repo
164
165
165 diff_limit = self.cut_off_limit if not fulldiff else None
166 diff_limit = self.cut_off_limit if not fulldiff else None
166
167
167 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
168 _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
168
169
169 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
170 diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
170 diff_limit=diff_limit)
171 diff_limit=diff_limit)
171 _parsed = diff_processor.prepare()
172 _parsed = diff_processor.prepare()
172
173
173 c.limited_diff = False
174 c.limited_diff = False
174 if isinstance(_parsed, LimitedDiffContainer):
175 if isinstance(_parsed, LimitedDiffContainer):
175 c.limited_diff = True
176 c.limited_diff = True
176
177
177 c.files = []
178 c.files = []
178 c.changes = {}
179 c.changes = {}
179 c.lines_added = 0
180 c.lines_added = 0
180 c.lines_deleted = 0
181 c.lines_deleted = 0
181 for f in _parsed:
182 for f in _parsed:
182 st = f['stats']
183 st = f['stats']
183 if st[0] != 'b':
184 if st[0] != 'b':
184 c.lines_added += st[0]
185 c.lines_added += st[0]
185 c.lines_deleted += st[1]
186 c.lines_deleted += st[1]
186 fid = h.FID('', f['filename'])
187 fid = h.FID('', f['filename'])
187 c.files.append([fid, f['operation'], f['filename'], f['stats']])
188 c.files.append([fid, f['operation'], f['filename'], f['stats']])
188 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
189 diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
189 c.changes[fid] = [f['operation'], f['filename'], diff]
190 c.changes[fid] = [f['operation'], f['filename'], diff]
190
191
191 return render('compare/compare_diff.html')
192 return render('compare/compare_diff.html')
General Comments 0
You need to be logged in to leave comments. Login now