hi i'm new to this list, so i don't yet know how things are done... but
please find attached a new Main.java which provides a -interactive flag
which keeps ant from exiting its VM. on my machine with my work habits,
this results in compiles that are several times faster when doing many
rebuilds (with the same options) in a row because the vm doesn't have to
spend all that time shutting down just to start up again... plus hotspot
has more of a chance to do its magic which is very cool!
i'm not sure that my modifications are exactly what others would want in
the way of this feature, but i tried to adapt to the coding style and i
tried not to break anything (no guarantees, it's just a quick hack!). a
code review would be a good idea if anyone likes the idea enough to
consider checking it in.
thanks for a great tool!
take care,
jon
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
import java.io.*;
import java.util.*;
/**
* Command line entry point into Ant. This class is entered via the
* cannonical `public static void main` entry point and reads the
* command line arguments. It then assembles and executes an Ant
* project.
* <p>
* If you integrating Ant into some other tool, this is not the class
* to use as an entry point. Please see the source code of this
* class to see how it manipulates the Ant project classes.
*
* @author [EMAIL PROTECTED]
*/
public class Main {
/** Our current message output status. Follows Project.MSG_XXX */
private static int msgOutputLevel = Project.MSG_INFO;
/** File that we are using for configuration */
private static File buildFile = new File("build.xml");
/** Save original console output stream */
private static PrintStream console = System.out;
/** Stream that we are using for logging */
private static PrintStream out = System.out;
/** The build targets */
private static Vector targets = new Vector(5);
/** Set of properties that can be used by tasks */
private static Properties definedProps = new Properties();
/**
* Reads the contents of a given file
* @param in The input stream to fully read
* @return The contents of the input stream as a string
*/
public static String readStream(InputStream in) throws IOException {
String content = "";
try {
InputStreamReader r = new InputStreamReader(in);
BufferedReader br = new BufferedReader(r);
String s;
while (null != (s = br.readLine())) {
content += s + "\n";
}
}
finally {
in.close();
}
return content;
}
/**
* Command line entry point. This method kicks off the building
* of a project object and executes a build using either a given
* target or the default target.
*
* @param args Command line args.
*/
public static void main(String[] args) {
// True if ant is interactive
boolean interactive = false;
// The logFile to output to
File logFile = null;
// Cycle through given args
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-help") || arg.equals("help")) {
printUsage();
return;
} else if (arg.equals("-interactive")) {
interactive = true;
} else if (arg.equals("-quiet") || arg.equals("-q") ||
arg.equals("q")) {
msgOutputLevel = Project.MSG_WARN;
} else if (arg.equals("-verbose") || arg.equals("-v") ||
arg.equals("v")) {
msgOutputLevel = Project.MSG_VERBOSE;
} else if (arg.equals("-logfile") || arg.equals("-l") ||
arg.equals("l")) {
try {
logFile = new File(args[i+1]);
i++;
} catch (ArrayIndexOutOfBoundsException aioobe) {
String msg = "You must specify a log file when " +
"using the -log argument";
System.out.println(msg);
return;
}
} else if (arg.equals("-buildfile") || arg.equals("-file") ||
arg.equals("-f") || arg.equals("f")) {
try {
buildFile = new File(args[i+1]);
i++;
} catch (ArrayIndexOutOfBoundsException aioobe) {
String msg = "You must specify a buildfile when " +
"using the -buildfile argument";
System.out.println(msg);
return;
}
} else if (arg.startsWith("-D")) {
/* Interestingly enough, we get to here when a user
* uses -Dname=value. However, in some cases, the JDK
* goes ahead * and parses this out to args
* {"-Dname", "value"}
* so instead of parsing on "=", we just make the "-D"
* characters go away and skip one argument forward.
*
* I don't know how to predict when the JDK is going
* to help or not, so we simply look for the equals sign.
*/
String name = arg.substring(2, arg.length());
String value = null;
int posEq = name.indexOf("=");
if (posEq > 0) {
value = name.substring(posEq+1);
name = name.substring(0, posEq);
} else if (i < args.length)
value = args[++i];
definedProps.put(name, value);
} else if (arg.startsWith("-")) {
// we don't have any more args to recognize!
String msg = "Unknown arg: " + arg;
System.out.println(msg);
printUsage();
return;
} else {
// if it's no other arg, it may be the target
targets.addElement(arg);
}
}
// make sure buildfile exists
if (!buildFile.exists()) {
System.out.println("Buildfile: " + buildFile + " does not exist!");
return;
}
// make sure it's not a directory (this falls into the ultra
// paranoid lets check everything catagory
if (buildFile.isDirectory()) {
System.out.println("What? Buildfile: " + buildFile + " is a dir!");
return;
}
// ok, so if we've made it here, let's run the damn build already
do {
// Is there a log file?
if (logFile != null)
{
// Delete any old log file
logFile.delete();
// Set output to the log file
try {
out = new PrintStream(new FileOutputStream(logFile));
System.setOut(out);
System.setErr(out);
}
catch (IOException ioe) {
String msg = "Cannot write on the specified log file. " +
"Make sure the path exists and you have write
permissions.";
System.out.println(msg);
return;
}
}
// Do the build
runBuild(interactive);
// Are we interactive?
if (interactive) {
// Is there a log file?
if (logFile != null) {
try {
// Show log file
console.println(readStream(new
FileInputStream(logFile)));
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
}
// Prompt user to rebuild
console.println("Press <Return> to rebuild.");
try {
new BufferedReader(new
InputStreamReader(System.in)).readLine();
}
catch (IOException e) {}
}
} while (interactive);
return;
}
/**
* Executes the build.
*/
private static void runBuild(boolean interactive) {
// track when we started
long startTime = System.currentTimeMillis();
if (msgOutputLevel >= Project.MSG_INFO) {
System.out.println("Buildfile: " + buildFile);
}
Project project = new Project(out, msgOutputLevel);
// set user-define properties
Enumeration e = definedProps.keys();
while (e.hasMoreElements()) {
String arg = (String)e.nextElement();
String value = (String)definedProps.get(arg);
project.setUserProperty(arg, value);
}
project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() );
// first use the ProjectHelper to create the project object
// from the given build file.
try {
ProjectHelper.configureProject(project, buildFile);
} catch (BuildException be) {
String msg = "BUILD CONFIG ERROR: ";
System.out.println(msg + be.getMessage());
be.printStackTrace();
System.exit(1);
}
// make sure that we have a target to execute
if (targets.size() == 0) {
targets.addElement(project.getDefaultTarget());
}
// actually do some work
try {
Enumeration en = targets.elements();
while (en.hasMoreElements()) {
project.executeTarget((String) en.nextElement());
}
} catch (BuildException be) {
String msg = "BUILD FATAL ERROR: ";
System.out.println(msg + be.getMessage());
if (msgOutputLevel > Project.MSG_INFO) {
be.printStackTrace();
}
if (!interactive) {
System.exit(1);
}
}
// track our stop time and let the user know how long things took.
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime;
if (msgOutputLevel >= Project.MSG_INFO) {
System.out.println("Completed in " + (elapsedTime/1000)
+ " seconds");
}
}
/**
* Prints the usage of how to use this class to System.out
*/
private static void printUsage() {
String lSep = System.getProperty("line.separator");
StringBuffer msg = new StringBuffer();
msg.append("ant [options] [target]" + lSep);
msg.append("Options: " + lSep);
msg.append(" -help print this message" + lSep);
msg.append(" -interactive build in a loop without exiting" +
lSep);
msg.append(" -quiet be extra quiet" + lSep);
msg.append(" -verbose be extra verbose" + lSep);
msg.append(" -logfile <file> use given file for log" + lSep);
msg.append(" -buildfile <file> use given buildfile" + lSep);
msg.append(" -D<property>=<value> use value for given property" +
lSep);
System.out.println(msg.toString());
}
}