James Moger
2013-11-12 c05da657ec71c46d0e5bc32b074ddcd9d8b76353
Add markup support for confluence, mediawiki, textile, trac, and twiki

Change-Id: I82ef161c6b6956c7b83cd4a1c37627beac6ea75b
7 files modified
220 ■■■■■ changed files
.classpath 6 ●●●●● patch | view | raw | blame | history
build.moxie 7 ●●●●● patch | view | raw | blame | history
gitblit.iml 66 ●●●●● patch | view | raw | blame | history
releases.moxie 2 ●●●●● patch | view | raw | blame | history
src/main/distrib/data/gitblit.properties 35 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/MarkupProcessor.java 100 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/DocsPage.html 4 ●●● patch | view | raw | blame | history
.classpath
@@ -27,6 +27,12 @@
    <classpathentry kind="lib" path="ext/asm-tree-4.1.jar" sourcepath="ext/src/asm-tree-4.1.jar" />
    <classpathentry kind="lib" path="ext/asm-analysis-4.1.jar" sourcepath="ext/src/asm-analysis-4.1.jar" />
    <classpathentry kind="lib" path="ext/asm-util-4.1.jar" sourcepath="ext/src/asm-util-4.1.jar" />
    <classpathentry kind="lib" path="ext/wikitext-core-1.4.jar" sourcepath="ext/src/wikitext-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/twiki-core-1.4.jar" sourcepath="ext/src/twiki-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/textile-core-1.4.jar" sourcepath="ext/src/textile-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/tracwiki-core-1.4.jar" sourcepath="ext/src/tracwiki-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/mediawiki-core-1.4.jar" sourcepath="ext/src/mediawiki-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/confluence-core-1.4.jar" sourcepath="ext/src/confluence-core-1.4.jar" />
    <classpathentry kind="lib" path="ext/org.eclipse.jgit-3.1.0.201310021548-r.jar" sourcepath="ext/src/org.eclipse.jgit-3.1.0.201310021548-r.jar" />
    <classpathentry kind="lib" path="ext/jsch-0.1.46.jar" sourcepath="ext/src/jsch-0.1.46.jar" />
    <classpathentry kind="lib" path="ext/JavaEWAH-0.5.6.jar" sourcepath="ext/src/JavaEWAH-0.5.6.jar" />
build.moxie
@@ -105,6 +105,7 @@
  groovy.version : 1.8.8
  bouncycastle.version : 1.47
  selenium.version : 2.28.0
  wikitext.version : 1.4
  }
# Dependencies
@@ -136,6 +137,12 @@
- compile 'org.apache.lucene:lucene-highlighter:${lucene.version}' :war :fedclient
- compile 'org.apache.lucene:lucene-memory:${lucene.version}' :war :fedclient
- compile 'org.pegdown:pegdown:1.4.1' :war
- compile 'org.fusesource.wikitext:wikitext-core:${wikitext.version}' :war
- compile 'org.fusesource.wikitext:twiki-core:${wikitext.version}' :war
- compile 'org.fusesource.wikitext:textile-core:${wikitext.version}' :war
- compile 'org.fusesource.wikitext:tracwiki-core:${wikitext.version}' :war
- compile 'org.fusesource.wikitext:mediawiki-core:${wikitext.version}' :war
- compile 'org.fusesource.wikitext:confluence-core:${wikitext.version}' :war
- compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager :authority
- compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :fedclient :manager :authority
- compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war :authority
gitblit.iml
@@ -273,6 +273,72 @@
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="wikitext-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/wikitext-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/wikitext-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="twiki-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/twiki-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/twiki-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="textile-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/textile-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/textile-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="tracwiki-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/tracwiki-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/tracwiki-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="mediawiki-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/mediawiki-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/mediawiki-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="confluence-core-1.4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/confluence-core-1.4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/confluence-core-1.4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="org.eclipse.jgit-3.1.0.201310021548-r.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit-3.1.0.201310021548-r.jar!/" />
releases.moxie
@@ -34,6 +34,7 @@
    - Set Link: <url>; rel="canonical" http header for SEO (issue-304)
    - Added raw links to the commit, commitdiff, and compare pages (issue-319)
    - Support intradocument linking in Markdown content using [[WikiLinks]] syntax (issue-324)
    - Support rendering confluence, mediawiki, textile, tracwiki, and twiki markup documents
    - Added setting to globally disable anonymous pushes in the receive pack
    - Added a normalized diffstat display to the commit, commitdiff, and compare pages
    - Added GO setting to automatically redirect all http requests to the secure https connector
