You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ComparePage.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  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. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import org.apache.wicket.PageParameters;
  21. import org.apache.wicket.markup.html.basic.Label;
  22. import org.apache.wicket.markup.html.form.DropDownChoice;
  23. import org.apache.wicket.markup.html.form.TextField;
  24. import org.apache.wicket.markup.html.link.BookmarkablePageLink;
  25. import org.apache.wicket.markup.html.link.ExternalLink;
  26. import org.apache.wicket.markup.html.panel.Fragment;
  27. import org.apache.wicket.markup.repeater.Item;
  28. import org.apache.wicket.markup.repeater.data.DataView;
  29. import org.apache.wicket.markup.repeater.data.ListDataProvider;
  30. import org.apache.wicket.model.IModel;
  31. import org.apache.wicket.model.Model;
  32. import org.apache.wicket.protocol.http.RequestUtils;
  33. import org.apache.wicket.request.target.basic.RedirectRequestTarget;
  34. import org.eclipse.jgit.diff.DiffEntry.ChangeType;
  35. import org.eclipse.jgit.lib.Repository;
  36. import org.eclipse.jgit.revwalk.RevCommit;
  37. import com.gitblit.Keys;
  38. import com.gitblit.models.PathModel.PathChangeModel;
  39. import com.gitblit.models.RefModel;
  40. import com.gitblit.models.RepositoryModel;
  41. import com.gitblit.models.SubmoduleModel;
  42. import com.gitblit.servlet.RawServlet;
  43. import com.gitblit.utils.DiffUtils;
  44. import com.gitblit.utils.DiffUtils.DiffOutput;
  45. import com.gitblit.utils.DiffUtils.DiffOutputType;
  46. import com.gitblit.utils.JGitUtils;
  47. import com.gitblit.utils.StringUtils;
  48. import com.gitblit.wicket.SessionlessForm;
  49. import com.gitblit.wicket.WicketUtils;
  50. import com.gitblit.wicket.panels.CommitLegendPanel;
  51. import com.gitblit.wicket.panels.DiffStatPanel;
  52. import com.gitblit.wicket.panels.LinkPanel;
  53. import com.gitblit.wicket.panels.LogPanel;
  54. /**
  55. * The compare page allows you to compare two branches, tags, or hash ids.
  56. *
  57. * @author James Moger
  58. *
  59. */
  60. public class ComparePage extends RepositoryPage {
  61. IModel<String> fromCommitId = new Model<String>("");
  62. IModel<String> toCommitId = new Model<String>("");
  63. IModel<String> fromRefId = new Model<String>("");
  64. IModel<String> toRefId = new Model<String>("");
  65. public ComparePage(PageParameters params) {
  66. super(params);
  67. Repository r = getRepository();
  68. RepositoryModel repository = getRepositoryModel();
  69. if (StringUtils.isEmpty(objectId)) {
  70. // seleciton form
  71. add(new Label("comparison").setVisible(false));
  72. } else {
  73. // active comparison
  74. Fragment comparison = new Fragment("comparison", "comparisonFragment", this);
  75. add(comparison);
  76. RevCommit fromCommit;
  77. RevCommit toCommit;
  78. String[] parts = objectId.split("\\.\\.");
  79. if (parts[0].startsWith("refs/") && parts[1].startsWith("refs/")) {
  80. // set the ref models
  81. fromRefId.setObject(parts[0]);
  82. toRefId.setObject(parts[1]);
  83. fromCommit = getCommit(r, fromRefId.getObject());
  84. toCommit = getCommit(r, toRefId.getObject());
  85. } else {
  86. // set the id models
  87. fromCommitId.setObject(parts[0]);
  88. toCommitId.setObject(parts[1]);
  89. fromCommit = getCommit(r, fromCommitId.getObject());
  90. toCommit = getCommit(r, toCommitId.getObject());
  91. }
  92. // prepare submodules
  93. getSubmodules(toCommit);
  94. final String startId = fromCommit.getId().getName();
  95. final String endId = toCommit.getId().getName();
  96. // commit ids
  97. fromCommitId.setObject(startId);
  98. toCommitId.setObject(endId);
  99. final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
  100. final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
  101. fromCommit.getName(), toCommit.getName(), imageExtensions);
  102. final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, DiffOutputType.HTML, handler);
  103. if (handler.getImgDiffCount() > 0) {
  104. addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
  105. }
  106. // add compare diffstat
  107. int insertions = 0;
  108. int deletions = 0;
  109. for (PathChangeModel pcm : diff.stat.paths) {
  110. insertions += pcm.insertions;
  111. deletions += pcm.deletions;
  112. }
  113. comparison.add(new DiffStatPanel("diffStat", insertions, deletions));
  114. // compare page links
  115. // comparison.add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
  116. // WicketUtils.newRangeParameter(repositoryName, fromCommitId.toString(), toCommitId.getObject())));
  117. // display list of commits
  118. comparison.add(new LogPanel("commitList", repositoryName, objectId, r, 0, 0, repository.showRemoteBranches));
  119. // changed paths list
  120. comparison.add(new CommitLegendPanel("commitLegend", diff.stat.paths));
  121. ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(diff.stat.paths);
  122. DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) {
  123. private static final long serialVersionUID = 1L;
  124. int counter;
  125. @Override
  126. public void populateItem(final Item<PathChangeModel> item) {
  127. final PathChangeModel entry = item.getModelObject();
  128. Label changeType = new Label("changeType", "");
  129. WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
  130. setChangeTypeTooltip(changeType, entry.changeType);
  131. item.add(changeType);
  132. item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true));
  133. boolean hasSubmodule = false;
  134. String submodulePath = null;
  135. if (entry.isTree()) {
  136. // tree
  137. item.add(new LinkPanel("pathName", null, entry.path, TreePage.class,
  138. WicketUtils
  139. .newPathParameter(repositoryName, endId, entry.path)));
  140. } else if (entry.isSubmodule()) {
  141. // submodule
  142. String submoduleId = entry.objectId;
  143. SubmoduleModel submodule = getSubmodule(entry.path);
  144. submodulePath = submodule.gitblitPath;
  145. hasSubmodule = submodule.hasSubmodule;
  146. // add relative link
  147. item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId));
  148. } else {
  149. // add relative link
  150. item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
  151. }
  152. // quick links
  153. if (entry.isSubmodule()) {
  154. // submodule
  155. item.add(new ExternalLink("patch", "").setEnabled(false));
  156. item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils
  157. .newObjectParameter(submodulePath, entry.objectId)).setEnabled(hasSubmodule));
  158. item.add(new ExternalLink("raw", "").setEnabled(false));
  159. item.add(new ExternalLink("blame", "").setEnabled(false));
  160. item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
  161. .newPathParameter(repositoryName, endId, entry.path))
  162. .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
  163. } else {
  164. // tree or blob
  165. item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, WicketUtils
  166. .newBlobDiffParameter(repositoryName, startId, endId, entry.path))
  167. .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
  168. item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
  169. .newPathParameter(repositoryName, endId, entry.path))
  170. .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
  171. String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, endId, entry.path);
  172. item.add(new ExternalLink("raw", rawUrl)
  173. .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
  174. item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils
  175. .newPathParameter(repositoryName, endId, entry.path))
  176. .setEnabled(!entry.changeType.equals(ChangeType.ADD)
  177. && !entry.changeType.equals(ChangeType.DELETE)));
  178. item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
  179. .newPathParameter(repositoryName, endId, entry.path))
  180. .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
  181. }
  182. WicketUtils.setAlternatingBackground(item, counter);
  183. counter++;
  184. }
  185. };
  186. comparison.add(pathsView);
  187. comparison.add(new Label("diffText", diff.content).setEscapeModelStrings(false));
  188. }
  189. //
  190. // ref selection form
  191. //
  192. SessionlessForm<Void> refsForm = new SessionlessForm<Void>("compareRefsForm", getClass(), getPageParameters()) {
  193. private static final long serialVersionUID = 1L;
  194. @Override
  195. public void onSubmit() {
  196. String from = ComparePage.this.fromRefId.getObject();
  197. String to = ComparePage.this.toRefId.getObject();
  198. PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
  199. String relativeUrl = urlFor(ComparePage.class, params).toString();
  200. String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
  201. getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
  202. }
  203. };
  204. List<String> refs = new ArrayList<String>();
  205. for (RefModel ref : JGitUtils.getLocalBranches(r, true, -1)) {
  206. refs.add(ref.getName());
  207. }
  208. if (repository.showRemoteBranches) {
  209. for (RefModel ref : JGitUtils.getRemoteBranches(r, true, -1)) {
  210. refs.add(ref.getName());
  211. }
  212. }
  213. for (RefModel ref : JGitUtils.getTags(r, true, -1)) {
  214. refs.add(ref.getName());
  215. }
  216. refsForm.add(new DropDownChoice<String>("fromRef", fromRefId, refs).setEnabled(refs.size() > 0));
  217. refsForm.add(new DropDownChoice<String>("toRef", toRefId, refs).setEnabled(refs.size() > 0));
  218. add(refsForm);
  219. //
  220. // manual ids form
  221. //
  222. SessionlessForm<Void> idsForm = new SessionlessForm<Void>("compareIdsForm", getClass(), getPageParameters()) {
  223. private static final long serialVersionUID = 1L;
  224. @Override
  225. public void onSubmit() {
  226. String from = ComparePage.this.fromCommitId.getObject();
  227. String to = ComparePage.this.toCommitId.getObject();
  228. PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
  229. String relativeUrl = urlFor(ComparePage.class, params).toString();
  230. String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
  231. getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
  232. }
  233. };
  234. TextField<String> fromIdField = new TextField<String>("fromId", fromCommitId);
  235. WicketUtils.setInputPlaceholder(fromIdField, getString("gb.from") + "...");
  236. idsForm.add(fromIdField);
  237. TextField<String> toIdField = new TextField<String>("toId", toCommitId);
  238. WicketUtils.setInputPlaceholder(toIdField, getString("gb.to") + "...");
  239. idsForm.add(toIdField);
  240. add(idsForm);
  241. r.close();
  242. }
  243. @Override
  244. protected String getPageName() {
  245. return getString("gb.compare");
  246. }
  247. @Override
  248. protected Class<? extends BasePage> getRepoNavPageClass() {
  249. return ComparePage.class;
  250. }
  251. private RevCommit getCommit(Repository r, String rev)
  252. {
  253. RevCommit otherCommit = JGitUtils.getCommit(r, rev);
  254. if (otherCommit == null) {
  255. error(MessageFormat.format(getString("gb.failedToFindCommit"), rev, repositoryName, getPageName()), true);
  256. }
  257. return otherCommit;
  258. }
  259. }