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 org.apache.maven.execution.MavenSession; 019import org.apache.maven.plugin.logging.Log; 020import org.apache.maven.plugin.logging.SystemStreamLog; 021import org.apache.maven.project.DefaultDependencyResolutionRequest; 022import org.apache.maven.project.DependencyResolutionRequest; 023import org.apache.maven.project.DependencyResolutionResult; 024import org.apache.maven.project.MavenProject; 025import org.apache.maven.project.ProjectDependenciesResolver; 026import org.apache.maven.shared.invoker.InvocationResult; 027import org.apache.maven.shared.invoker.MavenInvocationException; 028import org.eclipse.aether.RepositorySystemSession; 029import org.eclipse.aether.graph.Dependency; 030import org.eclipse.aether.graph.DependencyFilter; 031import org.eclipse.aether.util.filter.DependencyFilterUtils; 032 033import javax.inject.Inject; 034import javax.inject.Singleton; 035import java.io.File; 036import java.util.Collections; 037import java.util.Comparator; 038import java.util.List; 039import java.util.Optional; 040import java.util.stream.Collectors; 041 042/** 043 * Provides methods to compile a Maven project. 044 * 045 * @author Álvaro Sánchez-Mariscal 046 * @since 1.1 047 */ 048@Singleton 049public class CompilerService { 050 051 public static final String MAVEN_JAR_PLUGIN = "org.apache.maven.plugins:maven-jar-plugin"; 052 053 private static final String COMPILE_GOAL = "compile"; 054 055 private final Log log; 056 private final MavenSession mavenSession; 057 private final ExecutorService executorService; 058 private final ProjectDependenciesResolver resolver; 059 060 @SuppressWarnings("MnInjectionPoints") 061 @Inject 062 public CompilerService(MavenSession mavenSession, ExecutorService executorService, 063 ProjectDependenciesResolver resolver) { 064 this.mavenSession = mavenSession; 065 this.resolver = resolver; 066 this.log = new SystemStreamLog(); 067 this.executorService = executorService; 068 } 069 070 /** 071 * Compiles the project. 072 * 073 * @return the last compilation time millis. 074 */ 075 public Optional<Long> compileProject() { 076 Long lastCompilation = null; 077 if (log.isDebugEnabled()) { 078 log.debug("Compiling the project"); 079 } 080 try { 081 executorService.invokeGoals(COMPILE_GOAL); 082 lastCompilation = System.currentTimeMillis(); 083 } catch (Exception e) { 084 if (log.isErrorEnabled()) { 085 log.error("Error while compiling the project: ", e); 086 } 087 } 088 return Optional.ofNullable(lastCompilation); 089 } 090 091 /** 092 * Resolves project dependencies for the given scopes. 093 * 094 * @param runnableProject the project to resolve dependencies for. 095 * @param scopes the scopes to resolve dependencies for. 096 * @return the list of dependencies. 097 */ 098 public List<Dependency> resolveDependencies(MavenProject runnableProject, String... scopes) { 099 try { 100 DependencyFilter filter = DependencyFilterUtils.classpathFilter(scopes); 101 RepositorySystemSession session = mavenSession.getRepositorySession(); 102 DependencyResolutionRequest dependencyResolutionRequest = new DefaultDependencyResolutionRequest(runnableProject, session); 103 dependencyResolutionRequest.setResolutionFilter(filter); 104 DependencyResolutionResult result = resolver.resolve(dependencyResolutionRequest); 105 return result.getDependencies(); 106 } catch (org.apache.maven.project.DependencyResolutionException e) { 107 if (log.isWarnEnabled()) { 108 log.warn("Error while trying to resolve dependencies for the current project", e); 109 } 110 return Collections.emptyList(); 111 } 112 } 113 114 /** 115 * Builds a classpath string for the given dependencies. 116 * 117 * @param dependencies the dependencies to build the classpath for. 118 * @return the classpath string. 119 */ 120 public String buildClasspath(List<Dependency> dependencies) { 121 Comparator<Dependency> byGroupId = Comparator.comparing(d -> d.getArtifact().getGroupId()); 122 Comparator<Dependency> byArtifactId = Comparator.comparing(d -> d.getArtifact().getArtifactId()); 123 return dependencies.stream() 124 .sorted(byGroupId.thenComparing(byArtifactId)) 125 .map(dependency -> dependency.getArtifact().getFile().getAbsolutePath()) 126 .collect(Collectors.joining(File.pathSeparator)); 127 } 128 129 /** 130 * Packages the project by invoking the Jar plugin. 131 * 132 * @return the invocation result. 133 */ 134 public InvocationResult packageProject() throws MavenInvocationException { 135 return executorService.invokeGoal(MAVEN_JAR_PLUGIN, "jar"); 136 } 137}