/*
|
* Copyright 2013 gitblit.com.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
package com.gitblit.wicket.pages;
|
|
import java.text.MessageFormat;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
import org.apache.wicket.PageParameters;
|
import org.apache.wicket.markup.html.basic.Label;
|
import org.apache.wicket.markup.html.form.CheckBox;
|
import org.apache.wicket.markup.html.form.DropDownChoice;
|
import org.apache.wicket.markup.html.form.TextField;
|
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
import org.apache.wicket.markup.html.link.ExternalLink;
|
import org.apache.wicket.markup.html.panel.Fragment;
|
import org.apache.wicket.markup.repeater.Item;
|
import org.apache.wicket.markup.repeater.data.DataView;
|
import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
import org.apache.wicket.model.IModel;
|
import org.apache.wicket.model.Model;
|
import org.apache.wicket.protocol.http.RequestUtils;
|
import org.apache.wicket.request.target.basic.RedirectRequestTarget;
|
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
|
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
|
import com.gitblit.Keys;
|
import com.gitblit.models.PathModel.PathChangeModel;
|
import com.gitblit.models.RefModel;
|
import com.gitblit.models.RepositoryModel;
|
import com.gitblit.models.SubmoduleModel;
|
import com.gitblit.servlet.RawServlet;
|
import com.gitblit.utils.DiffUtils;
|
import com.gitblit.utils.DiffUtils.DiffComparator;
|
import com.gitblit.utils.DiffUtils.DiffOutput;
|
import com.gitblit.utils.DiffUtils.DiffOutputType;
|
import com.gitblit.utils.JGitUtils;
|
import com.gitblit.utils.StringUtils;
|
import com.gitblit.wicket.SessionlessForm;
|
import com.gitblit.wicket.WicketUtils;
|
import com.gitblit.wicket.panels.CommitLegendPanel;
|
import com.gitblit.wicket.panels.DiffStatPanel;
|
import com.gitblit.wicket.panels.LinkPanel;
|
import com.gitblit.wicket.panels.LogPanel;
|
|
/**
|
* The compare page allows you to compare two branches, tags, or hash ids.
|
*
|
* @author James Moger
|
*
|
*/
|
public class ComparePage extends RepositoryPage {
|
|
IModel<String> fromCommitId = new Model<String>("");
|
IModel<String> toCommitId = new Model<String>("");
|
|
IModel<String> fromRefId = new Model<String>("");
|
IModel<String> toRefId = new Model<String>("");
|
|
IModel<Boolean> ignoreWhitespace = Model.of(true);
|
|
public ComparePage(PageParameters params) {
|
super(params);
|
Repository r = getRepository();
|
RepositoryModel repository = getRepositoryModel();
|
|
if (StringUtils.isEmpty(objectId)) {
|
// seleciton form
|
add(new Label("comparison").setVisible(false));
|
} else {
|
// active comparison
|
Fragment comparison = new Fragment("comparison", "comparisonFragment", this);
|
add(comparison);
|
|
RevCommit fromCommit;
|
RevCommit toCommit;
|
|
String[] parts = objectId.split("\\.\\.");
|
if (parts[0].startsWith("refs/") && parts[1].startsWith("refs/")) {
|
// set the ref models
|
fromRefId.setObject(parts[0]);
|
toRefId.setObject(parts[1]);
|
|
fromCommit = getCommit(r, fromRefId.getObject());
|
toCommit = getCommit(r, toRefId.getObject());
|
} else {
|
// set the id models
|
fromCommitId.setObject(parts[0]);
|
toCommitId.setObject(parts[1]);
|
|
fromCommit = getCommit(r, fromCommitId.getObject());
|
toCommit = getCommit(r, toCommitId.getObject());
|
}
|
|
// prepare submodules
|
getSubmodules(toCommit);
|
|
final String startId = fromCommit.getId().getName();
|
final String endId = toCommit.getId().getName();
|
|
// commit ids
|
fromCommitId.setObject(startId);
|
toCommitId.setObject(endId);
|
|
final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
|
final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
|
fromCommit.getName(), toCommit.getName(), imageExtensions);
|
|
final DiffComparator diffComparator = WicketUtils.getDiffComparator(params);
|
final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, diffComparator, DiffOutputType.HTML, handler);
|
if (handler.getImgDiffCount() > 0) {
|
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
|
}
|
|
// add compare diffstat
|
int insertions = 0;
|
int deletions = 0;
|
for (PathChangeModel pcm : diff.stat.paths) {
|
insertions += pcm.insertions;
|
deletions += pcm.deletions;
|
}
|
comparison.add(new DiffStatPanel("diffStat", insertions, deletions));
|
|
// compare page links
|
// comparison.add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
|
// WicketUtils.newRangeParameter(repositoryName, fromCommitId.toString(), toCommitId.getObject())));
|
|
// display list of commits
|
comparison.add(new LogPanel("commitList", repositoryName, objectId, r, 0, 0, repository.showRemoteBranches));
|
|
// changed paths list
|
comparison.add(new CommitLegendPanel("commitLegend", diff.stat.paths));
|
ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(diff.stat.paths);
|
DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) {
|
private static final long serialVersionUID = 1L;
|
int counter;
|
|
@Override
|
public void populateItem(final Item<PathChangeModel> item) {
|
final PathChangeModel entry = item.getModelObject();
|
Label changeType = new Label("changeType", "");
|
WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
|
setChangeTypeTooltip(changeType, entry.changeType);
|
item.add(changeType);
|
item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true));
|
|
boolean hasSubmodule = false;
|
String submodulePath = null;
|
if (entry.isTree()) {
|
// tree
|
item.add(new LinkPanel("pathName", null, entry.path, TreePage.class,
|
WicketUtils
|
.newPathParameter(repositoryName, endId, entry.path)));
|
} else if (entry.isSubmodule()) {
|
// submodule
|
String submoduleId = entry.objectId;
|
SubmoduleModel submodule = getSubmodule(entry.path);
|
submodulePath = submodule.gitblitPath;
|
hasSubmodule = submodule.hasSubmodule;
|
|
// add relative link
|
item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId));
|
} else {
|
// add relative link
|
item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
|
}
|
|
// quick links
|
if (entry.isSubmodule()) {
|
// submodule
|
item.add(new ExternalLink("patch", "").setEnabled(false));
|
item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils
|
.newObjectParameter(submodulePath, entry.objectId)).setEnabled(hasSubmodule));
|
item.add(new ExternalLink("raw", "").setEnabled(false));
|
item.add(new ExternalLink("blame", "").setEnabled(false));
|
item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
|
.newPathParameter(repositoryName, endId, entry.path))
|
.setEnabled(!entry.changeType.equals(ChangeType.ADD)));
|
} else {
|
// tree or blob
|
item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, WicketUtils
|
.newBlobDiffParameter(repositoryName, startId, endId, entry.path))
|
.setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
|
item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
|
.newPathParameter(repositoryName, endId, entry.path))
|
.setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
|
String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, endId, entry.path);
|
item.add(new ExternalLink("raw", rawUrl)
|
.setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
|
item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils
|
.newPathParameter(repositoryName, endId, entry.path))
|
.setEnabled(!entry.changeType.equals(ChangeType.ADD)
|
&& !entry.changeType.equals(ChangeType.DELETE)));
|
item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
|
.newPathParameter(repositoryName, endId, entry.path))
|
.setEnabled(!entry.changeType.equals(ChangeType.ADD)));
|
}
|
WicketUtils.setAlternatingBackground(item, counter);
|
counter++;
|
}
|
};
|
comparison.add(pathsView);
|
comparison.add(new Label("diffText", diff.content).setEscapeModelStrings(false));
|
}
|
|
// set the default DiffComparator
|
DiffComparator diffComparator = WicketUtils.getDiffComparator(params);
|
ignoreWhitespace.setObject(DiffComparator.IGNORE_WHITESPACE == diffComparator);
|
|
//
|
// ref selection form
|
//
|
SessionlessForm<Void> refsForm = new SessionlessForm<Void>("compareRefsForm", getClass(), getPageParameters()) {
|
|
private static final long serialVersionUID = 1L;
|
|
@Override
|
public void onSubmit() {
|
String from = ComparePage.this.fromRefId.getObject();
|
String to = ComparePage.this.toRefId.getObject();
|
boolean ignoreWS = ignoreWhitespace.getObject();
|
|
PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
|
if (ignoreWS) {
|
params.put("w", 1);
|
}
|
|
String relativeUrl = urlFor(ComparePage.class, params).toString();
|
String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
|
getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
|
}
|
};
|
|
List<String> refs = new ArrayList<String>();
|
for (RefModel ref : JGitUtils.getLocalBranches(r, true, -1)) {
|
refs.add(ref.getName());
|
}
|
if (repository.showRemoteBranches) {
|
for (RefModel ref : JGitUtils.getRemoteBranches(r, true, -1)) {
|
refs.add(ref.getName());
|
}
|
}
|
for (RefModel ref : JGitUtils.getTags(r, true, -1)) {
|
refs.add(ref.getName());
|
}
|
refsForm.add(new DropDownChoice<String>("fromRef", fromRefId, refs).setEnabled(refs.size() > 0));
|
refsForm.add(new DropDownChoice<String>("toRef", toRefId, refs).setEnabled(refs.size() > 0));
|
refsForm.add(new Label("ignoreWhitespaceLabel", getString(DiffComparator.IGNORE_WHITESPACE.getTranslationKey())));
|
refsForm.add(new CheckBox("ignoreWhitespaceCheckbox", ignoreWhitespace));
|
add(refsForm);
|
|
//
|
// manual ids form
|
//
|
SessionlessForm<Void> idsForm = new SessionlessForm<Void>("compareIdsForm", getClass(), getPageParameters()) {
|
|
private static final long serialVersionUID = 1L;
|
|
@Override
|
public void onSubmit() {
|
String from = ComparePage.this.fromCommitId.getObject();
|
String to = ComparePage.this.toCommitId.getObject();
|
boolean ignoreWS = ignoreWhitespace.getObject();
|
|
PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
|
if (ignoreWS) {
|
params.put("w", 1);
|
}
|
String relativeUrl = urlFor(ComparePage.class, params).toString();
|
String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
|
getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
|
}
|
};
|
|
TextField<String> fromIdField = new TextField<String>("fromId", fromCommitId);
|
WicketUtils.setInputPlaceholder(fromIdField, getString("gb.from") + "...");
|
idsForm.add(fromIdField);
|
|
TextField<String> toIdField = new TextField<String>("toId", toCommitId);
|
WicketUtils.setInputPlaceholder(toIdField, getString("gb.to") + "...");
|
idsForm.add(toIdField);
|
idsForm.add(new Label("ignoreWhitespaceLabel", getString(DiffComparator.IGNORE_WHITESPACE.getTranslationKey())));
|
idsForm.add(new CheckBox("ignoreWhitespaceCheckbox", ignoreWhitespace));
|
add(idsForm);
|
|
r.close();
|
}
|
|
@Override
|
protected String getPageName() {
|
return getString("gb.compare");
|
}
|
|
@Override
|
protected Class<? extends BasePage> getRepoNavPageClass() {
|
return ComparePage.class;
|
}
|
|
private RevCommit getCommit(Repository r, String rev)
|
{
|
RevCommit otherCommit = JGitUtils.getCommit(r, rev);
|
if (otherCommit == null) {
|
error(MessageFormat.format(getString("gb.failedToFindCommit"), rev, repositoryName, getPageName()), true);
|
}
|
return otherCommit;
|
}
|
}
|