From 2f1cc3d955b1472cb5396c248070a930ec1bcd61 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Sun, 13 Dec 2015 20:00:14 -0700 Subject: [PATCH] resolves #170, #180, #179, #168 & #160 enable configuration for site parser - rewrite AsciidoctorParser (used by Maven Site Plugin) to make it more organized and extensible - pass AsciiDoc configuration defined in Maven Site plugin to the Asciidoctor API - enhance Maven Site integration test - add custom template - add include - add source highlighting - make validation code compatible with Java 6 - enable integration tests on Travis CI - remove unused legacy site module - fix license headers - minor cleanups --- .travis.yml | 2 +- src/it/maven-site-plugin/pom.xml | 25 ++- .../src/site/asciidoc/_include.adoc | 1 + .../src/site/asciidoc/file-with-toc.adoc | 26 +++- .../asciidoc/templates/paragraph.html.slim | 1 + src/it/maven-site-plugin/src/site/site.xml | 8 + src/it/maven-site-plugin/validate.bsh | 71 +++++++-- .../site/AsciidoctorLegacySiteModule.java | 42 ----- .../maven/site/AsciidoctorParser.java | 145 ++++++++++++++++-- .../maven/site/AsciidoctorParserModule.java | 14 +- .../maven/site/AsciidoctorSiteModule.java | 13 +- .../maven/test/AsciidoctorMojoTest.groovy | 2 +- 12 files changed, 260 insertions(+), 90 deletions(-) create mode 100644 src/it/maven-site-plugin/src/site/asciidoc/_include.adoc create mode 100644 src/it/maven-site-plugin/src/site/asciidoc/templates/paragraph.html.slim create mode 100644 src/it/maven-site-plugin/src/site/site.xml delete mode 100644 src/main/java/org/asciidoctor/maven/site/AsciidoctorLegacySiteModule.java diff --git a/.travis.yml b/.travis.yml index 31569e7e..a9e86fce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ jdk: install: - mvn package -DskipTests=true -Dmaven.javadoc.skip=true -B -V script: - - mvn test jacoco:report + - mvn verify -Prun-its jacoco:report after_success: # 'coveralls:report' goal is responsible for updating coverall.io stats once travisCI build completes # Look for the article 'Coveralls.io configuration for maven projects' in the wiki (https://github.com/asciidoctor/asciidoctor/wiki) for more details diff --git a/src/it/maven-site-plugin/pom.xml b/src/it/maven-site-plugin/pom.xml index eb978f6b..5ac317dd 100644 --- a/src/it/maven-site-plugin/pom.xml +++ b/src/it/maven-site-plugin/pom.xml @@ -2,19 +2,33 @@ 4.0.0 - org.asciidoctor - maven-site-test + maven-site-plugin-it 1.0-SNAPSHOT - - Maven Site Plugin Test - + Maven Site Plugin IT + org.apache.maven.plugins maven-site-plugin 3.3 + + + src/site/asciidoc/templates + + time + + + coderay + style + 2 + + + + **/_*.adoc + + org.asciidoctor @@ -23,6 +37,7 @@ + diff --git a/src/it/maven-site-plugin/src/site/asciidoc/_include.adoc b/src/it/maven-site-plugin/src/site/asciidoc/_include.adoc new file mode 100644 index 00000000..54effb0d --- /dev/null +++ b/src/it/maven-site-plugin/src/site/asciidoc/_include.adoc @@ -0,0 +1 @@ +Content included from the file _include.adoc. diff --git a/src/it/maven-site-plugin/src/site/asciidoc/file-with-toc.adoc b/src/it/maven-site-plugin/src/site/asciidoc/file-with-toc.adoc index 4f67e86d..6a2b4e79 100644 --- a/src/it/maven-site-plugin/src/site/asciidoc/file-with-toc.adoc +++ b/src/it/maven-site-plugin/src/site/asciidoc/file-with-toc.adoc @@ -1,16 +1,30 @@ -= Maven Site Plugin Test += File with TOC :toc: -This is an example file to test asciidoctor-maven-plugin with maven-site-plugin. +[.lead] +This is an example file that was processed by the site module in the Asciidoctor Maven Plugin. + +== First section -= First section This is the first section of the page. -== Sub section +include::_include.adoc[] + +=== Sub section + This is a subsection of the first section -= Second section +TIP: You can control the number of section levels displayed in the TOC using the `toclevels` attribute. + +== Second section + This is the first section of the page. -== Sub section +=== Sub section + This is a subsection of the second section. + +[source,xml,indent=0] +---- +include::../../../pom.xml[tag=plugin-decl] +---- diff --git a/src/it/maven-site-plugin/src/site/asciidoc/templates/paragraph.html.slim b/src/it/maven-site-plugin/src/site/asciidoc/templates/paragraph.html.slim new file mode 100644 index 00000000..0e213e64 --- /dev/null +++ b/src/it/maven-site-plugin/src/site/asciidoc/templates/paragraph.html.slim @@ -0,0 +1 @@ +p class=role =content diff --git a/src/it/maven-site-plugin/src/site/site.xml b/src/it/maven-site-plugin/src/site/site.xml new file mode 100644 index 00000000..31e63818 --- /dev/null +++ b/src/it/maven-site-plugin/src/site/site.xml @@ -0,0 +1,8 @@ + + + + + + ${reports} + + diff --git a/src/it/maven-site-plugin/validate.bsh b/src/it/maven-site-plugin/validate.bsh index 6a2bff16..dec50e30 100644 --- a/src/it/maven-site-plugin/validate.bsh +++ b/src/it/maven-site-plugin/validate.bsh @@ -1,37 +1,52 @@ import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -File outputDir = new File( basedir, "target/site" ); +File outputDir = new File(basedir, "target/site"); String[] expectedFiles = { "file-with-toc.html" }; +String[] unexpectedFiles = { + "_include.html" +}; + Pattern tocEntry = Pattern.compile("
  • .*"); Pattern elementIdPattern = Pattern.compile(".* id=\"(.*?)\".*"); -Matcher matcher = null; -for ( String expectedFile : expectedFiles ) -{ - File file = new File( outputDir, expectedFile ); - System.out.println( "Checking for existence of " + file ); - if ( !file.isFile() ) - { - throw new Exception( "Missing file " + file ); +for (String expectedFile : expectedFiles) { + File file = new File(outputDir, expectedFile); + System.out.println("Checking for presence of " + file); + if (!file.isFile()) { + throw new Exception("Missing file " + file); + } + + List lines = new ArrayList(); + Closeable resource = null; + try { + String line = null; + BufferedReader bReader = new BufferedReader(resource = new FileReader(file)); + while ((line = bReader.readLine()) != null) { + lines.add(line); + } + } + finally { + try { + resource.close(); + } + catch (IOException ignore) {} } - System.out.println("Ensuring that id's match TOC links"); - List lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); + System.out.println("Ensuring IDs match TOC links"); List tocEntries = new ArrayList(); for (String line : lines) { + Matcher matcher = null; matcher = tocEntry.matcher(line); if (matcher.matches()) { @@ -48,7 +63,35 @@ for ( String expectedFile : expectedFiles ) } if (tocEntries.size() != 0) { - throw new Exception("Couldn't find matching ids for the following TOC entries: " + tocEntries); + throw new Exception("Couldn't find matching IDs for the following TOC entries: " + tocEntries); + } + + boolean includeResolved = false; + boolean sourceHighlighted = false; + + for (String line : lines) { + if (!includeResolved && line.contains("Content included from the file _include.adoc")) { + includeResolved = true; + } + else if (!sourceHighlighted && line.contains("<plugin>")) { + sourceHighlighted = true; + } + } + + if (!includeResolved) { + throw new Exception("Include file was not resolved."); + } + + if (!sourceHighlighted) { + throw new Exception("Source code was not highlighted."); + } +} + +for (String unexpectedFile : unexpectedFiles) { + File file = new File(outputDir, unexpectedFile); + System.out.println("Checking for absence of " + file); + if (file.isFile()) { + throw new Exception("Unexpected file " + file); } } diff --git a/src/main/java/org/asciidoctor/maven/site/AsciidoctorLegacySiteModule.java b/src/main/java/org/asciidoctor/maven/site/AsciidoctorLegacySiteModule.java deleted file mode 100644 index 200c470f..00000000 --- a/src/main/java/org/asciidoctor/maven/site/AsciidoctorLegacySiteModule.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 org.asciidoctor.maven.site; - -import org.apache.maven.doxia.module.site.AbstractSiteModule; -import org.apache.maven.doxia.module.site.SiteModule; -import org.codehaus.plexus.component.annotations.Component; - -/** - * This class is the entry point for the site plugin integration. - * - * @author jdlee - */ -@Component(role = SiteModule.class, hint = AsciidoctorParser.ROLE_HINT) -public class AsciidoctorLegacySiteModule extends AbstractSiteModule { - - /** - * The source directory for AsciiDoc files. - */ - public static final String SOURCE_DIRECTORY = AsciidoctorParser.ROLE_HINT; - - /** - * The extension for AsciiDoc files. - */ - public static final String FILE_EXTENSION = "ad"; - - /** - * Build a new instance of {@link AsciidoctorSiteModule}. - */ - public AsciidoctorLegacySiteModule() { - super(SOURCE_DIRECTORY, FILE_EXTENSION, AsciidoctorParser.ROLE_HINT); - } -} diff --git a/src/main/java/org/asciidoctor/maven/site/AsciidoctorParser.java b/src/main/java/org/asciidoctor/maven/site/AsciidoctorParser.java index 49b28c25..261520b8 100644 --- a/src/main/java/org/asciidoctor/maven/site/AsciidoctorParser.java +++ b/src/main/java/org/asciidoctor/maven/site/AsciidoctorParser.java @@ -1,10 +1,14 @@ /* - * Licensed under the Apache License, Version 2.0 (the "License"); + * Copyright 2015 The Ascidoctor 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 + * + * 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, + * 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. @@ -15,13 +19,20 @@ import org.apache.maven.doxia.parser.ParseException; import org.apache.maven.doxia.parser.Parser; import org.apache.maven.doxia.sink.Sink; +import org.apache.maven.project.MavenProject; import org.asciidoctor.Asciidoctor; import org.asciidoctor.AttributesBuilder; import org.asciidoctor.OptionsBuilder; import org.asciidoctor.SafeMode; import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.Xpp3Dom; + +import org.asciidoctor.internal.JRubyRuntimeContext; +import org.asciidoctor.internal.RubyUtils; +import java.io.File; import java.io.IOException; import java.io.Reader; @@ -31,31 +42,139 @@ * process. * * @author jdlee + * @author mojavelinux */ @Component(role = Parser.class, hint = AsciidoctorParser.ROLE_HINT) public class AsciidoctorParser extends XhtmlParser { + @Requirement + protected MavenProject project; + /** * The role hint for the {@link AsciidoctorParser} Plexus component. */ public static final String ROLE_HINT = "asciidoc"; - protected final Asciidoctor asciidoctorInstance = Asciidoctor.Factory.create(); + protected final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); /** * {@inheritDoc} */ @Override - public void parse(Reader source, Sink sink) throws ParseException { + public void parse(Reader reader, Sink sink) throws ParseException { + String source = null; try { - // NOTE we have to generate a full document, but we unset stylesheet to keep framing minimal - String result = asciidoctorInstance.render(IOUtil.toString(source), - OptionsBuilder.options().headerFooter(false).safe(SafeMode.UNSAFE).backend("xhtml").attributes( - AttributesBuilder.attributes().unsetStyleSheet().attribute("idprefix", - "a_").asMap()).asMap()); - sink.rawText(result); - } catch (IOException ex) { - getLog().error(ex.getLocalizedMessage()); + source = IOUtil.toString(reader); + if (source == null) { + source = ""; + } + } + catch (IOException ex) { + getLog().error("Could not read AsciiDoc source: " + ex.getLocalizedMessage()); + return; + } + Xpp3Dom siteConfig = getSiteConfig(project); + File siteDirectory = resolveSiteDirectory(project, siteConfig); + OptionsBuilder options = processAsciiDocConfig( + siteConfig, + initOptions(project, siteDirectory), + initAttributes(project, siteDirectory)); + // QUESTION should we keep OptionsBuilder & AttributesBuilder separate for call to convertAsciiDoc? + sink.rawText(convertAsciiDoc(source, options)); + } + + protected Xpp3Dom getSiteConfig(MavenProject project) { + return project.getGoalConfiguration("org.apache.maven.plugins", "maven-site-plugin", "site", "site"); + } + + protected File resolveSiteDirectory(MavenProject project, Xpp3Dom siteConfig) { + File siteDirectory = new File(project.getBasedir(), "src/site"); + if (siteConfig != null) { + Xpp3Dom siteDirectoryNode = siteConfig.getChild("siteDirectory"); + if (siteDirectoryNode != null) { + siteDirectory = new File(siteDirectoryNode.getValue()); + } + } + return siteDirectory; + } + + protected OptionsBuilder initOptions(MavenProject project, File siteDirectory) { + return OptionsBuilder.options() + .backend("xhtml") + .safe(SafeMode.UNSAFE) + .baseDir(new File(siteDirectory, ROLE_HINT)); + } + + protected AttributesBuilder initAttributes(MavenProject project, File siteDirectory) { + return AttributesBuilder.attributes() + .attribute("idprefix", "@") + .attribute("showtitle", "@"); + } + + protected OptionsBuilder processAsciiDocConfig(Xpp3Dom siteConfig, OptionsBuilder options, AttributesBuilder attributes) { + if (siteConfig == null) { + return options.attributes(attributes); + } + + Xpp3Dom asciidocConfig = siteConfig.getChild("asciidoc"); + if (asciidocConfig == null) { + return options.attributes(attributes); + } + + for (Xpp3Dom asciidocOpt : asciidocConfig.getChildren()) { + String optName = asciidocOpt.getName(); + if ("attributes".equals(optName)) { + for (Xpp3Dom asciidocAttr : asciidocOpt.getChildren()) { + attributes.attribute(asciidocAttr.getName(), asciidocAttr.getValue()); + } + } + else if ("requires".equals(optName)) { + Xpp3Dom[] requires = asciidocOpt.getChildren("require"); + // supports variant: + // + // time + // + if (requires.length > 0) { + for (Xpp3Dom require : requires) { + requireLibrary(require.getValue()); + } + } + else { + // supports variant: + // time,base64 + for (String require : asciidocOpt.getValue().split(",")) { + requireLibrary(require); + } + } + } + // TODO support multiple template directories + else if ("templateDir".equals(optName) || "template_dir".equals(optName)) { + File templateDir = new File(asciidocOpt.getValue()); + if (!templateDir.isAbsolute()) { + templateDir = new File(project.getBasedir(), templateDir.toString()); + } + options.templateDir(templateDir); + } + else { + options.option(optName.replaceAll("(?') == 1 }