blob: 115ba326aab33c6be28d849995ede1d20b66fc5f [file] [log] [blame]
/* *******************************************************************
* 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.eclipse.ajdt.core.ant;
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.IMessageHandler;
import org.aspectj.bridge.IMessageHolder;
import org.aspectj.bridge.MessageHandler;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.IMessage.Kind;
import org.aspectj.tools.ajc.Main;
import org.aspectj.tools.ant.taskdefs.ICommandEditor;
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>
* &lt;javac srcdir=&quot;src&quot;&gt;
* &lt;compilerarg compiler=&quot;...&quot; line=&quot;-argfile src/args.lst&quot;/&gt;
* &lt;javac&gt;
* </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" };
static final String[] SOURCE_INPUTS = new String[] { "1.3", "1.4", "1.5", "1.6", "1.7" };
static final String[] COMPLIANCE_INPUTS = new String[] { "-1.3", "-1.4", "-1.5", "-1.6", "-1.7" };
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();
private boolean wasCompilationSuccessful;
// 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 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 &lt;jvmarg&gt; 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) {
wasCompilationSuccessful = executeInSameVM(args);
} else { // when forking, Adapter handles failonerror
wasCompilationSuccessful = 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();
}
}
}
boolean wasCompilationSuccessful() {
return wasCompilationSuccessful;
}
/**
* 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.
*
* @return true on successful compilation
* @throws BuildException if abort or failure messages or if errors and failonerror.
*
*/
protected boolean 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);
}
AjdtCommandForAnt command = new AjdtCommandForAnt();
{
Main newmain = new Main();
newmain.setCommand(command);
newmain.setHolder(holder);
newmain.setCompletionRunner(new Runnable() {
public void run() {
doCompletionTasks();
}
});
if (null != main) {
MessageUtil.fail(holder, "still running prior main");
return false;
}
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());
}
}
}
return command.isFailed();
}
/**
* 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
* @return true on successful compilation
*
* @see DefaultCompilerAdapter#executeExternalCompile(String[], int)
* @throws BuildException if ajc aborts (negative value) or if failonerror and there were compile errors.
*/
protected boolean executeInOtherVM(String[] args) {
javaCmd.setClassname(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();
}
}
// if we get here, then compilation was successful
return true;
}
/**
* 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) {
}
}
}