From 759f65f58692b83de956dfb331a4abfdf9466f0d Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Sun, 3 Nov 2024 19:04:55 +0100 Subject: [PATCH 1/8] Refactor asciidoctor-maven-plugin --- asciidoctor-maven-commons/pom.xml | 1 + .../maven/AsciidoctorJFactory.java | 55 ++++++ .../asciidoctor/maven/AsciidoctorMojo.java | 168 +++--------------- .../maven/AsciidoctorOptionsFactory.java | 90 ++++++++++ .../asciidoctor/maven/AsciidoctorZipMojo.java | 4 + .../maven/http/AsciidoctorHandler.java | 6 +- .../maven/process/CopyResourcesProcessor.java | 2 + .../maven/process/SourceDocumentFinder.java | 2 + .../asciidoctor/maven/test/MojoMocker.java | 9 + pom.xml | 14 ++ 10 files changed, 205 insertions(+), 146 deletions(-) create mode 100644 asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorJFactory.java create mode 100644 asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorOptionsFactory.java diff --git a/asciidoctor-maven-commons/pom.xml b/asciidoctor-maven-commons/pom.xml index d41012c6..168a45e4 100644 --- a/asciidoctor-maven-commons/pom.xml +++ b/asciidoctor-maven-commons/pom.xml @@ -37,6 +37,7 @@ ${maven.version} provided + org.codehaus.plexus plexus-utils diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorJFactory.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorJFactory.java new file mode 100644 index 00000000..a065b89a --- /dev/null +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorJFactory.java @@ -0,0 +1,55 @@ +package org.asciidoctor.maven; + +import java.io.File; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.asciidoctor.Asciidoctor; +import org.asciidoctor.jruby.AsciidoctorJRuby; +import org.asciidoctor.jruby.internal.JRubyRuntimeContext; +import org.jruby.Ruby; + +import javax.inject.Singleton; + +@Singleton +public class AsciidoctorJFactory { + + Asciidoctor create(String gemPath, Log log) throws MojoExecutionException { + Asciidoctor asciidoctor; + if (gemPath == null) { + asciidoctor = AsciidoctorJRuby.Factory.create(); + } else { + // Replace Windows path separator to avoid paths with mixed \ and /. + // This happens for instance when setting: ${project.build.directory}/gems-provided + // because the project's path is converted to string. + String normalizedGemPath = (File.separatorChar == '\\') ? gemPath.replaceAll("\\\\", "/") : gemPath; + asciidoctor = AsciidoctorJRuby.Factory.create(normalizedGemPath); + } + + Ruby rubyInstance = null; + try { + rubyInstance = (Ruby) JRubyRuntimeContext.class.getMethod("get") + .invoke(null); + } catch (NoSuchMethodException e) { + if (rubyInstance == null) { + try { + rubyInstance = (Ruby) JRubyRuntimeContext.class.getMethod("get", Asciidoctor.class).invoke(null, asciidoctor); + } catch (Exception e1) { + throw new MojoExecutionException("Failed to invoke get(AsciiDoctor) for JRubyRuntimeContext", e1); + } + + } + } catch (Exception e) { + throw new MojoExecutionException("Failed to invoke get for JRubyRuntimeContext", e); + } + + String gemHome = rubyInstance.evalScriptlet("ENV['GEM_HOME']").toString(); + String gemHomeExpected = (gemPath == null || "".equals(gemPath)) ? "" : gemPath.split(java.io.File.pathSeparator)[0]; + + if (!"".equals(gemHome) && !gemHomeExpected.equals(gemHome)) { + log.warn("Using inherited external environment to resolve gems (" + gemHome + "), i.e. build is platform dependent!"); + } + + return asciidoctor; + } +} diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java index a51bc12b..5e5fac7d 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -22,14 +21,8 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.asciidoctor.Asciidoctor; -import org.asciidoctor.Attributes; -import org.asciidoctor.AttributesBuilder; import org.asciidoctor.Options; import org.asciidoctor.OptionsBuilder; -import org.asciidoctor.SafeMode; -import org.asciidoctor.jruby.AsciidoctorJRuby; -import org.asciidoctor.jruby.internal.JRubyRuntimeContext; -import org.asciidoctor.maven.commons.AsciidoctorHelper; import org.asciidoctor.maven.extensions.AsciidoctorJExtensionRegistry; import org.asciidoctor.maven.extensions.ExtensionConfiguration; import org.asciidoctor.maven.extensions.ExtensionRegistry; @@ -38,14 +31,10 @@ import org.asciidoctor.maven.log.LogRecordsProcessors; import org.asciidoctor.maven.log.MemoryLogHandler; import org.asciidoctor.maven.model.Resource; -import org.asciidoctor.maven.process.CopyResourcesProcessor; import org.asciidoctor.maven.process.ResourcesProcessor; import org.asciidoctor.maven.process.SourceDirectoryFinder; import org.asciidoctor.maven.process.SourceDocumentFinder; -import org.jruby.Ruby; -import static org.asciidoctor.maven.commons.StringUtils.isBlank; -import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; import static org.asciidoctor.maven.process.SourceDirectoryFinder.DEFAULT_SOURCE_DIR; @@ -145,9 +134,14 @@ public class AsciidoctorMojo extends AbstractMojo { @Inject protected MavenProject project; - - - protected final ResourcesProcessor defaultResourcesProcessor = new CopyResourcesProcessor(); + @Inject + private AsciidoctorJFactory asciidoctorJFactory; + @Inject + private SourceDocumentFinder finder; + @Inject + protected ResourcesProcessor defaultResourcesProcessor; + @Inject + private AsciidoctorOptionsFactory asciidoctorOptionsFactory; @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -209,7 +203,8 @@ public void processSources(List sourceFiles, ResourcesProcessor resourcesP } } - final Asciidoctor asciidoctor = getAsciidoctorInstance(gemPath); + final Asciidoctor asciidoctor = asciidoctorJFactory.create(gemPath, getLog()); + if (enableVerbose) { asciidoctor.requireLibrary("enable_verbose.rb"); } @@ -224,8 +219,7 @@ public void processSources(List sourceFiles, ResourcesProcessor resourcesP } } - AttributesBuilder attributesBuilder = createAttributesBuilder(this, project); - OptionsBuilder optionsBuilder = createOptionsBuilder(this, attributesBuilder); + OptionsBuilder optionsBuilder = asciidoctorOptionsFactory.create(this, project, getLog()); // Copy output resources final File sourceDir = sourceDirectoryCandidate.get(); @@ -234,7 +228,7 @@ public void processSources(List sourceFiles, ResourcesProcessor resourcesP // register LogHandler to capture asciidoctor messages final Boolean outputToConsole = logHandler.getOutputToConsole() == null ? Boolean.TRUE : logHandler.getOutputToConsole(); final MemoryLogHandler memoryLogHandler = new MemoryLogHandler(outputToConsole, - logRecord -> getLog().info(LogRecordFormatter.format(logRecord, sourceDir))); + logRecord -> getLog().info(LogRecordFormatter.format(logRecord, sourceDir))); asciidoctor.registerLogHandler(memoryLogHandler); // disable default console output of AsciidoctorJ Logger.getLogger("asciidoctor").setUseParentHandlers(false); @@ -257,7 +251,7 @@ public void processSources(List sourceFiles, ResourcesProcessor resourcesP try { // process log messages according to mojo configuration new LogRecordsProcessors(logHandler, sourceDir, errorMessage -> getLog().error(errorMessage)) - .processLogRecords(memoryLogHandler); + .processLogRecords(memoryLogHandler); } catch (Exception exception) { throw new MojoExecutionException(exception.getMessage()); } @@ -266,12 +260,12 @@ public void processSources(List sourceFiles, ResourcesProcessor resourcesP public Optional findSourceDirectory(File initialSourceDirectory, File baseDir) { Optional sourceDirCandidate = new SourceDirectoryFinder(initialSourceDirectory, baseDir, - candidate -> { - String candidateName = candidate.toString(); - if (isRelativePath(candidateName)) candidateName = candidateName.substring(2); - getLog().info("sourceDirectory " + candidateName + " does not exist"); - }) - .find(); + candidate -> { + String candidateName = candidate.toString(); + if (isRelativePath(candidateName)) candidateName = candidateName.substring(2); + getLog().info("sourceDirectory " + candidateName + " does not exist"); + }) + .find(); return sourceDirCandidate; } @@ -317,8 +311,8 @@ public Destination setDestinationPaths(final File sourceFile, final OptionsBuild // allow overriding the output file name optionsBuilder.toFile(outputFile); return outputFile.isAbsolute() - ? new Destination(outputFile, true) - : new Destination(new File(toDir, outputFile.getPath()), true); + ? new Destination(outputFile, true) + : new Destination(new File(toDir, outputFile.getPath()), true); } else { return new Destination(new File(toDir, sourceFile.getName()), false); } @@ -338,59 +332,14 @@ class Destination { } } - protected Asciidoctor getAsciidoctorInstance(String gemPath) throws MojoExecutionException { - Asciidoctor asciidoctor; - if (gemPath == null) { - asciidoctor = AsciidoctorJRuby.Factory.create(); - } else { - // Replace Windows path separator to avoid paths with mixed \ and /. - // This happens for instance when setting: ${project.build.directory}/gems-provided - // because the project's path is converted to string. - String normalizedGemPath = (File.separatorChar == '\\') ? gemPath.replaceAll("\\\\", "/") : gemPath; - asciidoctor = AsciidoctorJRuby.Factory.create(normalizedGemPath); - } - - Ruby rubyInstance = null; - try { - rubyInstance = (Ruby) JRubyRuntimeContext.class.getMethod("get") - .invoke(null); - } catch (NoSuchMethodException e) { - if (rubyInstance == null) { - try { - rubyInstance = (Ruby) JRubyRuntimeContext.class.getMethod( - "get", Asciidoctor.class).invoke(null, asciidoctor); - } catch (Exception e1) { - throw new MojoExecutionException( - "Failed to invoke get(AsciiDoctor) for JRubyRuntimeContext", - e1); - } - - } - } catch (Exception e) { - throw new MojoExecutionException( - "Failed to invoke get for JRubyRuntimeContext", e); - } - - String gemHome = rubyInstance.evalScriptlet("ENV['GEM_HOME']").toString(); - String gemHomeExpected = (gemPath == null || "".equals(gemPath)) ? "" : gemPath.split(java.io.File.pathSeparator)[0]; - - if (!"".equals(gemHome) && !gemHomeExpected.equals(gemHome)) { - getLog().warn("Using inherited external environment to resolve gems (" + gemHome + "), i.e. build is platform dependent!"); - } - - return asciidoctor; - } - protected List findSourceFiles(File sourceDirectory) { if (sourceDocumentName != null) - return Arrays.asList(new File(sourceDirectory, sourceDocumentName)); - - Path sourceDirectoryPath = sourceDirectory.toPath(); - SourceDocumentFinder finder = new SourceDocumentFinder(); + return List.of(new File(sourceDirectory, sourceDocumentName)); + final Path sourceDirectoryPath = sourceDirectory.toPath(); return sourceDocumentExtensions.isEmpty() ? - finder.find(sourceDirectoryPath) : - finder.find(sourceDirectoryPath, sourceDocumentExtensions); + finder.find(sourceDirectoryPath) : + finder.find(sourceDirectoryPath, sourceDocumentExtensions); } protected void convertFile(Asciidoctor asciidoctor, Options options, File f) { @@ -409,73 +358,6 @@ protected boolean ensureOutputExists() { return true; } - /** - * Creates an OptionsBuilder instance with the options defined in the configuration. - * - * @param configuration AsciidoctorMojo containing conversion configuration. - * @param attributesBuilder If not null, Asciidoctor attributes to add to the OptionsBuilder created. - * @return initialized optionsBuilder. - */ - protected OptionsBuilder createOptionsBuilder(AsciidoctorMojo configuration, AttributesBuilder attributesBuilder) { - - final OptionsBuilder optionsBuilder = Options.builder() - .backend(configuration.getBackend()) - .safe(SafeMode.UNSAFE) - .standalone(configuration.standalone) - .mkDirs(true); - - if (!isBlank(configuration.getEruby())) - optionsBuilder.eruby(configuration.getEruby()); - - if (configuration.isSourcemap()) - optionsBuilder.option(Options.SOURCEMAP, true); - - if (configuration.isCatalogAssets()) - optionsBuilder.option(Options.CATALOG_ASSETS, true); - - if (!configuration.isTemplateCache()) - optionsBuilder.option(Options.TEMPLATE_CACHE, false); - - if (configuration.getDoctype() != null) - optionsBuilder.docType(doctype); - - if (configuration.getTemplateEngine() != null) - optionsBuilder.templateEngine(templateEngine); - - if (!configuration.getTemplateDirs().isEmpty()) - optionsBuilder.templateDirs(templateDirs.toArray(new File[]{})); - - optionsBuilder.attributes(attributesBuilder.build()); - return optionsBuilder; - } - - /** - * Creates an AttributesBuilder instance with the attributes defined in the configuration. - * - * @param configuration AsciidoctorMojo containing conversion configuration. - * @param mavenProject Current {@link MavenProject} instance. - * @return initialized attributesBuilder. - */ - protected AttributesBuilder createAttributesBuilder(AsciidoctorMojo configuration, MavenProject mavenProject) { - - final AttributesBuilder attributesBuilder = Attributes.builder(); - - if (configuration.isEmbedAssets()) { - attributesBuilder.linkCss(false); - attributesBuilder.dataUri(true); - } - - AsciidoctorHelper.addProperties(mavenProject.getProperties(), attributesBuilder); - AsciidoctorHelper.addAttributes(configuration.getAttributes(), attributesBuilder); - - if (isNotBlank(configuration.getAttributesChain())) { - getLog().info("Attributes: " + attributesChain); - attributesBuilder.arguments(attributesChain); - } - - return attributesBuilder; - } - public File getSourceDirectory() { return sourceDirectory; } diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorOptionsFactory.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorOptionsFactory.java new file mode 100644 index 00000000..70d52033 --- /dev/null +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorOptionsFactory.java @@ -0,0 +1,90 @@ +package org.asciidoctor.maven; + +import javax.inject.Singleton; +import java.io.File; + +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.asciidoctor.Attributes; +import org.asciidoctor.AttributesBuilder; +import org.asciidoctor.Options; +import org.asciidoctor.OptionsBuilder; +import org.asciidoctor.SafeMode; +import org.asciidoctor.maven.commons.AsciidoctorHelper; + +import static org.asciidoctor.maven.commons.StringUtils.isBlank; +import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; + +@Singleton +public class AsciidoctorOptionsFactory { + + /** + * Creates an AttributesBuilder instance with the attributes defined in the configuration. + * + * @param configuration AsciidoctorMojo containing conversion configuration. + * @param mavenProject Current {@link MavenProject} instance. + * @param log The mojo's {@link Log} reference. + * @return initialized attributesBuilder. + */ + private Attributes createAttributes(AsciidoctorMojo configuration, MavenProject mavenProject, Log log) { + + final AttributesBuilder attributesBuilder = Attributes.builder(); + + if (configuration.isEmbedAssets()) { + attributesBuilder.linkCss(false); + attributesBuilder.dataUri(true); + } + + AsciidoctorHelper.addProperties(mavenProject.getProperties(), attributesBuilder); + AsciidoctorHelper.addAttributes(configuration.getAttributes(), attributesBuilder); + + if (isNotBlank(configuration.getAttributesChain())) { + log.info("Attributes: " + configuration.getAttributesChain()); + attributesBuilder.arguments(configuration.getAttributesChain()); + } + + return attributesBuilder.build(); + } + + /** + * Creates an OptionsBuilder instance with the options defined in the configuration. + * + * @param configuration AsciidoctorMojo containing conversion configuration. + * @param project Current {@link MavenProject} instance. + * @param log The mojo's {@link Log} reference. + * @return initialized optionsBuilder. + */ + OptionsBuilder create(AsciidoctorMojo configuration, MavenProject project, Log log) { + + final OptionsBuilder optionsBuilder = Options.builder() + .backend(configuration.getBackend()) + .safe(SafeMode.UNSAFE) + .standalone(configuration.standalone) + .mkDirs(true); + + if (!isBlank(configuration.getEruby())) + optionsBuilder.eruby(configuration.getEruby()); + + if (configuration.isSourcemap()) + optionsBuilder.option(Options.SOURCEMAP, true); + + if (configuration.isCatalogAssets()) + optionsBuilder.option(Options.CATALOG_ASSETS, true); + + if (!configuration.isTemplateCache()) + optionsBuilder.option(Options.TEMPLATE_CACHE, false); + + if (configuration.getDoctype() != null) + optionsBuilder.docType(configuration.getDoctype()); + + if (configuration.getTemplateEngine() != null) + optionsBuilder.templateEngine(configuration.getTemplateEngine()); + + if (!configuration.getTemplateDirs().isEmpty()) + optionsBuilder.templateDirs(configuration.getTemplateDirs().toArray(new File[]{})); + + final Attributes attributes = createAttributes(configuration, project, log); + return optionsBuilder.attributes(attributes); + } + +} diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java index 0557fec4..cc5385e1 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; +import jnr.ffi.annotations.In; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; @@ -10,6 +11,9 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProjectHelper; import org.asciidoctor.maven.io.Zips; +import org.asciidoctor.maven.process.SourceDocumentFinder; + +import javax.inject.Inject; @Deprecated(since = "3.0.0", forRemoval = true) @Mojo(name = "zip") diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/http/AsciidoctorHandler.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/http/AsciidoctorHandler.java index 8744b353..d1827e25 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/http/AsciidoctorHandler.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/http/AsciidoctorHandler.java @@ -21,7 +21,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -public class AsciidoctorHandler extends SimpleChannelInboundHandler { +class AsciidoctorHandler extends SimpleChannelInboundHandler { private static final String HTML_MEDIA_TYPE = "text/html"; public static final String HTML_EXTENSION = ".html"; @@ -29,7 +29,7 @@ public class AsciidoctorHandler extends SimpleChannelInboundHandler T mock(Class clazz, Map mavenProperties, LogHandler logHa parametersInitializer.initialize(mojo); setVariableValueInObject(mojo, "log", new SystemStreamLog()); setVariableValueInObject(mojo, "project", mockMavenProject(mavenProperties)); + setVariableValueInObject(mojo, "asciidoctorJFactory", new AsciidoctorJFactory()); + setVariableValueInObject(mojo, "asciidoctorOptionsFactory", new AsciidoctorOptionsFactory()); + setVariableValueInObject(mojo, "defaultResourcesProcessor", new CopyResourcesProcessor()); + setVariableValueInObject(mojo, "finder", new SourceDocumentFinder()); + if (logHandler != null) setVariableValueInObject(mojo, "logHandler", logHandler); diff --git a/pom.xml b/pom.xml index 7fb70c42..23b9d5bd 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,20 @@ ${project.java.version} + + + org.eclipse.sisu + sisu-maven-plugin + 0.9.0.M3 + + + generate-index + + main-index + + + + From a0c75ea39104238e5446099e6a037e781eeb2b10 Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Sun, 3 Nov 2024 19:27:11 +0100 Subject: [PATCH 2/8] Use constructor injection --- .../maven/AsciidoctorHttpMojo.java | 8 ++++ .../asciidoctor/maven/AsciidoctorMojo.java | 22 +++++++---- .../maven/AsciidoctorRefreshMojo.java | 11 ++++-- .../asciidoctor/maven/AsciidoctorZipMojo.java | 7 ++++ .../process/CopyResourcesProcessorTest.java | 38 ++++++++++--------- ...CopyFileAlterationListenerAdaptorTest.java | 12 ++++-- .../asciidoctor/maven/test/MojoMocker.java | 2 +- 7 files changed, 68 insertions(+), 32 deletions(-) diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java index c5d31303..653e4422 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorHttpMojo.java @@ -1,10 +1,14 @@ package org.asciidoctor.maven; +import javax.inject.Inject; + import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.asciidoctor.maven.http.AsciidoctorHttpServer; +import org.asciidoctor.maven.process.ResourcesProcessor; +import org.asciidoctor.maven.process.SourceDocumentFinder; @Mojo(name = "http") public class AsciidoctorHttpMojo extends AsciidoctorRefreshMojo { @@ -17,6 +21,10 @@ public class AsciidoctorHttpMojo extends AsciidoctorRefreshMojo { @Parameter(property = PREFIX + "home", defaultValue = "index") protected String home; + @Inject + public AsciidoctorHttpMojo(AsciidoctorJFactory asciidoctorJFactory, AsciidoctorOptionsFactory asciidoctorOptionsFactory, SourceDocumentFinder finder, ResourcesProcessor defaultResourcesProcessor) { + super(asciidoctorJFactory, asciidoctorOptionsFactory, finder, defaultResourcesProcessor); + } @Override public void execute() throws MojoExecutionException, MojoFailureException { diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java index 5e5fac7d..51d6c904 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java @@ -134,14 +134,22 @@ public class AsciidoctorMojo extends AbstractMojo { @Inject protected MavenProject project; + + private final AsciidoctorJFactory asciidoctorJFactory; + + private final AsciidoctorOptionsFactory asciidoctorOptionsFactory; + + private final SourceDocumentFinder finder; + + protected final ResourcesProcessor defaultResourcesProcessor; + @Inject - private AsciidoctorJFactory asciidoctorJFactory; - @Inject - private SourceDocumentFinder finder; - @Inject - protected ResourcesProcessor defaultResourcesProcessor; - @Inject - private AsciidoctorOptionsFactory asciidoctorOptionsFactory; + public AsciidoctorMojo(AsciidoctorJFactory asciidoctorJFactory, AsciidoctorOptionsFactory asciidoctorOptionsFactory, SourceDocumentFinder finder, ResourcesProcessor defaultResourcesProcessor) { + this.asciidoctorJFactory = asciidoctorJFactory; + this.asciidoctorOptionsFactory = asciidoctorOptionsFactory; + this.finder = finder; + this.defaultResourcesProcessor = defaultResourcesProcessor; + } @Override public void execute() throws MojoExecutionException, MojoFailureException { diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java index da4c385e..87fd50d8 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorRefreshMojo.java @@ -1,5 +1,6 @@ package org.asciidoctor.maven; +import javax.inject.Inject; import java.io.File; import java.io.FileFilter; import java.util.Collection; @@ -19,6 +20,8 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; +import org.asciidoctor.maven.process.ResourcesProcessor; +import org.asciidoctor.maven.process.SourceDocumentFinder; import org.asciidoctor.maven.refresh.AdditionalSourceFileAlterationListenerAdaptor; import org.asciidoctor.maven.refresh.AsciidoctorConverterFileAlterationListenerAdaptor; import org.asciidoctor.maven.refresh.ResourceCopyFileAlterationListenerAdaptor; @@ -26,9 +29,7 @@ import org.asciidoctor.maven.refresh.TimeCounter; import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; -import static org.asciidoctor.maven.process.SourceDocumentFinder.CUSTOM_FILE_EXTENSIONS_PATTERN_PREFIX; -import static org.asciidoctor.maven.process.SourceDocumentFinder.CUSTOM_FILE_EXTENSIONS_PATTERN_SUFFIX; -import static org.asciidoctor.maven.process.SourceDocumentFinder.STANDARD_FILE_EXTENSIONS_PATTERN; +import static org.asciidoctor.maven.process.SourceDocumentFinder.*; @Mojo(name = "auto-refresh") public class AsciidoctorRefreshMojo extends AsciidoctorMojo { @@ -43,6 +44,10 @@ public class AsciidoctorRefreshMojo extends AsciidoctorMojo { private Collection monitors = null; + @Inject + public AsciidoctorRefreshMojo(AsciidoctorJFactory asciidoctorJFactory, AsciidoctorOptionsFactory asciidoctorOptionsFactory, SourceDocumentFinder finder, ResourcesProcessor defaultResourcesProcessor) { + super(asciidoctorJFactory, asciidoctorOptionsFactory, finder, defaultResourcesProcessor); + } @Override public void execute() throws MojoExecutionException, MojoFailureException { diff --git a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java index cc5385e1..d7cc032b 100644 --- a/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java +++ b/asciidoctor-maven-plugin/src/main/java/org/asciidoctor/maven/AsciidoctorZipMojo.java @@ -11,6 +11,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProjectHelper; import org.asciidoctor.maven.io.Zips; +import org.asciidoctor.maven.process.ResourcesProcessor; import org.asciidoctor.maven.process.SourceDocumentFinder; import javax.inject.Inject; @@ -18,6 +19,7 @@ @Deprecated(since = "3.0.0", forRemoval = true) @Mojo(name = "zip") public class AsciidoctorZipMojo extends AsciidoctorMojo { + public static final String PREFIX = AsciidoctorMaven.PREFIX + "zip."; @Component @@ -36,6 +38,11 @@ public class AsciidoctorZipMojo extends AsciidoctorMojo { @Parameter(property = PREFIX + "zipClassifier", defaultValue = "asciidoctor") protected String zipClassifier; + @Inject + public AsciidoctorZipMojo(AsciidoctorJFactory asciidoctorJFactory, AsciidoctorOptionsFactory asciidoctorOptionsFactory, SourceDocumentFinder finder, ResourcesProcessor defaultResourcesProcessor) { + super(asciidoctorJFactory, asciidoctorOptionsFactory, finder, defaultResourcesProcessor); + } + @Override public void execute() throws MojoExecutionException, MojoFailureException { super.execute(); diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/process/CopyResourcesProcessorTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/process/CopyResourcesProcessorTest.java index fc6376a3..6a066961 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/process/CopyResourcesProcessorTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/process/CopyResourcesProcessorTest.java @@ -31,7 +31,7 @@ public class CopyResourcesProcessorTest { @Test void should_not_fail_when_source_does_not_exist() { File nonExistentDir = new File(sourceDir, UUID.randomUUID().toString()); - AsciidoctorMojo config = new AsciidoctorMojo(); + AsciidoctorMojo config = createMojo(); resourceProcessor.process(nonExistentDir, outputDir, config); @@ -43,7 +43,7 @@ void should_not_fail_when_source_does_not_exist() { @Test void should_not_fail_when_output_does_not_exist() { File nonExistentDir = new File(sourceDir, UUID.randomUUID().toString()); - AsciidoctorMojo config = new AsciidoctorMojo(); + AsciidoctorMojo config = createMojo(); resourceProcessor.process(sourceDir, nonExistentDir, config); @@ -58,7 +58,7 @@ void should_ignore_asciidoc_source_files() { for (String fileExtension : fileExtensions) createFileWithContent(sourceDir, "source." + fileExtension); - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(sourceDir.listFiles()).hasSize(fileExtensions.length); assertThat(outputDir.listFiles()).hasSize(0); @@ -73,7 +73,7 @@ void should_ignore_docinfo_files() { createFileWithContent(sourceDir, filename); } - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(sourceDir.listFiles()).hasSize(IGNORED_FILE_NAMES.length); assertThat(outputDir.listFiles()).hasSize(0); @@ -82,7 +82,7 @@ void should_ignore_docinfo_files() { @Test void should_ignore_sourceDocumentName() { final String sourceDocumentName = "my-file.special"; - AsciidoctorMojo config = new AsciidoctorMojo(); + AsciidoctorMojo config = createMojo(); config.setSourceDocumentName(sourceDocumentName); createFileWithContent(sourceDir, sourceDocumentName); @@ -95,7 +95,7 @@ void should_ignore_sourceDocumentName() { @Test void should_ignore_sourceDocumentExtensions() { final List fileExtensions = Arrays.asList("ext1", "ext2", "exta", "extb"); - AsciidoctorMojo config = new AsciidoctorMojo(); + AsciidoctorMojo config = createMojo(); config.setSourceDocumentExtensions(fileExtensions); for (String fileExtension : fileExtensions) @@ -111,7 +111,7 @@ void should_copy_resources_in_root_source_directory() { createFileWithContent(sourceDir, "image.jpg"); createFileWithContent(sourceDir, "image.gif"); - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(outputDir.list()) .containsExactlyInAnyOrder("image.jpg", "image.gif"); @@ -123,7 +123,7 @@ void should_not_copy_empty_directories() throws IOException { FileUtils.forceMkdir(new File(sourceDir, "sub_2")); FileUtils.forceMkdir(new File(sourceDir, "sub_1/sub_1_2")); - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(outputDir.list()) .hasSize(0); @@ -137,7 +137,7 @@ void should_copy_resources_in_root_source_directory() { createFileWithContent(sourceDir, "image.jpg"); createFileWithContent(sourceDir, "image.gif"); - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(outputDir.list()) .containsExactlyInAnyOrder("image.jpg", "image.gif"); @@ -149,7 +149,7 @@ void should_copy_resources_in_sub_directories() { createFileWithContent(new File(sourceDir, "sub_2"), "image.gif"); createFileWithContent(new File(sourceDir, "sub_1/sub_1_2"), "image.bmp"); - resourceProcessor.process(sourceDir, outputDir, new AsciidoctorMojo()); + resourceProcessor.process(sourceDir, outputDir, createMojo()); assertThat(outputDir.list()) .containsExactlyInAnyOrder("sub_1", "sub_2"); @@ -171,7 +171,7 @@ void should_only_copy_resources_in_single_include() { .directory(sourceDir.getAbsolutePath()) .includes("**/*.txt") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -198,7 +198,7 @@ void should_only_copy_resources_with_multiple_includes() { .directory(sourceDir.getAbsolutePath()) .includes("**/*.txt", "**/*.doc") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -235,7 +235,7 @@ void should_only_copy_resources_in_multiple_includes() { .directory(sourceDir.getAbsolutePath()) .includes("**/*.img") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource1, resource2)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -268,7 +268,7 @@ void should_copy_resources_without_including_excluded_files() { .directory(sourceDir.getAbsolutePath()) .excludes("**/*.img") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.img"); @@ -298,7 +298,7 @@ void should_copy_resources_into_custom_relative_target_path() { .targetPath(targetPath) .excludes("**/*.img") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -334,7 +334,7 @@ void should_copy_resources_into_custom_absolute_target_path() { .targetPath(targetPath) .excludes("**/*.img") .build(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(Arrays.asList(resource)); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -365,7 +365,7 @@ void should_copy_resources_into_custom_absolute_target_path() { @Test void should_not_copy_any_resource() { List resources = ResourceBuilder.excludeAll(); - AsciidoctorMojo configuration = new AsciidoctorMojo(); + AsciidoctorMojo configuration = createMojo(); configuration.setResources(resources); createFileWithContent(new File(sourceDir, "sub_1"), "image-1.txt"); @@ -383,4 +383,8 @@ void should_not_copy_any_resource() { assertThat(outputDir.list()).hasSize(0); } } + + private static AsciidoctorMojo createMojo() { + return new AsciidoctorMojo(null, null, null,null); + } } diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/refresh/ResourceCopyFileAlterationListenerAdaptorTest.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/refresh/ResourceCopyFileAlterationListenerAdaptorTest.java index 03c07fb9..d91052e1 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/refresh/ResourceCopyFileAlterationListenerAdaptorTest.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/refresh/ResourceCopyFileAlterationListenerAdaptorTest.java @@ -33,7 +33,7 @@ void should_copy_files_when_match_resource_includes() { final File srcDir = newOutputTestDirectory(TEST_DIR); final File outputDir = newOutputTestDirectory(TEST_DIR); - final AsciidoctorRefreshMojo mojo = new AsciidoctorRefreshMojo(); + final AsciidoctorRefreshMojo mojo = createRefreshMojo(); final Log logSpy = Mockito.spy(Log.class); final ResourceCopyFileAlterationListenerAdaptor listenerAdaptor = new ResourceCopyFileAlterationListenerAdaptor(mojo, EMPTY_RUNNABLE, logSpy); @@ -72,7 +72,7 @@ void should_not_copy_files_when_match_resource_excludes() { final File srcDir = newOutputTestDirectory(TEST_DIR); final File outputDir = newOutputTestDirectory(TEST_DIR); - final AsciidoctorRefreshMojo mojo = new AsciidoctorRefreshMojo(); + final AsciidoctorRefreshMojo mojo = createRefreshMojo(); final Log logSpy = Mockito.spy(Log.class); final ResourceCopyFileAlterationListenerAdaptor listenerAdaptor = new ResourceCopyFileAlterationListenerAdaptor(mojo, EMPTY_RUNNABLE, logSpy); @@ -111,7 +111,7 @@ void should_copy_and_ignore_files_when_matching_both_resource_includes_and_exclu final File srcDir = newOutputTestDirectory(TEST_DIR); final File outputDir = newOutputTestDirectory(TEST_DIR); - final AsciidoctorRefreshMojo mojo = new AsciidoctorRefreshMojo(); + final AsciidoctorRefreshMojo mojo = createRefreshMojo(); final Log logSpy = Mockito.spy(Log.class); final ResourceCopyFileAlterationListenerAdaptor listenerAdaptor = new ResourceCopyFileAlterationListenerAdaptor(mojo, EMPTY_RUNNABLE, logSpy); @@ -152,7 +152,7 @@ void should_copy_special_asciidoctor_files() { final File srcDir = newOutputTestDirectory(TEST_DIR); final File outputDir = newOutputTestDirectory(TEST_DIR); - final AsciidoctorRefreshMojo mojo = new AsciidoctorRefreshMojo(); + final AsciidoctorRefreshMojo mojo = createRefreshMojo(); final Log logSpy = Mockito.spy(Log.class); final ResourceCopyFileAlterationListenerAdaptor listenerAdaptor = new ResourceCopyFileAlterationListenerAdaptor(mojo, EMPTY_RUNNABLE, logSpy); @@ -186,4 +186,8 @@ void should_copy_special_asciidoctor_files() { assertThat(outputCandidate).exists(); }); } + + private static AsciidoctorRefreshMojo createRefreshMojo() { + return new AsciidoctorRefreshMojo(null, null, null, null); + } } diff --git a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMocker.java b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMocker.java index ae7cd11f..7292e0fd 100644 --- a/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMocker.java +++ b/asciidoctor-maven-plugin/src/test/java/org/asciidoctor/maven/test/MojoMocker.java @@ -26,7 +26,7 @@ class MojoMocker { @SuppressWarnings("unchecked") T mock(Class clazz, Map mavenProperties, LogHandler logHandler) { - final AsciidoctorMojo mojo = (AsciidoctorMojo) clazz.getConstructor(new Class[]{}).newInstance(); + final AsciidoctorMojo mojo = (AsciidoctorMojo) clazz.getConstructors()[0].newInstance(new Object[]{null, null, null, null}); parametersInitializer.initialize(mojo); setVariableValueInObject(mojo, "log", new SystemStreamLog()); From ad938445cf159b6b3919f1b6677f915303b0525a Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Sat, 9 Nov 2024 21:30:58 +0100 Subject: [PATCH 3/8] Refactor site modules --- .../site/AsciidoctorConverterDoxiaParser.java | 84 +-- .../maven/site/SiteConverterDecorator.java | 13 +- .../AsciidoctorConverterDoxiaParserTest.java | 9 +- .../site/SiteConverterDecoratorTest.java | 28 +- .../maven/site/LogHandlerFactory.java | 28 + .../maven/site/SiteBaseDirResolver.java | 10 +- .../site/SiteConversionConfiguration.java | 21 +- .../SiteConversionConfigurationParser.java | 89 ++- ...SiteConversionConfigurationParserTest.java | 598 ++++++++++-------- .../parser/AsciidoctorAstDoxiaParser.java | 83 +-- .../parser/AsciidoctorAstDoxiaParserTest.java | 14 +- 11 files changed, 545 insertions(+), 432 deletions(-) create mode 100644 asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java diff --git a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java index e334ad3d..488aea86 100644 --- a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java +++ b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java @@ -1,7 +1,6 @@ package org.asciidoctor.maven.site; import javax.inject.Inject; -import javax.inject.Provider; import java.io.File; import java.io.IOException; import java.io.Reader; @@ -12,14 +11,8 @@ import org.apache.maven.doxia.sink.Sink; import org.apache.maven.project.MavenProject; import org.asciidoctor.Asciidoctor; -import org.asciidoctor.Attributes; -import org.asciidoctor.AttributesBuilder; -import org.asciidoctor.Options; -import org.asciidoctor.OptionsBuilder; -import org.asciidoctor.SafeMode; import org.asciidoctor.maven.commons.StringUtils; import org.asciidoctor.maven.log.LogHandler; -import org.asciidoctor.maven.log.LogRecordFormatter; import org.asciidoctor.maven.log.LogRecordsProcessors; import org.asciidoctor.maven.log.MemoryLogHandler; import org.asciidoctor.maven.site.SiteConverterDecorator.Result; @@ -29,8 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.asciidoctor.maven.site.SiteBaseDirResolver.resolveBaseDir; - /** * This class is used by the Doxia framework * to handle the actual parsing of the AsciiDoc input files into HTML to be consumed/wrapped @@ -43,15 +34,21 @@ @Component(role = Parser.class, hint = AsciidoctorConverterDoxiaParser.ROLE_HINT) public class AsciidoctorConverterDoxiaParser extends AbstractTextParser { - private static final Logger logger = LoggerFactory.getLogger(AsciidoctorConverterDoxiaParser.class); - - @Inject - protected Provider mavenProjectProvider; - /** * The role hint for the {@link AsciidoctorConverterDoxiaParser} Plexus component. */ - public static final String ROLE_HINT = "asciidoc"; + static final String ROLE_HINT = "asciidoc"; + + private static final Logger logger = LoggerFactory.getLogger(AsciidoctorConverterDoxiaParser.class); + + @Inject + private MavenProject mavenProject; + @Inject + private SiteConversionConfigurationParser siteConfigParser; + @Inject + private LogHandlerFactory logHandlerFactory; + @Inject + private SiteConverterDecorator siteConverter; /** * {@inheritDoc} @@ -68,9 +65,9 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept return; } - final MavenProject project = mavenProjectProvider.get(); - final Xpp3Dom siteConfig = getSiteConfig(project); - final File siteDirectory = resolveBaseDir(project.getBasedir(), siteConfig); + final SiteConversionConfiguration conversionConfig = siteConfigParser.processAsciiDocConfig(mavenProject, ROLE_HINT); + final Xpp3Dom siteConfig = conversionConfig.getSiteConfig(); + final File siteDirectory = conversionConfig.getSiteBaseDir(); // Doxia handles a single instance of this class and invokes it multiple times. // We need to ensure certain elements are initialized only once to avoid errors. @@ -78,17 +75,14 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept // And overriding init and other methods form parent classes does not work. final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); - SiteConversionConfiguration conversionConfig = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, defaultOptions(siteDirectory), defaultAttributes()); for (String require : conversionConfig.getRequires()) { requireLibrary(asciidoctor, require); } - final LogHandler logHandler = getLogHandlerConfig(siteConfig); - final MemoryLogHandler memoryLogHandler = asciidoctorLoggingSetup(asciidoctor, siteDirectory); + final LogHandler logHandler = logHandlerFactory.getConfiguration(siteConfig); + final MemoryLogHandler memoryLogHandler = logHandlerFactory.create(asciidoctor, siteDirectory, logger); - final SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); - final Result headerMetadata = siteConverter.process(source, conversionConfig.getOptions()); + final Result headerMetadata = siteConverter.process(asciidoctor, source, conversionConfig.getOptions()); try { // process log messages according to mojo configuration @@ -97,7 +91,7 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept if (logHandler.getOutputToConsole() && StringUtils.isNotBlank(reference)) { memoryLogHandler.processAll(); } - new LogRecordsProcessors(logHandler, siteDirectory, errorMessage -> logger.error(errorMessage)) + new LogRecordsProcessors(logHandler, siteDirectory, logger::error) .processLogRecords(memoryLogHandler); } } catch (Exception exception) { @@ -110,45 +104,6 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept sink.rawText(headerMetadata.getHtml()); } - private MemoryLogHandler asciidoctorLoggingSetup(Asciidoctor asciidoctor, File siteDirectory) { - - final MemoryLogHandler memoryLogHandler = new MemoryLogHandler(false, - logRecord -> logger.info(LogRecordFormatter.format(logRecord, siteDirectory))); - asciidoctor.registerLogHandler(memoryLogHandler); - // disable default console output of AsciidoctorJ - java.util.logging.Logger.getLogger("asciidoctor").setUseParentHandlers(false); - return memoryLogHandler; - } - - private LogHandler getLogHandlerConfig(Xpp3Dom siteConfig) { - Xpp3Dom asciidoc = siteConfig == null ? null : siteConfig.getChild("asciidoc"); - return new SiteLogHandlerDeserializer().deserialize(asciidoc); - } - - protected Xpp3Dom getSiteConfig(MavenProject project) { - return project.getGoalConfiguration("org.apache.maven.plugins", "maven-site-plugin", "site", "site"); - } - - - // The possible baseDir based on configuration are: - // - // with nothing : src/site + /asciidoc - // with locale : src/site + {locale} + /asciidoc - // with siteDirectory : {siteDirectory} + /asciidoc - // with siteDirectory + locale : {siteDirectory} + {locale} + /asciidoc - protected OptionsBuilder defaultOptions(File siteDirectory) { - return Options.builder() - .backend("xhtml") - .safe(SafeMode.UNSAFE) - .baseDir(new File(siteDirectory, ROLE_HINT).getAbsoluteFile()); - } - - protected AttributesBuilder defaultAttributes() { - return Attributes.builder() - .attribute("idprefix", "@") - .attribute("showtitle", "@"); - } - private void requireLibrary(Asciidoctor asciidoctor, String require) { if (!(require = require.trim()).isEmpty()) { try { @@ -158,4 +113,5 @@ private void requireLibrary(Asciidoctor asciidoctor, String require) { } } } + } diff --git a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/SiteConverterDecorator.java b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/SiteConverterDecorator.java index 8fecdaae..6e916f62 100644 --- a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/SiteConverterDecorator.java +++ b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/SiteConverterDecorator.java @@ -1,5 +1,6 @@ package org.asciidoctor.maven.site; +import javax.inject.Singleton; import java.util.Map; import org.asciidoctor.Asciidoctor; @@ -10,16 +11,13 @@ /** * Asciidoctor conversion wrapper for maven-site integration. * In addition to conversion, handles header metadata extraction. + * + * @since 3.0.0 */ +@Singleton class SiteConverterDecorator { - private final Asciidoctor asciidoctor; - - SiteConverterDecorator(Asciidoctor asciidoctor) { - this.asciidoctor = asciidoctor; - } - - Result process(String content, Options options) { + Result process(Asciidoctor asciidoctor, String content, Options options) { final Document document = asciidoctor.load(content, headerProcessingMetadata(options)); final HeaderMetadata headerMetadata = HeaderMetadata.from(document); @@ -61,5 +59,4 @@ String getHtml() { } } - } diff --git a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java index 1c485b95..748cf0b3 100644 --- a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java +++ b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java @@ -247,14 +247,14 @@ void should_fail_when_logHandler_failIf_is_WARNING() { } @SneakyThrows - private javax.inject.Provider createMavenProjectMock(String configuration) { + private MavenProject createMockMavenProject(String configuration) { MavenProject mockProject = Mockito.mock(MavenProject.class); when(mockProject.getBasedir()) .thenReturn(new File(".")); when(mockProject.getGoalConfiguration(anyString(), anyString(), anyString(), anyString())) .thenReturn(configuration != null ? Xpp3DomBuilder.build(new StringReader(configuration)) : null); - return () -> mockProject; + return mockProject; } @SneakyThrows @@ -265,7 +265,10 @@ private AsciidoctorConverterDoxiaParser mockAsciidoctorDoxiaParser() { @SneakyThrows private AsciidoctorConverterDoxiaParser mockAsciidoctorDoxiaParser(String configuration) { AsciidoctorConverterDoxiaParser parser = new AsciidoctorConverterDoxiaParser(); - setVariableValueInObject(parser, "mavenProjectProvider", createMavenProjectMock(configuration)); + setVariableValueInObject(parser, "mavenProject", createMockMavenProject(configuration)); + setVariableValueInObject(parser, "siteConfigParser", new SiteConversionConfigurationParser(new SiteBaseDirResolver())); + setVariableValueInObject(parser, "logHandlerFactory", new LogHandlerFactory()); + setVariableValueInObject(parser, "siteConverter", new SiteConverterDecorator()); return parser; } diff --git a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/SiteConverterDecoratorTest.java b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/SiteConverterDecoratorTest.java index db098b8e..0e432759 100644 --- a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/SiteConverterDecoratorTest.java +++ b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/SiteConverterDecoratorTest.java @@ -28,10 +28,10 @@ class SiteConverterDecoratorTest { "Hello, AsciiDoc!\n================" }) void should_extract_title_from_header(String title) { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); Options options = defaultOptions(); - Result result = siteConverter.process(title + "\n", options); + Result result = siteConverter.process(asciidoctor, title + "\n", options); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getTitle()).isEqualTo("Hello, AsciiDoc!"); @@ -40,7 +40,7 @@ void should_extract_title_from_header(String title) { @Test void should_extract_title_from_attribute() { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); Options options = Options.builder() .safe(SafeMode.UNSAFE) @@ -51,7 +51,7 @@ void should_extract_title_from_attribute() { .attribute("who", "me") .build()) .build(); - Result result = siteConverter.process("= Hello, {who}!\n", options); + Result result = siteConverter.process(asciidoctor, "= Hello, {who}!\n", options); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getTitle()).isEqualTo("Hello, me!"); @@ -62,10 +62,10 @@ void should_extract_title_from_attribute() { @ParameterizedTest @MethodSource("authorsProvider") void should_extract_author(String content, String expected) { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); Options options = defaultOptions(); - Result result = siteConverter.process(content + "\n", options); + Result result = siteConverter.process(asciidoctor, content + "\n", options); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getAuthors()) @@ -84,11 +84,11 @@ private static Stream authorsProvider() { @Test void should_extract_author_from_attribute() { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); String content = "= Hello, AsciiDoc!"; Options options = optionsWithAttributes(Collections.singletonMap("author", "From Attr")); - Result result = siteConverter.process(content + "\n", options); + Result result = siteConverter.process(asciidoctor, content + "\n", options); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getAuthors()) @@ -98,10 +98,10 @@ void should_extract_author_from_attribute() { @Test void should_extract_multiple_authors() { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); String content = "= Hello, AsciiDoc!\nfirstname1 lastname2; firstname3 middlename4 lastname5"; - Result result = siteConverter.process(content + "\n", defaultOptions()); + Result result = siteConverter.process(asciidoctor, content + "\n", defaultOptions()); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getAuthors()) @@ -111,10 +111,10 @@ void should_extract_multiple_authors() { @Test void should_extract_datetime_generated() { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); String content = "= Hello, AsciiDoc!"; - Result result = siteConverter.process(content + "\n", defaultOptions()); + Result result = siteConverter.process(asciidoctor, content + "\n", defaultOptions()); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getDateTime()).matches("(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2}) .*"); @@ -123,11 +123,11 @@ void should_extract_datetime_generated() { @Test void should_extract_datetime_from_attribute() { - SiteConverterDecorator siteConverter = new SiteConverterDecorator(asciidoctor); + SiteConverterDecorator siteConverter = new SiteConverterDecorator(); String content = "= Hello, AsciiDoc!"; Options options = optionsWithAttributes(Collections.singletonMap("docdatetime", "2024-11-22")); - Result result = siteConverter.process(content + "\n", options); + Result result = siteConverter.process(asciidoctor, content + "\n", options); HeaderMetadata headerMetadata = result.getHeaderMetadata(); assertThat(headerMetadata.getDateTime()).isEqualTo("2024-11-22"); diff --git a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java new file mode 100644 index 00000000..5fb17e75 --- /dev/null +++ b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java @@ -0,0 +1,28 @@ +package org.asciidoctor.maven.site; + +import org.asciidoctor.Asciidoctor; +import org.asciidoctor.maven.log.LogHandler; +import org.asciidoctor.maven.log.LogRecordFormatter; +import org.asciidoctor.maven.log.MemoryLogHandler; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.slf4j.Logger; + +import java.io.File; + +public class LogHandlerFactory { + + public LogHandler getConfiguration(Xpp3Dom siteConfig) { + Xpp3Dom asciidoc = siteConfig == null ? null : siteConfig.getChild("asciidoc"); + return new SiteLogHandlerDeserializer().deserialize(asciidoc); + } + + public MemoryLogHandler create(Asciidoctor asciidoctor, File siteDirectory, Logger logger) { + + final MemoryLogHandler memoryLogHandler = new MemoryLogHandler(false, + logRecord -> logger.info(LogRecordFormatter.format(logRecord, siteDirectory))); + asciidoctor.registerLogHandler(memoryLogHandler); + // disable default console output of AsciidoctorJ + java.util.logging.Logger.getLogger("asciidoctor").setUseParentHandlers(false); + return memoryLogHandler; + } +} diff --git a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteBaseDirResolver.java b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteBaseDirResolver.java index 124ea910..23073e65 100644 --- a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteBaseDirResolver.java +++ b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteBaseDirResolver.java @@ -1,5 +1,6 @@ package org.asciidoctor.maven.site; +import javax.inject.Singleton; import java.io.File; import java.nio.file.Path; @@ -15,11 +16,14 @@ * @author abelsromero * @since 3.1.1 */ +@Singleton public class SiteBaseDirResolver { private static final Logger logger = LoggerFactory.getLogger(SiteBaseDirResolver.class); + private static final String DEFAULT_SOURCE_LOCATION = "src/site"; - public static File resolveBaseDir(File mavenBaseDir, Xpp3Dom siteConfig) { + + File resolveBaseDir(File mavenBaseDir, Xpp3Dom siteConfig) { final String siteDirectory = resolveSiteDirectory(siteConfig); final String locale = resolveLocale(siteConfig); @@ -32,9 +36,9 @@ public static File resolveBaseDir(File mavenBaseDir, Xpp3Dom siteConfig) { return normalize(path, siteDirectory); if (locale != null) - return normalize(path, "src/site", locale); + return normalize(path, DEFAULT_SOURCE_LOCATION, locale); - return normalize(path, "src/site"); + return normalize(path, DEFAULT_SOURCE_LOCATION); } private static String resolveSiteDirectory(Xpp3Dom siteConfig) { diff --git a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfiguration.java b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfiguration.java index 98e32920..0ac8805f 100644 --- a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfiguration.java +++ b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfiguration.java @@ -1,19 +1,36 @@ package org.asciidoctor.maven.site; +import java.io.File; import java.util.List; import org.asciidoctor.Options; +import org.codehaus.plexus.util.xml.Xpp3Dom; -public class SiteConversionConfiguration { +public final class SiteConversionConfiguration { + private final Xpp3Dom siteConfig; + private final File siteBaseDir; private final Options options; private final List requires; - SiteConversionConfiguration(Options options, List requires) { + SiteConversionConfiguration(Xpp3Dom siteConfig, + File siteBaseDir, + Options options, + List requires) { + this.siteConfig = siteConfig; + this.siteBaseDir = siteBaseDir; this.options = options; this.requires = requires; } + public File getSiteBaseDir() { + return siteBaseDir; + } + + public Xpp3Dom getSiteConfig() { + return siteConfig; + } + public Options getOptions() { return options; } diff --git a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfigurationParser.java b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfigurationParser.java index 840184e5..cde397c9 100644 --- a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfigurationParser.java +++ b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/SiteConversionConfigurationParser.java @@ -1,49 +1,69 @@ package org.asciidoctor.maven.site; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.apache.maven.project.MavenProject; import org.asciidoctor.Attributes; import org.asciidoctor.AttributesBuilder; import org.asciidoctor.Options; import org.asciidoctor.OptionsBuilder; +import org.asciidoctor.SafeMode; import org.asciidoctor.maven.commons.AsciidoctorHelper; import org.asciidoctor.maven.commons.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; +/** + * Extract Asciidoctor required configurations from Maven Site Plugin + * configuration in POM file. + * + * @author mojavelinux + * @author abelsromero + * @since 2.0.0 + */ +@Singleton public class SiteConversionConfigurationParser { - private final MavenProject project; + private final SiteBaseDirResolver siteBaseDirResolver; - public SiteConversionConfigurationParser(MavenProject project) { - this.project = project; + @Inject + public SiteConversionConfigurationParser(SiteBaseDirResolver siteBaseDirResolver) { + this.siteBaseDirResolver = siteBaseDirResolver; } - public SiteConversionConfiguration processAsciiDocConfig(Xpp3Dom siteConfig, - OptionsBuilder presetOptions, - AttributesBuilder presetAttributes) { + Xpp3Dom getSiteConfig(MavenProject project) { + return project.getGoalConfiguration("org.apache.maven.plugins", "maven-site-plugin", "site", "site"); + } - AsciidoctorHelper.addProperties(project.getProperties(), presetAttributes); + public SiteConversionConfiguration processAsciiDocConfig(MavenProject mavenProject, String roleHint) { + final AttributesBuilder presetAttributes = defaultAttributes(); + AsciidoctorHelper.addProperties(mavenProject.getProperties(), presetAttributes); final Attributes attributes = presetAttributes.build(); + final File siteDir = siteBaseDirResolver.resolveBaseDir(mavenProject.getBasedir(), getSiteConfig(mavenProject)); + final OptionsBuilder presetOptions = defaultOptions(siteDir, roleHint); + + final Xpp3Dom siteConfig = getSiteConfig(mavenProject); if (siteConfig == null) { final Options options = presetOptions.attributes(attributes).build(); - return new SiteConversionConfiguration(options, Collections.emptyList()); + // TODO refactor this "always null" + return new SiteConversionConfiguration(siteConfig, siteDir, options, Collections.emptyList()); } final Xpp3Dom asciidocConfig = siteConfig.getChild("asciidoc"); if (asciidocConfig == null) { final Options options = presetOptions.attributes(attributes).build(); - return new SiteConversionConfiguration(options, Collections.emptyList()); + return new SiteConversionConfiguration(siteConfig, siteDir, options, Collections.emptyList()); } final List gemsToRequire = new ArrayList<>(); @@ -57,9 +77,9 @@ public SiteConversionConfiguration processAsciiDocConfig(Xpp3Dom siteConfig, if (requireNode.getValue().contains(",")) { // time, base64 Stream.of(requireNode.getValue().split(",")) - .filter(StringUtils::isNotBlank) - .map(String::trim) - .forEach(value -> gemsToRequire.add(value)); + .filter(StringUtils::isNotBlank) + .map(String::trim) + .forEach(value -> gemsToRequire.add(value)); } else { // // time @@ -76,23 +96,42 @@ public SiteConversionConfiguration processAsciiDocConfig(Xpp3Dom siteConfig, } } else if ("templateDirs".equals(optName) || "template_dirs".equals(optName)) { List dirs = Arrays.stream(asciidocOpt.getChildren("dir")) - .filter(node -> isNotBlank(node.getValue())) - .map(node -> resolveProjectDir(project, node.getValue())) - .collect(Collectors.toList()); + .filter(node -> isNotBlank(node.getValue())) + .map(node -> resolveProjectDir(mavenProject, node.getValue())) + .collect(Collectors.toList()); presetOptions.templateDirs(dirs.toArray(new File[dirs.size()])); } else if ("baseDir".equals(optName)) { - presetOptions.baseDir(resolveProjectDir(project, asciidocOpt.getValue())); + presetOptions.baseDir(resolveProjectDir(mavenProject, asciidocOpt.getValue())); } else { presetOptions.option(optName.replaceAll("(? optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); assertThat(configuration.getRequires()).isEmpty(); } @Test void should_return_default_configuration_when_asciidoc_xml_is_null() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.siteNode() - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.siteNode().build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); + // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + final Map optionsMap = assertContainsDefaultAttributes(configuration); + assertThat((String) optionsMap.get(BACKEND)).isEqualTo("xhtml"); + assertThat((String) optionsMap.get(BASEDIR)).endsWith(defaultPluginSources()); + assertThat((Integer) optionsMap.get(SAFE)).isEqualTo(SafeMode.UNSAFE.getLevel()); assertThat(configuration.getRequires()).isEmpty(); } + // TODO this should be the same? + private CharSequence defaultSiteSources() { + return String.join(File.separator, new String[]{"src", "site"}); + } + + private CharSequence defaultPluginSources() { + return String.join(File.separator, new String[]{"src", "site", "asciidoc"}); + } + @Test void should_return_simple_single_requires() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("requires") - .addChild("require", "gem") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("requires") + .addChild("require", "gem") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); assertThat(configuration.getRequires()) - .containsExactly("gem"); + .containsExactly("gem"); } @Test void should_return_multiple_requires() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("requires") - .addChild("require", "gem_1", "gem_2", "gem_3") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("requires") + .addChild("require", "gem_1", "gem_2", "gem_3") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); assertThat(configuration.getRequires()) - .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); + .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); } @Test void should_return_multiple_requires_when_defined_in_single_element() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("requires") - .addChild("require", "gem_1,gem_2, gem_3") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("requires") + .addChild("require", "gem_1,gem_2, gem_3") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); assertThat(configuration.getRequires()) - .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); + .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); } @Test void should_remove_empty_and_blank_requires() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("requires") - .addChild("require", "gem_1,,gem_2", "", ",,", "gem_3") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("requires") + .addChild("require", "gem_1,,gem_2", "", ",,", "gem_3") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); assertThat(configuration.getRequires()) - .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); + .containsExactlyInAnyOrder("gem_1", "gem_2", "gem_3"); } @Test void should_return_attributes() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("attributes") - .addChild("imagesdir", "./images") - .parent().addChild("source-highlighter", "coderay") - .parent().addChild("sectnums") - .parent().addChild("toc") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("attributes") + .addChild("imagesdir", "./images") + .parent().addChild("source-highlighter", "coderay") + .parent().addChild("sectnums") + .parent().addChild("toc") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); Map attributes = (Map) configuration.getOptions() - .map() - .get(ATTRIBUTES); - assertThat(attributes). - containsExactlyInAnyOrderEntriesOf(map( - entry("imagesdir", "./images"), - entry("source-highlighter", "coderay"), - entry("sectnums", ""), - entry("toc", "") - )); + .map() + .get(ATTRIBUTES); + assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( + entry("idprefix", "@"), + entry("imagesdir", "./images"), + entry("sectnums", ""), + entry("showtitle", "@"), + entry("source-highlighter", "coderay"), + entry("toc", "") + )); } @Test void should_map_null_attributes_as_empty_string() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("attributes") - .addChild("toc") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("attributes") + .addChild("toc") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - Map attributes = (Map) configuration - .getOptions() - .map() - .get(ATTRIBUTES); - assertThat(attributes). - containsExactlyInAnyOrderEntriesOf(map( - entry("toc", "") - )); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); + Map attributes = (Map) configuration.getOptions() + .map() + .get(ATTRIBUTES); + assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( + entry("idprefix", "@"), + entry("showtitle", "@"), + entry("toc", "") + )); + } @Test void should_map_true_boolean_attribute_as_empty_string_value() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("attributes") - .addChild("toc", "true") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("attributes") + .addChild("toc", "true") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); Map attributes = (Map) configuration - .getOptions() - .map() - .get(ATTRIBUTES); - assertThat(attributes). - containsExactlyInAnyOrderEntriesOf(map( - entry("toc", "") - )); + .getOptions() + .map() + .get(ATTRIBUTES); + assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( + entry("idprefix", "@"), + entry("showtitle", "@"), + entry("toc", "") + )); } @Test void should_map_false_boolean_attribute_as_null_value() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("attributes") - .addChild("toc", "false") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("attributes") + .addChild("toc", "false") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap) - .hasSize(1); - Map attributes = (Map) optionsMap.get(ATTRIBUTES); - assertThat(attributes). - containsExactlyInAnyOrderEntriesOf(map( - entry("toc", null) - )); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); + Map attributes = (Map) configuration + .getOptions() + .map() + .get(ATTRIBUTES); + assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( + entry("idprefix", "@"), + entry("showtitle", "@"), + entry("toc", null) + )); } @Test void should_return_template_dirs_when_defined_as_templateDirs_dir() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("templateDirs") - .addChild("dir", "path") - .parent() - .addChild("dir", "path2") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("templateDirs") + .addChild("dir", "path") + .parent() + .addChild("dir", "path2") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultAttributes(configuration); + assertThat(configuration.getRequires()).isEmpty(); + final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, TEMPLATE_DIRS); + assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, BACKEND, BASEDIR, SAFE, TEMPLATE_DIRS); assertThat(optionsMap.get(TEMPLATE_DIRS)) - .isEqualTo(Arrays.asList( - new File("path").getAbsolutePath(), - new File("path2").getAbsolutePath() - )); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + .isEqualTo(Arrays.asList( + new File("path").getAbsolutePath(), + new File("path2").getAbsolutePath() + )); } @Test void should_return_template_dirs_when_defined_as_template_dirs_dir() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("template_dirs") - .addChild("dir", "path") - .parent() - .addChild("dir", "path2") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("template_dirs") + .addChild("dir", "path") + .parent() + .addChild("dir", "path2") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultAttributes(configuration); + assertThat(configuration.getRequires()).isEmpty(); + final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, TEMPLATE_DIRS); + assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, BACKEND, BASEDIR, SAFE, TEMPLATE_DIRS); assertThat(optionsMap.get(TEMPLATE_DIRS)) - .isEqualTo(Arrays.asList( - new File("path").getAbsolutePath(), - new File("path2").getAbsolutePath() - )); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + .isEqualTo(Arrays.asList( + new File("path").getAbsolutePath(), + new File("path2").getAbsolutePath() + )); } @Test void should_not_return_empty_template_dirs() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("template_dirs") - .addChild("dir", "") - .parent() - .addChild("dir") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("template_dirs") + .addChild("dir", "") + .parent() + .addChild("dir") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); - // then - final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + // then: BASE_DIR option is not even added + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertContainsDefaultAttributes(configuration); + assertThat(configuration.getRequires()).isEmpty(); } @Test void should_return_baseDir_dirs_when_defined_as_template_dirs_dir() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("baseDir", "path") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("baseDir", "path") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then - final Map optionsMap = configuration.getOptions().map(); + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultAttributes(configuration); + assertThat(configuration.getRequires()).isEmpty(); - assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, BASEDIR); + final Map optionsMap = configuration.getOptions().map(); + assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, BACKEND, BASEDIR, SAFE); + assertThat((String) optionsMap.get(BACKEND)).isEqualTo("xhtml"); + assertThat((Integer) optionsMap.get(SAFE)).isEqualTo(SafeMode.UNSAFE.getLevel()); assertThat(optionsMap.get(BASEDIR)) - .isEqualTo(new File("path").getAbsolutePath()); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); + .isEqualTo(new File("path").getAbsolutePath()); } @Test void should_return_any_configuration_inside_asciidoc_node_as_option() { // given - final MavenProject project = fakeProject(); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() - .addChild("option-1", "value-1") - .parent().addChild("option_2", "value-2") - .parent().addChild("_option-3", "value-3") - .parent().addChild("option-4_", "value-4") - .parent().addChild("option.5", "value-5") - .build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode() + .addChild("option-1", "value-1") + .parent().addChild("option_2", "value-2") + .parent().addChild("_option-3", "value-3") + .parent().addChild("option-4_", "value-4") + .parent().addChild("option.5", "value-5") + .build(); + final MavenProject project = fakeMavenProjectBuilder().siteConfig(siteConfig).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultAttributes(configuration); + assertThat(configuration.getRequires()).isEmpty(); + final Map optionsMap = configuration.getOptions().map(); assertThat(optionsMap) - .containsOnlyKeys(ATTRIBUTES, "option-1", "option_2", "_option-3", "option-4_", "option.5"); + .containsOnlyKeys( + ATTRIBUTES, BACKEND, BASEDIR, SAFE, + "option-1", "option_2", "_option-3", "option-4_", "option.5"); assertThat(optionsMap.get("option-1")).isEqualTo("value-1"); assertThat(optionsMap.get("option_2")).isEqualTo("value-2"); assertThat(optionsMap.get("_option-3")).isEqualTo("value-3"); assertThat(optionsMap.get("option-4_")).isEqualTo("value-4"); assertThat(optionsMap.get("option.5")).isEqualTo("value-5"); - assertThat((Map) optionsMap.get(ATTRIBUTES)).isEmpty(); } @Test @@ -398,22 +417,24 @@ void should_return_and_format_any_maven_project_property_as_attribute_when_site_ final Map projectProperties = new HashMap<>(); projectProperties.put("mvn.property-test1", "value-1"); projectProperties.put("mvn-property.test2", "value_2"); - final MavenProject project = fakeProject(projectProperties); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); + final MavenProject project = fakeMavenProjectBuilder().properties(projectProperties).build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(null, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); + final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap) - .containsOnlyKeys(ATTRIBUTES); Map attributes = (Map) optionsMap.get(ATTRIBUTES); assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( - entry("mvn-property-test1", "value-1"), - entry("mvn-property-test2", "value_2") + entry("mvn-property-test1", "value-1"), + entry("mvn-property-test2", "value_2"), + entry("idprefix", "@"), + entry("showtitle", "@") )); } @@ -423,40 +444,123 @@ void should_return_and_format_any_maven_project_property_as_attribute_when_site_ final Map projectProperties = new HashMap<>(); projectProperties.put("mvn.property-test1", "value-1"); projectProperties.put("mvn-property.test2", "value_2"); - final MavenProject project = fakeProject(projectProperties); - OptionsBuilder emptyOptions = Options.builder(); - AttributesBuilder emptyAttributes = Attributes.builder(); - Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode().build(); + final Xpp3Dom siteConfig = Xpp3DoomBuilder.asciidocNode().build(); + final MavenProject project = fakeMavenProjectBuilder() + .properties(projectProperties) + .siteConfig(siteConfig) + .build(); // when - SiteConversionConfiguration configuration = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, emptyOptions, emptyAttributes); + SiteConversionConfiguration configuration = configParser.processAsciiDocConfig(project, ROLE_HINT); // then + assertThat(configuration.getSiteBaseDir().getPath()).endsWith(defaultSiteSources()); + assertThat(configuration.getSiteConfig()).isNotNull(); + assertContainsDefaultOptions(configuration); + assertThat(configuration.getRequires()).isEmpty(); + final Map optionsMap = configuration.getOptions().map(); - assertThat(optionsMap) - .containsOnlyKeys(ATTRIBUTES); Map attributes = (Map) optionsMap.get(ATTRIBUTES); assertThat(attributes).containsExactlyInAnyOrderEntriesOf(map( - entry("mvn-property-test1", "value-1"), - entry("mvn-property-test2", "value_2") + entry("mvn-property-test1", "value-1"), + entry("mvn-property-test2", "value_2"), + entry("idprefix", "@"), + entry("showtitle", "@") )); } + private void assertContainsDefaultOptions(SiteConversionConfiguration configuration) { + final Map optionsMap = configuration.getOptions().map(); + assertThat(optionsMap).containsOnlyKeys(ATTRIBUTES, BACKEND, BASEDIR, SAFE); + assertThat((String) optionsMap.get(BACKEND)).isEqualTo("xhtml"); + assertThat((String) optionsMap.get(BASEDIR)).endsWith(defaultPluginSources()); + assertThat((Integer) optionsMap.get(SAFE)).isEqualTo(SafeMode.UNSAFE.getLevel()); + } + + private static Map assertContainsDefaultAttributes(SiteConversionConfiguration configuration) { + final Map optionsMap = configuration.getOptions().map(); + assertThat((Map) optionsMap.get(ATTRIBUTES)).containsExactly( + MapEntry.entry("idprefix", "@"), + MapEntry.entry("showtitle", "@") + ); + return optionsMap; + } + + static class FakeMavenProjectBuilder { + Xpp3Dom siteConfig = null; + Map properties = null; + + static FakeMavenProjectBuilder fakeMavenProjectBuilder() { + return new FakeMavenProjectBuilder(); + } + + FakeMavenProjectBuilder siteConfig(Xpp3Dom siteConfig) { + this.siteConfig = siteConfig; + return this; + } + + FakeMavenProjectBuilder properties(Map properties) { + this.properties = properties; + return this; + } + + MavenProject build() { + final Model model = new Model(); + + if (properties != null) { + model.getProperties().putAll(properties); + } + + final MavenProject project = new MavenProject(model); + project.setFile(new File(".").getAbsoluteFile()); + + final Build build = new Build(); + if (siteConfig != null) { + final Plugin sitePlugin = new Plugin(); + sitePlugin.setGroupId("org.apache.maven.plugins"); + sitePlugin.setArtifactId("maven-site-plugin"); + + final PluginExecution pluginExecution = new PluginExecution(); + pluginExecution.setId("site"); + pluginExecution.setGoals(List.of("site")); + sitePlugin.setExecutions(List.of(pluginExecution)); + + pluginExecution.setConfiguration(siteConfig); + + build.addPlugin(sitePlugin); + } + + model.setBuild(build); + return project; + } + } + private MavenProject fakeProject() { return fakeProject(null); } private MavenProject fakeProject(Map properties) { - MavenProject project; + final Model model = new Model(); + if (properties != null) { - final Model model = new Model(); model.getProperties().putAll(properties); - project = new MavenProject(model); - } else { - project = new MavenProject(); } + + final MavenProject project = new MavenProject(model); + final Plugin sitePlugin = new Plugin(); + sitePlugin.setGroupId("org.apache.maven.plugins"); + sitePlugin.setArtifactId("maven-site-plugin"); + final PluginExecution pluginExecution = new PluginExecution(); + pluginExecution.setId("site"); + pluginExecution.setGoals(List.of("site")); + sitePlugin.setExecutions(List.of(pluginExecution)); + final Build build = new Build(); + build.addPlugin(sitePlugin); + model.setBuild(build); + + project.setFile(new File(".").getAbsoluteFile()); + return project; } diff --git a/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java b/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java index bc0602ce..a7c60d7d 100644 --- a/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java +++ b/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java @@ -1,11 +1,9 @@ package org.asciidoctor.maven.site.parser; import javax.inject.Inject; -import javax.inject.Provider; import java.io.File; import java.io.IOException; import java.io.Reader; -import java.util.logging.Logger; import org.apache.maven.doxia.parser.AbstractTextParser; import org.apache.maven.doxia.parser.ParseException; @@ -13,29 +11,24 @@ import org.apache.maven.doxia.sink.Sink; import org.apache.maven.project.MavenProject; import org.asciidoctor.Asciidoctor; -import org.asciidoctor.Attributes; -import org.asciidoctor.AttributesBuilder; -import org.asciidoctor.Options; -import org.asciidoctor.OptionsBuilder; -import org.asciidoctor.SafeMode; import org.asciidoctor.ast.Document; import org.asciidoctor.maven.commons.StringUtils; import org.asciidoctor.maven.log.LogHandler; -import org.asciidoctor.maven.log.LogRecordFormatter; import org.asciidoctor.maven.log.LogRecordsProcessors; import org.asciidoctor.maven.log.MemoryLogHandler; import org.asciidoctor.maven.site.HeadParser; import org.asciidoctor.maven.site.HeaderMetadata; -import org.asciidoctor.maven.site.SiteConversionConfiguration; +import org.asciidoctor.maven.site.LogHandlerFactory; import org.asciidoctor.maven.site.SiteConversionConfigurationParser; -import org.asciidoctor.maven.site.SiteLogHandlerDeserializer; +import org.asciidoctor.maven.site.SiteConversionConfiguration; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.asciidoctor.maven.commons.StringUtils.isNotBlank; -import static org.asciidoctor.maven.site.SiteBaseDirResolver.resolveBaseDir; + /** * This class is used by the Doxia framework @@ -48,16 +41,20 @@ @Component(role = Parser.class, hint = AsciidoctorAstDoxiaParser.ROLE_HINT) public class AsciidoctorAstDoxiaParser extends AbstractTextParser { - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AsciidoctorAstDoxiaParser.class); - - @Inject - protected Provider mavenProjectProvider; - /** * The role hint for the {@link AsciidoctorAstDoxiaParser} Plexus component. */ public static final String ROLE_HINT = "asciidoc"; + private static final Logger logger = LoggerFactory.getLogger(AsciidoctorAstDoxiaParser.class); + + @Inject + private MavenProject mavenProject; + @Inject + private SiteConversionConfigurationParser siteConfigParser; + @Inject + private LogHandlerFactory logHandlerFactory; + /** * {@inheritDoc} */ @@ -73,9 +70,9 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept return; } - final MavenProject project = mavenProjectProvider.get(); - final Xpp3Dom siteConfig = getSiteConfig(project); - final File siteDirectory = resolveBaseDir(project.getBasedir(), siteConfig); + final SiteConversionConfiguration conversionConfig = siteConfigParser.processAsciiDocConfig(mavenProject, ROLE_HINT); + final Xpp3Dom siteConfig = conversionConfig.getSiteConfig(); + final File siteDirectory = conversionConfig.getSiteBaseDir(); // Doxia handles a single instance of this class and invokes it multiple times. // We need to ensure certain elements are initialized only once to avoid errors. @@ -83,19 +80,17 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept // And overriding init and other methods form parent classes does not work. final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); - SiteConversionConfiguration conversionConfig = new SiteConversionConfigurationParser(project) - .processAsciiDocConfig(siteConfig, defaultOptions(siteDirectory), defaultAttributes()); for (String require : conversionConfig.getRequires()) { requireLibrary(asciidoctor, require); } - final LogHandler logHandler = getLogHandlerConfig(siteConfig); - final MemoryLogHandler memoryLogHandler = asciidoctorLoggingSetup(asciidoctor, siteDirectory); - if (isNotBlank(reference)) logger.debug("Document loaded: {}", reference); - Document document = asciidoctor.load(source, conversionConfig.getOptions()); + final LogHandler logHandler = logHandlerFactory.getConfiguration(siteConfig); + final MemoryLogHandler memoryLogHandler = logHandlerFactory.create(asciidoctor, siteDirectory, logger); + + final Document document = asciidoctor.load(source, conversionConfig.getOptions()); try { // process log messages according to mojo configuration @@ -104,54 +99,20 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept if (logHandler.getOutputToConsole() && StringUtils.isNotBlank(reference)) { memoryLogHandler.processAll(); } - new LogRecordsProcessors(logHandler, siteDirectory, errorMessage -> logger.error(errorMessage)) + new LogRecordsProcessors(logHandler, siteDirectory, logger::error) .processLogRecords(memoryLogHandler); } } catch (Exception exception) { throw new ParseException(exception.getMessage(), exception); } - HeaderMetadata headerMetadata = HeaderMetadata.from(document); - new HeadParser(sink) - .parse(headerMetadata); + .parse(HeaderMetadata.from(document)); new NodeSinker(sink) .sink(document); } - private MemoryLogHandler asciidoctorLoggingSetup(Asciidoctor asciidoctor, File siteDirectory) { - - final MemoryLogHandler memoryLogHandler = new MemoryLogHandler(false, - logRecord -> logger.info(LogRecordFormatter.format(logRecord, siteDirectory))); - asciidoctor.registerLogHandler(memoryLogHandler); - // disable default console output of AsciidoctorJ - Logger.getLogger("asciidoctor").setUseParentHandlers(false); - return memoryLogHandler; - } - - private LogHandler getLogHandlerConfig(Xpp3Dom siteConfig) { - Xpp3Dom asciidoc = siteConfig == null ? null : siteConfig.getChild("asciidoc"); - return new SiteLogHandlerDeserializer().deserialize(asciidoc); - } - - protected Xpp3Dom getSiteConfig(MavenProject project) { - return project.getGoalConfiguration("org.apache.maven.plugins", "maven-site-plugin", "site", "site"); - } - - protected OptionsBuilder defaultOptions(File siteDirectory) { - return Options.builder() - .backend("xhtml") - .safe(SafeMode.UNSAFE) - .baseDir(new File(siteDirectory, ROLE_HINT)); - } - - protected AttributesBuilder defaultAttributes() { - return Attributes.builder() - .attribute("idprefix", "@") - .attribute("showtitle", "@"); - } - private void requireLibrary(Asciidoctor asciidoctor, String require) { if (!(require = require.trim()).isEmpty()) { try { diff --git a/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java b/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java index 6087f8da..2258208e 100644 --- a/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java +++ b/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java @@ -12,6 +12,9 @@ import org.apache.maven.doxia.parser.ParseException; import org.apache.maven.doxia.sink.Sink; import org.apache.maven.project.MavenProject; +import org.asciidoctor.maven.site.LogHandlerFactory; +import org.asciidoctor.maven.site.SiteBaseDirResolver; +import org.asciidoctor.maven.site.SiteConversionConfigurationParser; import org.codehaus.plexus.util.xml.Xpp3DomBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -228,28 +231,29 @@ private String parse(AbstractTextParser parser, String source) throws ParseExcep } static class TestMocks { + @SneakyThrows - static javax.inject.Provider createMavenProjectMock(String configuration) { + static MavenProject createMockMavenProject(String configuration) { MavenProject mockProject = Mockito.mock(MavenProject.class); when(mockProject.getBasedir()) .thenReturn(new File(".")); when(mockProject.getGoalConfiguration(anyString(), anyString(), anyString(), anyString())) .thenReturn(configuration != null ? Xpp3DomBuilder.build(new StringReader(configuration)) : null); - return () -> mockProject; + return mockProject; } @SneakyThrows static AsciidoctorAstDoxiaParser mockAsciidoctorDoxiaParser() { - AsciidoctorAstDoxiaParser parser = new AsciidoctorAstDoxiaParser(); - setVariableValueInObject(parser, "mavenProjectProvider", createMavenProjectMock(null)); return mockAsciidoctorDoxiaParser(null); } @SneakyThrows static AsciidoctorAstDoxiaParser mockAsciidoctorDoxiaParser(String configuration) { AsciidoctorAstDoxiaParser parser = new AsciidoctorAstDoxiaParser(); - setVariableValueInObject(parser, "mavenProjectProvider", createMavenProjectMock(configuration)); + setVariableValueInObject(parser, "mavenProject", createMockMavenProject(configuration)); + setVariableValueInObject(parser, "siteConfigParser", new SiteConversionConfigurationParser(new SiteBaseDirResolver())); + setVariableValueInObject(parser, "logHandlerFactory", new LogHandlerFactory()); return parser; } } From 441f989443dcb1fdbf4fdd5f44423dd84d68b33c Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Sat, 9 Nov 2024 21:50:27 +0100 Subject: [PATCH 4/8] Use constructor injection --- .../site/AsciidoctorConverterDoxiaParser.java | 21 ++++++++++++------- .../AsciidoctorConverterDoxiaParserTest.java | 15 +++++++------ .../maven/site/LogHandlerFactory.java | 11 ++++++++-- .../parser/AsciidoctorAstDoxiaParser.java | 18 ++++++++++------ .../parser/AsciidoctorAstDoxiaParserTest.java | 11 +++++----- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java index 488aea86..0891ffd6 100644 --- a/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java +++ b/asciidoctor-converter-doxia-module/src/main/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParser.java @@ -41,14 +41,21 @@ public class AsciidoctorConverterDoxiaParser extends AbstractTextParser { private static final Logger logger = LoggerFactory.getLogger(AsciidoctorConverterDoxiaParser.class); + private final MavenProject mavenProject; + private final SiteConversionConfigurationParser siteConfigParser; + private final LogHandlerFactory logHandlerFactory; + private final SiteConverterDecorator siteConverter; + @Inject - private MavenProject mavenProject; - @Inject - private SiteConversionConfigurationParser siteConfigParser; - @Inject - private LogHandlerFactory logHandlerFactory; - @Inject - private SiteConverterDecorator siteConverter; + public AsciidoctorConverterDoxiaParser(MavenProject mavenProject, + SiteConversionConfigurationParser siteConfigParser, + LogHandlerFactory logHandlerFactory, + SiteConverterDecorator siteConverter) { + this.mavenProject = mavenProject; + this.siteConfigParser = siteConfigParser; + this.logHandlerFactory = logHandlerFactory; + this.siteConverter = siteConverter; + } /** * {@inheritDoc} diff --git a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java index 748cf0b3..3ce2c774 100644 --- a/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java +++ b/asciidoctor-converter-doxia-module/src/test/java/org/asciidoctor/maven/site/AsciidoctorConverterDoxiaParserTest.java @@ -19,7 +19,6 @@ import static org.asciidoctor.maven.site.AsciidoctorConverterDoxiaParser.ROLE_HINT; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -264,19 +263,19 @@ private AsciidoctorConverterDoxiaParser mockAsciidoctorDoxiaParser() { @SneakyThrows private AsciidoctorConverterDoxiaParser mockAsciidoctorDoxiaParser(String configuration) { - AsciidoctorConverterDoxiaParser parser = new AsciidoctorConverterDoxiaParser(); - setVariableValueInObject(parser, "mavenProject", createMockMavenProject(configuration)); - setVariableValueInObject(parser, "siteConfigParser", new SiteConversionConfigurationParser(new SiteBaseDirResolver())); - setVariableValueInObject(parser, "logHandlerFactory", new LogHandlerFactory()); - setVariableValueInObject(parser, "siteConverter", new SiteConverterDecorator()); - return parser; + return new AsciidoctorConverterDoxiaParser( + createMockMavenProject(configuration), + new SiteConversionConfigurationParser(new SiteBaseDirResolver()), + new LogHandlerFactory(), + new SiteConverterDecorator() + ); } private Sink createSinkMock() { return new TextProviderSink(); } - class TextProviderSink extends AbstractTextSink { + static class TextProviderSink extends AbstractTextSink { String text; @Override diff --git a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java index 5fb17e75..1bc554b8 100644 --- a/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java +++ b/asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/LogHandlerFactory.java @@ -1,5 +1,7 @@ package org.asciidoctor.maven.site; +import java.io.File; + import org.asciidoctor.Asciidoctor; import org.asciidoctor.maven.log.LogHandler; import org.asciidoctor.maven.log.LogRecordFormatter; @@ -7,8 +9,13 @@ import org.codehaus.plexus.util.xml.Xpp3Dom; import org.slf4j.Logger; -import java.io.File; - +/** + * Factory to parse and create {@link MemoryLogHandler} in order to handle + * issues during processing. + * + * @author abelsromero + * @since 3.1.1 + */ public class LogHandlerFactory { public LogHandler getConfiguration(Xpp3Dom siteConfig) { diff --git a/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java b/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java index a7c60d7d..44269848 100644 --- a/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java +++ b/asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java @@ -19,8 +19,8 @@ import org.asciidoctor.maven.site.HeadParser; import org.asciidoctor.maven.site.HeaderMetadata; import org.asciidoctor.maven.site.LogHandlerFactory; -import org.asciidoctor.maven.site.SiteConversionConfigurationParser; import org.asciidoctor.maven.site.SiteConversionConfiguration; +import org.asciidoctor.maven.site.SiteConversionConfigurationParser; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.xml.Xpp3Dom; @@ -48,12 +48,18 @@ public class AsciidoctorAstDoxiaParser extends AbstractTextParser { private static final Logger logger = LoggerFactory.getLogger(AsciidoctorAstDoxiaParser.class); + private final MavenProject mavenProject; + private final SiteConversionConfigurationParser siteConfigParser; + private final LogHandlerFactory logHandlerFactory; + @Inject - private MavenProject mavenProject; - @Inject - private SiteConversionConfigurationParser siteConfigParser; - @Inject - private LogHandlerFactory logHandlerFactory; + public AsciidoctorAstDoxiaParser(MavenProject mavenProject, + SiteConversionConfigurationParser siteConfigParser, + LogHandlerFactory logHandlerFactory) { + this.mavenProject = mavenProject; + this.siteConfigParser = siteConfigParser; + this.logHandlerFactory = logHandlerFactory; + } /** * {@inheritDoc} diff --git a/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java b/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java index 2258208e..cc13654b 100644 --- a/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java +++ b/asciidoctor-parser-doxia-module/src/test/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParserTest.java @@ -27,7 +27,6 @@ import static org.asciidoctor.maven.site.parser.processors.test.TestNodeProcessorFactory.createSink; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.codehaus.plexus.util.ReflectionUtils.setVariableValueInObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -250,11 +249,11 @@ static AsciidoctorAstDoxiaParser mockAsciidoctorDoxiaParser() { @SneakyThrows static AsciidoctorAstDoxiaParser mockAsciidoctorDoxiaParser(String configuration) { - AsciidoctorAstDoxiaParser parser = new AsciidoctorAstDoxiaParser(); - setVariableValueInObject(parser, "mavenProject", createMockMavenProject(configuration)); - setVariableValueInObject(parser, "siteConfigParser", new SiteConversionConfigurationParser(new SiteBaseDirResolver())); - setVariableValueInObject(parser, "logHandlerFactory", new LogHandlerFactory()); - return parser; + return new AsciidoctorAstDoxiaParser( + createMockMavenProject(configuration), + new SiteConversionConfigurationParser(new SiteBaseDirResolver()), + new LogHandlerFactory() + ); } } } From a92cabce600cc3a3db87bea46a90bdebc66f2dc4 Mon Sep 17 00:00:00 2001 From: Abel Salgado Romero Date: Sat, 9 Nov 2024 23:45:53 +0100 Subject: [PATCH 5/8] Update Maven4 build configuration Use profile to allow to modify dependencies and properties in a central point --- .github/workflows/build-maven-4.yaml | 2 +- asciidoctor-maven-commons/pom.xml | 4 ---- pom.xml | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-maven-4.yaml b/.github/workflows/build-maven-4.yaml index ddfd1a28..40bb356e 100644 --- a/.github/workflows/build-maven-4.yaml +++ b/.github/workflows/build-maven-4.yaml @@ -39,5 +39,5 @@ jobs: - name: Maven version run: mvn -version - name: Build & Test - run: mvn -B -Prun-its clean verify -D"maven.version=${{ matrix.maven }}" -D"plexus-utils.version=4.0.2" + run: mvn -B -Prun-its -Pmaven4 clean verify diff --git a/asciidoctor-maven-commons/pom.xml b/asciidoctor-maven-commons/pom.xml index 168a45e4..acc7f0f3 100644 --- a/asciidoctor-maven-commons/pom.xml +++ b/asciidoctor-maven-commons/pom.xml @@ -21,10 +21,6 @@ https://github.com/asciidoctor/asciidoctor-maven-plugin - - 3.5.1 - - org.asciidoctor diff --git a/pom.xml b/pom.xml index 23b9d5bd..07a5c0e7 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ 2.0.0 2.0.0 2.2.0 + 3.5.1 3.0.0 9.4.8.0 @@ -248,6 +249,20 @@ + + maven4 + + 4.0.0-beta-5 + 4.0.2 + + + + org.codehaus.plexus + plexus-xml + 4.0.4 + + +