From: James Moger Date: Thu, 21 Apr 2011 02:14:37 +0000 (-0400) Subject: Selectable diff presentation: gitblit, gitweb, or plain. X-Git-Tag: v0.5.0~70 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3df3496185d229e6f1cdeb6f182f7933884ca29c;p=gitblit.git Selectable diff presentation: gitblit, gitweb, or plain. --- diff --git a/gitblit.properties b/gitblit.properties index ae3866d2..48515a15 100644 --- a/gitblit.properties +++ b/gitblit.properties @@ -59,6 +59,9 @@ web.useClientTimezone = false web.datestampShortFormat = yyyy-MM-dd web.datetimestampLongFormat = EEEE, MMMM d, yyyy h:mm a z +# Choose the diff presentation style: gitblt, gitweb, or plain +web.diffStyle = gitblit + # Generates a line graph of repository activity over time on the Summary page. # This is a real-time graph so generation may be expensive. web.generateActivityGraph = true diff --git a/src/com/gitblit/tests/JGitUtilsTest.java b/src/com/gitblit/tests/JGitUtilsTest.java index f3c798f1..196058c5 100644 --- a/src/com/gitblit/tests/JGitUtilsTest.java +++ b/src/com/gitblit/tests/JGitUtilsTest.java @@ -15,6 +15,7 @@ import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.storage.file.FileRepository; import com.gitblit.utils.JGitUtils; +import com.gitblit.utils.JGitUtils.DiffOutputType; import com.gitblit.wicket.models.PathModel.PathChangeModel; import com.gitblit.wicket.models.RefModel; import com.gitblit.wicket.models.TicketModel; @@ -98,7 +99,7 @@ public class JGitUtilsTest extends TestCase { public void testCommitDiff() throws Exception { Repository r = getRepository(); RevCommit commit = JGitUtils.getCommit(r, Constants.HEAD); - String diff = JGitUtils.getCommitDiff(r, commit, false); + String diff = JGitUtils.getCommitDiff(r, commit, DiffOutputType.PLAIN); r.close(); System.out.println(diff); } diff --git a/src/com/gitblit/utils/GitBlitDiffFormatter.java b/src/com/gitblit/utils/GitBlitDiffFormatter.java new file mode 100644 index 00000000..54cb6c29 --- /dev/null +++ b/src/com/gitblit/utils/GitBlitDiffFormatter.java @@ -0,0 +1,127 @@ +package com.gitblit.utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.eclipse.jgit.diff.RawText; + +public class GitBlitDiffFormatter extends GitWebDiffFormatter { + + private final OutputStream os; + + private int left = 0, right = 0; + + public GitBlitDiffFormatter(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("....".getBytes()); + os.write('@'); + os.write('@'); + writeRange('-', aStartLine + 1, aEndLine - aStartLine); + writeRange('+', bStartLine + 1, bEndLine - bStartLine); + os.write(' '); + os.write('@'); + os.write('@'); + os.write("\n".getBytes()); + left = aStartLine + 1; + right = bStartLine + 1; + } + + @Override + protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException { + os.write("".getBytes()); + switch (prefix) { + case '+': + os.write(("" + (right++) + "").getBytes()); + os.write("
".getBytes()); + break; + case '-': + os.write(("" + (left++) + "").getBytes()); + os.write("
".getBytes()); + break; + default: + os.write(("" + (left++) + "" + (right++) + "").getBytes()); + os.write("".getBytes()); + break; + } + os.write(prefix); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + text.writeLine(bos, cur); + String line = bos.toString(); + line = StringUtils.escapeForHtml(line, false); + os.write(line.getBytes()); + switch (prefix) { + case '+': + case '-': + os.write("
".getBytes()); + break; + default: + os.write("".getBytes()); + } + os.write("\n".getBytes()); + } + + /** + * Workaround function for complex private methods in DiffFormatter. This + * sets the html for the diff headers. + * + * @return + */ + @Override + public String getHtml() { + String html = os.toString(); + String[] lines = html.split("\n"); + StringBuilder sb = new StringBuilder(); + boolean inFile = false; + String oldnull = "a/dev/null"; + for (String line : lines) { + if (line.startsWith("index")) { + // skip index lines + } else if (line.startsWith("new file")) { + // skip new file lines + } else if (line.startsWith("diff")) { + if (line.indexOf(oldnull) > -1) { + // a is null, use b + line = line.substring(("diff --git " + oldnull).length()).trim(); + line = line.substring(2); // trim b/ + } else { + // use a + line = line.substring("diff --git a/".length()).trim(); + line = line.substring(0, line.indexOf(" b/")).trim(); + } + if (inFile) { + sb.append("
\n"); + inFile = false; + } + sb.append("
").append(line).append("
"); + sb.append("
"); + sb.append(""); + inFile = true; + } else if (line.startsWith("---") || line.startsWith("+++")) { + // skip --- +++ lines + } else { + sb.append(line).append('\n'); + } + } + sb.append("
"); + return sb.toString(); + } +} diff --git a/src/com/gitblit/utils/GitWebDiffFormatter.java b/src/com/gitblit/utils/GitWebDiffFormatter.java new file mode 100644 index 00000000..2ac0a568 --- /dev/null +++ b/src/com/gitblit/utils/GitWebDiffFormatter.java @@ -0,0 +1,131 @@ +package com.gitblit.utils; + +import static org.eclipse.jgit.lib.Constants.encodeASCII; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.RawText; + +public class GitWebDiffFormatter extends DiffFormatter { + + private final OutputStream os; + + public GitWebDiffFormatter(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("
".getBytes()); + os.write('@'); + os.write('@'); + writeRange('-', aStartLine + 1, aEndLine - aStartLine); + writeRange('+', bStartLine + 1, bEndLine - bStartLine); + os.write(' '); + os.write('@'); + os.write('@'); + os.write("
".getBytes()); + } + + protected 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("".getBytes()); + break; + case '-': + os.write("".getBytes()); + break; + } + os.write(prefix); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + text.writeLine(bos, cur); + String line = bos.toString(); + line = StringUtils.escapeForHtml(line, false); + os.write(line.getBytes()); + switch (prefix) { + case '+': + case '-': + os.write("\n".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("
"); + for (String line : lines) { + if (line.startsWith("diff")) { + sb.append("
").append(line).append("
"); + } else if (line.startsWith("---")) { + sb.append("").append(line).append("
"); + } else if (line.startsWith("+++")) { + sb.append("").append(line).append("
"); + } else { + sb.append(line).append('\n'); + } + } + sb.append("
\n"); + return sb.toString(); + } +} diff --git a/src/com/gitblit/utils/HtmlDiffFormatter.java b/src/com/gitblit/utils/HtmlDiffFormatter.java deleted file mode 100644 index 24cdd8ac..00000000 --- a/src/com/gitblit/utils/HtmlDiffFormatter.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.gitblit.utils; - -import static org.eclipse.jgit.lib.Constants.encodeASCII; - -import java.io.ByteArrayOutputStream; -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("
".getBytes()); - os.write('@'); - os.write('@'); - writeRange('-', aStartLine + 1, aEndLine - aStartLine); - writeRange('+', bStartLine + 1, bEndLine - bStartLine); - os.write(' '); - os.write('@'); - os.write('@'); - os.write("
".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("".getBytes()); - break; - case '-': - os.write("".getBytes()); - break; - } - os.write(prefix); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - text.writeLine(bos, cur); - String line = bos.toString(); - line = StringUtils.escapeForHtml(line, false); - os.write(line.getBytes()); - switch (prefix) { - case '+': - case '-': - os.write("\n".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("
"); - for (String line : lines) { - if (line.startsWith("diff")) { - sb.append("
").append(line).append("
"); - } else if (line.startsWith("---")) { - sb.append("").append(line).append("
"); - } else if (line.startsWith("+++")) { - sb.append("").append(line).append("
"); - } else { - sb.append(line).append('\n'); - } - } - sb.append("
\n"); - return sb.toString(); - } -} diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java index daeb6389..5118425e 100644 --- a/src/com/gitblit/utils/JGitUtils.java +++ b/src/com/gitblit/utils/JGitUtils.java @@ -326,19 +326,32 @@ public class JGitUtils { return list; } - public static String getCommitDiff(Repository r, RevCommit commit, boolean outputHtml) { - return getCommitDiff(r, null, commit, null, outputHtml); + public static enum DiffOutputType { + PLAIN, GITWEB, GITBLIT; + + public static DiffOutputType forName(String name) { + for (DiffOutputType type : values()) { + if (type.name().equalsIgnoreCase(name)) { + return type; + } + } + return null; + } + } + + public static String getCommitDiff(Repository r, RevCommit commit, DiffOutputType outputType) { + return getCommitDiff(r, null, commit, null, outputType); } - public static String getCommitDiff(Repository r, RevCommit commit, String path, boolean outputHtml) { - return getCommitDiff(r, null, commit, path, outputHtml); + public static String getCommitDiff(Repository r, RevCommit commit, String path, DiffOutputType outputType) { + return getCommitDiff(r, null, commit, path, outputType); } - public static String getCommitDiff(Repository r, RevCommit baseCommit, RevCommit commit, boolean outputHtml) { - return getCommitDiff(r, baseCommit, commit, null, outputHtml); + public static String getCommitDiff(Repository r, RevCommit baseCommit, RevCommit commit, DiffOutputType outputType) { + return getCommitDiff(r, baseCommit, commit, null, outputType); } - public static String getCommitDiff(Repository r, RevCommit baseCommit, RevCommit commit, String path, boolean outputHtml) { + public static String getCommitDiff(Repository r, RevCommit baseCommit, RevCommit commit, String path, DiffOutputType outputType) { try { RevTree baseTree; if (baseCommit == null) { @@ -362,10 +375,17 @@ public class JGitUtils { final ByteArrayOutputStream os = new ByteArrayOutputStream(); RawTextComparator cmp = RawTextComparator.DEFAULT; DiffFormatter df; - if (outputHtml) { - df = new HtmlDiffFormatter(os); - } else { + switch (outputType) { + case GITWEB: + df = new GitWebDiffFormatter(os); + break; + case GITBLIT: + df = new GitBlitDiffFormatter(os); + break; + case PLAIN: + default: df = new DiffFormatter(os); + break; } df.setRepository(r); df.setDiffComparator(cmp); @@ -382,9 +402,9 @@ public class JGitUtils { df.format(diffs); } String diff; - if (outputHtml) { + if (df instanceof GitWebDiffFormatter) { // workaround for complex private methods in DiffFormatter - diff = ((HtmlDiffFormatter) df).getHtml(); + diff = ((GitWebDiffFormatter) df).getHtml(); } else { diff = os.toString(); } @@ -750,21 +770,21 @@ public class JGitUtils { df = new SimpleDateFormat("yyyy-MM"); } walk.markStart(lastCommit); - + Iterable revlog = walk; for (RevCommit rev : revlog) { Date d = getCommitDate(rev); String p = df.format(d); if (!metricMap.containsKey(p)) metricMap.put(p, new Metric(p)); - Metric m = metricMap.get(p); + Metric m = metricMap.get(p); m.count++; total.count++; if (tagMap.containsKey(rev.getId())) { m.tag++; total.tag++; } - } + } } catch (Throwable t) { LOGGER.error("Failed to mine log history for metrics", t); } diff --git a/src/com/gitblit/wicket/pages/BlobDiffPage.java b/src/com/gitblit/wicket/pages/BlobDiffPage.java index bb471712..99f44db6 100644 --- a/src/com/gitblit/wicket/pages/BlobDiffPage.java +++ b/src/com/gitblit/wicket/pages/BlobDiffPage.java @@ -6,8 +6,11 @@ import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import com.gitblit.GitBlit; +import com.gitblit.Keys; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; +import com.gitblit.utils.JGitUtils.DiffOutputType; import com.gitblit.wicket.LinkPanel; import com.gitblit.wicket.RepositoryPage; import com.gitblit.wicket.WicketUtils; @@ -24,15 +27,17 @@ public class BlobDiffPage extends RepositoryPage { Repository r = getRepository(); RevCommit commit = JGitUtils.getCommit(r, objectId); + DiffOutputType diffType = DiffOutputType.forName(GitBlit.self().settings().getString(Keys.web.diffStyle, DiffOutputType.GITBLIT.name())); + String diff; if (StringUtils.isEmpty(baseObjectId)) { // use first parent - diff = JGitUtils.getCommitDiff(r, commit, blobPath, true); + diff = JGitUtils.getCommitDiff(r, commit, blobPath, diffType); add(new BookmarkablePageLink("patchLink", PatchPage.class, WicketUtils.newPathParameter(repositoryName, objectId, blobPath))); } else { // base commit specified RevCommit baseCommit = JGitUtils.getCommit(r, baseObjectId); - diff = JGitUtils.getCommitDiff(r, baseCommit, commit, blobPath, true); + diff = JGitUtils.getCommitDiff(r, baseCommit, commit, blobPath, diffType); add(new BookmarkablePageLink("patchLink", PatchPage.class, WicketUtils.newBlobDiffParameter(repositoryName, baseObjectId, objectId, blobPath))); } diff --git a/src/com/gitblit/wicket/pages/CommitDiffPage.java b/src/com/gitblit/wicket/pages/CommitDiffPage.java index d52b7a36..c6f1f7d3 100644 --- a/src/com/gitblit/wicket/pages/CommitDiffPage.java +++ b/src/com/gitblit/wicket/pages/CommitDiffPage.java @@ -12,7 +12,10 @@ import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import com.gitblit.GitBlit; +import com.gitblit.Keys; import com.gitblit.utils.JGitUtils; +import com.gitblit.utils.JGitUtils.DiffOutputType; import com.gitblit.wicket.LinkPanel; import com.gitblit.wicket.RepositoryPage; import com.gitblit.wicket.WicketUtils; @@ -25,7 +28,8 @@ public class CommitDiffPage extends RepositoryPage { Repository r = getRepository(); RevCommit commit = JGitUtils.getCommit(r, objectId); - String diff = JGitUtils.getCommitDiff(r, commit, true); + DiffOutputType diffType = DiffOutputType.forName(GitBlit.self().settings().getString(Keys.web.diffStyle, DiffOutputType.GITBLIT.name())); + String diff = JGitUtils.getCommitDiff(r, commit, diffType); List parents = new ArrayList(); if (commit.getParentCount() > 0) { diff --git a/src/com/gitblit/wicket/resources/gitblit.css b/src/com/gitblit/wicket/resources/gitblit.css index 3c5aca8b..eff6f2af 100644 --- a/src/com/gitblit/wicket/resources/gitblit.css +++ b/src/com/gitblit/wicket/resources/gitblit.css @@ -221,6 +221,7 @@ div.bug_hold, span.bug_hold { div.diff { font-family: monospace; + overflow: auto; } div.diff.header { @@ -283,6 +284,59 @@ span.diff.hunk_section { font-family: inherit; } +div.diff.add2 { + background-color: #DDFFDD; + font-family: inherit; +} + +div.diff.remove2 { + background-color: #FFDDDD; + font-family: inherit; +} + +div.diff table { + border-right: 1px solid #bbb; + border-bottom: 1px solid #bbb; + width: 100%; +} + +div.diff table th, div.diff table td { + margin: 0px; + padding: 0px; + font-family: monospace; +} + +div.diff table th { + background-color: #faf8dc; + border-left: 1px solid #bbb; + text-align: center; + color: #999; + padding-left: 5px; + padding-right: 5px; +} + +div.diff table th.header { + background-color: #D2C3AF; + border-right: 0px; + border-bottom: 1px solid #808080; + font-family: inherit; + font-size:0.9em; + color: black; + padding: 2px; + text-align: left; +} + +div.diff table td.hunk_header { + background-color: #dAe2e5 !important; + border-bottom: 1px solid #bac2c5; + color: #555; +} + +div.diff table td { + border-left: 1px solid #bbb; + background-color: #fbfbfb; +} + span.addition, span.modification, span.deletion, span.rename { border: 1px solid #888; float: left;