]> source.dussan.org Git - aspectj.git/commitdiff
fixing version-handling.
authorwisberg <wisberg>
Mon, 23 Dec 2002 19:41:48 +0000 (19:41 +0000)
committerwisberg <wisberg>
Mon, 23 Dec 2002 19:41:48 +0000 (19:41 +0000)
build-properties.xml has actual version,
Version.java is generated,
and "DEVELOPMENT" is default.

build/build-properties.xml
build/build.xml
build/lib/BridgeVersion.java.txt
build/readme-build-module.html
build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java
build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java
build/src/org/aspectj/internal/tools/ant/taskdefs/VersionUptodate.java [new file with mode: 0644]
build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties
build/src/org/aspectj/internal/tools/build/BuildSpec.java
build/src/org/aspectj/internal/tools/build/Builder.java

index 64fab94a1070e04ccbde40d762d394e155f61f3c..e85eed1776b9515a21ca70521579ab6598ee879c 100644 (file)
     <target name="init-properties"
            unless="aspectj.modules.build.dir">
 
-      <!-- change version manually -->
-      <property name="build.version"       value="1.1b2"/> 
+      <!-- 
+       Changing version:
+       - base should always be 1.1 (used for manifests, other version-parsing code)
+       - Others should be DEVELOPMENT unless testing/doing release builds, when
+         they should be (e.g.,) 1.1b3 or 1.1beta3
+       - Changing version here causes org/aspectj/bridge/Version.java to be updated
+        - also change org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties
+      -->
+      <property name="build.version"       value="DEVELOPMENT"/> 
       <property name="build.version.base"  value="1.1"/> 
-      <property name="build.version.long"  value="1.1beta2"/> 
-      <property name="build.version.short" value="1.1b2"/> 
+      <property name="build.version.long"  value="DEVELOPMENT"/> 
+      <property name="build.version.short" value="DEVELOPMENT"/> 
 
       <!-- formats comply with SimpleDateFormat -->
       <property name="build.time.format"   value="MM/dd/yy 'at' hh:mm:ss z"/> 
                         timezone="PST"/>
          </tstamp>
          
+         <property name="company.name"         value="aspectj.org"/>
          <property name="copyright.allRights.from1998"
                value="Copyright (c) 1998-2001 Xerox Corporation, 2002 Palo Alto Research Center, Incorporated.  All rights reserved." />
-      <!-- XXX interim hack -->
-         <property name="aspectj.home.url"     value="http://aspectj.org" />
 
       <!-- callers define basedir as dir of build file? -->
       <property name="aspectj.modules.dir"
           unless="init-taskdefs.done" >
       <fail unless="aspectj.build.jar.available"
           message="unable to find aspectj.build.jar: ${aspectj.build.jar}"/>
+     <!-- run directly from classes in bin when debugging.
       <taskdef resource="org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties"
               classpath="${aspectj.build.jar}"/>
-     <!-- when debugging, etc.
+      -->
       <taskdef resource="org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties"
          classpath="${aspectj.modules.dir}/build/bin"/>
-      -->
       <property name="init-taskdefs.done" value="done"/>
     </target>
 
     <target name="init-filters"
          depends="init-properties"
           unless="init-filters.done" >
-      <!-- change version manually -->
-      <!-- see also org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties -->
+
+         <!-- build.version and build.date used in filters throughout, and
+              build.version.base used in filtering manifest, but 
+              others used mainly for installer-resources/properties.txt -->
+
       <filter token="build.version"       value="${build.version}"/> 
       <filter token="build.version.base"  value="${build.version.base}"/> 
       <filter token="build.version.long"  value="${build.version.long}"/> 
       <filter token="build.date.format"   value="${build.date.format}"/> 
       <filter token="build.date"          value="${build.date}"/>
       <filter token="build.time"          value="${build.time}"/>
+      <filter token="company.name"        value="${company.name}"/> 
       <filter token="copyright.allRights.from1998" 
               value="${copyright.allRights.from1998}" />
       <property name="init-filters.done" value="done"/>
   aspectj.modules.dir = ${aspectj.modules.dir}
          aj.build.dir = ${aj.build.dir}
        aj.results.dir = ${aj.results.dir}
-        release.build = ${release.build}
              ant.home = ${ant.home}
             java.home = ${java.home}
 </echo>
index 0382c44280d0e92b920be17ad64b4fe339c38a31..015493d91f7aa2b556df4e5042054116aba4917e 100644 (file)
 
     </target>
 
-    <target name="init-version" depends="init,init-filters" 
-         unless="init.version.done" if="release.build" > <!-- unless=version.uptodate -->
+    <target name="version-uptodate" depends="init,init-taskdefs"
+         unless="version-uptodate.done">
+                <versionuptodate
+                       version="${build.version}"
+                       versionSourceFile="${aspectj.modules.dir}/bridge/src/org/aspectj/bridge/Version.java"
+                       versionTagFile="${aj.temp.dir}/versionUptodate"/>
+                
+                <available file="${aj.temp.dir}/versionUptodate"
+                      property="version.uptodate"/>
+         <property name="version-uptodate.done" value="done"/>
+    </target>
+
+    <target name="init-version" depends="init,init-filters,version-uptodate" 
+         unless="version.uptodate">
       <antcall target="init-filters"/>
       <copy file="${aspectj.modules.dir}/build/lib/BridgeVersion.java.txt"
           tofile="${aspectj.modules.dir}/bridge/src/org/aspectj/bridge/Version.java"
            inheritAll="false"/> <!-- true? -->
        </target>
        
+       <target name="runtime" depends="init">
+         <antcall target="build-module-all">
+           <param name="module.name" value="runtime"/>
+         </antcall>
+       </target>
+       
     <!-- ===================================================================== -->
     <!-- boilerplate antcalls                                                  -->
     <!-- ===================================================================== -->
          </antcall>
        </target>
 
+       <target name="any-module-all" depends="init">
+         <antcall target="build-module-all">
+           <param name="module.name" value="${module.name}"/>
+         </antcall>
+       </target>
+
        <target name="any-product" depends="init">
          <antcall target="build-product">
            <param name="product.name" value="${product.name}"/>
index 95d41d201e1b1647d88b2681303e8dfd5da52f92..4d82a700b32d8905e8f7212d85af12a6487a6ba9 100644 (file)
@@ -20,14 +20,18 @@ import java.util.Date;
 /** release-specific version information */
 public class Version {
     
+    // generated from build/lib/BridgeVersion.java
+
     /** default version value for development version */
     public static final String DEVELOPMENT = "DEVELOPMENT";
+    // VersionUptodate.java depends on this value
 
     /** default time value for development version */
     public static final long NOTIME = 0L;
     
     /** set by build script */
     public static final String text = "@build.version@";
+    // VersionUptodate.java scans for "static final String text = "
     
     /** 
       * Time text set by build script using SIMPLE_DATE_FORMAT.
@@ -58,6 +62,24 @@ public class Version {
         }
         time = foundTime;
     }
+
+    /**
+     * Test whether the version is as specified by any first argument.
+     * Emit text to System.err on failure
+     * @param args String[] with first argument equal to Version.text
+     * @see Version#text
+     */
+    public static void main(String[] args) {
+        if ((null != args) && (0 < args.length)) {
+            if (!Version.text.equals(args[0])) {
+                System.err.println("version expected: \"" 
+                                + args[0] 
+                                + "\" actual=\"" 
+                                + Version.text 
+                                + "\"");
+            }
+        }
+    }
 }
     
 
index e056ba6f65cbc9f0dbe55ae03fdcea23da15dc38..bca0d78a54ef23340f81033f6409b49f28bd2018 100644 (file)
@@ -6,12 +6,11 @@
 This build module contains taskdefs and resources for doing builds
 and checking source licenses.
 
+<h3>Usage</h3>
+<h4>Running the build</h4>
 To do a build, use Ant to run <a href="build.xml">build.xml</a>
 from this directory.  To run Ant, use <a href="../lib/ant">../lib/ant</a>
-scripts and libraries.  In particular, when running Ant from eclipse,
-do not use the default Eclipse Ant classpath; remove those jars and
-add all the libraries in <a href="../lib/ant/lib">../lib/ant/lib</a>
-as well as in <a href="../lib/junit">../lib/junit</a>.  
+scripts and libraries.    
 Consider defining the following flag properties:
 <p>
 <table cellpadding="1" border="1">
