summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/gitblit
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2013-05-23 23:13:59 -0400
committerJames Moger <james.moger@gitblit.com>2013-05-23 23:13:59 -0400
commit722e2325300c7e5d73a93416e28c20354556fec4 (patch)
tree3b1051008d2d0c307920c6d8d7e86164ef07f1bc /src/main/java/com/gitblit
parent6b897653169833556612afbb40b8cadd1fbae486 (diff)
downloadgitblit-722e2325300c7e5d73a93416e28c20354556fec4.tar.gz
gitblit-722e2325300c7e5d73a93416e28c20354556fec4.zip
Implemented compare page for branch/tag/manual diffs (issue-75, issue-133)
Diffstat (limited to 'src/main/java/com/gitblit')
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.properties6
-rw-r--r--src/main/java/com/gitblit/wicket/WicketUtils.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ComparePage.html79
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ComparePage.java277
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.java1
6 files changed, 368 insertions, 1 deletions
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index 20d2f2a8..dcae53ef 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -36,6 +36,7 @@ import com.gitblit.wicket.pages.BlobPage;
import com.gitblit.wicket.pages.BranchesPage;
import com.gitblit.wicket.pages.CommitDiffPage;
import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.ComparePage;
import com.gitblit.wicket.pages.DocsPage;
import com.gitblit.wicket.pages.FederationRegistrationPage;
import com.gitblit.wicket.pages.ForkPage;
@@ -106,6 +107,7 @@ public class GitBlitWebApp extends WebApplication {
mount("/raw", RawPage.class, "r", "h", "f");
mount("/blobdiff", BlobDiffPage.class, "r", "h", "f");
mount("/commitdiff", CommitDiffPage.class, "r", "h");
+ mount("/compare", ComparePage.class, "r", "h");
mount("/patch", PatchPage.class, "r", "h", "f");
mount("/history", HistoryPage.class, "r", "h", "f");
mount("/search", GitSearchPage.class);
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index a6cac546..bec8b35b 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -454,4 +454,8 @@ gb.viewAccess = You do not have Gitblit read or write access
gb.overview = overview
gb.home = home
gb.monthlyActivity = monthly activity
-gb.myProfile = my profile \ No newline at end of file
+gb.myProfile = my profile
+gb.compare = compare
+gb.manual = manual
+gb.from = from
+gb.to = to \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java
index 2170d0b7..91686b67 100644
--- a/src/main/java/com/gitblit/wicket/WicketUtils.java
+++ b/src/main/java/com/gitblit/wicket/WicketUtils.java
@@ -319,6 +319,10 @@ public class WicketUtils {
return new PageParameters("r=" + repositoryName + ",h=" + objectId);
}
+ public static PageParameters newRangeParameter(String repositoryName, String startRange, String endRange) {
+ return new PageParameters("r=" + repositoryName + ",h=" + startRange + ".." + endRange);
+ }
+
public static PageParameters newPathParameter(String repositoryName, String objectId,
String path) {
if (StringUtils.isEmpty(path)) {
diff --git a/src/main/java/com/gitblit/wicket/pages/ComparePage.html b/src/main/java/com/gitblit/wicket/pages/ComparePage.html
new file mode 100644
index 00000000..8fb6e4f8
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/ComparePage.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:extend>
+
+ <div class="tabbable">
+ <ul class="nav nav-pills">
+ <li class="active"><a href="#refs" data-toggle="tab"><wicket:message key="gb.refs"></wicket:message></a></li>
+ <li><a href="#ids" data-toggle="tab"><wicket:message key="gb.manual"></wicket:message></a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="refs">
+ <form wicket:id="compareRefsForm" class="form-inline">
+ <select wicket:id="fromRef" class="span3" />
+ <select wicket:id="toRef" class="span3" />
+ <button class="btn" type="submit"><wicket:message key="gb.compare"></wicket:message></button>
+ </form>
+ </div>
+ <div class="tab-pane" id="ids">
+ <form wicket:id="compareIdsForm" class="form-inline">
+ <input wicket:id="fromId" type="text" class="span3" />
+ <input wicket:id="toId" type="text" class="span3" />
+ <button class="btn" type="submit"><wicket:message key="gb.compare"></wicket:message></button>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <div wicket:id="comparison"></div>
+
+ <wicket:fragment wicket:id="comparisonFragment">
+
+ <div class="tabbable">
+ <ul class="nav nav-tabs">
+ <li class="active"><a href="#commits" data-toggle="tab"><wicket:message key="gb.commits"></wicket:message></a></li>
+ <li><a href="#diff" data-toggle="tab"><wicket:message key="gb.diff"></wicket:message></a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="commits">
+ <!-- commit list -->
+ <div wicket:id="commitList">[commit list]</div>
+ </div>
+ <div class="tab-pane" id="diff">
+<!-- <div class="page_nav2"> -->
+<!-- <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> -->
+<!-- </div> -->
+
+ <!-- changed paths -->
+ <div>
+ <!-- commit legend -->
+ <div class="hidden-phone" style="text-align:right;" wicket:id="commitLegend"></div>
+ <div class="header"><i class="icon-file"></i> <wicket:message key="gb.changedFiles">[changed files]</wicket:message></div>
+ </div>
+ <table class="pretty">
+ <tr wicket:id="changedPath">
+ <td class="changeType"><span wicket:id="changeType">[change type]</span></td>
+ <td class="path"><span wicket:id="pathName">[commit path]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span class="link">
+ <a wicket:id="patch"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </table>
+
+ <!-- diff content -->
+ <pre style="padding-top:10px;" wicket:id="diffText">[diff text]</pre>
+ </div>
+ </div>
+ </div>
+ </wicket:fragment>
+
+</wicket:extend>
+</body>
+</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/ComparePage.java b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
new file mode 100644
index 00000000..f62dc649
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
@@ -0,0 +1,277 @@
+/*
+ * 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.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.GitBlit;
+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.utils.DiffUtils;
+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.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>("");
+
+ 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);
+
+ DiffOutputType diffType = DiffOutputType.forName(GitBlit.getString(Keys.web.diffStyle,
+ DiffOutputType.GITBLIT.name()));
+
+ 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());
+ }
+
+ final String startId = fromCommit.getId().getName();
+ final String endId = toCommit.getId().getName();
+
+ // commit ids
+ fromCommitId.setObject(startId);
+ toCommitId.setObject(endId);
+
+ String diff = DiffUtils.getDiff(r, fromCommit, toCommit, diffType);
+
+ // 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
+ List<PathChangeModel> paths = JGitUtils.getFilesInRange(r, fromCommit, toCommit);
+
+ comparison.add(new CommitLegendPanel("commitLegend", paths));
+ ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(paths);
+ DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ 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);
+
+ 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), "#" + entry.path));
+ } else {
+ // add relative link
+ item.add(new LinkPanel("pathName", "list", entry.path, "#" + entry.path));
+ }
+
+ // 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("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)));
+ 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).setEscapeModelStrings(false));
+ }
+
+ //
+ // 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();
+
+ PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
+ 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));
+ 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();
+
+ PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
+ 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);
+ 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;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
index 90fdd40b..8a233ead 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -169,6 +169,7 @@ public abstract class RepositoryPage extends RootPage {
}
pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params));
pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
+ pages.put("compare", new PageRegistration("gb.compare", ComparePage.class, params));
if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
}