]> source.dussan.org Git - aspectj.git/commitdiff
Now targeting Module results (release, test, release-all, test-all) rather than modul...
authorwisberg <wisberg>
Thu, 9 Jun 2005 00:11:27 +0000 (00:11 +0000)
committerwisberg <wisberg>
Thu, 9 Jun 2005 00:11:27 +0000 (00:11 +0000)
build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java
build/src/org/aspectj/internal/tools/build/Builder.java
build/src/org/aspectj/internal/tools/build/Module.java
build/src/org/aspectj/internal/tools/build/Modules.java
build/src/org/aspectj/internal/tools/build/Result.java [new file with mode: 0644]

index 0288f1f20fca3c22de8dd3775e9f8a1fcf1675c2..d7bd8436d28ee8825ead695d5af1f49ee71c956c 100644 (file)
@@ -40,18 +40,14 @@ import org.aspectj.internal.tools.build.BuildSpec;
 import org.aspectj.internal.tools.build.Builder;
 import org.aspectj.internal.tools.build.Messager;
 import org.aspectj.internal.tools.build.Module;
-import org.aspectj.internal.tools.build.Modules;
-import org.aspectj.internal.tools.build.ProductModule;
+import org.aspectj.internal.tools.build.Result;
 import org.aspectj.internal.tools.build.Util;
