001 /*
002 $Id: Groovy.java,v 1.5 2005/06/10 09:55:30 cstein Exp $
003
004 Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
005
006 Redistribution and use of this software and associated documentation
007 ("Software"), with or without modification, are permitted provided
008 that the following conditions are met:
009
010 1. Redistributions of source code must retain copyright
011 statements and notices. Redistributions must also contain a
012 copy of this document.
013
014 2. Redistributions in binary form must reproduce the
015 above copyright notice, this list of conditions and the
016 following disclaimer in the documentation and/or other
017 materials provided with the distribution.
018
019 3. The name "groovy" must not be used to endorse or promote
020 products derived from this Software without prior written
021 permission of The Codehaus. For written permission,
022 please contact info@codehaus.org.
023
024 4. Products derived from this Software may not be called "groovy"
025 nor may "groovy" appear in their names without prior written
026 permission of The Codehaus. "groovy" is a registered
027 trademark of The Codehaus.
028
029 5. Due credit should be given to The Codehaus -
030 http://groovy.codehaus.org/
031
032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043 OF THE POSSIBILITY OF SUCH DAMAGE.
044
045 */
046
047 package org.codehaus.groovy.ant;
048
049 import groovy.lang.GroovyShell;
050 import groovy.lang.Script;
051 import groovy.util.AntBuilder;
052
053 import java.io.BufferedOutputStream;
054 import java.io.BufferedReader;
055 import java.io.File;
056 import java.io.FileOutputStream;
057 import java.io.FileReader;
058 import java.io.IOException;
059 import java.io.PrintStream;
060 import java.io.Reader;
061 import java.lang.reflect.Field;
062 import java.util.Hashtable;
063 import java.util.Vector;
064
065 import org.apache.tools.ant.BuildException;
066 import org.apache.tools.ant.DirectoryScanner;
067 import org.apache.tools.ant.Project;
068 import org.apache.tools.ant.Task;
069 import org.apache.tools.ant.types.FileSet;
070 import org.apache.tools.ant.types.Path;
071 import org.apache.tools.ant.types.Reference;
072 import org.codehaus.groovy.control.CompilationFailedException;
073 import org.codehaus.groovy.runtime.InvokerHelper;
074
075 /**
076 * Executes a series of Groovy statements.
077 *
078 * <p>Statements can
079 * either be read in from a text file using the <i>src</i> attribute or from
080 * between the enclosing groovy tags.</p>
081 *
082 *
083 * Based heavily on SQLExec.java which is part of apache-ant
084 * http://cvs.apache.org/viewcvs.cgi/ant/src/main/org/apache/tools/ant/taskdefs/SQLExec.java?rev=MAIN
085 *
086 * Copyright 2000-2005 The Apache Software Foundation
087 *
088 * Licensed under the Apache License, Version 2.0 (the "License");
089 * you may not use this file except in compliance with the License.
090 * You may obtain a copy of the License at
091 *
092 * http://www.apache.org/licenses/LICENSE-2.0
093 *
094 * Unless required by applicable law or agreed to in writing, software
095 * distributed under the License is distributed on an "AS IS" BASIS,
096 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
097 * See the License for the specific language governing permissions and
098 * limitations under the License.
099 *
100 *
101 */
102 public class Groovy extends Task {
103 /**
104 * files to load
105 */
106 private Vector filesets = new Vector();
107
108 /**
109 * input file
110 */
111 private File srcFile = null;
112
113 /**
114 * input command
115 */
116 private String command = "";
117
118 /**
119 * Print results.
120 */
121 private boolean print = false;
122
123 /**
124 * Results Output file.
125 */
126 private File output = null;
127
128 /**
129 * Append to an existing file or overwrite it?
130 */
131 private boolean append = false;
132
133 /**
134 * Used for caching loaders / driver. This is to avoid
135 * getting an OutOfMemoryError when calling this task
136 * multiple times in a row.
137 */
138 private static Hashtable loaderMap = new Hashtable(3);
139
140 private Path classpath;
141
142 /**
143 * User name.
144 */
145 private String userId = null;
146
147 /**
148 * Groovy Version needed for this collection of statements.
149 **/
150 private String version = null;
151
152
153 /**
154 * Set the name of the file to be run.
155 * Required unless statements are enclosed in the build file
156 */
157 public void setSrc(File srcFile) {
158 this.srcFile = srcFile;
159 }
160
161 /**
162 * Set an inline command to execute.
163 * NB: Properties are not expanded in this text.
164 */
165 public void addText(String txt) {
166 log("addText('"+txt+"')", Project.MSG_VERBOSE);
167 this.command += txt;
168 }
169
170 /**
171 * Adds a set of files (nested fileset attribute).
172 */
173 public void addFileset(FileSet set) {
174 filesets.addElement(set);
175 }
176
177 /**
178 * Print results from the statements;
179 * optional, default false
180 */
181 public void setPrint(boolean print) {
182 this.print = print;
183 }
184
185 /**
186 * Set the output file;
187 * optional, defaults to the Ant log.
188 */
189 public void setOutput(File output) {
190 this.output = output;
191 }
192
193 /**
194 * whether output should be appended to or overwrite
195 * an existing file. Defaults to false.
196 *
197 * @since Ant 1.5
198 */
199 public void setAppend(boolean append) {
200 this.append = append;
201 }
202
203
204 /**
205 * Sets the classpath for loading.
206 * @param classpath The classpath to set
207 */
208 public void setClasspath(Path classpath) {
209 this.classpath = classpath;
210 }
211
212 /**
213 * Add a path to the classpath for loading.
214 */
215 public Path createClasspath() {
216 if (this.classpath == null) {
217 this.classpath = new Path(getProject());
218 }
219 return this.classpath.createPath();
220 }
221
222 /**
223 * Set the classpath for loading
224 * using the classpath reference.
225 */
226 public void setClasspathRef(Reference r) {
227 createClasspath().setRefid(r);
228 }
229
230 /**
231 * Sets the version string, execute task only if
232 * groovy version match; optional.
233 * @param version The version to set
234 */
235 public void setVersion(String version) {
236 this.version = version;
237 }
238
239
240 protected static Hashtable getLoaderMap() {
241 return loaderMap;
242 }
243
244
245
246
247 /**
248 * Gets the classpath.
249 * @return Returns a Path
250 */
251 public Path getClasspath() {
252 return classpath;
253 }
254
255 /**
256 * Gets the userId.
257 * @return Returns a String
258 */
259 public String getUserId() {
260 return userId;
261 }
262
263 /**
264 * Set the user name for the connection; required.
265 * @param userId The userId to set
266 */
267 public void setUserid(String userId) {
268 this.userId = userId;
269 }
270
271 /**
272 * Gets the version.
273 * @return Returns a String
274 */
275 public String getVersion() {
276 return version;
277 }
278
279 /**
280 * Load the file and then execute it
281 */
282 public void execute() throws BuildException {
283 log("execute()", Project.MSG_VERBOSE);
284
285 command = command.trim();
286
287 try {
288 if (srcFile == null && command.length() == 0
289 && filesets.isEmpty()) {
290 throw new BuildException("Source file does not exist!", getLocation());
291 }
292
293 if (srcFile != null && !srcFile.exists()) {
294 throw new BuildException("Source file does not exist!", getLocation());
295 }
296
297 // deal with the filesets
298 for (int i = 0; i < filesets.size(); i++) {
299 FileSet fs = (FileSet) filesets.elementAt(i);
300 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
301 File srcDir = fs.getDir(getProject());
302
303 String[] srcFiles = ds.getIncludedFiles();
304 }
305
306 try {
307 PrintStream out = System.out;
308 try {
309 if (output != null) {
310 log("Opening PrintStream to output file " + output,
311 Project.MSG_VERBOSE);
312 out = new PrintStream(
313 new BufferedOutputStream(
314 new FileOutputStream(output
315 .getAbsolutePath(),
316 append)));
317 }
318
319 // if there are no groovy statements between the enclosing Groovy tags
320 // then read groovy statements in from a text file using the src attribute
321 if (command == null || command.trim().length() == 0) {
322 command = getText(new BufferedReader(new FileReader(srcFile)));
323 }
324
325
326 if (command != null) {
327 execGroovy(command,out);
328 } else {
329 throw new BuildException("Source file does not exist!", getLocation());
330 }
331
332 } finally {
333 if (out != null && out != System.out) {
334 out.close();
335 }
336 }
337 } catch (IOException e) {
338 throw new BuildException(e, getLocation());
339 }
340
341 log("statements executed successfully");
342 } finally{}
343 }
344
345
346 private static String getText(BufferedReader reader) throws IOException {
347 StringBuffer answer = new StringBuffer();
348 // reading the content of the file within a char buffer allow to keep the correct line endings
349 char[] charBuffer = new char[4096];
350 int nbCharRead = 0;
351 while ((nbCharRead = reader.read(charBuffer)) != -1) {
352 // appends buffer
353 answer.append(charBuffer, 0, nbCharRead);
354 }
355 reader.close();
356 return answer.toString();
357 }
358
359
360 /**
361 * read in lines and execute them
362 */
363 protected void runStatements(Reader reader, PrintStream out)
364 throws IOException {
365 log("runStatements()", Project.MSG_VERBOSE);
366
367 StringBuffer txt = new StringBuffer();
368 String line = "";
369
370 BufferedReader in = new BufferedReader(reader);
371
372 while ((line = in.readLine()) != null) {
373 line = getProject().replaceProperties(line);
374
375 if (line.indexOf("--") >= 0) {
376 txt.append("\n");
377 }
378 }
379 // Catch any statements not followed by ;
380 if (!txt.equals("")) {
381 execGroovy(txt.toString(), out);
382 }
383 }
384
385
386 /**
387 * Exec the statement.
388 */
389 protected void execGroovy(String txt, PrintStream out) {
390 log("execGroovy()", Project.MSG_VERBOSE);
391
392 // Check and ignore empty statements
393 if ("".equals(txt.trim())) {
394 return;
395 }
396
397 log("Groovy: " + txt, Project.MSG_VERBOSE);
398
399 //log(getClasspath().toString(),Project.MSG_VERBOSE);
400 GroovyShell groovy = new GroovyShell(GroovyShell.class.getClassLoader());
401
402 try {
403 Script script = groovy.parse(txt);
404 Project project = getProject();
405 script.setProperty("ant",new AntBuilder(project));
406 script.setProperty("project",project);
407 script.setProperty("properties",project.getProperties());
408 script.setProperty("target",getOwningTarget());
409 script.setProperty("task",this);
410
411 // treat the case Ant is run through Maven, and
412 if ("org.apache.commons.grant.GrantProject".equals(project.getClass().getName())) {
413 try {
414 Object propsHandler = project.getClass().getMethod("getPropsHandler", new Class[0]).invoke(project, new Object[0]);
415 Field contextField = propsHandler.getClass().getDeclaredField("context");
416 contextField.setAccessible(true);
417 Object context = contextField.get(propsHandler);
418 Object mavenPom = InvokerHelper.invokeMethod(context, "getProject", new Object[0]);
419 script.setProperty("pom", mavenPom);
420 } catch (Exception e) {
421 throw new BuildException("Impossible to retrieve Maven's Ant project: " + e.getMessage(), getLocation());
422 }
423 }
424
425 script.run();
426 } catch (CompilationFailedException e) {
427 throw new BuildException("Script Failed: "+ e.getMessage(), getLocation());
428 }
429
430 if (print) {
431 StringBuffer line = new StringBuffer();
432 line.append( " foo bar");
433 out.println(line);
434 }
435
436
437 }
438
439 /**
440 * print any results in the statement.
441 */
442 protected void printResults(PrintStream out) {
443 log("printResults()", Project.MSG_VERBOSE);
444 StringBuffer line = new StringBuffer();
445 out.println(line);
446 line = new StringBuffer();
447 out.println();
448 }
449 }