diff --git a/pom.xml b/pom.xml index c85b4a3..0c823ba 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ under the License. maven-toolchains-plugin - 3.2.1-SNAPSHOT + 4.0.0-SNAPSHOT maven-plugin Apache Maven Toolchains Plugin @@ -42,7 +42,7 @@ under the License. - 3.6.3 + ${mavenVersion} @@ -67,8 +67,8 @@ under the License. - 8 - 3.9.9 + 17 + 4.0.0-rc-3-SNAPSHOT 2024-04-18T00:34:08Z @@ -87,43 +87,39 @@ under the License. org.apache.maven - maven-plugin-api + maven-api-core ${mavenVersion} - provided org.apache.maven - maven-core + maven-api-di ${mavenVersion} - provided - - - org.apache.maven.plugin-tools - maven-plugin-annotations - provided - org.codehaus.plexus - plexus-xml + org.apache.maven + maven-xml + ${mavenVersion} org.slf4j slf4j-api - 1.7.36 + 2.0.16 - javax.inject - javax.inject - 1 + org.junit.jupiter + junit-jupiter-api + test - org.eclipse.sisu - org.eclipse.sisu.plexus - provided + org.apache.maven + maven-core + ${mavenVersion} + test - org.junit.jupiter - junit-jupiter-api + org.mockito + mockito-core + 5.15.2 test @@ -131,6 +127,11 @@ under the License. + + org.apache.maven.plugins + maven-plugin-plugin + 4.0.0-beta-1 + com.diffplug.spotless spotless-maven-plugin @@ -150,11 +151,5 @@ under the License. - - - org.eclipse.sisu - sisu-maven-plugin - - diff --git a/src/it/setup-custom-toolchain/pom.xml b/src/it/setup-custom-toolchain/pom.xml index a82d309..2b65777 100644 --- a/src/it/setup-custom-toolchain/pom.xml +++ b/src/it/setup-custom-toolchain/pom.xml @@ -56,7 +56,7 @@ under the License. org.apache.maven.plugin-tools maven-plugin-annotations - 3.3 + 3.15.1 provided @@ -71,28 +71,27 @@ under the License. maven-compiler-plugin - 3.1 + 3.13.0 + + 17 + maven-install-plugin - 2.5.2 + 3.1.3 - org.codehaus.plexus - plexus-component-metadata - 1.5.5 - - - - generate-metadata - - - + org.eclipse.sisu + sisu-maven-plugin + 0.9.0.M3 org.apache.maven.plugins maven-plugin-plugin - 3.3 + 3.15.1 + + toolchain + default-descriptor @@ -103,10 +102,6 @@ under the License. helpmojo - - - true - @@ -128,9 +123,9 @@ under the License. org.apache.maven.plugins maven-plugin-plugin + 3.15.1 - - true + ctc diff --git a/src/main/java/org/apache/maven/plugins/toolchain/ToolchainConverter.java b/src/main/java/org/apache/maven/plugins/toolchain/ToolchainConverter.java index 2ce0c9f..ce35146 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/ToolchainConverter.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/ToolchainConverter.java @@ -19,14 +19,10 @@ package org.apache.maven.plugins.toolchain; import java.util.HashMap; +import java.util.List; import java.util.Map; -import org.codehaus.plexus.component.configurator.ComponentConfigurationException; -import org.codehaus.plexus.component.configurator.ConfigurationListener; -import org.codehaus.plexus.component.configurator.converters.AbstractConfigurationConverter; -import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup; -import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; -import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.apache.maven.api.xml.XmlNode; /** * Custom Plexus ConfigurationConverter to instantiate ToolchainRequirement from configuration. @@ -34,50 +30,26 @@ * @author mkleint * @see ToolchainsRequirement */ -public class ToolchainConverter extends AbstractConfigurationConverter { +public class ToolchainConverter { - /** - * @see org.codehaus.plexus.component.configurator.converters.ConfigurationConverter#canConvert(java.lang.Class) - */ - @Override - public boolean canConvert(Class type) { - return ToolchainsRequirement.class.isAssignableFrom(type); - } - - /** - * @see org.codehaus.plexus.component.configurator.converters.ConfigurationConverter#fromConfiguration(org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup, org.codehaus.plexus.configuration.PlexusConfiguration, java.lang.Class, java.lang.Class, java.lang.ClassLoader, org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator, org.codehaus.plexus.component.configurator.ConfigurationListener) - */ - @Override - public Object fromConfiguration( - ConverterLookup converterLookup, - PlexusConfiguration configuration, - Class type, - Class baseType, - ClassLoader classLoader, - ExpressionEvaluator expressionEvaluator, - ConfigurationListener listener) - throws ComponentConfigurationException { + public ToolchainsRequirement fromConfiguration(XmlNode configuration) { ToolchainsRequirement retValue = new ToolchainsRequirement(); - processConfiguration(retValue, configuration, expressionEvaluator); + processConfiguration(retValue, configuration); return retValue; } - private void processConfiguration( - ToolchainsRequirement requirement, - PlexusConfiguration configuration, - ExpressionEvaluator expressionEvaluator) - throws ComponentConfigurationException { + private void processConfiguration(ToolchainsRequirement requirement, XmlNode configuration) { Map> map = new HashMap<>(); - PlexusConfiguration[] tools = configuration.getChildren(); - for (PlexusConfiguration tool : tools) { + List tools = configuration.getChildren(); + for (XmlNode tool : tools) { String type = tool.getName(); - PlexusConfiguration[] params = tool.getChildren(); + List params = tool.getChildren(); Map parameters = new HashMap<>(); - for (PlexusConfiguration param : params) { + for (XmlNode param : params) { parameters.put(param.getName(), param.getValue()); } map.put(type, parameters); diff --git a/src/main/java/org/apache/maven/plugins/toolchain/ToolchainMojo.java b/src/main/java/org/apache/maven/plugins/toolchain/ToolchainMojo.java index d8454f6..c61dd79 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/ToolchainMojo.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/ToolchainMojo.java @@ -22,17 +22,17 @@ import java.util.List; import java.util.Map; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Component; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.toolchain.MisconfiguredToolchainException; -import org.apache.maven.toolchain.ToolchainManagerPrivate; -import org.apache.maven.toolchain.ToolchainPrivate; +import org.apache.maven.api.Lifecycle; +import org.apache.maven.api.Session; +import org.apache.maven.api.Toolchain; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.plugin.MojoException; +import org.apache.maven.api.plugin.annotations.Mojo; +import org.apache.maven.api.plugin.annotations.Parameter; +import org.apache.maven.api.services.MavenException; +import org.apache.maven.api.services.ToolchainManager; +import org.apache.maven.api.xml.XmlNode; /** * Check that toolchains requirements are met by currently configured toolchains in {@code toolchains.xml} and @@ -40,24 +40,16 @@ * * @author mkleint */ -@Mojo( - name = "toolchain", - defaultPhase = LifecyclePhase.VALIDATE, - configurator = "toolchains-requirement-configurator", - threadSafe = true) -public class ToolchainMojo extends AbstractMojo { - private static final Object LOCK = new Object(); +@Mojo(name = "toolchain", defaultPhase = Lifecycle.Phase.VALIDATE) +public class ToolchainMojo implements org.apache.maven.api.plugin.Mojo { - /** - */ - @Component - private ToolchainManagerPrivate toolchainManagerPrivate; + private static final Object LOCK = new Object(); /** * The current build session instance. This is used for toolchain manager API calls. */ - @Parameter(defaultValue = "${session}", readonly = true, required = true) - private MavenSession session; + @Inject + private Session session; /** * Toolchains requirements, specified by one @@ -68,101 +60,91 @@ public class ToolchainMojo extends AbstractMojo { * element for each required toolchain. */ @Parameter(required = true) - private ToolchainsRequirement toolchains; + private XmlNode toolchains; @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void execute() throws org.apache.maven.api.plugin.MojoException { if (toolchains == null) { // should not happen since parameter is required... getLog().warn("No toolchains requirements configured."); return; } - + ToolchainsRequirement toolchains = new ToolchainConverter().fromConfiguration(this.toolchains); List nonMatchedTypes = new ArrayList<>(); - for (Map.Entry> entry : toolchains.getToolchains().entrySet()) { String type = entry.getKey(); - if (!selectToolchain(type, entry.getValue())) { nonMatchedTypes.add(type); } } - if (!nonMatchedTypes.isEmpty()) { // TODO add the default toolchain instance if defined?? StringBuilder buff = new StringBuilder(); buff.append("Cannot find matching toolchain definitions for the following toolchain types:"); - for (String type : nonMatchedTypes) { buff.append(System.lineSeparator()); buff.append(getToolchainRequirementAsString(type, toolchains.getParams(type))); } - getLog().error(buff.toString()); - - throw new MojoFailureException(buff.toString() + System.lineSeparator() + throw new org.apache.maven.api.plugin.MojoException(buff.toString() + System.lineSeparator() + "Please make sure you define the required toolchains in your ~/.m2/toolchains.xml file."); } } protected String getToolchainRequirementAsString(String type, Map params) { - StringBuilder buff = new StringBuilder(); - - buff.append(type).append(" ["); - - if (params.size() == 0) { - buff.append(" any"); + if (params.isEmpty()) { + return type + " [ any ]"; } else { - for (Map.Entry param : params.entrySet()) { - buff.append(" ").append(param.getKey()).append("='").append(param.getValue()); - buff.append("'"); - } + StringBuilder buff = new StringBuilder(); + buff.append(type); + buff.append(" ["); + params.forEach( + (k, v) -> buff.append(" ").append(k).append("='").append(v).append("'")); + buff.append(" ]"); + return buff.toString(); } - - buff.append(" ]"); - - return buff.toString(); } - protected boolean selectToolchain(String type, Map params) throws MojoExecutionException { + protected boolean selectToolchain(String type, Map params) + throws org.apache.maven.api.plugin.MojoException { getLog().info("Required toolchain: " + getToolchainRequirementAsString(type, params)); int typeFound = 0; - try { - ToolchainPrivate[] tcs = getToolchains(type); - - for (ToolchainPrivate tc : tcs) { + ToolchainManager toolchainManager = session.getService(ToolchainManager.class); + List tcs = getToolchains(type); + for (Toolchain tc : tcs) { if (!type.equals(tc.getType())) { // useful because of MNG-5716 continue; } - typeFound++; - if (tc.matchesRequirements(params)) { getLog().info("Found matching toolchain for type " + type + ": " + tc); - // store matching toolchain to build context synchronized (LOCK) { - toolchainManagerPrivate.storeToolchainToBuildContext(tc, session); + toolchainManager.storeToolchainToBuildContext(session, tc); } - return true; } } - } catch (MisconfiguredToolchainException ex) { - throw new MojoExecutionException("Misconfigured toolchains.", ex); + } catch (MavenException ex) { + throw new MojoException("Misconfigured toolchains.", ex); } - getLog().error("No toolchain " + ((typeFound == 0) ? "found" : ("matched from " + typeFound + " found")) + " for type " + type); - return false; } - private ToolchainPrivate[] getToolchains(String type) - throws MojoExecutionException, MisconfiguredToolchainException { - return toolchainManagerPrivate.getToolchainsForType(type, session); + private List getToolchains(String type) { + ToolchainManager toolchainManager = session.getService(ToolchainManager.class); + return toolchainManager.getToolchains(session, type); + } + + @Inject() + private Log log; + + protected Log getLog() { + return log; } } diff --git a/src/main/java/org/apache/maven/plugins/toolchain/jdk/DisplayDiscoveredJdkToolchainsMojo.java b/src/main/java/org/apache/maven/plugins/toolchain/jdk/DisplayDiscoveredJdkToolchainsMojo.java index fc6a457..e96110c 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/jdk/DisplayDiscoveredJdkToolchainsMojo.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/jdk/DisplayDiscoveredJdkToolchainsMojo.java @@ -18,16 +18,14 @@ */ package org.apache.maven.plugins.toolchain.jdk; -import javax.inject.Inject; - import java.util.List; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.toolchain.model.PersistedToolchains; -import org.apache.maven.toolchain.model.ToolchainModel; -import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.plugin.annotations.Mojo; +import org.apache.maven.api.plugin.annotations.Parameter; +import org.apache.maven.api.toolchain.PersistedToolchains; +import org.apache.maven.api.toolchain.ToolchainModel; import static java.util.Comparator.comparing; import static org.apache.maven.plugins.toolchain.jdk.ToolchainDiscoverer.SORTED_PROVIDES; @@ -35,10 +33,10 @@ /** * Discover the JDK toolchains and print them to the console. * - * @since 3.2.0 + * TODO: Maven 4 plugins need to be thread safe. Please verify and fix thread safety issues. */ -@Mojo(name = "display-discovered-jdk-toolchains", requiresProject = false) -public class DisplayDiscoveredJdkToolchainsMojo extends AbstractMojo { +@Mojo(name = "display-discovered-jdk-toolchains", projectRequired = false) +public class DisplayDiscoveredJdkToolchainsMojo implements org.apache.maven.api.plugin.Mojo { /** * Comparator used to sort JDK toolchains for selection. @@ -66,12 +64,18 @@ public void execute() { List models = toolchains.getToolchains(); getLog().info("Discovered " + models.size() + " JDK toolchains:"); for (ToolchainModel model : models) { - getLog().info(" - " - + ((Xpp3Dom) model.getConfiguration()).getChild("jdkHome").getValue()); + getLog().info(" - " + model.getConfiguration().getChild("jdkHome").getValue()); getLog().info(" provides:"); model.getProvides().entrySet().stream() .sorted(comparing(e -> SORTED_PROVIDES.indexOf(e.getKey().toString()))) .forEach(e -> getLog().info(" " + e.getKey() + ": " + e.getValue())); } } + + @Inject() + private Log log; + + protected Log getLog() { + return log; + } } diff --git a/src/main/java/org/apache/maven/plugins/toolchain/jdk/GenerateJdkToolchainsXmlMojo.java b/src/main/java/org/apache/maven/plugins/toolchain/jdk/GenerateJdkToolchainsXmlMojo.java index e4f3e6e..03cb5ea 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/jdk/GenerateJdkToolchainsXmlMojo.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/jdk/GenerateJdkToolchainsXmlMojo.java @@ -18,29 +18,26 @@ */ package org.apache.maven.plugins.toolchain.jdk; -import javax.inject.Inject; - import java.io.IOException; import java.io.StringWriter; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.toolchain.model.PersistedToolchains; -import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Writer; +import org.apache.maven.api.Session; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.plugin.annotations.Mojo; +import org.apache.maven.api.plugin.annotations.Parameter; +import org.apache.maven.api.services.xml.ToolchainsXmlFactory; +import org.apache.maven.api.toolchain.PersistedToolchains; /** * Run the JDK toolchain discovery mechanism and generates a toolchains XML. * - * @since 3.2.0 + * TODO: Maven 4 plugins need to be thread safe. Please verify and fix thread safety issues. */ -@Mojo(name = "generate-jdk-toolchains-xml", requiresProject = false) -public class GenerateJdkToolchainsXmlMojo extends AbstractMojo { +@Mojo(name = "generate-jdk-toolchains-xml", projectRequired = false) +public class GenerateJdkToolchainsXmlMojo implements org.apache.maven.api.plugin.Mojo { /** * The path and name pf the toolchain XML file that will be generated. @@ -55,23 +52,24 @@ public class GenerateJdkToolchainsXmlMojo extends AbstractMojo { @Inject ToolchainDiscoverer discoverer; + @Inject + Session session; + @Override - public void execute() throws MojoFailureException { + public void execute() throws org.apache.maven.api.plugin.MojoException { try { PersistedToolchains toolchains = discoverer.discoverToolchains(); if (file != null) { Path file = Paths.get(this.file).toAbsolutePath(); Files.createDirectories(file.getParent()); - try (Writer writer = Files.newBufferedWriter(file)) { - new MavenToolchainsXpp3Writer().write(writer, toolchains); - } + session.getService(ToolchainsXmlFactory.class).write(toolchains, file); } else { StringWriter writer = new StringWriter(); - new MavenToolchainsXpp3Writer().write(writer, toolchains); + session.getService(ToolchainsXmlFactory.class).write(toolchains, writer); System.out.println(writer); } } catch (IOException e) { - throw new MojoFailureException("Unable to generate toolchains.xml", e); + throw new org.apache.maven.api.plugin.MojoException("Unable to generate toolchains.xml", e); } } } diff --git a/src/main/java/org/apache/maven/plugins/toolchain/jdk/SelectJdkToolchainMojo.java b/src/main/java/org/apache/maven/plugins/toolchain/jdk/SelectJdkToolchainMojo.java index c76f80f..7a2bd61 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/jdk/SelectJdkToolchainMojo.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/jdk/SelectJdkToolchainMojo.java @@ -18,29 +18,25 @@ */ package org.apache.maven.plugins.toolchain.jdk; -import javax.inject.Inject; -import javax.inject.Named; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.stream.Stream; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.toolchain.MisconfiguredToolchainException; -import org.apache.maven.toolchain.RequirementMatcherFactory; -import org.apache.maven.toolchain.ToolchainFactory; -import org.apache.maven.toolchain.ToolchainManagerPrivate; -import org.apache.maven.toolchain.ToolchainPrivate; -import org.apache.maven.toolchain.model.PersistedToolchains; -import org.apache.maven.toolchain.model.ToolchainModel; -import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.apache.maven.api.Lifecycle; +import org.apache.maven.api.Session; +import org.apache.maven.api.Toolchain; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.plugin.MojoException; +import org.apache.maven.api.plugin.annotations.Mojo; +import org.apache.maven.api.plugin.annotations.Parameter; +import org.apache.maven.api.services.Lookup; +import org.apache.maven.api.services.MavenException; +import org.apache.maven.api.services.ToolchainFactory; +import org.apache.maven.api.services.ToolchainManager; +import org.apache.maven.api.toolchain.PersistedToolchains; +import org.apache.maven.api.toolchain.ToolchainModel; import static org.apache.maven.plugins.toolchain.jdk.ToolchainDiscoverer.ENV; import static org.apache.maven.plugins.toolchain.jdk.ToolchainDiscoverer.RUNTIME_NAME; @@ -50,21 +46,28 @@ /** * Discover JDK toolchains and select a matching one. - * - * @since 3.2.0 */ -@Mojo(name = "select-jdk-toolchain", defaultPhase = LifecyclePhase.VALIDATE) -public class SelectJdkToolchainMojo extends AbstractMojo { +@Mojo(name = "select-jdk-toolchain", defaultPhase = Lifecycle.Phase.VALIDATE) +public class SelectJdkToolchainMojo implements org.apache.maven.api.plugin.Mojo { public static final String TOOLCHAIN_TYPE_JDK = "jdk"; - /** Jdk usage mode */ + /** + * Jdk usage mode + */ public enum JdkMode { - /** always ignore the current JDK */ + + /** + * always ignore the current JDK + */ Never, - /** to not use a toolchain if the toolchains that would be selected is the current JDK */ + /** + * to not use a toolchain if the toolchains that would be selected is the current JDK + */ IfSame, - /** favor the current JDK if it matches the requirements */ + /** + * favor the current JDK if it matches the requirements + */ IfMatch } @@ -133,24 +136,11 @@ public enum JdkMode { @Parameter(property = "toolchain.jdk.comparator", defaultValue = "lts,current,env,version,vendor") private String comparator; - /** - * Toolchain manager - */ - @Inject - private ToolchainManagerPrivate toolchainManager; - - /** - * Toolchain factory - */ - @Inject - @Named(TOOLCHAIN_TYPE_JDK) - ToolchainFactory factory; - /** * The current build session instance. This is used for toolchain manager API calls. */ @Inject - private MavenSession session; + private Session session; /** * Toolchain discoverer @@ -158,52 +148,53 @@ public enum JdkMode { @Inject ToolchainDiscoverer discoverer; + /** + * Toolchain factory + */ + ToolchainFactory factory; + @Override - public void execute() throws MojoFailureException { + public void execute() { try { doExecute(); - } catch (MisconfiguredToolchainException e) { - throw new MojoFailureException("Unable to select toolchain: " + e, e); + } catch (MavenException e) { + throw new MojoException("Unable to select toolchain: " + e, e); } } - private void doExecute() throws MisconfiguredToolchainException, MojoFailureException { + private void doExecute() throws MojoException { if (version == null && runtimeName == null && runtimeVersion == null && vendor == null && env == null) { return; } - + factory = session.getService(Lookup.class).lookup(ToolchainFactory.class, TOOLCHAIN_TYPE_JDK); Map requirements = new HashMap<>(); Optional.ofNullable(version).ifPresent(v -> requirements.put(VERSION, v)); Optional.ofNullable(runtimeName).ifPresent(v -> requirements.put(RUNTIME_NAME, v)); Optional.ofNullable(runtimeVersion).ifPresent(v -> requirements.put(RUNTIME_VERSION, v)); Optional.ofNullable(vendor).ifPresent(v -> requirements.put(VENDOR, v)); Optional.ofNullable(env).ifPresent(v -> requirements.put(ENV, v)); - ToolchainModel currentJdkToolchainModel = discoverer.getCurrentJdkToolchain().orElse(null); - ToolchainPrivate currentJdkToolchain = + Toolchain currentJdkToolchain = currentJdkToolchainModel != null ? factory.createToolchain(currentJdkToolchainModel) : null; - if (useJdk == JdkMode.IfMatch && currentJdkToolchain != null && matches(currentJdkToolchain, requirements)) { getLog().info("Not using an external toolchain as the current JDK matches the requirements."); return; } - - ToolchainPrivate toolchain = Stream.of(toolchainManager.getToolchainsForType(TOOLCHAIN_TYPE_JDK, session)) + ToolchainManager toolchainManager = session.getService(ToolchainManager.class); + Toolchain toolchain = toolchainManager.getToolchains(session, TOOLCHAIN_TYPE_JDK).stream() .filter(tc -> matches(tc, requirements)) .findFirst() .orElse(null); if (toolchain != null) { getLog().info("Found matching JDK toolchain: " + toolchain); } - if (toolchain == null && discoverToolchains) { getLog().debug("No matching toolchains configured, trying to discover JDK toolchains"); PersistedToolchains persistedToolchains = discoverer.discoverToolchains(comparator); getLog().debug("Discovered " + persistedToolchains.getToolchains().size() + " JDK toolchains"); - for (ToolchainModel tcm : persistedToolchains.getToolchains()) { - ToolchainPrivate tc = factory.createToolchain(tcm); + Toolchain tc = factory.createToolchain(tcm); if (tc != null && matches(tc, requirements)) { toolchain = tc; getLog().debug("Discovered matching JDK toolchain: " + toolchain); @@ -211,31 +202,28 @@ private void doExecute() throws MisconfiguredToolchainException, MojoFailureExce } } } - if (toolchain == null) { - throw new MojoFailureException( + throw new org.apache.maven.api.plugin.MojoException( "Cannot find matching toolchain definitions for the following toolchain types:" + requirements + System.lineSeparator() + "Define the required toolchains in your ~/.m2/toolchains.xml file."); } - if (useJdk == JdkMode.IfSame && currentJdkToolchain != null && Objects.equals(getJdkHome(currentJdkToolchain), getJdkHome(toolchain))) { getLog().debug("Not using an external toolchain as the current JDK has been selected."); return; } - - toolchainManager.storeToolchainToBuildContext(toolchain, session); + toolchainManager.storeToolchainToBuildContext(session, toolchain); getLog().debug("Found matching JDK toolchain: " + toolchain); } - private boolean matches(ToolchainPrivate tc, Map requirements) { + private boolean matches(Toolchain tc, Map requirements) { ToolchainModel model = tc.getModel(); for (Map.Entry req : requirements.entrySet()) { String key = req.getKey(); String reqVal = req.getValue(); - String tcVal = model.getProvides().getProperty(key); + String tcVal = model.getProvides().get(key); if (tcVal == null) { getLog().debug("Toolchain " + tc + " is missing required property: " + key); return false; @@ -249,19 +237,27 @@ private boolean matches(ToolchainPrivate tc, Map requirements) { } private boolean matches(String key, String reqVal, String tcVal) { - switch (key) { - case VERSION: - return RequirementMatcherFactory.createVersionMatcher(tcVal).matches(reqVal); - case ENV: - return reqVal.matches("(.*,|^)\\Q" + tcVal + "\\E(,.*|$)"); - default: - return RequirementMatcherFactory.createExactMatcher(tcVal).matches(reqVal); - } + return factory.createToolchain(ToolchainModel.newBuilder() + .type(TOOLCHAIN_TYPE_JDK) + .provides(Map.of(key, tcVal)) + .build()) + .matchesRequirements(Map.of(key, tcVal)); + + // return switch (key) { + // case VERSION -> RequirementMatcherFactory.createVersionMatcher(tcVal).matches(reqVal); + // case ENV -> reqVal.matches("(.*,|^)\\Q" + tcVal + "\\E(,.*|$)"); + // default -> RequirementMatcherFactory.createExactMatcher(tcVal).matches(reqVal); + // }; + } + + private String getJdkHome(Toolchain toolchain) { + return toolchain.getModel().getConfiguration().getChild("jdkHome").getValue(); } - private String getJdkHome(ToolchainPrivate toolchain) { - return ((Xpp3Dom) toolchain.getModel().getConfiguration()) - .getChild("jdkHome") - .getValue(); + @Inject() + private Log log; + + protected Log getLog() { + return log; } } diff --git a/src/main/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscoverer.java b/src/main/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscoverer.java index 897e69e..3ac0e27 100644 --- a/src/main/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscoverer.java +++ b/src/main/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscoverer.java @@ -18,12 +18,8 @@ */ package org.apache.maven.plugins.toolchain.jdk; -import javax.inject.Named; -import javax.inject.Singleton; - import java.io.IOException; import java.io.Reader; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -44,14 +40,17 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.toolchain.model.PersistedToolchains; -import org.apache.maven.toolchain.model.ToolchainModel; -import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader; -import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Writer; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.maven.api.Session; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.SessionScoped; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.services.xml.ToolchainsXmlFactory; +import org.apache.maven.api.services.xml.XmlReaderException; +import org.apache.maven.api.toolchain.PersistedToolchains; +import org.apache.maven.api.toolchain.ToolchainModel; +import org.apache.maven.api.xml.XmlNode; +import org.apache.maven.internal.xml.XmlNodeImpl; import static java.util.Comparator.comparing; import static org.apache.maven.plugins.toolchain.jdk.SelectJdkToolchainMojo.TOOLCHAIN_TYPE_JDK; @@ -63,7 +62,7 @@ * @since 3.2.0 */ @Named -@Singleton +@SessionScoped public class ToolchainDiscoverer { public static final String JAVA = "java."; @@ -89,12 +88,19 @@ public class ToolchainDiscoverer { private static final String COMMA = ","; public static final String USER_HOME = "user.home"; - private final Logger log = LoggerFactory.getLogger(getClass()); - private volatile Map cache; private volatile boolean cacheModified; private volatile Set foundJdks; + private final Log log; + private final Session session; + + @Inject + public ToolchainDiscoverer(Log log, Session session) { + this.log = log; + this.session = session; + } + /** * Build the model for the current JDK toolchain */ @@ -104,20 +110,21 @@ public Optional getCurrentJdkToolchain() { // in case the current JVM is not a JDK return Optional.empty(); } - ToolchainModel model = new ToolchainModel(); - model.setType(TOOLCHAIN_TYPE_JDK); + Map provides = new LinkedHashMap<>(); Stream.of(PROPERTIES).forEach(k -> { String v = System.getProperty(JAVA + k); if (v != null) { - model.addProvide(k, v); + provides.put(k, v); } }); - model.addProvide(CURRENT, "true"); - Xpp3Dom config = new Xpp3Dom("configuration"); - Xpp3Dom jdkHome = new Xpp3Dom(JDK_HOME); - jdkHome.setValue(currentJdkHome.toString()); - config.addChild(jdkHome); - model.setConfiguration(config); + provides.put(CURRENT, "true"); + XmlNode jdkHome = new XmlNodeImpl(JDK_HOME, currentJdkHome.toString()); + XmlNode config = new XmlNodeImpl("configuration", null, null, List.of(jdkHome), null); + ToolchainModel model = ToolchainModel.newBuilder() + .type(TOOLCHAIN_TYPE_JDK) + .provides(provides) + .configuration(config) + .build(); return Optional.of(model); } @@ -150,27 +157,25 @@ public PersistedToolchains discoverToolchains(String comparator) { List tcs = jdks.parallelStream() .map(s -> { ToolchainModel tc = getToolchainModel(s); - flags.getOrDefault(s, Collections.emptyMap()) - .forEach((k, v) -> tc.getProvides().setProperty(k, v)); - String version = tc.getProvides().getProperty(VERSION); + Map provides = new LinkedHashMap<>(tc.getProvides()); + provides.putAll(flags.getOrDefault(s, Collections.emptyMap())); + String version = provides.get(VERSION); if (isLts(version)) { - tc.getProvides().setProperty(LTS, "true"); + provides.put(LTS, "true"); } - return tc; + return tc.withProvides(provides); }) .sorted(getToolchainModelComparator(comparator)) .collect(Collectors.toList()); writeCache(); - PersistedToolchains ps = new PersistedToolchains(); - ps.setToolchains(tcs); - return ps; + return PersistedToolchains.newBuilder().toolchains(tcs).build(); } catch (Exception e) { if (log.isDebugEnabled()) { log.warn("Error discovering toolchains: " + e, e); } else { log.warn("Error discovering toolchains (enable debug level for more information): " + e); } - return new PersistedToolchains(); + return PersistedToolchains.newInstance(); } } @@ -187,7 +192,8 @@ private synchronized void readCache() { Path cacheFile = getCacheFile(); if (Files.isRegularFile(cacheFile)) { try (Reader r = Files.newBufferedReader(cacheFile)) { - PersistedToolchains pt = new MavenToolchainsXpp3Reader().read(r, false); + PersistedToolchains pt = + session.getService(ToolchainsXmlFactory.class).read(r, false); cache = pt.getToolchains().stream() // Remove stale entries .filter(tc -> { @@ -202,7 +208,7 @@ private synchronized void readCache() { .collect(Collectors.toConcurrentMap(this::getJdkHome, Function.identity())); } } - } catch (IOException | XmlPullParserException e) { + } catch (IOException | XmlReaderException e) { log.debug("Error reading toolchains cache: " + e, e); } } @@ -213,21 +219,20 @@ private synchronized void writeCache() { try { Path cacheFile = getCacheFile(); Files.createDirectories(cacheFile.getParent()); - try (Writer w = Files.newBufferedWriter(cacheFile)) { - PersistedToolchains pt = new PersistedToolchains(); - pt.setToolchains(cache.values().stream() - .map(tc -> { - ToolchainModel model = tc.clone(); - // Remove transient information - model.getProvides().remove(CURRENT); - model.getProvides().remove(ENV); - return model; - }) - .sorted(version().thenComparing(vendor())) - .collect(Collectors.toList())); - new MavenToolchainsXpp3Writer().write(w, pt); - } - } catch (IOException e) { + PersistedToolchains pt = PersistedToolchains.newBuilder() + .toolchains(cache.values().stream() + .map(tc -> + // Remove transient information + tc.withProvides(tc.getProvides().entrySet().stream() + .filter(e -> !e.getKey().equals(CURRENT)) + .filter(e -> !e.getKey().equals(ENV)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))) + .sorted(version().thenComparing(vendor())) + .collect(Collectors.toList())) + .build(); + + session.getService(ToolchainsXmlFactory.class).write(pt, cacheFile); + } catch (Exception e) { log.debug("Error writing toolchains cache: " + e, e); } cacheModified = false; @@ -249,8 +254,8 @@ private static Path getCacheFile() { } public Path getJdkHome(ToolchainModel toolchain) { - Xpp3Dom dom = (Xpp3Dom) toolchain.getConfiguration(); - Xpp3Dom javahome = dom != null ? dom.getChild(JDK_HOME) : null; + XmlNode dom = toolchain.getConfiguration(); + XmlNode javahome = dom != null ? dom.getChild(JDK_HOME) : null; String jdk = javahome != null ? javahome.getValue() : null; return Paths.get(Objects.requireNonNull(jdk)); } @@ -301,15 +306,13 @@ ToolchainModel doGetToolchainModel(Path jdk) { return null; } - ToolchainModel model = new ToolchainModel(); - model.setType(TOOLCHAIN_TYPE_JDK); - properties.forEach(model::addProvide); - Xpp3Dom configuration = new Xpp3Dom("configuration"); - Xpp3Dom jdkHome = new Xpp3Dom(JDK_HOME); - jdkHome.setValue(jdk.toString()); - configuration.addChild(jdkHome); - model.setConfiguration(configuration); - return model; + XmlNodeImpl jdkHome = new XmlNodeImpl(JDK_HOME, jdk.toString()); + XmlNodeImpl configuration = new XmlNodeImpl("configuration", null, null, List.of(jdkHome), null); + return ToolchainModel.newBuilder() + .type(TOOLCHAIN_TYPE_JDK) + .provides(properties) + .configuration(configuration) + .build(); } private static Path getCanonicalPath(Path path) { @@ -329,21 +332,15 @@ Comparator getToolchainModelComparator(String comparator) { } private Comparator getComparator(String part) { - switch (part.trim().toLowerCase(Locale.ROOT)) { - case LTS: - return lts(); - case VENDOR: - return vendor(); - case ENV: - return env(); - case CURRENT: - return current(); - case VERSION: - return version(); - default: - throw new IllegalArgumentException("Unsupported comparator: " + part - + ". Supported comparators are: vendor, env, current, lts and version."); - } + return switch (part.trim().toLowerCase(Locale.ROOT)) { + case LTS -> lts(); + case VENDOR -> vendor(); + case ENV -> env(); + case CURRENT -> current(); + case VERSION -> version(); + default -> throw new IllegalArgumentException("Unsupported comparator: " + part + + ". Supported comparators are: vendor, env, current, lts and version."); + }; } Comparator lts() { @@ -351,7 +348,7 @@ Comparator lts() { } Comparator vendor() { - return comparing((ToolchainModel tc) -> tc.getProvides().getProperty(VENDOR)); + return comparing((ToolchainModel tc) -> tc.getProvides().get(VENDOR)); } Comparator env() { @@ -363,7 +360,7 @@ Comparator current() { } Comparator version() { - return comparing((ToolchainModel tc) -> tc.getProvides().getProperty(VERSION), (v1, v2) -> { + return comparing((ToolchainModel tc) -> tc.getProvides().get(VERSION), (v1, v2) -> { String[] a = v1.split("\\."); String[] b = v2.split("\\."); int length = Math.min(a.length, b.length); diff --git a/src/main/resources/META-INF/plexus/components.xml b/src/main/resources/META-INF/plexus/components.xml deleted file mode 100644 index 8d96957..0000000 --- a/src/main/resources/META-INF/plexus/components.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - org.codehaus.plexus.component.configurator.ComponentConfigurator - toolchains-requirement-configurator - org.codehaus.plexus.component.configurator.BasicComponentConfigurator - - - org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup - toolchains-requirement-configurator - - - - - - org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup - toolchains-requirement-configurator - org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup - - - org.codehaus.plexus.component.configurator.converters.ConfigurationConverter - ToolchainsRequirement - customConverters - - - - - - org.codehaus.plexus.component.configurator.converters.ConfigurationConverter - ToolchainsRequirement - org.apache.maven.plugins.toolchain.ToolchainConverter - - - diff --git a/src/test/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscovererTest.java b/src/test/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscovererTest.java index 11657c0..168ccdf 100644 --- a/src/test/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscovererTest.java +++ b/src/test/java/org/apache/maven/plugins/toolchain/jdk/ToolchainDiscovererTest.java @@ -18,32 +18,39 @@ */ package org.apache.maven.plugins.toolchain.jdk; -import org.apache.maven.toolchain.model.PersistedToolchains; -import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.apache.maven.api.Session; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.services.xml.ToolchainsXmlFactory; +import org.apache.maven.api.toolchain.PersistedToolchains; +import org.apache.maven.impl.DefaultToolchainsXmlFactory; +import org.apache.maven.internal.impl.DefaultLog; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.JRE; -import org.slf4j.Logger; +import org.mockito.Mockito; import org.slf4j.LoggerFactory; import static org.apache.maven.plugins.toolchain.jdk.ToolchainDiscoverer.CURRENT; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; public class ToolchainDiscovererTest { - final Logger logger = LoggerFactory.getLogger(getClass()); + final Log logger = new DefaultLog(LoggerFactory.getLogger(ToolchainDiscovererTest.class)); @Test @DisabledOnJre(JRE.JAVA_8) // java 8 often has jdk != jre void testDiscovery() { - ToolchainDiscoverer discoverer = new ToolchainDiscoverer(); + Session session = Mockito.mock(Session.class); + ToolchainsXmlFactory xml = new DefaultToolchainsXmlFactory(); + when(session.getService(ToolchainsXmlFactory.class)).thenReturn(xml); + ToolchainDiscoverer discoverer = new ToolchainDiscoverer(logger, session); PersistedToolchains persistedToolchains = discoverer.discoverToolchains(); assertNotNull(persistedToolchains); persistedToolchains.getToolchains().forEach(model -> { - logger.info(" - " - + ((Xpp3Dom) model.getConfiguration()).getChild("jdkHome").getValue()); + logger.info(" - " + model.getConfiguration().getChild("jdkHome").getValue()); logger.info(" provides:"); model.getProvides().forEach((k, v) -> logger.info(" " + k + ": " + v)); });