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.NoExitSecurityManager;
10
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.net.MalformedURLException;
14
15 import static org.codehaus.gmavenplus.mojo.ExecuteMojo.GROOVY_4_0_0_RC_1;
16 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
17 import static org.codehaus.gmavenplus.util.ReflectionUtils.findField;
18 import static org.codehaus.gmavenplus.util.ReflectionUtils.findMethod;
19 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
20 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeMethod;
21 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeStaticMethod;
22
23
24
25
26
27
28
29
30
31
32
33 @Mojo(name = "shell", requiresDependencyResolution = ResolutionScope.TEST)
34 public class ShellMojo extends AbstractToolsMojo {
35
36
37
38
39 protected static final Version GROOVY_4_0_0_ALPHA1 = new Version(4, 0, 0, "alpha-1");
40
41
42
43
44
45
46
47
48
49
50 @Parameter(defaultValue = "QUIET")
51 protected String verbosity;
52
53
54
55
56
57
58 @Override
59 public void execute() throws MojoExecutionException {
60 try {
61 setupClassWrangler(project.getTestClasspathElements(), includeClasspath);
62 } catch (MalformedURLException e) {
63 throw new MojoExecutionException("Unable to add project test dependencies to classpath.", e);
64 } catch (DependencyResolutionRequiredException e) {
65 throw new MojoExecutionException("Test dependencies weren't resolved.", e);
66 }
67
68 logPluginClasspath();
69 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
70
71 try {
72 getLog().debug("Project test classpath:\n" + project.getTestClasspathElements());
73 } catch (DependencyResolutionRequiredException e) {
74 getLog().debug("Unable to log project test classpath");
75 }
76
77 if (!groovyVersionSupportsAction()) {
78 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support running a shell. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping shell startup.");
79 return;
80 }
81
82 final SecurityManager defaultSecurityManager = System.getSecurityManager();
83 try {
84 if (!allowSystemExits) {
85 getLog().warn("JEP 411 deprecated Security Manager in Java 17 for removal. Therefore `allowSystemExits` is also deprecated for removal.");
86 try {
87 System.setSecurityManager(new NoExitSecurityManager());
88 } catch (UnsupportedOperationException e) {
89 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.");
90 }
91 }
92
93
94 Class<?> shellClass = classWrangler.getClass(groovyAtLeast(GROOVY_4_0_0_ALPHA1) ? "org.apache.groovy.groovysh.Groovysh" : "org.codehaus.groovy.tools.shell.Groovysh");
95 Class<?> bindingClass = classWrangler.getClass("groovy.lang.Binding");
96 Class<?> ioClass = classWrangler.getClass("org.codehaus.groovy.tools.shell.IO");
97 Class<?> verbosityClass = classWrangler.getClass("org.codehaus.groovy.tools.shell.IO$Verbosity");
98 Class<?> loggerClass = classWrangler.getClass("org.codehaus.groovy.tools.shell.util.Logger");
99
100
101 Object shell = setupShell(shellClass, bindingClass, ioClass, verbosityClass, loggerClass);
102
103
104 invokeMethod(findMethod(shellClass, "run", String.class), shell, (String) null);
105 } catch (ClassNotFoundException e) {
106 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);
107 } catch (InvocationTargetException e) {
108 if (e.getCause() instanceof NoClassDefFoundError && e.getCause().getMessage() != null && e.getCause().getMessage().contains("jline")) {
109 throw new MojoExecutionException("Unable to get a JLine class from classpath. This might be because of a JLine version mismatch. If you are using Groovy < 2.2.0-beta-1, make sure you include JLine 1.0 as a runtime dependency in your project or the plugin.", e);
110 } else {
111 throw new MojoExecutionException("Error occurred while calling a method on a Groovy class from classpath.", e);
112 }
113 } catch (IllegalAccessException e) {
114 throw new MojoExecutionException("Unable to access a method on a Groovy class from classpath.", e);
115 } catch (InstantiationException e) {
116 throw new MojoExecutionException("Error occurred while instantiating a Groovy class from classpath.", e);
117 } finally {
118 if (!allowSystemExits) {
119 try {
120 System.setSecurityManager(defaultSecurityManager);
121 } catch (UnsupportedOperationException e) {
122 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.");
123 }
124 }
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 protected Object setupShell(final Class<?> shellClass, final Class<?> bindingClass, final Class<?> ioClass, final Class<?> verbosityClass, final Class<?> loggerClass) throws InvocationTargetException, IllegalAccessException, InstantiationException {
142 Object binding = invokeConstructor(findConstructor(bindingClass));
143 initializeProperties();
144 Method setVariable = findMethod(bindingClass, "setVariable", String.class, Object.class);
145 if (bindPropertiesToSeparateVariables) {
146 for (Object k : properties.keySet()) {
147 invokeMethod(setVariable, binding, k, properties.get(k));
148 }
149 } else {
150 if (groovyOlderThan(GROOVY_4_0_0_RC_1)) {
151 invokeMethod(setVariable, binding, "properties", properties);
152 } else {
153 throw new IllegalArgumentException("properties is a read-only property in Groovy " + GROOVY_4_0_0_RC_1 + " and later.");
154 }
155 }
156 Object io = invokeConstructor(findConstructor(ioClass));
157 invokeMethod(findMethod(ioClass, "setVerbosity", verbosityClass), io, invokeStaticMethod(findMethod(verbosityClass, "forName", String.class), verbosity));
158 findField(loggerClass, "io", ioClass).set(null, io);
159
160 return invokeConstructor(findConstructor(shellClass, ClassLoader.class, bindingClass, ioClass), classWrangler.getClassLoader(), binding, io);
161 }
162
163 }