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.
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);
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;
}
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
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();
// -- 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) {
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) {
} 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());
* 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);
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);
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();) {
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();) {
// 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);
}
handler.logException("BuildException zipping " + module, e);
return false;
} finally {
- module.clearOutOfDate();
+ result.clearOutOfDate();
}
}
* @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;
}
/**
- * 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) {
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();
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");
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) {
}
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);
}
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();) {
}
}
}
-
- /**
- * @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);
}
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.
*
* @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);
}
}
}
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;
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;
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;
/** 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();
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;
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 */
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);
}
}
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: "
}
/**
- * 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() {
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;
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");
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() {
} else {
result.add(s);
}
- } else { // not a delimiter
+ } else { // not a delimiter
if (inQuote) {
quote.append(s);
} else {
next(tokens[i]);
}
}
-
+
private Properties attributesToProperties() {
Properties result = new Properties();
for (int i = 0; i < attributes.length; i++) {
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.
*/
} 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);
}
}
}
}
}
}
-
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");
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 {
--- /dev/null
+/* *******************************************************************
+ * 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;
+ }
+ }
+
+}