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 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
317
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 }