1 package io.micronaut.build.services;
2
3 import org.apache.maven.execution.MavenSession;
4 import org.apache.maven.plugin.MojoExecutionException;
5 import org.apache.maven.plugin.logging.Log;
6 import org.apache.maven.plugin.logging.SystemStreamLog;
7 import org.apache.maven.project.MavenProject;
8
9 import javax.inject.Inject;
10 import javax.inject.Singleton;
11 import java.io.File;
12 import java.nio.file.Path;
13 import java.util.Arrays;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.concurrent.atomic.AtomicReference;
18 import java.util.function.Function;
19 import java.util.stream.Collectors;
20 import java.util.stream.Stream;
21
22
23
24
25
26
27
28 @Singleton
29 public class CompilerService {
30
31 private static final String JAVA = "java";
32 private static final String GROOVY = "groovy";
33 private static final String KOTLIN = "kotlin";
34
35 public static final String MAVEN_COMPILER_PLUGIN = "org.apache.maven.plugins:maven-compiler-plugin";
36 public static final String MAVEN_RESOURCES_PLUGIN = "org.apache.maven.plugins:maven-resources-plugin";
37 public static final String GMAVEN_PLUS_PLUGIN = "org.codehaus.gmavenplus:gmavenplus-plugin";
38 public static final String KOTLIN_MAVEN_PLUGIN = "org.jetbrains.kotlin:kotlin-maven-plugin";
39
40
41
42
43
44 private static final List<String> PHASES_AFTER_COMPILE = Arrays.asList(
45 "compile",
46 "process-classes",
47 "generate-test-sources",
48 "process-test-sources",
49 "generate-test-resources",
50 "process-test-resources",
51 "test-compile",
52 "process-test-classes",
53 "test",
54 "prepare-package",
55 "package",
56 "pre-integration-test",
57 "integration-test",
58 "post-integration-test",
59 "verify",
60 "install",
61 "deploy");
62
63 private final Log log;
64 private final Map<String, Path> sourceDirectories;
65 private final MavenProject mavenProject;
66 private final MavenSession mavenSession;
67 private final ExecutorService executorService;
68
69 @SuppressWarnings("CdiInjectionPointsInspection")
70 @Inject
71 public CompilerService(MavenProject mavenProject, MavenSession mavenSession, ExecutorService executorService) {
72 this.log = new SystemStreamLog();
73 this.mavenProject = mavenProject;
74 this.mavenSession = mavenSession;
75 this.executorService = executorService;
76 this.sourceDirectories = resolveSourceDirectories();
77 }
78
79 public boolean needsCompilation() {
80 return mavenSession.getGoals().stream().noneMatch(PHASES_AFTER_COMPILE::contains);
81 }
82
83 public Optional<Long> compileProject(boolean copyResources) {
84 Long lastCompilation = null;
85 if (log.isDebugEnabled()) {
86 log.debug("Compiling the project");
87 }
88 try {
89 if (sourceDirectories.containsKey(GROOVY)) {
90 executorService.executeGoal(GMAVEN_PLUS_PLUGIN, "addSources");
91 executorService.executeGoal(GMAVEN_PLUS_PLUGIN, "generateStubs");
92 if (copyResources) {
93 executorService.executeGoal(MAVEN_RESOURCES_PLUGIN, "resources");
94 }
95 executorService.executeGoal(MAVEN_COMPILER_PLUGIN, "compile");
96 executorService.executeGoal(GMAVEN_PLUS_PLUGIN, "compile");
97 executorService.executeGoal(GMAVEN_PLUS_PLUGIN, "removeStubs");
98 lastCompilation = System.currentTimeMillis();
99 }
100 if (sourceDirectories.containsKey(KOTLIN)) {
101 executorService.executeGoal(KOTLIN_MAVEN_PLUGIN, "kapt");
102 if (copyResources) {
103 executorService.executeGoal(MAVEN_RESOURCES_PLUGIN, "resources");
104 }
105 executorService.executeGoal(KOTLIN_MAVEN_PLUGIN, "compile");
106 executorService.executeGoal(MAVEN_COMPILER_PLUGIN, "compile#java-compile");
107 lastCompilation = System.currentTimeMillis();
108 }
109 if (sourceDirectories.containsKey(JAVA)) {
110 if (copyResources) {
111 executorService.executeGoal(MAVEN_RESOURCES_PLUGIN, "resources");
112 }
113 executorService.executeGoal(MAVEN_COMPILER_PLUGIN, "compile");
114 lastCompilation = System.currentTimeMillis();
115 }
116 } catch (MojoExecutionException e) {
117 if (log.isErrorEnabled()) {
118 log.error("Error while compiling the project: ", e);
119 }
120 }
121 return Optional.ofNullable(lastCompilation);
122 }
123
124 public Map<String, Path> resolveSourceDirectories() {
125 if (log.isDebugEnabled()) {
126 log.debug("Resolving source directories...");
127 }
128 AtomicReference<String> lang = new AtomicReference<>();
129 Map<String, Path> sourceDirectories = Stream.of(JAVA, GROOVY, KOTLIN)
130 .peek(lang::set)
131 .map(l -> new File(mavenProject.getBasedir(), "src/main/" + l))
132 .filter(File::exists)
133 .peek(f -> {
134 if (log.isDebugEnabled()) {
135 log.debug("Found source: " + f.getPath());
136 }
137 })
138 .map(File::toPath)
139 .collect(Collectors.toMap(path -> lang.get(), Function.identity()));
140 if (sourceDirectories.isEmpty()) {
141 throw new IllegalStateException("Source folders not found for neither Java/Groovy/Kotlin");
142 }
143 return sourceDirectories;
144 }
145
146 }