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()); | |||
| } | |||
| } | |||