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