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 }