| /* ******************************************************************* |
| * Copyright (c) 2001-2001 Xerox Corporation, |
| * 2002 Palo Alto Research Center, Incorporated (PARC) |
| * 2003-2004 Contributors. |
| * All rights reserved. |
| * This program and the accompanying materials are made available |
| * under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Xerox/PARC initial implementation |
| * Wes Isberg 2003-2004 changes |
| * ******************************************************************/ |
| |
| package org.aspectj.tools.ant.taskdefs; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| |
| import org.apache.tools.ant.AntClassLoader; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Location; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.taskdefs.Copy; |
| import org.apache.tools.ant.taskdefs.Delete; |
| import org.apache.tools.ant.taskdefs.Execute; |
| import org.apache.tools.ant.taskdefs.Expand; |
| import org.apache.tools.ant.taskdefs.Javac; |
| import org.apache.tools.ant.taskdefs.LogStreamHandler; |
| import org.apache.tools.ant.taskdefs.MatchingTask; |
| import org.apache.tools.ant.taskdefs.Mkdir; |
| import org.apache.tools.ant.taskdefs.PumpStreamHandler; |
| import org.apache.tools.ant.taskdefs.Zip; |
| import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.types.CommandlineJava; |
| import org.apache.tools.ant.types.FileSet; |
| import org.apache.tools.ant.types.Path; |
| import org.apache.tools.ant.types.PatternSet; |
| import org.apache.tools.ant.types.Reference; |
| import org.apache.tools.ant.types.ZipFileSet; |
| import org.apache.tools.ant.util.TaskLogger; |
| import org.aspectj.bridge.AbortException; |
| import org.aspectj.bridge.IMessage; |
| import org.aspectj.bridge.IMessage.Kind; |
| import org.aspectj.bridge.IMessageHandler; |
| import org.aspectj.bridge.IMessageHolder; |
| import org.aspectj.bridge.MessageHandler; |
| import org.aspectj.bridge.MessageUtil; |
| import org.aspectj.tools.ajc.Main; |
| import org.aspectj.util.FileUtil; |
| import org.aspectj.util.LangUtil; |
| |
| /** |
| * This runs the AspectJ 1.1 compiler, supporting all the command-line options. In 1.1.1, ajc copies resources from input jars, but |
| * you can copy resources from the source directories using sourceRootCopyFilter. When not forking, things will be copied as needed |
| * for each iterative compile, but when forking things are only copied at the completion of a successful compile. |
| * <p> |
| * See the development environment guide for usage documentation. |
| * |
| * @since AspectJ 1.1, Ant 1.5 |
| */ |
| public class AjcTask extends MatchingTask { |
| /* |
| * This task mainly converts ant specification for ajc, verbosely ignoring improper input. It also has some special features for |
| * non-obvious clients: (1) Javac compiler adapter supported in <code>setupAjc(AjcTask, Javac, File)</code> and |
| * <code>readArguments(String[])</code>; (2) testing is supported by (a) permitting the same specification to be re-run with |
| * added flags (settings once made cannot be removed); and (b) permitting recycling the task with <code>reset()</code> |
| * (untested). |
| * |
| * The parts that do more than convert ant specs are (a) code for forking; (b) code for copying resources. |
| * |
| * If you maintain/upgrade this task, keep in mind: (1) changes to the semantics of ajc (new options, new values permitted, |
| * etc.) will have to be reflected here. (2) the clients: the iajc ant script, Javac compiler adapter, maven clients of iajc, |
| * and testing code. |
| */ |
| |
| // XXX move static methods after static initializer |
| /** |
| * This method extracts javac arguments to ajc, and add arguments to make ajc behave more like javac in copying resources. |
| * <p> |
| * Pass ajc-specific options using compilerarg sub-element: |
| * |
| * <pre> |
| * <javac srcdir="src"> |
| * <compilerarg compiler="..." line="-argfile src/args.lst"/> |
| * <javac> |
| * </pre> |
| * |
| * Some javac arguments are not supported in this component (yet): |
| * |
| * <pre> |
| * String memoryInitialSize; |
| * boolean includeAntRuntime = true; |
| * boolean includeJavaRuntime = false; |
| * </pre> |
| * |
| * Other javac arguments are not supported in ajc 1.1: |
| * |
| * <pre> |
| * boolean optimize; |
| * String forkedExecutable; |
| * FacadeTaskHelper facade; |
| * boolean depend; |
| * String debugLevel; |
| * Path compileSourcepath; |
| * </pre> |
| * |
| * @param javac the Javac command to implement (not null) |
| * @param ajc the AjcTask to adapt (not null) |
| * @param destDir the File class destination directory (may be null) |
| * @return null if no error, or String error otherwise |
| */ |
| public String setupAjc(Javac javac) { |
| if (null == javac) { |
| return "null javac"; |
| } |
| AjcTask ajc = this; |
| // no null checks b/c AjcTask handles null input gracefully |
| ajc.setProject(javac.getProject()); |
| ajc.setLocation(javac.getLocation()); |
| ajc.setTaskName("javac-iajc"); |
| ajc.setDebug(javac.getDebug()); |
| ajc.setDeprecation(javac.getDeprecation()); |
| ajc.setFailonerror(javac.getFailonerror()); |
| final boolean fork = javac.isForkedJavac(); |
| ajc.setFork(fork); |
| if (fork) { |
| ajc.setMaxmem(javac.getMemoryMaximumSize()); |
| } |
| ajc.setNowarn(javac.getNowarn()); |
| ajc.setListFileArgs(javac.getListfiles()); |
| ajc.setVerbose(javac.getVerbose()); |
| ajc.setTarget(javac.getTarget()); |
| ajc.setSource(javac.getSource()); |
| ajc.setEncoding(javac.getEncoding()); |
| File javacDestDir = javac.getDestdir(); |
| if (null != javacDestDir) { |
| ajc.setDestdir(javacDestDir); |
| // filter requires dest dir |
| // mimic Javac task's behavior in copying resources, |
| ajc.setSourceRootCopyFilter("**/CVS/*,**/*.java,**/*.aj"); |
| } |
| ajc.setBootclasspath(javac.getBootclasspath()); |
| ajc.setExtdirs(javac.getExtdirs()); |
| ajc.setClasspath(javac.getClasspath()); |
| // ignore srcDir -- all files picked up in recalculated file list |
| // ajc.setSrcDir(javac.getSrcdir()); |
| ajc.addFiles(javac.getFileList()); |
| // arguments can override the filter, add to paths, override options |
| ajc.readArguments(javac.getCurrentCompilerArgs()); |
| |
| return null; |
| } |
| |
| /** |
| * Find aspectjtools.jar on the task or system classpath. Accept <code>aspectj{-}tools{...}.jar</code> mainly to support build |
| * systems using maven-style re-naming (e.g., <code>aspectj-tools-1.1.0.jar</code>. Note that we search the task classpath |
| * first, though an entry on the system classpath would be loaded first, because it seems more correct as the more specific one. |
| * |
| * @return readable File for aspectjtools.jar, or null if not found. |
| */ |
| public static File findAspectjtoolsJar() { |
| File result = null; |
| ClassLoader loader = AjcTask.class.getClassLoader(); |
| if (loader instanceof AntClassLoader) { |
| AntClassLoader taskLoader = (AntClassLoader) loader; |
| String cp = taskLoader.getClasspath(); |
| String[] cps = LangUtil.splitClasspath(cp); |
| for (int i = 0; (i < cps.length) && (null == result); i++) { |
| result = isAspectjtoolsjar(cps[i]); |
| } |
| } |
| if (null == result) { |
| final Path classpath = Path.systemClasspath; |
| final String[] paths = classpath.list(); |
| for (int i = 0; (i < paths.length) && (null == result); i++) { |
| result = isAspectjtoolsjar(paths[i]); |
| } |
| } |
| return (null == result ? null : result.getAbsoluteFile()); |
| } |
| |
| /** @return File if readable jar with aspectj tools name, or null */ |
| private static File isAspectjtoolsjar(String path) { |
| if (null == path) { |
| return null; |
| } |
| final String prefix = "aspectj"; |
| final String infix = "tools"; |
| final String altInfix = "-tools"; |
| final String suffix = ".jar"; |
| final int prefixLength = 7; // prefix.length(); |
| final int minLength = 16; |
| // prefixLength + infix.length() + suffix.length(); |
| if (!path.endsWith(suffix)) { |
| return null; |
| } |
| int loc = path.lastIndexOf(prefix); |
| if ((-1 != loc) && ((loc + minLength) <= path.length())) { |
| String rest = path.substring(loc + prefixLength); |
| if (-1 != rest.indexOf(File.pathSeparator)) { |
| return null; |
| } |
| if (rest.startsWith(infix) || rest.startsWith(altInfix)) { |
| File result = new File(path); |
| if (result.canRead() && result.isFile()) { |
| return result; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Maximum length (in chars) of command line before converting to an argfile when forking |
| */ |
| private static final int MAX_COMMANDLINE = 4096; |
| |
| private static final File DEFAULT_DESTDIR = new File(".") { |
| public String toString() { |
| return "(no destination dir specified)"; |
| } |
| }; |
| |
| /** do not throw BuildException on fail/abort message with usage */ |
| private static final String USAGE_SUBSTRING = "AspectJ-specific options"; |
| |
| /** valid -X[...] options other than -Xlint variants */ |
| private static final List VALID_XOPTIONS; |
| |
| /** valid warning (-warn:[...]) variants */ |
| private static final List VALID_WARNINGS; |
| |
| /** valid debugging (-g:[...]) variants */ |
| private static final List VALID_DEBUG; |
| |
| /** |
| * -Xlint variants (error, warning, ignore) |
| * |
| * @see org.aspectj.weaver.Lint |
| */ |
| private static final List VALID_XLINT; |
| |
| public static final String COMMAND_EDITOR_NAME = AjcTask.class.getName() + ".COMMAND_EDITOR"; |
| |
| static final String[] TARGET_INPUTS = new String[] { "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8" }; |
| static final String[] SOURCE_INPUTS = new String[] { "1.3", "1.4", "1.5", "1.6", "1.7", "1.8" }; |
| static final String[] COMPLIANCE_INPUTS = new String[] { "-1.3", "-1.4", "-1.5", "-1.6", "-1.7", "-1.8" }; |
| |
| private static final ICommandEditor COMMAND_EDITOR; |
| |
| static { |
| // many now deprecated: reweavable* |
| String[] xs = new String[] { "serializableAspects", "incrementalFile", "lazyTjp", "reweavable", "reweavable:compress", |
| "notReweavable", "noInline", "terminateAfterCompilation", "hasMember", "ajruntimetarget:1.2", |
| "ajruntimetarget:1.5", "addSerialVersionUID" |
| |
| // , "targetNearSource", "OcodeSize", |
| }; |
| VALID_XOPTIONS = Collections.unmodifiableList(Arrays.asList(xs)); |
| |
| xs = new String[] { "constructorName", "packageDefaultMethod", "deprecation", "maskedCatchBlocks", "unusedLocals", |
| "unusedArguments", "unusedImports", "syntheticAccess", "assertIdentifier", "allDeprecation", "allJavadoc", |
| "charConcat", "conditionAssign", |
| |
| "emptyBlock", "fieldHiding", "finally", "indirectStatic", "intfNonInherited", "javadoc", "localHiding", "nls", |
| "noEffectAssign", "pkgDefaultMethod", "semicolon", "unqualifiedField", "unusedPrivate", "unusedThrown", |
| "uselessTypeCheck", "specialParamHiding", "staticReceiver", "syntheticAccess", "none" }; |
| VALID_WARNINGS = Collections.unmodifiableList(Arrays.asList(xs)); |
| |
| xs = new String[] { "none", "lines", "vars", "source" }; |
| VALID_DEBUG = Collections.unmodifiableList(Arrays.asList(xs)); |
| |
| xs = new String[] { "error", "warning", "ignore" }; |
| VALID_XLINT = Collections.unmodifiableList(Arrays.asList(xs)); |
| |
| ICommandEditor editor = null; |
| try { |
| String editorClassName = System.getProperty(COMMAND_EDITOR_NAME); |
| if (null != editorClassName) { |
| ClassLoader cl = AjcTask.class.getClassLoader(); |
| Class editorClass = cl.loadClass(editorClassName); |
| editor = (ICommandEditor) editorClass.newInstance(); |
| } |
| } catch (Throwable t) { |
| System.err.println("Warning: unable to load command editor"); |
| t.printStackTrace(System.err); |
| } |
| COMMAND_EDITOR = editor; |
| } |
| // ---------------------------- state and Ant interface thereto |
| private boolean verbose; |
| private boolean timers; |
| private boolean listFileArgs; |
| private boolean failonerror; |
| private boolean fork; |
| private String maxMem; |
| private TaskLogger logger; |
| |
| // ------- single entries dumped into cmd |
| protected GuardedCommand cmd; |
| |
| // ------- lists resolved in addListArgs() at execute() time |
| private Path srcdir; |
| private Path injars; |
| private Path inpath; |
| private Path classpath; |
| private Path bootclasspath; |
| private Path forkclasspath; |
| private Path extdirs; |
| private Path aspectpath; |
| private Path argfiles; |
| private Path inxmlfiles; |
| private List ignored; |
| private Path sourceRoots; |
| private File xweaveDir; |
| private String xdoneSignal; |
| |
| // ----- added by adapter - integrate better? |
| private List /* File */adapterFiles; |
| private String[] adapterArguments; |
| |
| private IMessageHolder messageHolder; |
| private ICommandEditor commandEditor; |
| |
| // -------- resource-copying |
| /** true if copying injar non-.class files to the output jar */ |
| private boolean copyInjars; |
| private boolean copyInpath; |
| |
| /** non-null if copying all source root files but the filtered ones */ |
| private String sourceRootCopyFilter; |
| |
| /** non-null if copying all inpath dir files but the filtered ones */ |
| private String inpathDirCopyFilter; |
| |
| /** directory sink for classes */ |
| private File destDir; |
| |
| /** zip file sink for classes */ |
| private File outjar; |
| |
| /** track whether we've supplied any temp outjar */ |
| private boolean outjarFixedup; |
| |
| /** |
| * When possibly copying resources to the output jar, pass ajc a fake output jar to copy from, so we don't change the |
| * modification time of the output jar when copying injars/inpath into the actual outjar. |
| */ |
| private File tmpOutjar; |
| |
| private boolean executing; |
| |
| /** non-null only while executing in same vm */ |
| private Main main; |
| |
| /** true only when executing in other vm */ |
| private boolean executingInOtherVM; |
| |
| /** true if -incremental */ |
| private boolean inIncrementalMode; |
| |
| /** true if -XincrementalFile (i.e, setTagFile) */ |
| private boolean inIncrementalFileMode; |
| |
| /** log command in non-verbose mode */ |
| private boolean logCommand; |
| |
| /** used when forking */ |
| private CommandlineJava javaCmd = new CommandlineJava(); |
| |
| // also note MatchingTask grabs source files... |
| |
| public AjcTask() { |
| reset(); |
| } |
| |
| /** to use this same Task more than once (testing) */ |
| public void reset() { // XXX possible to reset MatchingTask? |
| // need declare for "all fields initialized in ..." |
| adapterArguments = null; |
| adapterFiles = new ArrayList(); |
| argfiles = null; |
| inxmlfiles = null; |
| executing = false; |
| aspectpath = null; |
| bootclasspath = null; |
| classpath = null; |
| cmd = new GuardedCommand(); |
| copyInjars = false; |
| copyInpath = false; |
| destDir = DEFAULT_DESTDIR; |
| executing = false; |
| executingInOtherVM = false; |
| extdirs = null; |
| failonerror = true; // non-standard default |
| forkclasspath = null; |
| inIncrementalMode = false; |
| inIncrementalFileMode = false; |
| ignored = new ArrayList(); |
| injars = null; |
| inpath = null; |
| listFileArgs = false; |
| maxMem = null; |
| messageHolder = null; |
| outjar = null; |
| sourceRootCopyFilter = null; |
| inpathDirCopyFilter = null; |
| sourceRoots = null; |
| srcdir = null; |
| tmpOutjar = null; |
| verbose = false; |
| timers = false; |
| xweaveDir = null; |
| xdoneSignal = null; |
| logCommand = false; |
| javaCmd = new CommandlineJava(); |
| } |
| |
| protected void ignore(String ignored) { |
| this.ignored.add(ignored + " at " + getLocation()); |
| } |
| |
| // ---------------------- option values |
| |
| // used by entries with internal commas |
| protected String validCommaList(String list, List valid, String label) { |
| return validCommaList(list, valid, label, valid.size()); |
| } |
| |
| protected String validCommaList(String list, List valid, String label, int max) { |
| StringBuffer result = new StringBuffer(); |
| StringTokenizer st = new StringTokenizer(list, ","); |
| int num = 0; |
| while (st.hasMoreTokens()) { |
| String token = st.nextToken().trim(); |
| num++; |
| if (num > max) { |
| ignore("too many entries for -" + label + ": " + token); |
| break; |
| } |
| if (!valid.contains(token)) { |
| ignore("bad commaList entry for -" + label + ": " + token); |
| } else { |
| if (0 < result.length()) { |
| result.append(","); |
| } |
| result.append(token); |
| } |
| } |
| return (0 == result.length() ? null : result.toString()); |
| } |
| |
| public void setIncremental(boolean incremental) { |
| cmd.addFlag("-incremental", incremental); |
| inIncrementalMode = incremental; |
| } |
| |
| public void setLogCommand(boolean logCommand) { |
| this.logCommand = logCommand; |
| } |
| |
| public void setHelp(boolean help) { |
| cmd.addFlag("-help", help); |
| } |
| |
| public void setVersion(boolean version) { |
| cmd.addFlag("-version", version); |
| } |
| |
| public void setXTerminateAfterCompilation(boolean b) { |
| cmd.addFlag("-XterminateAfterCompilation", b); |
| } |
| |
| public void setXReweavable(boolean reweavable) { |
| cmd.addFlag("-Xreweavable", reweavable); |
| } |
| |
| public void setXmlConfigured(boolean xmlConfigured) { |
| cmd.addFlag("-xmlConfigured", xmlConfigured); |
| } |
| |
| public void setXJoinpoints(String optionalJoinpoints) { |
| cmd.addFlag("-Xjoinpoints:" + optionalJoinpoints, true); |
| } |
| |
| public void setCheckRuntimeVersion(boolean b) { |
| cmd.addFlag("-checkRuntimeVersion:" + b, true); |
| } |
| |
| public void setXNoWeave(boolean b) { |
| if (logger != null) { |
| logger.warning("the noweave option is no longer required and is being ignored"); |
| } |
| } |
| |
| public void setNoWeave(boolean b) { |
| if (logger != null) { |
| logger.warning("the noweave option is no longer required and is being ignored"); |
| } |
| } |
| |
| public void setXNotReweavable(boolean notReweavable) { |
| cmd.addFlag("-XnotReweavable", notReweavable); |
| } |
| |
| public void setXaddSerialVersionUID(boolean addUID) { |
| cmd.addFlag("-XaddSerialVersionUID", addUID); |
| } |
| |
| public void setXNoInline(boolean noInline) { |
| cmd.addFlag("-XnoInline", noInline); |
| } |
| |
| public void setShowWeaveInfo(boolean showweaveinfo) { |
| cmd.addFlag("-showWeaveInfo", showweaveinfo); |
| } |
| |
| public void setNowarn(boolean nowarn) { |
| cmd.addFlag("-nowarn", nowarn); |
| } |
| |
| public void setDeprecation(boolean deprecation) { |
| cmd.addFlag("-deprecation", deprecation); |
| } |
| |
| public void setWarn(String warnings) { |
| warnings = validCommaList(warnings, VALID_WARNINGS, "warn"); |
| cmd.addFlag("-warn:" + warnings, (null != warnings)); |
| } |
| |
| public void setDebug(boolean debug) { |
| cmd.addFlag("-g", debug); |
| } |
| |
| public void setDebugLevel(String level) { |
| level = validCommaList(level, VALID_DEBUG, "g"); |
| cmd.addFlag("-g:" + level, (null != level)); |
| } |
| |
| public void setEmacssym(boolean emacssym) { |
| cmd.addFlag("-emacssym", emacssym); |
| } |
| |
| public void setCrossrefs(boolean on) { |
| cmd.addFlag("-crossrefs", on); |
| } |
| |
| /** |
| * -Xlint - set default level of -Xlint messages to warning (same as </code>-Xlint:warning</code>) |
| */ |
| public void setXlintwarnings(boolean xlintwarnings) { |
| cmd.addFlag("-Xlint", xlintwarnings); |
| } |
| |
| /** |
| * -Xlint:{error|warning|info} - set default level for -Xlint messages |
| * |
| * @param xlint the String with one of error, warning, ignored |
| */ |
| public void setXlint(String xlint) { |
| xlint = validCommaList(xlint, VALID_XLINT, "Xlint", 1); |
| cmd.addFlag("-Xlint:" + xlint, (null != xlint)); |
| } |
| |
| /** |
| * -Xlintfile {lint.properties} - enable or disable specific forms of -Xlint messages based on a lint properties file (default |
| * is <code>org/aspectj/weaver/XLintDefault.properties</code>) |
| * |
| * @param xlintFile the File with lint properties |
| */ |
| public void setXlintfile(File xlintFile) { |
| cmd.addFlagged("-Xlintfile", xlintFile.getAbsolutePath()); |
| } |
| |
| public void setPreserveAllLocals(boolean preserveAllLocals) { |
| cmd.addFlag("-preserveAllLocals", preserveAllLocals); |
| } |
| |
| public void setNoImportError(boolean noImportError) { |
| cmd.addFlag("-warn:-unusedImport", noImportError); |
| } |
| |
| public void setEncoding(String encoding) { |
| cmd.addFlagged("-encoding", encoding); |
| } |
| |
| public void setLog(File file) { |
| cmd.addFlagged("-log", file.getAbsolutePath()); |
| } |
| |
| public void setProceedOnError(boolean proceedOnError) { |
| cmd.addFlag("-proceedOnError", proceedOnError); |
| } |
| |
| public void setVerbose(boolean verbose) { |
| cmd.addFlag("-verbose", verbose); |
| this.verbose = verbose; |
| } |
| |
| public void setTimers(boolean timers) { |
| cmd.addFlag("-timers", timers); |
| this.timers = timers; |
| } |
| |
| public void setListFileArgs(boolean listFileArgs) { |
| this.listFileArgs = listFileArgs; |
| } |
| |
| public void setReferenceInfo(boolean referenceInfo) { |
| cmd.addFlag("-referenceInfo", referenceInfo); |
| } |
| |
| public void setTime(boolean time) { |
| cmd.addFlag("-time", time); |
| } |
| |
| public void setNoExit(boolean noExit) { |
| cmd.addFlag("-noExit", noExit); |
| } |
| |
| public void setFailonerror(boolean failonerror) { |
| this.failonerror = failonerror; |
| } |
| |
| /** |
| * @return true if fork was set |
| */ |
| public boolean isForked() { |
| return fork; |
| } |
| |
| public void setFork(boolean fork) { |
| this.fork = fork; |
| } |
| |
| public void setMaxmem(String maxMem) { |
| this.maxMem = maxMem; |
| } |
| |
| /** support for nested <jvmarg> elements */ |
| public Commandline.Argument createJvmarg() { |
| return this.javaCmd.createVmArgument(); |
| } |
| |
| // ---------------- |
| public void setTagFile(File file) { |
| inIncrementalMode = true; |
| cmd.addFlagged(Main.CommandController.TAG_FILE_OPTION, file.getAbsolutePath()); |
| inIncrementalFileMode = true; |
| } |
| |
| public void setOutjar(File file) { |
| if (DEFAULT_DESTDIR != destDir) { |
| String e = "specifying both output jar (" + file + ") and destination dir (" + destDir + ")"; |
| throw new BuildException(e); |
| } |
| outjar = file; |
| outjarFixedup = false; |
| tmpOutjar = null; |
| } |
| |
| public void setOutxml(boolean outxml) { |
| cmd.addFlag("-outxml", outxml); |
| } |
| |
| public void setOutxmlfile(String name) { |
| cmd.addFlagged("-outxmlfile", name); |
| } |
| |
| public void setDestdir(File dir) { |
| if (null != outjar) { |
| String e = "specifying both output jar (" + outjar + ") and destination dir (" + dir + ")"; |
| throw new BuildException(e); |
| } |
| cmd.addFlagged("-d", dir.getAbsolutePath()); |
| destDir = dir; |
| } |
| |
| /** |
| * @param input a String in TARGET_INPUTS |
| */ |
| public void setTarget(String input) { |
| String ignore = cmd.addOption("-target", TARGET_INPUTS, input); |
| if (null != ignore) { |
| ignore(ignore); |
| } |
| } |
| |
| /** |
| * Language compliance level. If not set explicitly, eclipse default holds. |
| * |
| * @param input a String in COMPLIANCE_INPUTS |
| */ |
| public void setCompliance(String input) { |
| String ignore = cmd.addOption(null, COMPLIANCE_INPUTS, input); |
| if (null != ignore) { |
| ignore(ignore); |
| } |
| } |
| |
| /** |
| * Source compliance level. If not set explicitly, eclipse default holds. |
| * |
| * @param input a String in SOURCE_INPUTS |
| */ |
| public void setSource(String input) { |
| String ignore = cmd.addOption("-source", SOURCE_INPUTS, input); |
| if (null != ignore) { |
| ignore(ignore); |
| } |
| } |
| |
| /** |
| * Flag to copy all non-.class contents of injars to outjar after compile completes. Requires both injars and outjar. |
| * |
| * @param doCopy |
| */ |
| public void setCopyInjars(boolean doCopy) { |
| ignore("copyInJars"); |
| log("copyInjars not required since 1.1.1.\n", Project.MSG_WARN); |
| // this.copyInjars = doCopy; |
| } |
| |
| /** |
| * Option to copy all files from all source root directories except those specified here. If this is specified and sourceroots |
| * are specified, then this will copy all files except those specified in the filter pattern. Requires sourceroots. |
| * |
| * @param filter a String acceptable as an excludes filter for an Ant Zip fileset. |
| */ |
| public void setSourceRootCopyFilter(String filter) { |
| this.sourceRootCopyFilter = filter; |
| } |
| |
| /** |
| * Option to copy all files from all inpath directories except the files specified here. If this is specified and inpath |
| * directories are specified, then this will copy all files except those specified in the filter pattern. Requires inpath. If |
| * the input does not contain "**\/*.class", then this prepends it, to avoid overwriting woven classes with unwoven input. |
| * |
| * @param filter a String acceptable as an excludes filter for an Ant Zip fileset. |
| */ |
| public void setInpathDirCopyFilter(String filter) { |
| if (null != filter) { |
| if (-1 == filter.indexOf("**/*.class")) { |
| filter = "**/*.class," + filter; |
| } |
| } |
| this.inpathDirCopyFilter = filter; |
| } |
| |
| public void setX(String input) { // ajc-only eajc-also docDone |
| StringTokenizer tokens = new StringTokenizer(input, ",", false); |
| while (tokens.hasMoreTokens()) { |
| String token = tokens.nextToken().trim(); |
| if (1 < token.length()) { |
| // new special case: allow -Xset:anything |
| if (VALID_XOPTIONS.contains(token) || token.indexOf("set:") == 0 || token.indexOf("joinpoints:") == 0) { |
| cmd.addFlag("-X" + token, true); |
| } else { |
| ignore("-X" + token); |
| } |
| } |
| } |
| } |
| |
| public void setXDoneSignal(String doneSignal) { |
| this.xdoneSignal = doneSignal; |
| } |
| |
| /** direct API for testing */ |
| public void setMessageHolder(IMessageHolder holder) { |
| this.messageHolder = holder; |
| } |
| |
| /** |
| * Setup custom message handling. |
| * |
| * @param className the String fully-qualified-name of a class reachable from this object's class loader, implementing |
| * IMessageHolder, and having a public no-argument constructor. |
| * @throws BuildException if unable to create instance of className |
| */ |
| public void setMessageHolderClass(String className) { |
| try { |
| Class mclass = Class.forName(className); |
| IMessageHolder holder = (IMessageHolder) mclass.newInstance(); |
| setMessageHolder(holder); |
| } catch (Throwable t) { |
| String m = "unable to instantiate message holder: " + className; |
| throw new BuildException(m, t); |
| } |
| } |
| |
| /** direct API for testing */ |
| public void setCommandEditor(ICommandEditor editor) { |
| this.commandEditor = editor; |
| } |
| |
| /** |
| * Setup command-line filter. To do this staticly, define the environment variable |
| * <code>org.aspectj.tools.ant.taskdefs.AjcTask.COMMAND_EDITOR</code> with the <code>className</code> parameter. |
| * |
| * @param className the String fully-qualified-name of a class reachable from this object's class loader, implementing |
| * ICommandEditor, and having a public no-argument constructor. |
| * @throws BuildException if unable to create instance of className |
| */ |
| public void setCommandEditorClass(String className) { // skip Ant interface? |
| try { |
| Class mclass = Class.forName(className); |
| setCommandEditor((ICommandEditor) mclass.newInstance()); |
| } catch (Throwable t) { |
| String m = "unable to instantiate command editor: " + className; |
| throw new BuildException(m, t); |
| } |
| } |
| |
| // ---------------------- Path lists |
| |
| /** |
| * Add path elements to source path and return result. Elements are added even if they do not exist. |
| * |
| * @param source the Path to add to - may be null |
| * @param toAdd the Path to add - may be null |
| * @return the (never-null) Path that results |
| */ |
| protected Path incPath(Path source, Path toAdd) { |
| if (null == source) { |
| source = new Path(project); |
| } |
| if (null != toAdd) { |
| source.append(toAdd); |
| } |
| return source; |
| } |
| |
| public void setSourcerootsref(Reference ref) { |
| createSourceRoots().setRefid(ref); |
| } |
| |
| public void setSourceRoots(Path roots) { |
| sourceRoots = incPath(sourceRoots, roots); |
| } |
| |
| public Path createSourceRoots() { |
| if (sourceRoots == null) { |
| sourceRoots = new Path(project); |
| } |
| return sourceRoots.createPath(); |
| } |
| |
| public void setXWeaveDir(File file) { |
| if ((null != file) && file.isDirectory() && file.canRead()) { |
| xweaveDir = file; |
| } |
| } |
| |
| public void setInjarsref(Reference ref) { |
| createInjars().setRefid(ref); |
| } |
| |
| public void setInpathref(Reference ref) { |
| createInpath().setRefid(ref); |
| } |
| |
| public void setInjars(Path path) { |
| injars = incPath(injars, path); |
| } |
| |
| public void setInpath(Path path) { |
| inpath = incPath(inpath, path); |
| } |
| |
| public Path createInjars() { |
| if (injars == null) { |
| injars = new Path(project); |
| } |
| return injars.createPath(); |
| } |
| |
| public Path createInpath() { |
| if (inpath == null) { |
| inpath = new Path(project); |
| } |
| return inpath.createPath(); |
| } |
| |
| public void setClasspath(Path path) { |
| classpath = incPath(classpath, path); |
| } |
| |
| public void setClasspathref(Reference classpathref) { |
| createClasspath().setRefid(classpathref); |
| } |
| |
| public Path createClasspath() { |
| if (classpath == null) { |
| classpath = new Path(project); |
| } |
| return classpath.createPath(); |
| } |
| |
| public void setBootclasspath(Path path) { |
| bootclasspath = incPath(bootclasspath, path); |
| } |
| |
| public void setBootclasspathref(Reference bootclasspathref) { |
| createBootclasspath().setRefid(bootclasspathref); |
| } |
| |
| public Path createBootclasspath() { |
| if (bootclasspath == null) { |
| bootclasspath = new Path(project); |
| } |
| return bootclasspath.createPath(); |
| } |
| |
| public void setForkclasspath(Path path) { |
| forkclasspath = incPath(forkclasspath, path); |
| } |
| |
| public void setForkclasspathref(Reference forkclasspathref) { |
| createForkclasspath().setRefid(forkclasspathref); |
| } |
| |
| public Path createForkclasspath() { |
| if (forkclasspath == null) { |
| forkclasspath = new Path(project); |
| } |
| return forkclasspath.createPath(); |
| } |
| |
| public void setExtdirs(Path path) { |
| extdirs = incPath(extdirs, path); |
| } |
| |
| public void setExtdirsref(Reference ref) { |
| createExtdirs().setRefid(ref); |
| } |
| |
| public Path createExtdirs() { |
| if (extdirs == null) { |
| extdirs = new Path(project); |
| } |
| return extdirs.createPath(); |
| } |
| |
| public void setAspectpathref(Reference ref) { |
| createAspectpath().setRefid(ref); |
| } |
| |
| public void setAspectpath(Path path) { |
| aspectpath = incPath(aspectpath, path); |
| } |
| |
| public Path createAspectpath() { |
| if (aspectpath == null) { |
| aspectpath = new Path(project); |
| } |
| return aspectpath.createPath(); |
| } |
| |
| public void setSrcDir(Path path) { |
| srcdir = incPath(srcdir, path); |
| } |
| |
| public Path createSrc() { |
| return createSrcdir(); |
| } |
| |
| public Path createSrcdir() { |
| if (srcdir == null) { |
| srcdir = new Path(project); |
| } |
| return srcdir.createPath(); |
| } |
| |
| /** @return true if in incremental mode (command-line or file) */ |
| public boolean isInIncrementalMode() { |
| return inIncrementalMode; |
| } |
| |
| /** @return true if in incremental file mode */ |
| public boolean isInIncrementalFileMode() { |
| return inIncrementalFileMode; |
| } |
| |
| public void setArgfilesref(Reference ref) { |
| createArgfiles().setRefid(ref); |
| } |
| |
| public void setArgfiles(Path path) { // ajc-only eajc-also docDone |
| argfiles = incPath(argfiles, path); |
| } |
| |
| public Path createArgfiles() { |
| if (argfiles == null) { |
| argfiles = new Path(project); |
| } |
| return argfiles.createPath(); |
| } |
| |
| public void setInxmlref(Reference ref) { |
| createArgfiles().setRefid(ref); |
| } |
| |
| public void setInxml(Path path) { // ajc-only eajc-also docDone |
| inxmlfiles = incPath(inxmlfiles, path); |
| } |
| |
| public Path createInxml() { |
| if (inxmlfiles == null) { |
| inxmlfiles = new Path(project); |
| } |
| return inxmlfiles.createPath(); |
| } |
| |
| // ------------------------------ run |
| |
| /** |
| * Compile using ajc per settings. |
| * |
| * @exception BuildException if the compilation has problems or if there were compiler errors and failonerror is true. |
| */ |
| public void execute() throws BuildException { |
| this.logger = new TaskLogger(this); |
| if (executing) { |
| throw new IllegalStateException("already executing"); |
| } else { |
| executing = true; |
| } |
| setupOptions(); |
| verifyOptions(); |
| try { |
| String[] args = makeCommand(); |
| if (logCommand) { |
| log("ajc " + Arrays.asList(args)); |
| } else { |
| logVerbose("ajc " + Arrays.asList(args)); |
| } |
| if (!fork) { |
| executeInSameVM(args); |
| } else { // when forking, Adapter handles failonerror |
| executeInOtherVM(args); |
| } |
| } catch (BuildException e) { |
| throw e; |
| } catch (Throwable x) { |
| this.logger.error(Main.renderExceptionForUser(x)); |
| throw new BuildException("IGNORE -- See " + LangUtil.unqualifiedClassName(x) + " rendered to ant logger"); |
| } finally { |
| executing = false; |
| if (null != tmpOutjar) { |
| tmpOutjar.delete(); |
| } |
| } |
| } |
| |
| /** |
| * Halt processing. This tells main in the same vm to quit. It fails when running in forked mode. |
| * |
| * @return true if not in forked mode and main has quit or been told to quit |
| */ |
| public boolean quit() { |
| if (executingInOtherVM) { |
| return false; |
| } |
| Main me = main; |
| if (null != me) { |
| me.quit(); |
| } |
| return true; |
| } |
| |
| // package-private for testing |
| String[] makeCommand() { |
| ArrayList result = new ArrayList(); |
| if (0 < ignored.size()) { |
| for (Iterator iter = ignored.iterator(); iter.hasNext();) { |
| logVerbose("ignored: " + iter.next()); |
| } |
| } |
| // when copying resources, use temp jar for class output |
| // then copy temp jar contents and resources to output jar |
| if ((null != outjar) && !outjarFixedup) { |
| if (copyInjars || copyInpath || (null != sourceRootCopyFilter) || (null != inpathDirCopyFilter)) { |
| String path = outjar.getAbsolutePath(); |
| int len = FileUtil.zipSuffixLength(path); |
| path = path.substring(0, path.length() - len) + ".tmp.jar"; |
| tmpOutjar = new File(path); |
| } |
| if (null == tmpOutjar) { |
| cmd.addFlagged("-outjar", outjar.getAbsolutePath()); |
| } else { |
| cmd.addFlagged("-outjar", tmpOutjar.getAbsolutePath()); |
| } |
| outjarFixedup = true; |
| } |
| |
| result.addAll(cmd.extractArguments()); |
| addListArgs(result); |
| |
| String[] command = (String[]) result.toArray(new String[0]); |
| if (null != commandEditor) { |
| command = commandEditor.editCommand(command); |
| } else if (null != COMMAND_EDITOR) { |
| command = COMMAND_EDITOR.editCommand(command); |
| } |
| return command; |
| } |
| |
| /** |
| * Create any pseudo-options required to implement some of the macro options |
| * |
| * @throws BuildException if options conflict |
| */ |
| protected void setupOptions() { |
| if (null != xweaveDir) { |
| if (DEFAULT_DESTDIR != destDir) { |
| throw new BuildException("weaveDir forces destdir"); |
| } |
| if (null != outjar) { |
| throw new BuildException("weaveDir forces outjar"); |
| } |
| if (null != injars) { |
| throw new BuildException("weaveDir incompatible with injars now"); |
| } |
| if (null != inpath) { |
| throw new BuildException("weaveDir incompatible with inpath now"); |
| } |
| |
| File injar = zipDirectory(xweaveDir); |
| setInjars(new Path(getProject(), injar.getAbsolutePath())); |
| setDestdir(xweaveDir); |
| } |
| } |
| |
| protected File zipDirectory(File dir) { |
| File tempDir = new File("."); |
| try { |
| tempDir = File.createTempFile("AjcTest", ".tmp"); |
| tempDir.mkdirs(); |
| tempDir.deleteOnExit(); // XXX remove zip explicitly.. |
| } catch (IOException e) { |
| // ignore |
| } |
| // File result = new File(tempDir, |
| String filename = "AjcTask-" + System.currentTimeMillis() + ".zip"; |
| File result = new File(filename); |
| Zip zip = new Zip(); |
| zip.setProject(getProject()); |
| zip.setDestFile(result); |
| zip.setTaskName(getTaskName() + " - zip"); |
| FileSet fileset = new FileSet(); |
| fileset.setDir(dir); |
| zip.addFileset(fileset); |
| zip.execute(); |
| Delete delete = new Delete(); |
| delete.setProject(getProject()); |
| delete.setTaskName(getTaskName() + " - delete"); |
| delete.setDir(dir); |
| delete.execute(); |
| Mkdir mkdir = new Mkdir(); |
| mkdir.setProject(getProject()); |
| mkdir.setTaskName(getTaskName() + " - mkdir"); |
| mkdir.setDir(dir); |
| mkdir.execute(); |
| return result; |
| } |
| |
| /** |
| * @throw BuildException if options conflict |
| */ |
| protected void verifyOptions() { |
| StringBuffer sb = new StringBuffer(); |
| if (fork && isInIncrementalMode() && !isInIncrementalFileMode()) { |
| sb.append("can fork incremental only using tag file.\n"); |
| } |
| if (((null != inpathDirCopyFilter) || (null != sourceRootCopyFilter)) && (null == outjar) && (DEFAULT_DESTDIR == destDir)) { |
| final String REQ = " requires dest dir or output jar.\n"; |
| if (null == inpathDirCopyFilter) { |
| sb.append("sourceRootCopyFilter"); |
| } else if (null == sourceRootCopyFilter) { |
| sb.append("inpathDirCopyFilter"); |
| } else { |
| sb.append("sourceRootCopyFilter and inpathDirCopyFilter"); |
| } |
| sb.append(REQ); |
| } |
| if (0 < sb.length()) { |
| throw new BuildException(sb.toString()); |
| } |
| } |
| |
| /** |
| * Run the compile in the same VM by loading the compiler (Main), setting up any message holders, doing the compile, and |
| * converting abort/failure and error messages to BuildException, as appropriate. |
| * |
| * @throws BuildException if abort or failure messages or if errors and failonerror. |
| * |
| */ |
| protected void executeInSameVM(String[] args) { |
| if (null != maxMem) { |
| log("maxMem ignored unless forked: " + maxMem, Project.MSG_WARN); |
| } |
| IMessageHolder holder = messageHolder; |
| int numPreviousErrors; |
| if (null == holder) { |
| MessageHandler mhandler = new MessageHandler(true); |
| final IMessageHandler delegate; |
| delegate = new AntMessageHandler(this.logger, this.verbose, false); |
| mhandler.setInterceptor(delegate); |
| holder = mhandler; |
| numPreviousErrors = 0; |
| } else { |
| numPreviousErrors = holder.numMessages(IMessage.ERROR, true); |
| } |
| { |
| Main newmain = new Main(); |
| newmain.setHolder(holder); |
| newmain.setCompletionRunner(new Runnable() { |
| public void run() { |
| doCompletionTasks(); |
| } |
| }); |
| if (null != main) { |
| MessageUtil.fail(holder, "still running prior main"); |
| return; |
| } |
| main = newmain; |
| } |
| main.runMain(args, false); |
| if (failonerror) { |
| int errs = holder.numMessages(IMessage.ERROR, false); |
| errs -= numPreviousErrors; |
| if (0 < errs) { |
| String m = errs + " errors"; |
| MessageUtil.print(System.err, holder, "", MessageUtil.MESSAGE_ALL, MessageUtil.PICK_ERROR, true); |
| throw new BuildException(m); |
| } |
| } |
| // Throw BuildException if there are any fail or abort |
| // messages. |
| // The BuildException message text has a list of class names |
| // for the exceptions found in the messages, or the |
| // number of fail/abort messages found if there were |
| // no exceptions for any of the fail/abort messages. |
| // The interceptor message handler should have already |
| // printed the messages, including any stack traces. |
| // HACK: this ignores the Usage message |
| { |
| IMessage[] fails = holder.getMessages(IMessage.FAIL, true); |
| if (!LangUtil.isEmpty(fails)) { |
| StringBuffer sb = new StringBuffer(); |
| String prefix = "fail due to "; |
| int numThrown = 0; |
| for (int i = 0; i < fails.length; i++) { |
| String message = fails[i].getMessage(); |
| if (LangUtil.isEmpty(message)) { |
| message = "<no message>"; |
| } else if (-1 != message.indexOf(USAGE_SUBSTRING)) { |
| continue; |
| } |
| Throwable t = fails[i].getThrown(); |
| if (null != t) { |
| numThrown++; |
| sb.append(prefix); |
| sb.append(LangUtil.unqualifiedClassName(t.getClass())); |
| String thrownMessage = t.getMessage(); |
| if (!LangUtil.isEmpty(thrownMessage)) { |
| sb.append(" \"" + thrownMessage + "\""); |
| } |
| } |
| sb.append("\"" + message + "\""); |
| prefix = ", "; |
| } |
| if (0 < sb.length()) { |
| sb.append(" (" + numThrown + " exceptions)"); |
| throw new BuildException(sb.toString()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Execute in a separate VM. Differences from normal same-VM execution: |
| * <ul> |
| * <li>ignores any message holder {class} set</li> |
| * <li>No resource-copying between interative runs</li> |
| * <li>failonerror fails when process interface fails to return negative values</li> |
| * </ul> |
| * |
| * @param args String[] of the complete compiler command to execute |
| * |
| * @see DefaultCompilerAdapter#executeExternalCompile(String[], int) |
| * @throws BuildException if ajc aborts (negative value) or if failonerror and there were compile errors. |
| */ |
| protected void executeInOtherVM(String[] args) { |
| javaCmd.setClassname(org.aspectj.tools.ajc.Main.class.getName()); |
| |
| final Path vmClasspath = javaCmd.createClasspath(getProject()); |
| { |
| File aspectjtools = null; |
| int vmClasspathSize = vmClasspath.size(); |
| if ((null != forkclasspath) && (0 != forkclasspath.size())) { |
| vmClasspath.addExisting(forkclasspath); |
| } else { |
| aspectjtools = findAspectjtoolsJar(); |
| if (null != aspectjtools) { |
| vmClasspath.createPathElement().setLocation(aspectjtools); |
| } |
| } |
| int newVmClasspathSize = vmClasspath.size(); |
| if (vmClasspathSize == newVmClasspathSize) { |
| String m = "unable to find aspectjtools to fork - "; |
| if (null != aspectjtools) { |
| m += "tried " + aspectjtools.toString(); |
| } else if (null != forkclasspath) { |
| m += "tried " + forkclasspath.toString(); |
| } else { |
| m += "define forkclasspath or put aspectjtools on classpath"; |
| } |
| throw new BuildException(m); |
| } |
| } |
| if (null != maxMem) { |
| javaCmd.setMaxmemory(maxMem); |
| } |
| File tempFile = null; |
| int numArgs = args.length; |
| args = GuardedCommand.limitTo(args, MAX_COMMANDLINE, getLocation()); |
| |
| if (args.length != numArgs) { |
| tempFile = new File(args[1]); |
| } |
| try { |
| boolean setMessageHolderOnForking = (this.messageHolder != null); |
| String[] javaArgs = javaCmd.getCommandline(); |
| String[] both = new String[javaArgs.length + args.length + (setMessageHolderOnForking ? 2 : 0)]; |
| System.arraycopy(javaArgs, 0, both, 0, javaArgs.length); |
| System.arraycopy(args, 0, both, javaArgs.length, args.length); |
| if (setMessageHolderOnForking) { |
| both[both.length - 2] = "-messageHolder"; |
| both[both.length - 1] = this.messageHolder.getClass().getName(); |
| } |
| // try to use javaw instead on windows |
| if (both[0].endsWith("java.exe")) { |
| String path = both[0]; |
| path = path.substring(0, path.length() - 4); |
| path = path + "w.exe"; |
| File javaw = new File(path); |
| if (javaw.canRead() && javaw.isFile()) { |
| both[0] = path; |
| } |
| } |
| logVerbose("forking " + Arrays.asList(both)); |
| int result = execInOtherVM(both); |
| if (0 > result) { |
| throw new BuildException("failure[" + result + "] running ajc"); |
| } else if (failonerror && (0 < result)) { |
| throw new BuildException("compile errors: " + result); |
| } |
| // when forking, do completion only at end and when successful |
| doCompletionTasks(); |
| } finally { |
| if (null != tempFile) { |
| tempFile.delete(); |
| } |
| } |
| } |
| |
| /** |
| * Execute in another process using the same JDK and the base directory of the project. XXX correct? |
| * |
| * @param args |
| * @return |
| */ |
| protected int execInOtherVM(String[] args) { |
| try { |
| |
| Project project = getProject(); |
| PumpStreamHandler handler = new LogStreamHandler(this, verbose ? Project.MSG_VERBOSE : Project.MSG_INFO, |
| Project.MSG_WARN); |
| |
| // replace above two lines with what follows as an aid to debugging when running the unit tests.... |
| // LogStreamHandler handler = new LogStreamHandler(this, |
| // Project.MSG_INFO, Project.MSG_WARN) { |
| // |
| // ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| // /* (non-Javadoc) |
| // * @see org.apache.tools.ant.taskdefs.PumpStreamHandler#createProcessOutputPump(java.io.InputStream, |
| // java.io.OutputStream) |
| // */ |
| // protected void createProcessErrorPump(InputStream is, |
| // OutputStream os) { |
| // super.createProcessErrorPump(is, baos); |
| // } |
| // |
| // /* (non-Javadoc) |
| // * @see org.apache.tools.ant.taskdefs.LogStreamHandler#stop() |
| // */ |
| // public void stop() { |
| // byte[] written = baos.toByteArray(); |
| // System.err.print(new String(written)); |
| // super.stop(); |
| // } |
| // }; |
| |
| Execute exe = new Execute(handler); |
| exe.setAntRun(project); |
| exe.setWorkingDirectory(project.getBaseDir()); |
| exe.setCommandline(args); |
| try { |
| if (executingInOtherVM) { |
| String s = "already running in other vm?"; |
| throw new BuildException(s, location); |
| } |
| executingInOtherVM = true; |
| exe.execute(); |
| } finally { |
| executingInOtherVM = false; |
| } |
| return exe.getExitValue(); |
| } catch (IOException e) { |
| String m = "Error executing command " + Arrays.asList(args); |
| throw new BuildException(m, e, location); |
| } |
| } |
| |
| // ------------------------------ setup and reporting |
| /** @return null if path null or empty, String rendition otherwise */ |
| protected static void addFlaggedPath(String flag, Path path, List list) { |
| if (!LangUtil.isEmpty(flag) && ((null != path) && (0 < path.size()))) { |
| list.add(flag); |
| list.add(path.toString()); |
| } |
| } |
| |
| /** |
| * Add to list any path or plural arguments. |
| */ |
| protected void addListArgs(List list) throws BuildException { |
| addFlaggedPath("-classpath", classpath, list); |
| addFlaggedPath("-bootclasspath", bootclasspath, list); |
| addFlaggedPath("-extdirs", extdirs, list); |
| addFlaggedPath("-aspectpath", aspectpath, list); |
| addFlaggedPath("-injars", injars, list); |
| addFlaggedPath("-inpath", inpath, list); |
| addFlaggedPath("-sourceroots", sourceRoots, list); |
| |
| if (argfiles != null) { |
| String[] files = argfiles.list(); |
| for (int i = 0; i < files.length; i++) { |
| File argfile = project.resolveFile(files[i]); |
| if (check(argfile, files[i], false, location)) { |
| list.add("-argfile"); |
| list.add(argfile.getAbsolutePath()); |
| } |
| } |
| } |
| if (inxmlfiles != null) { |
| String[] files = inxmlfiles.list(); |
| for (int i = 0; i < files.length; i++) { |
| File inxmlfile = project.resolveFile(files[i]); |
| if (check(inxmlfile, files[i], false, location)) { |
| list.add("-xmlConfigured"); |
| list.add(inxmlfile.getAbsolutePath()); |
| } |
| } |
| } |
| if (srcdir != null) { |
| // todo: ignore any srcdir if any argfiles and no explicit includes |
| String[] dirs = srcdir.list(); |
| for (int i = 0; i < dirs.length; i++) { |
| File dir = project.resolveFile(dirs[i]); |
| check(dir, dirs[i], true, location); |
| // relies on compiler to prune non-source files |
| String[] files = getDirectoryScanner(dir).getIncludedFiles(); |
| for (int j = 0; j < files.length; j++) { |
| File file = new File(dir, files[j]); |
| if (FileUtil.hasSourceSuffix(file)) { |
| if (!list.contains(file.getAbsolutePath())) { |
| list.add(file.getAbsolutePath()); |
| } |
| } |
| } |
| } |
| } |
| if (0 < adapterFiles.size()) { |
| for (Iterator iter = adapterFiles.iterator(); iter.hasNext();) { |
| File file = (File) iter.next(); |
| if (file.canRead() && FileUtil.hasSourceSuffix(file)) { |
| list.add(file.getAbsolutePath()); |
| } else { |
| this.logger.warning("skipping file: " + file); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Throw BuildException unless file is valid. |
| * |
| * @param file the File to check |
| * @param name the symbolic name to print on error |
| * @param isDir if true, verify file is a directory |
| * @param loc the Location used to create sensible BuildException |
| * @return |
| * @throws BuildException unless file valid |
| */ |
| protected final boolean check(File file, String name, boolean isDir, Location loc) { |
| loc = loc != null ? loc : location; |
| if (file == null) { |
| throw new BuildException(name + " is null!", loc); |
| } |
| if (!file.exists()) { |
| throw new BuildException(file + " doesn't exist!", loc); |
| } |
| if (isDir ^ file.isDirectory()) { |
| String e = file + " should" + (isDir ? "" : "n't") + " be a directory!"; |
| throw new BuildException(e, loc); |
| } |
| return true; |
| } |
| |
| /** |
| * Called when compile or incremental compile is completing, this completes the output jar or directory by copying resources if |
| * requested. Note: this is a callback run synchronously by the compiler. That means exceptions thrown here are caught by |
| * Main.run(..) and passed to the message handler. |
| */ |
| protected void doCompletionTasks() { |
| if (!executing) { |
| throw new IllegalStateException("should be executing"); |
| } |
| if (null != outjar) { |
| completeOutjar(); |
| } else { |
| completeDestdir(); |
| } |
| if (null != xdoneSignal) { |
| MessageUtil.info(messageHolder, xdoneSignal); |
| } |
| } |
| |
| /** |
| * Complete the destination directory by copying resources from the source root directories (if the filter is specified) and |
| * non-.class files from the input jars (if XCopyInjars is enabled). |
| */ |
| private void completeDestdir() { |
| if (!copyInjars && (null == sourceRootCopyFilter) && (null == inpathDirCopyFilter)) { |
| return; |
| } else if ((destDir == DEFAULT_DESTDIR) || !destDir.canWrite()) { |
| String s = "unable to copy resources to destDir: " + destDir; |
| throw new BuildException(s); |
| } |
| final Project project = getProject(); |
| if (copyInjars) { // XXXX remove as unused since 1.1.1 |
| if (null != inpath) { |
| log("copyInjars does not support inpath.\n", Project.MSG_WARN); |
| } |
| String taskName = getTaskName() + " - unzip"; |
| String[] paths = injars.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| PatternSet patternSet = new PatternSet(); |
| patternSet.setProject(project); |
| patternSet.setIncludes("**/*"); |
| patternSet.setExcludes("**/*.class"); |
| for (int i = 0; i < paths.length; i++) { |
| Expand unzip = new Expand(); |
| unzip.setProject(project); |
| unzip.setTaskName(taskName); |
| unzip.setDest(destDir); |
| unzip.setSrc(new File(paths[i])); |
| unzip.addPatternset(patternSet); |
| unzip.execute(); |
| } |
| } |
| } |
| if ((null != sourceRootCopyFilter) && (null != sourceRoots)) { |
| String[] paths = sourceRoots.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| Copy copy = new Copy(); |
| copy.setProject(project); |
| copy.setTodir(destDir); |
| for (int i = 0; i < paths.length; i++) { |
| FileSet fileSet = new FileSet(); |
| fileSet.setDir(new File(paths[i])); |
| fileSet.setIncludes("**/*"); |
| fileSet.setExcludes(sourceRootCopyFilter); |
| copy.addFileset(fileSet); |
| } |
| copy.execute(); |
| } |
| } |
| if ((null != inpathDirCopyFilter) && (null != inpath)) { |
| String[] paths = inpath.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| Copy copy = new Copy(); |
| copy.setProject(project); |
| copy.setTodir(destDir); |
| boolean gotDir = false; |
| for (int i = 0; i < paths.length; i++) { |
| File inpathDir = new File(paths[i]); |
| if (inpathDir.isDirectory() && inpathDir.canRead()) { |
| if (!gotDir) { |
| gotDir = true; |
| } |
| FileSet fileSet = new FileSet(); |
| fileSet.setDir(inpathDir); |
| fileSet.setIncludes("**/*"); |
| fileSet.setExcludes(inpathDirCopyFilter); |
| copy.addFileset(fileSet); |
| } |
| } |
| if (gotDir) { |
| copy.execute(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Complete the output jar by copying resources from the source root directories if the filter is specified. and non-.class |
| * files from the input jars if enabled. |
| */ |
| private void completeOutjar() { |
| if (((null == tmpOutjar) || !tmpOutjar.canRead()) |
| || (!copyInjars && (null == sourceRootCopyFilter) && (null == inpathDirCopyFilter))) { |
| return; |
| } |
| Zip zip = new Zip(); |
| Project project = getProject(); |
| zip.setProject(project); |
| zip.setTaskName(getTaskName() + " - zip"); |
| zip.setDestFile(outjar); |
| ZipFileSet zipfileset = new ZipFileSet(); |
| zipfileset.setProject(project); |
| zipfileset.setSrc(tmpOutjar); |
| zipfileset.setIncludes("**/*.class"); |
| zip.addZipfileset(zipfileset); |
| if (copyInjars) { |
| String[] paths = injars.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| for (int i = 0; i < paths.length; i++) { |
| File jarFile = new File(paths[i]); |
| zipfileset = new ZipFileSet(); |
| zipfileset.setProject(project); |
| zipfileset.setSrc(jarFile); |
| zipfileset.setIncludes("**/*"); |
| zipfileset.setExcludes("**/*.class"); |
| zip.addZipfileset(zipfileset); |
| } |
| } |
| } |
| if ((null != sourceRootCopyFilter) && (null != sourceRoots)) { |
| String[] paths = sourceRoots.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| for (int i = 0; i < paths.length; i++) { |
| File srcRoot = new File(paths[i]); |
| FileSet fileset = new FileSet(); |
| fileset.setProject(project); |
| fileset.setDir(srcRoot); |
| fileset.setIncludes("**/*"); |
| fileset.setExcludes(sourceRootCopyFilter); |
| zip.addFileset(fileset); |
| } |
| } |
| } |
| if ((null != inpathDirCopyFilter) && (null != inpath)) { |
| String[] paths = inpath.list(); |
| if (!LangUtil.isEmpty(paths)) { |
| for (int i = 0; i < paths.length; i++) { |
| File inpathDir = new File(paths[i]); |
| if (inpathDir.isDirectory() && inpathDir.canRead()) { |
| FileSet fileset = new FileSet(); |
| fileset.setProject(project); |
| fileset.setDir(inpathDir); |
| fileset.setIncludes("**/*"); |
| fileset.setExcludes(inpathDirCopyFilter); |
| zip.addFileset(fileset); |
| } |
| } |
| } |
| } |
| zip.execute(); |
| } |
| |
| // -------------------------- compiler adapter interface extras |
| |
| /** |
| * Add specified source files. |
| */ |
| void addFiles(File[] paths) { |
| for (int i = 0; i < paths.length; i++) { |
| addFile(paths[i]); |
| } |
| } |
| |
| /** |
| * Add specified source file. |
| */ |
| void addFile(File path) { |
| if (null != path) { |
| adapterFiles.add(path); |
| } |
| } |
| |
| /** |
| * Read arguments in as if from a command line, mainly to support compiler adapter compilerarg subelement. |
| * |
| * @param args the String[] of arguments to read |
| */ |
| public void readArguments(String[] args) { // XXX slow, stupid, unmaintainable |
| if ((null == args) || (0 == args.length)) { |
| return; |
| } |
| /** String[] wrapper with increment, error reporting */ |
| class Args { |
| final String[] args; |
| int index = 0; |
| |
| Args(String[] args) { |
| this.args = args; // not null or empty |
| } |
| |
| boolean hasNext() { |
| return index < args.length; |
| } |
| |
| String next() { |
| String err = null; |
| if (!hasNext()) { |
| err = "need arg for flag " + args[args.length - 1]; |
| } else { |
| String s = args[index++]; |
| if (null == s) { |
| err = "null value"; |
| } else { |
| s = s.trim(); |
| if (0 == s.trim().length()) { |
| err = "no value"; |
| } else { |
| return s; |
| } |
| } |
| } |
| err += " at [" + index + "] of " + Arrays.asList(args); |
| throw new BuildException(err); |
| } |
| } // class Args |
| |
| Args in = new Args(args); |
| String flag; |
| while (in.hasNext()) { |
| flag = in.next(); |
| if ("-1.3".equals(flag)) { |
| setCompliance(flag); |
| } else if ("-1.4".equals(flag)) { |
| setCompliance(flag); |
| } else if ("-1.5".equals(flag)) { |
| setCompliance("1.5"); |
| } else if ("-argfile".equals(flag)) { |
| setArgfiles(new Path(project, in.next())); |
| } else if ("-aspectpath".equals(flag)) { |
| setAspectpath(new Path(project, in.next())); |
| } else if ("-classpath".equals(flag)) { |
| setClasspath(new Path(project, in.next())); |
| } else if ("-extdirs".equals(flag)) { |
| setExtdirs(new Path(project, in.next())); |
| } else if ("-Xcopyinjars".equals(flag)) { |
| setCopyInjars(true); // ignored - will be flagged by setter |
| } else if ("-g".equals(flag)) { |
| setDebug(true); |
| } else if (flag.startsWith("-g:")) { |
| setDebugLevel(flag.substring(2)); |
| } else if ("-deprecation".equals(flag)) { |
| setDeprecation(true); |
| } else if ("-d".equals(flag)) { |
| setDestdir(new File(in.next())); |
| } else if ("-crossrefs".equals(flag)) { |
| setCrossrefs(true); |
| } else if ("-emacssym".equals(flag)) { |
| setEmacssym(true); |
| } else if ("-encoding".equals(flag)) { |
| setEncoding(in.next()); |
| } else if ("-Xfailonerror".equals(flag)) { |
| setFailonerror(true); |
| } else if ("-fork".equals(flag)) { |
| setFork(true); |
| } else if ("-forkclasspath".equals(flag)) { |
| setForkclasspath(new Path(project, in.next())); |
| } else if ("-help".equals(flag)) { |
| setHelp(true); |
| } else if ("-incremental".equals(flag)) { |
| setIncremental(true); |
| } else if ("-injars".equals(flag)) { |
| setInjars(new Path(project, in.next())); |
| } else if ("-inpath".equals(flag)) { |
| setInpath(new Path(project, in.next())); |
| } else if ("-Xlistfileargs".equals(flag)) { |
| setListFileArgs(true); |
| } else if ("-Xmaxmem".equals(flag)) { |
| setMaxmem(in.next()); |
| } else if ("-Xmessageholderclass".equals(flag)) { |
| setMessageHolderClass(in.next()); |
| } else if ("-noexit".equals(flag)) { |
| setNoExit(true); |
| } else if ("-noimport".equals(flag)) { |
| setNoExit(true); |
| } else if ("-noExit".equals(flag)) { |
| setNoExit(true); |
| } else if ("-noImportError".equals(flag)) { |
| setNoImportError(true); |
| } else if ("-noWarn".equals(flag)) { |
| setNowarn(true); |
| } else if ("-noexit".equals(flag)) { |
| setNoExit(true); |
| } else if ("-outjar".equals(flag)) { |
| setOutjar(new File(in.next())); |
| } else if ("-outxml".equals(flag)) { |
| setOutxml(true); |
| } else if ("-outxmlfile".equals(flag)) { |
| setOutxmlfile(in.next()); |
| } else if ("-preserveAllLocals".equals(flag)) { |
| setPreserveAllLocals(true); |
| } else if ("-proceedOnError".equals(flag)) { |
| setProceedOnError(true); |
| } else if ("-referenceInfo".equals(flag)) { |
| setReferenceInfo(true); |
| } else if ("-source".equals(flag)) { |
| setSource(in.next()); |
| } else if ("-Xsourcerootcopyfilter".equals(flag)) { |
| setSourceRootCopyFilter(in.next()); |
| } else if ("-sourceroots".equals(flag)) { |
| setSourceRoots(new Path(project, in.next())); |
| } else if ("-Xsrcdir".equals(flag)) { |
| setSrcDir(new Path(project, in.next())); |
| } else if ("-Xtagfile".equals(flag)) { |
| setTagFile(new File(in.next())); |
| } else if ("-target".equals(flag)) { |
| setTarget(in.next()); |
| } else if ("-time".equals(flag)) { |
| setTime(true); |
| } else if ("-time".equals(flag)) { |
| setTime(true); |
| } else if ("-verbose".equals(flag)) { |
| setVerbose(true); |
| } else if ("-showWeaveInfo".equals(flag)) { |
| setShowWeaveInfo(true); |
| } else if ("-version".equals(flag)) { |
| setVersion(true); |
| } else if ("-warn".equals(flag)) { |
| setWarn(in.next()); |
| } else if (flag.startsWith("-warn:")) { |
| setWarn(flag.substring(6)); |
| } else if ("-Xlint".equals(flag)) { |
| setXlintwarnings(true); |
| } else if (flag.startsWith("-Xlint:")) { |
| setXlint(flag.substring(7)); |
| } else if ("-Xlintfile".equals(flag)) { |
| setXlintfile(new File(in.next())); |
| } else if ("-XterminateAfterCompilation".equals(flag)) { |
| setXTerminateAfterCompilation(true); |
| } else if ("-Xreweavable".equals(flag)) { |
| setXReweavable(true); |
| } else if ("-XnotReweavable".equals(flag)) { |
| setXNotReweavable(true); |
| } else if (flag.startsWith("@")) { |
| File file = new File(flag.substring(1)); |
| if (file.canRead()) { |
| setArgfiles(new Path(project, file.getPath())); |
| } else { |
| ignore(flag); |
| } |
| } else { |
| File file = new File(flag); |
| if (file.isFile() && file.canRead() && FileUtil.hasSourceSuffix(file)) { |
| addFile(file); |
| } else { |
| ignore(flag); |
| } |
| } |
| } |
| |
| } |
| |
| protected void logVerbose(String text) { |
| if (this.verbose) { |
| this.logger.info(text); |
| } else { |
| this.logger.verbose(text); |
| } |
| } |
| |
| /** |
| * Commandline wrapper that only permits addition of non-empty values and converts to argfile form if necessary. |
| */ |
| public static class GuardedCommand { |
| Commandline command; |
| |
| // int size; |
| |
| static boolean isEmpty(String s) { |
| return ((null == s) || (0 == s.trim().length())); |
| } |
| |
| GuardedCommand() { |
| command = new Commandline(); |
| } |
| |
| void addFlag(String flag, boolean doAdd) { |
| if (doAdd && !isEmpty(flag)) { |
| command.createArgument().setValue(flag); |
| // size += 1 + flag.length(); |
| } |
| } |
| |
| /** @return null if added or ignoreString otherwise */ |
| String addOption(String prefix, String[] validOptions, String input) { |
| if (isEmpty(input)) { |
| return null; |
| } |
| for (int i = 0; i < validOptions.length; i++) { |
| if (input.equals(validOptions[i])) { |
| if (isEmpty(prefix)) { |
| addFlag(input, true); |
| } else { |
| addFlagged(prefix, input); |
| } |
| return null; |
| } |
| } |
| return (null == prefix ? input : prefix + " " + input); |
| } |
| |
| void addFlagged(String flag, String argument) { |
| if (!isEmpty(flag) && !isEmpty(argument)) { |
| command.addArguments(new String[] { flag, argument }); |
| // size += 1 + flag.length() + argument.length(); |
| } |
| } |
| |
| // private void addFile(File file) { |
| // if (null != file) { |
| // String path = file.getAbsolutePath(); |
| // addFlag(path, true); |
| // } |
| // } |
| |
| List extractArguments() { |
| ArrayList result = new ArrayList(); |
| String[] cmds = command.getArguments(); |
| if (!LangUtil.isEmpty(cmds)) { |
| result.addAll(Arrays.asList(cmds)); |
| } |
| return result; |
| } |
| |
| /** |
| * Adjust args for size if necessary by creating an argument file, which should be deleted by the client after the compiler |
| * run has completed. |
| * |
| * @param max the int maximum length of the command line (in char) |
| * @return the temp File for the arguments (if generated), for deletion when done. |
| * @throws IllegalArgumentException if max is negative |
| */ |
| static String[] limitTo(String[] args, int max, Location location) { |
| if (max < 0) { |
| throw new IllegalArgumentException("negative max: " + max); |
| } |
| // sigh - have to count anyway for now |
| int size = 0; |
| for (int i = 0; (i < args.length) && (size < max); i++) { |
| size += 1 + (null == args[i] ? 0 : args[i].length()); |
| } |
| if (size <= max) { |
| return args; |
| } |
| File tmpFile = null; |
| PrintWriter out = null; |
| // adapted from DefaultCompilerAdapter.executeExternalCompile |
| try { |
| String userDirName = System.getProperty("user.dir"); |
| File userDir = new File(userDirName); |
| tmpFile = File.createTempFile("argfile", "", userDir); |
| out = new PrintWriter(new FileWriter(tmpFile)); |
| for (int i = 0; i < args.length; i++) { |
| out.println(args[i]); |
| } |
| out.flush(); |
| return new String[] { "-argfile", tmpFile.getAbsolutePath() }; |
| } catch (IOException e) { |
| throw new BuildException("Error creating temporary file", e, location); |
| } finally { |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (Throwable t) { |
| } |
| } |
| } |
| } |
| } |
| |
| private static class AntMessageHandler implements IMessageHandler { |
| |
| private TaskLogger logger; |
| private final boolean taskLevelVerbose; |
| private final boolean handledMessage; |
| |
| public AntMessageHandler(TaskLogger logger, boolean taskVerbose, boolean handledMessage) { |
| this.logger = logger; |
| this.taskLevelVerbose = taskVerbose; |
| this.handledMessage = handledMessage; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.aspectj.bridge.IMessageHandler#handleMessage(org.aspectj.bridge.IMessage) |
| */ |
| public boolean handleMessage(IMessage message) throws AbortException { |
| Kind messageKind = message.getKind(); |
| String messageText = message.toString(); |
| if (messageKind == IMessage.ABORT) { |
| this.logger.error(messageText); |
| } else if (messageKind == IMessage.DEBUG) { |
| this.logger.debug(messageText); |
| } else if (messageKind == IMessage.ERROR) { |
| this.logger.error(messageText); |
| } else if (messageKind == IMessage.FAIL) { |
| this.logger.error(messageText); |
| } else if (messageKind == IMessage.INFO) { |
| if (this.taskLevelVerbose) { |
| this.logger.info(messageText); |
| } else { |
| this.logger.verbose(messageText); |
| } |
| } else if (messageKind == IMessage.WARNING) { |
| this.logger.warning(messageText); |
| } else if (messageKind == IMessage.WEAVEINFO) { |
| this.logger.info(messageText); |
| } else if (messageKind == IMessage.TASKTAG) { |
| // ignore |
| } else { |
| throw new BuildException("Unknown message kind from AspectJ compiler: " + messageKind.toString()); |
| } |
| return handledMessage; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.aspectj.bridge.IMessageHandler#isIgnoring(org.aspectj.bridge.IMessage.Kind) |
| */ |
| public boolean isIgnoring(Kind kind) { |
| return false; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.aspectj.bridge.IMessageHandler#dontIgnore(org.aspectj.bridge.IMessage.Kind) |
| */ |
| public void dontIgnore(Kind kind) { |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.aspectj.bridge.IMessageHandler#ignore(org.aspectj.bridge.IMessage.Kind) |
| */ |
| public void ignore(Kind kind) { |
| } |
| |
| } |
| } |