@@ -20,17 +19,63 @@ Consider defining the following flag properties:
 <tr><td>check.build.jar
     </td><td>fail if build.jar is out of date
        </td></tr>
-<tr><td>release.build
-    </td><td>regenerate org/aspectj/bridge/Version.java
-       </td></tr>
-</table>                       
+</table>       
+<p>            
+
+<u>Release builds</u>: Release builds differ only in running
+from a clean, up-to-date tree and with correct build version values
+in <a href="build-properties.xml">build-properties.xml</a>, which
+will update org.aspectj.bridge.Version.  
+See below for more details on how the version is updated.
+<p>
+
+<h4>Updating module dependencies and file locations</h4>  
+Because the BuildModule taskdef extracts dependencies from the Eclipse 
+<code>.classpath</code> file, there is no need to update build scripts when
+adding or removing modules or changing their dependencies, so long
+as they are all in the base modules directory (usually the base of
+the eclipse workspace.
+All required libraries are checked into the <code>lib</code> module.
+
+<p>The BuildModule taskdef makes some assumptions about the naming, 
+position, and contents of module directories and files.  
+Understand those (documented in 
+<a href="src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java">
+   BuildModule.java</a>) before using non-standard module directories. 
+
+<p>
+<h4>Running builds or built jars under Eclipse</h4>
+When running Ant from eclipse,
+do not use the default Eclipse Ant classpath; remove those jars and
+add all the libraries in <a href="../lib/ant/lib">../lib/ant/lib</a>
+as well as in <a href="../lib/junit">../lib/junit</a>.
+<p>
+<u>warning</u>: Jar files do not seem to be closed properly when running under eclipse.
+This affects build products (e.g., installers) which are run under eclipse
+(e.g., by opening with the "default system editor") and libraries used
+when compiling under Javac (if not zip products or input).  This problem
+presents as files not being writable, i.e., deleted or modified.
+You might get no notice of the problem when
+deleting with quiet="on". (The alternative to that is to create any
+directories being deleted before deleting them).
 
 <p>
+Currently BuildModule taskdefs fork the Javac command to work around
+this problem, but the Zip commands do not work around it.
+
+If under Eclipse, you get strange behavior with Ant builds, clear 
+out everything and build from the command line. In some cases, you
+have to exit Eclipse before files can be deleted.  (*sigh*)
+
+
+<h3>Development</h3>
+<h4>BuildModule task</h4>
 The 
 <a href="src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java">
    BuildModule</a>
 taskdef implements an integrated module or product build.
-<u>Module builds</u> are based on the Eclipse .classpath file, and can produce
+<u>Module builds</u> are based on the Eclipse <code>.classpath</code>
+file, and can produce
 a jar with the module classes, with two variations: (a) include only
 the module classes, or assemble the jar complete with all antecedent
 modules and libraries; and (b) compile the module(s) without any
@@ -47,27 +92,37 @@ and a <code>dist</code> directory containing all files belonging in
 the distribution, including 0-length placeholders for the module build
 results.
 
+<h4>Build notes</h4>
 <p>
-Top-level temporary build directories are prefixed "aj-",
+<u>Directory names</u>: Top-level temporary build directories are prefixed "aj-",
 so you can safely destroy any such directory or ignore it
 in CVS or the Eclipse package explorer.  By default the build script
-puts them at the same level as other modules.
-<p>
-<u>Updating this module</u>:  
+puts them at the same level as other modules.  Property names follow
+a similar convention; those prefixed "aj-" may be deleted at will, while
+"aspectj-" names are source directories which should never be deleted.
 
-Because the BuildModule taskdef extracts dependencies from the Eclipse 
-.classpath file, there is no need to update build scripts when
-adding or removing modules or changing their dependencies, so long
-as they are all in the base modules directory (usually the base of
-the eclipse workspace.
-All required libraries are checked into the <code>lib</code> module.
+<p>
+<u>Version synchronization</u>: 
+Developers use the default "DEVELOPMENT" version unless doing or testing
+release builds.
 
-<p>The BuildModule taskdef makes some assumptions about the naming, 
-position, and contents of module directories and files.  
-Understand those (documented in 
-<a href="src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java">
-   BuildModule.java</a>) before using non-standard module directories. 
+The build version is set in 
+<a href="build-properties.xml">build-properties.xml</a> and tracked in
+<a href="../bridge/src/org/aspectj/bridge/Version.java">
+         ../bridge/src/org/aspectj/bridge/Version.java</a>
+which the <a href="build.xml">build.xml</a> <code>init-version</code> task
+generates from a template 
+<a href="lib/BridgeVersion.java.txt">lib/BridgeVersion.java.txt</a>
+using copy filters to set the build version and date.
+To avoid updating <code>Version.java</code> whenever 
+<code>build-properties.xml</code> changes, a task
+<a href="src/org/aspectj/internal/tools/ant/taskdefs/VersionUptodate.java">
+         src/org/aspectj/internal/tools/ant/taskdefs/VersionUptodate.java</a>
+determines whether Version.java has the same version by scanning the source file.
+(Do not change the lines flagged in the template without also
+changing the scanning code in the task.)
 
+<p>
 <hr>
 
 </body>
index 0aaaac8800859fca675152505582c348e9284699..06b2f1738df539f042557018a7965a131c891fc6 100644 (file)
@@ -16,7 +16,6 @@ import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Target;
 import org.apache.tools.ant.Task;
 import org.apache.tools.ant.taskdefs.Copy;
-import org.apache.tools.ant.taskdefs.Filter;
 import org.apache.tools.ant.taskdefs.Javac;
 import org.apache.tools.ant.taskdefs.Zip;
 import org.apache.tools.ant.types.FileSet;
@@ -34,11 +33,9 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Properties;
 
 /**
  * Implement Builder in Ant.
@@ -116,6 +113,7 @@ public class AntBuilder extends Builder {
     }
 
     protected final Project project;
+    protected boolean filterSetup;
 
     protected AntBuilder(Project project, File tempDir, boolean useEclipseCompiles,
         Messager handler) {
@@ -123,6 +121,7 @@ public class AntBuilder extends Builder {
         this.project = project;
         Util.iaxIfNull(project, "project");
     }
+    
     protected boolean copyFile(File fromFile, File toFile, boolean filter) {
         Copy copy = makeCopyTask(filter);
         copy.setFile(fromFile);
@@ -131,58 +130,54 @@ public class AntBuilder extends Builder {
         return true;
     }
     
+    /**
+      * @see org.aspectj.internal.tools.ant.taskdefs.Builder#copyFiles(File, File, String, String, boolean)
+      */
+    protected boolean copyFiles(
+         File fromDir,
+         File toDir,
+         String includes,
+         String excludes,
+         boolean filter) {
+         Copy copy = makeCopyTask(filter);
+         copy.setTodir(toDir);
+         FileSet fileset = new FileSet();
+         fileset.setDir(fromDir);
+         if (null != includes) {
+             fileset.setIncludes(includes);
+         }
+         if (null != excludes) {
+             fileset.setExcludes(excludes);
+         }
+         copy.addFileset(fileset);
+         executeTask(copy);
+        
+         return false;
+     }
+    
     protected void copyFileset(File toDir, FileSet fileSet, boolean filter) {
         Copy copy = makeCopyTask(filter);
         copy.addFileset(fileSet);
         copy.setTodir(toDir);
         executeTask(copy);
     }
-
+    
     /** filter if FILTER_ON, use filters */
     protected Copy makeCopyTask(boolean filter) {
         Copy copy = new Copy();
         copy.setProject(project);
         if (FILTER_ON == filter) {
             copy.setFiltering(true);
-            setupFilters(); 
         }
         return copy;
     }
-    
-    /** lazily and manually generate properties */
-    protected Properties getFilterProperties() { // 
-        if (filterProps == null) {
-            long time = System.currentTimeMillis();
-            String version = null; // unknown - system?
-            filterProps = BuildSpec.getFilterProperties(time, version);
-        }
-        return filterProps;
-    }
-        
-    protected void setupFilters() {
-        if (!filterSetup) { // XXX check Ant - is this static?
-            Properties props = getFilterProperties();
-            for (Enumeration enum = props.keys(); enum.hasMoreElements();) {
-                String token = (String) enum.nextElement();
-                String value = props.getProperty(token);
-                Filter filter = new Filter();
-                filter.setProject(project);
-                filter.setToken(token);
-                filter.setValue(value);
-                if (!executeTask(filter)) {
-                    return;
-                }
-            }
-            filterSetup = true;
-        }
-    }
-    
+
     protected boolean compile(Module module, File classesDir, List errors) {
         // XXX  test whether build.compiler property takes effect automatically
         // I suspect it requires the proper adapter setup.
-        Javac javac = new Javac();
+        Javac javac = new Javac(); 
         javac.setProject(project);
-        
+        javac.setTaskName("javac");     
         // -- source paths
         Path path = new Path(project);
         for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) {
@@ -274,16 +269,16 @@ public class AntBuilder extends Builder {
                 zipfileset.setProject(project);
                 zipfileset.setSrc(mergeJar);
                 zipfileset.setIncludes("**/*");
-                zipfileset.setExcludes("META-INF/*"); // XXXFileLiteral
-                zipfileset.setExcludes("meta-inf/*");
+                zipfileset.setExcludes("META-INF/manifest.mf"); // XXXFileLiteral
+                zipfileset.setExcludes("meta-inf/manifest.MF");
+                zipfileset.setExcludes("META-INF/MANIFEST.mf"); 
+                zipfileset.setExcludes("meta-inf/MANIFEST.MF");
                 zip.addZipfileset(zipfileset);
             }
         }
         // merge classes; put any meta-inf/manifest.mf here
         File metaInfDir = new File(classesDir, "META-INF");
-        if (metaInfDir.canWrite()) {
-            Util.deleteContents(metaInfDir); // XXX only delete manifest
-        } 
+        Util.deleteContents(metaInfDir);
 
         // -- manifest
         File manifest = new File(module.moduleDir, module.name + ".mf.txt");  // XXXFileLiteral
@@ -408,31 +403,6 @@ public class AntBuilder extends Builder {
                return false;
        }
     
-    /**
-        * @see org.aspectj.internal.tools.ant.taskdefs.Builder#copyFiles(File, File, String, String, boolean)
-        */
-       protected boolean copyFiles(
-               File fromDir,
-               File toDir,
-               String includes,
-               String excludes,
-               boolean filter) {
-        Copy copy = makeCopyTask(filter);
-        copy.setTodir(toDir);
-        FileSet fileset = new FileSet();
-        fileset.setDir(fromDir);
-        if (null != includes) {
-            fileset.setIncludes(includes);
-        }
-        if (null != excludes) {
-            fileset.setExcludes(excludes);
-        }
-        copy.addFileset(fileset);
-        executeTask(copy);
-        
-               return false;
-       }
-    
     /** task.execute() and any advice */
     protected boolean executeTask(Task task) {
         if (!buildingEnabled) {
index 5853559c9b699be48d600c1671dc3e878d7b8c21..9e29b81384dc2b992228a16297eae82ac7a8bddb 100644 (file)
@@ -47,7 +47,6 @@ public class BuildModule extends Task { // quickie hack...
 
     public BuildModule() {
         buildSpec = new BuildSpec();
-        buildSpec.version = BuildSpec.BUILD_VERSION_DEFAULT;
     }
     
     public void setModuledir(Path moduleDir) {
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/VersionUptodate.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/VersionUptodate.java
new file mode 100644 (file)
index 0000000..a2ac09f
--- /dev/null
@@ -0,0 +1,145 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Common Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/cpl-v10.html 
+ *  
+ * Contributors: 
+ *     Xerox/PARC     initial implementation 
+ * ******************************************************************/
+
+package org.aspectj.internal.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/** 
+ * Check if version source file has the specified build version,
+ * and ensure a tag file reflects whether it does or not.
+ */
+public class VersionUptodate extends Task {
+    public VersionUptodate() {}
+
+    private String buildVersion;
+    private File versionSource;
+    private File versionTagFile;
+    
+    /** 
+     * @param buildVersion String expected as Version.text - required
+     */
+    public void setVersion(String buildVersion) {
+        this.buildVersion = buildVersion;
+    }
+
+    /** 
+     * @param versionSource the File Version.java containing text constant 
+     * - required
+     */
+    public void setVersionSourceFile(File versionSource) {
+        this.versionSource = versionSource;
+    }
+    
+    /** 
+     * @param versionTagFile the File whose existence signals that the version
+     * is uptodate after this task executes - required.
+     */
+    public void setVersionTagFile(File versionTagFile) {
+        this.versionTagFile = versionTagFile;
+    }
+    
+    /**
+     * If the Version.java source file contains the correct
+     * build version, then create the output tag file,
+     * else delete it if it exists.
+     * @throws BuildException if tagFile not creatable and version is incorrect
+     *          or if version is correct and tagFile cannot be deleted.
+     */
+    public void execute() throws BuildException {
+        if (null == buildVersion) {
+            throw new BuildException("require buildVersion");
+        }
+        if ((null == versionSource) || !versionSource.canRead()){
+            throw new BuildException("require versionSource");
+        }
+        if (null == versionTagFile){
+            throw new BuildException("require versionTagFile");
+        }
+        if (sameVersion(versionSource, buildVersion)) {
+            if (!versionTagFile.exists()) {
+                createFile(versionTagFile, buildVersion);
+            }
+        } else if (null == versionTagFile) {
+            throw new BuildException("no tag file, and version out of date");
+        } else if (versionTagFile.exists()) {
+            if (!versionTagFile.delete()) {
+                throw new BuildException("version out of date, but cannot delete " + versionTagFile);
+            }
+        }
+    }
+    
+       /**
+        * Detect whether version is correct in Java sources.
+     * @param versionSource
+        * @param buildVersion
+        * @return boolean
+        */
+       private boolean sameVersion(File versionSource, String buildVersion) {
+        // XXX build and load instead of scanning?
+        FileReader fileReader = null;
+        try {
+            fileReader = new FileReader(versionSource);
+            BufferedReader reader = new BufferedReader(fileReader);
+            String line;
+            while (null != (line = reader.readLine())) {
+                int loc = line.indexOf("static final String text = ");
+                if (-1 != loc) {
+                    return (-1 != line.indexOf(buildVersion , loc));
+                }
+            }
+            return false;
+        } catch (IOException e) {
+            return false;
+        } finally {
+            if (null != fileReader) {
+                try {
+                    fileReader.close();
+                } catch (IOException e) {
+                }
+            }
+        }        
+       }
+    
+    /**
+     * Create file with contents
+     */
+    private void createFile(File versionTagFile, String contents) {
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(versionTagFile);
+            char[] buf = new char[contents.length()];
+            contents.getChars(0, buf.length, buf, 0);
+            writer.write(contents);
+        } catch (IOException e) {
+            throw new BuildException("writing " + versionTagFile, e);
+        } finally {
+            if (null != writer) {
+                try {
+                    writer.close();
+                } catch (IOException e){
+                    // ignore
+                }
+            }
+        }
+    }
+    
+} 
+
index 37da66e9e28ae64935d84dfa302ead1e61618582..884077a8573b8a7c4e81fe418bc18f99651b06cc 100644 (file)
@@ -1,6 +1,7 @@
 ajinstaller=org.aspectj.internal.tools.ant.taskdefs.AJInstaller
 ajpush=org.aspectj.internal.tools.ant.taskdefs.AJPush
 ajbuild=org.aspectj.internal.tools.ant.taskdefs.BuildModule
+versionuptodate=org.aspectj.internal.tools.ant.taskdefs.VersionUptodate
 checklics=org.aspectj.internal.tools.ant.taskdefs.Checklics
 stripnonbodyhtml=org.aspectj.internal.tools.ant.taskdefs.StripNonBodyHtml
 
index f40ff6b06111467759732a075946fdd8c2aaf27b..f5b53c72bc6813d28a6f99b49ab0944d56abe171 100644 (file)
@@ -17,7 +17,10 @@ package org.aspectj.internal.tools.build;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 import java.util.Properties;
 
 /** 
@@ -27,107 +30,124 @@ import java.util.Properties;
  * Static state has much of the Ant build properties (move?)
  */
 public class BuildSpec {
-    public static final String baseDir_NAME = "aspectj.modules.dir";
-    public static final String stagingDir_NAME = "aj.staging.dir";
-    public static final String jarDir_NAME = "aj.jar.dir";
-    public static final String tempDir_NAME = "aj.temp.dir";
-    public static final String distDir_NAME = "aj.dist.dir";
-    
-    /** name of a system property for reading the build version */
-    public static final String SYSTEM_BUILD_VERSION_KEY = "aspectj.build.version";
-
-    /** value of the build.version if build version not defined */
-    public static final String BUILD_VERSION_DEFAULT = "DEVELOPMENT";
-
-    /** name of a filter property for the normal build version */
-    public static final String BUILD_VERSION_NAME = "build.version";
-
-    /** name of a filter property for the company */
-    public static final String COMPANY_NAME = "company.name";
-
-    /** default value of of a filter property for the company */
-    public static final String COMPANY_NAME_DEFAULT = "aspectj.org";
-
-    /** name of a filter property for the base build version (no alpha, etc.) */
-    public static final String BUILD_VERSION_BASE_NAME = "build.version.base";
-
-    /** copyright property name */
-    public static final String COPYRIGHT_NAME = "copyright.allRights.from1998";
-
-    /** overall copyright */
-    public static final String COPYRIGHT =
-       "Copyright (c) 1998-2001 Xerox Corporation, "
-       + "2002 Palo Alto Research Center, Incorporated. All rights reserved.";
-
-    /** name of a filter property for the long build version (alpha) */
-    public static final String BUILD_VERSION_LONG_NAME = "build.version.long";
-
-    /** name of a filter property for the short build version (alpha -> a, etc.) */
-    public static final String BUILD_VERSION_SHORT_NAME = "build.version.short";
-
-    /** name of a filter property for the build time */
-    public static final String BUILD_TIME_NAME = "build.time";
-
-    /** name of a filter property for the build date */
-    public static final String BUILD_DATE_NAME = "build.date";
-    
-    /** lazily and manually generate properties */
-    public static Properties getFilterProperties(long time, String longVersion) {
-        if (time < 1) {
-            time = System.currentTimeMillis();
-        }  
-        if ((null == longVersion) || (0 == longVersion.length())) {
-            longVersion = System.getProperty(
-                        BuildSpec.SYSTEM_BUILD_VERSION_KEY, 
-                        BuildSpec.BUILD_VERSION_DEFAULT);
-        }
-        Properties filterProps = new Properties();
-
-        // build time and date  XXX set in build script?
-        String timeString = time+"L";
-        // XXX wrong date format - use Version.java template format?
-        String date = new SimpleDateFormat("MMMM d, yyyy").format(new Date());
-        filterProps.setProperty(BUILD_TIME_NAME, timeString);
-        filterProps.setProperty(BUILD_DATE_NAME, date);
-
-        // build version, short build version, and base build version 
-        // 1.1alpha1,     1.1a1,               and 1.1
-        String key = BuildSpec.BUILD_VERSION_NAME;
-        String value = longVersion;
-        value = value.trim();
-        filterProps.setProperty(key, value);
-        
-        key = BuildSpec.BUILD_VERSION_LONG_NAME;
-        filterProps.setProperty(key, value);
-
-        if (!BuildSpec.BUILD_VERSION_DEFAULT.equals(value)) {
-            value = Util.shortVersion(value);
-        }
-        key = BuildSpec.BUILD_VERSION_SHORT_NAME;
-        filterProps.setProperty(key, value);
-
-        key = BuildSpec.BUILD_VERSION_BASE_NAME;
-        if (!BuildSpec.BUILD_VERSION_DEFAULT.equals(value)) {
-            int MAX = value.length();
-            for (int i = 0; i < MAX; i++) {
-                char c = value.charAt(i);
-                if ((c != '.') && ((c < '0') || (c > '9'))) {
-                    value = value.substring(0,i);
-                    break;
-                }
-            }
-        }
-        filterProps.setProperty(key, value);
-
-        // company name, copyright XXX fix company name
-        key = BuildSpec.COMPANY_NAME;
-        value = System.getProperty(key, BuildSpec.COMPANY_NAME_DEFAULT);
-        filterProps.setProperty(key, value);
-        filterProps.setProperty(BuildSpec.COPYRIGHT_NAME, BuildSpec.COPYRIGHT);
-        
-        return filterProps;
-    }
+    public static final String DEFAULT_VERSION = "DEVELOPMENT";
+//    public static final String baseDir_NAME = "aspectj.modules.dir";
+//    public static final String stagingDir_NAME = "aj.staging.dir";
+//    public static final String jarDir_NAME = "aj.jar.dir";
+//    public static final String tempDir_NAME = "aj.temp.dir";
+//    public static final String distDir_NAME = "aj.dist.dir";
     
+//    /** name of a system property for reading the build version */
+//    public static final String SYSTEM_BUILD_VERSION_KEY = "aspectj.build.version";
+//
+//    /** value of the build.version if build version not defined */
+//    public static final String BUILD_VERSION_DEFAULT = "DEVELOPMENT";
+//
+//    /** name of a filter property for the normal build version */
+//    public static final String BUILD_VERSION_NAME = "build.version";
+//
+//    /** name of a filter property for the company */
+//    public static final String COMPANY_NAME = "company.name";
+//
+//    /** default value of of a filter property for the company */
+//    public static final String COMPANY_NAME_DEFAULT = "aspectj.org";
+//
+//    /** name of a filter property for the base build version (no alpha, etc.) */
+//    public static final String BUILD_VERSION_BASE_NAME = "build.version.base";
+//
+//    /** copyright property name */
+//    public static final String COPYRIGHT_NAME = "copyright.allRights.from1998";
+//
+//    /** overall copyright */
+//    public static final String COPYRIGHT =
+//       "Copyright (c) 1998-2001 Xerox Corporation, "
+//       + "2002 Palo Alto Research Center, Incorporated. All rights reserved.";
+//
+//    /** name of a filter property for the long build version (alpha) */
+//    public static final String BUILD_VERSION_LONG_NAME = "build.version.long";
+//
+//    /** name of a filter property for the short build version (alpha -> a, etc.) */
+//    public static final String BUILD_VERSION_SHORT_NAME = "build.version.short";
+//
+//    /** name of a filter property for the build time */
+//    public static final String BUILD_TIME_NAME = "build.time";
+//
+//    /** name of a filter property for the build date */
+//    public static final String BUILD_DATE_NAME = "build.date";
+//    
+//    /* default value of build date format by convention tracks 
+//     * build-properties.xml build.date.format.
+//     */
+//    public static final String BUILD_DATE_FORMAT = "EEEE MMM d, yyyy"; 
+//    
+//    /** unmodifiable List of String keys to build properties */
+//    public static final List PROPERTY_NAMES;
+//    static {
+//        String[] names = new String[]
+//            { BUILD_VERSION_NAME, COMPANY_NAME, BUILD_VERSION_BASE_NAME,
+//                COPYRIGHT_NAME, BUILD_VERSION_LONG_NAME, 
+//                BUILD_VERSION_SHORT_NAME, BUILD_TIME_NAME,
+//                BUILD_DATE_NAME
+//            };
+//        PROPERTY_NAMES = Collections.unmodifiableList(Arrays.asList(names));
+//    }
+//    
+//    /** lazily and manually generate properties */
+//    public static Properties getBuildProperties(long time, String longVersion) {
+//        if (time < 1) {
+//            time = System.currentTimeMillis();
+//        }  
+//        if ((null == longVersion) || (0 == longVersion.length())) {
+//            longVersion = System.getProperty(
+//                        BuildSpec.SYSTEM_BUILD_VERSION_KEY, 
+//                        BuildSpec.BUILD_VERSION_DEFAULT);
+//        }
+//        Properties filterProps = new Properties();
+//
+//        // build time and date  XXX set in build script?
+//        String timeString = time+"L";
+//        String date = new SimpleDateFormat("MMMM d, yyyy").format(new Date());
+//        filterProps.setProperty(BUILD_TIME_NAME, timeString);
+//        filterProps.setProperty(BUILD_DATE_NAME, date);
+//
+//        // build version, short build version, and base build version 
+//        // 1.1alpha1,     1.1a1,               and 1.1
+//        String key = BuildSpec.BUILD_VERSION_NAME;
+//        String value = longVersion;
+//        value = value.trim();
+//        filterProps.setProperty(key, value);
+//        
+//        key = BuildSpec.BUILD_VERSION_LONG_NAME;
+//        filterProps.setProperty(key, value);
+//
+//        if (!BuildSpec.BUILD_VERSION_DEFAULT.equals(value)) {
+//            value = Util.shortVersion(value);
+//        }
+//        key = BuildSpec.BUILD_VERSION_SHORT_NAME;
+//        filterProps.setProperty(key, value);
+//
+//        key = BuildSpec.BUILD_VERSION_BASE_NAME;
+//        if (!BuildSpec.BUILD_VERSION_DEFAULT.equals(value)) {
+//            int MAX = value.length();
+//            for (int i = 0; i < MAX; i++) {
+//                char c = value.charAt(i);
+//                if ((c != '.') && ((c < '0') || (c > '9'))) {
+//                    value = value.substring(0,i);
+//                    break;
+//                }
+//            }
+//        }
+//        filterProps.setProperty(key, value);
+//
+//        // company name, copyright XXX fix company name
+//        key = BuildSpec.COMPANY_NAME;
+//        value = System.getProperty(key, BuildSpec.COMPANY_NAME_DEFAULT);
+//        filterProps.setProperty(key, value);
+//        filterProps.setProperty(BuildSpec.COPYRIGHT_NAME, BuildSpec.COPYRIGHT);
+//        
+//        return filterProps;
+//    }
+//    
     // shared
     public File baseDir;
     public File moduleDir;
@@ -141,6 +161,7 @@ public class BuildSpec {
     public boolean assembleAll;
     public boolean failonerror;
     public boolean verbose;
+    private Properties buildProperties;
 
     // building products
     public File productDir;
@@ -149,6 +170,38 @@ public class BuildSpec {
     
     // building modules
     public String module;
+    public BuildSpec() {
+        version = DEFAULT_VERSION;
+    }
+    
+//    /**
+//     * Generate and cache build properties.
+//     * @return Properties
+//     */
+//    public Properties getBuildProperties() {
+//        if (null == buildProperties) {
+//            long time = System.currentTimeMillis();
+//            buildProperties = BuildSpec.getBuildProperties(time, version);
+//        } else if (null != version) { // check if version is out of sync
+//            String versionValue = buildProperties.getProperty(BUILD_VERSION_NAME);
+//            if (!version.equals(versionValue)) {
+//                // XXX ok, now what - reset? alert?
+//            }
+//        }
+//        return buildProperties;
+//    }
+    
+    public boolean isProduct() {
+        return (Util.canReadDir(productDir));
+    }
+
+    public boolean isModule() {
+        return (!isProduct() && Util.canReadDir(moduleDir));
+    }
+
+    public boolean isValid() {
+        return (isProduct() || isModule());
+    }
     
     public String toString() { // XXX better
         if (null != productDir) {
index 19c2ecb4bb27a846e8a4736fc16c07851702306e..9798ce3201c28ac004be41bae337f4eb838a5e0f 100644 (file)
@@ -11,7 +11,6 @@
  *     Xerox/PARC     initial implementation 
  * ******************************************************************/
 
 package org.aspectj.internal.tools.build;
 
 import org.apache.tools.ant.BuildException;
@@ -74,424 +73,495 @@ import java.util.Properties;
  * Written to compile standalone.  Refactor if using utils, bridge, etc.
  */
 public abstract class Builder {
-    
-    /**
-     *  This has only weak forms for build instructions needed:
-     * - resource pattern
-     * - compiler selection and control
-     * 
-     * Both assumed and generated paths are scattered;
-     * see XXXNameLiteral and XXXFileLiteral.
-     */
-    
-    public static final String RESOURCE_PATTERN
-        = "**/*.txt,**/*.rsc,**/*.gif,**/*.properties";
-
-    public static final String BINARY_SOURCE_PATTERN
-        = "**/*.rsc,**/*.gif,**/*.jar,**/*.zip";
-        
-    public static final String ALL_PATTERN = "**/*"; 
-
-    /** enable copy filter semantics */
-    protected static final boolean FILTER_ON = true;
-    
-    /** disable copy filter semantics */
-    protected static final boolean FILTER_OFF = false;
-        
-    protected final Messager handler;
-    protected boolean buildingEnabled;    
-
-    private final File tempDir;
-    private final ArrayList tempFiles;
-    private final boolean useEclipseCompiles;
-
-    protected boolean verbose;
-    protected Properties filterProps;
-    protected boolean filterSetup;
-
-    
-    protected Builder(File tempDir, boolean useEclipseCompiles,
-        Messager handler) {
-        Util.iaxIfNull(handler, "handler");
-        this.useEclipseCompiles = useEclipseCompiles;
-        this.handler = handler;
-        this.tempFiles = new ArrayList();
-        if ((null == tempDir) || !tempDir.canWrite() || !tempDir.isDirectory()) {
-            this.tempDir = Util.makeTempDir("Builder");
-        } else {
-            this.tempDir = tempDir;
-        }
-        buildingEnabled = true;
-    }
-            
-    /** tell builder to stop or that it's ok to run */
-    public void setBuildingEnabled(boolean enabled) {
-        buildingEnabled = enabled;
-        // XXX support user cancels in eclipse...
-    }
-
-    public void setVerbose(boolean verbose) {
-        this.verbose = verbose;
-    }
-    
-    public boolean build(BuildSpec buildSpec) {
-        if (!buildingEnabled) {
-            return false;
-        }
-        
-        if (null == buildSpec.productDir) { // ensure module properties
-            // derive moduleDir from baseDir + module
-            if (null == buildSpec.moduleDir) { 
-                if (null == buildSpec.baseDir) {
-                    throw new BuildException("require baseDir or moduleDir");
-                } else if (null == buildSpec.module) {
-                    throw new BuildException("require module with baseDir");
-                } else {
-                    if (null == buildSpec.baseDir) {
-                       buildSpec.baseDir  = new File("."); // user.home?
-                    }
-                    buildSpec.moduleDir = new File(buildSpec.baseDir, buildSpec.module);
-                }
-            } else if (null == buildSpec.baseDir) { // derive baseDir from moduleDir parent
-                buildSpec.baseDir = buildSpec.moduleDir.getParentFile();  // rule: base is parent
-                if (null == buildSpec.baseDir) {
-                    buildSpec.baseDir = new File("."); // user.home?
-                }
-            }
-            Util.iaxIfNotCanReadDir(buildSpec.moduleDir, "moduleDir");
-            
-            if (null == buildSpec.module) {              // derive module name from directory
-                buildSpec.module = buildSpec.moduleDir.getName();
-                if (null == buildSpec.module) {
-                    throw new BuildException("no name, even from " + buildSpec.moduleDir);
-                }
-            }
-        }
-        
-        if (null != buildSpec.productDir) {
-            return buildProduct(buildSpec);
-        }
-        if (buildSpec.trimTesting && (-1 != buildSpec.module.indexOf("testing"))) {  // XXXNameLiteral
-            String warning = "Warning - cannot trimTesting for testing modules: ";
-            handler.log(warning + buildSpec.module);
-        }
-        Messager handler = new Messager();
-        Modules modules = new Modules(buildSpec.baseDir, buildSpec.jarDir, buildSpec.trimTesting, handler);
-                           
-        final Module moduleToBuild = modules.getModule(buildSpec.module);
-        ArrayList errors = new ArrayList();
-        try {
-            return buildAll(
-                moduleToBuild, 
-                errors, 
-                buildSpec.rebuild, 
-                buildSpec.assembleAll);
-        } finally {
-            if (0 < errors.size()) {
-                String label = "error building " + buildSpec + ": ";
-                for (Iterator iter = errors.iterator(); iter.hasNext();) {
-                    handler.error(label + iter.next());
-                }
-            }
-        }
-    }
-    
-    /**
-     * Clean up any temporary files, etc. after build completes
-     */
-    public boolean cleanup() {
-        boolean noErr = true;
-        for (ListIterator iter = tempFiles.listIterator(); iter.hasNext();) {
+
+       /**
+        *  This has only weak forms for build instructions needed:
+        * - resource pattern
+        * - compiler selection and control
+        * 
+        * Both assumed and generated paths are scattered;
+        * see XXXNameLiteral and XXXFileLiteral.
+        * 
+        * Builder is supposed to be thread-safe, but currently caches build
+        * properties to tunnel for filters. hmm.
+        */
+
+       public static final String RESOURCE_PATTERN =
+               "**/*.txt,**/*.rsc,**/*.gif,**/*.properties";
+
+       public static final String BINARY_SOURCE_PATTERN =
+               "**/*.rsc,**/*.gif,**/*.jar,**/*.zip";
+
+       public static final String ALL_PATTERN = "**/*";
+
+       /** enable copy filter semantics */
+       protected static final boolean FILTER_ON = true;
+
+       /** disable copy filter semantics */
+       protected static final boolean FILTER_OFF = false;
+
+       protected final Messager handler;
+       protected boolean buildingEnabled;
+
+       private final File tempDir;
+       private final ArrayList tempFiles;
+       private final boolean useEclipseCompiles;
+
+       protected boolean verbose;
+
+       protected Builder(
+               File tempDir,
+               boolean useEclipseCompiles,
+               Messager handler) {
+               Util.iaxIfNull(handler, "handler");
+               this.useEclipseCompiles = useEclipseCompiles;
+               this.handler = handler;
+               this.tempFiles = new ArrayList();
+               if ((null == tempDir)
+                       || !tempDir.canWrite()
+                       || !tempDir.isDirectory()) {
+                       this.tempDir = Util.makeTempDir("Builder");
+               } else {
+                       this.tempDir = tempDir;
+               }
+               buildingEnabled = true;
+       }
+
+       /** tell builder to stop or that it's ok to run */
+       public void setBuildingEnabled(boolean enabled) {
+               buildingEnabled = enabled;
+       }
+
+       public void setVerbose(boolean verbose) {
+               this.verbose = verbose;
+       }
+
+       public boolean build(BuildSpec buildSpec) {
+               if (!buildingEnabled) {
+                       return false;
+               }
+               if (null == buildSpec.productDir) { // ensure module properties
+                       // derive moduleDir from baseDir + module
+                       if (null == buildSpec.moduleDir) {
+                               if (null == buildSpec.baseDir) {
+                                       throw new BuildException("require baseDir or moduleDir");
+                               } else if (null == buildSpec.module) {
+                                       throw new BuildException("require module with baseDir");
+                               } else {
+                                       if (null == buildSpec.baseDir) {
+                                               buildSpec.baseDir = new File("."); // user.home?
+                                       }
+                                       buildSpec.moduleDir =
+                                               new File(buildSpec.baseDir, buildSpec.module);
+                               }
+                       } else if (null == buildSpec.baseDir) {
+                               // derive baseDir from moduleDir parent
+                               buildSpec.baseDir = buildSpec.moduleDir.getParentFile();
+                               // rule: base is parent
+                               if (null == buildSpec.baseDir) {
+                                       buildSpec.baseDir = new File("."); // user.home?
+                               }
+                handler.log("Builder using derived baseDir: " 
+                            + buildSpec.baseDir);
+                       }
+                       Util.iaxIfNotCanReadDir(buildSpec.moduleDir, "moduleDir");
+
+                       if (null == buildSpec.module) {
+                               // derive module name from directory
+                               buildSpec.module = buildSpec.moduleDir.getName();
+                               if (null == buildSpec.module) {
+                                       throw new BuildException(
+                                               "no name, even from " + buildSpec.moduleDir);
+                               }
+                       }
+               }
+
+               if (null != buildSpec.productDir) {
+                       return buildProduct(buildSpec);
+               }
+               if (buildSpec.trimTesting
+                       && (-1 != buildSpec.module.indexOf("testing"))) { // XXXNameLiteral
+                       String warning =
+                               "Warning - cannot trimTesting for testing modules: ";
+                       handler.log(warning + buildSpec.module);
+               }
+               Messager handler = new Messager();
+               Modules modules =
+                       new Modules(
+                               buildSpec.baseDir,
+                               buildSpec.jarDir,
+                               buildSpec.trimTesting,
+                               handler);
+
+               final Module moduleToBuild = modules.getModule(buildSpec.module);
+               ArrayList errors = new ArrayList();
+               try {
+                       return buildAll(
+                               moduleToBuild,
+                               errors,
+                               buildSpec.rebuild,
+                               buildSpec.assembleAll);
+               } finally {
+                       if (0 < errors.size()) {
+                               String label = "error building " + buildSpec + ": ";
+                               for (Iterator iter = errors.iterator(); iter.hasNext();) {
+                                       handler.error(label + iter.next());
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Clean up any temporary files, etc. after build completes
+        */
+       public boolean cleanup() {
+               boolean noErr = true;
+               for (ListIterator iter = tempFiles.listIterator();
+                       iter.hasNext();
+                       ) {
                        File file = (File) iter.next();
-            if (!Util.deleteContents(file) || !file.delete()) {
-                if (noErr) {
-                    noErr = false;
-                }
-                handler.log("unable to clean up " + file);
-            }                  
+                       if (!Util.deleteContents(file) || !file.delete()) {
+                               if (noErr) {
+                                       noErr = false;
+                               }
+                               handler.log("unable to clean up " + file);
+                       }
                }
-        return noErr;
-    }
-
-    /**
-     * Build a module with all antecedants.
-     * @param module the Module to build
-     * @param errors the List sink for errors, if any
-     * @return false after successful build, when module jar should exist
-     */
-    protected boolean buildAll(Module module, List errors, boolean rebuild, boolean assembleAll) {
-        String[] buildList = getAntecedantModuleNames(module, rebuild);
-        if ((null != buildList) && (0 < buildList.length)) {
-            final Modules modules = module.getModules();
-            final Messager handler = this.handler;
-            final boolean log = (verbose && (null != handler));
-            final boolean verbose = this.verbose;
-            if (log) {
-                handler.log("modules to build: " + Arrays.asList(buildList));
-            }
-            for (int i = 0; i < buildList.length; i++) {
-                
-                if (!buildingEnabled) {
-                    return false;
-                }
-                String modName = buildList[i];
-                if (log) {
-                    handler.log("building " + modName);
-                }
-                Module next = modules.getModule(modName);
-                if (!buildOnly(next, errors)) {
-                    return false;
-                }
-            }
-        }
-        if (assembleAll && !assembleAll(module, handler)) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Build a module but no antecedants.
-     * @param module the Module to build
-     * @param errors the List sink for errors, if any
-     * @return false after successful build, when module jar should exist
-     */
-    protected boolean buildOnly(Module module, List errors) {
-        if (!buildingEnabled) {
-            return false;
-        }
-        File classesDir = useEclipseCompiles 
-            ? new File(module.moduleDir, "bin")  // XXXFileLiteral
-            : new File(tempDir, "classes-" + System.currentTimeMillis()); 
-        if (verbose) {
-            handler.log("buildOnly " + module);
-        }
-        try {
-            return (useEclipseCompiles || compile(module, classesDir, errors)) 
-                    && assemble(module, classesDir, errors);
-        } finally {
-            if (!useEclipseCompiles
-                && (!Util.deleteContents(classesDir) || !classesDir.delete())) {
-                errors.add("unable to delete " + classesDir);
-            }
-        }
-    }
-    
-    /**
-     * Register temporary file or directory to be deleted when
-     * the build is complete, even if an Exception is thrown.
-     */
-    protected void addTempFile(File tempFile) {
-        if (null != tempFile) {
-            tempFiles.add(tempFile);
-        }
-    }
-    /**
-     * Build product by discovering any modules to build,
-     * building those, assembling the product distribution,
-     * and optionally creating an installer for it.
-     * @return true on success
-     */
-    protected boolean buildProduct(BuildSpec buildSpec) 
-        throws BuildException {
-        Util.iaxIfNull(buildSpec, "buildSpec");
-        // XXX if installer and not out of date, do not rebuild unless rebuild set
-
-        if (!buildSpec.trimTesting) {
-            buildSpec.trimTesting = true;
-            handler.log("testing trimmed for " + buildSpec);
-        }
-        Util.iaxIfNotCanReadDir(buildSpec.productDir, "productDir");
-        Util.iaxIfNotCanReadDir(buildSpec.baseDir, "baseDir");
-        Util.iaxIfNotCanWriteDir(buildSpec.distDir, "distDir");
-
-        // ---- discover modules to build, and build them
-        Modules modules = new Modules(
-            buildSpec.baseDir, 
-            buildSpec.jarDir, 
-            buildSpec.trimTesting, 
-            handler);
-        ProductModule[] productModules = discoverModules(buildSpec.productDir, modules);
-        for (int i = 0; i < productModules.length; i++) {
-            if (buildSpec.verbose) {
-                handler.log("building product module " + productModules[i]); 
-            }
-            if (!buildProductModule(productModules[i])) {
-                return false;
-            }
-        }
-        if (buildSpec.verbose) {
-            handler.log("assembling product module for " + buildSpec); 
-        }
-        
-        // ---- assemble product distribution
-        final String productName = buildSpec.productDir.getName();
-        final File targDir = new File(buildSpec.distDir, productName);
-        final String targDirPath = targDir.getPath();
-        if (targDir.canWrite()) {
-            Util.deleteContents(targDir);
-        }
-        
-        if (!targDir.canWrite() && !targDir.mkdirs()) {
-            if (buildSpec.verbose) {
-                handler.log("unable to create " + targDir);
-            }
-            return false;
-        }
-        // filter-copy everything but the binaries
-        File distDir = new File(buildSpec.productDir, "dist");       // XXXFileLiteral
-        String excludes = Builder.BINARY_SOURCE_PATTERN;
-        String includes = Builder.ALL_PATTERN;
-        if (!copyFiles(distDir, targDir, includes, excludes, FILTER_ON)) {
-            return false;
-        }
-        
-        // copy binaries (but not module flag files)       
-        excludes = null;
-        {
-            StringBuffer buf = new StringBuffer();        
-            for (int i = 0; i < productModules.length; i++) {
-                if (0 < buf.length()) {
-                    buf.append(",");
-                }
-                buf.append(productModules[i].relativePath);
-            }
-            if (0 < buf.length()) {
-                excludes = buf.toString();
-            }
-        }
-        includes = Builder.BINARY_SOURCE_PATTERN;
-        if (!copyFiles(distDir, targDir, includes, excludes, FILTER_OFF)) {
-            return false;
-        }
-
-        // copy binaries associated with module flag files
-        for (int i = 0; i < productModules.length; i++) {
-            ProductModule product = productModules[i];
-            String targPath = targDirPath + "/" + product.relativePath;
-            File jarFile = (product.assembleAll 
-                ? product.module.getAssembledJar()
-                : product.module.getModuleJar() );
-            copyFile(jarFile, new File(targPath), FILTER_OFF);
-        } 
-        handler.log("created product in " + targDir);
-
-        // ---- create installer 
-        if (buildSpec.createInstaller) {
-            return buildInstaller(buildSpec, targDirPath);
-        } else {
-            return true;
-        }
-    }
-    
-    protected boolean buildProductModule(ProductModule module) {
-        boolean noRebuild = false;
-        ArrayList errors = new ArrayList();
-        try {
-            return buildAll(module.module, errors, noRebuild,  module.assembleAll);
-        } finally {
-            for (Iterator iter = errors.iterator(); iter.hasNext();) {
-                handler.error("error building " + module + ": " + iter.next());                
-            }
-        }
-    }
-    
-    /**
-     * Discover any modules that might need to be built
-     * in order to assemble the product distribution.
-     * This interprets empty .jar files as module deliverables.
-     */
-    protected ProductModule[] discoverModules(File productDir, Modules modules) {
-        final ArrayList found = new ArrayList();
-        FileFilter filter = new FileFilter() {
-            public boolean accept(File file) {
-                if ((null != file) 
-                    && file.canRead()
-                    && file.getPath().endsWith(".jar")   // XXXFileLiteral
-                    && (0l == file.length())) {
-                    found.add(file);
-                }
-                return true;
-            }
-        };
-        Util.visitFiles(productDir, filter);
-        ArrayList results = new ArrayList();
-        for (Iterator iter = found.iterator(); iter.hasNext();) {
-            File file = (File) iter.next();
-            String jarName = moduleAliasFor(file.getName().toLowerCase());
-            if (jarName.endsWith(".jar") || jarName.endsWith(".zip")) {   // XXXFileLiteral
-                jarName = jarName.substring(0, jarName.length()-4);
-            } else {
-                handler.log("can only replace .[jar|zip]: " + file); // XXX error?
-            }
-            boolean assembleAll = jarName.endsWith("-all");  // XXXFileLiteral
-            String name = (!assembleAll ? jarName : jarName.substring(0, jarName.length()-4));
-            Module module = modules.getModule(name);
-            if (null == module) {
-                handler.log("unable to find module for " + file);
-            } else {
-                results.add(new ProductModule(productDir, file, module, assembleAll));
-            }
-        }
-        return (ProductModule[]) results.toArray(new ProductModule[0]);
-    }
-
-    /**
-     * Map delivered-jar name to created-module name
-     * @param jarName the String (lowercased) of the jar/zip to map
-     */
-    protected String moduleAliasFor(String jarName) {
-        if ("aspectjtools.jar".equals(jarName)) {    // XXXFileLiteral
-            return "ajbrowser-all.jar";
-        } else if ("aspectjrt.jar".equals(jarName)) {
-            return "runtime.jar";
-        } else {
-            return jarName;
-        }
-    }
-    
-    /** 
-     * @return String[] names of modules to build for this module
-     */
-    abstract protected String[] getAntecedantModuleNames(Module toBuild, boolean rebuild);
-
-    /**
-     * Compile module classes to classesDir, saving String errors.
-     */
-    abstract protected boolean compile(Module module, File classesDir, List errors);
-
-    /**
-     * Assemble the module distribution from the classesDir, saving String errors.
-     */
-    abstract protected boolean assemble(Module module, File classesDir, List errors);
-
-    /**
-     * Assemble the module distribution from the classesDir and all antecendants, 
-     * saving String errors.
-     */
-    abstract protected boolean assembleAll(Module module, Messager handler);
-
-    /**
-     * Generate the installer for this product to targDirPath
-     */
-    abstract protected boolean buildInstaller(BuildSpec buildSpec, String targDirPath);
-
-    /** 
-     * Copy fromFile to toFile, optionally filtering contents
-     */
-    abstract protected boolean copyFile(File fromFile, File toFile, boolean filter);
-    
-    /** 
-     * Copy toDir any fromDir included files without any exluded files, 
-     * optionally filtering contents.
-     * @param fromDir File dir to read from - error if not readable
-     * @param toDir File dir to write to - error if not writable
-     * @param included String Ant pattern of included files (if null, include all)
-     * @param excluded String Ant pattern of excluded files (if null, exclude none)
-     * @param filter if FILTER_ON, then filter file contents using global token/value pairs
-     */
-    abstract protected boolean copyFiles(File fromDir, File toDir, String included, String excluded, boolean filter);
-}
-        
+               return noErr;
+       }
+
+       /**
+        * Build a module with all antecedants.
+        * @param module the Module to build
+        * @param errors the List sink for errors, if any
+        * @return false after successful build, when module jar should exist
+        */
+       protected boolean buildAll(
+               Module module,
+               List errors,
+               boolean rebuild,
+               boolean assembleAll) {
+               String[] buildList = getAntecedantModuleNames(module, rebuild);
+               if ((null != buildList) && (0 < buildList.length)) {
+                       final Modules modules = module.getModules();
+                       final Messager handler = this.handler;
+                       final boolean log = (verbose && (null != handler));
+                       final boolean verbose = this.verbose;
+                       if (log) {
+                               handler.log(
+                                       "modules to build: " + Arrays.asList(buildList));
+                       }
+                       for (int i = 0; i < buildList.length; i++) {
+
+                               if (!buildingEnabled) {
+                                       return false;
+                               }
+                               String modName = buildList[i];
+                               if (log) {
+                                       handler.log("building " + modName);
+                               }
+                               Module next = modules.getModule(modName);
+                               if (!buildOnly(next, errors)) {
+                                       return false;
+                               }
+                       }
+               }
+               if (assembleAll && !assembleAll(module, handler)) {
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * Build a module but no antecedants.
+        * @param module the Module to build
+        * @param errors the List sink for errors, if any
+        * @return false after successful build, when module jar should exist
+        */
+       protected boolean buildOnly(Module module, List errors) {
+               if (!buildingEnabled) {
+                       return false;
+               }
+                       File classesDir =
+                               useEclipseCompiles
+                                       ? new File(module.moduleDir, "bin") // FileLiteral
+       : new File(tempDir, "classes-" + System.currentTimeMillis());
+               if (verbose) {
+                       handler.log("buildOnly " + module);
+               }
+               try {
+                       return (
+                               useEclipseCompiles || compile(module, classesDir, errors))
+                               && assemble(module, classesDir, errors);
+               } finally {
+                       if (!useEclipseCompiles
+                               && (!Util.deleteContents(classesDir)
+                                       || !classesDir.delete())) {
+                               errors.add("unable to delete " + classesDir);
+                       }
+               }
+       }
 
+       /**
+        * Register temporary file or directory to be deleted when
+        * the build is complete, even if an Exception is thrown.
+        */
+       protected void addTempFile(File tempFile) {
+               if (null != tempFile) {
+                       tempFiles.add(tempFile);
+               }
+       }
+       /**
+        * Build product by discovering any modules to build,
+        * building those, assembling the product distribution,
+        * and optionally creating an installer for it.
+        * @return true on success
+        */
+       protected boolean buildProduct(BuildSpec buildSpec)
+               throws BuildException {
+               Util.iaxIfNull(buildSpec, "buildSpec");
+               // XXX if installer and not out of date, do not rebuild unless rebuild set
+
+               if (!buildSpec.trimTesting) {
+                       buildSpec.trimTesting = true;
+                       handler.log("testing trimmed for " + buildSpec);
+               }
+               Util.iaxIfNotCanReadDir(buildSpec.productDir, "productDir");
+               Util.iaxIfNotCanReadDir(buildSpec.baseDir, "baseDir");
+               Util.iaxIfNotCanWriteDir(buildSpec.distDir, "distDir");
+
+               // ---- discover modules to build, and build them
+               Modules modules =
+                       new Modules(
+                               buildSpec.baseDir,
+                               buildSpec.jarDir,
+                               buildSpec.trimTesting,
+                               handler);
+               ProductModule[] productModules =
+                       discoverModules(buildSpec.productDir, modules);
+               for (int i = 0; i < productModules.length; i++) {
+                       if (buildSpec.verbose) {
+                               handler.log(
+                                       "building product module " + productModules[i]);
+                       }
+                       if (!buildProductModule(productModules[i])) {
+                               return false;
+                       }
+               }
+               if (buildSpec.verbose) {
+                       handler.log("assembling product module for " + buildSpec);
+               }
+
+               // ---- assemble product distribution
+               final String productName = buildSpec.productDir.getName();
+               final File targDir = new File(buildSpec.distDir, productName);
+               final String targDirPath = targDir.getPath();
+               if (targDir.canWrite()) {
+                       Util.deleteContents(targDir);
+               }
+
+               if (!targDir.canWrite() && !targDir.mkdirs()) {
+                       if (buildSpec.verbose) {
+                               handler.log("unable to create " + targDir);
+                       }
+                       return false;
+               }
+               // filter-copy everything but the binaries
+               File distDir = new File(buildSpec.productDir, "dist");
+               // XXXFileLiteral
+               String excludes = Builder.BINARY_SOURCE_PATTERN;
+               String includes = Builder.ALL_PATTERN;
+               if (!copyFiles(distDir, targDir, includes, excludes, FILTER_ON)) {
+                       return false;
+               }
+
+               // copy binaries (but not module flag files)       
+               excludes = null;
+               {
+                       StringBuffer buf = new StringBuffer();
+                       for (int i = 0; i < productModules.length; i++) {
+                               if (0 < buf.length()) {
+                                       buf.append(",");
+                               }
+                               buf.append(productModules[i].relativePath);
+                       }
+                       if (0 < buf.length()) {
+                               excludes = buf.toString();
+                       }
+               }
+               includes = Builder.BINARY_SOURCE_PATTERN;
+               if (!copyFiles(distDir,
+                       targDir,
+                       includes,
+                       excludes,
+                       FILTER_OFF)) {
+                       return false;
+               }
+
+               // copy binaries associated with module flag files
+               for (int i = 0; i < productModules.length; i++) {
+                       ProductModule product = productModules[i];
+                       String targPath = targDirPath + "/" + product.relativePath;
+                       File jarFile =
+                               (product.assembleAll
+                                       ? product.module.getAssembledJar()
+                                       : product.module.getModuleJar());
+                       copyFile(jarFile, new File(targPath), FILTER_OFF);
+               }
+               handler.log("created product in " + targDir);
 
+               // ---- create installer 
+               if (buildSpec.createInstaller) {
+                       return buildInstaller(buildSpec, targDirPath);
+               } else {
+                       return true;
+               }
+       }
+
+       protected boolean buildProductModule(ProductModule module) {
+               boolean noRebuild = false;
+               ArrayList errors = new ArrayList();
+               try {
+                       return buildAll(
+                               module.module,
+                               errors,
+                               noRebuild,
+                               module.assembleAll);
+               } finally {
+                       for (Iterator iter = errors.iterator(); iter.hasNext();) {
+                               handler.error(
+                                       "error building " + module + ": " + iter.next());
+                       }
+               }
+       }
+
+       /**
+        * Discover any modules that might need to be built
+        * in order to assemble the product distribution.
+        * This interprets empty .jar files as module deliverables.
+        */
+       protected ProductModule[] discoverModules(
+               File productDir,
+               Modules modules) {
+               final ArrayList found = new ArrayList();
+                       FileFilter filter = new FileFilter() {// empty jar files
+       public boolean accept(File file) {
+                                       if ((null != file)
+                                               && file.canRead()
+                                               && file.getPath().endsWith(
+                                                       ".jar") // XXXFileLiteral
+                                               && (0l == file.length())) {
+                                       found.add(file);
+                               }
+                               return true;
+                       }
+               };
+               Util.visitFiles(productDir, filter);
+               ArrayList results = new ArrayList();
+               for (Iterator iter = found.iterator(); iter.hasNext();) {
+                       File file = (File) iter.next();
+                       String jarName = moduleAliasFor(file.getName().toLowerCase());
+                       if (jarName.endsWith(".jar")
+                               || jarName.endsWith(".zip")) { // XXXFileLiteral
+                               jarName = jarName.substring(0, jarName.length() - 4);
+                       } else {
+                               handler.log("can only replace .[jar|zip]: " + file);
+                               // XXX error?
+                       }
+                       boolean assembleAll = jarName.endsWith("-all");
+                       // XXXFileLiteral
+                       String name =
+                               (!assembleAll
+                                       ? jarName
+                                       : jarName.substring(0, jarName.length() - 4));
+                       Module module = modules.getModule(name);
+                       if (null == module) {
+                               handler.log("unable to find module for " + file);
+                       } else {
+                               results.add(
+                                       new ProductModule(
+                                               productDir,
+                                               file,
+                                               module,
+                                               assembleAll));
+                       }
+               }
+               return (ProductModule[]) results.toArray(new ProductModule[0]);
+       }
+
+       /**
+        * Map delivered-jar name to created-module name
+        * @param jarName the String (lowercased) of the jar/zip to map
+        */
+       protected String moduleAliasFor(String jarName) {
+               if ("aspectjtools.jar".equals(jarName)) { // XXXFileLiteral
+                       return "ajbrowser-all.jar";
+               } else if ("aspectjrt.jar".equals(jarName)) {
+                       return "runtime.jar";
+               } else {
+                       return jarName;
+               }
+       }
+
+       /** 
+        * @return String[] names of modules to build for this module
+        */
+       abstract protected String[] getAntecedantModuleNames(
+               Module toBuild,
+               boolean rebuild);
+
+       /**
+        * Compile module classes to classesDir, saving String errors.
+        */
+       abstract protected boolean compile(
+               Module module,
+               File classesDir,
+               List errors);
+
+       /**
+        * Assemble the module distribution from the classesDir, saving String errors.
+        */
+       abstract protected boolean assemble(
+               Module module,
+               File classesDir,
+               List errors);
+
+       /**
+        * Assemble the module distribution from the classesDir and all antecendants, 
+        * saving String errors.
+        */
+       abstract protected boolean assembleAll(
+               Module module,
+               Messager handler);
+
+       /**
+        * Generate the installer for this product to targDirPath
+        */
+       abstract protected boolean buildInstaller(
+               BuildSpec buildSpec,
+               String targDirPath);
+
+       /** 
+        * Copy fromFile to toFile, optionally filtering contents
+        */
+       abstract protected boolean copyFile(
+               File fromFile,
+               File toFile,
+               boolean filter);
+
+       /** 
+        * Copy toDir any fromDir included files without any exluded files, 
+        * optionally filtering contents.
+        * @param fromDir File dir to read from - error if not readable
+        * @param toDir File dir to write to - error if not writable
+        * @param included String Ant pattern of included files (if null, include all)
+        * @param excluded String Ant pattern of excluded files (if null, exclude none)
+        * @param filter if FILTER_ON, then filter file contents using global token/value pairs
+        */
+       abstract protected boolean copyFiles(
+               File fromDir,
+               File toDir,
+               String included,
+               String excluded,
+               boolean filter);
+}