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 io.micronaut.maven.InvocationResultWithOutput; 020import io.micronaut.maven.InvocationResultWithOutput.PerGoalOutputHandler; 021import org.apache.maven.execution.MavenSession; 022import org.apache.maven.model.Plugin; 023import org.apache.maven.model.PluginExecution; 024import org.apache.maven.plugin.BuildPluginManager; 025import org.apache.maven.plugin.MojoExecutionException; 026import org.apache.maven.project.MavenProject; 027import org.apache.maven.shared.invoker.DefaultInvocationRequest; 028import org.apache.maven.shared.invoker.Invoker; 029import org.apache.maven.shared.invoker.MavenInvocationException; 030import org.codehaus.plexus.util.xml.Xpp3Dom; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033import org.twdata.maven.mojoexecutor.MojoExecutor; 034 035import javax.inject.Inject; 036import javax.inject.Singleton; 037import java.io.File; 038import java.util.Arrays; 039import java.util.Optional; 040import java.util.Properties; 041import java.util.concurrent.atomic.AtomicReference; 042 043import static io.micronaut.maven.testresources.TestResourcesConfiguration.TEST_RESOURCES_ENABLED_PROPERTY; 044import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration; 045import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo; 046import static org.twdata.maven.mojoexecutor.MojoExecutor.executionEnvironment; 047import static org.twdata.maven.mojoexecutor.MojoExecutor.goal; 048import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin; 049 050/** 051 * Provides methods to execute goals on the current project. 052 * 053 * @author Álvaro Sánchez-Mariscal 054 * @since 1.1 055 */ 056@Singleton 057public class ExecutorService { 058 059 private static final Logger LOG = LoggerFactory.getLogger(ExecutorService.class); 060 061 private final MojoExecutor.ExecutionEnvironment executionEnvironment; 062 private final MavenProject mavenProject; 063 private final MavenSession mavenSession; 064 private final Invoker invoker; 065 066 @SuppressWarnings("CdiInjectionPointsInspection") 067 @Inject 068 public ExecutorService(MavenProject mavenProject, MavenSession mavenSession, BuildPluginManager pluginManager, 069 Invoker invoker) { 070 this.executionEnvironment = executionEnvironment(mavenProject, mavenSession, pluginManager); 071 this.mavenProject = mavenProject; 072 this.mavenSession = mavenSession; 073 this.invoker = invoker; 074 } 075 076 /** 077 * Executes the given goal from the given plugin coordinates. 078 * 079 * @param pluginKey The plugin coordinates in the format groupId:artifactId:version 080 * @param goal The goal to execute 081 * @throws MojoExecutionException If the goal execution fails 082 */ 083 public void executeGoal(String pluginKey, String goal) throws MojoExecutionException { 084 final Plugin plugin = mavenProject.getPlugin(pluginKey); 085 if (plugin != null) { 086 var executionId = new AtomicReference<>(goal); 087 if (goal != null && goal.indexOf('#') > -1) { 088 int pos = goal.indexOf('#'); 089 executionId.set(goal.substring(pos + 1)); 090 goal = goal.substring(0, pos); 091 } 092 Optional<PluginExecution> execution = plugin 093 .getExecutions() 094 .stream() 095 .filter(e -> e.getId().equals(executionId.get())) 096 .findFirst(); 097 Xpp3Dom configuration; 098 if (execution.isPresent()) { 099 configuration = (Xpp3Dom) execution.get().getConfiguration(); 100 } else if (plugin.getConfiguration() != null) { 101 configuration = (Xpp3Dom) plugin.getConfiguration(); 102 } else { 103 configuration = configuration(); 104 } 105 executeMojo(plugin, goal(goal), configuration, executionEnvironment); 106 } else { 107 throw new MojoExecutionException("Plugin not found: " + pluginKey); 108 } 109 } 110 111 /** 112 * Executes a goal using the given arguments. 113 * 114 * @param pluginGroup plugin group id 115 * @param pluginArtifact plugin artifact id 116 * @param pluginVersion plugin version 117 * @param goal goal to execute 118 * @param configuration configuration for the goal 119 * @throws MojoExecutionException if the goal execution fails 120 */ 121 public void executeGoal(String pluginGroup, String pluginArtifact, String pluginVersion, String goal, Xpp3Dom configuration) throws MojoExecutionException { 122 final Plugin plugin = plugin(pluginGroup, pluginArtifact, pluginVersion); 123 executeMojo(plugin, goal(goal), configuration, executionEnvironment); 124 } 125 126 /** 127 * Executes a goal using the Maven shared invoker. 128 * 129 * @param pluginKey The plugin coordinates in the format groupId:artifactId 130 * @param goal The goal to execute 131 * @return The result of the invocation 132 * @throws MavenInvocationException If the goal execution fails 133 */ 134 public InvocationResultWithOutput invokeGoal(String pluginKey, String goal) throws MavenInvocationException { 135 return invokeGoals(pluginKey + ":" + goal); 136 } 137 138 /** 139 * Executes a goal using the Maven shared invoker. 140 * 141 * @param goals The goals to execute 142 * @return The result of the invocation 143 * @throws MavenInvocationException If the goal execution fails 144 */ 145 public InvocationResultWithOutput invokeGoals(String... goals) throws MavenInvocationException { 146 return invokeGoals(mavenProject, goals); 147 } 148 149 /** 150 * Executes a goal using the Maven shared invoker. 151 * 152 * @param project The Maven project 153 * @param goals The goals to execute 154 * @return The result of the invocation 155 * @throws MavenInvocationException If the goal execution fails 156 */ 157 public InvocationResultWithOutput invokeGoals(MavenProject project, String... goals) throws MavenInvocationException { 158 var request = new DefaultInvocationRequest(); 159 request.setPomFile(project.getFile()); 160 File settingsFile = mavenSession.getRequest().getUserSettingsFile(); 161 if (settingsFile.exists()) { 162 request.setUserSettingsFile(settingsFile); 163 } 164 165 var properties = new Properties(); 166 //Pass through Jib properties 167 System.getProperties() 168 .entrySet() 169 .stream() 170 .filter(e -> e.getKey().toString().startsWith("jib")) 171 .forEach(e -> properties.put(e.getKey(), e.getValue())); 172 properties.put(TEST_RESOURCES_ENABLED_PROPERTY, StringUtils.FALSE); 173 request.setProperties(properties); 174 175 request.setLocalRepositoryDirectory(new File(mavenSession.getLocalRepository().getBasedir())); 176 request.setGoals(Arrays.asList(goals)); 177 request.setBatchMode(true); 178 request.setQuiet(false); 179 request.setAlsoMake(true); 180 181 var outputHandler = new PerGoalOutputHandler(); 182 request.setOutputHandler(outputHandler); 183 request.setErrorHandler(outputHandler); 184 185 var result = invoker.execute(request); 186 return new InvocationResultWithOutput(result, outputHandler); 187 } 188}