1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 package org.codehaus.groovy.ant;
48
49 import groovy.lang.Binding;
50 import groovy.lang.GroovyClassLoader;
51 import groovy.lang.GroovyShell;
52 import groovy.lang.Script;
53 import groovy.util.AntBuilder;
54
55 import java.io.BufferedOutputStream;
56 import java.io.BufferedReader;
57 import java.io.File;
58 import java.io.FileOutputStream;
59 import java.io.FileReader;
60 import java.io.IOException;
61 import java.io.PrintStream;
62 import java.io.PrintWriter;
63 import java.io.Reader;
64 import java.io.StringWriter;
65 import java.lang.reflect.Field;
66 import java.util.Vector;
67
68 import org.apache.tools.ant.BuildException;
69 import org.apache.tools.ant.DirectoryScanner;
70 import org.apache.tools.ant.Project;
71 import org.apache.tools.ant.Task;
72 import org.apache.tools.ant.types.FileSet;
73 import org.apache.tools.ant.types.Path;
74 import org.apache.tools.ant.types.Reference;
75 import org.codehaus.groovy.control.CompilationFailedException;
76 import org.codehaus.groovy.control.CompilerConfiguration;
77 import org.codehaus.groovy.runtime.InvokerHelper;
78 import org.codehaus.groovy.tools.ErrorReporter;
79
80 /***
81 * Executes a series of Groovy statements.
82 *
83 * <p>Statements can
84 * either be read in from a text file using the <i>src</i> attribute or from
85 * between the enclosing groovy tags.</p>
86 */
87 public class Groovy extends Task {
88 /***
89 * files to load
90 */
91 private Vector filesets = new Vector();
92
93 /***
94 * input file
95 */
96 private File srcFile = null;
97
98 /***
99 * input command
100 */
101 private String command = "";
102
103 /***
104 * Results Output file.
105 */
106 private File output = null;
107
108 /***
109 * Append to an existing file or overwrite it?
110 */
111 private boolean append = false;
112
113 private Path classpath;
114
115 /***
116 * Compiler configuration.
117 *
118 * Used to specify the debug output to print stacktraces in case something fails.
119 * TODO: Could probably be reused to specify the encoding of the files to load or other properties.
120 */
121 private CompilerConfiguration configuration = new CompilerConfiguration();
122
123 /***
124 * Enable compiler to report stack trace information if a problem occurs
125 * during compilation.
126 * @param stacktrace
127 */
128 public void setStacktrace(boolean stacktrace) {
129 configuration.setDebug(stacktrace);
130 }
131
132
133 /***
134 * Set the name of the file to be run. The folder of the file is automatically added to the classpath.
135 * Required unless statements are enclosed in the build file
136 */
137 public void setSrc(final File srcFile) {
138 this.srcFile = srcFile;
139 }
140
141 /***
142 * Set an inline command to execute.
143 * NB: Properties are not expanded in this text.
144 */
145 public void addText(String txt) {
146 log("addText('"+txt+"')", Project.MSG_VERBOSE);
147 this.command += txt;
148 }
149
150 /***
151 * Adds a set of files (nested fileset attribute).
152 */
153 public void addFileset(FileSet set) {
154 filesets.addElement(set);
155 }
156
157 /***
158 * Set the output file;
159 * optional, defaults to the Ant log.
160 */
161 public void setOutput(File output) {
162 this.output = output;
163 }
164
165 /***
166 * whether output should be appended to or overwrite
167 * an existing file. Defaults to false.
168 *
169 * @since Ant 1.5
170 */
171 public void setAppend(boolean append) {
172 this.append = append;
173 }
174
175
176 /***
177 * Sets the classpath for loading.
178 * @param classpath The classpath to set
179 */
180 public void setClasspath(final Path classpath) {
181 this.classpath = classpath;
182 }
183
184 /***
185 * Returns a new path element that can be configured.
186 * Gets called for instance by Ant when it encounters a nested <classpath> element.
187 */
188 public Path createClasspath() {
189 if (this.classpath == null) {
190 this.classpath = new Path(getProject());
191 }
192 return this.classpath.createPath();
193 }
194
195 /***
196 * Set the classpath for loading
197 * using the classpath reference.
198 */
199 public void setClasspathRef(final Reference r) {
200 createClasspath().setRefid(r);
201 }
202
203 /***
204 * Gets the classpath.
205 * @return Returns a Path
206 */
207 public Path getClasspath() {
208 return classpath;
209 }
210
211 /***
212 * Load the file and then execute it
213 */
214 public void execute() throws BuildException {
215 log("execute()", Project.MSG_VERBOSE);
216
217 command = command.trim();
218
219 if (srcFile == null && command.length() == 0
220 && filesets.isEmpty()) {
221 throw new BuildException("Source file does not exist!", getLocation());
222 }
223
224 if (srcFile != null && !srcFile.exists()) {
225 throw new BuildException("Source file does not exist!", getLocation());
226 }
227
228
229 for (int i = 0; i < filesets.size(); i++) {
230 FileSet fs = (FileSet) filesets.elementAt(i);
231 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
232 File srcDir = fs.getDir(getProject());
233
234 String[] srcFiles = ds.getIncludedFiles();
235 }
236
237 try {
238 PrintStream out = System.out;
239 try {
240 if (output != null) {
241 log("Opening PrintStream to output file " + output,
242 Project.MSG_VERBOSE);
243 out = new PrintStream(
244 new BufferedOutputStream(
245 new FileOutputStream(output
246 .getAbsolutePath(),
247 append)));
248 }
249
250
251
252 if (command == null || command.trim().length() == 0) {
253 createClasspath().add(new Path(getProject(), srcFile.getParentFile().getCanonicalPath()));
254 command = getText(new BufferedReader(new FileReader(srcFile)));
255 }
256
257
258 if (command != null) {
259 execGroovy(command,out);
260 } else {
261 throw new BuildException("Source file does not exist!", getLocation());
262 }
263
264 } finally {
265 if (out != null && out != System.out) {
266 out.close();
267 }
268 }
269 } catch (IOException e) {
270 throw new BuildException(e, getLocation());
271 }
272
273 log("statements executed successfully", Project.MSG_VERBOSE);
274 }
275
276
277 private static String getText(BufferedReader reader) throws IOException {
278 StringBuffer answer = new StringBuffer();
279
280 char[] charBuffer = new char[4096];
281 int nbCharRead = 0;
282 while ((nbCharRead = reader.read(charBuffer)) != -1) {
283
284 answer.append(charBuffer, 0, nbCharRead);
285 }
286 reader.close();
287 return answer.toString();
288 }
289
290
291 /***
292 * read in lines and execute them
293 */
294 protected void runStatements(Reader reader, PrintStream out)
295 throws IOException {
296 log("runStatements()", Project.MSG_VERBOSE);
297
298 StringBuffer txt = new StringBuffer();
299 String line = "";
300
301 BufferedReader in = new BufferedReader(reader);
302
303 while ((line = in.readLine()) != null) {
304 line = getProject().replaceProperties(line);
305
306 if (line.indexOf("--") >= 0) {
307 txt.append("\n");
308 }
309 }
310
311 if (!txt.equals("")) {
312 execGroovy(txt.toString(), out);
313 }
314 }
315
316
317 /***
318 * Exec the statement.
319 */
320 protected void execGroovy(final String txt, final PrintStream out) {
321 log("execGroovy()", Project.MSG_VERBOSE);
322
323
324 if ("".equals(txt.trim())) {
325 return;
326 }
327
328 log("Groovy: " + txt, Project.MSG_VERBOSE);
329
330
331 Object mavenPom = null;
332 final Project project = getProject();
333 final ClassLoader baseClassLoader;
334
335 if ("org.apache.commons.grant.GrantProject".equals(project.getClass().getName())) {
336 try {
337 final Object propsHandler = project.getClass().getMethod("getPropsHandler", new Class[0]).invoke(project, new Object[0]);
338 final Field contextField = propsHandler.getClass().getDeclaredField("context");
339 contextField.setAccessible(true);
340 final Object context = contextField.get(propsHandler);
341 mavenPom = InvokerHelper.invokeMethod(context, "getProject", new Object[0]);
342 }
343 catch (Exception e) {
344 throw new BuildException("Impossible to retrieve Maven's Ant project: " + e.getMessage(), getLocation());
345 }
346
347 Thread.currentThread().setContextClassLoader(GroovyShell.class.getClassLoader());
348
349
350 baseClassLoader = mavenPom.getClass().getClassLoader();
351 } else {
352 baseClassLoader = GroovyShell.class.getClassLoader();
353 }
354
355 final GroovyClassLoader classLoader = new GroovyClassLoader(baseClassLoader);
356 addClassPathes(classLoader);
357
358 final GroovyShell groovy = new GroovyShell(classLoader, new Binding(), configuration);
359 try {
360 final Script script = groovy.parse(txt);
361 script.setProperty("ant", new AntBuilder(project, getOwningTarget()));
362 script.setProperty("project", project);
363 script.setProperty("properties", new AntProjectPropertiesDelegate(project));
364 script.setProperty("target", getOwningTarget());
365 script.setProperty("task", this);
366 if (mavenPom != null) {
367 script.setProperty("pom", mavenPom);
368 }
369 script.run();
370 } catch (CompilationFailedException e) {
371 StringWriter writer = new StringWriter();
372 new ErrorReporter( e, false ).write( new PrintWriter(writer) );
373 String message = writer.toString();
374 throw new BuildException("Script Failed: "+ message, getLocation());
375 }
376 }
377
378
379 /***
380 * Adds the class pathes (if any)
381 * @param classLoader the classloader to configure
382 */
383 protected void addClassPathes(final GroovyClassLoader classLoader)
384 {
385 if (classpath != null)
386 {
387 for (int i = 0; i < classpath.list().length; i++)
388 {
389 classLoader.addClasspath(classpath.list()[i]);
390 }
391 }
392 }
393
394 /***
395 * print any results in the statement.
396 */
397 protected void printResults(PrintStream out) {
398 log("printResults()", Project.MSG_VERBOSE);
399 StringBuffer line = new StringBuffer();
400 out.println(line);
401 line = new StringBuffer();
402 out.println();
403 }
404 }