View Javadoc

1   /*
2    $Id: Groovyc.java,v 1.11 2004/04/29 22:39:39 glaforge Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package org.codehaus.groovy.ant;
47  
48  import java.io.File;
49  import java.io.PrintWriter;
50  import java.io.StringWriter;
51  import java.nio.charset.Charset;
52  
53  import org.apache.tools.ant.BuildException;
54  import org.apache.tools.ant.DirectoryScanner;
55  import org.apache.tools.ant.Project;
56  import org.apache.tools.ant.taskdefs.MatchingTask;
57  import org.apache.tools.ant.types.Path;
58  import org.apache.tools.ant.types.Reference;
59  import org.apache.tools.ant.util.GlobPatternMapper;
60  import org.apache.tools.ant.util.SourceFileScanner;
61  import org.codehaus.groovy.control.CompilationUnit;
62  import org.codehaus.groovy.control.CompilerConfiguration;
63  import org.codehaus.groovy.tools.ErrorReporter;
64  
65  
66  /***
67   * Compiles Groovy source files. This task can take the following
68   * arguments:
69   * <ul>
70   * <li>sourcedir
71   * <li>destdir
72   * <li>classpath
73   * </ul>
74   * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
75   * <p>
76   * When this task executes, it will recursively scan the sourcedir and
77   * destdir looking for Groovy source files to compile. This task makes its
78   * compile decision based on timestamp.
79   * 
80   * Based heavily on the Javac implementation in Ant
81   *
82   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
83   * @version $Revision: 1.11 $ 
84   */
85  public class Groovyc extends MatchingTask {
86  
87      private CompilerConfiguration configuration = new CompilerConfiguration();
88      private Path src;
89      private File destDir;
90      private Path compileClasspath;
91      private Path compileSourcepath;
92      private String encoding;
93  
94      protected boolean failOnError = true;
95      protected boolean listFiles = false;
96      protected File[] compileList = new File[0];
97  
98      public Groovyc() {
99      }
100 
101     /***
102      * Adds a path for source compilation.
103      *
104      * @return a nested src element.
105      */
106     public Path createSrc() {
107         if (src == null) {
108             src = new Path(getProject());
109         }
110         return src.createPath();
111     }
112 
113     /***
114      * Recreate src.
115      *
116      * @return a nested src element.
117      */
118     protected Path recreateSrc() {
119         src = null;
120         return createSrc();
121     }
122 
123     /***
124      * Set the source directories to find the source Java files.
125      * @param srcDir the source directories as a path
126      */
127     public void setSrcdir(Path srcDir) {
128         if (src == null) {
129             src = srcDir;
130         }
131         else {
132             src.append(srcDir);
133         }
134     }
135 
136     /***
137      * Gets the source dirs to find the source java files.
138      * @return the source directorys as a path
139      */
140     public Path getSrcdir() {
141         return src;
142     }
143 
144     /***
145      * Set the destination directory into which the Java source
146      * files should be compiled.
147      * @param destDir the destination director
148      */
149     public void setDestdir(File destDir) {
150         this.destDir = destDir;
151     }
152 
153     /***
154      * Enable verbose compiling which will display which files
155      * are being compiled
156      * @param verbose
157      */
158     public void setVerbose(boolean verbose) {
159         configuration.setVerbose( verbose );
160     }
161 
162     /***
163      * Gets the destination directory into which the java source files
164      * should be compiled.
165      * @return the destination directory
166      */
167     public File getDestdir() {
168         return destDir;
169     }
170 
171     /***
172      * Set the sourcepath to be used for this compilation.
173      * @param sourcepath the source path
174      */
175     public void setSourcepath(Path sourcepath) {
176         if (compileSourcepath == null) {
177             compileSourcepath = sourcepath;
178         }
179         else {
180             compileSourcepath.append(sourcepath);
181         }
182     }
183 
184     /***
185      * Gets the sourcepath to be used for this compilation.
186      * @return the source path
187      */
188     public Path getSourcepath() {
189         return compileSourcepath;
190     }
191 
192     /***
193      * Adds a path to sourcepath.
194      * @return a sourcepath to be configured
195      */
196     public Path createSourcepath() {
197         if (compileSourcepath == null) {
198             compileSourcepath = new Path(getProject());
199         }
200         return compileSourcepath.createPath();
201     }
202 
203     /***
204      * Adds a reference to a source path defined elsewhere.
205      * @param r a reference to a source path
206      */
207     public void setSourcepathRef(Reference r) {
208         createSourcepath().setRefid(r);
209     }
210 
211     /***
212      * Set the classpath to be used for this compilation.
213      *
214      * @param classpath an Ant Path object containing the compilation classpath.
215      */
216     public void setClasspath(Path classpath) {
217         if (compileClasspath == null) {
218             compileClasspath = classpath;
219         }
220         else {
221             compileClasspath.append(classpath);
222         }
223     }
224 
225     /***
226      * Gets the classpath to be used for this compilation.
227      * @return the class path
228      */
229     public Path getClasspath() {
230         return compileClasspath;
231     }
232 
233     /***
234      * Adds a path to the classpath.
235      * @return a class path to be configured
236      */
237     public Path createClasspath() {
238         if (compileClasspath == null) {
239             compileClasspath = new Path(getProject());
240         }
241         return compileClasspath.createPath();
242     }
243 
244     /***
245      * Adds a reference to a classpath defined elsewhere.
246      * @param r a reference to a classpath
247      */
248     public void setClasspathRef(Reference r) {
249         createClasspath().setRefid(r);
250     }
251 
252     public String createEncoding() {
253         if (encoding == null) {
254             encoding = System.getProperty("file.encoding");
255         }
256         return encoding;
257     }
258 
259     public void setEncoding(String encoding) {
260         this.encoding = encoding;
261     }
262 
263     public String getEncoding() {
264         return encoding;
265     }
266 
267     /***
268      * If true, list the source files being handed off to the compiler.
269      * @param list if true list the source files
270      */
271     public void setListfiles(boolean list) {
272         listFiles = list;
273     }
274 
275     /***
276      * Get the listfiles flag.
277      * @return the listfiles flag
278      */
279     public boolean getListfiles() {
280         return listFiles;
281     }
282 
283     /***
284      * Indicates whether the build will continue
285      * even if there are compilation errors; defaults to true.
286      * @param fail if true halt the build on failure
287      */
288     public void setFailonerror(boolean fail) {
289         failOnError = fail;
290     }
291 
292     /***
293      * @ant.attribute ignore="true"
294      * @param proceed inverse of failoferror
295      */
296     public void setProceed(boolean proceed) {
297         failOnError = !proceed;
298     }
299 
300     /***
301      * Gets the failonerror flag.
302      * @return the failonerror flag
303      */
304     public boolean getFailonerror() {
305         return failOnError;
306     }
307 
308     /***
309      * Executes the task.
310      * @exception BuildException if an error occurs
311      */
312     public void execute() throws BuildException {
313         checkParameters();
314         resetFileLists();
315 
316         // scan source directories and dest directory to build up
317         // compile lists
318         String[] list = src.list();
319         for (int i = 0; i < list.length; i++) {
320             File srcDir = getProject().resolveFile(list[i]);
321             if (!srcDir.exists()) {
322                 throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", getLocation());
323             }
324 
325             DirectoryScanner ds = this.getDirectoryScanner(srcDir);
326             String[] files = ds.getIncludedFiles();
327 
328             scanDir(srcDir, destDir != null ? destDir : srcDir, files);
329         }
330 
331         compile();
332     }
333 
334     /***
335      * Clear the list of files to be compiled and copied..
336      */
337     protected void resetFileLists() {
338         compileList = new File[0];
339     }
340 
341     /***
342      * Scans the directory looking for source files to be compiled.
343      * The results are returned in the class variable compileList
344      *
345      * @param srcDir   The source directory
346      * @param destDir  The destination directory
347      * @param files    An array of filenames
348      */
349     protected void scanDir(File srcDir, File destDir, String[] files) {
350         GlobPatternMapper m = new GlobPatternMapper();
351         m.setFrom("*.groovy");
352         m.setTo("*.class");
353         SourceFileScanner sfs = new SourceFileScanner(this);
354         File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
355 
356         if (newFiles.length > 0) {
357             File[] newCompileList = new File[compileList.length + newFiles.length];
358             System.arraycopy(compileList, 0, newCompileList, 0, compileList.length);
359             System.arraycopy(newFiles, 0, newCompileList, compileList.length, newFiles.length);
360             compileList = newCompileList;
361         }
362     }
363 
364     /***
365      * Gets the list of files to be compiled.
366      * @return the list of files as an array
367      */
368     public File[] getFileList() {
369         return compileList;
370     }
371 
372     protected void checkParameters() throws BuildException {
373         if (src == null) {
374             throw new BuildException("srcdir attribute must be set!", getLocation());
375         }
376         if (src.size() == 0) {
377             throw new BuildException("srcdir attribute must be set!", getLocation());
378         }
379 
380         if (destDir != null && !destDir.isDirectory()) {
381             throw new BuildException(
382                 "destination directory \"" + destDir + "\" does not exist " + "or is not a directory",
383                 getLocation());
384         }
385 
386         if (encoding != null && !Charset.isSupported(encoding)) {
387             throw new BuildException("encoding \"\" not supported");
388         }
389     }
390 
391     protected void compile() {
392 
393         if (compileList.length > 0) {
394             log(
395                 "Compiling "
396                     + compileList.length
397                     + " source file"
398                     + (compileList.length == 1 ? "" : "s")
399                     + (destDir != null ? " to " + destDir : ""));
400 
401             if (listFiles) {
402                 for (int i = 0; i < compileList.length; i++) {
403                     String filename = compileList[i].getAbsolutePath();
404                     log(filename);
405                 }
406             }
407 
408             try {
409                 Path classpath = getClasspath();
410                 if (classpath != null) {
411                     configuration.setClasspath(classpath.toString());
412                 }
413                 configuration.setTargetDirectory(destDir);
414 
415                 if (encoding != null) {
416                     configuration.setSourceEncoding(encoding);
417                 }
418 
419                 CompilationUnit unit = new CompilationUnit( configuration );
420                 unit.addSources( compileList );
421                 unit.compile( );
422             }
423             catch (Exception e) {
424 
425                 StringWriter writer = new StringWriter();
426                 new ErrorReporter( e, false ).write( new PrintWriter(writer) );
427                 String message = writer.toString();
428 
429                 if (failOnError) {
430                     throw new BuildException(message, e, getLocation());
431                 }
432                 else {
433                     log(message, Project.MSG_ERR);
434                 }
435 
436             }
437         }
438     }
439 }