commit | author | age
|
722e23
|
1 |
/* |
JM |
2 |
* Copyright 2013 gitblit.com. |
|
3 |
* |
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 |
* you may not use this file except in compliance with the License. |
|
6 |
* You may obtain a copy of the License at |
|
7 |
* |
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
9 |
* |
|
10 |
* Unless required by applicable law or agreed to in writing, software |
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 |
* See the License for the specific language governing permissions and |
|
14 |
* limitations under the License. |
|
15 |
*/ |
|
16 |
package com.gitblit.wicket.pages; |
|
17 |
|
|
18 |
import java.text.MessageFormat; |
|
19 |
import java.util.ArrayList; |
|
20 |
import java.util.List; |
|
21 |
|
|
22 |
import org.apache.wicket.PageParameters; |
|
23 |
import org.apache.wicket.markup.html.basic.Label; |
520a47
|
24 |
import org.apache.wicket.markup.html.form.CheckBox; |
722e23
|
25 |
import org.apache.wicket.markup.html.form.DropDownChoice; |
JM |
26 |
import org.apache.wicket.markup.html.form.TextField; |
|
27 |
import org.apache.wicket.markup.html.link.BookmarkablePageLink; |
|
28 |
import org.apache.wicket.markup.html.link.ExternalLink; |
|
29 |
import org.apache.wicket.markup.html.panel.Fragment; |
|
30 |
import org.apache.wicket.markup.repeater.Item; |
|
31 |
import org.apache.wicket.markup.repeater.data.DataView; |
|
32 |
import org.apache.wicket.markup.repeater.data.ListDataProvider; |
|
33 |
import org.apache.wicket.model.IModel; |
|
34 |
import org.apache.wicket.model.Model; |
|
35 |
import org.apache.wicket.protocol.http.RequestUtils; |
|
36 |
import org.apache.wicket.request.target.basic.RedirectRequestTarget; |
|
37 |
import org.eclipse.jgit.diff.DiffEntry.ChangeType; |
|
38 |
import org.eclipse.jgit.lib.Repository; |
|
39 |
import org.eclipse.jgit.revwalk.RevCommit; |
|
40 |
|
7dd99f
|
41 |
import com.gitblit.Keys; |
722e23
|
42 |
import com.gitblit.models.PathModel.PathChangeModel; |
JM |
43 |
import com.gitblit.models.RefModel; |
|
44 |
import com.gitblit.models.RepositoryModel; |
|
45 |
import com.gitblit.models.SubmoduleModel; |
ff17f7
|
46 |
import com.gitblit.servlet.RawServlet; |
722e23
|
47 |
import com.gitblit.utils.DiffUtils; |
cff352
|
48 |
import com.gitblit.utils.DiffUtils.DiffComparator; |
319342
|
49 |
import com.gitblit.utils.DiffUtils.DiffOutput; |
722e23
|
50 |
import com.gitblit.utils.DiffUtils.DiffOutputType; |
JM |
51 |
import com.gitblit.utils.JGitUtils; |
|
52 |
import com.gitblit.utils.StringUtils; |
|
53 |
import com.gitblit.wicket.SessionlessForm; |
|
54 |
import com.gitblit.wicket.WicketUtils; |
|
55 |
import com.gitblit.wicket.panels.CommitLegendPanel; |
319342
|
56 |
import com.gitblit.wicket.panels.DiffStatPanel; |
722e23
|
57 |
import com.gitblit.wicket.panels.LinkPanel; |
JM |
58 |
import com.gitblit.wicket.panels.LogPanel; |
|
59 |
|
|
60 |
/** |
|
61 |
* The compare page allows you to compare two branches, tags, or hash ids. |
699e71
|
62 |
* |
722e23
|
63 |
* @author James Moger |
JM |
64 |
* |
|
65 |
*/ |
|
66 |
public class ComparePage extends RepositoryPage { |
|
67 |
|
|
68 |
IModel<String> fromCommitId = new Model<String>(""); |
|
69 |
IModel<String> toCommitId = new Model<String>(""); |
|
70 |
|
|
71 |
IModel<String> fromRefId = new Model<String>(""); |
|
72 |
IModel<String> toRefId = new Model<String>(""); |
520a47
|
73 |
|
JM |
74 |
IModel<Boolean> ignoreWhitespace = Model.of(true); |
722e23
|
75 |
|
JM |
76 |
public ComparePage(PageParameters params) { |
|
77 |
super(params); |
|
78 |
Repository r = getRepository(); |
|
79 |
RepositoryModel repository = getRepositoryModel(); |
699e71
|
80 |
|
722e23
|
81 |
if (StringUtils.isEmpty(objectId)) { |
JM |
82 |
// seleciton form |
|
83 |
add(new Label("comparison").setVisible(false)); |
|
84 |
} else { |
|
85 |
// active comparison |
|
86 |
Fragment comparison = new Fragment("comparison", "comparisonFragment", this); |
|
87 |
add(comparison); |
699e71
|
88 |
|
722e23
|
89 |
RevCommit fromCommit; |
JM |
90 |
RevCommit toCommit; |
699e71
|
91 |
|
722e23
|
92 |
String[] parts = objectId.split("\\.\\."); |
JM |
93 |
if (parts[0].startsWith("refs/") && parts[1].startsWith("refs/")) { |
|
94 |
// set the ref models |
|
95 |
fromRefId.setObject(parts[0]); |
|
96 |
toRefId.setObject(parts[1]); |
699e71
|
97 |
|
722e23
|
98 |
fromCommit = getCommit(r, fromRefId.getObject()); |
JM |
99 |
toCommit = getCommit(r, toRefId.getObject()); |
|
100 |
} else { |
|
101 |
// set the id models |
|
102 |
fromCommitId.setObject(parts[0]); |
|
103 |
toCommitId.setObject(parts[1]); |
699e71
|
104 |
|
722e23
|
105 |
fromCommit = getCommit(r, fromCommitId.getObject()); |
JM |
106 |
toCommit = getCommit(r, toCommitId.getObject()); |
|
107 |
} |
|
108 |
|
80d636
|
109 |
// prepare submodules |
JM |
110 |
getSubmodules(toCommit); |
699e71
|
111 |
|
722e23
|
112 |
final String startId = fromCommit.getId().getName(); |
JM |
113 |
final String endId = toCommit.getId().getName(); |
|
114 |
|
|
115 |
// commit ids |
|
116 |
fromCommitId.setObject(startId); |
|
117 |
toCommitId.setObject(endId); |
|
118 |
|
7dd99f
|
119 |
final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions); |
b6f475
|
120 |
final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName, |
7dd99f
|
121 |
fromCommit.getName(), toCommit.getName(), imageExtensions); |
dd661a
|
122 |
final DiffComparator diffComparator = WicketUtils.getDiffComparator(params); |
310a80
|
123 |
final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4); |
JM |
124 |
final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, diffComparator, DiffOutputType.HTML, handler, tabLength); |
3e1336
|
125 |
if (handler.getImgDiffCount() > 0) { |
T |
126 |
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs |
|
127 |
} |
319342
|
128 |
|
JM |
129 |
// add compare diffstat |
|
130 |
int insertions = 0; |
|
131 |
int deletions = 0; |
|
132 |
for (PathChangeModel pcm : diff.stat.paths) { |
|
133 |
insertions += pcm.insertions; |
|
134 |
deletions += pcm.deletions; |
|
135 |
} |
|
136 |
comparison.add(new DiffStatPanel("diffStat", insertions, deletions)); |
722e23
|
137 |
|
JM |
138 |
// compare page links |
|
139 |
// comparison.add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class, |
|
140 |
// WicketUtils.newRangeParameter(repositoryName, fromCommitId.toString(), toCommitId.getObject()))); |
|
141 |
|
|
142 |
// display list of commits |
|
143 |
comparison.add(new LogPanel("commitList", repositoryName, objectId, r, 0, 0, repository.showRemoteBranches)); |
|
144 |
|
|
145 |
// changed paths list |
319342
|
146 |
comparison.add(new CommitLegendPanel("commitLegend", diff.stat.paths)); |
JM |
147 |
ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(diff.stat.paths); |
722e23
|
148 |
DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) { |
JM |
149 |
private static final long serialVersionUID = 1L; |
|
150 |
int counter; |
|
151 |
|
699e71
|
152 |
@Override |
722e23
|
153 |
public void populateItem(final Item<PathChangeModel> item) { |
JM |
154 |
final PathChangeModel entry = item.getModelObject(); |
|
155 |
Label changeType = new Label("changeType", ""); |
|
156 |
WicketUtils.setChangeTypeCssClass(changeType, entry.changeType); |
|
157 |
setChangeTypeTooltip(changeType, entry.changeType); |
|
158 |
item.add(changeType); |
319342
|
159 |
item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true)); |
722e23
|
160 |
|
JM |
161 |
boolean hasSubmodule = false; |
|
162 |
String submodulePath = null; |
|
163 |
if (entry.isTree()) { |
|
164 |
// tree |
|
165 |
item.add(new LinkPanel("pathName", null, entry.path, TreePage.class, |
|
166 |
WicketUtils |
|
167 |
.newPathParameter(repositoryName, endId, entry.path))); |
|
168 |
} else if (entry.isSubmodule()) { |
|
169 |
// submodule |
|
170 |
String submoduleId = entry.objectId; |
|
171 |
SubmoduleModel submodule = getSubmodule(entry.path); |
|
172 |
submodulePath = submodule.gitblitPath; |
|
173 |
hasSubmodule = submodule.hasSubmodule; |
|
174 |
|
|
175 |
// add relative link |
f0ebfe
|
176 |
item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId)); |
722e23
|
177 |
} else { |
JM |
178 |
// add relative link |
f0ebfe
|
179 |
item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId)); |
722e23
|
180 |
} |
JM |
181 |
|
|
182 |
// quick links |
|
183 |
if (entry.isSubmodule()) { |
|
184 |
// submodule |
|
185 |
item.add(new ExternalLink("patch", "").setEnabled(false)); |
|
186 |
item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils |
|
187 |
.newObjectParameter(submodulePath, entry.objectId)).setEnabled(hasSubmodule)); |
eb0f7e
|
188 |
item.add(new ExternalLink("raw", "").setEnabled(false)); |
722e23
|
189 |
item.add(new ExternalLink("blame", "").setEnabled(false)); |
JM |
190 |
item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils |
|
191 |
.newPathParameter(repositoryName, endId, entry.path)) |
|
192 |
.setEnabled(!entry.changeType.equals(ChangeType.ADD))); |
|
193 |
} else { |
|
194 |
// tree or blob |
|
195 |
item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, WicketUtils |
|
196 |
.newBlobDiffParameter(repositoryName, startId, endId, entry.path)) |
|
197 |
.setEnabled(!entry.changeType.equals(ChangeType.DELETE))); |
|
198 |
item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils |
|
199 |
.newPathParameter(repositoryName, endId, entry.path)) |
|
200 |
.setEnabled(!entry.changeType.equals(ChangeType.DELETE))); |
ff17f7
|
201 |
String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, endId, entry.path); |
JM |
202 |
item.add(new ExternalLink("raw", rawUrl) |
c95e30
|
203 |
.setEnabled(!entry.changeType.equals(ChangeType.DELETE))); |
722e23
|
204 |
item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils |
JM |
205 |
.newPathParameter(repositoryName, endId, entry.path)) |
|
206 |
.setEnabled(!entry.changeType.equals(ChangeType.ADD) |
|
207 |
&& !entry.changeType.equals(ChangeType.DELETE))); |
|
208 |
item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils |
|
209 |
.newPathParameter(repositoryName, endId, entry.path)) |
|
210 |
.setEnabled(!entry.changeType.equals(ChangeType.ADD))); |
|
211 |
} |
|
212 |
WicketUtils.setAlternatingBackground(item, counter); |
|
213 |
counter++; |
|
214 |
} |
|
215 |
}; |
|
216 |
comparison.add(pathsView); |
319342
|
217 |
comparison.add(new Label("diffText", diff.content).setEscapeModelStrings(false)); |
722e23
|
218 |
} |
JM |
219 |
|
520a47
|
220 |
// set the default DiffComparator |
JM |
221 |
DiffComparator diffComparator = WicketUtils.getDiffComparator(params); |
|
222 |
ignoreWhitespace.setObject(DiffComparator.IGNORE_WHITESPACE == diffComparator); |
|
223 |
|
722e23
|
224 |
// |
JM |
225 |
// ref selection form |
|
226 |
// |
|
227 |
SessionlessForm<Void> refsForm = new SessionlessForm<Void>("compareRefsForm", getClass(), getPageParameters()) { |
|
228 |
|
|
229 |
private static final long serialVersionUID = 1L; |
|
230 |
|
|
231 |
@Override |
|
232 |
public void onSubmit() { |
|
233 |
String from = ComparePage.this.fromRefId.getObject(); |
|
234 |
String to = ComparePage.this.toRefId.getObject(); |
520a47
|
235 |
boolean ignoreWS = ignoreWhitespace.getObject(); |
699e71
|
236 |
|
722e23
|
237 |
PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to); |
520a47
|
238 |
if (ignoreWS) { |
JM |
239 |
params.put("w", 1); |
|
240 |
} |
|
241 |
|
722e23
|
242 |
String relativeUrl = urlFor(ComparePage.class, params).toString(); |
JM |
243 |
String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl); |
|
244 |
getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); |
|
245 |
} |
|
246 |
}; |
699e71
|
247 |
|
722e23
|
248 |
List<String> refs = new ArrayList<String>(); |
JM |
249 |
for (RefModel ref : JGitUtils.getLocalBranches(r, true, -1)) { |
|
250 |
refs.add(ref.getName()); |
|
251 |
} |
|
252 |
if (repository.showRemoteBranches) { |
|
253 |
for (RefModel ref : JGitUtils.getRemoteBranches(r, true, -1)) { |
|
254 |
refs.add(ref.getName()); |
|
255 |
} |
|
256 |
} |
|
257 |
for (RefModel ref : JGitUtils.getTags(r, true, -1)) { |
|
258 |
refs.add(ref.getName()); |
|
259 |
} |
|
260 |
refsForm.add(new DropDownChoice<String>("fromRef", fromRefId, refs).setEnabled(refs.size() > 0)); |
|
261 |
refsForm.add(new DropDownChoice<String>("toRef", toRefId, refs).setEnabled(refs.size() > 0)); |
520a47
|
262 |
refsForm.add(new Label("ignoreWhitespaceLabel", getString(DiffComparator.IGNORE_WHITESPACE.getTranslationKey()))); |
JM |
263 |
refsForm.add(new CheckBox("ignoreWhitespaceCheckbox", ignoreWhitespace)); |
722e23
|
264 |
add(refsForm); |
699e71
|
265 |
|
722e23
|
266 |
// |
JM |
267 |
// manual ids form |
|
268 |
// |
|
269 |
SessionlessForm<Void> idsForm = new SessionlessForm<Void>("compareIdsForm", getClass(), getPageParameters()) { |
|
270 |
|
|
271 |
private static final long serialVersionUID = 1L; |
|
272 |
|
|
273 |
@Override |
|
274 |
public void onSubmit() { |
|
275 |
String from = ComparePage.this.fromCommitId.getObject(); |
|
276 |
String to = ComparePage.this.toCommitId.getObject(); |
520a47
|
277 |
boolean ignoreWS = ignoreWhitespace.getObject(); |
699e71
|
278 |
|
722e23
|
279 |
PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to); |
520a47
|
280 |
if (ignoreWS) { |
JM |
281 |
params.put("w", 1); |
|
282 |
} |
722e23
|
283 |
String relativeUrl = urlFor(ComparePage.class, params).toString(); |
JM |
284 |
String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl); |
|
285 |
getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); |
|
286 |
} |
|
287 |
}; |
699e71
|
288 |
|
722e23
|
289 |
TextField<String> fromIdField = new TextField<String>("fromId", fromCommitId); |
JM |
290 |
WicketUtils.setInputPlaceholder(fromIdField, getString("gb.from") + "..."); |
|
291 |
idsForm.add(fromIdField); |
699e71
|
292 |
|
722e23
|
293 |
TextField<String> toIdField = new TextField<String>("toId", toCommitId); |
JM |
294 |
WicketUtils.setInputPlaceholder(toIdField, getString("gb.to") + "..."); |
|
295 |
idsForm.add(toIdField); |
520a47
|
296 |
idsForm.add(new Label("ignoreWhitespaceLabel", getString(DiffComparator.IGNORE_WHITESPACE.getTranslationKey()))); |
JM |
297 |
idsForm.add(new CheckBox("ignoreWhitespaceCheckbox", ignoreWhitespace)); |
722e23
|
298 |
add(idsForm); |
699e71
|
299 |
|
722e23
|
300 |
r.close(); |
JM |
301 |
} |
|
302 |
|
|
303 |
@Override |
|
304 |
protected String getPageName() { |
|
305 |
return getString("gb.compare"); |
|
306 |
} |
699e71
|
307 |
|
722e23
|
308 |
@Override |
JM |
309 |
protected Class<? extends BasePage> getRepoNavPageClass() { |
|
310 |
return ComparePage.class; |
|
311 |
} |
|
312 |
|
|
313 |
private RevCommit getCommit(Repository r, String rev) |
|
314 |
{ |
|
315 |
RevCommit otherCommit = JGitUtils.getCommit(r, rev); |
|
316 |
if (otherCommit == null) { |
|
317 |
error(MessageFormat.format(getString("gb.failedToFindCommit"), rev, repositoryName, getPageName()), true); |
|
318 |
} |
|
319 |
return otherCommit; |
|
320 |
} |
|
321 |
} |