+import org.aspectj.internal.tools.build.Result.Kind;
 
 /**
  * Implement Builder in Ant.
  */
 public class AntBuilder extends Builder {
-    /*
-     * warning: This just constructs and uses Ant Task objects, 
-     * which in some cases causes the tasks to fail.
-     */
 
     /**
      * Factory for a Builder.
@@ -72,7 +68,7 @@ public class AntBuilder extends Builder {
                 verbose = true;
             }
         }
-        Messager handler = new ProjectMessager(project);
+        Messager handler = new Messager(); // TODO new ProjectMessager(project);
         Builder result = new ProductBuilder(project, tempDir, useEclipseCompiles, handler);
         if (verbose) {
             result.setVerbose(true);
@@ -80,51 +76,89 @@ public class AntBuilder extends Builder {
         return result;
     }
     
+    private static String resultToTargetName(Result result) {
+        return result.getName();
+    }
     /** 
-     * Make and register target for this module and antecedants.
-     * This ensures that the (direct) depends list is generated
-     * for each target.
-     * This depends on topoSort to detect cycles. XXX unverified
+     * Ensure targets exist for this module and all antecedants,
+     * so topoSort can work.
      */
-    private static void makeTargetsForModule(
-        final Module module
-        final Hashtable targets, 
-        final boolean rebuild) {
-        Target target = (Target) targets.get(module.name);
-        if (null == target) {
-            // first add the target
-            target = new Target();
-            target.setName(module.name);
-            List req = module.getRequired();
-            StringBuffer depends = new StringBuffer();
-            boolean first = true;
-            for (Iterator iterator = req.iterator(); iterator.hasNext();) {
-                Module reqModule = (Module) iterator.next();
-                if (rebuild || reqModule.outOfDate(false)) {
+    private static void makeTargetsForResult(
+            final Result result
+            final Hashtable targets) {
+            final String resultTargetName = resultToTargetName(result);
+            Target target = (Target) targets.get(resultTargetName);
+            if (null == target) {
+                // first add the target
+                target = new Target();
+                target.setName(resultTargetName);
+                
+                Result[] reqs = result.getRequired();
+                StringBuffer depends = new StringBuffer();
+                boolean first = true;
+                for (int i = 0; i < reqs.length; i++) {
+                    Result reqResult = reqs[i];
                     if (!first) {
                         depends.append(",");
                     } else {
                         first = false;
                     }
-                    depends.append(reqModule.name);
+                    depends.append(resultToTargetName(reqResult));
                 }
-            }
-            if (0 < depends.length()) {
-                target.setDepends(depends.toString());
-            }
-            targets.put(module.name, target);
+                if (0 < depends.length()) {
+                    target.setDepends(depends.toString());
+                }
+                targets.put(resultTargetName, target);
 
-            // then recursively add any required modules
-            for (Iterator iterator = module.getRequired().iterator();
-                iterator.hasNext();
-                ) {
-                Module reqModule = (Module) iterator.next();
-                if (rebuild || reqModule.outOfDate(false)) {
-                    makeTargetsForModule(reqModule, targets, rebuild);
-                }                
-            }                        
+                // then recursively add any required results
+                for (int i = 0; i < reqs.length; i++) {
+                    Result reqResult = reqs[i];
+                    makeTargetsForResult(reqResult, targets);
+                }                        
+            }
         }
-    }
+//    private static void edited_makeTargetsForResult(
+//            final Result result, 
+//            final Hashtable targets, 
+//            final boolean rebuild) {
+//            String resultTargetName = result.getOutputFile().getName();
+//            Target target = (Target) targets.get(resultTargetName);
+//            if (null == target) {
+//                // first add the target
+//                target = new Target();
+//                target.setName(resultTargetName);
+//                Kind kind = result.getKind();
+//                Module module = result.getModule();
+//                Kind compileKind = Result.kind(module.isNormal(), !Result.ASSEMBLE);
+//                Result compileResult = module.getResult(compileKind);
+//                Result[] req = compileResult.getRequired();
+//                StringBuffer depends = new StringBuffer();
+//                boolean first = true;
+//                for (int i = 0; i < req.length; i++) {
+//                    Result reqResult = req[i];
+//                    if (!first) {
+//                        depends.append(",");
+//                    } else {
+//                        first = false;
+//                    }
+//                    depends.append(reqResult.name);
+//                }
+//                if (0 < depends.length()) {
+//                    target.setDepends(depends.toString());
+//                }
+//                targets.put(module.name, target);
+//
+//                // then recursively add any required modules
+//                for (Iterator iterator = compileResult.getRequired().iterator();
+//                    iterator.hasNext();
+//                    ) {
+//                    Module reqModule = (Module) iterator.next();
+//                    if (rebuild || reqModule.outOfDate(kind, false)) {
+//                        makeTargetsForResult(reqModule, targets, rebuild, kind);
+//                    }                
+//                }                        
+//            }
+//        }
 
     private final Project project;
 
@@ -208,18 +242,43 @@ public class AntBuilder extends Builder {
         }
         return copy;
     }
-
+    protected void dumpMinFile(Result result,File classesDir, List errors) {
+        String name = result.getName() + "-empty";
+        File minFile = new File(classesDir, name);
+        FileWriter fw = null;
+        try {
+            fw = new FileWriter(minFile);
+            fw.write(name);
+        } catch (IOException e) {
+            errors.add("IOException writing " 
+                + name
+                + " to "
+                + minFile
+                + ": "
+                + Util.renderException(e));
+        } finally {
+            Util.close(fw);
+        }
+        
+    }
     protected boolean compile(
-        Module module
+        Result result
         File classesDir,
         boolean useExistingClasses, 
         List errors) {
         
+        if (!classesDir.exists() && !classesDir.mkdirs()) {
+            errors.add("compile - unable to create " + classesDir);
+            return false;
+        }
+        if (useExistingClasses) {
+            return true;
+        }
         // -- source paths
         Path path = new Path(project);
         boolean hasSourceDirectories = false;
         boolean isJava5Compile = false;
-        for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) {
+        for (Iterator iter = result.getSrcDirs().iterator(); iter.hasNext();) {
             File file = (File) iter.next();
             path.createPathElement().setLocation(file);
             if (!isJava5Compile 
@@ -231,31 +290,9 @@ public class AntBuilder extends Builder {
                 hasSourceDirectories = true;
             }
         }
-        if (!classesDir.exists() && !classesDir.mkdirs()) {
-            errors.add("compile - unable to create " + classesDir);
-            return false;
-        }
-        if (!hasSourceDirectories) { // none - dump minimal file and exit
-            File minFile = new File(classesDir, module.name);
-            FileWriter fw = null;
-            try {
-                fw = new FileWriter(minFile);
-                fw.write(module.name);
-            } catch (IOException e) {
-                errors.add("IOException writing " 
-                    + module.name
-                    + " to "
-                    + minFile
-                    + ": "
-                    + Util.renderException(e));
-            } finally {
-                Util.close(fw);
-            }
+        if (!hasSourceDirectories) { 
             return true; // nothing to compile - ok
         }
-        if (useExistingClasses) {
-            return true;
-        }
         // XXX  test whether build.compiler property takes effect automatically
         // I suspect it requires the proper adapter setup.
         Javac javac = new Javac(); 
@@ -268,18 +305,19 @@ public class AntBuilder extends Builder {
         
         // -- classpath
         Path classpath = new Path(project);
-        boolean hasLibraries = setupClasspath(module, classpath);
+        boolean hasLibraries = setupClasspath(result, classpath);
         // need to add system classes??
-        boolean inEclipse = true; // XXX detect, fork only in eclipse
-        if (hasLibraries && inEclipse) {
-            javac.setFork(true); // XXX otherwise never releases library jars
-        }
+//        boolean inEclipse = true; // XXX detect, fork only in eclipse
+//        if (hasLibraries && inEclipse) { // if fork, on compiler failure, no report
+//            javac.setFork(true); // TODO XXX otherwise never releases library jars
+//        }
         // also fork if using 1.5?
         // can we build under 1.4, but fork javac 1.5 compile?
         
         // -- set output directory
         classpath.createPathElement().setLocation(classesDir);
         javac.setClasspath(classpath);
+
         // misc
         javac.setDebug(true);
         if (!isJava5Compile) {
@@ -293,7 +331,7 @@ public class AntBuilder extends Builder {
         boolean passed = false;
         BuildException failure = null;
         try {
-            passed = executeTask(AspectJSupport.wrapIfNeeded(module, javac));
+            passed = executeTask(AspectJSupport.wrapIfNeeded(result, javac));
         } catch (BuildException e) {
             failure = e;
         } catch (Error e) {
@@ -301,36 +339,43 @@ public class AntBuilder extends Builder {
         } catch (RuntimeException e) {
             failure = new BuildException(e);
         } finally {
+            if (!passed) {
+                String args = "" + Arrays.asList(javac.getCurrentCompilerArgs());
+                if ("[]".equals(args)) {
+                    args = "{" + result.toLongString() + "}";
+                }
+                String m = "BuildException compiling " + result.toLongString() + args 
+                    + (null == failure? "" : ": " + Util.renderException(failure));
+                //debuglog System.err.println(m);
+                errors.add(m);
+            }
             javac.init(); // be nice to let go of classpath libraries...
         }
-        if (!passed) {
-            String args = "" + Arrays.asList(javac.getCurrentCompilerArgs());
-            errors.add("BuildException compiling " + module.toLongString() + args 
-                + (null == failure? "" : ": " + Util.renderException(failure)));
-        }
         return passed;
     }
     
-    public boolean setupClasspath(Module module, Path classpath) { // XXX fix test access
+    public boolean setupClasspath(Result result, Path classpath) { // XXX fix test access
         boolean hasLibraries = false;
         // required libraries
-        for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) {
+        for (Iterator iter = result.getLibJars().iterator(); iter.hasNext();) {
             File file = (File) iter.next();            
             classpath.createPathElement().setLocation(file);
             if (!hasLibraries) {
                 hasLibraries = true;
             }
         }
+        Kind kind = result.getKind();
+        Result[] reqs = result.getRequired();
         // required modules and their exported libraries
-        for (Iterator iter = module.getRequired().iterator(); iter.hasNext();) {
-            Module required = (Module) iter.next();            
-            classpath.createPathElement().setLocation(required.getModuleJar());
+        for (int i = 0; i < reqs.length; i++) {
+            Result requiredResult = reqs[i];
+            classpath.createPathElement().setLocation(requiredResult.getOutputFile());
             if (!hasLibraries) {
                 hasLibraries = true;
             }
             // also put on classpath libraries exported from required module
             // XXX exported modules not supported
-            for (Iterator iterator = required.getExportedLibJars().iterator();
+            for (Iterator iterator = requiredResult.getExportedLibJars().iterator();
                 iterator.hasNext();
                 ) {
                 classpath.createPathElement().setLocation((File) iterator.next());
@@ -344,18 +389,19 @@ public class AntBuilder extends Builder {
      * with any specified manifest file.  
      * META-INF directories are excluded.
      */
-    protected boolean assemble(Module module, File classesDir, List errors) {
+    protected boolean assemble(Result result, File classesDir, List errors) {
         if (!buildingEnabled) {
             return false;
         }
+
         // ---- zip result up
         Zip zip = new Zip();
         setupTask(zip, "zip");
-        zip.setDestFile(module.getModuleJar());
+        zip.setDestFile(result.getOutputFile());
         ZipFileSet zipfileset = null;
         
         // -- merge any resources in any of the src directories
-        for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) {
+        for (Iterator iter = result.getSrcDirs().iterator(); iter.hasNext();) {
             File srcDir = (File) iter.next();
             zipfileset = new ZipFileSet();
             zipfileset.setProject(project);
@@ -364,25 +410,27 @@ public class AntBuilder extends Builder {
             zip.addZipfileset(zipfileset);
         }
         
+        final Module module = result.getModule();
         // -- merge any merge jars
-        List mergeJars =  module.getMerges();
-        removeLibraryFilesToSkip(module, mergeJars);
-//        final boolean useManifest = false;
-        if (0 < mergeJars.size()) {
-            for (Iterator iter = mergeJars.iterator(); iter.hasNext();) {
-                File mergeJar = (File) iter.next();
-                zipfileset = new ZipFileSet();
-                zipfileset.setProject(project);
-                zipfileset.setSrc(mergeJar);
-                zipfileset.setIncludes("**/*");
-                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
+//      TODO removing-merges
+//        List mergeJars =  result.getMerges();
+//        removeLibraryFilesToSkip(module, mergeJars);
+////        final boolean useManifest = false;
+//        if (0 < mergeJars.size()) {
+//            for (Iterator iter = mergeJars.iterator(); iter.hasNext();) {
+//                File mergeJar = (File) iter.next();
+//                zipfileset = new ZipFileSet();
+//                zipfileset.setProject(project);
+//                zipfileset.setSrc(mergeJar);
+//                zipfileset.setIncludes("**/*");
+//                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");
         Util.deleteContents(metaInfDir);
 
@@ -403,32 +451,38 @@ public class AntBuilder extends Builder {
         zipfileset.setDir(classesDir);
         zipfileset.setIncludes("**/*");
         zip.addZipfileset(zipfileset);
+        File[] contents = classesDir.listFiles();
+        if ((null == contents) || (0 == contents.length)) {
+            // *something* to zip up
+            dumpMinFile(result, classesDir,errors);
+        }
 
         try {
-            handler.log("assembling " + module  + " in " + module.getModuleJar());
+            handler.log("assembling " + module  + " in " + result.getOutputFile());
             return executeTask(zip)
                 // zip returns true when it doesn't create zipfile
                 // because there are no entries to add, so verify done
-                && Util.canReadFile(module.getModuleJar());
+                && Util.canReadFile(result.getOutputFile());
         } catch (BuildException e) {
             errors.add("BuildException zipping " + module + ": " + e.getMessage());
             return false;
         } finally {
-            module.clearOutOfDate();
+            result.clearOutOfDate();
         }
     }
     /**
         * @see org.aspectj.internal.tools.build.Builder#buildAntecedants(Module)
         */
-       protected String[] getAntecedantModuleNames(Module module, boolean rebuild) {
+       protected Result[] getAntecedantResults(Result moduleResult) {
         Hashtable targets = new Hashtable();
-        makeTargetsForModule(module, targets, rebuild);   
-        // XXX bug: doc says topoSort returns String, but returns Target 
-        Collection result = project.topoSort(module.name, targets);
-        // XXX is it topoSort that should detect cycles?
+        makeTargetsForResult(moduleResult, targets);   
+        String targetName = resultToTargetName(moduleResult);
+        // bug: doc says topoSort returns String, but returns Target 
+        Collection result = project.topoSort(targetName, targets);
+        // fyi, we don't rely on topoSort to detect cycles - see buildAll
         int size = result.size();
         if (0 == result.size()) {
-            return new String[0];
+            return new Result[0];
         }
         ArrayList toReturn = new ArrayList();
         for (Iterator iter = result.iterator(); iter.hasNext();) {
@@ -440,35 +494,36 @@ public class AntBuilder extends Builder {
                 toReturn.add(name);
             }
         }
-        // topoSort always returns module.name    
+        // topoSort always returns target name    
         if ((1 == size) 
-            && module.name.equals(toReturn.get(0))
-            && !module.outOfDate(false)) {
-            return new String[0];
+            && targetName.equals(toReturn.get(0))
+            && !moduleResult.outOfDate(false)) {
+            return new Result[0];
         }
-        return (String[]) toReturn.toArray(new String[0]);
+        return Result.getResults((String[]) toReturn.toArray(new String[0]));
     }
         
     /**
      * Generate Module.assembledJar with merge of itself and all antecedants
      */                    
-    protected boolean assembleAll(Module module, Messager handler) {
+    protected boolean assembleAll(Result result, Messager handler) {
+        //System.out.println("assembling " + result);
         if (!buildingEnabled) {
             return false;
         }
-        Util.iaxIfNull(module, "module");
+        Util.iaxIfNull(result, "result");
         Util.iaxIfNull(handler, "handler");
-        if (module.outOfDate(false)) {
-            throw new IllegalStateException("module out of date: " + module);
+        if (!result.getKind().isAssembly()) {
+            throw new IllegalStateException("not assembly: " + result);
         }
         
         // ---- zip result up
         Zip zip = new Zip();
         setupTask(zip, "zip");
-        zip.setDestFile(module.getAssembledJar());
+        zip.setDestFile(result.getOutputFile());
         ZipFileSet zipfileset = null;
-        
-        List known = module.findKnownJarAntecedants();
+        final Module module = result.getModule();
+        List known = result.findKnownJarAntecedants();
         removeLibraryFilesToSkip(module, known);
         // -- merge any antecedents, less any manifest
         for (Iterator iter = known.iterator(); iter.hasNext();) {
@@ -487,11 +542,14 @@ public class AntBuilder extends Builder {
         // merge the module jar itself, including same manifest (?)
         zipfileset = new ZipFileSet();
         zipfileset.setProject(project);
-        zipfileset.setSrc(module.getModuleJar());
+        Kind normal = Result.kind(result.getKind().isNormal(), !Result.ASSEMBLE);
+        File src = module.getResult(normal).getOutputFile();
+        zipfileset.setSrc(src);
         zip.addZipfileset(zipfileset);
 
         try {
-            handler.log("assembling all " + module  + " in " + module.getAssembledJar());
+            handler.log("assembling all " + module
+                    + " in " + result.getOutputFile());
             if (verbose) {
                    handler.log("knownAntecedants: " + known);
             }
@@ -500,7 +558,7 @@ public class AntBuilder extends Builder {
             handler.logException("BuildException zipping " + module, e);
             return false;
         } finally {
-            module.clearOutOfDate();
+            result.clearOutOfDate();
         }
     }
 
@@ -543,25 +601,28 @@ public class AntBuilder extends Builder {
          * @param javac the Javac compile commands
          * @return javac or a Task to compile with AspectJ if needed
          */
-        static Task wrapIfNeeded(Module module, Javac javac) {
+        static Task wrapIfNeeded(Result result, Javac javac) {
             final Project project = javac.getProject();
             Path runtimeJar = null;
-            if (runtimeJarOnClasspath(module)) { 
+            final Module module = result.getModule();
+            if (runtimeJarOnClasspath(result)) { 
                 // yes aspectjrt.jar on classpath
-            } else if (module.getClasspathVariables().contains(ASPECTJRT_JAR_VARIABLE)) {
+            } else if (result.getClasspathVariables().contains(ASPECTJRT_JAR_VARIABLE)) {
                 // yes, in variables - find aspectjrt.jar to add to classpath
                 runtimeJar = getAspectJLib(project, module, "aspectjrt.jar");
             } else {
                 // no
+                //System.out.println("javac " + result + " " + javac.getClasspath()); 
                 return javac;
             }
+            //System.out.println("aspectj " + result + " " + javac.getClasspath()); 
             Path aspectjtoolsJar = getAspectJLib(project, module, "aspectjtools.jar");
             return aspectJTask(javac, aspectjtoolsJar, runtimeJar);
         }
         
         /** @return true if aspectjrt.jar is on classpath */
-        private static boolean runtimeJarOnClasspath(Module module) {
-            for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) {
+        private static boolean runtimeJarOnClasspath(Result result) {
+            for (Iterator iter = result.getLibJars().iterator(); iter.hasNext();) {
                 File file = (File) iter.next();
                 if ("aspectjrt.jar".equals(file.getName())) {
                     return true;
@@ -741,113 +802,34 @@ class ProductBuilder extends AntBuilder {
     }
     
     /**
-     * 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
+     * Delegate for super.buildProduct(..) template method.
      */
-    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);
+    protected boolean copyBinaries(BuildSpec buildSpec, File distDir, File targDir, String excludes) {
+        Copy copy = makeCopyTask(false);
+        copy.setTodir(targDir);
+        FileSet fileset = new FileSet();
+        fileset.setDir(distDir);
+        fileset.setIncludes(Builder.BINARY_SOURCE_PATTERN);
+        if (null != excludes) {
+            fileset.setExcludes(excludes);
         }
-        Util.iaxIfNotCanReadDir(buildSpec.productDir, "productDir");
-        Util.iaxIfNotCanReadDir(buildSpec.baseDir, "baseDir");
-        Util.iaxIfNotCanWriteDir(buildSpec.distDir, "distDir");
+        copy.addFileset(fileset);
+        return executeTask(copy);
+    }
 
-        // ---- 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("buildProduct unable to create " + targDir);
-            }
-            return false;
-        }
+    /**
+     * Delegate for super.buildProduct(..) template method.
+     */
+    protected boolean copyNonBinaries(BuildSpec buildSpec, File distDir, File targDir) {
         // filter-copy everything but the binaries
         Copy copy = makeCopyTask(true);
         copy.setTodir(targDir);
-        File distDir = new File(buildSpec.productDir, "dist");       // XXXFileLiteral
         Util.iaxIfNotCanReadDir(distDir, "product dist directory");
         FileSet fileset = new FileSet();
         fileset.setDir(distDir);
         fileset.setExcludes(Builder.BINARY_SOURCE_PATTERN);
         copy.addFileset(fileset);
-        if (!executeTask(copy)) {
-            return false;
-        }
-        
-        // copy binaries (but not module flag files)
-        String 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();
-            }
-        }
-        copy = makeCopyTask(false);
-        copy.setTodir(targDir);
-        fileset = new FileSet();
-        fileset.setDir(distDir);
-        fileset.setIncludes(Builder.BINARY_SOURCE_PATTERN);
-        if (null != excludes) {
-            fileset.setExcludes(excludes);
-        }
-        copy.addFileset(fileset);
-        if (!executeTask(copy)) {
-            return false;
-        }
-
-        // copy binaries associated with module flag files
-        for (int i = 0; i < productModules.length; i++) {
-            ProductModule product = productModules[i];
-            String targPath = Util.path(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;
-        }
+        return executeTask(copy);
     }
     
     protected boolean buildInstaller(BuildSpec buildSpec, String targDirPath) {
index b9303ffb8e63ac7d15a18cca80b1a64181431c63..cfac0192da13b1d7cf894b4114d553b2742e746f 100644 (file)
@@ -26,87 +26,88 @@ import java.util.Properties;
 import java.util.StringTokenizer;
 
 import org.apache.tools.ant.BuildException;
+import org.aspectj.internal.tools.build.Result.Kind;
 
 /**
- * Template class to build (eclipse) modules (and, weakly, products),
- * including any required modules.
- * When building modules, this assumes:
+ * Template class to build (eclipse) modules (and, weakly, products), including
+ * any required modules. When building modules, this assumes:
  * <ul>
  * <li>the name of the module is the base name of the module directory</li>
  * <li>all module directories are in the same base (workspace) directory</li>
  * <li>the name of the target module jar is {moduleName}.jar</li>
  * <li>a module directory contains a <code>.classpath</code> file with
- *     (currently line-parseable) entries per Eclipse (XML) conventions</li>
- * <li><code>Builder.RESOURCE_PATTERN</code> 
- *      identifies all resources to copy to output.</li>
+ * (currently line-parseable) entries per Eclipse (XML) conventions</li>
+ * <li><code>Builder.RESOURCE_PATTERN</code> identifies all resources to copy
+ * to output.</li>
  * <li>This can safely trim test-related code:
- *     <ul>
- *     <li>source directories named "testsrc"</li>
- *     <li>libraries named "junit.jar"</li>
- *     <li>required modules whose names start with "testing"</li>
- *     </ul>
- * <li>A file <code>{moduleDir}/{moduleName}.properties</code> 
- *     is a property file possibly
- *     containing entries defining requirements to be merged with the output jar
- *     (deprecated mechanism - use assembleAll or products)</li>
+ * <ul>
+ * <li>source directories named "testsrc"</li>
+ * <li>libraries named "junit.jar"</li>
+ * <li>required modules whose names start with "testing"</li>
+ * </ul>
+ * <li>A file <code>{moduleDir}/{moduleName}.properties</code> is a property
+ * file possibly containing entries defining requirements to be merged with the
+ * output jar (deprecated mechanism - use assembleAll or products)</li>
  * </ul>
- * This currently provides no control over the compile or assembly process, 
- * but clients can harvest <code>{moduleDir}/bin</code> directories to re-use 
- * the results of eclipse compiles.
+ * This currently provides no control over the compile or assembly process, but
+ * clients can harvest <code>{moduleDir}/bin</code> directories to re-use the
+ * results of eclipse compiles.
  * <p>
  * When building products, this assumes:
  * <ul>
  * <li>the installer-resources directory is a peer of the products directory,
- *     itself the parent of the particular product directory.</li>
+ * itself the parent of the particular product directory.</li>
  * <li>the dist, jar, product, and base (module) directory are set</li>
- * <li>the product distribution consists of all (and only) the files 
- *     in the dist sub-directory of the product directory</li> 
+ * <li>the product distribution consists of all (and only) the files in the
+ * dist sub-directory of the product directory</li>
  * <li>files in the dist sub-directory that are empty and end with .jar
- *     represent modules to build, either as named or through aliases
- *     known here.</li>
- * <li>When assembling the distribution, all non-binary files are to 
- *     be filtered.<li>
- * <li>the name of the product installer is aspectj-{productName}-{version}.jar, 
- *     where {productName} is the base name of the product directory</li>
+ * represent modules to build, either as named or through aliases known here.</li>
+ * <li>When assembling the distribution, all non-binary files are to be
+ * filtered.
+ * <li>
+ * <li>the name of the product installer is
+ * aspectj-{productName}-{version}.jar, where {productName} is the base name of
+ * the product directory</li>
  * </ul>
  * <p>
- * When run using main(String[]), all relevant Ant libraries and properties
- * must be defined.
+ * When run using main(String[]), all relevant Ant libraries and properties must
+ * be defined.
  * <p>
- * Written to compile standalone.  Refactor if using utils, bridge, etc.
+ * 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.
-        * 
-        * Builder is supposed to be thread-safe, but currently caches build
-        * properties to tunnel for filters. hmm.
-        */
+    /**
+     * 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;
+    public static final String RESOURCE_PATTERN;
 
-       public static final String BINARY_SOURCE_PATTERN;
+    public static final String BINARY_SOURCE_PATTERN;
 
-       public static final String ALL_PATTERN;
+    public static final String ALL_PATTERN;
 
-       /** enable copy filter semantics */
-       protected static final boolean FILTER_ON = true;
+    /** enable copy filter semantics */
+    protected static final boolean FILTER_ON = true;
 
-       /** disable copy filter semantics */
-       protected static final boolean FILTER_OFF = false;
+    /** disable copy filter semantics */
+    protected static final boolean FILTER_OFF = false;
 
     /** define libraries to skip as comma-delimited values for this key */
     private static final String SKIP_LIBRARIES_KEY = "skip.libraries";
-    
+
     /** List (String) names of libraries to skip during assembly */
     private static final List SKIP_LIBRARIES;
+
     private static final String ERROR_KEY = "error loading properties";
+
     private static final Properties PROPS;
     static {
         PROPS = new Properties();
@@ -116,8 +117,9 @@ public abstract class Builder {
         String binarySourcePattern = "**/*.rsc,**/*.gif,**/*.jar,**/*.zip";
         String name = Builder.class.getName().replace('.', '/') + ".properties";
         try {
-            InputStream in = Builder.class.getClassLoader().getResourceAsStream(name);
-            PROPS.load(in); 
+            InputStream in = Builder.class.getClassLoader()
+                    .getResourceAsStream(name);
+            PROPS.load(in);
             allPattern = PROPS.getProperty("all.pattern");
             resourcePattern = PROPS.getProperty("resource.pattern");
             binarySourcePattern = PROPS.getProperty("binarySource.pattern");
@@ -134,12 +136,13 @@ public abstract class Builder {
         BINARY_SOURCE_PATTERN = binarySourcePattern;
         RESOURCE_PATTERN = resourcePattern;
     }
-    
+
     /**
-     * Splits strings into an unmodifable <code>List</code> of String
-     * using comma as the delimiter and trimming whitespace from the result.
-     *
-     * @param text <code>String</code> to split.
+     * Splits strings into an unmodifable <code>List</code> of String using
+     * comma as the delimiter and trimming whitespace from the result.
+     * 
+     * @param text
+     *            <code>String</code> to split.
      * @return unmodifiable List (String) of String delimited by comma in text
      */
     public static List commaStrings(String text) {
@@ -156,9 +159,12 @@ public abstract class Builder {
         }
         return Collections.unmodifiableList(strings);
     }
+
     /**
      * Map delivered-jar name to created-module name
-     * @param jarName the String (lowercased) of the jar/zip to map
+     * 
+     * @param jarName
+     *            the String (lowercased) of the jar/zip to map
      */
     private String moduleAliasFor(String jarName) {
         String result = PROPS.getProperty("alias." + jarName, jarName);
@@ -168,405 +174,425 @@ public abstract class Builder {
         }
         return result;
     }
-       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);
-                       }
-               }
-               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;
-               }
-               final File classesDir;
+
+    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;
+    }
+
+    private void verifyBuildSpec(BuildSpec buildSpec) {
+        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);
+                }
+            }
+        }
+    }
+
+    /**
+     * Find the Result (and hence Module and Modules) for this BuildSpec.
+     */
+    protected Result specifyResultFor(BuildSpec 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,
+                handler);
+
+        final Module moduleToBuild = modules.getModule(buildSpec.module);
+        Kind kind = Result.kind(buildSpec.trimTesting,
+                buildSpec.assembleAll);
+        return moduleToBuild.getResult(kind);
+    }
+
+    public final boolean build(BuildSpec buildSpec) {
+        if (!buildingEnabled) {
+            return false;
+        }
+        verifyBuildSpec(buildSpec);
+
+        if (null != buildSpec.productDir) {
+            return buildProduct(buildSpec);
+        }
+        Result result = specifyResultFor(buildSpec);
+        ArrayList errors = new ArrayList();
+        try {
+            return buildAll(result, errors);
+        } finally {
+            if (0 < errors.size()) {
+                String label = "error building " + buildSpec + ": ";
+                for (Iterator iter = errors.iterator(); iter.hasNext();) {
+                    String m = label + iter.next();
+                    handler.error(m);
+                }
+            }
+        }
+    }
+
+    /**
+     * 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);
+            }
+        }
+        return noErr;
+    }
+
+    protected Result[] skipUptodate(Result[] results) {
+        if (null == results) {
+            return new Result[0];
+        }
+        Result[] done = new Result[results.length];
+        int to = 0;
+        for (int i = 0; i < done.length; i++) {
+            if ((null != results[i]) && results[i].outOfDate(false)) {
+                done[to++] = results[i];
+            }
+        }
+        if (to < results.length) {
+            Result[] newdone = new Result[to];
+            System.arraycopy(done, 0, newdone, 0, newdone.length);
+            done = newdone;
+        }
+        return done;
+    }
+
+    /**
+     * Build a result with all antecedants.
+     * 
+     * @param result
+     *            the Result to build
+     * @param errors
+     *            the List sink for errors, if any
+     * @return false after successful build, when module jar should exist
+     */
+    protected final boolean buildAll(Result result, List errors) {
+        Result[] buildList = skipUptodate(getAntecedantResults(result));
+        ArrayList doneList = new ArrayList();
+        if ((null != buildList) && (0 < buildList.length)) {
+            final Modules modules = result.getModule().getModules();
+            final Messager handler = this.handler;
+            final boolean log = (verbose && (null != handler));
+            if (log) {
+                handler.log("modules to build: " + Arrays.asList(buildList));
+            }
+            for (int i = 0; i < buildList.length; i++) {
+                Result required = buildList[i];
+                if (!buildingEnabled) {
+                    return false;
+                }
+                String requiredName = required.getName();
+                if (!doneList.contains(requiredName)) {
+                    doneList.add(requiredName);
+                    if (required.outOfDate(false)) {
+                        if (log) {
+                            handler.log("building " + requiredName);
+                        }
+                        if (!buildOnly(required, errors)) {
+                            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 final boolean buildOnly(Result result, List errors) {
+        if (!buildingEnabled) {
+            return false;
+        }
+        if (result.getKind().assemble) {
+            return assembleAll(result, handler);
+        }
+        Module module = result.getModule();
+        final File classesDir;
         if (useEclipseCompiles) {
             classesDir = new File(module.moduleDir, "bin"); // FileLiteral
         } else {
             String name = "classes-" + System.currentTimeMillis();
             classesDir = new File(tempDir, name);
         }
-               if (verbose) {
-                       handler.log("buildOnly " + module);
-               }
-               try {
-                       return (
-                               compile(module, classesDir, useEclipseCompiles, errors))
-                               && assemble(module, classesDir, errors);
-               } finally {
-                       if (!useEclipseCompiles && !Util.delete(classesDir)) {
-                               errors.add("buildOnly 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("buildProduct 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;
-               }
-        // duplicate code?
-               // copy binaries associated with module flag files
-               for (int i = 0; i < productModules.length; i++) {
-                       ProductModule product = productModules[i];
-                       String targPath = Util.path(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]);
-       }
+        if (verbose) {
+            handler.log("buildOnly " + module);
+        }
+        try {
+            return (compile(result, classesDir,useEclipseCompiles, errors))
+                    && assemble(result, classesDir, errors);
+        } finally {
+            if (!useEclipseCompiles && !Util.delete(classesDir)) {
+                errors.add("buildOnly 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 final boolean buildProduct(BuildSpec buildSpec)
+            throws BuildException {
+        Util.iaxIfNull(buildSpec, "buildSpec");
+
+        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,
+                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("buildProduct unable to create " + targDir);
+            }
+            return false;
+        }
+
+        // copy non-binaries (with filter)
+        File distDir = new File(buildSpec.productDir, "dist");
+        if (!copyNonBinaries(buildSpec, distDir, targDir)) {
+            return false;
+        }
+
+        // copy binaries (but not module flag files)
+        String 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();
+            }
+        }
+
+        if (!copyBinaries(buildSpec, distDir, targDir, excludes)) {
+            return false;
+        }
+
+        // copy binaries associated with module flag files
+        for (int i = 0; i < productModules.length; i++) {
+            final ProductModule product = productModules[i];
+            final Kind kind = Result.kind(Result.NORMAL, product.assembleAll);
+            Result result = product.module.getResult(kind);
+            String targPath = Util.path(targDirPath, product.relativePath);
+            File jarFile = result.getOutputFile();
+            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 copyBinaries(BuildSpec buildSpec, File distDir,
+            File targDir, String excludes) {
+        String includes = Builder.BINARY_SOURCE_PATTERN;
+        return copyFiles(distDir, targDir, includes, excludes, FILTER_OFF);
+    }
+
+    /**
+     * filter-copy everything but the binaries
+     */
+    protected boolean copyNonBinaries(BuildSpec buildSpec, File distDir,
+            File targDir) {
+        String excludes = Builder.BINARY_SOURCE_PATTERN;
+        String includes = Builder.ALL_PATTERN;
+        return copyFiles(distDir, targDir, includes, excludes, FILTER_ON);
+    }
+
+    protected final boolean buildProductModule(ProductModule module) {
+        boolean noRebuild = false;
+        ArrayList errors = new ArrayList();
+        try {
+            Kind productKind = Result.kind(Result.NORMAL, Result.ASSEMBLE);
+            Result result = module.module.getResult(productKind);
+            return buildAll(result, errors);
+        } 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]);
+    }
 
     /**
      * Subclasses should query whether to include library files in the assembly.
-     * @param module the Module being built
-     * @param libraries the List of File path to the jar to consider assembling
+     * 
+     * @param module
+     *            the Module being built
+     * @param libraries
+     *            the List of File path to the jar to consider assembling
      * @return true if the jar should be included, false otherwise.
      */
     protected void removeLibraryFilesToSkip(Module module, List libraries) {
         for (ListIterator liter = libraries.listIterator(); liter.hasNext();) {
-            File library= (File) liter.next();
+            File library = (File) liter.next();
             final String fname = library.getName();
             if (null != fname) {
                 for (Iterator iter = SKIP_LIBRARIES.iterator(); iter.hasNext();) {
@@ -579,74 +605,72 @@ public abstract class Builder {
             }
         }
     }
-    
-       /** 
-        * @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.
-     * @param module the Module to compile
-     * @param classesDir the File directory to compile to
-     * @param useExistingClasses if true, don't recompile
-     *        and ensure classes are available
-     * @param errors the List to add error messages to
-        */
-       abstract protected boolean compile(
-               Module module,
-               File classesDir,
-        boolean useExistingClasses,
-               List errors);
-
-       /**
-        * Assemble the module distribution from the classesDir, saving String errors.
+
+    /**
+     * @return String[] names of results to build for this module
+     */
+    abstract protected Result[] getAntecedantResults(Result toBuild);
+
+    /**
+     * Compile module classes to classesDir, saving String errors.
+     * 
+     * @param module
+     *            the Module to compile
+     * @param classesDir
+     *            the File directory to compile to
+     * @param useExistingClasses
+     *            if true, don't recompile and ensure classes are available
+     * @param errors
+     *            the List to add error messages to
+     */
+    abstract protected boolean compile(Result result, File classesDir,
+            boolean useExistingClasses, List errors);
+
+    /**
+     * Assemble the module distribution from the classesDir, saving String
+     * errors.
+     * 
      * @see #removeLibraryFilesToSkip(Module, File)
-        */
-       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 assemble(Result result, File classesDir,
+            List errors);
+
+    /**
+     * Assemble the module distribution from the classesDir and all
+     * antecendants, saving String errors.
+     * 
      * @see #removeLibraryFilesToSkip(Module, File)
-        */
-       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);
+     */
+    abstract protected boolean assembleAll(Result result, 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);
 }
index 8539e6c8c514e818a00ba302c1d1d7b1d3b22c6f..d37b8bed4cd5846cf4eddd3b585371918a798726 100644 (file)
@@ -21,13 +21,15 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Properties;
 import java.util.StringTokenizer;
 
+import org.aspectj.internal.tools.build.Result.Kind;
+
+
 /**
  * This represents an (eclipse) build module/unit used by a Builder to compile
  * classes and/or assemble zip file of classes, optionally with all antecedants.
@@ -97,16 +99,18 @@ public class Module {
      * 
      * @see findKnownJarAntecedants()
      */
-    private static void doFindKnownJarAntecedants(Module module, List known) {
-        Util.iaxIfNull(module, "module");
+     static void doFindKnownJarAntecedants(Result result, List known) {
+        Util.iaxIfNull(result, "result");
         Util.iaxIfNull(known, "known");
-        addIfNew(module.getLibJars(), known);
-        for (Iterator iter = module.getRequired().iterator(); iter.hasNext();) {
-            Module required = (Module) iter.next();
-            File requiredJar = required.getModuleJar();
+        addIfNew(result.getLibJars(), known);
+        addIfNew(result.getExportedLibJars(), known);
+        Result[] reqs = result.getRequired();
+        for (int i = 0; i < reqs.length; i++) {
+            Result requiredResult = reqs[i];
+            File requiredJar = requiredResult.getOutputFile();
             if (!known.contains(requiredJar)) {
                 known.add(requiredJar);
-                doFindKnownJarAntecedants(required, known);
+                doFindKnownJarAntecedants(requiredResult, known);
             }
         }
     }
@@ -117,6 +121,31 @@ public class Module {
         return (path.endsWith(".java") || path.endsWith(".aj")); // XXXFileLiteral
     }
 
+    /** @return List of File of any module or library jar ending with suffix */
+    private static ArrayList findJarsBySuffix(String suffix, Kind kind,
+            List libJars, List required) {
+        ArrayList result = new ArrayList();
+        if (null != suffix) {
+            // library jars
+            for (Iterator iter = libJars.iterator(); iter.hasNext();) {
+                File file = (File) iter.next();
+                if (file.getPath().endsWith(suffix)) {
+                    result.add(file);
+                }
+            }
+            // module jars
+            for (Iterator iter = required.iterator(); iter.hasNext();) {
+                Module module = (Module) iter.next();
+                Result moduleResult = module.getResult(kind);
+                File file = moduleResult.getOutputFile();
+                if (file.getPath().endsWith(suffix)) {
+                    result.add(file);
+                }
+            }
+        }
+        return result;
+    }
+    
     public final boolean valid;
 
     public final File moduleDir;
@@ -124,7 +153,15 @@ public class Module {
     public final String name;
 
     /** reference back to collection for creating required modules */
-    final Modules modules;
+    private final Modules modules;
+
+    private final Result release;
+
+    private final Result test;
+
+    private final Result testAll;
+
+    private final Result releaseAll;
 
     /** path to output jar - may not exist */
     private final File moduleJar;
@@ -151,7 +188,7 @@ public class Module {
     private final Properties properties;
 
     /** Module list of required modules */
-    private final List required;
+    private final List requiredModules;
 
     /** List of File that are newer than moduleJar. Null until requested */
     // private List newerFiles;
@@ -161,23 +198,22 @@ public class Module {
     /** true if we have calculated whether this is out of date */
     private boolean outOfDateSet;
 
-    /** if true, trim testing-related source directories, modules, and libraries */
-    private final boolean trimTesting;
-
     /** logger */
     private final Messager messager;
 
+    private final File jarDir;
+
     Module(File moduleDir, File jarDir, String name, Modules modules,
-            boolean trimTesting, Messager messager) {
+            Messager messager) {
         Util.iaxIfNotCanReadDir(moduleDir, "moduleDir");
         Util.iaxIfNotCanReadDir(jarDir, "jarDir");
         Util.iaxIfNull(name, "name");
         Util.iaxIfNull(modules, "modules");
         this.moduleDir = moduleDir;
-        this.trimTesting = trimTesting;
+        this.jarDir = jarDir;
         this.libJars = new ArrayList();
         this.exportedLibJars = new ArrayList();
-        this.required = new ArrayList();
+        this.requiredModules = new ArrayList();
         this.srcDirs = new ArrayList();
         this.classpathVariables = new ArrayList();
         this.properties = new Properties();
@@ -186,128 +222,65 @@ public class Module {
         this.messager = messager;
         this.moduleJar = new File(jarDir, name + ".jar");
         this.assembledJar = new File(jarDir, name + "-all.jar");
+        this.release = new Result(Result.RELEASE, this, jarDir);
+        this.releaseAll = new Result(Result.RELEASE_ALL, this, jarDir);
+        this.test = new Result(Result.TEST, this, jarDir);
+        this.testAll = new Result(Result.TEST_ALL, this, jarDir);
         valid = init();
     }
 
-    /** @return path to output jar - may not exist */
-    public File getModuleJar() {
-        return moduleJar;
-    }
-
-    /** @return path to output assembled jar - may not exist */
-    public File getAssembledJar() {
-        return assembledJar;
-    }
-
-    /** @return unmodifiable List of String classpath variables */
-    public List getClasspathVariables() {
-        return Collections.unmodifiableList(classpathVariables);
-    }
-
-    /** @return unmodifiable List of required modules String names */
-    public List getRequired() {
-        return Collections.unmodifiableList(required);
-    }
-
-    /** @return unmodifiable list of exported library files, guaranteed readable */
-    public List getExportedLibJars() {
-        return Collections.unmodifiableList(exportedLibJars);
-    }
-
-    /** @return unmodifiable list of required library files, guaranteed readable */
-    public List getLibJars() {
-        return Collections.unmodifiableList(libJars);
-    }
-
-    /** @return unmodifiable list of source directories, guaranteed readable */
-    public List getSrcDirs() {
-        return Collections.unmodifiableList(srcDirs);
-    }
 
     /** @return Modules registry of known modules, including this one */
     public Modules getModules() {
         return modules;
     }
 
-    /** @return List of File jar paths to be merged into module-dist */
-    public List getMerges() {
-        String value = properties.getProperty(name + ".merges");
-        if ((null == value) || (0 == value.length())) {
-            return Collections.EMPTY_LIST;
-        }
-        ArrayList result = new ArrayList();
-        StringTokenizer st = new StringTokenizer(value);
-        while (st.hasMoreTokens()) {
-            result.addAll(findJarsBySuffix(st.nextToken()));
-        }
-        return result;
-    }
-
-    public void clearOutOfDate() {
-        outOfDate = false;
-        outOfDateSet = false;
-    }
-
     /**
+     * @param kind
+     *            the Kind of the result to recalculate
      * @param recalculate
      *            if true, then force recalculation
      * @return true if the target jar for this module is older than any source
      *         files in a source directory or any required modules or any
      *         libraries or if any libraries or required modules are missing
      */
-    public boolean outOfDate(boolean recalculate) {
-        if (recalculate) {
-            outOfDateSet = false;
-        }
-        if (!outOfDateSet) {
-            outOfDate = false;
-            try {
-                if (!(moduleJar.exists() && moduleJar.canRead())) {
-                    return outOfDate = true;
-                }
-                final long time = moduleJar.lastModified();
-                File file;
-                for (Iterator iter = srcDirs.iterator(); iter.hasNext();) {
-                    File srcDir = (File) iter.next();
-                    for (Iterator srcFiles = sourceFiles(srcDir); srcFiles
-                            .hasNext();) {
-                        file = (File) srcFiles.next();
-                        if (outOfDate(time, file)) {
-                            return outOfDate = true;
-                        }
-                    }
-                }
-                // required modules
-                for (Iterator iter = getRequired().iterator(); iter.hasNext();) {
-                    Module required = (Module) iter.next();
-                    file = required.getModuleJar();
-                    if (outOfDate(time, file)) {
-                        return outOfDate = true;
-                    }
-                }
-                // libraries
-                for (Iterator iter = getLibJars().iterator(); iter.hasNext();) {
-                    file = (File) iter.next();
-                    if (outOfDate(time, file)) {
-                        return outOfDate = true;
-                    }
+    public static boolean outOfDate(Result result, boolean recalculate) {
+        File outputFile = result.getOutputFile();
+        if (!(outputFile.exists() && outputFile.canRead())) {
+            return true;
+        }
+        final long time = outputFile.lastModified();
+        File file;
+        for (Iterator iter = result.getSrcDirs().iterator(); iter.hasNext();) {
+            File srcDir = (File) iter.next();
+            for (Iterator srcFiles = sourceFiles(srcDir); srcFiles.hasNext();) {
+                file = (File) srcFiles.next();
+                if (outOfDate(time, file)) {
+                    return true;
                 }
-            } finally {
-                outOfDateSet = true;
             }
         }
-        return outOfDate;
+        // required modules
+        final Kind kind = result.getKind();
+        Result[] reqs = result.getRequired();
+        for (int i = 0; i < reqs.length; i++) {
+            Result requiredResult = reqs[i];
+            file = requiredResult.getOutputFile();
+            if (outOfDate(time, file)) {
+                return true;
+            }
+        }
+        // libraries
+        for (Iterator iter = result.getLibJars().iterator(); iter.hasNext();) {
+            file = (File) iter.next();
+            if (outOfDate(time, file)) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    /**
-     * Add any (File) library jar or (File) required module jar to the List
-     * known, if not added already.
-     */
-    public ArrayList findKnownJarAntecedants() {
-        ArrayList result = new ArrayList();
-        doFindKnownJarAntecedants(this, result);
-        return result;
-    }
+    
 
     public String toString() {
         return name;
@@ -315,12 +288,45 @@ public class Module {
 
     public String toLongString() {
         return "Module [name=" + name + ", srcDirs=" + srcDirs + ", required="
-                + required + ", moduleJar=" + moduleJar + ", libJars="
+                + requiredModules + ", moduleJar=" + moduleJar + ", libJars="
                 + libJars + "]";
     }
 
+    public Result getResult(Kind kind) {
+        return kind.assemble ? (kind.normal ? releaseAll : testAll)
+                : (kind.normal ? release : test);
+    }
+    
+    List srcDirs(Result result) {
+        myResult(result);
+        return srcDirs;
+    }
+    List libJars(Result result) {
+        myResult(result);
+        return libJars;
+    }
+    List classpathVariables(Result result) {
+        myResult(result);
+        return classpathVariables;
+    }
+    List exportedLibJars(Result result) {
+        myResult(result);
+        return exportedLibJars;
+    }
+    List requiredModules(Result result) {
+        myResult(result);
+        return requiredModules;
+    }
+    
+    private void myResult(Result result) {
+        if ((null == result) || this != result.getModule()) {
+            throw new IllegalArgumentException("not my result: " + result + ": " + this);
+        }
+    }
+
     private boolean init() {
-        return initClasspath() && initProperties() && reviewInit();
+        return initClasspath() && initProperties() && reviewInit()
+                && initResults();
     }
 
     /** read eclipse .classpath file XXX line-oriented hack */
@@ -336,7 +342,7 @@ public class Module {
             while (null != (line = reader.readLine())) {
                 line = line.trim();
                 // dumb - only handle comment-only lines
-                if (!line.startsWith("<?xml") && ! line.startsWith("<!--")) {
+                if (!line.startsWith("<?xml") && !line.startsWith("<!--")) {
                     item.acceptLine(line);
                 }
             }
@@ -358,18 +364,19 @@ public class Module {
         String kind = attributes[getATTSIndex("kind")];
         String path = attributes[getATTSIndex("path")];
         String exp = attributes[getATTSIndex("exported")];
-        boolean exported = ("true".equals(exp));                 
+        boolean exported = ("true".equals(exp));
         return update(kind, path, toString, exported);
     }
-    
-    private boolean update(String kind, String path, String toString, boolean exported) {    
+
+    private boolean update(String kind, String path, String toString,
+            boolean exported) {
         String libPath = null;
         if ("src".equals(kind)) {
             if (path.startsWith("/")) { // module
                 String moduleName = path.substring(1);
                 Module req = modules.getModule(moduleName);
                 if (null != req) {
-                    required.add(req);
+                    requiredModules.add(req);
                     return true;
                 } else {
                     messager.error("update unable to create required module: "
@@ -468,13 +475,8 @@ public class Module {
     }
 
     /**
-     * Post-process initialization. This implementation trims testing-related
-     * source directories, libraries, and modules if trimTesting is
-     * enabled/true. For modules whose names start with "testing",
-     * testing-related sources are trimmed, but this does not trim dependencies
-     * on other modules prefixed "testing" or on testing libraries like junit.
-     * That means testing modules can be built with trimTesting enabled.
-     * 
+     * Post-process initialization. This implementation trims java5 source dirs
+     * if not running in a Java 5 VM.
      * @return true if initialization post-processing worked
      */
     protected boolean reviewInit() {
@@ -482,44 +484,26 @@ public class Module {
             for (ListIterator iter = srcDirs.listIterator(); iter.hasNext();) {
                 File srcDir = (File) iter.next();
                 String lcname = srcDir.getName().toLowerCase();
-                if (trimTesting
-                        && (Util.Constants.TESTSRC.equals(lcname) || Util.Constants.JAVA5_TESTSRC
-                                .equals(lcname))) {
-                    iter.remove();
-                } else if (!Util.JAVA5_VM
+                if (!Util.JAVA5_VM
                         && (Util.Constants.JAVA5_SRC.equals(lcname) || Util.Constants.JAVA5_TESTSRC
                                 .equals(lcname))) {
                     // assume optional for pre-1.5 builds
                     iter.remove();
                 }
             }
-            if (!trimTesting) {
-                return true;
-            }
-            if (!name.startsWith("testing")) {
-                for (ListIterator iter = libJars.listIterator(); iter.hasNext();) {
-                    File libJar = (File) iter.next();
-                    String name = libJar.getName();
-                    if ("junit.jar".equals(name.toLowerCase())) { // XXXFileLiteral
-                        iter.remove(); // XXX if verbose log
-                    }
-                }
-                for (ListIterator iter = required.listIterator(); iter
-                        .hasNext();) {
-                    Module required = (Module) iter.next();
-                    String name = required.name;
-                    // XXX testing-util only ?
-                    if (name.toLowerCase().startsWith("testing")) { // XXXFileLiteral
-                        iter.remove(); // XXX if verbose log
-                    }
-                }
-            }
         } catch (UnsupportedOperationException e) {
             return false; // failed XXX log also if verbose
         }
         return true;
     }
 
+    /**
+     * After reviewInit, setup four kinds of results.
+     */
+    protected boolean initResults() {
+        return true; // results initialized lazily
+    }
+
     /** resolve path absolutely, assuming / means base of modules dir */
     public String getFullPath(String path) {
         String fullPath;
@@ -541,29 +525,6 @@ public class Module {
         return fullPath;
     }
 
-    /** @return List of File of any module or library jar ending with suffix */
-    private ArrayList findJarsBySuffix(String suffix) {
-        ArrayList result = new ArrayList();
-        if (null != suffix) {
-            // library jars
-            for (Iterator iter = getLibJars().iterator(); iter.hasNext();) {
-                File file = (File) iter.next();
-                if (file.getPath().endsWith(suffix)) {
-                    result.add(file);
-                }
-            }
-            // module jars
-            for (Iterator iter = getRequired().iterator(); iter.hasNext();) {
-                Module module = (Module) iter.next();
-                File file = module.getModuleJar();
-                if (file.getPath().endsWith(suffix)) {
-                    result.add(file);
-                }
-            }
-        }
-        return result;
-    }
-
     class ICB implements XMLItem.ICallback {
         public void end(Properties attributes) {
             String kind = attributes.getProperty("kind");
@@ -580,23 +541,28 @@ public class Module {
         public interface ICallback {
             void end(Properties attributes);
         }
+
         static final String START_NAME = "classpathentry";
 
         static final String ATT_STARTED = "STARTED";
 
         final ICallback callback;
+
         final StringBuffer input = new StringBuffer();
 
         final String[] attributes = new String[ATTS.length];
+
         final String targetEntity;
+
         String entityName;
+
         String attributeName;
 
         XMLItem(String targetEntity, ICallback callback) {
             this.callback = callback;
             this.targetEntity = targetEntity;
             reset();
-            
+
         }
 
         private void reset() {
@@ -630,7 +596,7 @@ public class Module {
                     } else {
                         result.add(s);
                     }
-                } else {  // not a delimiter
+                } else { // not a delimiter
                     if (inQuote) {
                         quote.append(s);
                     } else {
@@ -647,7 +613,7 @@ public class Module {
                 next(tokens[i]);
             }
         }
-        
+
         private Properties attributesToProperties() {
             Properties result = new Properties();
             for (int i = 0; i < attributes.length; i++) {
@@ -664,17 +630,17 @@ public class Module {
                 error("Did not expect " + name + ": " + value);
             }
         }
-        
+
         void errorIfNull(String name, String value) {
             if (null == value) {
                 error("expected value for " + name);
             }
         }
-        
+
         boolean activeEntity() {
             return targetEntity.equals(entityName);
         }
-        
+
         /**
          * Assumes that comments and "<?xml"-style lines are removed.
          */
@@ -716,7 +682,9 @@ public class Module {
                 } else if (null == attributeName) {
                     attributeName = s;
                 } else {
-                    System.out.println("unknown state - not value, attribute, or entity: " + s);
+                    System.out
+                            .println("unknown state - not value, attribute, or entity: "
+                                    + s);
                 }
             }
         }
@@ -748,4 +716,3 @@ public class Module {
         }
     }
 }
-
index 55b2fa800c882bdaf22f6f782a2e0d98b30befae..39ace3485b2b27e823e9eb5457469cf262df6bf7 100644 (file)
@@ -28,13 +28,11 @@ public class Modules {
     public final File baseDir;
     public final File jarDir;
     private final Messager handler;
-    public final boolean trimTesting;
     
-    public Modules(File baseDir, File jarDir, boolean trimTesting, Messager handler) {
+    public Modules(File baseDir, File jarDir, Messager handler) {
         this.baseDir = baseDir;
         this.jarDir = jarDir;
         this.handler = handler;
-        this.trimTesting = trimTesting;
         Util.iaxIfNotCanReadDir(baseDir, "baseDir");
         Util.iaxIfNotCanReadDir(jarDir, "jarDir");
         Util.iaxIfNull(handler, "handler");
@@ -55,7 +53,7 @@ public class Modules {
             if (!Util.canReadDir(moduleDir)) {
                 handler.error("not a module: " + name);
             } else {
-                result = new Module(moduleDir, jarDir, name, this, trimTesting, handler);
+                result = new Module(moduleDir, jarDir, name, this, handler);
                 if (result.valid) {
                     modules.put(name, result);
                 } else {
diff --git a/build/src/org/aspectj/internal/tools/build/Result.java b/build/src/org/aspectj/internal/tools/build/Result.java
new file mode 100644 (file)
index 0000000..3efd095
--- /dev/null
@@ -0,0 +1,401 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Wes Isberg       initial implementation 
+ * ******************************************************************/
+
+package org.aspectj.internal.tools.build;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Represents a prospective build result and any requirements for it. Used for
+ * [testing|normal][jar|assembled-jar|classesDir?].
+ */
+public class Result {
+    public static final boolean NORMAL = true;
+
+    public static final boolean ASSEMBLE = true;
+
+    static final Kind RELEASE = new Kind("RELEASE", NORMAL, !ASSEMBLE);
+
+    static final Kind RELEASE_ALL = new Kind("RELEASE_ALL", NORMAL, ASSEMBLE);
+
+    static final Kind TEST = new Kind("TEST", !NORMAL, !ASSEMBLE);
+
+    static final Kind TEST_ALL = new Kind("TEST_ALL", !NORMAL, ASSEMBLE);
+
+    private static final Kind[] KINDS = { RELEASE, TEST, RELEASE_ALL, TEST_ALL };
+
+    private static final HashMap nameToResult = new HashMap();
+
+    public static boolean isTestingJar(String name) {
+        name = name.toLowerCase();
+        return "junit.jar".equals(name);
+    }
+
+    public static boolean isTestingDir(String name) {
+        name = name.toLowerCase();
+        return (Util.Constants.TESTSRC.equals(name) || Util.Constants.JAVA5_TESTSRC
+                .equals(name));
+    }
+
+    public static boolean isTestingModule(Module module) {
+        String name = module.name.toLowerCase();
+        return name.startsWith("testing") || "tests".equals(name);
+    }
+
+    public static synchronized Result getResult(String name) {
+        if (null == name) {
+            throw new IllegalArgumentException("null name");
+        }
+        return (Result) nameToResult.get(name);
+    }
+
+    public static Result[] getResults(String[] names) {
+        if (null == names) {
+            return new Result[0];
+        }
+        Result[] results = new Result[names.length];
+
+        for (int i = 0; i < results.length; i++) {
+            String name = names[i];
+            if (null == name) {
+                String m = "no name at " + i + ": " + Arrays.asList(names);
+                throw new IllegalArgumentException(m);
+            }
+            Result r = Result.getResult(name);
+            if (null == r) {
+                String m = "no result [" + i + "]: " + name + ": "
+                        + Arrays.asList(names);
+                throw new IllegalArgumentException(m);
+            }
+            results[i] = r;
+        }
+        return results;
+
+    }
+
+    public static Kind[] KINDS() {
+        Kind[] result = new Kind[KINDS.length];
+        System.arraycopy(KINDS, 0, result, 0, result.length);
+        return result;
+    }
+
+    public static void iaxUnlessNormal(Result result) {
+        if ((null == result) || !result.getKind().normal) {
+            throw new IllegalArgumentException("not normal: " + result);
+        }
+    }
+
+    public static void iaxUnlessAssembly(Result result) {
+        if ((null == result) || !result.getKind().assemble) {
+            throw new IllegalArgumentException("not assembly: " + result);
+        }
+    }
+
+    public static Kind kind(boolean normal, boolean assemble) {
+        return (normal == NORMAL ? (assemble == ASSEMBLE ? RELEASE_ALL
+                : RELEASE) : (assemble == ASSEMBLE ? TEST_ALL : TEST));
+    }
+
+    public static class Kind {
+        final String name;
+
+        final boolean normal;
+
+        final boolean assemble;
+
+        private Kind(String name, boolean normal, boolean assemble) {
+            this.name = name;
+            this.normal = normal;
+            this.assemble = assemble;
+        }
+
+        public final boolean isAssembly() {
+            return assemble;
+        }
+
+        public final boolean isNormal() {
+            return normal;
+        }
+
+        public final String toString() {
+            return name;
+        }
+    }
+
+    /** path to output jar - may not exist */
+    private final File outputFile;
+
+    /** list of required Result */
+    private final List requiredResults;
+
+    /** File list of library jars */
+    private final List libJars;
+
+    /** String list of classpath variables */
+    private final List classpathVariables;
+
+    transient String toLongString;
+
+    /**
+     * File list of library jars exported to clients (duplicates some libJars
+     * entries)
+     */
+    private final List exportedLibJars;
+
+    /** File list of source directories */
+    private final List srcDirs;
+
+    /** true if this has calculated List fields. */
+    private boolean requiredDone;
+
+    /** true if this has been found to be out of date */
+    private boolean outOfDate;
+
+    /** true if we have calculated whether this is out of date */
+    private boolean outOfDateSet;
+
+    private final Kind kind;
+
+    private final Module module;
+
+    private final String name;
+
+    Result(Kind kind, Module module, File jarDir) {
+        this.kind = kind;
+        this.module = module;
+        this.libJars = new ArrayList();
+        this.exportedLibJars = new ArrayList();
+        this.srcDirs = new ArrayList();
+        this.classpathVariables = new ArrayList();
+        this.requiredResults = new ArrayList();
+        String name = module.name;
+        if (!kind.normal) {
+            name += "-test";
+        }
+        if (kind.assemble) {
+            name += "-all";
+        }
+        this.name = name;
+        this.outputFile = new File(jarDir, name + ".jar");
+        nameToResult.put(name, this);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public File getOutputFile() {
+        return outputFile;
+    }
+
+    public void rebuilding() {
+        outOfDate = true;
+        outOfDateSet = true;
+        if (outputFile.exists()) {
+            outputFile.delete();
+            if (outputFile.exists()) {
+                throw new Error("unable to delete existing " + outputFile);
+            }
+        }
+    }
+
+    public void clearOutOfDate() {
+        outOfDateSet = false;
+        outOfDate = false;
+    }
+
+    public boolean outOfDate(boolean recalculate) {
+        if (recalculate) {
+            clearOutOfDate();
+        }
+        if (!outOfDateSet) {
+            outOfDate = Module.outOfDate(this, recalculate);
+            outOfDateSet = true;
+        }
+        return outOfDate;
+    }
+
+    public List findKnownJarAntecedants() {
+        ArrayList result = new ArrayList();
+        Module.doFindKnownJarAntecedants(this, result);
+        return result;
+    }
+
+    /** @return unmodifiable List of String classpath variables */
+    public List getClasspathVariables() {
+        return safeList(classpathVariables);
+    }
+
+    //
+    /** @return unmodifiable List of required modules String names */
+    public Result[] getRequired() {
+        return safeResults(requiredResults);
+    }
+
+    /**
+     * @return unmodifiable list of exported library files, guaranteed readable
+     */
+    public List getExportedLibJars() {
+        return safeList(exportedLibJars);
+    }
+
+    /**
+     * @return unmodifiable list of required library files, guaranteed readable
+     */
+    public List getLibJars() {
+        requiredDone();
+        return safeList(libJars);
+    }
+
+    /**
+     * @return unmodifiable list of required library files, guaranteed readable
+     */
+    // public List getMerges() {
+    // requiredDone();
+    // return safeList(merges);
+    // }
+    /** @return unmodifiable list of source directories, guaranteed readable */
+    public List getSrcDirs() {
+        return safeList(srcDirs);
+    }
+
+    public Module getModule() {
+        return module;
+    }
+
+    public Kind getKind() {
+        return kind;
+    }
+
+    public String toLongString() {
+        if (null == toLongString) {
+            toLongString = name + "[outputFile=" + outputFile
+                    + ", requiredResults=" + requiredResults + ", srcDirs="
+                    + srcDirs + ", libJars=" + libJars + "]";
+        }
+        return toLongString;
+    }
+
+    public String toString() {
+        return name;
+    }
+
+    private List safeList(List l) {
+        requiredDone();
+        return Collections.unmodifiableList(l);
+    }
+
+    private Result[] safeResults(List list) {
+        requiredDone();
+        if (null == list) {
+            return new Result[0];
+        }
+        return (Result[]) list.toArray(new Result[0]);
+    }
+
+    private void initSrcDirs() {
+        srcDirs.addAll(getModule().srcDirs(this));
+        if (getKind().normal) {
+            // trim testing source directories
+            for (ListIterator iter = srcDirs.listIterator(); iter.hasNext();) {
+                File srcDir = (File) iter.next();
+                if (isTestingDir(srcDir.getName())) {
+                    iter.remove();
+                }
+            }
+        }
+    }
+
+    private void initLibJars() {
+        libJars.addAll(getModule().libJars(this));
+        if (getKind().normal && !isTestingModule(getModule())) {
+            // trim testing libraries
+            for (ListIterator iter = libJars.listIterator(); iter.hasNext();) {
+                File libJar = (File) iter.next();
+                if (isTestingJar(libJar.getName())) {
+                    iter.remove();
+                }
+            }
+        }
+    }
+
+    private void assertKind(Kind kind) {
+        if (kind != getKind()) {
+            throw new IllegalArgumentException("expected " + getKind()
+                    + " got " + kind);
+        }
+    }
+
+    private void initRequiredResults() {
+        Module module = getModule();
+        final Kind kind = getKind();
+        if (kind.assemble) {
+            if (kind.normal) {
+                assertKind(RELEASE_ALL);
+                requiredResults.add(module.getResult(RELEASE));
+            } else {
+                assertKind(TEST_ALL);
+                requiredResults.add(module.getResult(TEST));
+                requiredResults.add(module.getResult(RELEASE));
+            }
+        } else if (!kind.normal) {
+            assertKind(TEST);
+            requiredResults.add(module.getResult(RELEASE));
+        } else {
+            assertKind(RELEASE);
+        }
+        // externally-required:
+        List modules = module.requiredModules(this);
+        final boolean thisIsTestingModule = isTestingModule(module);
+        for (Iterator iter = modules.iterator(); iter.hasNext();) {
+            module = (Module) iter.next();
+            if (thisIsTestingModule || !kind.normal) {
+                // testing builds can rely on other release and test results
+                requiredResults.add(module.getResult(TEST));
+                requiredResults.add(module.getResult(RELEASE));
+            } else {
+                // release builds can only rely on non-testing results
+                // from non-testing modules
+                requiredResults.add(module.getResult(RELEASE));
+            }
+        }
+    }
+
+    private void initClasspathVariables() {
+        // no difference
+        classpathVariables.addAll(getModule().classpathVariables(this));
+    }
+
+    private void initExportedLibJars() {
+        // no difference
+        exportedLibJars.addAll(getModule().exportedLibJars(this));
+    }
+
+    private synchronized void requiredDone() {
+        if (!requiredDone) {
+            initSrcDirs();
+            initLibJars();
+            initRequiredResults();
+            initClasspathVariables();
+            initExportedLibJars();
+            requiredDone = true;
+        }
+    }
+
+}