From c3300283ecc397d26ad9dfe31d1710ec45db2af0 Mon Sep 17 00:00:00 2001 From: wisberg Date: Mon, 16 Dec 2002 17:09:36 +0000 Subject: initial version --- build/src/$installer$/org/aspectj/Main.java | 1699 ++++++++++++++++++++ .../internal/tools/ant/taskdefs/AJInstaller.java | 330 ++++ .../internal/tools/ant/taskdefs/AJPush.java | 89 + .../internal/tools/ant/taskdefs/AntBuilder.java | 721 +++++++++ .../internal/tools/ant/taskdefs/BuildModule.java | 156 ++ .../internal/tools/ant/taskdefs/Checklics.java | 735 +++++++++ .../tools/ant/taskdefs/ConditionalTask.java | 182 +++ .../ant/taskdefs/CopyAndInlineStylesheet.java | 113 ++ .../tools/ant/taskdefs/StripNonBodyHtml.java | 233 +++ .../tools/ant/taskdefs/TestBuildModule.java | 79 + .../tools/ant/taskdefs/taskdefs.properties | 20 + .../aspectj/internal/tools/build/BuildSpec.java | 161 ++ .../org/aspectj/internal/tools/build/Builder.java | 497 ++++++ .../org/aspectj/internal/tools/build/Messager.java | 43 + .../org/aspectj/internal/tools/build/Module.java | 501 ++++++ .../org/aspectj/internal/tools/build/Modules.java | 68 + .../internal/tools/build/ProductModule.java | 70 + .../src/org/aspectj/internal/tools/build/Util.java | 174 ++ .../org/aspectj/internal/tools/build/package.html | 12 + 19 files changed, 5883 insertions(+) create mode 100644 build/src/$installer$/org/aspectj/Main.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/AJInstaller.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/AJPush.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/AntBuilder.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/BuildModule.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/Checklics.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/ConditionalTask.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/CopyAndInlineStylesheet.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/StripNonBodyHtml.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/TestBuildModule.java create mode 100644 build/src/org/aspectj/internal/tools/ant/taskdefs/taskdefs.properties create mode 100644 build/src/org/aspectj/internal/tools/build/BuildSpec.java create mode 100644 build/src/org/aspectj/internal/tools/build/Builder.java create mode 100644 build/src/org/aspectj/internal/tools/build/Messager.java create mode 100644 build/src/org/aspectj/internal/tools/build/Module.java create mode 100644 build/src/org/aspectj/internal/tools/build/Modules.java create mode 100644 build/src/org/aspectj/internal/tools/build/ProductModule.java create mode 100644 build/src/org/aspectj/internal/tools/build/Util.java create mode 100644 build/src/org/aspectj/internal/tools/build/package.html (limited to 'build/src') diff --git a/build/src/$installer$/org/aspectj/Main.java b/build/src/$installer$/org/aspectj/Main.java new file mode 100644 index 000000000..b7cdda94e --- /dev/null +++ b/build/src/$installer$/org/aspectj/Main.java @@ -0,0 +1,1699 @@ +/* ******************************************************************* + * Copyright (c) 2000-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 $installer$.org.aspectj; + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.net.URL; +import java.util.zip.*; +import java.util.*; +import java.lang.reflect.InvocationTargetException; + +/** + * Invoke the Installer gui. + * To run without gui, pass two arguments: + *
  • "-text".equals(arg[0])
  • + *
  • arg[1] is the path to a properties file which defines + * name="output.dir" value="{path to output dir}" + * name="context.javaPath" value="{path to JDKDIR}", i.e,. + *
    output.dir=c:/latest
    + *   "context.javaPath=c:/apps/jdk1.3.1
  • + *
  • outputDir must be created and empty (i.e., no overwriting
  • + *
  • the VM being invoked should be the target vm
  • + */ +public class Main { + public static void main(String[] args) { + Options.loadArgs(args); + boolean hasGui = (null == Options.textProperties); + Properties properties = new Properties(); + InputStream istream = null; + try { + istream = Main.class.getResourceAsStream(Installer.RESOURCE_DIR + "/properties.txt"); + if (istream == null) { + System.err.println("unable to load properties.txt using Main.class - exiting"); + Main.exit(-1); + } + properties.load(istream); + if (!hasGui) { + istream.close(); + istream = new FileInputStream(Options.textProperties); + properties.load(istream); + } + istream.close(); + istream = null; + } catch (IOException ioe) { + handleException(ioe); + } finally { + if (null != istream) { + try {istream.close();} + catch (IOException e){} // ignore + } + } + + try { + String className = (String)properties.get("installer.main.class"); + //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + Installer installer = (Installer)Class.forName(className).newInstance(); + InstallContext installerContext = new InstallContext(properties); + installerContext.setHasGui(hasGui); + installer.setContext(installerContext); + if (installerContext.hasGui()) { // let context force whether or not to run gui + installer.runGUI(); + } else { + // set output dir and java path in context after minimal validation + String propName = "output.dir"; + String propValue = properties.getProperty(propName); + if (null == propValue) { + throw new Exception("expecting property " + propName); + } + String outputDirName = propValue; + propName = "context.javaPath"; + propValue = properties.getProperty(propName); + if (null == propValue) { + throw new Exception("expecting property " + propName); + } + String javaPath = propValue; + File outputDir = new File(outputDirName); + if (! outputDir.isDirectory()) { + throw new Exception("not a dir outputDirName: " + outputDirName + + " dir: " + outputDir); + } + if (! outputDir.canWrite()) { + throw new Exception("cannot write outputDirName: " + outputDirName + + " dir: " + outputDir); + } + InstallContext context = installer.getContext(); // todo: why not use installerContext? + context.setOutputDir(outputDir); + context.javaPath = new File(javaPath); + // todo: check javaPath for ... bin/java? lib/rt.jar? + if (! outputDir.isDirectory() || ! outputDir.canRead()) { + throw new Exception("invalid javaPath: " + javaPath); + } + // directly set context and run + installer.getInstallPane().setContext(installerContext); + installer.run(); + } + } catch (Exception e) { + handleException(e); + } + } + + public static void handleException(Throwable e) { + System.out.println("internal error: " + e.toString()); + e.printStackTrace(); + Main.exit(-1); + } + + /** indirection for System.exit - todo apply cleanup here as necessary */ + public static void exit(int value) { + System.exit(value); + } +} // class Main + +class Options { + public static boolean verbose = false; + public static String textProperties = null; + public static boolean forceError1 = false; + public static boolean forceError2 = false; + public static boolean forceHandConfigure = false; + + public static void loadArgs(String[] args) { + if (args == null) return; + for (int i=0; i 600) x = 600; + if (y < 0) y = 0; + if (y > 400) y = 400; + + frame.setLocation(x, y); + frame.setSize(getWidth(), getHeight()); + moveToPane(getPanes()[0]); + frame.setVisible(true); + } + + public void moveToPane(WizardPane pane) { + pane.setContext(this.context); + + Dimension size = frame.getContentPane().getSize(); + + JPanel contents = new JPanel(); + contents.setLayout(new BorderLayout()); + header = makeHeader(); + contents.add(header, BorderLayout.NORTH); + + body = pane.getPanel(); + contents.add(body, BorderLayout.CENTER); + + footer = pane.getButtons(); + contents.add(footer, BorderLayout.SOUTH); + + contents.revalidate(); + contents.setSize(size); + + frame.setContentPane(contents); + + //XXX deal with threading here? + pane.run(); + } + + public Icon loadImage(String name) { + return new javax.swing.ImageIcon(this.getClass().getResource(name)); + } + + public Component makeHeader() { + return new JLabel(loadImage(Installer.RESOURCE_DIR + "/aspectjBanner.gif")); + } + + public ActionListener makeNextAction(final WizardPane pane) { + int nextPaneIndex = findPaneIndex(pane) + 1; + if (nextPaneIndex >= getPanes().length) { + return null; + } + + final WizardPane nextPane = getPanes()[nextPaneIndex]; + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + pane.finish(); + moveToPane(nextPane); + } + }; + } + + public ActionListener makeBackAction(final WizardPane pane) { + int nextPaneIndex = findPaneIndex(pane) - 1; + if (nextPaneIndex < 0) { + return null; + } + + final WizardPane nextPane = getPanes()[nextPaneIndex]; + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + moveToPane(nextPane); + } + }; + } + + public ActionListener makeCancelAction(WizardPane pane) { + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + int ret = JOptionPane.showConfirmDialog(frame, EXIT_MESSAGE, EXIT_TITLE, + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (ret == JOptionPane.YES_OPTION) { + Main.exit(-1); + } + } + }; + } + public ActionListener makeFinishAction(WizardPane pane) { + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + Main.exit(0); + } + }; + } +} + + + + // willing to go up to 3 levels deep to find either jre or jdk + + // jre\[*\]lib\ext + // jdk*\lib\tools.jar + + /***** + final static int MAX_DEPTH = 4; + public static void findPaths(String prefix, File currentDir, int currentDepth) { + if (currentDepth > MAX_DEPTH) return; + if (!currentDir.exists() || !currentDir.isDirectory()) return; + File [] files = currentDir.listFiles(); + if (files == null) return; + for (int i=0; i"); + int stopIndex = text.indexOf(""); + if (startIndex == -1 || stopIndex == -1) return text; + stopIndex += 7; + return text.substring(0, startIndex) + text.substring(stopIndex); + } + + static String styleHeader = "";/*"); + } + + + 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(" This task can take the following arguments:

    + * + *
      + *
    • srcdir
    • + *
    • destdir
    • + *
    • include
    • + *
    • exclude
    • + *
    + * + *

    Of these arguments, only sourcedir is required.

    + * + *

    When this task executes, it will scan the srcdir based on the + * include and exclude properties.

    + */ + +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 = ""; + final String END = ""; + 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("= 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("", start); + if (end == -1) { + end = s.indexOf("", 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: + *
      + *
    • the name of the module is the base name of the module directory
    • + *
    • all module directories are in the same base (workspace) directory
    • + *
    • the name of the target module jar is {moduleName}.jar
    • + *
    • a module directory contains a .classpath file with + * (currently line-parseable) entries per Eclipse (XML) conventions
    • + *
    • Builder.RESOURCE_PATTERN + * identifies all resources to copy to output.
    • + *
    • This can safely trim test-related code: + *
        + *
      • source directories named "testsrc"
      • + *
      • libraries named "junit.jar"
      • + *
      • required modules whose names start with "testing"
      • + *
      + *
    • A file {moduleDir}/{moduleName}.properties + * is a property file possibly + * containing entries defining requirements to be merged with the output jar + * (deprecated mechanism - use assembleAll or products)
    • + *
    + * This currently provides no control over the compile or assembly process, + * but clients can harvest {moduleDir}/bin directories to re-use + * the results of eclipse compiles. + *

    + * When building products, this assumes: + *

      + *
    • the installer-resources directory is a peer of the products directory, + * itself the parent of the particular product directory.
    • + *
    • the dist, jar, product, and base (module) directory are set
    • + *
    • the product distribution consists of all (and only) the files + * in the dist sub-directory of the product directory
    • + *
    • 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.
    • + *
    • When assembling the distribution, all non-binary files are to + * be filtered.
    • + *
    • the name of the product installer is aspectj-{productName}-{version}.jar, + * where {productName} is the base name of the product directory
    • + *
    + *

    + * When run using main(String[]), all relevant Ant libraries and properties + * must be defined. + *

    + * 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: + *

      + *
    • an Eclipse project .classpath file + * containing required libraries and modules + * (collectively, "antecedants") + *
    • + *
    • a file {moduleName}.mf.txt is taken as + * the manifest of any .jar file produced, after filtering. + *
    • + *
    + * + * @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 @@ + + + +The build taskdef relies on the classes in this package for +behavior independent of Ant. + + -- cgit v1.2.3