1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.gmavenplus.mojo;
18
19 import org.apache.maven.plugins.annotations.Parameter;
20 import org.codehaus.gmavenplus.model.IncludeClasspath;
21
22 import java.io.File;
23
24 import org.apache.maven.plugins.annotations.Component;
25 import org.apache.maven.toolchain.Toolchain;
26 import org.apache.maven.toolchain.ToolchainManager;
27 import org.codehaus.gmavenplus.model.GroovyCompileConfiguration;
28 import org.codehaus.gmavenplus.util.ForkedGroovyCompiler;
29 import org.codehaus.gmavenplus.util.GroovyCompiler;
30
31 import java.io.*;
32 import java.lang.reflect.InvocationTargetException;
33 import java.net.MalformedURLException;
34 import java.nio.file.Files;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Set;
38
39
40
41
42
43
44
45 public abstract class AbstractCompileMojo extends AbstractGroovySourcesMojo {
46
47
48
49
50 @Parameter(defaultValue = "${project.build.sourceEncoding}")
51 protected String sourceEncoding;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 @Parameter(property = "maven.compiler.target", defaultValue = "1.8")
99 protected String targetBytecode;
100
101
102
103
104
105
106 @Parameter(property = "skipBytecodeCheck", defaultValue = "false")
107 protected boolean skipBytecodeCheck;
108
109
110
111
112 @Parameter(defaultValue = "false")
113 protected boolean debug;
114
115
116
117
118 @Parameter(defaultValue = "false")
119 protected boolean verbose;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 @Parameter(defaultValue = "1")
135 protected int warningLevel;
136
137
138
139
140 @Parameter(defaultValue = "0")
141 protected int tolerance;
142
143
144
145
146
147 @Parameter(defaultValue = "false")
148 protected boolean invokeDynamic;
149
150
151
152
153
154
155
156 @Parameter
157 protected Boolean parallelParsing = null;
158
159
160
161
162
163 @Parameter
164 protected File configScript;
165
166
167
168
169
170 @Parameter(defaultValue = "false")
171 protected boolean parameters;
172
173
174
175
176
177
178
179
180
181
182
183
184 @Parameter(defaultValue = "PROJECT_ONLY")
185 protected IncludeClasspath includeClasspath;
186
187
188
189
190
191
192
193 @Parameter(defaultValue = "false")
194 protected boolean previewFeatures;
195
196
197
198
199 @Component
200 protected ToolchainManager toolchainManager;
201
202
203
204
205 @Parameter(defaultValue = "false")
206 protected boolean fork;
207
208
209
210
211
212
213
214
215
216
217
218
219
220 @SuppressWarnings({"rawtypes"})
221 protected synchronized void doCompile(final Set<File> sources, final List classpath, final File compileOutputDirectory)
222 throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, MalformedURLException {
223 GroovyCompileConfiguration configuration = new GroovyCompileConfiguration(sources, classpath, compileOutputDirectory);
224 configuration.setIncludeClasspath(includeClasspath);
225 configuration.setSkipBytecodeCheck(skipBytecodeCheck);
226 configuration.setDebug(debug);
227 configuration.setVerbose(verbose);
228 configuration.setWarningLevel(warningLevel);
229 configuration.setTolerance(tolerance);
230 configuration.setInvokeDynamic(invokeDynamic);
231 configuration.setParallelParsing(parallelParsing);
232 configuration.setConfigScript(configScript);
233 configuration.setParameters(parameters);
234 configuration.setPreviewFeatures(previewFeatures);
235 configuration.setSourceEncoding(sourceEncoding);
236 configuration.setTargetBytecode(targetBytecode);
237
238 Toolchain toolchain = toolchainManager.getToolchainFromBuildContext("jdk", session);
239 if (toolchain != null) {
240 getLog().info("Toolchain in gmavenplus-plugin: " + toolchain);
241 performForkedCompilation(configuration, toolchain.findTool("java"));
242 } else if (fork) {
243 String javaExecutable = getJavaExecutable();
244 getLog().info("Forking compilation using " + javaExecutable);
245 performForkedCompilation(configuration, javaExecutable);
246 } else {
247 performInProcessCompilation(configuration, classpath);
248 }
249 }
250
251 protected void performInProcessCompilation(GroovyCompileConfiguration configuration, List<?> classpath) throws MalformedURLException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
252 setupClassWrangler(classpath, includeClasspath);
253 logPluginClasspath();
254 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
255
256 if (!groovyVersionSupportsAction()) {
257 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support compilation. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping compiling.");
258 return;
259 }
260
261 GroovyCompiler compiler = new GroovyCompiler(classWrangler, getLog());
262 compiler.compile(configuration);
263 }
264
265 protected void performForkedCompilation(GroovyCompileConfiguration configuration, String javaExecutable) {
266 if (javaExecutable == null) {
267 getLog().warn("Unable to find 'java' executable for toolchain. Falling back to in-process compilation.");
268 try {
269 performInProcessCompilation(configuration, configuration.getClasspath());
270 } catch (Exception e) {
271 throw new RuntimeException("Compilation failed", e);
272 }
273 return;
274 }
275
276 try {
277 File configFile = File.createTempFile("gmavenplus-compile-config", ".ser");
278 configFile.deleteOnExit();
279 try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(configFile.toPath()))) {
280 oos.writeObject(configuration);
281 }
282
283 List<String> command = new ArrayList<>();
284 command.add(javaExecutable);
285 command.add("-cp");
286 command.add(buildForkClasspath());
287 command.add(ForkedGroovyCompiler.class.getName());
288 command.add(configFile.getAbsolutePath());
289
290 getLog().info("Forking compilation using " + javaExecutable);
291 getLog().debug("Command: " + command);
292
293 ProcessBuilder pb = new ProcessBuilder(command);
294 pb.inheritIO();
295 Process process = pb.start();
296 int exitCode = process.waitFor();
297 if (exitCode != 0) {
298 throw new RuntimeException("Groovy compilation failed with exit code " + exitCode);
299 }
300 } catch (IOException | InterruptedException e) {
301 throw new RuntimeException("Unable to fork compilation", e);
302 }
303 }
304
305 protected String buildForkClasspath() {
306 StringBuilder cp = new StringBuilder();
307
308 cp.append(pluginDescriptor.getPluginArtifact().getFile().getAbsolutePath());
309
310
311 for (org.apache.maven.artifact.Artifact artifact : pluginDescriptor.getArtifacts()) {
312 cp.append(File.pathSeparator);
313 cp.append(artifact.getFile().getAbsolutePath());
314 }
315
316
317 try {
318 Class<?> logClass = org.apache.maven.plugin.logging.Log.class;
319 java.security.CodeSource codeSource = logClass.getProtectionDomain().getCodeSource();
320 if (codeSource != null) {
321 String logJar = new File(codeSource.getLocation().toURI()).getAbsolutePath();
322 cp.append(File.pathSeparator).append(logJar);
323 }
324 } catch (Exception e) {
325 getLog().warn("Could not find maven-plugin-api jar to add to fork classpath", e);
326 }
327
328 return cp.toString();
329 }
330
331 }