/* ******************************************************************* * Copyright (c) 2001-2001 Xerox Corporation, * 2002 Palo Alto Research Center, Incorporated (PARC) * 2003 Contributors. * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Common Public License v1.0 * which accompanies this distribution and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * Xerox/PARC initial implementation * ******************************************************************/ package org.aspectj.tools.ant.taskdefs; import java.io.*; import java.util.*; import org.apache.tools.ant.*; import org.apache.tools.ant.taskdefs.*; import org.apache.tools.ant.types.*; import org.aspectj.bridge.*; import org.aspectj.tools.ajc.Main; import org.aspectj.tools.ajc.Main.MessagePrinter; import org.aspectj.util.*; /** * 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. *
* 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
* setupAjc(AjcTask, Javac, File)
* and
* readArguments(String[])
;
* (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
* reset()
(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.
*
* Pass ajc-specific options using compilerarg sub-element: *
* <javac srcdir="src"> * <compilerarg compiler="..." line="-argfile src/args.lst"/> * <javac> ** Some javac arguments are not supported in this component (yet): *
* String memoryInitialSize; * boolean includeAntRuntime = true; * boolean includeJavaRuntime = false; ** Other javac arguments are not supported in ajc 1.1: *
* boolean optimize; * String forkedExecutable; * FacadeTaskHelper facade; * boolean depend; * String debugLevel; * Path compileSourcepath; ** @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
aspectj{-}tools{...}.jar
* mainly to support build systems using maven-style
* re-naming
* (e.g., aspectj-tools-1.1.0.jar
.
* 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";
private static final ICommandEditor COMMAND_EDITOR;
static {
String[] xs = new String[]
{ "serializableAspects", "incrementalFile"
//, "targetNearSource", "OcodeSize",
};
VALID_XOPTIONS = Collections.unmodifiableList(Arrays.asList(xs));
xs = new String[]
{"constructorName", "packageDefaultMethod", "deprecation",
"maskedCatchBlocks", "unusedLocals", "unusedArguments",
"unusedImports", "syntheticAccess", "assertIdentifier", "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 listFileArgs;
private boolean failonerror;
private boolean fork;
private String maxMem;
// ------- 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 List ignored;
private Path sourceRoots;
private File xweaveDir;
// ----- 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;
/** 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;
// 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;
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;
sourceRoots = null;
srcdir = null;
tmpOutjar = null;
verbose = false;
xweaveDir = null;
}
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 setHelp(boolean help) {
cmd.addFlag("-help", help);
}
public void setVersion(boolean version) {
cmd.addFlag("-version", version);
}
public void setXNoweave(boolean noweave) {
cmd.addFlag("-XnoWeave", noweave);
}
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);
}
/**
* -Xlint - set default level of -Xlint messages to warning
* (same as -Xlint:warning)
*/
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
* org/aspectj/weaver/XLintDefault.properties
)
* @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 setListFileArgs(boolean listFileArgs) {
this.listFileArgs = listFileArgs;
}
public void setReferenceInfo(boolean referenceInfo) {
cmd.addFlag("-referenceInfo", referenceInfo);
}
public void setProgress(boolean progress) {
cmd.addFlag("-progress", progress);
}
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;
}
// ----------------
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 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;
}
public void setTarget(String either11or12) {
if ("1.1".equals(either11or12)) {
cmd.addFlagged("-target", "1.1");
} else if ("1.2".equals(either11or12)) {
cmd.addFlagged("-target", "1.2");
} else if (null != either11or12){
ignore("-target " + either11or12);
}
}
/**
* Language compliance level.
* If not set explicitly, eclipse default holds.
* @param either13or14 either "1.3" or "1.4"
*/
public void setCompliance(String either13or14) {
if ("1.3".equals(either13or14)) {
cmd.addFlag("-1.3", true);
} else if ("1.4".equals(either13or14)) {
cmd.addFlag("-1.4", true);
// } else if ("1.5".equals(either13or14)) {
// cmd.addFlag("-1.5", true);
} else if (null != either13or14) {
ignore(either13or14 + "[compliance]");
}
}
/**
* Source compliance level.
* If not set explicitly, eclipse default holds.
* @param either13or14 either "1.3" or "1.4"
*/
public void setSource(String either13or14) {
if ("1.3".equals(either13or14)) {
cmd.addFlagged("-source", "1.3");
} else if ("1.4".equals(either13or14)) {
cmd.addFlagged("-source", "1.4");
} else if (null != either13or14) {
ignore("-source " + either13or14);
}
}
/**
* 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;
}
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()) {
if (VALID_XOPTIONS.contains(token)) {
cmd.addFlag("-X" + token, true);
} else {
ignore("-X" + token);
}
}
}
}
/** 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
* org.aspectj.tools.ant.taskdefs.AjcTask.COMMAND_EDITOR
* with the className
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();
}
// ------------------------------ 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 {
if (executing) {
throw new IllegalStateException("already executing");
} else {
executing = true;
}
setupOptions();
verifyOptions();
try {
String[] args = makeCommand();
if (verbose || listFileArgs) { // XXX if listFileArgs, only do that
log("ajc " + Arrays.asList(args), Project.MSG_VERBOSE);
}
if (!fork) {
executeInSameVM(args);
} else { // when forking, Adapter handles failonerror
executeInOtherVM(args);
}
} catch (BuildException e) {
throw e;
} catch (Throwable x) {
System.err.println(Main.renderExceptionForUser(x));
throw new BuildException("IGNORE -- See "
+ LangUtil.unqualifiedClassName(x)
+ " rendered to System.err");
} 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();) {
log("ignored: " + iter.next(), Project.MSG_INFO);
}
}
// 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)) {
String path = outjar.getAbsolutePath();
int len = FileUtil.zipSuffixLength(path);
if (len < 1) {
log("not copying resources - weird outjar: " + path);
} else {
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 != sourceRootCopyFilter) && (null == outjar)
&& (DEFAULT_DESTDIR == destDir)) {
final String REQ = " requires dest dir or output jar.\n";
sb.append("sourceRootCopyFilter");
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
= verbose ? MessagePrinter.VERBOSE: MessagePrinter.TERSE;
mhandler.setInterceptor(delegate);
if (!verbose) {
mhandler.ignore(IMessage.INFO);
}
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;
}
try {
main.runMain(args, false);
} finally {
main = null;
}
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 = "