1 /*
2 * Copyright 2014 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * You may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.codehaus.gmavenplus.mojo;
18
19 import org.apache.maven.plugins.annotations.Component;
20 import org.apache.maven.plugins.annotations.Parameter;
21 import org.apache.maven.project.MavenProjectHelper;
22 import org.codehaus.gmavenplus.model.IncludeClasspath;
23
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.Properties;
26
27 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
28 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
29
30
31 /**
32 * The base tools mojo, which all tool mojos extend.
33 * Note that it references the plugin classloader to pull in dependencies
34 * Groovy didn't include (for things like Ant for AntBuilder, Ivy for @grab, and Jansi for Groovysh).
35 * Note that using the <code>ant</code> property requires Java 8, as the included Ant version was compiled for Java 8.
36 *
37 * @author Keegan Witt
38 * @since 1.1
39 */
40 public abstract class AbstractToolsMojo extends AbstractGroovyMojo {
41
42 /**
43 * Maven ProjectHelper to use in properties.
44 *
45 * @since 1.3
46 */
47 @Component
48 protected MavenProjectHelper projectHelper;
49
50 /**
51 * Properties to make available in scripts as variables using the property name. By default will include
52 * <dl>
53 * <dt>project</dt>
54 * <dd>A org.apache.maven.project.Project object of the current Maven project.</dd>
55 * <dt>session</dt>
56 * <dd>A org.apache.maven.execution.MavenSession object of the current Maven session.</dd>
57 * <dt>pluginArtifacts</dt>
58 * <dd>A list of org.apache.maven.artifact.Artifact objects of this plugin's artifacts.</dd>
59 * <dt>mojoExecution</dt>
60 * <dd>A org.apache.maven.plugin.MojoExecution object of this plugin's mojo execution.</dd>
61 * <dt>log</dt>
62 * <dd>A org.apache.maven.plugin.logging.Log object of Maven's log.</dd>
63 * <dt>ant</dt>
64 * <dd>A groovy.util.AntBuilder object (if groovy.ant.AntBuilder or groovy.util.AntBuilder is available).</dd>
65 * </dl>
66 * These can be overridden.
67 *
68 * @since 1.0-beta-3
69 */
70 @Parameter
71 protected Properties properties = new Properties();
72
73 /**
74 * Whether to allow System.exit() to be used. Should not be set to <code>false</code> when using parallel
75 * execution, as it isn't thread-safe.
76 *
77 * @since 1.2
78 */
79 @Parameter(defaultValue = "true")
80 protected boolean allowSystemExits;
81
82 /**
83 * Whether to bind each property to a separate variable (otherwise binds properties to a single 'properties' variable).
84 *
85 * @since 1.2
86 */
87 @Parameter(defaultValue = "true")
88 protected boolean bindPropertiesToSeparateVariables;
89
90 /**
91 * What classpath to include. One of
92 * <ul>
93 * <li>PROJECT_ONLY</li>
94 * <li>PROJECT_AND_PLUGIN</li>
95 * <li>PLUGIN_ONLY</li>
96 * </ul>
97 * Uses the same scope as the required dependency resolution of this mojo. Use only if you know what you're doing.
98 *
99 * @since 1.8.0
100 */
101 @Parameter(defaultValue = "PROJECT_AND_PLUGIN")
102 protected IncludeClasspath includeClasspath;
103
104 /**
105 * Whether to add all properties from <code>project.properties</code> into properties.
106 *
107 * @since 1.10.1
108 */
109 @Parameter(defaultValue = "false")
110 protected boolean bindAllProjectProperties;
111
112 /**
113 * Whether to add user session properties from <code>session.userProperties</code> that override project properties
114 * into properties. <code>bindAllSessionUserProperties</code> takes priority over this property if present. Has no
115 * effect if <code>bindAllProjectProperties</code> is <code>false</code>.
116 *
117 * @since 1.10.1
118 */
119 @Parameter(defaultValue = "false")
120 protected boolean bindSessionUserOverrideProperties;
121
122 /**
123 * Whether to add all properties from <code>session.userProperties</code> into properties. If both
124 * <code>bindAllProjectProperties</code> and <code>bindAllSessionUserProperties</code> are specified, the session
125 * properties will override the project properties, but it will also include properties not present in project
126 * properties. To only include user session properties that are also in project properties, use
127 * <code>bindSessionUserOverrideProperties</code>.
128 *
129 * @since 1.10.1
130 */
131 @Parameter(defaultValue = "false")
132 protected boolean bindAllSessionUserProperties;
133
134 /**
135 * Initializes the properties field.
136 */
137 protected void initializeProperties() {
138 if (project != null && !properties.containsKey("project")) {
139 properties.put("project", project);
140 }
141 if (session != null && !properties.containsKey("session")) {
142 properties.put("session", session);
143 }
144 if (pluginArtifacts != null && !properties.containsKey("pluginArtifacts")) {
145 properties.put("pluginArtifacts", pluginArtifacts);
146 }
147 if (mojoExecution != null && !properties.containsKey("mojoExecution")) {
148 properties.put("mojoExecution", mojoExecution);
149 }
150 if (!properties.containsKey("log")) {
151 properties.put("log", getLog());
152 }
153 if (projectHelper != null && !properties.containsKey("projectHelper")) {
154 properties.put("projectHelper", projectHelper);
155 }
156 if (!properties.containsKey("ant")) {
157 Object antBuilder = null;
158 try {
159 antBuilder = invokeConstructor(findConstructor(classWrangler.getClass("groovy.ant.AntBuilder")));
160 } catch (ClassNotFoundException e1) {
161 getLog().debug("groovy.ant.AntBuilder not available, trying groovy.util.AntBuilder.");
162 try {
163 antBuilder = invokeConstructor(findConstructor(classWrangler.getClass("groovy.util.AntBuilder")));
164 } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InvocationTargetException e2) {
165 logUnableToInitializeAntBuilder(e2);
166 }
167 } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
168 logUnableToInitializeAntBuilder(e);
169 }
170 if (antBuilder != null) {
171 properties.put("ant", antBuilder);
172 }
173 }
174 if (bindSessionUserOverrideProperties && !bindAllProjectProperties) {
175 getLog().warn("bindSessionUserOverrideProperties set without bindAllProjectProperties, ignoring.");
176 }
177 if (bindAllSessionUserProperties && bindSessionUserOverrideProperties) {
178 getLog().warn("bindAllSessionUserProperties and bindSessionUserOverrideProperties both set, bindAllSessionUserProperties will take precedence.");
179 }
180 if (bindAllProjectProperties && project != null) {
181 properties.putAll(project.getProperties());
182 }
183 if (session != null) {
184 if (bindAllSessionUserProperties) {
185 properties.putAll(session.getUserProperties());
186 } else if (bindAllProjectProperties && bindSessionUserOverrideProperties && project != null) {
187 for (Object key : project.getProperties().keySet()) {
188 if (session.getUserProperties().get(key) != null) {
189 properties.put(key, session.getUserProperties().get(key));
190 }
191 }
192 }
193 }
194 }
195
196 /**
197 * Logs errors that caused the 'ant' object to not be populated.
198 *
199 * @param e the exception causing the failure
200 */
201 protected void logUnableToInitializeAntBuilder(final Throwable e) {
202 getLog().warn("Unable to initialize 'ant' with a new AntBuilder object. Is Groovy a dependency? If you are using Groovy >= 2.3.0-rc-1, remember to include groovy-ant as a dependency.");
203 }
204
205 }