001 /* 002 $Id: Groovy.java,v 1.6 2005/07/18 22:11:48 glaforge 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", new AntProjectPropertiesDelegate(project)); 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 }