Allow projects to define own CSS for ASCIIDOCTOR formatter
Projects may have different preferences of how their asciidoc
documentation should be formatted. By default the standard Gerrit CSS
for asciidoc files is used, but now projects can override it by custom
CSS that is stored in the project's refs/meta/config branch as
'xdocs/asciidoctor.css'.
Custom CSS is not inherited from parent projects.
Some methods which are useful for different formatters have been made
available in a FormatterUtil class so that they can be reused.
Change-Id: I75ef3a8cc252363957fe073366740e2ff4e936bd
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
index 5517fbe..57ba4a8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
@@ -17,6 +17,7 @@
import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_INCLUDE_TOC;
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.common.base.MoreObjects;
import com.google.common.io.ByteStreams;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.annotations.PluginData;
@@ -51,14 +52,17 @@
private static final String ERUBY = "erb";
private final File baseDir;
- private final String css;
+ private final String defaultCss;
private final Properties attributes;
+ private final FormatterUtil util;
@Inject
- public AsciidoctorFormatter(@PluginData File baseDir) throws IOException {
+ public AsciidoctorFormatter(@PluginData File baseDir,
+ FormatterUtil formatterUtil) throws IOException {
this.baseDir = baseDir;
- this.css = readCss();
+ this.defaultCss = readCss();
this.attributes = readAttributes();
+ this.util = formatterUtil;
}
@Override
@@ -74,7 +78,10 @@
try (FileInputStream input = new FileInputStream(tmpFile)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteStreams.copy(input, out);
- return insertCss(out.toString(UTF_8.name()));
+ return util.insertCss(
+ out.toString(UTF_8.name()),
+ MoreObjects.firstNonNull(
+ util.getCss(projectName, "asciidoctor"), defaultCss));
}
} finally {
if (!tmpFile.delete()) {
@@ -107,21 +114,6 @@
return ab.get();
}
- private String insertCss(String html) {
- int p = html.lastIndexOf("</head>");
- if (p > 0) {
- StringBuilder b = new StringBuilder();
- b.append(html.substring(0, p));
- b.append("<style type=\"text/css\">\n");
- b.append(css);
- b.append("</style>\n");
- b.append(html.substring(p));
- return b.toString();
- } else {
- return html;
- }
- }
-
private static String readCss() throws IOException {
String name = "asciidoctor.css";
URL url = AsciidoctorFormatter.class.getResource(name);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
new file mode 100644
index 0000000..3fb1d18
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
@@ -0,0 +1,131 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.xdocs.formatter;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+
+import java.io.IOException;
+
+@Singleton
+public class FormatterUtil {
+ private final GitRepositoryManager repoManager;
+ private final String pluginName;
+
+ @Inject
+ FormatterUtil(@PluginName String pluginName,
+ GitRepositoryManager repoManager) {
+ this.pluginName = pluginName;
+ this.repoManager = repoManager;
+ }
+
+ /**
+ * Returns the CSS from the file "<plugin-name>/<name>.css" in the
+ * refs/meta/config branch of the project.
+ *
+ * @param name the name of the file in the "<plugin-name>/" folder without the
+ * ".css" file extension
+ * @return the CSS from the file; HTML characters are escaped;
+ * <code>null</code> if the file doesn't exist
+ */
+ public String getCss(String projectName, String name) {
+ return escapeHtml(getMetaConfigFile(projectName, name + ".css"));
+ }
+
+ /**
+ * Inserts the given CSS into the given HTML.
+ *
+ * @param html the HTML
+ * @param css the CSS
+ * @return the HTML that includes the CSS
+ */
+ public String insertCss(String html, String css) {
+ if (html == null || css == null) {
+ return html;
+ }
+
+ int p = html.lastIndexOf("</head>");
+ if (p > 0) {
+ StringBuilder b = new StringBuilder();
+ b.append(html.substring(0, p));
+ b.append("<style type=\"text/css\">\n");
+ b.append(css);
+ b.append("</style>\n");
+ b.append(html.substring(p));
+ return b.toString();
+ } else {
+ return html;
+ }
+ }
+
+ /**
+ * Returns the content of the specified file from the "<plugin-name>/" folder
+ * of the ref/meta/config branch.
+ *
+ * @param projectName the name of the project
+ * @param fileName the name of the file in the "<plugin-name>/" folder
+ * @return the file content, <code>null</code> if the file doesn't exist
+ */
+ public String getMetaConfigFile(String projectName, String fileName) {
+ try {
+ Repository repo =
+ repoManager.openRepository(new Project.NameKey(projectName));
+ try {
+ RevWalk rw = new RevWalk(repo);
+ try {
+ RevCommit commit = rw.parseCommit(repo.resolve(RefNames.REFS_CONFIG));
+ RevTree tree = commit.getTree();
+ TreeWalk tw = new TreeWalk(repo);
+ try {
+ tw.addTree(tree);
+ tw.setRecursive(true);
+ tw.setFilter(PathFilter.create(pluginName + "/" + fileName));
+ if (!tw.next()) {
+ return null;
+ }
+ ObjectId objectId = tw.getObjectId(0);
+ ObjectLoader loader = repo.open(objectId);
+ byte[] raw = loader.getBytes(Integer.MAX_VALUE);
+ return new String(raw, UTF_8);
+ } finally {
+ tw.release();
+ }
+ } finally {
+ rw.release();
+ }
+ } finally {
+ repo.close();
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
index 0f2b2f3..e646027 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
@@ -16,39 +16,21 @@
import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_ALLOW_HTML;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevTree;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.treewalk.filter.PathFilter;
-
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class MarkdownFormatter implements Formatter {
public final static String NAME = "MARKDOWN";
- private final GitRepositoryManager repoManager;
- private final String pluginName;
+ private final FormatterUtil util;
@Inject
- MarkdownFormatter(@PluginName String pluginName,
- GitRepositoryManager repoManager) {
- this.pluginName = pluginName;
- this.repoManager = repoManager;
+ MarkdownFormatter(FormatterUtil formatterUtil) {
+ this.util = formatterUtil;
}
@Override
@@ -62,43 +44,8 @@
// if there is no project-specific CSS and f.setCss(null) is invoked
// com.google.gerrit.server.documentation.MarkdownFormatter applies the
// default CSS
- f.setCss(getCss(projectName));
+ f.setCss(util.getCss(projectName, "markdown"));
byte[] b = f.markdownToDocHtml(raw, UTF_8.name());
return new String(b, UTF_8);
}
-
- private String getCss(String projectName) {
- try {
- Repository repo =
- repoManager.openRepository(new Project.NameKey(projectName));
- try {
- RevWalk rw = new RevWalk(repo);
- try {
- RevCommit commit = rw.parseCommit(repo.resolve(RefNames.REFS_CONFIG));
- RevTree tree = commit.getTree();
- TreeWalk tw = new TreeWalk(repo);
- try {
- tw.addTree(tree);
- tw.setRecursive(true);
- tw.setFilter(PathFilter.create(pluginName + "/markdown.css"));
- if (!tw.next()) {
- return null;
- }
- ObjectId objectId = tw.getObjectId(0);
- ObjectLoader loader = repo.open(objectId);
- byte[] raw = loader.getBytes(Integer.MAX_VALUE);
- return escapeHtml(new String(raw, UTF_8));
- } finally {
- tw.release();
- }
- } finally {
- rw.release();
- }
- } finally {
- repo.close();
- }
- } catch (IOException e) {
- return null;
- }
- }
}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index c18c697..d0b648d 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -61,6 +61,7 @@
For some formatters a custom CSS file for the rendering can be
provided in the `refs/meta/config` branch of the project:
+* `ASCIIDOCTOR`: `xdoc/asciidoctor.css`
* `MARKDOWN`: `xdoc/markdown.css`
Custom CSS files are *NOT* inherited from parent projects.