diff options
author | Tom <tw201207@gmail.com> | 2014-11-11 07:52:15 +0100 |
---|---|---|
committer | Tom <tw201207@gmail.com> | 2014-11-11 08:00:30 +0100 |
commit | 7dd99fe7474604f314c01bcd4123eb7cbacfb583 (patch) | |
tree | 84f3b0da388cdc79c2b31e6fab5619fc1617e455 /src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java | |
parent | 8cd4feca58b55f311a543c744777e930c4f4b34a (diff) | |
download | gitblit-7dd99fe7474604f314c01bcd4123eb7cbacfb583.tar.gz gitblit-7dd99fe7474604f314c01bcd4123eb7cbacfb583.zip |
Image diffs
Ticket 88: https://dev.gitblit.com/tickets/gitblit.git/88
Based on Lea Verou's pure CSS slider:
http://lea.verou.me/2014/07/image-comparison-slider-with-pure-css/
* Add a callback interface, pass it through DiffUtils to the
GitBlitDiffFormatter. Is needed because the rendering needs access
to the repositoryName and other things that are known only at higher
levels.
* New class ImageDiffHandler responsible for rendering an image diff.
Called for all binary diffs, doesn't do anything if it's not an
image. HTML is generated via JSoup: no worries about forgetting to
close a tag, not about HTML escaping, nor about XSS.
* The 3 diff pages set up such an ImageDIffHandler and pass it along.
* CSS changes: from Lea Verou, with some minor improvements.
I think in the long run there'll be no way around rewriting the
HTML diff formatter from scratch, not using the standard JGit
DiffFormatter at all.
Diffstat (limited to 'src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java')
-rw-r--r-- | src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java index 5de9e50a..edaed70f 100644 --- a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java +++ b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java @@ -19,8 +19,10 @@ import static org.eclipse.jgit.lib.Constants.encode; import static org.eclipse.jgit.lib.Constants.encodeASCII; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -34,6 +36,7 @@ import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.util.RawParseUtils; import com.gitblit.models.PathModel.PathChangeModel; +import com.gitblit.utils.DiffUtils.BinaryDiffHandler; import com.gitblit.utils.DiffUtils.DiffStat; import com.gitblit.wicket.GitBlitWebApp; @@ -71,7 +74,7 @@ public class GitBlitDiffFormatter extends DiffFormatter { */ private static final int GLOBAL_DIFF_LIMIT = 20000; - private final ResettableByteArrayOutputStream os; + private final DiffOutputStream os; private final DiffStat diffStat; @@ -122,9 +125,45 @@ public class GitBlitDiffFormatter extends DiffFormatter { /** If {@link #truncated}, contains all entries skipped. */ private final List<DiffEntry> skipped = new ArrayList<DiffEntry>(); - public GitBlitDiffFormatter(String commitId, String path) { - super(new ResettableByteArrayOutputStream()); - this.os = (ResettableByteArrayOutputStream) getOutputStream(); + /** + * A {@link ResettableByteArrayOutputStream} that intercept the "Binary files differ" message produced + * by the super implementation. Unfortunately the super implementation has far too many things private; + * otherwise we'd just have re-implemented {@link GitBlitDiffFormatter#format(DiffEntry) format(DiffEntry)} + * completely without ever calling the super implementation. + */ + private static class DiffOutputStream extends ResettableByteArrayOutputStream { + + private static final String BINARY_DIFFERENCE = "Binary files differ\n"; + + private GitBlitDiffFormatter formatter; + private BinaryDiffHandler binaryDiffHandler; + + public void setFormatter(GitBlitDiffFormatter formatter, BinaryDiffHandler handler) { + this.formatter = formatter; + this.binaryDiffHandler = handler; + } + + @Override + public void write(byte[] b, int offset, int length) { + if (binaryDiffHandler != null + && RawParseUtils.decode(Arrays.copyOfRange(b, offset, offset + length)).contains(BINARY_DIFFERENCE)) + { + String binaryDiff = binaryDiffHandler.renderBinaryDiff(formatter.entry); + if (binaryDiff != null) { + byte[] bb = ("<tr><td colspan='4'>" + binaryDiff + "</td></tr>").getBytes(StandardCharsets.UTF_8); + super.write(bb, 0, bb.length); + return; + } + } + super.write(b, offset, length); + } + + } + + public GitBlitDiffFormatter(String commitId, String path, BinaryDiffHandler handler) { + super(new DiffOutputStream()); + this.os = (DiffOutputStream) getOutputStream(); + this.os.setFormatter(this, handler); this.diffStat = new DiffStat(commitId); // If we have a full commitdiff, install maxima to avoid generating a super-long diff listing that // will only tax the browser too much. @@ -217,7 +256,7 @@ public class GitBlitDiffFormatter extends DiffFormatter { super.format(ent); if (!truncated) { // Close the table - os.write("</tbody></table></div><br />\n".getBytes()); + os.write("</tbody></table></div>\n".getBytes()); } } @@ -235,13 +274,7 @@ public class GitBlitDiffFormatter extends DiffFormatter { private void reset() { if (!isOff) { os.resetTo(startCurrent); - try { - os.write("<tr><td class='diff-cell' colspan='4'>".getBytes()); - os.write(StringUtils.escapeForHtml(getMsg("gb.diffFileDiffTooLarge", "Diff too large"), false).getBytes()); - os.write("</td></tr>\n".getBytes()); - } catch (IOException ex) { - // Cannot happen with a ByteArrayOutputStream - } + writeFullWidthLine(getMsg("gb.diffFileDiffTooLarge", "Diff too large")); totalNofLinesCurrent = totalNofLinesPrevious; isOff = true; } @@ -277,13 +310,7 @@ public class GitBlitDiffFormatter extends DiffFormatter { default: return; } - try { - os.write("<tr><td class='diff-cell' colspan='4'>".getBytes()); - os.write(StringUtils.escapeForHtml(message, false).getBytes()); - os.write("</td></tr>\n".getBytes()); - } catch (IOException ex) { - // Cannot happen with a ByteArrayOutputStream - } + writeFullWidthLine(message); } /** @@ -355,6 +382,22 @@ public class GitBlitDiffFormatter extends DiffFormatter { } } + /** + * Writes a line spanning the full width of the code view, including the gutter. + * + * @param text + * to put on that line; will be HTML-escaped. + */ + private void writeFullWidthLine(String text) { + try { + os.write("<tr><td class='diff-cell' colspan='4'>".getBytes()); + os.write(StringUtils.escapeForHtml(text, false).getBytes()); + os.write("</td></tr>\n".getBytes()); + } catch (IOException ex) { + // Cannot happen with a ByteArrayOutputStream + } + } + @Override protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException { if (nofLinesCurrent++ == 0) { @@ -453,6 +496,7 @@ public class GitBlitDiffFormatter extends DiffFormatter { if (gitLinkDiff) { sb.append("</td></tr>"); } + sb.append('\n'); } } if (truncated) { |