summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--resources/gitblit.css67
-rw-r--r--src/com/gitblit/tests/JGitUtilsTest.java42
-rw-r--r--src/com/gitblit/utils/HtmlDiffFormatter.java128
-rw-r--r--src/com/gitblit/utils/JGitUtils.java95
-rw-r--r--src/com/gitblit/wicket/GitBlitWebApp.java2
-rw-r--r--src/com/gitblit/wicket/pages/CommitPage.java2
-rw-r--r--src/com/gitblit/wicket/pages/DiffPage.html31
-rw-r--r--src/com/gitblit/wicket/pages/DiffPage.java46
-rw-r--r--src/com/gitblit/wicket/panels/PathLinksPanel.java3
-rw-r--r--src/com/gitblit/wicket/panels/ShortLogLinksPanel.java4
10 files changed, 387 insertions, 33 deletions
diff --git a/resources/gitblit.css b/resources/gitblit.css
index d126a8ae..96815bd5 100644
--- a/resources/gitblit.css
+++ b/resources/gitblit.css
@@ -18,8 +18,9 @@ body {
padding: 0px;
}
-pre.prettyprint, pre.plainprint {
+pre, pre.prettyprint, pre.plainprint {
color: black;
+ font-family: monospace;
font-size:12px;
border:0px;
}
@@ -201,6 +202,70 @@ div.bug_hold {
text-align: center;
}
+div.diff {
+ font-family: monospace;
+}
+
+div.diff.header {
+ -moz-border-bottom-colors: none;
+ -moz-border-image: none;
+ -moz-border-left-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-top-colors: none;
+ background-color: #EDECE6;
+ border-color: #D9D8D1;
+ border-style: solid;
+ border-width: 1px 0;
+ font-weight: bold;
+ margin-top: 4px;
+ padding: 4px 0 2px;
+}
+
+div.diff.extended_header {
+ background-color: #F6F5EE;
+ padding: 2px 0;
+ font-family: inherit;
+}
+
+div.diff.add {
+ color: #008800;
+ font-family: inherit;
+}
+
+div.diff.remove {
+ color: #cc0000;
+ font-family: inherit;
+}
+
+div.diff.unchanged {
+ color: inherit;
+ font-family: inherit;
+}
+
+div.diff.hunk_header {
+ -moz-border-bottom-colors: none;
+ -moz-border-image: none;
+ -moz-border-left-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-top-colors: none;
+ border-color: #FFE0FF;
+ border-style: dotted;
+ border-width: 1px 0 0;
+ margin-top: 2px;
+ font-family: inherit;
+}
+
+span.diff.hunk_info {
+ background-color: #FFEEFF;
+ color: #990099;
+ font-family: inherit;
+}
+
+span.diff.hunk_section {
+ color: #AA22AA;
+ font-family: inherit;
+}
+
a.list {
text-decoration: none;
color: #000000;
diff --git a/src/com/gitblit/tests/JGitUtilsTest.java b/src/com/gitblit/tests/JGitUtilsTest.java
index 6c398401..708f35af 100644
--- a/src/com/gitblit/tests/JGitUtilsTest.java
+++ b/src/com/gitblit/tests/JGitUtilsTest.java
@@ -16,50 +16,50 @@ import org.eclipse.jgit.storage.file.FileRepository;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.TicGitTicket;
+import com.gitblit.wicket.models.PathModel;
import com.gitblit.wicket.models.RefModel;
-
public class JGitUtilsTest extends TestCase {
-
+
private File repositoriesFolder = new File("c:/projects/git");
private boolean exportAll = true;
private boolean readNested = true;
-
+
private List<String> getRepositories() {
return JGitUtils.getRepositoryList(repositoriesFolder, exportAll, readNested);
}
-
+
private Repository getRepository() throws Exception {
return new FileRepository(new File(repositoriesFolder, getRepositories().get(0)) + "/" + Constants.DOT_GIT);
}
-
+
public void testFindRepositories() {
List<String> list = getRepositories();
assertTrue("No repositories found in " + repositoriesFolder, list.size() > 0);
}
-
- public void testOpenRepository() throws Exception {
+
+ public void testOpenRepository() throws Exception {
Repository r = getRepository();
r.close();
assertTrue("Could not find repository!", r != null);
}
-
- public void testLastChangeRepository() throws Exception {
+
+ public void testLastChangeRepository() throws Exception {
Repository r = getRepository();
Date date = JGitUtils.getLastChange(r);
r.close();
assertTrue("Could not get last repository change date!", date != null);
}
-
+
public void testRetrieveRevObject() throws Exception {
Repository r = getRepository();
RevCommit commit = JGitUtils.getCommit(r, Constants.HEAD);
RevTree tree = commit.getTree();
- RevObject object = JGitUtils.getRevObject(r, tree, "AUTHORS");
+ RevObject object = JGitUtils.getRevObject(r, tree, "AUTHORS");
r.close();
assertTrue("Object is null!", object != null);
}
-
+
public void testRetrieveStringContent() throws Exception {
Repository r = getRepository();
RevCommit commit = JGitUtils.getCommit(r, Constants.HEAD);
@@ -69,7 +69,7 @@ public class JGitUtilsTest extends TestCase {
r.close();
assertTrue("Content is null!", content != null);
}
-
+
public void testTicGit() throws Exception {
Repository r = new FileRepository(new File(repositoriesFolder, "ticgit") + "/" + Constants.DOT_GIT);
RefModel ticgit = JGitUtils.getTicGitBranch(r);
@@ -79,4 +79,20 @@ public class JGitUtilsTest extends TestCase {
r.close();
}
+ public void testFilesInCommit() throws Exception {
+ Repository r = getRepository();
+ RevCommit commit = JGitUtils.getCommit(r, Constants.HEAD);
+ List<PathModel> paths = JGitUtils.getFilesInCommit(r, commit);
+ r.close();
+ assertTrue("No changed paths found!", paths.size() > 0);
+ }
+
+ public void testCommitDiff() throws Exception {
+ Repository r = getRepository();
+ RevCommit commit = JGitUtils.getCommit(r, Constants.HEAD);
+ String diff = JGitUtils.getCommitDiff(r, commit, false);
+ r.close();
+ System.out.println(diff);
+ }
+
}
diff --git a/src/com/gitblit/utils/HtmlDiffFormatter.java b/src/com/gitblit/utils/HtmlDiffFormatter.java
new file mode 100644
index 00000000..7c37862c
--- /dev/null
+++ b/src/com/gitblit/utils/HtmlDiffFormatter.java
@@ -0,0 +1,128 @@
+package com.gitblit.utils;
+
+import static org.eclipse.jgit.lib.Constants.encodeASCII;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.diff.RawText;
+
+public class HtmlDiffFormatter extends DiffFormatter {
+ private final OutputStream os;
+
+ public HtmlDiffFormatter(OutputStream os) {
+ super(os);
+ this.os = os;
+ }
+
+ /**
+ * Output a hunk header
+ *
+ * @param aStartLine
+ * within first source
+ * @param aEndLine
+ * within first source
+ * @param bStartLine
+ * within second source
+ * @param bEndLine
+ * within second source
+ * @throws IOException
+ */
+ @Override
+ protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, int bEndLine) throws IOException {
+ os.write("<div class=\"diff hunk_header\"><span class=\"diff hunk_info\">".getBytes());
+ os.write('@');
+ os.write('@');
+ writeRange('-', aStartLine + 1, aEndLine - aStartLine);
+ writeRange('+', bStartLine + 1, bEndLine - bStartLine);
+ os.write(' ');
+ os.write('@');
+ os.write('@');
+ // TODO not sure if JGit can determine hunk section
+ //os.write("<span class=\"diff hunk_section\">".getBytes());
+ //os.write("</span>".getBytes());
+ os.write("</span></div>".getBytes());
+ }
+
+ private void writeRange(final char prefix, final int begin, final int cnt) throws IOException {
+ os.write(' ');
+ os.write(prefix);
+ switch (cnt) {
+ case 0:
+ // If the range is empty, its beginning number must
+ // be the
+ // line just before the range, or 0 if the range is
+ // at the
+ // start of the file stream. Here, begin is always 1
+ // based,
+ // so an empty file would produce "0,0".
+ //
+ os.write(encodeASCII(begin - 1));
+ os.write(',');
+ os.write('0');
+ break;
+
+ case 1:
+ // If the range is exactly one line, produce only
+ // the number.
+ //
+ os.write(encodeASCII(begin));
+ break;
+
+ default:
+ os.write(encodeASCII(begin));
+ os.write(',');
+ os.write(encodeASCII(cnt));
+ break;
+ }
+ }
+
+ @Override
+ protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException {
+ switch (prefix) {
+ case '+':
+ os.write("<div class=\"diff add\">".getBytes());
+ break;
+ case '-':
+ os.write("<div class=\"diff remove\">".getBytes());
+ break;
+ }
+ os.write(prefix);
+ text.writeLine(os, cur);
+ switch (prefix) {
+ case '+':
+ case '-':
+ os.write("</div>".getBytes());
+ break;
+ default:
+ os.write('\n');
+ }
+ }
+
+ /**
+ * Workaround function for complex private methods in DiffFormatter. This
+ * sets the html for the diff headers.
+ *
+ * @return
+ */
+ public String getHtml() {
+ String html = os.toString();
+ String[] lines = html.split("\n");
+ StringBuilder sb = new StringBuilder();
+ sb.append("<div class=\"diff\">");
+ for (String line : lines) {
+ if (line.startsWith("diff")) {
+ sb.append("<div class=\"diff header\">").append(line).append("</div>");
+ } else if (line.startsWith("---")) {
+ sb.append("<div class=\"diff remove\">").append(line).append("</div>");
+ } else if (line.startsWith("+++")) {
+ sb.append("<div class=\"diff add\">").append(line).append("</div>");
+ } else {
+ sb.append(line).append('\n');
+ }
+ }
+ sb.append("</div>");
+ return sb.toString();
+ }
+}
diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index b4e0b151..1b418b08 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -17,6 +17,9 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
@@ -35,6 +38,8 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.io.DisabledOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -243,29 +248,89 @@ public class JGitUtils {
return list;
}
- public static List<PathModel> getCommitChangedPaths(Repository r, String commitId) {
+ public static List<PathModel> getFilesInCommit(Repository r, String commitId) {
RevCommit commit = getCommit(r, commitId);
- return getCommitChangedPaths(r, commit);
+ return getFilesInCommit(r, commit);
}
- public static List<PathModel> getCommitChangedPaths(Repository r, RevCommit commit) {
+ public static List<PathModel> getFilesInCommit(Repository r, RevCommit commit) {
List<PathModel> list = new ArrayList<PathModel>();
- final TreeWalk walk = new TreeWalk(r);
- walk.setRecursive(false);
try {
- walk.addTree(commit.getTree());
- while (walk.next()) {
- list.add(getPathModel(walk, null, commit));
+ final RevWalk rw = new RevWalk(r);
+ RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
+ RevTree parentTree = parent.getTree();
+ RevTree commitTree = commit.getTree();
+
+ final TreeWalk walk = new TreeWalk(r);
+ walk.reset();
+ walk.setRecursive(true);
+ walk.addTree(parentTree);
+ walk.addTree(commitTree);
+ walk.setFilter(TreeFilter.ANY_DIFF);
+
+ RawTextComparator cmp = RawTextComparator.DEFAULT;
+ DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
+ df.setRepository(r);
+ df.setDiffComparator(cmp);
+ df.setDetectRenames(true);
+ List<DiffEntry> diffs = df.scan(parentTree, commitTree);
+ for (DiffEntry diff : diffs) {
+ list.add(new PathModel(diff.getNewPath(), diff.getNewPath(), 0, diff.getNewMode().getBits(), commit.getId().getName()));
}
+ } catch (Throwable t) {
+ LOGGER.error("failed to determine files in commit!", t);
+ }
+ return list;
+ }
- } catch (IOException e) {
- LOGGER.error("Failed to get files for commit " + commit.getName(), e);
- } finally {
- if (walk != null) {
- walk.release();
+ public static String getCommitDiff(Repository r, RevCommit commit, boolean outputHtml) {
+ return getCommitDiff(r, commit, null, outputHtml);
+ }
+
+ public static String getCommitDiff(Repository r, RevCommit commit, String path, boolean outputHtml) {
+ try {
+ final RevWalk rw = new RevWalk(r);
+ RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
+ RevTree parentTree = parent.getTree();
+ RevTree commitTree = commit.getTree();
+
+ final TreeWalk walk = new TreeWalk(r);
+ walk.reset();
+ walk.setRecursive(true);
+ walk.addTree(parentTree);
+ walk.addTree(commitTree);
+ if (path != null && path.trim().length() > 0) {
+ walk.setFilter(PathFilter.create(path));
+ } else {
+ walk.setFilter(TreeFilter.ANY_DIFF);
+ }
+
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ RawTextComparator cmp = RawTextComparator.DEFAULT;
+ DiffFormatter df;
+ if (outputHtml) {
+ df = new HtmlDiffFormatter(os);
+ } else {
+ df = new DiffFormatter(os);
+ }
+ df.setRepository(r);
+ df.setDiffComparator(cmp);
+ df.setDetectRenames(true);
+ List<DiffEntry> diffs = df.scan(parentTree, commitTree);
+ df.format(diffs);
+ String diff;
+ if (outputHtml) {
+ // workaround for complex private methods in DiffFormatter
+ diff = ((HtmlDiffFormatter) df).getHtml();
+ } else {
+ diff = os.toString();
}
+ df.flush();
+ return diff;
+ } catch (Throwable t) {
+ LOGGER.error("failed to generate commit diff!", t);
}
- return list;
+ return null;
}
private static PathModel getPathModel(TreeWalk walk, String basePath, RevCommit commit) {
@@ -519,7 +584,7 @@ public class JGitUtils {
}
return null;
}
-
+
private static void readTicketContents(Repository r, RefModel ticgitBranch, TicGitTicket ticket) {
List<PathModel> ticketFiles = getFilesInPath(r, ticket.name, ticgitBranch.getCommit());
for (PathModel file : ticketFiles) {
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.java b/src/com/gitblit/wicket/GitBlitWebApp.java
index 6e8a6dd5..70bb9702 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/com/gitblit/wicket/GitBlitWebApp.java
@@ -31,6 +31,7 @@ import com.gitblit.wicket.models.RepositoryModel;
import com.gitblit.wicket.pages.BlobPage;
import com.gitblit.wicket.pages.BranchesPage;
import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.DiffPage;
import com.gitblit.wicket.pages.RepositoriesPage;
import com.gitblit.wicket.pages.ShortLogPage;
import com.gitblit.wicket.pages.SummaryPage;
@@ -69,6 +70,7 @@ public class GitBlitWebApp extends WebApplication {
mount(new MixedParamUrlCodingStrategy("/tag", TagPage.class, new String[] { "p", "h" }));
mount(new MixedParamUrlCodingStrategy("/tree", TreePage.class, new String[] { "p", "h", "f" }));
mount(new MixedParamUrlCodingStrategy("/blob", BlobPage.class, new String[] { "p", "h", "f" }));
+ mount(new MixedParamUrlCodingStrategy("/diff", DiffPage.class, new String[] { "p", "h", "f" }));
// setup extended urls
mount(new MixedParamUrlCodingStrategy("/ticgit", TicGitPage.class, new String[] { "p" }));
diff --git a/src/com/gitblit/wicket/pages/CommitPage.java b/src/com/gitblit/wicket/pages/CommitPage.java
index ad1fce06..0754532b 100644
--- a/src/com/gitblit/wicket/pages/CommitPage.java
+++ b/src/com/gitblit/wicket/pages/CommitPage.java
@@ -76,7 +76,7 @@ public class CommitPage extends RepositoryPage {
addFullText("fullMessage", c.getFullMessage(), true);
// changed paths list
- List<PathModel> paths = JGitUtils.getCommitChangedPaths(r, c);
+ List<PathModel> paths = JGitUtils.getFilesInCommit(r, c);
ListDataProvider<PathModel> pathsDp = new ListDataProvider<PathModel>(paths);
DataView<PathModel> pathsView = new DataView<PathModel>("changedPath", pathsDp) {
private static final long serialVersionUID = 1L;
diff --git a/src/com/gitblit/wicket/pages/DiffPage.html b/src/com/gitblit/wicket/pages/DiffPage.html
new file mode 100644
index 00000000..b7aa03b2
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/DiffPage.html
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<head>
+ <link href="prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="prettify/prettify.js"></script>
+</head>
+<body onload="prettyPrint()">
+ <!-- page header -->
+ <div wicket:id="pageHeader"></div>
+
+ <!-- page nav links -->
+ <div wicket:id="pageLinks"></div>
+
+ <!-- blob nav links -->
+ <div class="page_nav2">
+ <span wicket:id="historyLink"></span> | <span wicket:id="rawLink"></span> | <span wicket:id="headLink"></span>
+ </div>
+
+ <!-- shortlog header -->
+ <div class="header" wicket:id="shortlog"></div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs"></div>
+
+ <!-- diff content -->
+ <pre wicket:id="diffText"></pre>
+
+ <!-- footer -->
+ <div wicket:id="pageFooter"></div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/DiffPage.java b/src/com/gitblit/wicket/pages/DiffPage.java
new file mode 100644
index 00000000..05500f83
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/DiffPage.java
@@ -0,0 +1,46 @@
+package com.gitblit.wicket.pages;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.wicket.LinkPanel;
+import com.gitblit.wicket.RepositoryPage;
+import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
+
+public class DiffPage extends RepositoryPage {
+
+ public DiffPage(PageParameters params) {
+ super(params, "diff");
+
+ final String blobPath = params.getString("f", null);
+
+ Repository r = getRepository();
+ RevCommit commit = JGitUtils.getCommit(r, commitId);
+ String diff;
+ if (blobPath != null && blobPath.length() > 0) {
+ // blob diff
+ diff = JGitUtils.getCommitDiff(r, commit, blobPath, true);
+ } else {
+ // commit diff
+ diff = JGitUtils.getCommitDiff(r, commit, true);
+ }
+ r.close();
+
+ // diff page links
+ add(new Label("historyLink", "history"));
+ add(new Label("rawLink", "raw"));
+ add(new Label("headLink", "HEAD"));
+
+ add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
+
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, commitId));
+
+ add(new Label("diffText", diff).setEscapeModelStrings(false));
+
+ // footer
+ addFooter();
+ }
+}
diff --git a/src/com/gitblit/wicket/panels/PathLinksPanel.java b/src/com/gitblit/wicket/panels/PathLinksPanel.java
index c29124be..49aeb4ac 100644
--- a/src/com/gitblit/wicket/panels/PathLinksPanel.java
+++ b/src/com/gitblit/wicket/panels/PathLinksPanel.java
@@ -7,6 +7,7 @@ import org.apache.wicket.markup.html.panel.Panel;
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.models.PathModel;
import com.gitblit.wicket.pages.BlobPage;
+import com.gitblit.wicket.pages.DiffPage;
public class PathLinksPanel extends Panel {
@@ -15,7 +16,7 @@ public class PathLinksPanel extends Panel {
public PathLinksPanel(String id, String repositoryName, PathModel path) {
super(id);
- add(new Label("diff", "diff"));
+ add(new LinkPanel("diff", null, "diff", DiffPage.class, new PageParameters("p=" + repositoryName + ",h=" + path.commitId + ",f=" + path.path)));
add(new LinkPanel("blob", null, "view", BlobPage.class, new PageParameters("p=" + repositoryName + ",h=" + path.commitId + ",f=" + path.path)));
add(new Label("history", "history"));
}
diff --git a/src/com/gitblit/wicket/panels/ShortLogLinksPanel.java b/src/com/gitblit/wicket/panels/ShortLogLinksPanel.java
index 58ec37ac..51c894db 100644
--- a/src/com/gitblit/wicket/panels/ShortLogLinksPanel.java
+++ b/src/com/gitblit/wicket/panels/ShortLogLinksPanel.java
@@ -1,11 +1,11 @@
package com.gitblit.wicket.panels;
import org.apache.wicket.PageParameters;
-import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.DiffPage;
import com.gitblit.wicket.pages.TreePage;
@@ -17,7 +17,7 @@ public class ShortLogLinksPanel extends Panel {
super(id);
add(new LinkPanel("commit", null, "commit", CommitPage.class, new PageParameters("p=" + repositoryName + ",h=" + commitId)));
- add(new Label("commitdiff", "commitdiff"));
+ add(new LinkPanel("commitdiff", null, "commitdiff", DiffPage.class, new PageParameters("p=" + repositoryName + ",h=" + commitId)));
add(new LinkPanel("tree", null, "tree", TreePage.class, new PageParameters("p=" + repositoryName + ",h=" + commitId)));
}
} \ No newline at end of file