James Moger
2011-04-13 608ecec9dff2ea4ce8e2a1ea6fc8909a64492a68
Patch formatter.  Ensure html escaping. css tweaks.
2 files renamed
1 files deleted
8 files added
19 files modified
732 ■■■■ changed files
src/com/gitblit/tests/JGitUtilsTest.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/utils/HtmlDiffFormatter.java 23 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/JGitUtils.java 78 ●●●● patch | view | raw | blame | history
src/com/gitblit/utils/PatchFormatter.java 111 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/Utils.java 47 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.java 12 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.properties 4 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/WicketUtils.java 3 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/models/TicGitTicket.java 5 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BlobDiffPage.html 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BlobDiffPage.java 44 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BlobPage.html 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BlobPage.java 7 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitDiffPage.html 38 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitDiffPage.java 80 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitPage.html 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitPage.java 9 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/DiffPage.java 48 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/PatchPage.html 13 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/PatchPage.java 46 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RawPage.html 13 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RawPage.java 91 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TagPage.html 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TagPage.java 15 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TicGitPage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TicGitTicketPage.java 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TreePage.html 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TreePage.java 6 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/panels/LogPanel.java 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/resources/gitblit.css 15 ●●●● patch | view | raw | blame | history
src/com/gitblit/tests/JGitUtilsTest.java
@@ -15,9 +15,9 @@
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;
import com.gitblit.wicket.models.TicGitTicket;
public class JGitUtilsTest extends TestCase {
src/com/gitblit/utils/HtmlDiffFormatter.java
@@ -2,6 +2,7 @@
import static org.eclipse.jgit.lib.Constants.encodeASCII;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -9,6 +10,7 @@
import org.eclipse.jgit.diff.RawText;
public class HtmlDiffFormatter extends DiffFormatter {
    private final OutputStream os;
    public HtmlDiffFormatter(OutputStream os) {
@@ -39,9 +41,6 @@
        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());
    }
@@ -82,18 +81,22 @@
    protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException {
        switch (prefix) {
        case '+':
            os.write("<div class=\"diff add\">".getBytes());
            os.write("<span class=\"diff add\">".getBytes());
            break;
        case '-':
            os.write("<div class=\"diff remove\">".getBytes());
            os.write("<span class=\"diff remove\">".getBytes());
            break;
        }
        os.write(prefix);
        text.writeLine(os, cur);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        text.writeLine(bos, cur);
        String line = bos.toString();
        line = Utils.escapeForHtml(line, false);
        os.write(line.getBytes());
        switch (prefix) {
        case '+':
        case '-':
            os.write("</div>".getBytes());
            os.write("</span>\n".getBytes());
            break;
        default:
            os.write('\n');
@@ -115,14 +118,14 @@
            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>");
                sb.append("<span class=\"diff remove\">").append(line).append("</span><br/>");
            } else if (line.startsWith("+++")) {
                sb.append("<div class=\"diff add\">").append(line).append("</div>");
                sb.append("<span class=\"diff add\">").append(line).append("</span><br/>");
            } else {
                sb.append(line).append('\n');
            }
        }
        sb.append("</div>");
        sb.append("</div>\n");
        return sb.toString();
    }
}
src/com/gitblit/utils/JGitUtils.java
@@ -42,10 +42,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.utils.TicGitTicket.Comment;
import com.gitblit.wicket.models.Metric;
import com.gitblit.wicket.models.PathModel;
import com.gitblit.wicket.models.RefModel;
import com.gitblit.wicket.models.TicGitTicket;
import com.gitblit.wicket.models.TicGitTicket.Comment;
public class JGitUtils {
@@ -98,12 +99,15 @@
        return getCommitDate(commit);
    }
    public static RevCommit getCommit(Repository r, String commitId) {
    public static RevCommit getCommit(Repository r, String objectId) {
        RevCommit commit = null;
        try {
            ObjectId objectId = r.resolve(commitId);
            if (objectId == null || objectId.trim().length() == 0) {
                objectId = Constants.HEAD;
            }
            ObjectId object = r.resolve(objectId);
            RevWalk walk = new RevWalk(r);
            RevCommit rev = walk.parseCommit(objectId);
            RevCommit rev = walk.parseCommit(object);
            commit = rev;
            walk.dispose();
        } catch (Throwable t) {
@@ -205,8 +209,8 @@
        return new String(getRawContent(r, (RevBlob) obj));
    }
    public static List<PathModel> getFilesInPath(Repository r, String basePath, String commitId) {
        RevCommit commit = getCommit(r, commitId);
    public static List<PathModel> getFilesInPath(Repository r, String basePath, String objectId) {
        RevCommit commit = getCommit(r, objectId);
        return getFilesInPath(r, basePath, commit);
    }
@@ -298,11 +302,7 @@
            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);
            }
            walk.setFilter(TreeFilter.ANY_DIFF);
            final ByteArrayOutputStream os = new ByteArrayOutputStream();
            RawTextComparator cmp = RawTextComparator.DEFAULT;
@@ -316,7 +316,16 @@
            df.setDiffComparator(cmp);
            df.setDetectRenames(true);
            List<DiffEntry> diffs = df.scan(parentTree, commitTree);
            df.format(diffs);
            if (path != null && path.length() > 0) {
                for (DiffEntry diff : diffs) {
                    if (diff.getNewPath().equalsIgnoreCase(path)) {
                        df.format(diff);
                        break;
                    }
                }
            } else {
                df.format(diffs);
            }
            String diff;
            if (outputHtml) {
                // workaround for complex private methods in DiffFormatter
@@ -324,6 +333,50 @@
            } else {
                diff = os.toString();
            }
            df.flush();
            return diff;
        } catch (Throwable t) {
            LOGGER.error("failed to generate commit diff!", t);
        }
        return null;
    }
    public static String getCommitPatch(Repository r, RevCommit commit) {
        return getCommitPatch(r, commit);
    }
    public static String getCommitPatch(Repository r, RevCommit commit, String path) {
        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);
            walk.setFilter(TreeFilter.ANY_DIFF);
            final ByteArrayOutputStream os = new ByteArrayOutputStream();
            RawTextComparator cmp = RawTextComparator.DEFAULT;
            PatchFormatter df = new PatchFormatter(os);
            df.setRepository(r);
            df.setDiffComparator(cmp);
            df.setDetectRenames(true);
            List<DiffEntry> diffs = df.scan(parentTree, commitTree);
            if (path != null && path.length() > 0) {
                for (DiffEntry diff : diffs) {
                    if (diff.getNewPath().equalsIgnoreCase(path)) {
                        df.format(diff);
                        break;
                    }
                }
            } else {
                df.format(diffs);
            }
            String diff = df.getPatch(commit);
            df.flush();
            return diff;
        } catch (Throwable t) {
@@ -523,6 +576,7 @@
    }
    public static List<Metric> getDateMetrics(Repository r) {
        final List<RefModel> tags = getTags(r, -1);
        final Map<String, Metric> map = new HashMap<String, Metric>();
        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM");
src/com/gitblit/utils/PatchFormatter.java
New file
@@ -0,0 +1,111 @@
package com.gitblit.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.revwalk.RevCommit;
import com.gitblit.Constants;
public class PatchFormatter extends DiffFormatter {
    private final OutputStream os;
    private PatchTouple currentTouple = null;
    Map<String, PatchTouple> changes = new HashMap<String, PatchTouple>();
    public PatchFormatter(OutputStream os) {
        super(os);
        this.os = os;
    }
    public void format(DiffEntry entry) throws IOException {
        currentTouple = new PatchTouple();
        changes.put(entry.getNewPath(), currentTouple);
        super.format(entry);
    }
    @Override
    protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException {
        switch (prefix) {
        case '+':
            currentTouple.insertions++;
            break;
        case '-':
            currentTouple.deletions++;
            break;
        }
        super.writeLine(prefix, text, cur);
    }
    public String getPatch(RevCommit commit) {
        StringBuilder patch = new StringBuilder();
        // hard-code the mon sep 17 2001 date string.
        // I have no idea why that is there. it seems to be a constant.
        patch.append("From " + commit.getName() + " Mon Sep 17 00:00:00 2001" + "\n");
        patch.append("From: " + JGitUtils.getDisplayName(commit.getAuthorIdent()) + "\n");
        patch.append("Date: " + (new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z").format(new Date(commit.getCommitTime() * 1000l))) + "\n");
        patch.append("Subject: [PATCH] " + commit.getShortMessage() + "\n");
        patch.append("\n");
        patch.append("---");
        int maxPathLen = 0;
        int files = 0;
        int insertions = 0;
        int deletions = 0;
        for (String path : changes.keySet()) {
            if (path.length() > maxPathLen) {
                maxPathLen = path.length();
            }
            PatchTouple touple = changes.get(path);
            files++;
            insertions += touple.insertions;
            deletions += touple.deletions;
        }
        int columns = 60;
        int total = insertions + deletions;
        int unit = total / columns + (total % columns > 0 ? 1 : 0);
        if (unit == 0) {
            unit = 1;
        }
        for (String path : changes.keySet()) {
            PatchTouple touple = changes.get(path);
            patch.append("\n " + Utils.rightPad(path, maxPathLen, ' ') + " | " + Utils.leftPad("" + touple.total(), 4, ' ') + " " + touple.relativeScale(unit));
        }
        patch.append(MessageFormat.format("\n {0} files changed, {1} insertions(+), {2} deletions(-)\n\n", files, insertions, deletions));
        patch.append(os.toString());
        patch.append("\n--\n");
        patch.append(Constants.getRunningVersion());
        return patch.toString();
    }
    private class PatchTouple {
        int insertions = 0;
        int deletions = 0;
        int total() {
            return insertions + deletions;
        }
        String relativeScale(int unit) {
            int plus = (insertions / unit);
            int minus = (deletions / unit);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < plus; i++) {
                sb.append('+');
            }
            for (int i = 0; i < minus; i++) {
                sb.append('-');
            }
            return sb.toString();
        }
    }
}
src/com/gitblit/utils/Utils.java
@@ -116,4 +116,51 @@
        }
        return ago;
    }
    public static String leftPad(String input, int length, char pad) {
        if (input.length() < length) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0, len = length - input.length(); i < len; i++) {
                sb.append(pad);
            }
            sb.append(input);
            return sb.toString();
        }
        return input;
    }
    public static String rightPad(String input, int length, char pad) {
        if (input.length() < length) {
            StringBuilder sb = new StringBuilder();
            sb.append(input);
            for (int i = 0, len = length - input.length(); i < len; i++) {
                sb.append(pad);
            }
            return sb.toString();
        }
        return input;
    }
    public static String escapeForHtml(String inStr, boolean changeSpace) {
        StringBuffer retStr = new StringBuffer();
        int i = 0;
        while (i < inStr.length()) {
            if (inStr.charAt(i) == '&') {
                retStr.append("&amp;");
            } else if (inStr.charAt(i) == '<') {
                retStr.append("&lt;");
            } else if (inStr.charAt(i) == '>') {
                retStr.append("&gt;");
            } else if (inStr.charAt(i) == '\"') {
                retStr.append("&quot;");
            } else if (changeSpace && inStr.charAt(i) == ' ') {
                retStr.append("&nbsp;");
            } else if (changeSpace && inStr.charAt(i) == '\t') {
                retStr.append(" &nbsp; &nbsp;");
            } else
                retStr.append(inStr.charAt(i));
            i++;
        }
        return retStr.toString();
    }
}
src/com/gitblit/wicket/GitBlitWebApp.java
@@ -28,12 +28,15 @@
import com.gitblit.StoredSettings;
import com.gitblit.utils.JGitUtils;
import com.gitblit.wicket.models.RepositoryModel;
import com.gitblit.wicket.pages.BlobDiffPage;
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.CommitDiffPage;
import com.gitblit.wicket.pages.LogPage;
import com.gitblit.wicket.pages.PatchPage;
import com.gitblit.wicket.pages.RawPage;
import com.gitblit.wicket.pages.RepositoriesPage;
import com.gitblit.wicket.pages.SummaryPage;
import com.gitblit.wicket.pages.TagPage;
import com.gitblit.wicket.pages.TagsPage;
@@ -70,7 +73,10 @@
        mount(new MixedParamUrlCodingStrategy("/tag", TagPage.class, new String[] { "r", "h" }));
        mount(new MixedParamUrlCodingStrategy("/tree", TreePage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/blob", BlobPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/diff", DiffPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/raw", RawPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/blobdiff", BlobDiffPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/commitdiff", CommitDiffPage.class, new String[] { "r", "h" }));
        mount(new MixedParamUrlCodingStrategy("/patch", PatchPage.class, new String[] { "r", "h", "f" }));
        
        // setup extended urls
        mount(new MixedParamUrlCodingStrategy("/ticgit", TicGitPage.class, new String[] { "p" }));
src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -38,4 +38,6 @@
gb.pageFirst = first
gb.pagePrevious prev
gb.pageNext = next
gb.parent = parent
gb.parent = parent
gb.head = HEAD
gb.blame = blame
src/com/gitblit/wicket/WicketUtils.java
@@ -10,6 +10,7 @@
import org.apache.wicket.PageParameters;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.eclipse.jgit.lib.Constants;
import com.gitblit.StoredSettings;
import com.gitblit.utils.Utils;
@@ -108,7 +109,7 @@
    }
    public static String getObject(PageParameters params) {
        return params.getString("h", "");
        return params.getString("h", Constants.HEAD);
    }
    public static String getPath(PageParameters params) {
src/com/gitblit/wicket/models/TicGitTicket.java
File was renamed from src/com/gitblit/utils/TicGitTicket.java
@@ -1,13 +1,10 @@
package com.gitblit.utils;
package com.gitblit.wicket.models;
import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.gitblit.wicket.models.PathModel;
public class TicGitTicket implements Serializable, Comparable<TicGitTicket> {
src/com/gitblit/wicket/pages/BlobDiffPage.html
File was renamed from src/com/gitblit/wicket/pages/DiffPage.html
@@ -12,7 +12,7 @@
    
    <!-- blob nav links -->    
    <div class="page_nav2">
        <span wicket:id="historyLink">[history link]</span> | <span wicket:id="rawLink">[raw link]</span> | <span wicket:id="headLink">[head link]</span>
        <span wicket:id="blameLink">[blame link]</span> | <span wicket:id="historyLink">[history link]</span> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="commitLink"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="commitDiffLink"><wicket:message key="gb.commitdiff"></wicket:message></a>
    </div>    
    
    <!-- shortlog header -->
src/com/gitblit/wicket/pages/BlobDiffPage.java
New file
@@ -0,0 +1,44 @@
package com.gitblit.wicket.pages;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
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.WicketUtils;
import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
public class BlobDiffPage extends RepositoryPage {
    public BlobDiffPage(PageParameters params) {
        super(params);
        final String blobPath = WicketUtils.getPath(params);
        Repository r = getRepository();
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        String diff = JGitUtils.getCommitDiff(r, commit, blobPath, true);
        add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class, WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
        add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        // diff page links
        add(new Label("blameLink", getString("gb.blame")));
        add(new Label("historyLink", getString("gb.history")));
        add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
        add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId));
        add(new Label("diffText", diff).setEscapeModelStrings(false));
    }
    @Override
    protected String getPageName() {
        return getString("gb.diff");
    }
}
src/com/gitblit/wicket/pages/BlobPage.html
@@ -21,7 +21,7 @@
    
        <!-- blob nav links -->    
        <div class="page_nav2">
            <span wicket:id="historyLink">[history link]</span> | <span wicket:id="rawLink">[raw link]</span> | <span wicket:id="headLink">[head link]</span>
            <span wicket:id="blameLink">[blame link]</span> | <span wicket:id="historyLink">[history link]</span> | <a wicket:id="rawLink"><wicket:message key="gb.raw"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a>
        </div>    
    
        <!-- shortlog header -->
src/com/gitblit/wicket/pages/BlobPage.java
@@ -6,6 +6,8 @@
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -28,9 +30,10 @@
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        // blob page links
        add(new Label("blameLink", getString("gb.blame")));
        add(new Label("historyLink", getString("gb.history")));
        add(new Label("rawLink", getString("gb.raw")));
        add(new Label("headLink", "HEAD"));
        add(new BookmarkablePageLink<Void>("rawLink", RawPage.class, WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
        add(new BookmarkablePageLink<Void>("headLink", BlobPage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, blobPath)));
        add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
src/com/gitblit/wicket/pages/CommitDiffPage.html
New file
@@ -0,0 +1,38 @@
<!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>
    <!-- page nav links -->
    <div wicket:id="pageLinks">[page links]</div>
    <!-- commitdiff nav links -->
    <div class="page_nav2">
        <wicket:message key="gb.parent"></wicket:message>: <span wicket:id="parentLink">[parent link]</span> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="commitLink"><wicket:message key="gb.commit"></wicket:message></a>
    </div>
    <!-- shortlog header -->
    <div class="header" wicket:id="shortlog">[shortlog header]</div>
    <!-- changed paths -->
    <table style="margin-top:10px;border-top:1px solid #bbb;" class="pretty">
        <tr wicket:id="changedPath">
            <td class="path"><span wicket:id="pathName">[commit path]</span></td>
            <td>
                <div 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>
                </div>
            </td>
        </tr>
    </table>
    <!--  diff content -->
    <pre wicket:id="diffText">[diff text]</pre>
</wicket:extend>
</body>
</html>
src/com/gitblit/wicket/pages/CommitDiffPage.java
New file
@@ -0,0 +1,80 @@
package com.gitblit.wicket.pages;
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.link.BookmarkablePageLink;
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.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.WicketUtils;
import com.gitblit.wicket.models.PathModel;
public class CommitDiffPage extends RepositoryPage {
    public CommitDiffPage(PageParameters params) {
        super(params);
        Repository r = getRepository();
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        String diff = JGitUtils.getCommitDiff(r, commit, true);
        List<String> parents = new ArrayList<String>();
        if (commit.getParentCount() > 0) {
            for (RevCommit parent : commit.getParents()) {
                parents.add(parent.name());
            }
        }
        // commit page links
        if (parents.size() == 0) {
            add(new Label("parentLink", "none"));
        } else {
            add(new LinkPanel("parentLink", null, parents.get(0).substring(0, 8), CommitDiffPage.class, newCommitParameter(parents.get(0))));
        }
        add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
        // changed paths list
        List<PathModel> paths  = JGitUtils.getFilesInCommit(r, commit);
        ListDataProvider<PathModel> pathsDp = new ListDataProvider<PathModel>(paths);
        DataView<PathModel> pathsView = new DataView<PathModel>("changedPath", pathsDp) {
            private static final long serialVersionUID = 1L;
            int counter = 0;
            public void populateItem(final Item<PathModel> item) {
                final PathModel entry = item.getModelObject();
                if (entry.isTree()) {
                    item.add(new LinkPanel("pathName", null, entry.path, TreePage.class, newPathParameter(entry.path)));
                } else {
                    item.add(new LinkPanel("pathName", "list", entry.path, BlobPage.class, newPathParameter(entry.path)));
                }
                item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("blame", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                WicketUtils.setAlternatingBackground(item, counter);
                counter++;
            }
        };
        add(pathsView);
        add(new Label("diffText", diff).setEscapeModelStrings(false));
    }
    @Override
    protected String getPageName() {
        return getString("gb.commitdiff");
    }
}
src/com/gitblit/wicket/pages/CommitPage.html
@@ -12,7 +12,7 @@
    
    <!-- commit nav links -->    
    <div class="page_nav2">
        <wicket:message key="gb.parent"></wicket:message>: <span wicket:id="parentLink">[parent link]</span> | <span wicket:id="patchLink">[patch link]</span> | <span wicket:id="commitdiffLink">[commitdiff link]</span>
        <wicket:message key="gb.parent"></wicket:message>: <span wicket:id="parentLink">[parent link]</span> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <span wicket:id="commitdiffLink">[commitdiff link]</span>
    </div>    
    
    <!-- shortlog header -->
@@ -40,7 +40,7 @@
            <td class="path"><span wicket:id="pathName">[commit path]</span></td>            
            <td>
                <div class="link">
                    <a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a> | <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
                    <a wicket:id="diff"><wicket:message key="gb.diff"></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>
                </div>
            </td>
        </tr>
src/com/gitblit/wicket/pages/CommitPage.java
@@ -41,11 +41,11 @@
            add(new Label("commitdiffLink", getString("gb.commitdiff")));
        } else {
            add(new LinkPanel("parentLink", null, parents.get(0).substring(0, 8), CommitPage.class, newCommitParameter(parents.get(0))));
            add(new LinkPanel("commitdiffLink", null, new StringResourceModel("gb.commitdiff", this, null), DiffPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
            add(new LinkPanel("commitdiffLink", null, new StringResourceModel("gb.commitdiff", this, null), CommitDiffPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        }
        add(new Label("patchLink", getString("gb.patch")));
        add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        
        add(new LinkPanel("shortlog", "title", c.getShortMessage(), LogPage.class, newRepositoryParameter()));
        add(new LinkPanel("shortlog", "title", c.getShortMessage(), CommitDiffPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        
        addRefs(r, c);
@@ -88,8 +88,9 @@
                    item.add(new LinkPanel("pathName", "list", entry.path, BlobPage.class, newPathParameter(entry.path)));
                }
                
                item.add(new BookmarkablePageLink<Void>("diff", DiffPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("blame", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                WicketUtils.setAlternatingBackground(item, counter);
src/com/gitblit/wicket/pages/DiffPage.java
File was deleted
src/com/gitblit/wicket/pages/PatchPage.html
New file
@@ -0,0 +1,13 @@
<!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>
        <!-- patch content -->
        <pre style="border:0px;" wicket:id="patchText">[patch content]</pre>
</body>
</html>
src/com/gitblit/wicket/pages/PatchPage.java
New file
@@ -0,0 +1,46 @@
package com.gitblit.wicket.pages;
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import com.gitblit.utils.JGitUtils;
import com.gitblit.wicket.GitBlitWebApp;
import com.gitblit.wicket.WicketUtils;
public class PatchPage extends WebPage {
    public PatchPage(PageParameters params) {
        super(params);
        if (!params.containsKey("r")) {
            error("Repository not specified!");
            redirectToInterceptPage(new RepositoriesPage());
        }
        final String repositoryName = WicketUtils.getRepositoryName(params);
        final String objectId = WicketUtils.getObject(params);
        final String blobPath = WicketUtils.getPath(params);
        ServletWebRequest servletWebRequest = (ServletWebRequest) getRequest();
        HttpServletRequest req = servletWebRequest.getHttpServletRequest();
        req.getServerName();
        Repository r = GitBlitWebApp.get().getRepository(req, repositoryName);
        if (r == null) {
            error("Can not load repository " + repositoryName);
            redirectToInterceptPage(new RepositoriesPage());
            return;
        }
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        String patch = JGitUtils.getCommitPatch(r, commit, blobPath);
        add(new Label("patchText", patch));
        r.close();
    }
}
src/com/gitblit/wicket/pages/RawPage.html
New file
@@ -0,0 +1,13 @@
<!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>
        <!-- raw content -->
        <pre style="border:0px;" wicket:id="rawText">[raw content]</pre>
</body>
</html>
src/com/gitblit/wicket/pages/RawPage.java
New file
@@ -0,0 +1,91 @@
package com.gitblit.wicket.pages;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import com.gitblit.StoredSettings;
import com.gitblit.utils.JGitUtils;
import com.gitblit.wicket.GitBlitWebApp;
import com.gitblit.wicket.WicketUtils;
public class RawPage extends WebPage {
    public RawPage(PageParameters params) {
        super(params);
        if (!params.containsKey("r")) {
            error("Repository not specified!");
            redirectToInterceptPage(new RepositoriesPage());
        }
        final String repositoryName = WicketUtils.getRepositoryName(params);
        final String objectId = WicketUtils.getObject(params);
        final String blobPath = WicketUtils.getPath(params);
        ServletWebRequest servletWebRequest = (ServletWebRequest) getRequest();
        HttpServletRequest req = servletWebRequest.getHttpServletRequest();
        req.getServerName();
        Repository r = GitBlitWebApp.get().getRepository(req, repositoryName);
        if (r == null) {
            error("Can not load repository " + repositoryName);
            redirectToInterceptPage(new RepositoriesPage());
            return;
        }
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        String extension = null;
        if (blobPath.lastIndexOf('.') > -1) {
            extension = blobPath.substring(blobPath.lastIndexOf('.') + 1);
        }
        // Map the extensions to types
        Map<String, Integer> map = new HashMap<String, Integer>();
        for (String ext : StoredSettings.getStrings("imageExtensions")) {
            map.put(ext.toLowerCase(), 2);
        }
        for (String ext : StoredSettings.getStrings("binaryExtensions")) {
            map.put(ext.toLowerCase(), 3);
        }
        if (extension != null) {
            int type = 0;
            if (map.containsKey(extension)) {
                type = map.get(extension);
            }
            Component c = null;
            switch (type) {
            case 2:
                // TODO image blobs
                c = new Label("rawText", "Image File");
                break;
            case 3:
                // TODO binary blobs
                c = new Label("rawText", "Binary File");
                break;
            default:
                // plain text
                c = new Label("rawText", JGitUtils.getRawContentAsString(r, commit, blobPath));
                WicketUtils.setCssClass(c, "plainprint");
            }
            add(c);
        } else {
            // plain text
            Label blobLabel = new Label("rawText", JGitUtils.getRawContentAsString(r, commit, blobPath));
            WicketUtils.setCssClass(blobLabel, "plainprint");
            add(blobLabel);
        }
        r.close();
    }
}
src/com/gitblit/wicket/pages/TagPage.html
@@ -11,7 +11,7 @@
    <div wicket:id="pageLinks">[page links]</div>
    <!-- summary header -->
    <div style="padding-top: 5px;" class="header" wicket:id="commit">[shortlog header]</div>
    <div style="margin-top: 5px;" class="header" wicket:id="commit">[shortlog header]</div>
    
    <!-- commit info -->
    <table class="plain">
src/com/gitblit/wicket/pages/TagPage.java
@@ -1,5 +1,7 @@
package com.gitblit.wicket.pages;
import java.util.List;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.eclipse.jgit.lib.Repository;
@@ -9,6 +11,7 @@
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.RepositoryPage;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.models.RefModel;
public class TagPage extends RepositoryPage {
@@ -16,10 +19,18 @@
    public TagPage(PageParameters params) {
        super(params);
        Repository r = getRepository();
        Repository r = getRepository();
        List<RefModel> tags = JGitUtils.getTags(r, -1);
        RevCommit c = JGitUtils.getCommit(r, objectId);
        String name = c.getName();
        for (RefModel tag:tags) {
            if (tag.getName().equals(objectId)) {
                name = tag.getDisplayName();
            }
        }
        add(new LinkPanel("commit", "title", c.getName(), CommitPage.class, newCommitParameter()));
        add(new LinkPanel("commit", "title", name, CommitPage.class, newCommitParameter()));
        add(new LinkPanel("tagId", "list", c.getName(), CommitPage.class, newCommitParameter(c.getName())));
        add(new Label("tagAuthor", JGitUtils.getDisplayName(c.getAuthorIdent())));
src/com/gitblit/wicket/pages/TicGitPage.java
@@ -9,11 +9,11 @@
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.TicGitTicket;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.RepositoryPage;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.models.TicGitTicket;
public class TicGitPage extends RepositoryPage {
src/com/gitblit/wicket/pages/TicGitTicketPage.java
@@ -8,11 +8,11 @@
import org.eclipse.jgit.lib.Repository;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.TicGitTicket;
import com.gitblit.utils.TicGitTicket.Comment;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.RepositoryPage;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.models.TicGitTicket;
import com.gitblit.wicket.models.TicGitTicket.Comment;
public class TicGitTicketPage extends RepositoryPage {
src/com/gitblit/wicket/pages/TreePage.html
@@ -12,7 +12,7 @@
    
    <!-- blob nav links -->    
    <div class="page_nav2">
        <span wicket:id="historyLink">[history link]</span> | <span wicket:id="headLink">[head link]</span>
        <span wicket:id="historyLink">[history link]</span> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a>
    </div>    
    
    <!-- shortlog header -->
src/com/gitblit/wicket/pages/TreePage.java
@@ -9,6 +9,7 @@
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.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -34,7 +35,8 @@
        // tree page links
        add(new Label("historyLink", getString("gb.history")));
        add(new Label("headLink", "HEAD"));
        add(new BookmarkablePageLink<Void>("headLink", TreePage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, basePath)));
        add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
@@ -79,7 +81,7 @@
                        // links
                        Fragment links = new Fragment("pathLinks", "blobLinks", this);
                        links.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        links.add(new BookmarkablePageLink<Void>("raw", BlobPage.class).setEnabled(false));
                        links.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        links.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                        item.add(links);
                    }
src/com/gitblit/wicket/panels/LogPanel.java
@@ -19,7 +19,7 @@
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.pages.CommitPage;
import com.gitblit.wicket.pages.DiffPage;
import com.gitblit.wicket.pages.CommitDiffPage;
import com.gitblit.wicket.pages.LogPage;
import com.gitblit.wicket.pages.SummaryPage;
import com.gitblit.wicket.pages.TreePage;
@@ -82,7 +82,7 @@
                item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));
                item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                item.add(new BookmarkablePageLink<Void>("diff", DiffPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                item.add(new BookmarkablePageLink<Void>("diff", CommitDiffPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                item.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                WicketUtils.setAlternatingBackground(item, counter);
src/com/gitblit/wicket/resources/gitblit.css
@@ -229,9 +229,9 @@
    background-color: #EDECE6;
    border-color: #D9D8D1;
    border-style: solid;
    border-width: 1px 0;
    border-width: 1px;
    font-weight: bold;
    margin-top: 4px;
    margin-top: 10px;
    padding: 4px 0 2px;
}
@@ -241,17 +241,17 @@
    font-family: inherit;
}
div.diff.add {
span.diff.add {
    color: #008800;
    font-family: inherit;
}
div.diff.remove {
span.diff.remove {
    color: #cc0000;
    font-family: inherit;
}
div.diff.unchanged {
span.diff.unchanged {
    color: inherit;
    font-family: inherit;
}
@@ -425,11 +425,12 @@
span .tagRef a, span .headRef a, span .remoteRef a, span .otherRef a {
    text-decoration: none;
    color: inherit;
    color: black;
}
span .tagRef a:hover, span .headRef a:hover, span .remoteRef a:hover, span .otherRef a:hover {
    color: inherit;
    color: black;
    text-decoration: underline;
}
span .otherRef {