001/* 002 * Copyright 2017-2022 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven.services; 017 018import io.micronaut.core.util.StringUtils; 019import org.apache.maven.execution.MavenSession; 020import org.apache.maven.model.Plugin; 021import org.apache.maven.model.PluginExecution; 022import org.apache.maven.plugin.BuildPluginManager; 023import org.apache.maven.plugin.MojoExecutionException; 024import org.apache.maven.project.MavenProject; 025import org.apache.maven.shared.invoker.DefaultInvocationRequest; 026import org.apache.maven.shared.invoker.InvocationResult; 027import org.apache.maven.shared.invoker.Invoker; 028import org.apache.maven.shared.invoker.MavenInvocationException; 029import org.codehaus.plexus.util.xml.Xpp3Dom; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import javax.inject.Inject; 034import javax.inject.Singleton; 035import java.io.File; 036import java.util.Arrays; 037import java.util.Optional; 038import java.util.Properties; 039import java.util.concurrent.atomic.AtomicReference; 040 041import static io.micronaut.maven.testresources.TestResourcesConfiguration.TEST_RESOURCES_ENABLED_PROPERTY; 042import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration; 043import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo; 044import static org.twdata.maven.mojoexecutor.MojoExecutor.executionEnvironment; 045import static org.twdata.maven.mojoexecutor.MojoExecutor.goal; 046import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin; 047 048/** 049 * Provides methods to execute goals on the current project. 050 * 051 * @author Álvaro Sánchez-Mariscal 052 * @since 1.1 053 */ 054@Singleton 055public class ExecutorService { 056 057 private static final Logger LOG = LoggerFactory.getLogger(ExecutorService.class); 058 059 private final BuildPluginManager pluginManager; 060 private final MavenProject mavenProject; 061 private final MavenSession mavenSession; 062 private final Invoker invoker; 063 064 @SuppressWarnings("CdiInjectionPointsInspection") 065 @Inject 066 public ExecutorService(MavenProject mavenProject, MavenSession mavenSession, BuildPluginManager pluginManager, 067 Invoker invoker) { 068 this.pluginManager = pluginManager; 069 this.mavenProject = mavenProject; 070 this.mavenSession = mavenSession; 071 this.invoker = invoker; 072 } 073 074 /** 075 * Executes the given goal from the given plugin coordinates. 076 * 077 * @param pluginKey The plugin coordinates in the format groupId:artifactId:version 078 * @param goal The goal to execute 079 * @throws MojoExecutionException If the goal execution fails 080 */ 081 public void executeGoal(String pluginKey, String goal) throws MojoExecutionException { 082 executeGoal(mavenProject, pluginKey, goal, null); 083 } 084 085 public final void executeGoal(MavenProject project, String pluginKey, String goal) throws MojoExecutionException { 086 executeGoal(project, pluginKey, goal, null); 087 } 088 089 public final void executeGoal(MavenProject project, String pluginKey, String goal, Xpp3Dom overriddenConfiguration) throws MojoExecutionException { 090 MavenProject targetProject = project == null ? mavenProject : project; 091 final Plugin plugin = targetProject.getPlugin(pluginKey); 092 if (plugin != null) { 093 String goalName = goal; 094 var executionId = new AtomicReference<>(goalName); 095 if (goalName != null && goalName.indexOf('#') > -1) { 096 int pos = goalName.indexOf('#'); 097 executionId.set(goal.substring(pos + 1)); 098 goalName = goalName.substring(0, pos); 099 } 100 Optional<PluginExecution> execution = plugin 101 .getExecutions() 102 .stream() 103 .filter(e -> e.getId().equals(executionId.get())) 104 .findFirst(); 105 Xpp3Dom configuration; 106 if (overriddenConfiguration != null) { 107 configuration = overriddenConfiguration; 108 } else if (execution.isPresent()) { 109 configuration = (Xpp3Dom) execution.get().getConfiguration(); 110 } else if (plugin.getConfiguration() != null) { 111 configuration = (Xpp3Dom) plugin.getConfiguration(); 112 } else { 113 configuration = configuration(); 114 } 115 executeMojo(plugin, goal(goalName), configuration, executionEnvironment(targetProject, mavenSession, pluginManager)); 116 } else { 117 throw new MojoExecutionException("Plugin not found: " + pluginKey); 118 } 119 } 120 121 /** 122 * Executes a goal using the given arguments. 123 * 124 * @param pluginGroup plugin group id 125 * @param pluginArtifact plugin artifact id 126 * @param pluginVersion plugin version 127 * @param goal goal to execute 128 * @param configuration configuration for the goal 129 * @throws MojoExecutionException if the goal execution fails 130 */ 131 public void executeGoal(String pluginGroup, String pluginArtifact, String pluginVersion, String goal, Xpp3Dom configuration) throws MojoExecutionException { 132 final Plugin plugin = plugin(pluginGroup, pluginArtifact, pluginVersion); 133 executeMojo(plugin, goal(goal), configuration, executionEnvironment(mavenProject, mavenSession, pluginManager)); 134 } 135 136 /** 137 * Executes a goal using the Maven shared invoker. 138 * 139 * @param pluginKey The plugin coordinates in the format groupId:artifactId 140 * @param goal The goal to execute 141 * @return The result of the invocation 142 * @throws MavenInvocationException If the goal execution fails 143 */ 144 public InvocationResult invokeGoal(String pluginKey, String goal) throws MavenInvocationException { 145 return invokeGoals(pluginKey + ":" + goal); 146 } 147 148 /** 149 * Executes a goal using the Maven shared invoker. 150 * 151 * @param goals The goals to execute 152 * @return The result of the invocation 153 * @throws MavenInvocationException If the goal execution fails 154 */ 155 public InvocationResult invokeGoals(String... goals) throws MavenInvocationException { 156 return invokeGoals(mavenProject, goals); 157 } 158 159 /** 160 * Executes a goal using the Maven shared invoker. 161 * 162 * @param project The Maven project 163 * @param goals The goals to execute 164 * @return The result of the invocation 165 * @throws MavenInvocationException If the goal execution fails 166 */ 167 168 public InvocationResult invokeGoals(MavenProject project, String... goals) throws MavenInvocationException { 169 var request = new DefaultInvocationRequest(); 170 request.setPomFile(project.getFile()); 171 File settingsFile = mavenSession.getRequest().getUserSettingsFile(); 172 if (settingsFile.exists()) { 173 request.setUserSettingsFile(settingsFile); 174 } 175 var properties = new Properties(); 176 properties.put(TEST_RESOURCES_ENABLED_PROPERTY, StringUtils.FALSE); 177 178 request.setLocalRepositoryDirectory(new File(mavenSession.getLocalRepository().getBasedir())); 179 request.addArgs(Arrays.asList(goals)); 180 request.setBatchMode(true); 181 request.setQuiet(true); 182 request.setAlsoMake(true); 183 request.setErrorHandler(LOG::error); 184 request.setOutputHandler(LOG::info); 185 request.setProperties(properties); 186 return invoker.execute(request); 187 } 188}