@@ -41,6 +42,7 @@
    - updated to Jetty 7.6.13
    - updated to JGit 3.1.0
    - replaced MarkdownPapers with pegdown 1.4.1
    - added Eclipse WikiText libraries for processing confluence, mediawiki, textile, tracwiki, and twiki
    settings:
    - { name: 'git.createRepositoriesShared', defaultValue: 'false' }
    - { name: 'git.allowAnonymousPushes', defaultValue: 'false' }
src/main/distrib/data/gitblit.properties
@@ -1016,6 +1016,41 @@
# SINCE 0.5.0
web.markdownExtensions = md mkd markdown MD MKD
# Registered extensions for mediawiki transformation
#
# SPACE-DELIMITED
# CASE-SENSITIVE
# SINCE 1.4.0
web.mediawikiExtensions = mw mediawiki
# Registered extensions for twiki transformation
#
# SPACE-DELIMITED
# CASE-SENSITIVE
# SINCE 1.4.0
web.twikiExtensions = twiki
# Registered extensions for textile transformation
#
# SPACE-DELIMITED
# CASE-SENSITIVE
# SINCE 1.4.0
web.textileExtensions = textile
# Registered extensions for confluence transformation
#
# SPACE-DELIMITED
# CASE-SENSITIVE
# SINCE 1.4.0
web.confluenceExtensions = confluence
# Registered extensions for tracwiki transformation
#
# SPACE-DELIMITED
# CASE-SENSITIVE
# SINCE 1.4.0
web.tracwikiExtensions = tracwiki
# Image extensions
#
# SPACE-DELIMITED
src/main/java/com/gitblit/wicket/MarkupProcessor.java
@@ -16,6 +16,7 @@
package com.gitblit.wicket;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
@@ -26,6 +27,15 @@
import org.apache.wicket.RequestCycle;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.mylyn.wikitext.confluence.core.ConfluenceLanguage;
import org.eclipse.mylyn.wikitext.core.parser.Attributes;
import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
import org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
import org.eclipse.mylyn.wikitext.tracwiki.core.TracWikiLanguage;
import org.eclipse.mylyn.wikitext.twiki.core.TWikiLanguage;
import org.pegdown.LinkRenderer;
import org.pegdown.ast.WikiLinkNode;
import org.slf4j.Logger;
@@ -38,6 +48,7 @@
import com.gitblit.utils.MarkdownUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.pages.DocPage;
import com.gitblit.wicket.pages.RawPage;
/**
 * Processes markup content and generates html with repository-relative page and
@@ -49,7 +60,7 @@
public class MarkupProcessor {
    public enum MarkupSyntax {
        PLAIN, MARKDOWN
        PLAIN, MARKDOWN, TWIKI, TRACWIKI, TEXTILE, MEDIAWIKI, CONFLUENCE
    }
    private Logger logger = LoggerFactory.getLogger(getClass());
@@ -62,7 +73,12 @@
    public List<String> getMarkupExtensions() {
        List<String> list = new ArrayList<String>();
        list.addAll(settings.getStrings(Keys.web.confluenceExtensions));
        list.addAll(settings.getStrings(Keys.web.markdownExtensions));
        list.addAll(settings.getStrings(Keys.web.mediawikiExtensions));
        list.addAll(settings.getStrings(Keys.web.textileExtensions));
        list.addAll(settings.getStrings(Keys.web.tracwikiExtensions));
        list.addAll(settings.getStrings(Keys.web.twikiExtensions));
        return list;
    }
@@ -72,8 +88,18 @@
            return MarkupSyntax.PLAIN;
        }
        if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
        if (settings.getStrings(Keys.web.confluenceExtensions).contains(ext)) {
            return MarkupSyntax.CONFLUENCE;
        } else if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
            return MarkupSyntax.MARKDOWN;
        } else if (settings.getStrings(Keys.web.mediawikiExtensions).contains(ext)) {
            return MarkupSyntax.MEDIAWIKI;
        } else if (settings.getStrings(Keys.web.textileExtensions).contains(ext)) {
            return MarkupSyntax.TEXTILE;
        } else if (settings.getStrings(Keys.web.tracwikiExtensions).contains(ext)) {
            return MarkupSyntax.TRACWIKI;
        } else if (settings.getStrings(Keys.web.twikiExtensions).contains(ext)) {
            return MarkupSyntax.TWIKI;
        }
        return MarkupSyntax.PLAIN;
@@ -115,8 +141,23 @@
        if (markupText != null) {
            try {
                switch (syntax){
                case CONFLUENCE:
                    parse(doc, repositoryName, commitId, new ConfluenceLanguage());
                    break;
                case MARKDOWN:
                    parse(doc, repositoryName, commitId);
                    break;
                case MEDIAWIKI:
                    parse(doc, repositoryName, commitId, new MediaWikiLanguage());
                    break;
                case TEXTILE:
                    parse(doc, repositoryName, commitId, new TextileLanguage());
                    break;
                case TRACWIKI:
                    parse(doc, repositoryName, commitId, new TracWikiLanguage());
                    break;
                case TWIKI:
                    parse(doc, repositoryName, commitId, new TWikiLanguage());
                    break;
                default:
                    doc.html = MarkdownUtils.transformPlainText(markupText);
@@ -140,6 +181,61 @@
    }
    /**
     * Parses the markup using the specified markup language
     *
     * @param doc
     * @param repositoryName
     * @param commitId
     * @param lang
     */
    private void parse(final MarkupDocument doc, final String repositoryName, final String commitId, MarkupLanguage lang) {
        StringWriter writer = new StringWriter();
        HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer) {
            @Override
            public void image(Attributes attributes, String imagePath) {
                String url;
                if (imagePath.indexOf("://") == -1) {
                    // relative image
                    String path = doc.getRelativePath(imagePath);
                    url = getWicketUrl(RawPage.class, repositoryName, commitId, path);
                } else {
                    // absolute image
                    url = imagePath;
                }
                super.image(attributes, url);
            }
            @Override
            public void link(Attributes attributes, String hrefOrHashName, String text) {
                String url;
                if (hrefOrHashName.charAt(0) != '#') {
                    if (hrefOrHashName.indexOf("://") == -1) {
                        // relative link
                        String path = doc.getRelativePath(hrefOrHashName);
                        url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
                    } else {
                        // absolute link
                        url = hrefOrHashName;
                    }
                } else {
                    // page-relative hash link
                    url = hrefOrHashName;
                }
                super.link(attributes, url, text);
            }
        };
        // avoid the <html> and <body> tags
        builder.setEmitAsDocument(false);
        MarkupParser parser = new MarkupParser(lang);
        parser.setBuilder(builder);
        parser.parse(doc.markup);
        doc.html = writer.toString();
    }
    /**
     * Parses the document as Markdown using Pegdown.
     *
     * @param doc
src/main/java/com/gitblit/wicket/pages/DocsPage.html
@@ -15,7 +15,9 @@
        <li><a data-toggle="tab" href="#pages"><wicket:message key="gb.pages">[pages]</wicket:message></a></li>
    </ul>
    <div class="tab-content">
        <div id="home" wicket:id="index" class="tab-pane active"></div>
        <div id="home" class="tab-pane active">
            <div class="markdown" wicket:id="index"></div>
        </div>
        <div id="pages" wicket:id="documents" class="tab-pane"></div>
    </div>
</wicket:fragment>