diff --git a/pom.xml b/pom.xml index cde6f42e..f7f42f26 100644 --- a/pom.xml +++ b/pom.xml @@ -209,7 +209,7 @@ under the License. 3.3.2 3.5.0 3.2.2 - 3.12.0 + 3.13.0 4.0.0-M14 2.0.0-M8 2023-12-14T15:35:29Z diff --git a/src/main/java/org/apache/maven/plugins/site/render/AbstractSiteRenderingMojo.java b/src/main/java/org/apache/maven/plugins/site/render/AbstractSiteRenderingMojo.java index c74ab234..0abacd3e 100644 --- a/src/main/java/org/apache/maven/plugins/site/render/AbstractSiteRenderingMojo.java +++ b/src/main/java/org/apache/maven/plugins/site/render/AbstractSiteRenderingMojo.java @@ -37,6 +37,7 @@ import org.apache.maven.doxia.site.SiteModel; import org.apache.maven.doxia.siterenderer.DocumentRenderer; import org.apache.maven.doxia.siterenderer.DocumentRenderingContext; +import org.apache.maven.doxia.siterenderer.ParserConfigurator; import org.apache.maven.doxia.siterenderer.RendererException; import org.apache.maven.doxia.siterenderer.SiteRenderer; import org.apache.maven.doxia.siterenderer.SiteRenderingContext; @@ -58,6 +59,8 @@ import org.apache.maven.reporting.exec.MavenReportExecutor; import org.apache.maven.reporting.exec.MavenReportExecutorRequest; import org.apache.maven.shared.utils.WriterFactory; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.util.ReaderFactory; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; @@ -95,6 +98,37 @@ public abstract class AbstractSiteRenderingMojo extends AbstractSiteDescriptorMo @Parameter private Map attributes; + /** + * Parser configurations (per matching Doxia markup source file path patterns). + * Each configuration item has the following format: + *

+ *


+     * <parserId>
+     *   <configurations>
+     *     <configuration>
+     *       <patterns>
+     *         <pattern>glob:**/*.md</pattern><!-- is either glob or regex syntax with the according prefix -->
+     *       </patterns>
+     *       <!-- all configurations apart from pattern are directly applied to the underlying parser -->
+     *       <emitComments>true</emitComments><!-- false by default -->
+     *       <emitAnchorsForIndexableEntries>false</emitAnchorsForIndexableEntries><!-- true by default -->
+     *     </configuration>
+     *   </configurations>
+     * </parserId>
+     * 
+ * The configuration is only applied if both + * + * + * The first matching configuration wins (i.e. is applied). + * @since 4.0.0 + * @see java.nio.file.FileSystem#getPathMatcher(String) FileSystem.getPathMatcher(String) for the supported patterns + */ + @Parameter + private Map> parserConfigurations; + /** * Site renderer. */ @@ -270,7 +304,12 @@ private ReportPlugin[] getReportingPlugins() { return reportingPlugins.toArray(new ReportPlugin[0]); } - protected SiteRenderingContext createSiteRenderingContext(Locale locale) + protected ParserConfiguratorImpl createParserConfigurator() throws ComponentLookupException { + return new ParserConfiguratorImpl( + parserConfigurations, mavenSession.getContainer(), mojoExecution.getMojoDescriptor()); + } + + protected SiteRenderingContext createSiteRenderingContext(Locale locale, ParserConfigurator parserConfigurator) throws MojoExecutionException, IOException, MojoFailureException { SiteModel siteModel = prepareSiteModel(locale); Map templateProperties = new HashMap<>(); @@ -332,7 +371,7 @@ protected SiteRenderingContext createSiteRenderingContext(Locale locale) context.setProcessedContentOutput(processedDir); } } - + context.setParserConfigurator(parserConfigurator); return context; } diff --git a/src/main/java/org/apache/maven/plugins/site/render/ParserConfiguratorImpl.java b/src/main/java/org/apache/maven/plugins/site/render/ParserConfiguratorImpl.java new file mode 100644 index 00000000..673055c9 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/site/render/ParserConfiguratorImpl.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.site.render; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.maven.doxia.parser.Parser; +import org.apache.maven.doxia.siterenderer.ParserConfigurator; +import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.configurator.ComponentConfigurationException; +import org.codehaus.plexus.component.configurator.ComponentConfigurator; +import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.configuration.PlexusConfiguration; + +/** + * Configures a parser based on a {@link PlexusConfiguration} for a particular parser id and optionally matching one of multiple patterns. + * It internally leverages the {@link ComponentConfigurator} for calling the right methods inside the parser implementation. + */ +public class ParserConfiguratorImpl implements ParserConfigurator, Closeable { + + private static final class ParserConfigurationKey { + + ParserConfigurationKey(String parserId, PlexusConfiguration patternsConfiguration) { + this(parserId, PlexusConfigurationUtils.getStringArrayValues(patternsConfiguration)); + } + + ParserConfigurationKey(String parserId, Collection patterns) { + this.parserId = parserId; + // lazily populate all matchers + matchers = patterns.stream() + .map(p -> FileSystems.getDefault().getPathMatcher(p)) + .collect(Collectors.toList()); + } + + private final String parserId; + + /** + * List of {@link PathMatcher}s for all of the patterns passed to the constructor + */ + private List matchers; + + /** + * Returns {@code true} the given file path matches one of the {@link #patterns} given via {@link #addPattern(String)} + * @param filePath the file path to check + * @return {@code true} if the given file path matches at least one of the patterns, {@code false} otherwise. + * @throws IllegalArgumentException + * If one of the patterns does not comply with the form: {@code syntax:pattern} + * @throws java.util.regex.PatternSyntaxException + * If one of the regex patterns is invalid + * @throws UnsupportedOperationException + * If one of the patterns syntax prefix is not known to the implementation + * @see FileSystem#getPathMatcher(String) + */ + public boolean matches(String parserId, Path filePath) { + if (this.parserId.equals(parserId)) { + return false; + } + if (matchers.isEmpty()) { + return true; // no patterns mean always match + } + return matchers.stream().anyMatch(m -> m.matches(filePath)); + } + } + + private final org.codehaus.plexus.classworlds.realm.ClassRealm pluginClassRealm; + private final PlexusContainer plexusContainer; + private final ComponentConfigurator componentConfigurator; + + private final Map parserConfigurations; + + public ParserConfiguratorImpl( + Map> parserConfigurations, + PlexusContainer plexusContainer, + MojoDescriptor mojoDescriptor) + throws ComponentLookupException { + this.parserConfigurations = new LinkedHashMap<>(); + if (parserConfigurations != null) { + for (Map.Entry> parserConfigurationPerId : + parserConfigurations.entrySet()) { + String parserId = parserConfigurationPerId.getKey(); + for (PlexusConfiguration configuration : parserConfigurationPerId.getValue()) { + ParserConfigurationKey key = + new ParserConfigurationKey(parserId, configuration.getChild("patterns")); + this.parserConfigurations.put(key, configuration); + } + } + } + pluginClassRealm = mojoDescriptor.getRealm(); + this.plexusContainer = plexusContainer; + componentConfigurator = getComponentConfigurator(mojoDescriptor.getComponentConfigurator()); + } + + ComponentConfigurator getComponentConfigurator(String configuratorId) throws ComponentLookupException { + // logic copied from + // https://github.com/apache/maven/blob/267de063eec17111688fd1a27d4e3aae6c8d0c51/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java#L696C9-L700C10 + if (configuratorId == null || configuratorId.isEmpty()) { + configuratorId = "basic"; // TODO: support v4 + } + return plexusContainer.lookup(ComponentConfigurator.class, configuratorId); + } + + public void configureParser(PlexusConfiguration configuration, Parser parser) + throws ComponentConfigurationException { + componentConfigurator.configureComponent(parser, configuration, pluginClassRealm); + } + + @Override + public void close() throws IOException { + try { + plexusContainer.release(componentConfigurator); + } catch (ComponentLifecycleException e) { + throw new IOException(e); + } + } + + @Override + public boolean configure(String parserId, Path filePath, Parser parser) { + Optional config = parserConfigurations.entrySet().stream() + .filter(c -> c.getKey().matches(parserId, filePath)) + .findFirst() + .map(Map.Entry::getValue); + config.ifPresent(c -> { + try { + configureParser(c, parser); + } catch (ComponentConfigurationException e) { + throw new IllegalStateException("Could not configure parser " + parser, e); + } + }); + return config.isPresent(); + } +} diff --git a/src/main/java/org/apache/maven/plugins/site/render/PlexusConfigurationUtils.java b/src/main/java/org/apache/maven/plugins/site/render/PlexusConfigurationUtils.java new file mode 100644 index 00000000..09d53b92 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/site/render/PlexusConfigurationUtils.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.site.render; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.codehaus.plexus.configuration.PlexusConfiguration; + +public class PlexusConfigurationUtils { + + private PlexusConfigurationUtils() { + // not supposed to be instantiated + } + + /** + * Retrieves all string values from the children of the given {@link PlexusConfiguration} + * @param arrayContainer the configuration containing the array container (may be {@code null}) + * @return the list of string values + */ + static List getStringArrayValues(PlexusConfiguration arrayContainer) { + if (arrayContainer == null) { + return Collections.emptyList(); + } + List stringValues = new ArrayList<>(); + for (PlexusConfiguration item : arrayContainer.getChildren()) { + stringValues.add(item.getValue()); + } + return stringValues; + } +} diff --git a/src/main/java/org/apache/maven/plugins/site/render/SiteMojo.java b/src/main/java/org/apache/maven/plugins/site/render/SiteMojo.java index f6431abc..cca2a2a3 100644 --- a/src/main/java/org/apache/maven/plugins/site/render/SiteMojo.java +++ b/src/main/java/org/apache/maven/plugins/site/render/SiteMojo.java @@ -30,6 +30,7 @@ import org.apache.maven.doxia.siterenderer.DocumentRenderer; import org.apache.maven.doxia.siterenderer.DoxiaDocumentRenderer; +import org.apache.maven.doxia.siterenderer.ParserConfigurator; import org.apache.maven.doxia.siterenderer.RendererException; import org.apache.maven.doxia.siterenderer.SiteRenderingContext; import org.apache.maven.doxia.tools.SiteTool; @@ -43,6 +44,7 @@ import org.apache.maven.reporting.MavenReportException; import org.apache.maven.reporting.exec.MavenReportExecution; import org.apache.maven.shared.utils.logging.MessageBuilder; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; @@ -95,7 +97,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { checkInputEncoding(); - try { + try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) { List localesList = getLocales(); for (Locale locale : localesList) { @@ -108,7 +110,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { File outputDirectory = getOutputDirectory(locale); List reports = generateReports ? getReports(outputDirectory) : Collections.emptyList(); - renderLocale(locale, reports, localesList, outputDirectory); + renderLocale(locale, reports, localesList, outputDirectory, parserConfigurator); } } catch (RendererException e) { if (e.getCause() instanceof MavenReportException) { @@ -118,13 +120,19 @@ public void execute() throws MojoExecutionException, MojoFailureException { throw new MojoExecutionException("Failed to render site", e); } catch (IOException e) { throw new MojoExecutionException("Error during site generation", e); + } catch (ComponentLookupException e) { + throw new MojoExecutionException("Cannot lookup ComponentConfigurator for configuration of parsers", e); } } private void renderLocale( - Locale locale, List reports, List supportedLocales, File outputDirectory) + Locale locale, + List reports, + List supportedLocales, + File outputDirectory, + ParserConfigurator parserConfigurator) throws IOException, RendererException, MojoFailureException, MojoExecutionException { - SiteRenderingContext context = createSiteRenderingContext(locale); + SiteRenderingContext context = createSiteRenderingContext(locale, parserConfigurator); context.addSiteLocales(supportedLocales); context.setInputEncoding(getInputEncoding()); context.setOutputEncoding(getOutputEncoding()); diff --git a/src/main/java/org/apache/maven/plugins/site/run/SiteRunMojo.java b/src/main/java/org/apache/maven/plugins/site/run/SiteRunMojo.java index 266909c4..a9af5cde 100644 --- a/src/main/java/org/apache/maven/plugins/site/run/SiteRunMojo.java +++ b/src/main/java/org/apache/maven/plugins/site/run/SiteRunMojo.java @@ -37,6 +37,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.plugins.site.render.AbstractSiteRenderingMojo; +import org.apache.maven.plugins.site.render.ParserConfiguratorImpl; import org.apache.maven.reporting.exec.MavenReportExecution; import org.codehaus.plexus.util.IOUtil; import org.eclipse.jetty.server.Server; @@ -125,11 +126,11 @@ private WebAppContext createWebApplication() throws MojoExecutionException { List localesList = getLocales(); webapp.setAttribute(DoxiaFilter.LOCALES_LIST_KEY, localesList); - try { + try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) { Map i18nDoxiaContexts = new HashMap<>(); for (Locale locale : localesList) { - SiteRenderingContext i18nContext = createSiteRenderingContext(locale); + SiteRenderingContext i18nContext = createSiteRenderingContext(locale, parserConfigurator); i18nContext.setInputEncoding(getInputEncoding()); i18nContext.setOutputEncoding(getOutputEncoding());