aboutsummaryrefslogtreecommitdiffstats
path: root/build/src/org
diff options
context:
space:
mode:
authorwisberg <wisberg>2002-12-16 17:09:36 +0000
committerwisberg <wisberg>2002-12-16 17:09:36 +0000
commitc3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch)
treee9acb7f3d33c1499975cec9ef3cc7ea151078344 /build/src/org
parent3cde920c3f7eb8241bf569007e25225d80b43c0f (diff)
downloadaspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz
aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip
initial version
Diffstat (limited to 'build/src/org')
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/AJInstaller.java330
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/AJPush.java89
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java721
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java156
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/Checklics.java735
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/ConditionalTask.java182
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/CopyAndInlineStylesheet.java113
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/StripNonBodyHtml.java233
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/TestBuildModule.java79
-rw-r--r--build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties20
-rw-r--r--build/src/org/aspectj/internal/tools/build/BuildSpec.java161
-rw-r--r--build/src/org/aspectj/internal/tools/build/Builder.java497
-rw-r--r--build/src/org/aspectj/internal/tools/build/Messager.java43
-rw-r--r--build/src/org/aspectj/internal/tools/build/Module.java501
-rw-r--r--build/src/org/aspectj/internal/tools/build/Modules.java68
-rw-r--r--build/src/org/aspectj/internal/tools/build/ProductModule.java70
-rw-r--r--build/src/org/aspectj/internal/tools/build/Util.java174
-rw-r--r--build/src/org/aspectj/internal/tools/build/package.html12
18 files changed, 4184 insertions, 0 deletions
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/AJInstaller.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/AJInstaller.java
new file mode 100644
index 000000000..4dd35c4b8
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/AJInstaller.java
@@ -0,0 +1,330 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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
+ * ******************************************************************/
+
+//XXX INCLUDES CODE FROM ANT -- UNDER APACHE LICENSE
+package org.aspectj.internal.tools.ant.taskdefs;
+
+import org.apache.tools.ant.types.*;
+import java.io.*;
+import java.util.zip.ZipOutputStream;
+import java.util.*;
+import java.util.zip.*;
+import org.apache.tools.ant.taskdefs.*;
+import org.apache.tools.ant.*;
+
+public class AJInstaller extends MatchingTask {
+ static final String INCLUDE_CLASSES = "$installer$/org/aspectj/*.class";
+ static final String MAIN_CLASS = "$installer$.org.aspectj.Main";
+ static final String CONTENTS_FILE = "$installer$/org/aspectj/resources/contents.txt";
+ private String htmlSrc;
+
+ public void setHtmlSrc(String v) { htmlSrc = v; }
+
+ private String resourcesSrc;
+
+ public void setResourcesSrc(String v) { resourcesSrc = v; }
+
+ private String mainclass;
+
+ public void setMainclass(String v) { mainclass = v; }
+
+ private File installerClassJar;
+
+ public void setInstallerclassjar(String v) {
+ installerClassJar = project.resolveFile(v);
+ }
+
+ protected List contentsNames = new ArrayList();
+
+ protected long contentsBytes = 0;
+
+ protected void addToContents(File file, String vPath) {
+ contentsNames.add(vPath);
+ contentsBytes += file.length();
+ }
+
+ String[] getFiles(File baseDir) {
+ DirectoryScanner ds = new DirectoryScanner();
+ setBasedir(baseDir.getAbsolutePath());
+ ds.setBasedir(baseDir);
+ //ds.setIncludes(new String [] {pattern});
+ ds.scan();
+ return ds.getIncludedFiles();
+ }
+
+ protected Copy getCopyTask() {
+ Copy cd = (Copy)project.createTask("copy");
+ if (null == cd) {
+ log("project.createTask(\"copy\") failed - direct", project.MSG_VERBOSE);
+ cd = new Copy();
+ cd.setProject(getProject());
+ }
+ return cd;
+ }
+ protected void finishZipOutputStream(ZipOutputStream zOut) throws IOException, BuildException {
+ writeContents(zOut);
+ writeManifest(zOut);
+ File tmpDirF = File.createTempFile("tgz", ".di");
+ File tmpDir = new File(tmpDirF.getAbsolutePath() + "r");
+ tmpDirF.delete();
+ String tmp = tmpDir.getAbsolutePath();
+
+ // installer class files
+ Expand expand = new Expand();
+ expand.setProject(getProject());
+ expand.setSrc(installerClassJar);
+ expand.setDest(new File(tmp));
+ PatternSet patterns = new PatternSet();
+ patterns.setIncludes(INCLUDE_CLASSES);
+ expand.addPatternset(patterns);
+ expand.execute();
+
+ // move the correct resource files into the jar
+ Copy cd = getCopyTask();
+ fileset = new FileSet();
+ fileset.setDir(new File(resourcesSrc));
+ fileset.setIncludes("*");
+ fileset.setExcludes("contents.txt,properties.txt");
+ cd.addFileset(fileset);
+ cd.setTodir(new File(tmp+"/$installer$/org/aspectj/resources"));
+ cd.execute();
+ project.addFilter("installer.main.class", this.mainclass);
+ Copy cf = getCopyTask();
+ fileset = new FileSet();
+ fileset.setDir(new File(resourcesSrc));
+ fileset.setIncludes("properties.txt");
+ cf.setFiltering(true);
+ cf.addFileset(fileset);
+ cf.setTodir(new File(tmp+"/$installer$/org/aspectj/resources"));
+ cf.execute();
+ // move the correct resource files into the jar
+ cd = getCopyTask();
+ fileset = new FileSet();
+ fileset.setDir(new File(htmlSrc));
+ fileset.setIncludes("*");
+ cd.addFileset(fileset);
+ cd.setTodir(new File(tmp+"/$installer$/org/aspectj/resources"));
+ cd.execute();
+ // now move these files into the jar
+ setBasedir(tmp);
+ writeFiles(zOut, getFiles(tmpDir));
+ // and delete the tmp dir
+ Delete dt = (Delete)project.createTask("delete");
+ if (null == dt) {
+ dt = new Delete();
+ dt.setProject(getProject());
+ }
+ dt.setDir(new File(tmp));
+ dt.execute();
+ }
+
+ static final char NEWLINE = '\n';
+
+ protected void writeContents(ZipOutputStream zOut) throws IOException {
+ // write to a StringBuffer
+ StringBuffer buf = new StringBuffer();
+ buf.append(contentsBytes);
+ buf.append(NEWLINE);
+ for (Iterator i = contentsNames.iterator(); i.hasNext(); ) {
+ String name = (String)i.next();
+ buf.append(name);
+ buf.append(NEWLINE);
+ }
+ zipFile(new StringBufferInputStream(buf.toString()), zOut, CONTENTS_FILE, System.currentTimeMillis());
+ }
+
+ protected void writeManifest(ZipOutputStream zOut) throws IOException {
+ // write to a StringBuffer
+ StringBuffer buf = new StringBuffer();
+ buf.append("Manifest-Version: 1.0");
+ buf.append(NEWLINE);
+ buf.append("Main-Class: " + MAIN_CLASS);
+ buf.append(NEWLINE);
+ zipFile(new StringBufferInputStream(buf.toString()), zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis());
+ }
+
+ //XXX cut-and-paste from Zip super-class (under apache license)
+ private File zipFile;
+ private File baseDir;
+ private boolean doCompress = true;
+ protected String archiveType = "zip";
+
+ /**
+ * This is the name/location of where to
+ * create the .zip file.
+ */
+ public void setZipfile(String zipFilename) {
+ zipFile = project.resolveFile(zipFilename);
+ }
+
+ /**
+ * This is the base directory to look in for
+ * things to zip.
+ */
+ public void setBasedir(String baseDirname) {
+ baseDir = project.resolveFile(baseDirname);
+ }
+
+ /**
+ * Sets whether we want to compress the files or only store them.
+ */
+ public void setCompress(String compress) {
+ doCompress = Project.toBoolean(compress);
+ }
+
+ protected void initZipOutputStream(ZipOutputStream zOut)
+ throws IOException, BuildException
+ {
+ }
+
+ protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
+ throws IOException
+ {
+ }
+
+ protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,
+ long lastModified)
+ throws IOException
+ {
+ ZipEntry ze = new ZipEntry(vPath);
+ ze.setTime(lastModified);
+
+ /*
+ * XXX ZipOutputStream.putEntry expects the ZipEntry to know its
+ * size and the CRC sum before you start writing the data when using
+ * STORED mode.
+ *
+ * This forces us to process the data twice.
+ *
+ * I couldn't find any documentation on this, just found out by try
+ * and error.
+ */
+ if (!doCompress) {
+ long size = 0;
+ CRC32 cal = new CRC32();
+ if (!in.markSupported()) {
+ // Store data into a byte[]
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ size += count;
+ cal.update(buffer, 0, count);
+ bos.write(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ in = new ByteArrayInputStream(bos.toByteArray());
+ } else {
+ in.mark(Integer.MAX_VALUE);
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ size += count;
+ cal.update(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ in.reset();
+ }
+ ze.setSize(size);
+ ze.setCrc(cal.getValue());
+ }
+ zOut.putNextEntry(ze);
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ zOut.write(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ }
+
+ protected void zipFile(File file, ZipOutputStream zOut, String vPath)
+ throws IOException
+ {
+ if ( !vPath.startsWith("$installer$") ) {
+ addToContents(file, vPath);
+ }
+ FileInputStream fIn = new FileInputStream(file);
+ try {
+ zipFile(fIn, zOut, vPath, file.lastModified());
+ } finally {
+ fIn.close();
+ }
+ }
+
+ public void execute() throws BuildException {
+ if (installerClassJar == null) {
+ throw new BuildException("installerClassJar attribute must be set!");
+ }
+ if (!installerClassJar.canRead()
+ || !installerClassJar.getPath().endsWith(".jar")) {
+ throw new BuildException("not readable jar:" + installerClassJar);
+ }
+// if (installerClassDir == null) {
+// throw new BuildException("installerClassDir attribute must be set!");
+// }
+// if (!installerClassDir.exists()) {
+// throw new BuildException("no such directory: installerClassDir=" + installerClassDir);
+// }
+ if (baseDir == null) {
+ throw new BuildException("basedir attribute must be set!");
+ }
+ if (!baseDir.exists()) {
+ throw new BuildException("basedir does not exist!");
+ }
+ DirectoryScanner ds = super.getDirectoryScanner(baseDir);
+ String[] files = ds.getIncludedFiles();
+ String[] dirs = ds.getIncludedDirectories();
+ log("Building installer: "+ zipFile.getAbsolutePath());
+ ZipOutputStream zOut = null;
+ try {
+ zOut = new ZipOutputStream(new FileOutputStream(zipFile));
+ if (doCompress) {
+ zOut.setMethod(ZipOutputStream.DEFLATED);
+ } else {
+ zOut.setMethod(ZipOutputStream.STORED);
+ }
+ initZipOutputStream(zOut);
+ writeDirs(zOut, dirs);
+ writeFiles(zOut, files);
+ finishZipOutputStream(zOut);
+ } catch (IOException ioe) {
+ String msg = "Problem creating " + archiveType + " " + ioe.getMessage();
+ throw new BuildException(msg, ioe, location);
+ } finally {
+ if (zOut != null) {
+ try {
+ // close up
+ zOut.close();
+ }
+ catch (IOException e) {}
+ }
+ }
+ }
+
+ protected void writeDirs(ZipOutputStream zOut, String[] dirs) throws IOException {
+ for (int i = 0; i < dirs.length; i++) {
+ File f = new File(baseDir,dirs[i]);
+ String name = dirs[i].replace(File.separatorChar,'/')+"/";
+ zipDir(f, zOut, name);
+ }
+ }
+
+ protected void writeFiles(ZipOutputStream zOut, String[] files) throws IOException {
+ for (int i = 0; i < files.length; i++) {
+ File f = new File(baseDir,files[i]);
+ String name = files[i].replace(File.separatorChar,'/');
+ zipFile(f, zOut, name);
+ }
+ }
+
+}
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/AJPush.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/AJPush.java
new file mode 100644
index 000000000..4a778cb67
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/AJPush.java
@@ -0,0 +1,89 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.*;
+import org.apache.tools.ant.types.*;
+import org.apache.tools.ant.taskdefs.*;
+import java.io.*;
+import java.util.*;
+import java.text.DecimalFormat;
+
+public class AJPush extends ConditionalTask {
+ private File src;
+
+ public void setSrc(String v) { src = project.resolveFile(v); }
+
+ private String key;
+
+ public void setKey(String v) { key = v; }
+
+ File releaseDir = null;
+ File downloadDir = null;
+ boolean waiting = false;
+
+ public void execute() throws org.apache.tools.ant.BuildException {
+ //File releaseDir = src.getParentFile();
+ // todo: dependency on ant script variable name aj.release.dir
+ releaseDir = project.resolveFile(project.getProperty("aj.release.dir"));
+ // todo: dependency on ant script variable name download.dir
+ downloadDir = project.resolveFile(project.getProperty("download.dir"));
+ // For testing make sure these directories are made
+ Mkdir mkdir = (Mkdir) project.createTask("mkdir");
+ mkdir.setDir(releaseDir);
+ mkdir.execute();
+ mkdir = (Mkdir) project.createTask("mkdir");
+ mkdir.setDir(downloadDir);
+ mkdir.execute();
+ log("Pushing from " + releaseDir + " to " + downloadDir);
+ // add info to release.txt
+ try {
+ File releaseFile = new File(releaseDir, "release.txt");
+ File downloadFile = new File(downloadDir, "release.txt");
+ if (!releaseFile.canRead()) {
+ releaseFile.createNewFile();
+ }
+ addReleaseInfo(src, releaseFile);
+ // copy to staging web server
+ project.copyFile(src, new File(downloadDir, src.getName()));
+ project.copyFile(releaseFile, downloadFile);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ void addReleaseInfo(File file, File propFile) throws IOException {
+ Properties props = new Properties();
+ if (propFile.canRead()) {
+ props.load(new FileInputStream(propFile));
+ }
+ file.createNewFile(); // create new only if necessary
+ long bytes = file.length();
+ DecimalFormat df = new DecimalFormat();
+ df.setGroupingSize(3);
+ String bytesString = df.format(bytes);
+ props.put("release." + key + ".size.bytes", bytesString);
+ props.put("release." + key + ".date", project.getProperty("build.date"));
+ props.put("release." + key + ".filename", file.getName());
+ props.put("release.date", project.getProperty("build.date"));
+ props.put("release.version", project.getProperty("build.version.short"));
+ props.put("release.versionName", project.getProperty("build.version.long"));
+ String userName = System.getProperty("user.name");
+ if (userName != null) {
+ props.put("release." + key + ".username", userName);
+ }
+ props.store(new FileOutputStream(propFile), null);
+ }
+
+}
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java
new file mode 100644
index 000000000..d4001161e
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java
@@ -0,0 +1,721 @@
+/* *******************************************************************
+ * 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.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 org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.aspectj.internal.tools.build.BuildSpec;
+import org.aspectj.internal.tools.build.Builder;
+import org.aspectj.internal.tools.build.Messager;
+import org.aspectj.internal.tools.build.Module;
+import org.aspectj.internal.tools.build.Modules;
+import org.aspectj.internal.tools.build.ProductModule;
+import org.aspectj.internal.tools.build.Util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Implement Builder in Ant.
+ */
+public class AntBuilder extends Builder {
+ /*
+ * XXX This just constructs and uses Ant Task objects,
+ * which in some cases causes the tasks to fail.
+ */
+
+ /** @return a Builder for this project and configuration */
+ public static Builder getBuilder(String config, Project project, File tempDir) {
+ boolean useEclipseCompiles = false;
+ boolean verbose = false;
+ if (null != config) {
+ if (-1 != config.indexOf("useEclipseCompiles")) {
+ useEclipseCompiles = true;
+ }
+ if (-1 != config.indexOf("verbose")) {
+ verbose = true;
+ }
+ }
+ Messager handler = new ProjectMessager(project);
+ Builder result = new ProductBuilder(project, tempDir, useEclipseCompiles, handler);
+ if (verbose) {
+ result.setVerbose(true);
+ }
+ return result;
+ }
+
+ /**
+ * 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
+ */
+ 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)) {
+ if (!first) {
+ depends.append(",");
+ } else {
+ first = false;
+ }
+ depends.append(reqModule.name);
+ }
+ }
+ if (0 < depends.length()) {
+ target.setDepends(depends.toString());
+ }
+ targets.put(module.name, 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);
+ }
+ }
+ }
+ }
+
+ protected final Project project;
+
+ protected AntBuilder(Project project, File tempDir, boolean useEclipseCompiles,
+ Messager handler) {
+ super(tempDir, useEclipseCompiles, handler);
+ this.project = project;
+ Util.iaxIfNull(project, "project");
+ }
+ protected boolean copyFile(File fromFile, File toFile, boolean filter) {
+ Copy copy = makeCopyTask(filter);
+ copy.setFile(fromFile);
+ copy.setTofile(toFile);
+ executeTask(copy);
+ return true;
+ }
+
+ 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.setProject(project);
+
+ // -- source paths
+ Path path = new Path(project);
+ for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) {
+ File file = (File) iter.next();
+ path.createPathElement().setLocation(file);
+ }
+ javac.setSrcdir(path);
+ path = null;
+
+ // -- classpath
+ Path classpath = new Path(project);
+ boolean hasLibraries = false;
+ // modules
+ for (Iterator iter = module.getRequired().iterator(); iter.hasNext();) {
+ Module required = (Module) iter.next();
+ classpath.createPathElement().setLocation(required.getModuleJar());
+ if (!hasLibraries) {
+ hasLibraries = true;
+ }
+ }
+ // libraries
+ for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) {
+ File file = (File) iter.next();
+ classpath.createPathElement().setLocation(file);
+ if (!hasLibraries) {
+ hasLibraries = true;
+ }
+ }
+ // 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
+ }
+
+ // -- set output directory
+ classpath.createPathElement().setLocation(classesDir);
+ javac.setClasspath(classpath);
+ javac.setDestdir(classesDir);
+ if (!classesDir.mkdirs()) {
+ errors.add("unable to create classes directory");
+ return false;
+ }
+
+ // compile
+ try {
+ return executeTask(javac);
+ } catch (BuildException e) {
+ String args = "" + Arrays.asList(javac.getCurrentCompilerArgs());
+ errors.add("BuildException compiling " + module.toLongString() + args
+ + ": " + Util.renderException(e));
+ return false;
+ } finally {
+ javac.init(); // be nice to let go of classpath libraries...
+ }
+ }
+
+ /**
+ * Merge classes directory and any merge jars into module jar
+ * with any specified manifest file.
+ * META-INF directories are excluded.
+ */
+ protected boolean assemble(Module module, File classesDir, List errors) {
+ if (!buildingEnabled) {
+ return false;
+ }
+ // ---- zip result up
+ Zip zip = new Zip();
+ zip.setProject(project);
+ zip.setDestFile(module.getModuleJar());
+ ZipFileSet zipfileset = null;
+
+ // -- merge any resources in any of the src directories
+ for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) {
+ File srcDir = (File) iter.next();
+ zipfileset = new ZipFileSet();
+ zipfileset.setProject(project);
+ zipfileset.setDir(srcDir);
+ zipfileset.setIncludes(RESOURCE_PATTERN);
+ zip.addZipfileset(zipfileset);
+ }
+
+ // -- merge any merge jars
+ List mergeJars = module.getMerges();
+ 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/*"); // XXXFileLiteral
+ zipfileset.setExcludes("meta-inf/*");
+ 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
+ }
+
+ // -- manifest
+ File manifest = new File(module.moduleDir, module.name + ".mf.txt"); // XXXFileLiteral
+ if (Util.canReadFile(manifest)) {
+ if (Util.canReadDir(metaInfDir) || metaInfDir.mkdirs()) {
+ copyFile(manifest, new File(metaInfDir, "manifest.mf"), FILTER_ON); // XXXFileLiteral
+ } else {
+ errors.add("have manifest, but unable to create " + metaInfDir);
+ return false;
+ }
+ }
+
+ zipfileset = new ZipFileSet();
+ zipfileset.setProject(project);
+ zipfileset.setDir(classesDir);
+ zipfileset.setIncludes("**/*");
+ zip.addZipfileset(zipfileset);
+
+ try {
+ handler.log("assembling " + module + " in " + module.getModuleJar());
+ return executeTask(zip);
+ } catch (BuildException e) {
+ errors.add("BuildException zipping " + module + ": " + e.getMessage());
+ return false;
+ } finally {
+ module.clearOutOfDate();
+ }
+ }
+ /**
+ * @see org.aspectj.internal.tools.build.Builder#buildAntecedants(Module)
+ */
+ protected String[] getAntecedantModuleNames(Module module, boolean rebuild) {
+ 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?
+ int size = result.size();
+ if (0 == result.size()) {
+ return new String[0];
+ }
+ ArrayList toReturn = new ArrayList();
+ for (Iterator iter = result.iterator(); iter.hasNext();) {
+ Target target = (Target) iter.next();
+ String name = target.getName();
+ if (null == name) {
+ throw new Error("null name?");
+ } else {
+ toReturn.add(name);
+ }
+ }
+ // topoSort always returns module.name
+ if ((1 == size)
+ && module.name.equals(toReturn.get(0))
+ && !module.outOfDate(false)) {
+ return new String[0];
+ }
+ return (String[]) toReturn.toArray(new String[0]);
+ }
+
+ /**
+ * Generate Module.assembledJar with merge of itself and all antecedants
+ */
+ protected boolean assembleAll(Module module, Messager handler) {
+ if (!buildingEnabled) {
+ return false;
+ }
+ Util.iaxIfNull(module, "module");
+ Util.iaxIfNull(handler, "handler");
+ if (module.outOfDate(false)) {
+ throw new IllegalStateException("module out of date: " + module);
+ }
+
+ // ---- zip result up
+ Zip zip = new Zip();
+ zip.setProject(project);
+ zip.setDestFile(module.getAssembledJar());
+ ZipFileSet zipfileset = null;
+
+ ArrayList known = module.findKnownJarAntecedants();
+
+ // -- merge any antecedents, less any manifest
+ for (Iterator iter = known.iterator(); iter.hasNext();) {
+ File jarFile = (File) iter.next();
+ zipfileset = new ZipFileSet();
+ zipfileset.setProject(project);
+ zipfileset.setSrc(jarFile);
+ 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 the module jar itself, including same manifest (?)
+ zipfileset = new ZipFileSet();
+ zipfileset.setProject(project);
+ zipfileset.setSrc(module.getModuleJar());
+ zip.addZipfileset(zipfileset);
+
+ try {
+ handler.log("assembling all " + module + " in " + module.getAssembledJar());
+ return executeTask(zip);
+ } catch (BuildException e) {
+ handler.logException("BuildException zipping " + module, e);
+ return false;
+ } finally {
+ module.clearOutOfDate();
+ }
+ }
+
+ /**
+ * @see org.aspectj.internal.tools.ant.taskdefs.Builder#buildInstaller(BuildSpec, String)
+ */
+ protected boolean buildInstaller(
+ BuildSpec buildSpec,
+ String targDirPath) {
+ 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) {
+ return false;
+ }
+ task.execute();
+ return true;
+ }
+
+}
+
+
+// finally caught by failing to comply with proper ant initialization
+// /**
+// * Build a module that has a build script.
+// * @param buildSpec the module to build
+// * @param buildScript the script file
+// * @throws BuildException if build fails
+// */
+// private void buildByScript(BuildSpec buildSpec, File buildScript)
+// throws BuildException {
+// Ant ant = new Ant();
+// ant.setProject(getProject());
+// ant.setAntfile(buildScript.getAbsolutePath());
+// ant.setDescription("building module " + buildSpec.module);
+// ant.setDir(buildScript.getParentFile());
+// ant.setInheritAll(true);
+// ant.setInheritRefs(false);
+// ant.setLocation(getLocation());
+// ant.setOwningTarget(getOwningTarget());
+// // by convention, for build.xml, use module name to publish
+// ant.setTarget(buildSpec.module);
+// ant.setTaskName("ant");
+// loadAntProperties(ant, buildSpec);
+// ant.execute();
+// }
+//
+// /** override definitions */
+// private void loadAntProperties(Ant ant, BuildSpec buildSpec) {
+// Property property = ant.createProperty();
+// property.setName(BuildSpec.baseDir_NAME);
+// property.setFile(buildSpec.baseDir);
+// property = ant.createProperty();
+// property.setName(buildSpec.distDir_NAME);
+// property.setFile(buildSpec.distDir);
+// property = ant.createProperty();
+// property.setName(BuildSpec.tempDir_NAME);
+// property.setFile(buildSpec.tempDir);
+// property = ant.createProperty();
+// property.setName(BuildSpec.jarDir_NAME);
+// property.setFile(buildSpec.jarDir);
+// property = ant.createProperty();
+// property.setName(BuildSpec.stagingDir_NAME);
+// property.setFile(buildSpec.stagingDir);
+// }
+
+
+/**
+ * Segregate product-building API's from module-building APIs for clarity.
+ * These are called by the superclass if the BuildSpec warrants.
+ * XXX extremely brittle/arbitrary assumptions.
+ * @see BuildModule for assumptions
+ */
+class ProductBuilder extends AntBuilder {
+
+ private static String getProductInstallResourcesSrc(BuildSpec buildSpec) {
+ final String resourcesName = "installer-resources"; // XXXFileLiteral
+ File dir = buildSpec.productDir.getParentFile();
+ String result = null;
+ if (null == dir) {
+ return "../../" + resourcesName;
+ }
+ dir = dir.getParentFile();
+ if (null == dir) {
+ return "../" + resourcesName;
+ } else {
+ dir = new File(dir, resourcesName);
+ return dir.getPath();
+ }
+ }
+
+ private static String getProductInstallerFileName(BuildSpec buildSpec) { // XXXFileLiteral
+ return "aspectj-"
+ + buildSpec.productDir.getName()
+ + "-"
+ + Util.shortVersion(buildSpec.version)
+ + ".jar";
+ }
+
+ /**
+ * Calculate name of main, typically InitialCap, and hence installer class.
+ * @return $$installer$$.org.aspectj." + ProductName + "Installer"
+ */
+
+ private static String getProductInstallerMainClass(BuildSpec buildSpec) {
+ String productName = buildSpec.productDir.getName();
+ String initial = productName.substring(0, 1).toUpperCase();
+ productName = initial + productName.substring(1);
+ return "$installer$.org.aspectj." + productName + "Installer"; // XXXNameLiteral
+ }
+
+ /** @see Builder.getBuilder(String, Project, File) */
+ ProductBuilder(
+ Project project,
+ File tempDir,
+ boolean useEclipseCompiles,
+ Messager handler) {
+ super(project, tempDir, useEclipseCompiles, handler);
+ }
+
+ /**
+ * 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
+ 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 = 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 buildInstaller(BuildSpec buildSpec, String targDirPath) {
+ if (buildSpec.verbose) {
+ handler.log("creating installer for " + buildSpec);
+ }
+ AJInstaller installer = new AJInstaller();
+ installer.setProject(project);
+ installer.setBasedir(targDirPath);
+ //installer.setCompress();
+ File installSrcDir = new File(buildSpec.productDir, "install"); // XXXFileLiteral
+ Util.iaxIfNotCanReadDir(installSrcDir, "installSrcDir");
+ installer.setHtmlSrc(installSrcDir.getPath());
+ String resourcePath = getProductInstallResourcesSrc(buildSpec);
+ File resourceSrcDir = new File(resourcePath);
+ Util.iaxIfNotCanReadDir(resourceSrcDir, "resourceSrcDir");
+ installer.setResourcesSrc(resourcePath);
+ String name = getProductInstallerFileName(buildSpec);
+ File outFile = new File(buildSpec.jarDir, name);
+ installer.setZipfile(outFile.getPath());
+ installer.setMainclass(getProductInstallerMainClass(buildSpec));
+ installer.setInstallerclassjar(getBuildJar(buildSpec));
+ return executeTask(installer);
+
+ // -- test installer XXX
+ // create text setup file
+ // run installer with setup file
+ // cleanup installed product
+ }
+
+ private String getBuildJar(BuildSpec buildSpec) {
+ return buildSpec.baseDir.getPath()
+ + "/lib/build/build.jar" ; // XXX
+ }
+
+ private Module moduleForReplaceFile(File replaceFile, Modules modules) {
+ String jarName = moduleAliasFor(replaceFile.getName().toLowerCase());
+ if (jarName.endsWith(".jar") || jarName.endsWith(".zip")) { // XXXFileLiteral
+ jarName = jarName.substring(0, jarName.length()-4);
+ } else {
+ throw new IllegalArgumentException("can only replace .[jar|zip]");
+ }
+ boolean assembleAll = jarName.endsWith("-all");
+ String name = (!assembleAll ? jarName : jarName.substring(0, jarName.length()-4));
+ return modules.getModule(name);
+ }
+
+}
+
+
+class ProjectMessager extends Messager {
+ private final Project project;
+ public ProjectMessager(Project project) {
+ Util.iaxIfNull(project, "project");
+ this.project = project;
+ }
+
+ public boolean log(String s) {
+ project.log(s);
+ return true;
+ }
+ public boolean error(String s) {
+ project.log(s, project.MSG_ERR);
+ return true;
+ }
+ public boolean logException(String context, Throwable thrown) {
+ project.log(context + Util.renderException(thrown), project.MSG_ERR);
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java
new file mode 100644
index 000000000..a0f56f1d6
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java
@@ -0,0 +1,156 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.Location;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.aspectj.internal.tools.build.BuildSpec;
+import org.aspectj.internal.tools.build.Builder;
+
+import java.io.File;
+
+/**
+ * Ant interface to build a product or module, including any required modules.
+ * @see Builder
+ */
+public class BuildModule extends Task { // quickie hack...
+
+ public static void main(String[] args) {
+ TestBuildModule.main(args);
+ }
+
+ private static File pathToFile(Path path) {
+ if (null != path) {
+ String[] list = path.list();
+ if ((null == list) || (1 != list.length)) {
+ throw new IllegalArgumentException("expected exactly 1 element");
+ }
+ return new File(list[0]);
+ }
+ return null;
+ }
+ BuildSpec buildSpec;
+
+ public BuildModule() {
+ buildSpec = new BuildSpec();
+ buildSpec.version = BuildSpec.BUILD_VERSION_DEFAULT;
+ }
+
+ public void setModuledir(Path moduleDir) {
+ buildSpec.moduleDir = pathToFile(moduleDir);
+ }
+
+ public void setModule(String module) { // XXX handle multiple modules, same builder
+ buildSpec.module = module;
+ }
+
+ public void setVersion(String version) {
+ buildSpec.version = version;
+ }
+ public void setBasedir(Path baseDir) {
+ buildSpec.baseDir = pathToFile(baseDir);
+ }
+
+ public void setJardir(Path jarDir) {
+ buildSpec.jarDir = pathToFile(jarDir);
+ }
+
+ public void setTrimtesting(boolean trimTesting) {
+ buildSpec.trimTesting = trimTesting;
+ }
+
+ public void setAssembleall(boolean assembleAll) {
+ buildSpec.assembleAll = assembleAll;
+ }
+
+ public void setRebuild(boolean rebuild) {
+ buildSpec.rebuild = rebuild;
+ }
+
+ public void setFailonerror(boolean failonerror) {
+ buildSpec.failonerror = failonerror;
+ }
+
+ public void setCreateinstaller(boolean create) {
+ buildSpec.createInstaller = create;
+ }
+
+ public void setVerbose(boolean verbose) {
+ buildSpec.verbose = verbose;
+ }
+
+ public void setBuildConfig(String buildConfig) {
+ buildSpec.buildConfig = buildConfig;
+ }
+
+ // --------------------------------------------------------- product build
+
+ public void setProductdir(Path productDir) {
+ buildSpec.productDir = pathToFile(productDir);
+ }
+
+ public void setTempdir(Path tempDir) {
+ buildSpec.tempDir = pathToFile(tempDir);
+ }
+
+ public void setDistdir(Path distdir) {
+ buildSpec.distDir = pathToFile(distdir);
+ }
+
+ public void execute() throws BuildException {
+ final BuildSpec buildSpec = this.buildSpec;
+ this.buildSpec = new BuildSpec();
+ build(buildSpec);
+ }
+
+ private void build(BuildSpec buildSpec) throws BuildException {
+ final boolean failonerror = buildSpec.failonerror;
+ Builder builder = null;
+ try {
+ File buildScript = new File(buildSpec.moduleDir, "build.xml"); // XXXFileLiteral
+ if (buildScript.canRead()) {
+ if (!buildByScript(buildSpec, buildScript)) {
+ log("unable to build " + buildSpec + " using script: " + buildScript);
+ }
+ } else {
+ builder = AntBuilder.getBuilder(
+ buildSpec.buildConfig,
+ getProject(),
+ buildSpec.tempDir);
+ if (!builder.build(buildSpec) && failonerror) {
+ Location loc = getLocation();
+ throw new BuildException("error building " + buildSpec, loc);
+ }
+ }
+ } catch (BuildException e) {
+ throw e;
+ } catch (Throwable t) {
+ Location loc = getLocation();
+ throw new BuildException("error building " + buildSpec, t, loc);
+ } finally {
+ if (null != builder) {
+ builder.cleanup();
+ }
+ }
+ }
+
+ boolean buildByScript(BuildSpec buildSpec, File buildScript)
+ throws BuildException {
+ return false;
+ }
+}
+ \ No newline at end of file
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/Checklics.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/Checklics.java
new file mode 100644
index 000000000..d79c9774f
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/Checklics.java
@@ -0,0 +1,735 @@
+/* *******************************************************************
+ * 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.*;
+import org.apache.tools.ant.types.*;
+import org.apache.tools.ant.taskdefs.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Check that included .java files contain license and copyright strings
+ * for MPL 1.0 (default), Apache, or CPL.
+ * Use list="true" to get a list of known license variants {license}-{copyrightHolder}
+ * todo reimplement with regexp and jdiff FileLine utilities
+ */
+public class Checklics extends MatchingTask {
+ /*
+ This does not enforce that copyrights are correct/current,
+ only that they exist.
+ E.g., the default behavior requires MPL but permits either
+ Xerox or PARC copyright holders and any valid year.
+ */
+ public static final String MPL_TAG = "mpl";
+ public static final String APACHE_TAG = "apache";
+ public static final String CPL_IBM_PARC_TAG = "cpl-ibm|parc";
+ public static final String CPL_IBM_TAG = "cpl-ibm";
+ public static final String MPL_XEROX_PARC_TAG = "mpl-parc|xerox";
+ public static final String MPL_ONLY_TAG = "mpl-only";
+ public static final String MPL_PARC_TAG = "mpl-parc";
+ public static final String PARC_COPYRIGHT_TAG = "parc-copy";
+ public static final String CPL_IBM_PARC_XEROX_TAG = "cpl-ibm|parc|xerox";
+ public static final String DEFAULT = CPL_IBM_PARC_XEROX_TAG;
+
+ static final Hashtable LICENSES; // XXX unmodifiable Map
+
+ static {
+ final String XEROX = "Xerox";
+ final String PARC = "Palo Alto Research Center";
+ final String APACHE = "The Apache Software Foundation";
+ final String IBM = "IBM";
+ final String IBM_LONG = "International Business Machines";
+ final String LIC_APL =
+ "Apache Software Foundation (http://www.apache.org/)";
+ // XXX
+ final String LIC_MPL = "http://aspectj.org/MPL/";
+ //final String LIC_CPL = "http://www.eclipse.org/legal/cpl-v"; // XXX not versioned
+ final String LIC_CPL = "Common Public License";
+ // XXX not versioned
+ License APL = new License(APACHE_TAG, LIC_APL, APACHE);
+ License MPL = new License(MPL_TAG, LIC_MPL, XEROX);
+ License MPL_XEROX_PARC = new License(DEFAULT, LIC_MPL, XEROX, PARC);
+ License CPL_IBM_PARC = new License(CPL_IBM_PARC_TAG,LIC_CPL,
+ new String[] { IBM_LONG, IBM, PARC });
+ License CPL_IBM_PARC_XEROX = new License(CPL_IBM_PARC_XEROX_TAG,LIC_CPL,
+ new String[] { IBM_LONG, IBM, PARC, XEROX });
+ License CPL_IBM = new License(CPL_IBM_TAG, LIC_CPL, IBM, IBM_LONG);
+ License MPL_ONLY = new License(MPL_ONLY_TAG, LIC_MPL);
+ License MPL_PARC = new License(MPL_PARC_TAG, LIC_MPL, PARC);
+ License PARC_COPYRIGHT = new License(PARC_COPYRIGHT_TAG, null, PARC);
+ LICENSES = new Hashtable();
+ LICENSES.put(APL.tag, APL);
+ LICENSES.put(MPL.tag, MPL);
+ LICENSES.put(MPL_PARC.tag, MPL_PARC);
+ LICENSES.put(MPL_XEROX_PARC.tag, MPL_XEROX_PARC);
+ LICENSES.put(CPL_IBM_PARC.tag, CPL_IBM_PARC);
+ LICENSES.put(MPL_ONLY.tag, MPL_ONLY);
+ LICENSES.put(CPL_IBM.tag, CPL_IBM);
+ LICENSES.put(PARC_COPYRIGHT.tag, PARC_COPYRIGHT);
+ LICENSES.put(CPL_IBM_PARC_XEROX.tag, CPL_IBM_PARC_XEROX);
+ }
+
+ /** @param args String[] { &lt; sourcepath &gt; {, &lt; licenseTag &gt; } } */
+ public static void main(String[] args) {
+ switch (args.length) {
+ case 1 : runDirect(args[0], null);
+ break;
+ case 2 : runDirect(args[0], args[1]);
+ break;
+ default:
+ String options = "{replace-headers|get-years|list|{licenseTag}}";
+ System.err.println("java {me} sourcepath " + options);
+ break;
+ }
+ }
+
+ /**
+ * Run the license check directly
+ * @param sourcepaths String[] of paths to source directories
+ * @param license the String tag for the license, if any
+ * @throws IllegalArgumentException if sourcepaths is empty
+ * @return total number of failed licenses
+ */
+ public static int runDirect(String sourcepath, String license) {
+ if ((null == sourcepath) || (1 > sourcepath.length())) {
+ throw new IllegalArgumentException("bad sourcepath: " + sourcepath);
+ }
+ Checklics me = new Checklics();
+ Project p = new Project();
+ p.setName("direct interface to Checklics");
+ p.setBasedir(".");
+ me.setProject(p);
+ me.setSourcepath(new Path(p, sourcepath));
+ if (null != license) {
+ if ("replace-headers".equals(license)) {
+ me.setReplaceheaders(true);
+ } else if ("get-years".equals(license)) {
+ me.setGetYears(true);
+ } else if ("list".equals(license)) {
+ me.setList(true);
+ } else {
+ me.setLicense(license);
+ }
+ }
+ me.execute();
+ return me.failed;
+ }
+
+ private Path sourcepath;
+ private License license;
+ private boolean list;
+ private String streamTag;
+ private boolean failOnError;
+ private boolean getYears;
+ private boolean replaceHeaders;
+ private int passed;
+ private int failed;
+
+ private boolean printDirectories;
+
+ /** @param list if true, don't run but list known license tags */
+ public void setList(boolean list) {
+ this.list = list;
+ }
+
+ public void setPrintDirectories(boolean print) {
+ printDirectories = print;
+ }
+
+ /**
+ * When failOnError is true, if any file failed, throw BuildException
+ * listing number of files that file failed to pass license check
+ * @param fail if true, report errors by throwing BuildException
+ */
+ public void setFailOnError(boolean fail) {
+ this.failOnError = fail;
+ }
+
+ /** @param tl mpl | apache | cpl */
+ public void setLicense(String tl) {
+ License input = (License) LICENSES.get(tl);
+ if (null == input) {
+ throw new BuildException("no license known for " + tl);
+ }
+ license = input;
+ }
+
+ public void setSourcepath(Path path) {
+ if (sourcepath == null) {
+ sourcepath = path;
+ } else {
+ sourcepath.append(path);
+ }
+ }
+
+ public Path createSourcepath() {
+ return sourcepath == null
+ ? (sourcepath = new Path(project))
+ : sourcepath.createPath();
+ }
+
+ public void setSourcepathRef(Reference id) {
+ createSourcepath().setRefid(id);
+ }
+
+ /** @param out "out" or "err" */
+ public void setOutputStream(String out) {
+ this.streamTag = out;
+ }
+
+ public void setReplaceheaders(boolean replaceHeaders) {
+ this.replaceHeaders = replaceHeaders;
+ }
+
+ public void setGetYears(boolean getYears) {
+ this.getYears = getYears;
+ }
+
+ /** list known licenses or check source tree */
+ public void execute() throws BuildException {
+ if (list) {
+ list();
+ } else if (replaceHeaders) {
+ replaceHeaders();
+ } else if (getYears) {
+ getYears();
+ } else {
+ checkLicenses();
+ }
+ }
+
+ private PrintStream getOut() {
+ return ("err".equals(streamTag) ? System.err : System.out);
+ }
+
+ interface FileVisitor {
+ void visit(File file);
+ }
+
+ /** visit all .java files in all directories... */
+ private void visitAll(FileVisitor visitor) {
+ List filelist = new ArrayList();
+ String[] dirs = sourcepath.list();
+ for (int i = 0; i < dirs.length; i++) {
+ File dir = project.resolveFile(dirs[i]);
+ String[] files = getDirectoryScanner(dir).getIncludedFiles();
+ for (int j = 0; j < files.length; j++) {
+ File file = new File(dir, files[j]);
+ String path = file.getPath();
+ if (path.endsWith(".java")) {
+ visitor.visit(file);
+ }
+ }
+ }
+ }
+
+ private void replaceHeaders() {
+ class YearVisitor implements FileVisitor {
+ public void visit(File file) {
+ HeaderInfo info = Header.checkFile(file);
+ if (!Header.replaceHeader(file, info)) {
+ throw new BuildException("failed to replace header for " + file
+ + " using " + info);
+ }
+ }
+ }
+ visitAll(new YearVisitor());
+ }
+
+ private void getYears() {
+ final PrintStream out = getOut();
+ class YearVisitor implements FileVisitor {
+ public void visit(File file) {
+ HeaderInfo info = Header.checkFile(file);
+ out.println(info.toString());
+ }
+ }
+ visitAll(new YearVisitor());
+ }
+
+ private void checkLicenses() throws BuildException {
+ if (null == license) {
+ setLicense(DEFAULT);
+ }
+ final License license = this.license; // being paranoid...
+ if (null == license) {
+ throw new BuildException("no license");
+ }
+ final PrintStream out = getOut();
+
+ class Visitor implements FileVisitor {
+ int failed = 0;
+ int passed = 0;
+ public void visit(File file) {
+ if (license.checkFile(file)) {
+ passed++;
+ } else {
+ failed++;
+ String path = file.getPath();
+ if (!license.foundLicense()) {
+ out.println(
+ license.tag + " LICENSE FAIL: " + path);
+ }
+ if (!license.foundCopyright()) {
+ out.println(
+ license.tag + " COPYRIGHT FAIL: " + path);
+ }
+ }
+ }
+ }
+ Visitor visitor = new Visitor();
+ visitAll(visitor);
+ getOut().println(
+ "Total passed: "
+ + visitor.passed
+ + (visitor.failed == 0 ? "" : " failed: " + visitor.failed));
+ if (failOnError && (0 < visitor.failed)) {
+ throw new BuildException(
+ failed + " files failed license check");
+ }
+ }
+
+ private void oldrun() throws BuildException {
+ if (list) {
+ list();
+ return;
+ }
+ if (null == license) {
+ setLicense(DEFAULT);
+ }
+ final License license = this.license; // being paranoid...
+ if (null == license) {
+ throw new BuildException("no license");
+ }
+ final PrintStream out = getOut();
+
+ List filelist = new ArrayList();
+ String[] dirs = sourcepath.list();
+ failed = 0;
+ passed = 0;
+ for (int i = 0; i < dirs.length; i++) {
+ int dirFailed = 0;
+ int dirPassed = 0;
+ File dir = project.resolveFile(dirs[i]);
+ String[] files = getDirectoryScanner(dir).getIncludedFiles();
+ for (int j = 0; j < files.length; j++) {
+ File file = new File(dir, files[j]);
+ String path = file.getPath();
+ if (path.endsWith(".java")) {
+ if (license.checkFile(file)) {
+ dirPassed++;
+ } else {
+ dirFailed++;
+ if (!license.foundLicense()) {
+ out.println(
+ license.tag + " LICENSE FAIL: " + path);
+ }
+ if (!license.foundCopyright()) {
+ out.println(
+ license.tag + " COPYRIGHT FAIL: " + path);
+ }
+ }
+ }
+ }
+ if (printDirectories) {
+ out.println(
+ "dir: "
+ + dirs[i]
+ + " passed: "
+ + dirPassed
+ + (dirFailed == 0 ? "" : " failed: " + dirFailed));
+ }
+ failed += dirFailed;
+ passed += dirPassed;
+ }
+ }
+
+ private void list() {
+ Enumeration enum = LICENSES.keys();
+ StringBuffer sb = new StringBuffer();
+ sb.append("known license keys:");
+ boolean first = true;
+ while (enum.hasMoreElements()) {
+ sb.append((first ? " " : ", ") + enum.nextElement());
+ if (first) {
+ first = false;
+ }
+ }
+ getOut().println(sb.toString());
+ }
+
+
+ /**
+ * Encapsulate license and copyright specifications
+ * to check files use hokey string matching.
+ */
+ public static class License {
+ /** acceptable years for copyright prefix to company - append " " */
+ static final String[] YEARS = // XXX remove older after license xfer?
+ new String[] { "2002 ", "2003 ", "2001 ", "2000 ", "1999 " };
+ public final String tag;
+ public final String license;
+ private final String[] copyright;
+ private boolean gotLicense;
+ private boolean gotCopyright;
+
+ License(String tag, String license) {
+ this(tag, license, (String[]) null);
+ }
+
+ License(String tag, String license, String copyright) {
+ this(tag, license, new String[] { copyright });
+ }
+
+ License(
+ String tag,
+ String license,
+ String copyright,
+ String altCopyright) {
+ this(tag, license, new String[] { copyright, altCopyright });
+ }
+
+ License(String tag, String license, String[] copyright) {
+ this.tag = tag;
+ if ((null == tag) || (0 == tag.length())) {
+ throw new IllegalArgumentException("null tag");
+ }
+ this.license = license;
+ this.copyright = copyright;
+ }
+
+ public final boolean gotValidFile() {
+ return foundLicense() && foundCopyright();
+ }
+
+ /** @return true if no license sought or if some license found */
+ public final boolean foundLicense() {
+ return ((null == license) || gotLicense);
+ }
+
+ /** @return true if no copyright sought or if some copyright found */
+ public final boolean foundCopyright() {
+ return ((null == copyright) || gotCopyright);
+ }
+
+ public boolean checkFile(final File file) {
+ clear();
+ boolean result = false;
+ BufferedReader input = null;
+ int lineNum = 0;
+ try {
+ input = new BufferedReader(new FileReader(file));
+ String line;
+ while (!gotValidFile()
+ && (line = input.readLine()) != null) {
+ lineNum++;
+ checkLine(line);
+ }
+ } catch (IOException e) {
+ System.err.println(
+ "reading line " + lineNum + " of " + file);
+ e.printStackTrace(System.err);
+ } finally {
+ if (null != input) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ } // ignore
+ }
+ }
+ return gotValidFile();
+ }
+
+ public String toString() {
+ return tag;
+ }
+
+ private void checkLine(String line) {
+ if ((null == line) || (0 == line.length())) {
+ return;
+ }
+ if (!gotLicense
+ && (null != license)
+ && (-1 != line.indexOf(license))) {
+ gotLicense = true;
+ }
+ if (!gotCopyright && (null != copyright)) {
+ int loc;
+ for (int j = 0;
+ !gotCopyright && (j < YEARS.length);
+ j++) {
+ if (-1 != (loc = line.indexOf(YEARS[j]))) {
+ loc += YEARS[j].length();
+ String afterLoc = line.substring(loc).trim();
+ for (int i = 0;
+ !gotCopyright && (i < copyright.length);
+ i++) {
+ if (0 == afterLoc.indexOf(copyright[i])) {
+ gotCopyright = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void clear() {
+ if (gotLicense) {
+ gotLicense = false;
+ }
+ if (gotCopyright) {
+ gotCopyright = false;
+ }
+ }
+ } // class License
+}
+
+class HeaderInfo {
+ /** File for which this is the info */
+ public final File file;
+
+ /** unmodifiable List of String years */
+ public final List years;
+
+ /** last line of license */
+ public final int lastLine;
+
+ /** last line of license */
+ public final boolean hasLicense;
+
+ public HeaderInfo(File file, int lastLine, List years, boolean hasLicense) {
+ this.lastLine = lastLine;
+ this.file = file;
+ this.hasLicense = hasLicense;
+ List newYears = new ArrayList();
+ newYears.addAll(years);
+ Collections.sort(newYears);
+ this.years = Collections.unmodifiableList(newYears);
+ if ((null == file) || !file.canWrite()) {
+ throw new IllegalArgumentException("bad file: " + this);
+ }
+ if (!hasLicense) {
+ if ((0> lastLine) || (65 < lastLine)) {
+ throw new IllegalArgumentException("bad last line: " + this);
+ }
+ } else {
+ if ((null == years) || (1 > years.size())) {
+ throw new IllegalArgumentException("no years: " + this);
+ }
+ if ((20 > lastLine) || (65 < lastLine)) {
+ throw new IllegalArgumentException("bad last line: " + this);
+ }
+ }
+ }
+
+ public String toString() {
+ return file.getPath() + ":" + lastLine + " " + years;
+ }
+
+ public void writeHeader(PrintWriter writer) {
+ if (!hasLicense) {
+ writer.println(TOP);
+ writer.println(PARC_ONLY);
+ writeRest(writer);
+ } else {
+ final int size = years.size();
+ if (1 > size) {
+ throw new Error("no years found in " + toString());
+ }
+ String first = (String) years.get(0);
+ String last = (String) years.get(size-1);
+ boolean lastIs2002 = "2002".equals(last);
+ String xlast = last;
+ if (lastIs2002) { // 2002 was PARC
+ xlast = (String) (size > 1 ? years.get(size-2) : null);
+ // 1999-2002 Xerox implies 1999-2001 Xerox
+ if (first.equals(xlast) && !"2001".equals(xlast)) {
+ xlast = "2001";
+ }
+ }
+ String xyears = first + "-" + xlast;
+ if (first.equals(last)) {
+ xyears = first;
+ }
+
+ writer.println(TOP);
+ if (!lastIs2002) { // Xerox only
+ writer.println(XEROX_PREFIX + xyears + XEROX_SUFFIX + ". ");
+ } else if (size == 1) { // PARC only
+ writer.println(PARC_ONLY);
+ } else { // XEROX plus PARC
+ writer.println(XEROX_PREFIX + xyears + XEROX_SUFFIX + ", ");
+ writer.println(PARC);
+ }
+ writeRest(writer);
+ }
+ }
+
+ void writeRest(PrintWriter writer) {
+ writer.println(" * All rights reserved. ");
+ writer.println(" * This program and the accompanying materials are made available ");
+ writer.println(" * under the terms of the Common Public License v1.0 ");
+ writer.println(" * which accompanies this distribution and is available at ");
+ writer.println(" * http://www.eclipse.org/legal/cpl-v10.html ");
+ writer.println(" * ");
+ writer.println(" * Contributors: ");
+ writer.println(" * Xerox/PARC initial implementation ");
+ writer.println(" * ******************************************************************/");
+ writer.println("");
+ }
+
+ public static final String TOP
+ = "/* *******************************************************************";
+ public static final String PARC
+ = " * 2002 Palo Alto Research Center, Incorporated (PARC).";
+ public static final String PARC_ONLY
+ = " * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).";
+ public static final String XEROX_PREFIX
+ = " * Copyright (c) ";
+ public static final String XEROX_SUFFIX
+ = " Xerox Corporation";
+ /*
+/* *******************************************************************
+ * Copyright (c) 1998-2001 Xerox Corporation,
+ * 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
+ * ******************************************************************
+
+ */
+}
+
+/**
+ * header search/replace using hokey string matching
+ */
+class Header {
+
+ /** replace the header in file */
+ public static boolean replaceHeader(File file, HeaderInfo info) {
+ ArrayList years = new ArrayList();
+ int endLine = 0;
+ BufferedReader input = null;
+ PrintWriter output = null;
+ FileWriter outWriter = null;
+ int lineNum = 0;
+ boolean result = false;
+ final File inFile = new File(file.getPath() + ".tmp");
+ try {
+ File outFile = new File(file.getPath());
+ if (!file.renameTo(inFile) || !inFile.canRead()) {
+ throw new Error("unable to rename " + file + " to " + inFile);
+ }
+ outWriter = new FileWriter(outFile);
+ input = new BufferedReader(new FileReader(inFile));
+ output = new PrintWriter(outWriter, true);
+ info.writeHeader(output);
+ String line;
+ while (null != (line = input.readLine())) {
+ lineNum++;
+ if (lineNum > info.lastLine) {
+ output.println(line);
+ }
+ }
+ } catch (IOException e) {
+ System.err.println(
+ "writing line " + lineNum + " of " + file);
+ e.printStackTrace(System.err);
+ result = false;
+ } finally {
+ if (null != input) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ result = false;
+ }
+ }
+ if (null != outWriter) {
+ try {
+ outWriter.close();
+ } catch (IOException e) {
+ result = false;
+ }
+ }
+ result = inFile.delete();
+ }
+ return result;
+ }
+
+ public static HeaderInfo checkFile(final File file) {
+ ArrayList years = new ArrayList();
+ int endLine = 0;
+ BufferedReader input = null;
+ int lineNum = 0;
+ try {
+ input = new BufferedReader(new FileReader(file));
+ String line;
+ while (null != (line = input.readLine())) {
+ lineNum++;
+ String ll = line.trim();
+ if (ll.startsWith("package ")
+ || ll.startsWith("import ")) {
+ break; // ignore default package w/o imports
+ }
+ if (checkLine(line, years)) {
+ endLine = lineNum;
+ break;
+ }
+ }
+ } catch (IOException e) {
+ System.err.println(
+ "reading line " + lineNum + " of " + file);
+ e.printStackTrace(System.err);
+ } finally {
+ if (null != input) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ } // ignore
+ }
+ }
+ return new HeaderInfo(file, endLine, years, endLine > 0);
+ }
+
+ /**
+ * Add any years found (as String) to years,
+ * and return true at the first end-of-comment
+ * @return true if this line has end-of-comment
+ */
+ private static boolean checkLine(String line, ArrayList years) {
+ if ((null == line) || (0 == line.length())) {
+ return false;
+ }
+ int loc;
+ int start = 0;
+
+ while ((-1 != (loc = line.indexOf("199", start))
+ || (-1 != (loc = line.indexOf("200", start))))) {
+ char c = line.charAt(loc + 3);
+ if ((c <= '9') && (c >= '0')) {
+ years.add(line.substring(loc, loc+4));
+ }
+ start = loc + 4;
+ }
+
+ return (-1 != line.indexOf("*/"));
+ }
+
+} // class Header
+
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/ConditionalTask.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/ConditionalTask.java
new file mode 100644
index 000000000..8b5184121
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/ConditionalTask.java
@@ -0,0 +1,182 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.*;
+import java.util.*;
+
+public abstract class ConditionalTask extends Task {
+
+ public final static String TRUE = "true";
+
+ private List ifs;
+ protected List ifs() {
+ return ifs != null ? ifs : (ifs = new Vector());
+ }
+
+ public If createIf() {
+ If i = new If();
+ ifs().add(i);
+ return i;
+ }
+
+ public If createIf(String name, String equals, boolean strict) {
+ If i = createIf();
+ i.setName(name);
+ i.setEquals(equals);
+ i.setStrict(strict);
+ return i;
+ }
+
+ public If createIf(String name, String equals) {
+ return createIf(name, equals, false);
+ }
+
+ public If createIf(String name) {
+ return createIf(name, TRUE, false);
+ }
+
+ public If createIf(String name, boolean strict) {
+ return createIf(name, TRUE, strict);
+ }
+
+ public void setIfs(String ifs) {
+ StringTokenizer tok = new StringTokenizer(ifs, ",;: ", false);
+ while (tok.hasMoreTokens()) {
+ String next = tok.nextToken();
+ int iequals = next.lastIndexOf("=");
+ String equals;
+ String name;
+ boolean strict;
+ If i = createIf();
+ if (iequals != -1) {
+ name = next.substring(0, iequals);
+ equals = next.substring(iequals + 1);
+ strict = true;
+ } else {
+ name = next.substring(0);
+ equals = TRUE;
+ strict = false;
+ }
+ i.setName(name);
+ i.setEquals(equals);
+ i.setStrict(strict);
+ }
+ }
+
+ public void setIf(String ifStr) {
+ setIfs(ifStr);
+ }
+
+ public class If {
+ public If() {
+ this(null, null);
+ }
+ public If(String name) {
+ this(name, TRUE);
+ }
+ public If(String name, String equals) {
+ setName(name);
+ setEquals(equals);
+ }
+ private String name;
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ return name;
+ }
+ private String equals;
+ public void setEquals(String equals) {
+ this.equals = equals;
+ }
+ public String getEquals() {
+ return equals;
+ }
+ private boolean strict = false;
+ public void setStrict(boolean strict) {
+ this.strict = strict;
+ }
+ public boolean isStrict() {
+ return strict;
+ }
+ public boolean isOk(String prop) {
+ return isOk(prop, isStrict());
+ }
+ //XXX Need a better boolean parser
+ public boolean isOk(String prop, boolean isStrict) {
+ if (isStrict) {
+ return prop != null && prop.equals(getEquals());
+ } else {
+ if (isOk(prop, true)) {
+ return true;
+ }
+ if (prop == null || isFalse(getEquals())) {
+ return true;
+ }
+ if ( (isTrue(getEquals()) && isTrue(prop)) ||
+ (isFalse(getEquals()) && isFalse(prop)) ) {
+ return true;
+ }
+ return false;
+ }
+ }
+ private boolean isFalse(String prop) {
+ return isOneOf(prop, falses) || isOneOf(prop, complement(trues));
+ }
+ private boolean isTrue(String prop) {
+ return isOneOf(prop, trues) || isOneOf(prop, complement(falses));
+ }
+ private boolean isOneOf(String prop, String[] strings) {
+ for (int i = 0; i < strings.length; i++) {
+ if (strings[i].equals(prop)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ private String[] complement(String[] strings) {
+ for (int i = 0; i < strings.length; i++) {
+ strings[i] = "!" + strings[i];
+ }
+ return strings;
+ }
+ }
+
+ final static String[] falses = { "false", "no" };
+ final static String[] trues = { "true", "yes" };
+
+ protected boolean checkIfs() {
+ return getFalses().size() == 0;
+ }
+
+ protected List getFalses() {
+ Iterator iter = ifs().iterator();
+ List result = new Vector();
+ while (iter.hasNext()) {
+ If next = (If) iter.next();
+ String name = next.getName();
+ String prop = project.getProperty(name);
+ if (prop == null) {
+ prop = project.getUserProperty(name);
+ }
+ if (!next.isOk(prop)) {
+ result.add(name);
+ }
+ }
+ return result;
+ }
+
+ public abstract void execute() throws BuildException;
+}
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/CopyAndInlineStylesheet.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/CopyAndInlineStylesheet.java
new file mode 100644
index 000000000..bafe5da2b
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/CopyAndInlineStylesheet.java
@@ -0,0 +1,113 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.*;
+import org.apache.tools.ant.taskdefs.*;
+import java.io.*;
+
+public class CopyAndInlineStylesheet extends Task {
+
+ private File file;
+ public void setFile(String file) {
+ this.file = project.resolveFile(file);
+ }
+
+ private File todir;
+ public void setTodir(String todir) {
+ this.todir = project.resolveFile(todir);
+ }
+
+
+ public void execute() throws BuildException {
+ try {
+ if (todir == null) {
+ throw new BuildException("must set 'todir' attribute");
+ }
+ if (file == null) {
+ throw new BuildException("must set 'file' attribute");
+ }
+ log("copying html from" + file + " to " + todir.getAbsolutePath());
+
+ File toFile = new File(todir, file.getName());
+
+ Mkdir mkdir = (Mkdir) project.createTask("mkdir");
+ mkdir.setDir(todir);
+ mkdir.execute();
+
+ BufferedReader in = new BufferedReader(new FileReader(file));
+ PrintStream out = new PrintStream(new FileOutputStream(toFile));
+
+ outer:
+ while (true) {
+ String line = in.readLine();
+ if (line == null) break;
+ if (isStyleSheet(line)) {
+ doStyleSheet(line, out, file);
+ while (true) {
+ String line2 = in.readLine();
+ if (line2 == null) break outer;
+ out.println(line2);
+ }
+ } else {
+ out.println(line);
+ }
+ }
+
+ in.close();
+ out.close();
+ } catch (IOException e) {
+ throw new BuildException(e.getMessage());
+ }
+ }
+
+ private static void doStyleSheet(String line, PrintStream out, File file) throws IOException {
+ int srcIndex = line.indexOf("href");
+ int startQuotIndex = line.indexOf('"', srcIndex);
+ int endQuotIndex = line.indexOf('"', startQuotIndex + 1);
+
+ String stylesheetLocation = line.substring(startQuotIndex + 1, endQuotIndex);
+
+ File styleSheetFile = new File(file.getParent(), stylesheetLocation);
+
+ out.println("<style type=\"text/css\">");
+ out.println("<!--");
+
+ BufferedReader inStyle = new BufferedReader(new FileReader(styleSheetFile));
+
+ while (true) {
+ String line2 = inStyle.readLine();
+ if (line2 == null) break;
+ out.println(line2);
+ }
+ inStyle.close();
+
+ out.println("-->");
+ out.println("</style>");
+ }
+
+
+ private static boolean isStyleSheet(String line) throws IOException {
+ line = line.toLowerCase();
+ int len = line.length();
+ int i = 0;
+
+ while (true) {
+ if (i == len) return false;
+ if (! Character.isWhitespace(line.charAt(i))) break;
+ }
+
+ return line.startsWith("<link", i);
+ }
+}
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/StripNonBodyHtml.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/StripNonBodyHtml.java
new file mode 100644
index 000000000..0a019707c
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/StripNonBodyHtml.java
@@ -0,0 +1,233 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.*;
+import org.apache.tools.ant.taskdefs.*;
+import java.io.*;
+
+/**
+ * Task to convert html source files into files with only body content.
+ *
+ * <p> This task can take the following arguments:</p>
+ *
+ * <ul>
+ * <li>srcdir</li>
+ * <li>destdir</li>
+ * <li>include</li>
+ * <li>exclude</li>
+ * </ul>
+ *
+ * <p>Of these arguments, only <b>sourcedir</b> is required.</p>
+ *
+ * <p> When this task executes, it will scan the srcdir based on the
+ * include and exclude properties.</p>
+ */
+
+public class StripNonBodyHtml extends MatchingTask {
+
+ private File srcDir;
+ private File destDir = null;
+
+ public void setSrcdir(File srcDir) {
+ this.srcDir = srcDir;
+ }
+
+ public void setDestdir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ public void execute() throws BuildException {
+ if (srcDir == null) {
+ throw new BuildException("srcdir attribute must be set!");
+ }
+ if (!srcDir.exists()) {
+ throw new BuildException("srcdir does not exist!");
+ }
+ if (!srcDir.isDirectory()) {
+ throw new BuildException("srcdir is not a directory!");
+ }
+ if (destDir != null) {
+ if (!destDir.exists()) {
+ throw new BuildException("destdir does not exist!");
+ }
+ if (!destDir.isDirectory()) {
+ throw new BuildException("destdir is not a directory!");
+ }
+ }
+
+ DirectoryScanner ds = super.getDirectoryScanner(srcDir);
+ String[] files = ds.getIncludedFiles();
+
+ log("stripping " + files.length + " files");
+ int stripped = 0;
+ for (int i = 0, len = files.length; i < len; i++) {
+ if (processFile(files[i])) {
+ stripped++;
+ } else {
+ log(files[i] + " not stripped");
+ }
+ }
+ log(stripped + " files successfully stripped");
+ }
+
+ boolean processFile(String filename) throws BuildException {
+ File srcFile = new File(srcDir, filename);
+ File destFile;
+ if (destDir == null) {
+ destFile = srcFile;
+ } else {
+ destFile = new File(destDir, filename);
+ destFile.getParentFile().mkdirs();
+ }
+ try {
+ return strip(srcFile, destFile);
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ private boolean strip(File f, File g) throws IOException {
+ BufferedInputStream in =
+ new BufferedInputStream(new FileInputStream(f));
+ String s = readToString(in);
+ in.close();
+ return writeBodyTo(s, g);
+ }
+
+ private ByteArrayOutputStream temp = new ByteArrayOutputStream();
+ private byte[] buf = new byte[2048];
+
+ private String readToString(InputStream in) throws IOException {
+ ByteArrayOutputStream temp = this.temp;
+ byte[] buf = this.buf;
+ String s = "";
+ try {
+ while (true) {
+ int i = in.read(buf, 0, 2048);
+ if (i == -1) break;
+ temp.write(buf, 0, i);
+
+ }
+ s = temp.toString();
+ } finally {
+ temp.reset();
+ }
+ return s;
+ }
+
+ private boolean writeBodyTo(String s, File f) throws IOException {
+ int start, end;
+ try {
+ start = findStart(s);
+ end = findEnd(s, start);
+ } catch (ParseException e) {
+ return false; // if we get confused, just don't write the file.
+ }
+ s = processBody(s,f);
+ BufferedOutputStream out =
+ new BufferedOutputStream(new FileOutputStream(f));
+
+ out.write(s.getBytes());
+ out.close();
+ return true;
+ }
+
+ /**
+ * Process body. This implemenation strips text
+ * between &lt!-- start strip --&gt
+ * and &lt!-- end strip --&gt
+ * inclusive.
+ */
+ private String processBody(String body, File file) {
+ if (null == body) return body;
+ final String START = "<!-- start strip -->";
+ final String END = "<!-- end strip -->";
+ return stripTags(body, file.toString(), START, END);
+ }
+
+ /**
+ * Strip 0..n substrings in input: "s/${START}.*${END}//g"
+ * @param input the String to strip
+ * @param source the name of the source for logging purposes
+ * @param start the starting tag (case sensitive)
+ * @param end the ending tag (case sensitive)
+ */
+ String stripTags(String input, final String SOURCE,
+ final String START, final String END) {
+ if (null == input) return input;
+ StringBuffer buffer = new StringBuffer(input.length());
+ String result = input;
+ int curLoc = 0;
+ while (true) {
+ int startLoc = input.indexOf(START, curLoc);
+ if (-1 == startLoc) {
+ buffer.append(input.substring(curLoc));
+ result = buffer.toString();
+ break; // <------------ valid exit
+ } else {
+ int endLoc = input.indexOf(END, startLoc);
+ if (-1 == endLoc) {
+ log(SOURCE + " stripTags - no end tag - startLoc=" + startLoc);
+ break; // <------------ invalid exit
+ } else if (endLoc < startLoc) {
+ log(SOURCE + " stripTags - impossible: startLoc="
+ + startLoc + " > endLoc=" + endLoc);
+ break; // <------------ invalid exit
+ } else {
+ buffer.append(input.substring(curLoc, startLoc));
+ curLoc = endLoc + END.length();
+ }
+ }
+ }
+ return result;
+ }
+
+ private int findStart(String s) throws ParseException {
+ int len = s.length();
+ int start = 0;
+ while (true) {
+ start = s.indexOf("<body", start);
+ if (start == -1) {
+ start = s.indexOf("<BODY", start);
+ if (start == -1) throw barf();
+ }
+ start = start + 5;
+ if (start >= len) throw barf();
+ char ch = s.charAt(start);
+ if (ch == '>') return start + 1;
+ if (Character.isWhitespace(ch)) {
+ start = s.indexOf('>', start);
+ if (start == -1) return -1;
+ return start + 1;
+ }
+ }
+ }
+
+ private int findEnd(String s, int start) throws ParseException {
+ int end;
+ end = s.indexOf("</body>", start);
+ if (end == -1) {
+ end = s.indexOf("</BODY>", start);
+ if (end == -1) throw barf();
+ }
+ return end;
+ }
+
+ private static class ParseException extends Exception {}
+
+ private static ParseException barf() {
+ return new ParseException();
+ }
+}
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/TestBuildModule.java b/build/src/org/aspectj/internal/tools/ant/taskdefs/TestBuildModule.java
new file mode 100644
index 000000000..374f71d79
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/TestBuildModule.java
@@ -0,0 +1,79 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.Project;
+import org.aspectj.internal.tools.build.*;
+import org.aspectj.internal.tools.build.BuildSpec;
+import org.aspectj.internal.tools.build.Util;
+
+import java.io.File;
+import java.util.Arrays;
+
+public class TestBuildModule {
+ private static boolean REBUILD = false;
+ private static final String SYNTAX = "java {classname} <[product|module]dir>";
+ public static void main(String[] args) {
+
+ if ((null == args) || (1 > args.length)
+ || !Util.canReadDir(new File(args[0]))) {
+ System.err.println(SYNTAX);
+ return;
+ }
+ File dir = new File(args[0]);
+ // create a module
+ if (Util.canReadDir(new File(dir, "dist"))) {
+ createProduct(args);
+ } else if (Util.canReadFile(new File(dir, ".classpath"))) {
+ createModule(args);
+ } else {
+ System.err.println(SYNTAX);
+ }
+ }
+
+ static void createModule(String[] args) {
+ File moduleDir = new File(args[0]);
+ File baseDir = moduleDir.getParentFile();
+ if (null == baseDir) {
+ baseDir = new File(".");
+ }
+ File jarDir = new File(baseDir, "aj-build-jars");
+ if (!(Util.canReadDir(jarDir) || jarDir.mkdirs())) {
+ System.err.println("unable to create " + jarDir);
+ return;
+ }
+
+ // set module dir or basedir plus module name
+ BuildSpec buildSpec = new BuildSpec();
+ buildSpec.moduleDir = moduleDir;
+ buildSpec.jarDir = jarDir;
+ buildSpec.verbose = true;
+ buildSpec.failonerror = true;
+ buildSpec.trimTesting = true;
+ buildSpec.rebuild = true;
+
+ File tempDir = null;
+ Project project = new Project();
+ project.setProperty("verbose", "true");
+ project.setName("TestBuildModule.createModule" + Arrays.asList(args));
+ Builder builder = AntBuilder.getBuilder("", project, tempDir);
+ builder.build(buildSpec);
+ }
+
+ static void createProduct(String[] args) {
+ throw new Error("unimplemented");
+ }
+}
+
diff --git a/build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties b/build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties
new file mode 100644
index 000000000..37da66e9e
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties
@@ -0,0 +1,20 @@
+ajinstaller=org.aspectj.internal.tools.ant.taskdefs.AJInstaller
+ajpush=org.aspectj.internal.tools.ant.taskdefs.AJPush
+ajbuild=org.aspectj.internal.tools.ant.taskdefs.BuildModule
+checklics=org.aspectj.internal.tools.ant.taskdefs.Checklics
+stripnonbodyhtml=org.aspectj.internal.tools.ant.taskdefs.StripNonBodyHtml
+
+# ajclean=org.aspectj.internal.tools.ant.taskdefs.AJclean
+# ajcvs=org.aspectj.internal.tools.ant.taskdefs.Ajcvs
+# ajikes=org.aspectj.internal.tools.ant.taskdefs.AJikes
+# ajinit=org.aspectj.internal.tools.ant.taskdefs.AjInit
+# checkrelease=org.aspectj.internal.tools.ant.taskdefs.Checkrelease
+# clear=org.aspectj.internal.tools.ant.taskdefs.Clear
+# inlinestylesheetaj=org.aspectj.internal.tools.ant.taskdefs.CopyAndInlineStyleshee
+# ensure=org.aspectj.internal.tools.ant.taskdefs.Ensure
+# ensureproperties=org.aspectj.internal.tools.ant.taskdefs.EnsureProperties
+# newdir=org.aspectj.internal.tools.ant.taskdefs.Newdir
+# overwrite=org.aspectj.internal.tools.ant.taskdefs.Overwrite
+# props2filters=org.aspectj.internal.tools.ant.taskdefs.Props2Filters
+# tgz=org.aspectj.internal.tools.ant.taskdefs.Tgz
+# vmcheck=org.aspectj.internal.tools.ant.taskdefs.VMCheck
diff --git a/build/src/org/aspectj/internal/tools/build/BuildSpec.java b/build/src/org/aspectj/internal/tools/build/BuildSpec.java
new file mode 100644
index 000000000..bf9ccdea8
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/BuildSpec.java
@@ -0,0 +1,161 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+
+/**
+ * Open struct for specifying builds for both modules and products.
+ * Separated from bulder to permit this to build many modules
+ * concurrently.
+ * 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;
+ }
+
+ // shared
+ public File baseDir;
+ public File moduleDir;
+ public File jarDir;
+ public File tempDir;
+ public File stagingDir;
+ public String buildConfig;
+ public String version;
+ public boolean rebuild;
+ public boolean trimTesting;
+ public boolean assembleAll;
+ public boolean failonerror;
+ public boolean verbose;
+
+ // building products
+ public File productDir;
+ public boolean createInstaller;
+ public File distDir;
+
+ // building modules
+ public String module;
+
+ public String toString() { // XXX better
+ if (null != productDir) {
+ return "product " + productDir.getName();
+ } else {
+ return "module " + moduleDir.getName();
+ }
+ }
+}
+
diff --git a/build/src/org/aspectj/internal/tools/build/Builder.java b/build/src/org/aspectj/internal/tools/build/Builder.java
new file mode 100644
index 000000000..19c2ecb4b
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/Builder.java
@@ -0,0 +1,497 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+import org.apache.tools.ant.BuildException;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+
+/**
+ * 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>
+ * <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>
+ * 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>
+ * <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>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>
+ * </ul>
+ * <p>
+ * 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.
+ */
+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();) {
+ 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;
+ }
+ 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);
+}
+
+
+
diff --git a/build/src/org/aspectj/internal/tools/build/Messager.java b/build/src/org/aspectj/internal/tools/build/Messager.java
new file mode 100644
index 000000000..c7b12d4a9
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/Messager.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+/** logging stub XXX replace */
+public class Messager {
+ public Messager() {
+ }
+ public boolean log(String s) {
+ System.out.println(s);
+ return true;
+ }
+
+ public boolean error(String s) {
+ System.out.println(s);
+ return true;
+ }
+
+ public boolean logException(String context, Throwable thrown) {
+ System.err.println(context);
+ thrown.printStackTrace(System.err);
+ return true;
+ }
+}
+
+
+
+
+
+
+
diff --git a/build/src/org/aspectj/internal/tools/build/Module.java b/build/src/org/aspectj/internal/tools/build/Module.java
new file mode 100644
index 000000000..9c6022d18
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/Module.java
@@ -0,0 +1,501 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+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;
+
+/**
+ * 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.
+ * This implementation infers attributes from two
+ * files in the module directory:
+ * <ul>
+ * <li>an Eclipse project <code>.classpath</code> file
+ * containing required libraries and modules
+ * (collectively, "antecedants")
+ * </li>
+ * <li>a file <code>{moduleName}.mf.txt</code> is taken as
+ * the manifest of any .jar file produced, after filtering.
+ * </li>
+ * </ul>
+ *
+ * @see Builder
+ * @see Modules#getModule(String)
+ */
+public class Module {
+
+ /** @return true if file is null or cannot be read or was
+ * last modified after time
+ */
+ private static boolean outOfDate(long time, File file) {
+ return ((null == file)
+ || !file.canRead()
+ || (file.lastModified() > time));
+ }
+
+ /** @return all source files under srcDir */
+ private static Iterator sourceFiles(File srcDir) {
+ ArrayList result = new ArrayList();
+ sourceFiles(srcDir, result);
+ return result.iterator();
+ }
+
+ private static void sourceFiles(File srcDir, List result) {
+ if ((null == srcDir) || !srcDir.canRead() || !srcDir.isDirectory()) {
+ return;
+ }
+ File[] files = srcDir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ sourceFiles(files[i], result);
+ } else if (isSourceFile(files[i])) {
+ result.add(files[i]);
+ }
+ }
+ }
+
+ /**
+ * Recursively find antecedant jars.
+ * @see findKnownJarAntecedants()
+ */
+ private static void doFindKnownJarAntecedants(Module module, ArrayList known) {
+ Util.iaxIfNull(module, "module");
+ Util.iaxIfNull(known, "known");
+
+ for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) {
+ File libJar = (File) iter.next();
+ if (!skipLibraryJarAntecedant(libJar)
+ && !known.contains(libJar)) { // XXX what if same referent, diff path...
+ known.add(libJar);
+ }
+ }
+ for (Iterator iter = module.getRequired().iterator(); iter.hasNext();) {
+ Module required = (Module) iter.next();
+ File requiredJar = required.getModuleJar();
+ if (!known.contains(requiredJar)) {
+ known.add(requiredJar);
+ doFindKnownJarAntecedants(required, known);
+ }
+ }
+ }
+
+ /** XXX gack explicitly skip Ant */
+ private static boolean skipLibraryJarAntecedant(File libJar) {
+ if (null == libJar) {
+ return true;
+ }
+ String path = libJar.getPath().replace('\\', '/');
+ return (-1 == path.indexOf("/lib/ant/lib/"));
+ }
+
+ /**@return true if this is a source file */
+ private static boolean isSourceFile(File file) {
+ String path = file.getPath();
+ return (path.endsWith(".java") || path.endsWith(".aj")); // XXXFileLiteral
+ }
+
+ public final boolean valid;
+
+ public final File moduleDir;
+
+ public final String name;
+
+ /** reference back to collection for creating required modules */
+ final Modules modules;
+
+ /** path to output jar - may not exist */
+ private final File moduleJar;
+
+ /** path to fully-assembed jar - may not exist */
+ private final File assembledJar;
+
+ /** File list of library jars */
+ private final List libJars;
+
+ /** File list of source directories */
+ private final List srcDirs;
+
+ /** properties from the modules {name}.properties file */
+ private final Properties properties;
+
+ /** Module list of required modules */
+ private final List required;
+
+ /** List of File that are newer than moduleJar. Null until requested */
+ //private List newerFiles;
+ /** 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;
+
+ /** if true, trim testing-related source directories, modules, and libraries */
+ private final boolean trimTesting;
+
+ /** logger */
+ private final Messager messager;
+
+ Module(File moduleDir,
+ File jarDir,
+ String name,
+ Modules modules,
+ boolean trimTesting,
+ 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.libJars = new ArrayList();
+ this.required = new ArrayList();
+ this.srcDirs = new ArrayList();
+ this.properties = new Properties();
+ this.name = name;
+ this.modules = modules;
+ this.messager = messager;
+ this.moduleJar = new File(jarDir, name + ".jar");
+ this.assembledJar = new File(jarDir, name + "-all.jar");
+ 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 required modules String names*/
+ public List getRequired() {
+ return Collections.unmodifiableList(required);
+ }
+
+ /** @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 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;
+ }
+ }
+ } finally {
+ outOfDateSet = true;
+ }
+ }
+ return outOfDate;
+ }
+ /**
+ * 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="
+ + libJars
+ + "]";
+ }
+
+ private boolean init() {
+ return initClasspath() && initProperties() && reviewInit();
+ }
+
+ /** read eclipse .classpath file XXX line-oriented hack */
+ private boolean initClasspath() {
+ // meaning testsrc directory, junit library, etc.
+ File file = new File(moduleDir, ".classpath"); // XXXFileLiteral
+ FileReader fin = null;
+ try {
+ fin = new FileReader(file);
+ BufferedReader reader = new BufferedReader(fin);
+ String line;
+ String lastKind = null;
+ while (null != (line = reader.readLine())) {
+ lastKind = parseLine(line, lastKind);
+ }
+ return (0 < srcDirs.size());
+ } catch (IOException e) {
+ messager.logException("IOException reading " + file, e);
+ } finally {
+ if (null != fin) {
+ try { fin.close(); }
+ catch (IOException e) {} // ignore
+ }
+ }
+ return false;
+ }
+
+ /** @return true if any properties were read correctly */
+ private boolean initProperties() {
+ File file = new File(moduleDir, name + ".properties"); // XXXFileLiteral
+ if (!Util.canReadFile(file)) {
+ return true; // no properties to read
+ }
+ FileInputStream fin = null;
+ try {
+ fin = new FileInputStream(file);
+ properties.load(fin);
+ return true;
+ } catch (IOException e) {
+ messager.logException("IOException reading " + file, e);
+ return false;
+ } finally {
+ if (null != fin) {
+ try { fin.close(); }
+ catch (IOException e) {} // ignore
+ }
+ }
+ }
+
+ /**
+ * Post-process initialization.
+ * This implementation trims testing-related source
+ * directories, libraries, and modules if trimTesting is enabled/true.
+ * To build testing modules, trimTesting must be false.
+ * @return true if initialization post-processing worked
+ */
+ protected boolean reviewInit() {
+ if (!trimTesting) {
+ return true;
+ }
+ try {
+ for (ListIterator iter = srcDirs.listIterator(); iter.hasNext();) {
+ File srcDir = (File) iter.next();
+ String name = srcDir.getName();
+ if ("testsrc".equals(name.toLowerCase())) { // XXXFileLiteral
+ iter.remove(); // XXX if verbose log
+ }
+ }
+ 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;
+ }
+
+ private String parseLine(String line, String lastKind) {
+ if (null == line) {
+ return null;
+ }
+ String kind;
+ int loc = line.indexOf("kind=\"");
+ if ((-1 == loc) || (loc + 9 > line.length())) {
+ // no kind string - fail unless have lastKind
+ if (null == lastKind) {
+ return null;
+ } else {
+ kind = lastKind;
+ }
+ } else { // have kind string - get kind
+ loc += 6; // past kind="
+ kind = line.substring(loc, loc+3);
+ }
+
+ // now look for value
+ loc = line.indexOf("path=\"");
+ if (-1 == loc) { // no value - return lastKind
+ return kind;
+ }
+ loc += 6; // past path="
+ int end = line.indexOf("\"", loc);
+ if (-1 == end) {
+ throw new Error("unterminated path in " + line);
+ }
+ final String path = line.substring(loc, end);
+
+ if ("src".equals(kind)) {
+ if (path.startsWith("/")) { // module
+ String moduleName = path.substring(1);
+ Module req = modules.getModule(moduleName);
+ if (null != req) {
+ required.add(req);
+ } else {
+ messager.error("unable to create required module: " + moduleName);
+ }
+ } else { // src dir
+ File srcDir = new File(moduleDir, path);
+ if (srcDir.canRead() && srcDir.isDirectory()) {
+ srcDirs.add(srcDir);
+ } else {
+ messager.error("not a src dir: " + srcDir);
+ }
+ }
+ } else if ("lib".equals(kind)) {
+ String libPath = path.startsWith("/")
+ ? modules.baseDir.getAbsolutePath() + path
+ : path;
+ File libJar = new File(libPath);
+ if (libJar.canRead() && libJar.isFile()) {
+ libJars.add(libJar);
+ } else {
+ messager.error("no such library jar " + libJar + " from " + line);
+ }
+ } else if ("var".equals(kind)) {
+ if (!"JRE_LIB".equals(path)) {
+ messager.log("cannot handle var yet: " + line);
+ }
+ } else if ("con".equals(kind)) {
+ messager.log("cannot handle con yet: " + line);
+ } else if ("out".equals(kind)) {
+ // ignore output entries
+ } else {
+ messager.log("unrecognized kind " + kind + " in " + line);
+ }
+ return null;
+ }
+
+ /** @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;
+ }
+}
+
diff --git a/build/src/org/aspectj/internal/tools/build/Modules.java b/build/src/org/aspectj/internal/tools/build/Modules.java
new file mode 100644
index 000000000..55b2fa800
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/Modules.java
@@ -0,0 +1,68 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+import java.io.File;
+import java.util.Hashtable;
+
+/**
+ * Registration and factory for modules
+ * @see Module
+ * @see Builder
+ */
+public class Modules {
+
+ private final Hashtable modules = new Hashtable();
+ 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) {
+ this.baseDir = baseDir;
+ this.jarDir = jarDir;
+ this.handler = handler;
+ this.trimTesting = trimTesting;
+ Util.iaxIfNotCanReadDir(baseDir, "baseDir");
+ Util.iaxIfNotCanReadDir(jarDir, "jarDir");
+ Util.iaxIfNull(handler, "handler");
+ }
+
+
+ /**
+ * Get module associated with name.
+ * @return fail if unable to find or create module {name}.
+ */
+ public Module getModule(String name) {
+ if (null == name) {
+ return null;
+ }
+ Module result = (Module) modules.get(name);
+ if (null == result) {
+ File moduleDir = new File(baseDir, name);
+ if (!Util.canReadDir(moduleDir)) {
+ handler.error("not a module: " + name);
+ } else {
+ result = new Module(moduleDir, jarDir, name, this, trimTesting, handler);
+ if (result.valid) {
+ modules.put(name, result);
+ } else {
+ handler.error("invalid module: " + result.toLongString());
+ }
+ }
+ }
+ return result;
+ }
+} \ No newline at end of file
diff --git a/build/src/org/aspectj/internal/tools/build/ProductModule.java b/build/src/org/aspectj/internal/tools/build/ProductModule.java
new file mode 100644
index 000000000..90e6f3879
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/ProductModule.java
@@ -0,0 +1,70 @@
+/* *******************************************************************
+ * 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.build;
+
+import java.io.File;
+
+/**
+ * Struct associating module with target product distribution jar
+ * and assembly instructions.
+ * When building product distributions, a zero-length jar file
+ * in the dist directory may signify a module to be built,
+ * renamed, and included in the distribution.
+ */
+public class ProductModule {
+ /** name of distribution directory in product directory */
+ private static final String DIST = "dist";
+
+ /** top-level product directory being produced */
+ public final File productDir;
+
+ /** path to file in distribution template dir for this module jar */
+ public final File replaceFile;
+
+ /** relative path within distribution of this product module jar */
+ public final String relativePath;
+
+ /** the module jar is the file to replace */
+ public final Module module;
+
+ /** if true, assemble all when building module */
+ public final boolean assembleAll;
+
+ public ProductModule(File productDir, File replaceFile, Module module, boolean assembleAll) {
+ this.replaceFile = replaceFile;
+ this.module = module;
+ this.productDir = productDir;
+ this.assembleAll = assembleAll;
+ Util.iaxIfNull(module, "module");
+ Util.iaxIfNotCanReadDir(productDir, "productDir");
+ Util.iaxIfNotCanReadFile(replaceFile, "replaceFile");
+ String productDirPath = productDir.getAbsolutePath();
+ String replaceFilePath = replaceFile.getAbsolutePath();
+ if (!replaceFilePath.startsWith(productDirPath)) {
+ String m = "\"" + replaceFilePath
+ + "\" does not start with \""
+ + productDirPath
+ + "\"";
+ throw new IllegalArgumentException(m);
+ }
+ replaceFilePath = replaceFilePath.substring(1+productDirPath.length());
+ if (!replaceFilePath.startsWith(DIST)) {
+ String m = "\"" + replaceFilePath
+ + "\" does not start with \"" + DIST + "\"";
+ throw new IllegalArgumentException(m);
+ }
+ relativePath = replaceFilePath.substring(1 + DIST.length());
+ }
+ public String toString() {
+ return "" + module + " for " + productDir;
+ }
+}
diff --git a/build/src/org/aspectj/internal/tools/build/Util.java b/build/src/org/aspectj/internal/tools/build/Util.java
new file mode 100644
index 000000000..27ca9e1b4
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/Util.java
@@ -0,0 +1,174 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 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.build;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Build-only utilities.
+ * Many mirror utils module APIs.
+ */
+public class Util {
+
+ /**
+ * Map version in long form to short,
+ * e.g., replacing "alpha" with "a"
+ */
+ public static String shortVersion(String version) {
+ version = Util.replace(version, "alpha", "a");
+ version = Util.replace(version, "beta", "b");
+ version = Util.replace(version, "candidate", "rc");
+ version = Util.replace(version, "development", "d");
+ version = Util.replace(version, "dev", "d");
+ return version;
+ }
+
+ /**
+ * Replace any instances of {replace} in {input} with {with}.
+ * @param input the String to search/replace
+ * @param replace the String to search for in input
+ * @param with the String to replace with in input
+ * @return input if it has no replace, otherwise a new String
+ */
+ public static String replace(String input, String replace, String with) {
+ int loc = input.indexOf(replace);
+ if (-1 != loc) {
+ String result = input.substring(0, loc);
+ result += with;
+ int start = loc + replace.length();
+ if (start < input.length()) {
+ result += input.substring(start);
+ }
+ input = result;
+ }
+ return input;
+ }
+
+ /** @return false if filter returned false for any file in baseDir subtree */
+ public static boolean visitFiles(File baseDir, FileFilter filter) {
+ Util.iaxIfNotCanReadDir(baseDir, "baseDir");
+ Util.iaxIfNull(filter, "filter");
+ File[] files = baseDir.listFiles();
+ boolean passed = true;
+ for (int i = 0; passed && (i < files.length); i++) {
+ passed = files[i].isDirectory()
+ ? visitFiles(files[i], filter)
+ : filter.accept(files[i]);
+ }
+ return passed;
+ }
+
+ /** @throws IllegalArgumentException if cannot read dir */
+ public static void iaxIfNotCanReadDir(File dir, String name) {
+ if (!canReadDir(dir)) {
+ throw new IllegalArgumentException(name + " dir not readable: " + dir);
+ }
+ }
+
+ /** @throws IllegalArgumentException if cannot read file */
+ public static void iaxIfNotCanReadFile(File file, String name) {
+ if (!canReadFile(file)) {
+ throw new IllegalArgumentException(name + " file not readable: " + file);
+ }
+ }
+
+ /** @throws IllegalArgumentException if cannot write dir */
+ public static void iaxIfNotCanWriteDir(File dir, String name) {
+ if (!canWriteDir(dir)) {
+ throw new IllegalArgumentException(name + " dir not writeable: " + dir);
+ }
+ }
+
+ /** @throws IllegalArgumentException if input is null */
+ public static void iaxIfNull(Object input, String name) {
+ if (null == input) {
+ throw new IllegalArgumentException("null " + name);
+ }
+ }
+
+ /** render exception to String */
+ public static String renderException(Throwable thrown) {
+ if (null == thrown) {
+ return "(Throwable) null";
+ }
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ pw.println(thrown.getMessage());
+ thrown.printStackTrace(pw);
+ pw.flush();
+ return sw.getBuffer().toString();
+ }
+
+ /** @return true if dir is a writable directory */
+ public static boolean canWriteDir(File dir) {
+ return (null != dir) && dir.canWrite() && dir.isDirectory();
+ }
+
+ /** @return true if dir is a readable directory */
+ public static boolean canReadDir(File dir) {
+ return (null != dir) && dir.canRead() && dir.isDirectory();
+ }
+
+ /** @return true if dir is a readable file */
+ public static boolean canReadFile(File file) {
+ return (null != file) && file.canRead() && file.isFile();
+ }
+
+ /**
+ * Delete contents of directory.
+ * The directory itself is not deleted.
+ * @param dir the File directory whose contents should be deleted.
+ * @return true if all contents of dir were deleted
+ */
+ public static boolean deleteContents(File dir) {
+ if ((null == dir) || !dir.canWrite()) {
+ return false;
+ } else if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (!deleteContents(files[i]) || !files[i].delete()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /** @return File temporary directory with the given prefix */
+ public static File makeTempDir(String prefix) {
+ if (null == prefix) {
+ prefix = "tempDir";
+ }
+ File tempFile = null;
+ for (int i = 0; i < 10; i++) {
+ try {
+ tempFile = File.createTempFile(prefix,"tmp");
+ tempFile.delete();
+ if (tempFile.mkdirs()) {
+ break;
+ }
+ tempFile = null;
+ } catch (IOException e) {
+ }
+ }
+ return tempFile;
+ }
+
+}
+
diff --git a/build/src/org/aspectj/internal/tools/build/package.html b/build/src/org/aspectj/internal/tools/build/package.html
new file mode 100644
index 000000000..3fa443812
--- /dev/null
+++ b/build/src/org/aspectj/internal/tools/build/package.html
@@ -0,0 +1,12 @@
+<html>
+<!-- todo
+- backed off on doing product installer builds directly;
+ the one installer is now built using Ant.
+
+-
+-->
+<body>
+The build taskdef relies on the classes in this package for
+behavior independent of Ant.
+</body>
+</html>