diff options
author | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
commit | c3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch) | |
tree | e9acb7f3d33c1499975cec9ef3cc7ea151078344 /build/src/org | |
parent | 3cde920c3f7eb8241bf569007e25225d80b43c0f (diff) | |
download | aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip |
initial version
Diffstat (limited to 'build/src/org')
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[] { < sourcepath > {, < licenseTag > } } */ + 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 <!-- start strip --> + * and <!-- end strip --> + * 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> |