/* ******************************************************************* * 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 java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; 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.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; /** * Implement Builder in Ant. */ public class AntBuilder extends Builder { /* * warning: This just constructs and uses Ant Task objects, * which in some cases causes the tasks to fail. */ /** * Factory for a Builder. * @param config the String configuration, where only substrings * "verbose" and "useEclipseCompiles" are significant * @param project the owning Project for all tasks (not null) * @param tempDir the File path to a temporary dir for side effects (may be null) * @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); } } } } private final Project project; protected AntBuilder(Project project, File tempDir, boolean useEclipseCompiles, Messager handler) { super(tempDir, useEclipseCompiles, handler); this.project = project; Util.iaxIfNull(project, "project"); } /** * Initialize task with project and "ajbuild-" + name as name. (Using bm- * prefix distinguishes these tasks from tasks found in the build script.) * @param task the Task to initialize - not null * @param name the String name suffix for the task * @return true unless some error */ protected boolean setupTask(Task task, String name) { task.setProject(project); task.setTaskName("ajbuild-" + name); return true; } /** * Copy file, optionally filtering. * (Filters set in project.) * @param fromFile the readable File source to copy * @param toFile the writable File destination file * @param boolean filter if true, enable filtering * @see org.aspectj.internal.tools.build.Builder#copyFile(File, File, boolean) */ protected boolean copyFile(File fromFile, File toFile, boolean filter) { Copy copy = makeCopyTask(filter); copy.setFile(fromFile); copy.setTofile(toFile); executeTask(copy); return true; } /** * (Filters set in project.) * @see org.aspectj.internal.tools.ant.taskdefs.Builder#copyFiles(File, File, String, String, boolean) */ protected boolean copyFiles( File fromDir, File toDir, String includes, String excludes, boolean filter) { Copy copy = makeCopyTask(filter); copy.setTodir(toDir); FileSet fileset = new FileSet(); fileset.setDir(fromDir); if (null != includes) { fileset.setIncludes(includes); } if (null != excludes) { fileset.setExcludes(excludes); } copy.addFileset(fileset); executeTask(copy); return false; } protected void copyFileset(File toDir, FileSet fileSet, boolean filter) { Copy copy = makeCopyTask(filter); copy.addFileset(fileSet); copy.setTodir(toDir); executeTask(copy); } /** * @param filter if FILTER_ON, use filters */ protected Copy makeCopyTask(boolean filter) { Copy copy = new Copy(); setupTask(copy, "copy"); if (FILTER_ON == filter) { copy.setFiltering(true); } return copy; } protected boolean compile( Module module, File classesDir, boolean useExistingClasses, List errors) { // -- source paths Path path = new Path(project); boolean hasSourceDirectories = false; boolean isJava5Compile = false; for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) { File file = (File) iter.next(); path.createPathElement().setLocation(file); if (!isJava5Compile && Util.Constants.JAVA5_SRC.equals(file.getName())) { isJava5Compile = true; } if (!hasSourceDirectories) { hasSourceDirectories = true; } } if (!classesDir.exists() && !classesDir.mkdirs()) { errors.add("compile - unable to create " + classesDir); return false; } if (!hasSourceDirectories) { // none - dump minimal file and exit File minFile = new File(classesDir, module.name); FileWriter fw = null; try { fw = new FileWriter(minFile); fw.write(module.name); } catch (IOException e) { errors.add("IOException writing " + module.name + " to " + minFile + ": " + Util.renderException(e)); } finally { Util.close(fw); } return true; // nothing to compile - ok } if (useExistingClasses) { return true; } // XXX test whether build.compiler property takes effect automatically // I suspect it requires the proper adapter setup. Javac javac = new Javac(); setupTask(javac, "javac"); javac.setDestdir(classesDir); javac.setSrcdir(path); path = null; // -- classpath Path classpath = new Path(project); boolean hasLibraries = setupClasspath(module, classpath); // need to add system classes?? boolean inEclipse = true; // XXX detect, fork only in eclipse if (hasLibraries && inEclipse) { javac.setFork(true); // XXX otherwise never releases library jars } // also fork if using 1.5? // can we build under 1.4, but fork javac 1.5 compile? // -- set output directory classpath.createPathElement().setLocation(classesDir); javac.setClasspath(classpath); // misc javac.setDebug(true); if (!isJava5Compile) { javac.setTarget("1.1"); // 1.1 class files - Javac in 1.4 uses 1.4 javac.setSource("1.3"); } else { javac.setSource("1.5"); javac.setTarget("1.5"); // gack if non-java5 and non-testsrc in this build for (Iterator iter = module.getSrcDirs().iterator(); iter.hasNext();) { String name = ((File) iter.next()).getName(); if (!Util.Constants.JAVA5_SRC.equals(name) && !Util.Constants.TESTSRC.equals(name)) { String m = "modules mixing pre-15 and 15 source are built with -target 1.5"; throw new BuildException(m + ": " + name); } } } // compile boolean passed = false; BuildException failure = null; try { passed = executeTask(AspectJSupport.wrapIfNeeded(module, javac)); } catch (BuildException e) { failure = e; } finally { javac.init(); // be nice to let go of classpath libraries... } if (!passed) { String args = "" + Arrays.asList(javac.getCurrentCompilerArgs()); errors.add("BuildException compiling " + module.toLongString() + args + (null == failure? "" : ": " + Util.renderException(failure))); } return passed; } public boolean setupClasspath(Module module, Path classpath) { // XXX fix test access boolean hasLibraries = false; // required libraries for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) { File file = (File) iter.next(); classpath.createPathElement().setLocation(file); if (!hasLibraries) { hasLibraries = true; } } // required modules and their exported libraries for (Iterator iter = module.getRequired().iterator(); iter.hasNext();) { Module required = (Module) iter.next(); classpath.createPathElement().setLocation(required.getModuleJar()); if (!hasLibraries) { hasLibraries = true; } // also put on classpath libraries exported from required module // XXX exported modules not supported for (Iterator iterator = required.getExportedLibJars().iterator(); iterator.hasNext(); ) { classpath.createPathElement().setLocation((File) iterator.next()); } } return hasLibraries; } /** * 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(); setupTask(zip, "zip"); 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/manifest.mf"); // XXXFileLiteral zipfileset.setExcludes("meta-inf/manifest.MF"); zipfileset.setExcludes("META-INF/MANIFEST.mf"); zipfileset.setExcludes("meta-inf/MANIFEST.MF"); zip.addZipfileset(zipfileset); } } // merge classes; put any meta-inf/manifest.mf here File metaInfDir = new File(classesDir, "META-INF"); Util.deleteContents(metaInfDir); // -- manifest File manifest = new File(module.moduleDir, module.name + ".mf.txt"); // XXXFileLiteral if (Util.canReadFile(manifest)) { if (Util.canReadDir(metaInfDir) || metaInfDir.mkdirs()) { // Jar spec requires a MANIFEST.MF not a manifest.mf 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) // zip returns true when it doesn't create zipfile // because there are no entries to add, so verify done && Util.canReadFile(module.getModuleJar()); } 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(); setupTask(zip, "zip"); 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()); if (verbose) { handler.log("knownAntecedants: " + known); } 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; } /** task.execute() and any advice */ protected boolean executeTask(Task task) { if (!buildingEnabled) { return false; } task.execute(); return true; } /** * Support for compiling basic AspectJ projects. * Projects may only compile all (and only) their source directories; * aspectpath, inpath, etc. are not supported. * To load the compiler, this assumes the user has either defined * a project property "aspectj.home" or that there exists * {module-dir}/lib/aspectj/lib/aspectj[tools|rt].jar. */ static class AspectJSupport { static final String AJCTASK = "org.aspectj.tools.ant.taskdefs.AjcTask"; static final String ASPECTJRT_JAR_VARIABLE = "ASPECTJRT_LIB"; static final String LIBASPECTJ_RPATH = "/lib/aspectj"; static final Map nameToAspectjrtjar = new HashMap(); static final String NONE = "NONE"; /** * If this module should be compiled with AspectJ, * return a task to do so. * @param module the Module to compile * @param javac the Javac compile commands * @return javac or a Task to compile with AspectJ if needed */ static Task wrapIfNeeded(Module module, Javac javac) { final Project project = javac.getProject(); Path runtimeJar = null; if (runtimeJarOnClasspath(module)) { // yes aspectjrt.jar on classpath } else if (module.getClasspathVariables().contains(ASPECTJRT_JAR_VARIABLE)) { // yes, in variables - find aspectjrt.jar to add to classpath runtimeJar = getAspectJLib(project, module, "aspectjrt.jar"); } else { // no return javac; } Path aspectjtoolsJar = getAspectJLib(project, module, "aspectjtools.jar"); return aspectJTask(javac, aspectjtoolsJar, runtimeJar); } /** @return true if aspectjrt.jar is on classpath */ private static boolean runtimeJarOnClasspath(Module module) { for (Iterator iter = module.getLibJars().iterator(); iter.hasNext();) { File file = (File) iter.next(); if ("aspectjrt.jar".equals(file.getName())) { return true; } } return false; } static Path getAspectJLib(Project project, Module module, String name) { Path result = null; String[] libDirNames = { "aspectj.home", "ASPECTJ_HOME", LIBASPECTJ_RPATH}; String[] libDirs = new String[libDirNames.length]; for (int i = 0; i < libDirNames.length; i++) { if (LIBASPECTJ_RPATH == libDirNames[i]) { libDirs[i] = module.getFullPath(LIBASPECTJ_RPATH); } else { libDirs[i] = project.getProperty(libDirNames[i]); } if (null != libDirs[i]) { libDirs[i] += File.separator + "lib"; result = new Path(project, libDirs[i] + File.separator + name); String path = result.toString(); if (new File(path).canRead()) { return result; } } } String m = "unable to find " + name + " in " + Arrays.asList(libDirs); throw new BuildException(m); } /** * Wrap AspectJ compiler as Task. * Only works for javac-like source compilation of everything * under srcDir. * Written reflectively to compile in the build module, * which can't depend on the whole tree. * TODO output from ajc is hidden on failure. * @param javac the Javac specification * @param toolsJar the Path to the aspectjtools.jar * @param runtimeJar the Path to the aspectjrt.jar * @return javac or another Task invoking the AspectJ compiler */ static Task aspectJTask(Javac javac, Path toolsJar, Path runtimeJar) { Object task = null; String url = null; try { url = "file:" + toolsJar.toString().replace('\\', '/'); ClassLoader loader = new URLClassLoader(new URL[] {new URL(url)}); Class c = loader.loadClass(AJCTASK); task = c.newInstance(); Project project = javac.getProject(); Method m = c.getMethod("setupAjc", new Class[] {Javac.class}); m.invoke(task, new Object[] {javac}); m = c.getMethod("setFork", new Class[] {boolean.class}); m.invoke(task, new Object[] {Boolean.TRUE}); m = c.getMethod("setForkclasspath", new Class[] {Path.class}); m.invoke(task, new Object[] {toolsJar}); m = c.getMethod("setSourceRoots", new Class[] {Path.class}); m.invoke(task, new Object[] {javac.getSrcdir()}); if (null != runtimeJar) { m = c.getMethod("setClasspath", new Class[] {Path.class}); m.invoke(task, new Object[] {runtimeJar}); } } catch (BuildException e) { throw e; } catch (Throwable t) { StringBuffer sb = new StringBuffer(); sb.append("classpath="); sb.append(url); throw new BuildException(sb.toString(), t); } return (Task) task; } private AspectJSupport() {throw new Error("no instances");} } } // 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("buildProduct 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(); setupTask(installer, "installer"); 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; } }