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.artifact.DependencyResolutionRequiredException;
20 import org.apache.maven.plugin.MojoExecutionException;
21 import org.apache.maven.plugins.annotations.Mojo;
22 import org.apache.maven.plugins.annotations.Parameter;
23 import org.apache.maven.plugins.annotations.ResolutionScope;
24 import org.codehaus.gmavenplus.model.internal.Version;
25 import org.codehaus.gmavenplus.util.FileUtils;
26 import org.codehaus.gmavenplus.util.NoExitSecurityManager;
27
28 import java.io.BufferedReader;
29 import java.io.File;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.io.Reader;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Method;
36 import java.net.MalformedURLException;
37 import java.net.URL;
38 import java.net.URLConnection;
39
40 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
41 import static org.codehaus.gmavenplus.util.ReflectionUtils.findMethod;
42 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
43 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeMethod;
44
45
46
47
48
49
50
51
52
53
54
55 @Mojo(name = "execute", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true)
56 public class ExecuteMojo extends AbstractToolsMojo {
57
58
59
60
61 protected static final Version GROOVY_4_0_0_RC_1 = new Version(4, 0, 0, "RC-1");
62
63
64
65
66 protected static final Version GROOVY_1_7_0 = new Version(1, 7, 0);
67
68
69
70
71
72 @Parameter(required = true, property = "scripts")
73 protected String[] scripts;
74
75
76
77
78 @Parameter(defaultValue = "false", property = "continueExecuting")
79 protected boolean continueExecuting;
80
81
82
83
84
85
86 @Parameter(defaultValue = "${project.build.sourceEncoding}")
87 protected String sourceEncoding;
88
89
90
91
92
93
94 @Parameter(defaultValue = "false", property = "skipScriptExecution")
95 protected boolean skipScriptExecution;
96
97
98
99
100
101
102 @Parameter(defaultValue = "0", property = "urlConnectionTimeout")
103 protected int urlConnectionTimeout;
104
105
106
107
108
109
110 @Parameter(defaultValue = "0", property = "urlReadTimeout")
111 protected int urlReadTimeout;
112
113
114
115
116
117
118 @Override
119 public void execute() throws MojoExecutionException {
120 doExecute();
121 }
122
123
124
125
126
127
128 protected synchronized void doExecute() throws MojoExecutionException {
129 if (skipScriptExecution) {
130 getLog().info("Skipping script execution because ${skipScriptExecution} was set to true.");
131 return;
132 }
133
134 if (scripts == null || scripts.length == 0) {
135 getLog().info("No scripts specified for execution. Skipping.");
136 return;
137 }
138
139 try {
140 setupClassWrangler(project.getTestClasspathElements(), includeClasspath);
141 } catch (MalformedURLException e) {
142 throw new MojoExecutionException("Unable to add project test dependencies to classpath.", e);
143 } catch (DependencyResolutionRequiredException e) {
144 throw new MojoExecutionException("Test dependencies weren't resolved.", e);
145 }
146
147 logPluginClasspath();
148 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
149
150 try {
151 getLog().debug("Project test classpath:\n" + project.getTestClasspathElements());
152 } catch (DependencyResolutionRequiredException e) {
153 getLog().debug("Unable to log project test classpath");
154 }
155
156 if (!groovyVersionSupportsAction()) {
157 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support script execution. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping script execution.");
158 return;
159 }
160
161 final SecurityManager defaultSecurityManager = System.getSecurityManager();
162 try {
163 if (!allowSystemExits) {
164 getLog().warn("JEP 411 deprecated Security Manager in Java 17 for removal. Therefore `allowSystemExits` is also deprecated for removal.");
165 try {
166 System.setSecurityManager(new NoExitSecurityManager());
167 } catch (UnsupportedOperationException e) {
168 getLog().warn("Attempted to use Security Manager in a JVM where it's disabled by default. You might try `-Djava.security.manager=allow` to override this.");
169 }
170 }
171
172
173 Class<?> groovyShellClass = classWrangler.getClass("groovy.lang.GroovyShell");
174
175
176 Object shell = setupShell(groovyShellClass);
177
178
179 executeScripts(groovyShellClass, shell);
180 } catch (ClassNotFoundException e) {
181 throw new MojoExecutionException("Unable to get a Groovy class from classpath (" + e.getMessage() + "). Do you have Groovy as a compile dependency in your project or the plugin?", e);
182 } catch (InvocationTargetException e) {
183 throw new MojoExecutionException("Error occurred while calling a method on a Groovy class from classpath.", e);
184 } catch (InstantiationException e) {
185 throw new MojoExecutionException("Error occurred while instantiating a Groovy class from classpath.", e);
186 } catch (IllegalAccessException e) {
187 throw new MojoExecutionException("Unable to access a method on a Groovy class from classpath.", e);
188 } finally {
189 if (!allowSystemExits) {
190 try {
191 System.setSecurityManager(defaultSecurityManager);
192 } catch (UnsupportedOperationException e) {
193 getLog().warn("Attempted to use Security Manager in a JVM where it's disabled by default. You might try `-Djava.security.manager=allow` to override this.");
194 }
195 }
196 }
197 }
198
199
200
201
202
203
204
205
206
207
208
209 protected Object setupShell(final Class<?> groovyShellClass) throws InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException {
210 Object shell;
211 if (sourceEncoding != null) {
212 Class<?> compilerConfigurationClass = classWrangler.getClass("org.codehaus.groovy.control.CompilerConfiguration");
213 Object compilerConfiguration = invokeConstructor(findConstructor(compilerConfigurationClass));
214 invokeMethod(findMethod(compilerConfigurationClass, "setSourceEncoding", String.class), compilerConfiguration, sourceEncoding);
215 shell = invokeConstructor(findConstructor(groovyShellClass, ClassLoader.class, compilerConfigurationClass), classWrangler.getClassLoader(), compilerConfiguration);
216 } else {
217 shell = invokeConstructor(findConstructor(groovyShellClass, ClassLoader.class), classWrangler.getClassLoader());
218 }
219 initializeProperties();
220 Method setProperty = findMethod(groovyShellClass, "setProperty", String.class, Object.class);
221 if (bindPropertiesToSeparateVariables) {
222 for (Object k : properties.keySet()) {
223 invokeMethod(setProperty, shell, k, properties.get(k));
224 }
225 } else {
226 if (groovyOlderThan(GROOVY_4_0_0_RC_1)) {
227 invokeMethod(setProperty, shell, "properties", properties);
228 } else {
229 throw new IllegalArgumentException("properties is a read-only property in Groovy " + GROOVY_4_0_0_RC_1 + " and later.");
230 }
231 }
232
233 return shell;
234 }
235
236
237
238
239
240
241
242
243
244
245 protected void executeScripts(final Class<?> groovyShellClass, final Object shell) throws InvocationTargetException, IllegalAccessException, MojoExecutionException {
246 int scriptNum = 1;
247 for (String script : scripts) {
248 try {
249
250 try {
251
252 executeScriptFromUrl(groovyShellClass, shell, script);
253 } catch (MalformedURLException e) {
254
255 File scriptFile = new File(script);
256 if (scriptFile.isFile()) {
257 getLog().info("Running Groovy script from " + scriptFile.getCanonicalPath() + ".");
258 Method evaluateFile = findMethod(groovyShellClass, "evaluate", File.class);
259 invokeMethod(evaluateFile, shell, scriptFile);
260 } else {
261
262 Method evaluateString = findMethod(groovyShellClass, "evaluate", String.class);
263 invokeMethod(evaluateString, shell, script);
264 }
265 }
266 } catch (IOException ioe) {
267 if (continueExecuting) {
268 getLog().error("An Exception occurred while executing script " + scriptNum + ". Continuing to execute remaining scripts.", ioe);
269 } else {
270 throw new MojoExecutionException("An Exception occurred while executing script " + scriptNum + ".", ioe);
271 }
272 }
273 scriptNum++;
274 }
275 }
276
277
278
279
280
281
282
283
284
285
286
287 protected void executeScriptFromUrl(Class<?> groovyShellClass, Object shell, String script) throws IOException, InvocationTargetException, IllegalAccessException {
288 URLConnection urlConnection = new URL(script).openConnection();
289 if (urlConnectionTimeout > 0) {
290 urlConnection.setConnectTimeout(urlConnectionTimeout);
291 }
292 if (urlReadTimeout > 0) {
293 urlConnection.setReadTimeout(urlReadTimeout);
294 }
295 getLog().info("Running Groovy script from " + urlConnection.getURL() + ".");
296 if (groovyAtLeast(GROOVY_1_7_0)) {
297 Method evaluateUrlWithReader = findMethod(groovyShellClass, "evaluate", Reader.class);
298 BufferedReader reader = null;
299 try {
300 if (sourceEncoding != null) {
301 reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), sourceEncoding));
302 } else {
303 reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
304 }
305 invokeMethod(evaluateUrlWithReader, shell, reader);
306 } finally {
307 FileUtils.closeQuietly(reader);
308 }
309 } else {
310 Method evaluateUrlWithStream = findMethod(groovyShellClass, "evaluate", InputStream.class);
311 InputStream inputStream = null;
312 try {
313 if (sourceEncoding != null) {
314 getLog().warn("Source encoding does not apply to Groovy versions previous to 1.7.0, ignoring.");
315 }
316 inputStream = urlConnection.getInputStream();
317 invokeMethod(evaluateUrlWithStream, shell, urlConnection.getInputStream());
318 } finally {
319 FileUtils.closeQuietly(inputStream);
320 }
321 }
322 }
323
324 }