git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272497 13f79535-47bb-0310-9956-ffa450edef68master
@@ -82,7 +82,7 @@ import java.util.Enumeration; | |||
public class Main { | |||
/** The default build file name. */ | |||
public final static String DEFAULT_BUILD_FILENAME = "build.xml"; | |||
public static final String DEFAULT_BUILD_FILENAME = "build.xml"; | |||
/** Our current message output status. Follows Project.MSG_XXX. */ | |||
private int msgOutputLevel = Project.MSG_INFO; | |||
@@ -91,10 +91,10 @@ public class Main { | |||
private File buildFile; /* null */ | |||
/** Stream to use for logging. */ | |||
private PrintStream out = System.out; | |||
private static PrintStream out = System.out; | |||
/** Stream that we are using for logging error messages. */ | |||
private PrintStream err = System.err; | |||
private static PrintStream err = System.err; | |||
/** The build targets. */ | |||
private Vector targets = new Vector(5); | |||
@@ -104,13 +104,13 @@ public class Main { | |||
/** Names of classes to add as listeners to project. */ | |||
private Vector listeners = new Vector(5); | |||
/** File names of property files to load on startup. */ | |||
private Vector propertyFiles = new Vector(5); | |||
/** | |||
* The Ant logger class. There may be only one logger. It will have | |||
* the right to use the 'out' PrintStream. The class must implements the | |||
* The Ant logger class. There may be only one logger. It will have | |||
* the right to use the 'out' PrintStream. The class must implements the | |||
* BuildLogger interface. | |||
*/ | |||
private String loggerClassname = null; | |||
@@ -135,15 +135,21 @@ public class Main { | |||
private boolean readyToRun = false; | |||
/** | |||
* Whether or not we should only parse and display the project help | |||
* Whether or not we should only parse and display the project help | |||
* information. | |||
*/ | |||
private boolean projectHelp = false; | |||
/** | |||
* Prints the message of the Throwable if it (the message) is not | |||
* Is a logfile being used? This is used to | |||
* check if the output streams must be closed. | |||
*/ | |||
private static boolean isLogFileUsed = false; | |||
/** | |||
* Prints the message of the Throwable if it (the message) is not | |||
* <code>null</code>. | |||
* | |||
* | |||
* @param t Throwable to print the message of. | |||
* Must not be <code>null</code>. | |||
*/ | |||
@@ -158,12 +164,12 @@ public class Main { | |||
* Creates a new instance of this class using the | |||
* arguments specified, gives it any extra user properties which have been | |||
* specified, and then runs the build using the classloader provided. | |||
* | |||
* | |||
* @param args Command line arguments. Must not be <code>null</code>. | |||
* @param additionalUserProperties Any extra properties to use in this | |||
* build. May be <code>null</code>, which is the equivalent to | |||
* @param additionalUserProperties Any extra properties to use in this | |||
* build. May be <code>null</code>, which is the equivalent to | |||
* passing in an empty set of properties. | |||
* @param coreLoader Classloader used for core classes. May be | |||
* @param coreLoader Classloader used for core classes. May be | |||
* <code>null</code> in which case the system classloader is used. | |||
*/ | |||
public static void start(String[] args, Properties additionalUserProperties, | |||
@@ -172,19 +178,20 @@ public class Main { | |||
try { | |||
m = new Main(args); | |||
} catch(Throwable exc) { | |||
} catch (Throwable exc) { | |||
printMessage(exc); | |||
System.exit(1); | |||
} | |||
if (additionalUserProperties != null) { | |||
for (Enumeration e = additionalUserProperties.keys(); e.hasMoreElements(); ) { | |||
for (Enumeration e = additionalUserProperties.keys(); | |||
e.hasMoreElements();) { | |||
String key = (String) e.nextElement(); | |||
String property = additionalUserProperties.getProperty(key); | |||
m.definedProps.put(key, property); | |||
} | |||
} | |||
try { | |||
m.runBuild(coreLoader); | |||
System.exit(0); | |||
@@ -193,13 +200,30 @@ public class Main { | |||
printMessage(be); | |||
} | |||
System.exit(1); | |||
} catch(Throwable exc) { | |||
} catch (Throwable exc) { | |||
exc.printStackTrace(); | |||
printMessage(exc); | |||
System.exit(1); | |||
} finally { | |||
if (isLogFileUsed) { | |||
if (out != null) { | |||
try { | |||
out.close(); | |||
} catch (final Exception e) { | |||
//ignore | |||
} | |||
} | |||
if (err != null) { | |||
try { | |||
err.close(); | |||
} catch (final Exception e) { | |||
//ignore | |||
} | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Command line entry point. This method kicks off the building | |||
* of a project object and executes a build using either a given | |||
@@ -216,11 +240,11 @@ public class Main { | |||
// BuildException is thrown. What's the rationale for when to do | |||
// what? | |||
/** | |||
* Sole constructor, which parses and deals with command line | |||
* Sole constructor, which parses and deals with command line | |||
* arguments. | |||
* | |||
* | |||
* @param args Command line arguments. Must not be <code>null</code>. | |||
* | |||
* | |||
* @exception BuildException if the specified build file doesn't exist | |||
* or is a directory. | |||
*/ | |||
@@ -249,15 +273,17 @@ public class Main { | |||
msgOutputLevel = Project.MSG_DEBUG; | |||
} else if (arg.equals("-logfile") || arg.equals("-l")) { | |||
try { | |||
File logFile = new File(args[i+1]); | |||
File logFile = new File(args[i + 1]); | |||
i++; | |||
out = new PrintStream(new FileOutputStream(logFile)); | |||
err = out; | |||
System.setOut(out); | |||
System.setErr(out); | |||
isLogFileUsed = true; | |||
} catch (IOException ioe) { | |||
String msg = "Cannot write on the specified log file. " + | |||
"Make sure the path exists and you have write permissions."; | |||
String msg = "Cannot write on the specified log file. " | |||
+ "Make sure the path exists and you have write " | |||
+ "permissions."; | |||
System.out.println(msg); | |||
return; | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
@@ -266,9 +292,10 @@ public class Main { | |||
System.out.println(msg); | |||
return; | |||
} | |||
} else if (arg.equals("-buildfile") || arg.equals("-file") || arg.equals("-f")) { | |||
} else if (arg.equals("-buildfile") || arg.equals("-file") | |||
|| arg.equals("-f")) { | |||
try { | |||
buildFile = new File(args[i+1]); | |||
buildFile = new File(args[i + 1]); | |||
i++; | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
String msg = "You must specify a buildfile when " + | |||
@@ -278,7 +305,7 @@ public class Main { | |||
} | |||
} else if (arg.equals("-listener")) { | |||
try { | |||
listeners.addElement(args[i+1]); | |||
listeners.addElement(args[i + 1]); | |||
i++; | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
String msg = "You must specify a classname when " + | |||
@@ -303,35 +330,35 @@ public class Main { | |||
String value = null; | |||
int posEq = name.indexOf("="); | |||
if (posEq > 0) { | |||
value = name.substring(posEq+1); | |||
value = name.substring(posEq + 1); | |||
name = name.substring(0, posEq); | |||
} else if (i < args.length-1) { | |||
} else if (i < args.length - 1) { | |||
value = args[++i]; | |||
} | |||
definedProps.put(name, value); | |||
} else if (arg.equals("-logger")) { | |||
if (loggerClassname != null) { | |||
System.out.println("Only one logger class may be specified."); | |||
System.out.println("Only one logger class may " | |||
+ " be specified."); | |||
return; | |||
} | |||
try { | |||
loggerClassname = args[++i]; | |||
} | |||
catch (ArrayIndexOutOfBoundsException aioobe) { | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
System.out.println("You must specify a classname when " + | |||
"using the -logger argument"); | |||
return; | |||
} | |||
} else if (arg.equals("-inputhandler")) { | |||
if (inputHandlerClassname != null) { | |||
System.out.println("Only one input handler class may be specified."); | |||
System.out.println("Only one input handler class may " + | |||
"be specified."); | |||
return; | |||
} | |||
try { | |||
inputHandlerClassname = args[++i]; | |||
} | |||
catch (ArrayIndexOutOfBoundsException aioobe) { | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
System.out.println("You must specify a classname when " + | |||
"using the -inputhandler argument"); | |||
return; | |||
@@ -343,14 +370,14 @@ public class Main { | |||
projectHelp = true; | |||
} else if (arg.equals("-find")) { | |||
// eat up next arg if present, default to build.xml | |||
if (i < args.length-1) { | |||
if (i < args.length - 1) { | |||
searchForThis = args[++i]; | |||
} else { | |||
searchForThis = DEFAULT_BUILD_FILENAME; | |||
} | |||
} else if (arg.startsWith("-propertyfile")) { | |||
try { | |||
propertyFiles.addElement(args[i+1]); | |||
propertyFiles.addElement(args[i + 1]); | |||
i++; | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
String msg = "You must specify a property filename when " + | |||
@@ -369,12 +396,12 @@ public class Main { | |||
targets.addElement(arg); | |||
} | |||
} | |||
// if buildFile was not specified on the command line, | |||
if (buildFile == null) { | |||
// but -find then search for it | |||
if (searchForThis != null) { | |||
buildFile = findBuildFile(System.getProperty("user.dir"), | |||
buildFile = findBuildFile(System.getProperty("user.dir"), | |||
searchForThis); | |||
} else { | |||
buildFile = new File(DEFAULT_BUILD_FILENAME); | |||
@@ -396,17 +423,17 @@ public class Main { | |||
} | |||
// Load the property files specified by -propertyfile | |||
for (int propertyFileIndex=0; | |||
for (int propertyFileIndex = 0; | |||
propertyFileIndex < propertyFiles.size(); | |||
propertyFileIndex++) { | |||
String filename = (String) propertyFiles.elementAt(propertyFileIndex); | |||
String filename | |||
= (String) propertyFiles.elementAt(propertyFileIndex); | |||
Properties props = new Properties(); | |||
FileInputStream fis = null; | |||
try { | |||
fis = new FileInputStream(filename); | |||
props.load(fis); | |||
} | |||
catch (IOException e) { | |||
} catch (IOException e) { | |||
System.out.println("Could not load property file " | |||
+ filename + ": " + e.getMessage()); | |||
} finally { | |||
@@ -417,7 +444,7 @@ public class Main { | |||
} | |||
} | |||
} | |||
// ensure that -D properties take precedence | |||
Enumeration propertyNames = props.propertyNames(); | |||
while (propertyNames.hasMoreElements()) { | |||
@@ -445,7 +472,7 @@ public class Main { | |||
filename = file.getParent(); | |||
if (filename != null && msgOutputLevel >= Project.MSG_VERBOSE) { | |||
System.out.println("Searching in "+filename); | |||
System.out.println("Searching in " + filename); | |||
} | |||
return (filename == null) ? null : new File(filename); | |||
@@ -463,34 +490,35 @@ public class Main { | |||
* Must not be <code>null</code>. | |||
* @param suffix Suffix filename to look for in parents. | |||
* Must not be <code>null</code>. | |||
* | |||
* | |||
* @return A handle to the build file if one is found | |||
* | |||
* @exception BuildException if no build file is found | |||
*/ | |||
private File findBuildFile(String start, String suffix) throws BuildException { | |||
private File findBuildFile(String start, String suffix) | |||
throws BuildException { | |||
if (msgOutputLevel >= Project.MSG_INFO) { | |||
System.out.println("Searching for " + suffix + " ..."); | |||
} | |||
File parent = new File(new File(start).getAbsolutePath()); | |||
File file = new File(parent, suffix); | |||
// check if the target file exists in the current directory | |||
while (!file.exists()) { | |||
// change to parent directory | |||
parent = getParentFile(parent); | |||
// if parent is null, then we are at the root of the fs, | |||
// complain that we can't find the build file. | |||
if (parent == null) { | |||
throw new BuildException("Could not locate a build file!"); | |||
} | |||
// refresh our file handle | |||
file = new File(parent, suffix); | |||
} | |||
return file; | |||
} | |||
@@ -498,11 +526,11 @@ public class Main { | |||
* Executes the build. If the constructor for this instance failed | |||
* (e.g. returned after issuing a warning), this method returns | |||
* immediately. | |||
* | |||
* | |||
* @param coreLoader The classloader to use to find core classes. | |||
* May be <code>null</code>, in which case the | |||
* system classloader is used. | |||
* | |||
* | |||
* @exception BuildException if the build fails | |||
*/ | |||
private void runBuild(ClassLoader coreLoader) throws BuildException { | |||
@@ -532,11 +560,11 @@ public class Main { | |||
// use a system manager that prevents from System.exit() | |||
// only in JDK > 1.1 | |||
SecurityManager oldsm = null; | |||
if ( !Project.JAVA_1_0.equals(Project.getJavaVersion()) && | |||
!Project.JAVA_1_1.equals(Project.getJavaVersion()) ){ | |||
if (!Project.JAVA_1_0.equals(Project.getJavaVersion()) && | |||
!Project.JAVA_1_1.equals(Project.getJavaVersion())){ | |||
oldsm = System.getSecurityManager(); | |||
//SecurityManager can not be installed here for backwards | |||
//SecurityManager can not be installed here for backwards | |||
//compatability reasons (PD). Needs to be loaded prior to | |||
//ant class if we are going to implement it. | |||
//System.setSecurityManager(new NoExitSecurityManager()); | |||
@@ -554,17 +582,19 @@ public class Main { | |||
// set user-define properties | |||
Enumeration e = definedProps.keys(); | |||
while (e.hasMoreElements()) { | |||
String arg = (String)e.nextElement(); | |||
String value = (String)definedProps.get(arg); | |||
String arg = (String) e.nextElement(); | |||
String value = (String) definedProps.get(arg); | |||
project.setUserProperty(arg, value); | |||
} | |||
project.setUserProperty("ant.file" , buildFile.getAbsolutePath() ); | |||
project.setUserProperty("ant.file", | |||
buildFile.getAbsolutePath()); | |||
// first use the ProjectHelper to create the project object | |||
// from the given build file. | |||
String noParserMessage = | |||
"No JAXP compliant XML parser found. Please visit http://xml.apache.org for a suitable parser"; | |||
String noParserMessage = "No JAXP compliant XML parser found. " | |||
+ "Please visit http://xml.apache.org " | |||
+ "for a suitable parser"; | |||
try { | |||
Class.forName("javax.xml.parsers.SAXParserFactory"); | |||
ProjectHelper.configureProject(project, buildFile); | |||
@@ -578,18 +608,17 @@ public class Main { | |||
if (projectHelp) { | |||
printDescription(project); | |||
printTargets(project, msgOutputLevel > Project.MSG_INFO ); | |||
printTargets(project, msgOutputLevel > Project.MSG_INFO); | |||
return; | |||
} | |||
// make sure that we have a target to execute | |||
if (targets.size() == 0) { | |||
targets.addElement(project.getDefaultTarget()); | |||
} | |||
project.executeTargets(targets); | |||
} | |||
finally { | |||
} finally { | |||
// put back the original security manager | |||
//The following will never eval to true. (PD) | |||
if (oldsm != null){ | |||
@@ -599,16 +628,13 @@ public class Main { | |||
System.setOut(out); | |||
System.setErr(err); | |||
} | |||
} | |||
catch(RuntimeException exc) { | |||
} catch (RuntimeException exc) { | |||
error = exc; | |||
throw exc; | |||
} | |||
catch(Error err) { | |||
} catch (Error err) { | |||
error = err; | |||
throw err; | |||
} | |||
finally { | |||
} finally { | |||
if (!projectHelp) { | |||
project.fireBuildFinished(error); | |||
} | |||
@@ -618,7 +644,7 @@ public class Main { | |||
/** | |||
* Adds the listeners specified in the command line arguments, | |||
* along with the default listener, to the specified project. | |||
* | |||
* | |||
* @param project The project to add listeners to. | |||
* Must not be <code>null</code>. | |||
*/ | |||
@@ -633,9 +659,9 @@ public class Main { | |||
BuildListener listener = | |||
(BuildListener) Class.forName(className).newInstance(); | |||
project.addBuildListener(listener); | |||
} | |||
catch(Throwable exc) { | |||
throw new BuildException("Unable to instantiate listener " + className, exc); | |||
} catch (Throwable exc) { | |||
throw new BuildException("Unable to instantiate listener " | |||
+ className, exc); | |||
} | |||
} | |||
} | |||
@@ -654,48 +680,51 @@ public class Main { | |||
handler = new DefaultInputHandler(); | |||
} else { | |||
try { | |||
handler = (InputHandler)(Class.forName(inputHandlerClassname).newInstance()); | |||
} | |||
catch (ClassCastException e) { | |||
handler = (InputHandler) | |||
(Class.forName(inputHandlerClassname).newInstance()); | |||
} catch (ClassCastException e) { | |||
String msg = "The specified input handler class " | |||
+ inputHandlerClassname | |||
+ " does not implement the InputHandler interface"; | |||
throw new BuildException(msg); | |||
} | |||
catch (Exception e) { | |||
String msg = "Unable to instantiate specified input handler class " | |||
+ inputHandlerClassname + " : " + e.getClass().getName(); | |||
String msg = "Unable to instantiate specified input handler " | |||
+ "class " + inputHandlerClassname + " : " | |||
+ e.getClass().getName(); | |||
throw new BuildException(msg); | |||
} | |||
} | |||
project.setInputHandler(handler); | |||
} | |||
// XXX: (Jon Skeet) Any reason for writing a message and then using a bare | |||
// XXX: (Jon Skeet) Any reason for writing a message and then using a bare | |||
// RuntimeException rather than just using a BuildException here? Is it | |||
// in case the message could end up being written to no loggers (as the loggers | |||
// could have failed to be created due to this failure)? | |||
// in case the message could end up being written to no loggers (as the | |||
// loggers could have failed to be created due to this failure)? | |||
/** | |||
* Creates the default build logger for sending build events to the ant log. | |||
* Creates the default build logger for sending build events to the ant | |||
* log. | |||
* | |||
* @return the logger instance for this build. | |||
*/ | |||
private BuildLogger createLogger() { | |||
BuildLogger logger = null; | |||
if (loggerClassname != null) { | |||
try { | |||
logger = (BuildLogger)(Class.forName(loggerClassname).newInstance()); | |||
} | |||
catch (ClassCastException e) { | |||
System.err.println("The specified logger class " + loggerClassname + | |||
" does not implement the BuildLogger interface"); | |||
logger = (BuildLogger) (Class.forName(loggerClassname).newInstance()); | |||
} catch (ClassCastException e) { | |||
System.err.println("The specified logger class " | |||
+ loggerClassname | |||
+ " does not implement the BuildLogger interface"); | |||
throw new RuntimeException(); | |||
} | |||
catch (Exception e) { | |||
System.err.println("Unable to instantiate specified logger class " + | |||
loggerClassname + " : " + e.getClass().getName()); | |||
} catch (Exception e) { | |||
System.err.println("Unable to instantiate specified logger " | |||
+ "class " + loggerClassname + " : " | |||
+ e.getClass().getName()); | |||
throw new RuntimeException(); | |||
} | |||
} | |||
else { | |||
} else { | |||
logger = new DefaultLogger(); | |||
} | |||
@@ -736,7 +765,7 @@ public class Main { | |||
/** | |||
* Prints the Ant version information to <code>System.out</code>. | |||
* | |||
* | |||
* @exception BuildException if the version information is unavailable | |||
*/ | |||
private static void printVersion() throws BuildException { | |||
@@ -752,10 +781,10 @@ public class Main { | |||
* Returns the Ant version information, if available. Once the information | |||
* has been loaded once, it's cached and returned from the cache on future | |||
* calls. | |||
* | |||
* @return the Ant version information as a String | |||
* | |||
* @return the Ant version information as a String | |||
* (always non-<code>null</code>) | |||
* | |||
* | |||
* @exception BuildException if the version information is unavailable | |||
*/ | |||
public static synchronized String getAntVersion() throws BuildException { | |||
@@ -766,7 +795,7 @@ public class Main { | |||
Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt"); | |||
props.load(in); | |||
in.close(); | |||
String lSep = System.getProperty("line.separator"); | |||
StringBuffer msg = new StringBuffer(); | |||
msg.append("Apache Ant version "); | |||
@@ -785,9 +814,9 @@ public class Main { | |||
} | |||
/** | |||
* Prints the description of a project (if there is one) to | |||
* Prints the description of a project (if there is one) to | |||
* <code>System.out</code>. | |||
* | |||
* | |||
* @param project The project to display a description of. | |||
* Must not be <code>null</code>. | |||
*/ | |||
@@ -798,9 +827,9 @@ public class Main { | |||
} | |||
/** | |||
* Prints a list of all targets in the specified project to | |||
* Prints a list of all targets in the specified project to | |||
* <code>System.out</code>, optionally including subtargets. | |||
* | |||
* | |||
* @param project The project to display a description of. | |||
* Must not be <code>null</code>. | |||
* @param printSubTargets Whether or not subtarget names should also be | |||
@@ -820,7 +849,7 @@ public class Main { | |||
Vector subNames = new Vector(); | |||
while (ptargets.hasMoreElements()) { | |||
currentTarget = (Target)ptargets.nextElement(); | |||
currentTarget = (Target) ptargets.nextElement(); | |||
targetName = currentTarget.getName(); | |||
targetDescription = currentTarget.getDescription(); | |||
// maintain a sorted list of targets | |||
@@ -838,31 +867,32 @@ public class Main { | |||
} | |||
printTargets(topNames, topDescriptions, "Main targets:", maxLength); | |||
if( printSubTargets ) { | |||
if (printSubTargets) { | |||
printTargets(subNames, null, "Subtargets:", 0); | |||
} | |||
String defaultTarget = project.getDefaultTarget(); | |||
if (defaultTarget != null && !"".equals(defaultTarget)) { // shouldn't need to check but... | |||
System.out.println( "Default target: " + defaultTarget ); | |||
if (defaultTarget != null && !"".equals(defaultTarget)) { | |||
// shouldn't need to check but... | |||
System.out.println("Default target: " + defaultTarget); | |||
} | |||
} | |||
/** | |||
* Searches for the correct place to insert a name into a list so as | |||
* to keep the list sorted alphabetically. | |||
* | |||
* | |||
* @param names The current list of names. Must not be <code>null</code>. | |||
* @param name The name to find a place for. | |||
* Must not be <code>null</code>. | |||
* | |||
* | |||
* @return the correct place in the list for the given name | |||
*/ | |||
private static int findTargetPosition(Vector names, String name) { | |||
int res = names.size(); | |||
for (int i=0; i<names.size() && res == names.size(); i++) { | |||
if (name.compareTo((String)names.elementAt(i)) < 0) { | |||
for (int i = 0; i < names.size() && res == names.size(); i++) { | |||
if (name.compareTo((String) names.elementAt(i)) < 0) { | |||
res = i; | |||
} | |||
} | |||
@@ -871,23 +901,38 @@ public class Main { | |||
/** | |||
* Writes a formatted list of target names to <code>System.out</code> | |||
* with an optional description | |||
* with an optional description. | |||
* | |||
* @param names The names to be printed. | |||
* Must not be <code>null</code>. | |||
* @param descriptions The associated target descriptions. | |||
* May be <code>null</code>, in which case | |||
* no descriptions are displayed. | |||
* If non-<code>null</code>, this should have | |||
* as many elements as <code>names</code>. | |||
* @param heading The heading to display. | |||
* Should not be <code>null</code>. | |||
* @param maxlen The maximum length of the names of the targets. | |||
* If descriptions are given, they are padded to this | |||
* position so they line up (so long as the names really | |||
* <i>are</i> shorter than this). | |||
*/ | |||
private static void printTargets(Vector names, Vector descriptions, String heading, int maxlen) { | |||
private static void printTargets(Vector names, Vector descriptions, | |||
String heading, int maxlen) { | |||
// now, start printing the targets and their descriptions | |||
String lSep = System.getProperty("line.separator"); | |||
// got a bit annoyed that I couldn't find a pad function | |||
String spaces = " "; | |||
while (spaces.length()<maxlen) { | |||
while (spaces.length() < maxlen) { | |||
spaces += spaces; | |||
} | |||
StringBuffer msg = new StringBuffer(); | |||
msg.append(heading + lSep + lSep); | |||
for (int i=0; i<names.size(); i++) { | |||
for (int i = 0; i < names.size(); i++) { | |||
msg.append(" "); | |||
msg.append(names.elementAt(i)); | |||
if (descriptions != null) { | |||
msg.append(spaces.substring(0, maxlen - ((String)names.elementAt(i)).length() + 2)); | |||
msg.append(spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2)); | |||
msg.append(descriptions.elementAt(i)); | |||
} | |||
msg.append(lSep); | |||
@@ -68,6 +68,7 @@ import java.lang.reflect.Modifier; | |||
import org.apache.tools.ant.types.FilterSet; | |||
import org.apache.tools.ant.types.FilterSetCollection; | |||
import org.apache.tools.ant.util.FileUtils; | |||
import org.apache.tools.ant.util.JavaEnvUtils; | |||
import org.apache.tools.ant.input.InputHandler; | |||
/** | |||
@@ -88,45 +89,42 @@ import org.apache.tools.ant.input.InputHandler; | |||
public class Project { | |||
/** Message priority of "error". */ | |||
public final static int MSG_ERR = 0; | |||
public static final int MSG_ERR = 0; | |||
/** Message priority of "warning". */ | |||
public final static int MSG_WARN = 1; | |||
public static final int MSG_WARN = 1; | |||
/** Message priority of "information". */ | |||
public final static int MSG_INFO = 2; | |||
public static final int MSG_INFO = 2; | |||
/** Message priority of "verbose". */ | |||
public final static int MSG_VERBOSE = 3; | |||
public static final int MSG_VERBOSE = 3; | |||
/** Message priority of "debug". */ | |||
public final static int MSG_DEBUG = 4; | |||
public static final int MSG_DEBUG = 4; | |||
/** | |||
* Constant for the "visiting" state, used when | |||
* traversing a DFS of target dependencies. | |||
*/ | |||
private final static String VISITING = "VISITING"; | |||
private static final String VISITING = "VISITING"; | |||
/** | |||
* Constant for the "visited" state, used when | |||
* traversing a DFS of target dependencies. | |||
*/ | |||
private final static String VISITED = "VISITED"; | |||
/** Version of currently running VM. */ | |||
private static String javaVersion; | |||
private static final String VISITED = "VISITED"; | |||
/** Version constant for Java 1.0 */ | |||
public final static String JAVA_1_0 = "1.0"; | |||
public static final String JAVA_1_0 = JavaEnvUtils.JAVA_1_0; | |||
/** Version constant for Java 1.1 */ | |||
public final static String JAVA_1_1 = "1.1"; | |||
public static final String JAVA_1_1 = JavaEnvUtils.JAVA_1_1; | |||
/** Version constant for Java 1.2 */ | |||
public final static String JAVA_1_2 = "1.2"; | |||
public static final String JAVA_1_2 = JavaEnvUtils.JAVA_1_2; | |||
/** Version constant for Java 1.3 */ | |||
public final static String JAVA_1_3 = "1.3"; | |||
public static final String JAVA_1_3 = JavaEnvUtils.JAVA_1_3; | |||
/** Version constant for Java 1.4 */ | |||
public final static String JAVA_1_4 = "1.4"; | |||
public static final String JAVA_1_4 = JavaEnvUtils.JAVA_1_4; | |||
/** Default filter start token. */ | |||
public final static String TOKEN_START = FilterSet.DEFAULT_TOKEN_START; | |||
public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START; | |||
/** Default filter end token. */ | |||
public final static String TOKEN_END = FilterSet.DEFAULT_TOKEN_END; | |||
public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END; | |||
/** Name of this project. */ | |||
private String name; | |||
@@ -166,7 +164,9 @@ public class Project { | |||
* contains one FilterSet, but the wrapper is needed in order to | |||
* make it easier to use the FileUtils interface. | |||
*/ | |||
private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet); | |||
private FilterSetCollection globalFilters | |||
= new FilterSetCollection(globalFilterSet); | |||
/** Project base directory. */ | |||
private File baseDir; | |||
@@ -207,31 +207,6 @@ public class Project { | |||
return inputHandler; | |||
} | |||
static { | |||
// Determine the Java version by looking at available classes | |||
// java.lang.CharSequence was introduced in JDK 1.4 | |||
// java.lang.StrictMath was introduced in JDK 1.3 | |||
// java.lang.ThreadLocal was introduced in JDK 1.2 | |||
// java.lang.Void was introduced in JDK 1.1 | |||
// Count up version until a NoClassDefFoundError ends the try | |||
try { | |||
javaVersion = JAVA_1_0; | |||
Class.forName("java.lang.Void"); | |||
javaVersion = JAVA_1_1; | |||
Class.forName("java.lang.ThreadLocal"); | |||
javaVersion = JAVA_1_2; | |||
Class.forName("java.lang.StrictMath"); | |||
javaVersion = JAVA_1_3; | |||
Class.forName("java.lang.CharSequence"); | |||
javaVersion = JAVA_1_4; | |||
} catch (ClassNotFoundException cnfe) { | |||
// swallow as we've hit the max class version that | |||
// we have | |||
} | |||
} | |||
/** Instance of a utility class to use for file operations. */ | |||
private FileUtils fileUtils; | |||
@@ -272,9 +247,11 @@ public class Project { | |||
Class taskClass = Class.forName(value); | |||
addTaskDefinition(key, taskClass); | |||
} catch (NoClassDefFoundError ncdfe) { | |||
log("Could not load a dependent class (" + ncdfe.getMessage() + ") for task " + key, MSG_DEBUG); | |||
log("Could not load a dependent class (" | |||
+ ncdfe.getMessage() + ") for task " + key, MSG_DEBUG); | |||
} catch (ClassNotFoundException cnfe) { | |||
log("Could not load class (" + value + ") for task " + key, MSG_DEBUG); | |||
log("Could not load class (" + value | |||
+ ") for task " + key, MSG_DEBUG); | |||
} | |||
} | |||
} catch (IOException ioe) { | |||
@@ -283,7 +260,7 @@ public class Project { | |||
String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; | |||
try{ | |||
try { | |||
Properties props = new Properties(); | |||
InputStream in = this.getClass().getResourceAsStream(dataDefs); | |||
if (in == null) { | |||
@@ -481,6 +458,10 @@ public class Project { | |||
/** | |||
* Sets a property unless it is already defined as a user property | |||
* (in which case the method returns silently). | |||
* | |||
* @param name The name of the property. | |||
* Must not be <code>null</code>. | |||
* @param value The property value. Must not be <code>null</code>. | |||
*/ | |||
private void setPropertyInternal(String name, String value) { | |||
if (null != userProperties.get(name)) { | |||
@@ -517,8 +498,8 @@ public class Project { | |||
* by values, or <code>null</code> if the given string is | |||
* <code>null</code>. | |||
* | |||
* @exception BuildException if the given value has an unclosed property name, | |||
* e.g. <code>${xxx</code> | |||
* @exception BuildException if the given value has an unclosed | |||
* property name, e.g. <code>${xxx</code> | |||
*/ | |||
public String replaceProperties(String value) | |||
throws BuildException { | |||
@@ -544,7 +525,8 @@ public class Project { | |||
/** | |||
* Returns a copy of the properties table. | |||
* @return a hashtable containing all properties (including user properties). | |||
* @return a hashtable containing all properties | |||
* (including user properties). | |||
*/ | |||
public Hashtable getProperties() { | |||
Hashtable propertiesCopy = new Hashtable(); | |||
@@ -656,6 +638,8 @@ public class Project { | |||
* | |||
* @param token The token to filter. | |||
* Must not be <code>null</code>. | |||
* @param value The replacement value. | |||
* Must not be <code>null</code>. | |||
* @deprecated Use getGlobalFilterSet().addFilter(token,value) | |||
* | |||
* @see #getGlobalFilterSet() | |||
@@ -710,13 +694,15 @@ public class Project { | |||
public void setBaseDir(File baseDir) throws BuildException { | |||
baseDir = fileUtils.normalize(baseDir.getAbsolutePath()); | |||
if (!baseDir.exists()) { | |||
throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " does not exist"); | |||
throw new BuildException("Basedir " + baseDir.getAbsolutePath() | |||
+ " does not exist"); | |||
} | |||
if (!baseDir.isDirectory()) { | |||
throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " is not a directory"); | |||
throw new BuildException("Basedir " + baseDir.getAbsolutePath() | |||
+ " is not a directory"); | |||
} | |||
this.baseDir = baseDir; | |||
setPropertyInternal( "basedir", this.baseDir.getPath()); | |||
setPropertyInternal("basedir", this.baseDir.getPath()); | |||
String msg = "Project base dir set to: " + this.baseDir; | |||
log(msg, MSG_VERBOSE); | |||
} | |||
@@ -741,9 +727,10 @@ public class Project { | |||
/** | |||
* Returns the version of Java this class is running under. | |||
* @return the version of Java as a String, e.g. "1.1" | |||
* @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion | |||
*/ | |||
public static String getJavaVersion() { | |||
return javaVersion; | |||
return JavaEnvUtils.getJavaVersion(); | |||
} | |||
/** | |||
@@ -754,17 +741,19 @@ public class Project { | |||
* | |||
* @exception BuildException if this Java version is not supported | |||
* | |||
* @see #getJavaVersion() | |||
* @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion | |||
*/ | |||
public void setJavaVersionProperty() throws BuildException { | |||
String javaVersion = JavaEnvUtils.getJavaVersion(); | |||
setPropertyInternal("ant.java.version", javaVersion); | |||
// sanity check | |||
if (javaVersion == JAVA_1_0) { | |||
if (javaVersion == JavaEnvUtils.JAVA_1_0) { | |||
throw new BuildException("Ant cannot work on Java 1.0"); | |||
} | |||
log("Detected Java version: " + javaVersion + " in: " + System.getProperty("java.home"), MSG_VERBOSE); | |||
log("Detected Java version: " + javaVersion + " in: " | |||
+ System.getProperty("java.home"), MSG_VERBOSE); | |||
log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE); | |||
} | |||
@@ -803,8 +792,9 @@ public class Project { | |||
* | |||
* @see #checkTaskClass(Class) | |||
*/ | |||
public void addTaskDefinition(String taskName, Class taskClass) throws BuildException { | |||
Class old = (Class)taskClassDefinitions.get(taskName); | |||
public void addTaskDefinition(String taskName, Class taskClass) | |||
throws BuildException { | |||
Class old = (Class) taskClassDefinitions.get(taskName); | |||
if (null != old) { | |||
if (old.equals(taskClass)) { | |||
log("Ignoring override for task " + taskName | |||
@@ -812,7 +802,7 @@ public class Project { | |||
MSG_VERBOSE); | |||
return; | |||
} else { | |||
log("Trying to override old definition of task "+taskName, | |||
log("Trying to override old definition of task " + taskName, | |||
MSG_WARN); | |||
invalidateCreatedTasks(taskName); | |||
} | |||
@@ -829,31 +819,35 @@ public class Project { | |||
* Ant task implementation classes must be public, concrete, and have | |||
* a no-arg constructor. | |||
* | |||
* @param taskClass The class to be checked. | |||
* Must not be <code>null</code>. | |||
* | |||
* @exception BuildException if the class is unsuitable for being an Ant | |||
* task. An error level message is logged before | |||
* task. An error level message is logged before | |||
* this exception is thrown. | |||
*/ | |||
public void checkTaskClass(final Class taskClass) throws BuildException { | |||
if(!Modifier.isPublic(taskClass.getModifiers())) { | |||
if (!Modifier.isPublic(taskClass.getModifiers())) { | |||
final String message = taskClass + " is not public"; | |||
log(message, Project.MSG_ERR); | |||
throw new BuildException(message); | |||
} | |||
if(Modifier.isAbstract(taskClass.getModifiers())) { | |||
if (Modifier.isAbstract(taskClass.getModifiers())) { | |||
final String message = taskClass + " is abstract"; | |||
log(message, Project.MSG_ERR); | |||
throw new BuildException(message); | |||
} | |||
try { | |||
taskClass.getConstructor( null ); | |||
taskClass.getConstructor(null); | |||
// don't have to check for public, since | |||
// getConstructor finds public constructors only. | |||
} catch(NoSuchMethodException e) { | |||
final String message = "No public no-arg constructor in " + taskClass; | |||
} catch (NoSuchMethodException e) { | |||
final String message = "No public no-arg constructor in " | |||
+ taskClass; | |||
log(message, Project.MSG_ERR); | |||
throw new BuildException(message); | |||
} | |||
if( !Task.class.isAssignableFrom(taskClass) ) { | |||
if (!Task.class.isAssignableFrom(taskClass)) { | |||
TaskAdapter.checkTaskClass(taskClass, this); | |||
} | |||
} | |||
@@ -879,11 +873,11 @@ public class Project { | |||
* | |||
* @param typeName The name of the datatype. | |||
* Must not be <code>null</code>. | |||
* @param taskClass The full name of the class implementing the datatype. | |||
* @param typeClass The full name of the class implementing the datatype. | |||
* Must not be <code>null</code>. | |||
*/ | |||
public void addDataTypeDefinition(String typeName, Class typeClass) { | |||
Class old = (Class)dataClassDefinitions.get(typeName); | |||
Class old = (Class) dataClassDefinitions.get(typeName); | |||
if (null != old) { | |||
if (old.equals(typeClass)) { | |||
log("Ignoring override for datatype " + typeName | |||
@@ -891,19 +885,20 @@ public class Project { | |||
MSG_VERBOSE); | |||
return; | |||
} else { | |||
log("Trying to override old definition of datatype "+typeName, | |||
MSG_WARN); | |||
log("Trying to override old definition of datatype " | |||
+ typeName, MSG_WARN); | |||
} | |||
} | |||
String msg = " +User datatype: " + typeName + " " + typeClass.getName(); | |||
String msg = " +User datatype: " + typeName + " " | |||
+ typeClass.getName(); | |||
log(msg, MSG_DEBUG); | |||
dataClassDefinitions.put(typeName, typeClass); | |||
} | |||
/** | |||
* Returns the current datatype definition hashtable. The returned hashtable is | |||
* "live" and so should not be modified. | |||
* Returns the current datatype definition hashtable. The returned | |||
* hashtable is "live" and so should not be modified. | |||
* | |||
* @return a map of from datatype name to implementing class | |||
* (String to Class). | |||
@@ -922,10 +917,10 @@ public class Project { | |||
* | |||
* @see Project#addOrReplaceTarget | |||
*/ | |||
public void addTarget(Target target) { | |||
public void addTarget(Target target) throws BuildException { | |||
String name = target.getName(); | |||
if (targets.get(name) != null) { | |||
throw new BuildException("Duplicate target: `"+name+"'"); | |||
throw new BuildException("Duplicate target: `" + name + "'"); | |||
} | |||
addOrReplaceTarget(name, target); | |||
} | |||
@@ -945,7 +940,7 @@ public class Project { | |||
public void addTarget(String targetName, Target target) | |||
throws BuildException { | |||
if (targets.get(targetName) != null) { | |||
throw new BuildException("Duplicate target: `"+targetName+"'"); | |||
throw new BuildException("Duplicate target: `" + targetName + "'"); | |||
} | |||
addOrReplaceTarget(targetName, target); | |||
} | |||
@@ -1008,14 +1003,14 @@ public class Project { | |||
try { | |||
Object o = c.newInstance(); | |||
Task task = null; | |||
if( o instanceof Task ) { | |||
task=(Task)o; | |||
if (o instanceof Task) { | |||
task = (Task) o; | |||
} else { | |||
// "Generic" Bean - use the setter pattern | |||
// and an Adapter | |||
TaskAdapter taskA=new TaskAdapter(); | |||
taskA.setProxy( o ); | |||
task=taskA; | |||
TaskAdapter taskA = new TaskAdapter(); | |||
taskA.setProxy(o); | |||
task = taskA; | |||
} | |||
task.setProject(this); | |||
task.setTaskType(taskType); | |||
@@ -1080,7 +1075,7 @@ public class Project { | |||
/** | |||
* Creates a new instance of a data type. | |||
* | |||
* @param taskType The name of the data type to create an instance of. | |||
* @param typeName The name of the data type to create an instance of. | |||
* Must not be <code>null</code>. | |||
* | |||
* @return an instance of the specified data type, or <code>null</code> if | |||
@@ -1116,7 +1111,7 @@ public class Project { | |||
o = ctor.newInstance(new Object[] {this}); | |||
} | |||
if (o instanceof ProjectComponent) { | |||
((ProjectComponent)o).setProject(this); | |||
((ProjectComponent) o).setProject(this); | |||
} | |||
String msg = " +DataType: " + typeName; | |||
log (msg, MSG_DEBUG); | |||
@@ -1146,7 +1141,7 @@ public class Project { | |||
Throwable error = null; | |||
for (int i = 0; i < targetNames.size(); i++) { | |||
executeTarget((String)targetNames.elementAt(i)); | |||
executeTarget((String) targetNames.elementAt(i)); | |||
} | |||
} | |||
@@ -1160,15 +1155,13 @@ public class Project { | |||
* or information (<code>false</code>). | |||
*/ | |||
public void demuxOutput(String line, boolean isError) { | |||
Task task = (Task)threadTasks.get(Thread.currentThread()); | |||
Task task = (Task) threadTasks.get(Thread.currentThread()); | |||
if (task == null) { | |||
fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO); | |||
} | |||
else { | |||
} else { | |||
if (isError) { | |||
task.handleErrorOutput(line); | |||
} | |||
else { | |||
} else { | |||
task.handleOutput(line); | |||
} | |||
} | |||
@@ -1221,6 +1214,8 @@ public class Project { | |||
* respect to. May be <code>null</code>, in which case | |||
* the current directory is used. | |||
* | |||
* @return the resolved File. | |||
* | |||
* @deprecated | |||
*/ | |||
public File resolveFile(String fileName, File rootDir) { | |||
@@ -1235,6 +1230,9 @@ public class Project { | |||
* | |||
* @param fileName The name of the file to resolve. | |||
* Must not be <code>null</code>. | |||
* | |||
* @return the resolved File. | |||
* | |||
*/ | |||
public File resolveFile(String fileName) { | |||
return fileUtils.resolveFile(baseDir, fileName); | |||
@@ -1257,7 +1255,7 @@ public class Project { | |||
* @see PathTokenizer | |||
*/ | |||
public static String translatePath(String toProcess) { | |||
if ( toProcess == null || toProcess.length() == 0 ) { | |||
if (toProcess == null || toProcess.length() == 0) { | |||
return ""; | |||
} | |||
@@ -1289,7 +1287,8 @@ public class Project { | |||
* | |||
* @deprecated | |||
*/ | |||
public void copyFile(String sourceFile, String destFile) throws IOException { | |||
public void copyFile(String sourceFile, String destFile) | |||
throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile); | |||
} | |||
@@ -1310,7 +1309,8 @@ public class Project { | |||
*/ | |||
public void copyFile(String sourceFile, String destFile, boolean filtering) | |||
throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null); | |||
} | |||
/** | |||
@@ -1333,7 +1333,8 @@ public class Project { | |||
*/ | |||
public void copyFile(String sourceFile, String destFile, boolean filtering, | |||
boolean overwrite) throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null, overwrite); | |||
} | |||
/** | |||
@@ -1362,8 +1363,8 @@ public class Project { | |||
public void copyFile(String sourceFile, String destFile, boolean filtering, | |||
boolean overwrite, boolean preserveLastModified) | |||
throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, | |||
overwrite, preserveLastModified); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null, overwrite, preserveLastModified); | |||
} | |||
/** | |||
@@ -1400,7 +1401,8 @@ public class Project { | |||
*/ | |||
public void copyFile(File sourceFile, File destFile, boolean filtering) | |||
throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null); | |||
} | |||
/** | |||
@@ -1417,13 +1419,14 @@ public class Project { | |||
* @param overwrite Whether or not the destination file should be | |||
* overwritten if it already exists. | |||
* | |||
* @exception IOException | |||
* @exception IOException if the file cannot be copied. | |||
* | |||
* @deprecated | |||
*/ | |||
public void copyFile(File sourceFile, File destFile, boolean filtering, | |||
boolean overwrite) throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null, overwrite); | |||
} | |||
/** | |||
@@ -1445,32 +1448,35 @@ public class Project { | |||
* the resulting file should be set to that | |||
* of the source file. | |||
* | |||
* @exception IOException if the copying fails | |||
* @exception IOException if the file cannot be copied. | |||
* | |||
* @deprecated | |||
*/ | |||
public void copyFile(File sourceFile, File destFile, boolean filtering, | |||
boolean overwrite, boolean preserveLastModified) | |||
throws IOException { | |||
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, | |||
overwrite, preserveLastModified); | |||
fileUtils.copyFile(sourceFile, destFile, | |||
filtering ? globalFilters : null, overwrite, preserveLastModified); | |||
} | |||
/** | |||
* Calls File.setLastModified(long time) on Java above 1.1, and logs | |||
* a warning on Java 1.1. | |||
* | |||
* @param File The file to set the last modified time on. | |||
* @param file The file to set the last modified time on. | |||
* Must not be <code>null</code>. | |||
* | |||
* @param time the required modification time. | |||
* | |||
* @deprecated | |||
* | |||
* @exception BuildException if the last modified time cannot be set | |||
* despite running on a platform with a version | |||
* above 1.1. | |||
*/ | |||
public void setFileLastModified(File file, long time) throws BuildException { | |||
if (getJavaVersion() == JAVA_1_1) { | |||
public void setFileLastModified(File file, long time) | |||
throws BuildException { | |||
if (JavaEnvUtils.getJavaVersion() == JavaEnvUtils.JAVA_1_1) { | |||
log("Cannot change the modification time of " + file | |||
+ " in JDK 1.1", Project.MSG_WARN); | |||
return; | |||
@@ -1526,18 +1532,18 @@ public class Project { | |||
// build Target. | |||
tsort(root, targets, state, visiting, ret); | |||
log("Build sequence for target `"+root+"' is "+ret, MSG_VERBOSE); | |||
for (Enumeration en=targets.keys(); en.hasMoreElements();) { | |||
String curTarget = (String)(en.nextElement()); | |||
log("Build sequence for target `" + root + "' is " + ret, MSG_VERBOSE); | |||
for (Enumeration en = targets.keys(); en.hasMoreElements();) { | |||
String curTarget = (String) en.nextElement(); | |||
String st = (String) state.get(curTarget); | |||
if (st == null) { | |||
tsort(curTarget, targets, state, visiting, ret); | |||
} | |||
else if (st == VISITING) { | |||
throw new RuntimeException("Unexpected node in visiting state: "+curTarget); | |||
} else if (st == VISITING) { | |||
throw new RuntimeException("Unexpected node in visiting state: " | |||
+ curTarget); | |||
} | |||
} | |||
log("Complete build sequence is "+ret, MSG_VERBOSE); | |||
log("Complete build sequence is " + ret, MSG_VERBOSE); | |||
return ret; | |||
} | |||
@@ -1588,7 +1594,7 @@ public class Project { | |||
state.put(root, VISITING); | |||
visiting.push(root); | |||
Target target = (Target)(targets.get(root)); | |||
Target target = (Target) targets.get(root); | |||
// Make sure we exist | |||
if (target == null) { | |||
@@ -1597,7 +1603,7 @@ public class Project { | |||
sb.append("' does not exist in this project. "); | |||
visiting.pop(); | |||
if (!visiting.empty()) { | |||
String parent = (String)visiting.peek(); | |||
String parent = (String) visiting.peek(); | |||
sb.append("It is used from target `"); | |||
sb.append(parent); | |||
sb.append("'."); | |||
@@ -1606,14 +1612,13 @@ public class Project { | |||
throw new BuildException(new String(sb)); | |||
} | |||
for (Enumeration en=target.getDependencies(); en.hasMoreElements();) { | |||
for (Enumeration en = target.getDependencies(); en.hasMoreElements();) { | |||
String cur = (String) en.nextElement(); | |||
String m=(String)state.get(cur); | |||
String m = (String) state.get(cur); | |||
if (m == null) { | |||
// Not been visited | |||
tsort(cur, targets, state, visiting, ret); | |||
} | |||
else if (m == VISITING) { | |||
} else if (m == VISITING) { | |||
// Currently visiting this node, so have a cycle | |||
throw makeCircularException(cur, visiting); | |||
} | |||
@@ -1621,14 +1626,16 @@ public class Project { | |||
String p = (String) visiting.pop(); | |||
if (root != p) { | |||
throw new RuntimeException("Unexpected internal error: expected to pop "+root+" but got "+p); | |||
throw new RuntimeException("Unexpected internal error: expected to " | |||
+ "pop " + root + " but got " + p); | |||
} | |||
state.put(root, VISITED); | |||
ret.addElement(target); | |||
} | |||
/** | |||
* Builds an appropriate exception detailing a specified circular dependency. | |||
* Builds an appropriate exception detailing a specified circular | |||
* dependency. | |||
* | |||
* @param end The dependency to stop at. Must not be <code>null</code>. | |||
* @param stk A stack of dependencies. Must not be <code>null</code>. | |||
@@ -1640,10 +1647,10 @@ public class Project { | |||
sb.append(end); | |||
String c; | |||
do { | |||
c = (String)stk.pop(); | |||
c = (String) stk.pop(); | |||
sb.append(" <- "); | |||
sb.append(c); | |||
} while(!c.equals(end)); | |||
} while (!c.equals(end)); | |||
return new BuildException(new String(sb)); | |||
} | |||
@@ -1654,12 +1661,17 @@ public class Project { | |||
* @param value The value of the reference. Must not be <code>null</code>. | |||
*/ | |||
public void addReference(String name, Object value) { | |||
if (null != references.get(name)) { | |||
Object old = references.get(name); | |||
if (old == value) { | |||
// no warning, this is not changing anything | |||
return; | |||
} | |||
if (old != null) { | |||
log("Overriding previous definition of reference to " + name, | |||
MSG_WARN); | |||
} | |||
log("Adding reference: " + name + " -> " + value, MSG_DEBUG); | |||
references.put(name,value); | |||
references.put(name, value); | |||
} | |||
/** | |||
@@ -1792,7 +1804,7 @@ public class Project { | |||
*/ | |||
protected void fireTaskStarted(Task task) { | |||
// register this as the current task on the current thread. | |||
threadTasks.put(Thread.currentThread(), task); | |||
registerThreadTask(Thread.currentThread(), task); | |||
BuildEvent event = new BuildEvent(task); | |||
for (int i = 0; i < listeners.size(); i++) { | |||
BuildListener listener = (BuildListener) listeners.elementAt(i); | |||
@@ -1811,7 +1823,7 @@ public class Project { | |||
* a successful build. | |||
*/ | |||
protected void fireTaskFinished(Task task, Throwable exception) { | |||
threadTasks.remove(Thread.currentThread()); | |||
registerThreadTask(Thread.currentThread(), null); | |||
System.out.flush(); | |||
System.err.flush(); | |||
BuildEvent event = new BuildEvent(task); | |||
@@ -1832,7 +1844,8 @@ public class Project { | |||
* @param message The message to send. Should not be <code>null</code>. | |||
* @param priority The priority of the message. | |||
*/ | |||
private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) { | |||
private void fireMessageLoggedEvent(BuildEvent event, String message, | |||
int priority) { | |||
event.setMessage(message, priority); | |||
for (int i = 0; i < listeners.size(); i++) { | |||
BuildListener listener = (BuildListener) listeners.elementAt(i); | |||
@@ -1849,7 +1862,8 @@ public class Project { | |||
* @param message The message to send. Should not be <code>null</code>. | |||
* @param priority The priority of the message. | |||
*/ | |||
protected void fireMessageLogged(Project project, String message, int priority) { | |||
protected void fireMessageLogged(Project project, String message, | |||
int priority) { | |||
BuildEvent event = new BuildEvent(project); | |||
fireMessageLoggedEvent(event, message, priority); | |||
} | |||
@@ -1863,7 +1877,8 @@ public class Project { | |||
* @param message The message to send. Should not be <code>null</code>. | |||
* @param priority The priority of the message. | |||
*/ | |||
protected void fireMessageLogged(Target target, String message, int priority) { | |||
protected void fireMessageLogged(Target target, String message, | |||
int priority) { | |||
BuildEvent event = new BuildEvent(target); | |||
fireMessageLoggedEvent(event, message, priority); | |||
} | |||
@@ -1881,4 +1896,33 @@ public class Project { | |||
BuildEvent event = new BuildEvent(task); | |||
fireMessageLoggedEvent(event, message, priority); | |||
} | |||
/** | |||
* Register a task as the current task for a thread. | |||
* If the task is null, the thread's entry is removed. | |||
* | |||
* @param thread the thread on which the task is registered. | |||
* @param task the task to be registered. | |||
* @since 1.102, Ant 1.5 | |||
*/ | |||
public void registerThreadTask(Thread thread, Task task) { | |||
if (task != null) { | |||
threadTasks.put(thread, task); | |||
} else { | |||
threadTasks.remove(thread); | |||
} | |||
} | |||
/** | |||
* Get the current task assopciated with a thread, if any | |||
* | |||
* @param thread the thread for which the task is required. | |||
* @return the task which is currently registered for the given thread or | |||
* null if no task is registered. | |||
*/ | |||
public Task getThreadTask(Thread thread) { | |||
return (Task) threadTasks.get(thread); | |||
} | |||
} |
@@ -67,6 +67,7 @@ import org.apache.tools.ant.BuildException; | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
* @since Ant 1.5 | |||
*/ | |||
public class DefaultInputHandler implements InputHandler { | |||
@@ -76,6 +77,10 @@ public class DefaultInputHandler implements InputHandler { | |||
public DefaultInputHandler() { | |||
} | |||
/** | |||
* Prompts and requests input. May loop until a valid input has | |||
* been entered. | |||
*/ | |||
public void handleInput(InputRequest request) throws BuildException { | |||
String prompt = getPrompt(request); | |||
BufferedReader in = | |||
@@ -95,7 +100,7 @@ public class DefaultInputHandler implements InputHandler { | |||
/** | |||
* Constructs user prompt from a request. | |||
* | |||
* <p>This implemenation adds (choice1,choice2,choice3,...) to the | |||
* <p>This implementation adds (choice1,choice2,choice3,...) to the | |||
* prompt for <code>MultipleChoiceInputRequest</code>s.</p> | |||
* | |||
* @param request the request to construct the prompt for. | |||
@@ -110,12 +115,11 @@ public class DefaultInputHandler implements InputHandler { | |||
((MultipleChoiceInputRequest) request).getChoices().elements(); | |||
boolean first = true; | |||
while (enum.hasMoreElements()) { | |||
if (first) { | |||
first = false; | |||
} else { | |||
if (!first) { | |||
sb.append(","); | |||
} | |||
sb.append(enum.nextElement()); | |||
first = false; | |||
} | |||
sb.append(")"); | |||
prompt = sb.toString(); | |||
@@ -59,6 +59,7 @@ package org.apache.tools.ant.input; | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
* @since Ant 1.5 | |||
*/ | |||
public interface InputHandler { | |||
@@ -59,6 +59,7 @@ package org.apache.tools.ant.input; | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
* @since Ant 1.5 | |||
*/ | |||
public class InputRequest { | |||
private String prompt; | |||
@@ -61,6 +61,7 @@ import java.util.Vector; | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
* @since Ant 1.5 | |||
*/ | |||
public class MultipleChoiceInputRequest extends InputRequest { | |||
private Vector choices = new Vector(); | |||
@@ -79,12 +80,15 @@ public class MultipleChoiceInputRequest extends InputRequest { | |||
} | |||
/** | |||
* The possible values. | |||
* @return The possible values. | |||
*/ | |||
public Vector getChoices() { | |||
return choices; | |||
} | |||
/** | |||
* @return true if the input is one of the allowed values. | |||
*/ | |||
public boolean isInputValid() { | |||
return choices.contains(getInput()); | |||
} | |||
@@ -66,6 +66,7 @@ import java.util.Properties; | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @version $Revision$ | |||
* @since Ant 1.5 | |||
*/ | |||
public class PropertyFileInputHandler implements InputHandler { | |||
private Properties props = null; | |||
@@ -81,6 +82,12 @@ public class PropertyFileInputHandler implements InputHandler { | |||
public PropertyFileInputHandler() { | |||
} | |||
/** | |||
* Picks up the input from a property, using the prompt as the | |||
* name of the property. | |||
* | |||
* @exception BuildException if no property of that name can be found. | |||
*/ | |||
public void handleInput(InputRequest request) throws BuildException { | |||
readProps(); | |||
Object o = props.get(request.getPrompt()); | |||
@@ -95,13 +102,17 @@ public class PropertyFileInputHandler implements InputHandler { | |||
} | |||
} | |||
/** | |||
* Reads the properties file if it hasn't already been read. | |||
*/ | |||
private synchronized void readProps() throws BuildException { | |||
if (props == null) { | |||
String propsFile = System.getProperty(FILE_NAME_KEY); | |||
if (propsFile == null) { | |||
throw new BuildException("System property " | |||
+ FILE_NAME_KEY | |||
+ " for PropertyFileInputHandler not set"); | |||
+ " for PropertyFileInputHandler not" | |||
+ " set"); | |||
} | |||
props = new Properties(); | |||
@@ -109,7 +120,7 @@ public class PropertyFileInputHandler implements InputHandler { | |||
try { | |||
props.load(new FileInputStream(propsFile)); | |||
} catch (IOException e) { | |||
throw new BuildException("Couldn't load "+propsFile, e); | |||
throw new BuildException("Couldn't load " + propsFile, e); | |||
} | |||
} | |||
} | |||
@@ -70,6 +70,8 @@ import org.apache.tools.ant.util.StringUtils; | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* | |||
* @since Ant 1.5 | |||
* | |||
* @ant.task category="control" | |||
*/ | |||
public class Input extends Task { | |||
private String validargs = null; | |||
@@ -136,12 +138,7 @@ public class Input extends Task { | |||
getProject().getInputHandler().handleInput(request); | |||
if (addproperty != null) { | |||
if (project.getProperty(addproperty) == null) { | |||
project.setNewProperty(addproperty, request.getInput()); | |||
} else { | |||
log("Override ignored for " + addproperty, | |||
Project.MSG_VERBOSE); | |||
} | |||
project.setNewProperty(addproperty, request.getInput()); | |||
} | |||
} | |||