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