This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch feature/configure-parser-with-plexus-configurator in repository https://gitbox.apache.org/repos/asf/maven-site-plugin.git
commit 614a05759cd41ef63ed3c7ce351c49ec89a480a9 Author: Konrad Windszus <k...@apache.org> AuthorDate: Sat Dec 30 12:47:52 2023 +0100 [MSITE-1000] Introduce parser configuration parameter This leverages PlexusConfigurator under the hood --- pom.xml | 2 +- .../site/render/AbstractSiteRenderingMojo.java | 43 +++++- .../site/render/ParserConfiguratorImpl.java | 156 +++++++++++++++++++++ .../site/render/PlexusConfigurationUtils.java | 48 +++++++ .../apache/maven/plugins/site/render/SiteMojo.java | 16 ++- .../apache/maven/plugins/site/run/SiteRunMojo.java | 7 +- 6 files changed, 262 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index b9d095c4..a53174eb 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,7 @@ under the License. <!-- for dependencies --> <jettyVersion>9.4.53.v20231009</jettyVersion> <doxiaVersion>2.0.0-M8</doxiaVersion> - <doxiaSitetoolsVersion>2.0.0-M16</doxiaSitetoolsVersion> + <doxiaSitetoolsVersion>2.0.0-M18-SNAPSHOT</doxiaSitetoolsVersion> <wagonVersion>3.5.3</wagonVersion> <slf4jVersion>1.7.36</slf4jVersion> <!-- for ITs --> 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 8906cbc8..2d9049f7 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.MenuItem; 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; @@ -57,6 +58,8 @@ import org.apache.maven.reporting.exec.MavenReportExecution; 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; @@ -94,6 +97,37 @@ public abstract class AbstractSiteRenderingMojo extends AbstractSiteDescriptorMo @Parameter private Map<String, Object> attributes; + /** + * Parser configurations (per matching Doxia markup source file path patterns). + * Each configuration item has the following format: + * <p/> + * <pre><code> + * <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> + * </code></pre> + * The configuration is only applied if both + * <ul> + * <li>the parser id matches the parser used for a specific markup source file and</li> + * <li>one of the given patterns matches the Doxia markup source file path (or no pattern is given at all).</li> + * </ul> + * + * 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<String, List<PlexusConfiguration>> parserConfigurations; + /** * Site renderer. */ @@ -269,7 +303,12 @@ public abstract class AbstractSiteRenderingMojo extends AbstractSiteDescriptorMo 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<String, Object> templateProperties = new HashMap<>(); @@ -329,7 +368,7 @@ public abstract class AbstractSiteRenderingMojo extends AbstractSiteDescriptorMo 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..c240db01 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/site/render/ParserConfiguratorImpl.java @@ -0,0 +1,156 @@ +/* + * 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<String> 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<PathMatcher> 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<ParserConfigurationKey, PlexusConfiguration> parserConfigurations; + + public ParserConfiguratorImpl( + Map<String, List<PlexusConfiguration>> parserConfigurations, + PlexusContainer plexusContainer, + MojoDescriptor mojoDescriptor) + throws ComponentLookupException { + this.parserConfigurations = new LinkedHashMap<>(); + for (Map.Entry<String, List<PlexusConfiguration>> 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<PlexusConfiguration> 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 + " due to ", 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<String> getStringArrayValues(PlexusConfiguration arrayContainer) { + if (arrayContainer == null) { + return Collections.emptyList(); + } + List<String> 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 7b261ac7..d22bac0b 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 @@ -29,6 +29,7 @@ import java.util.TreeMap; 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; @@ -42,6 +43,7 @@ import org.apache.maven.project.MavenProject; 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; @@ -94,7 +96,7 @@ public class SiteMojo extends AbstractSiteRenderingMojo { checkInputEncoding(); - try { + try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) { List<Locale> localesList = getLocales(); for (Locale locale : localesList) { @@ -107,7 +109,7 @@ public class SiteMojo extends AbstractSiteRenderingMojo { File outputDirectory = getOutputDirectory(locale); List<MavenReportExecution> 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) { @@ -117,13 +119,19 @@ public class SiteMojo extends AbstractSiteRenderingMojo { throw new MojoExecutionException("Failed to render reports", 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<MavenReportExecution> reports, List<Locale> supportedLocales, File outputDirectory) + Locale locale, + List<MavenReportExecution> reports, + List<Locale> supportedLocales, + File outputDirectory, + ParserConfigurator parserConfigurator) throws IOException, RendererException, MojoFailureException, MojoExecutionException { - SiteRenderingContext context = createSiteRenderingContext(locale); + SiteRenderingContext context = createSiteRenderingContext(locale, parserConfigurator); context.addSiteLocales(supportedLocales); if (!locale.equals(SiteTool.DEFAULT_LOCALE)) { context.addSiteDirectory(new File(generatedSiteDirectory, locale.toString())); 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 f5430e00..ae5105b5 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.Mojo; 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,15 +126,15 @@ public class SiteRunMojo extends AbstractSiteRenderingMojo { List<Locale> localesList = getLocales(); webapp.setAttribute(DoxiaFilter.LOCALES_LIST_KEY, localesList); - try { + try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) { Map<String, DoxiaBean> i18nDoxiaContexts = new HashMap<>(); for (Locale locale : localesList) { - SiteRenderingContext i18nContext = createSiteRenderingContext(locale); + SiteRenderingContext i18nContext = createSiteRenderingContext(locale, parserConfigurator); i18nContext.setInputEncoding(getInputEncoding()); i18nContext.setOutputEncoding(getOutputEncoding()); - SiteRenderingContext i18nGeneratedSiteContext = createSiteRenderingContext(locale); + SiteRenderingContext i18nGeneratedSiteContext = createSiteRenderingContext(locale, parserConfigurator); i18nGeneratedSiteContext.setInputEncoding(getInputEncoding()); i18nGeneratedSiteContext.setOutputEncoding(getOutputEncoding()); i18nGeneratedSiteContext.getSiteDirectories().clear();