From bdbc4dea8d098067d58b743d68e816640a11cb6e Mon Sep 17 00:00:00 2001 From: wisberg Date: Thu, 9 Jun 2005 00:11:27 +0000 Subject: [PATCH] Now targeting Module results (release, test, release-all, test-all) rather than modules (with variants), since that conflated test and release classes. uptodate check needs work. --- .../tools/ant/taskdefs/AntBuilder.java | 444 ++++--- .../aspectj/internal/tools/build/Builder.java | 1046 +++++++++-------- .../aspectj/internal/tools/build/Module.java | 343 +++--- .../aspectj/internal/tools/build/Modules.java | 6 +- .../aspectj/internal/tools/build/Result.java | 401 +++++++ 5 files changed, 1306 insertions(+), 934 deletions(-) create mode 100644 build/src/org/aspectj/internal/tools/build/Result.java diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java index 0288f1f20..d7bd8436d 100644 --- a/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java +++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java @@ -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) { diff --git a/build/src/org/aspectj/internal/tools/build/Builder.java b/build/src/org/aspectj/internal/tools/build/Builder.java index b9303ffb8..cfac0192d 100644 --- a/build/src/org/aspectj/internal/tools/build/Builder.java +++ b/build/src/org/aspectj/internal/tools/build/Builder.java @@ -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: * - * This currently provides no control over the compile or assembly process, - * but clients can harvest {moduleDir}/bin directories to re-use - * the results of eclipse compiles. + * This currently provides no control over the compile or assembly process, but + * clients can harvest {moduleDir}/bin directories to re-use the + * results of eclipse compiles. *

* When building products, this assumes: *

*

- * 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. *

- * 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 List of String - * using comma as the delimiter and trimming whitespace from the result. - * - * @param text String to split. + * Splits strings into an unmodifable List of String using + * comma as the delimiter and trimming whitespace from the result. + * + * @param text + * String 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); } diff --git a/build/src/org/aspectj/internal/tools/build/Module.java b/build/src/org/aspectj/internal/tools/build/Module.java index 8539e6c8c..d37b8bed4 100644 --- a/build/src/org/aspectj/internal/tools/build/Module.java +++ b/build/src/org/aspectj/internal/tools/build/Module.java @@ -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("