Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 945   Methods: 18
NCLOC: 548   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Main.java 32.1% 34.5% 50% 34.4%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 package org.apache.tools.ant;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.FileOutputStream;
 60   
 import java.io.IOException;
 61   
 import java.io.InputStream;
 62   
 import java.io.PrintStream;
 63   
 import java.util.Enumeration;
 64   
 import java.util.Properties;
 65   
 import java.util.Vector;
 66   
 import org.apache.tools.ant.input.DefaultInputHandler;
 67   
 import org.apache.tools.ant.input.InputHandler;
 68   
 import org.apache.tools.ant.util.JavaEnvUtils;
 69   
 
 70   
 /**
 71   
  * Command line entry point into Ant. This class is entered via the
 72   
  * cannonical `public static void main` entry point and reads the
 73   
  * command line arguments. It then assembles and executes an Ant
 74   
  * project.
 75   
  * <p>
 76   
  * If you integrating Ant into some other tool, this is not the class
 77   
  * to use as an entry point. Please see the source code of this
 78   
  * class to see how it manipulates the Ant project classes.
 79   
  *
 80   
  * @author duncan@x180.com
 81   
  */
 82   
 public class Main {
 83   
 
 84   
     /** The default build file name. */
 85   
     public static final String DEFAULT_BUILD_FILENAME = "build.xml";
 86   
 
 87   
     /** Our current message output status. Follows Project.MSG_XXX. */
 88   
     private int msgOutputLevel = Project.MSG_INFO;
 89   
 
 90   
     /** File that we are using for configuration. */
 91   
     private File buildFile; /* null */
 92   
 
 93   
     /** Stream to use for logging. */
 94   
     private static PrintStream out = System.out;
 95   
 
 96   
     /** Stream that we are using for logging error messages. */
 97   
     private static PrintStream err = System.err;
 98   
 
 99   
     /** The build targets. */
 100   
     private Vector targets = new Vector(5);
 101   
 
 102   
     /** Set of properties that can be used by tasks. */
 103   
     private Properties definedProps = new Properties();
 104   
 
 105   
     /** Names of classes to add as listeners to project. */
 106   
     private Vector listeners = new Vector(5);
 107   
 
 108   
     /** File names of property files to load on startup. */
 109   
     private Vector propertyFiles = new Vector(5);
 110   
 
 111   
     /**
 112   
      * The Ant logger class. There may be only one logger. It will have
 113   
      * the right to use the 'out' PrintStream. The class must implements the
 114   
      * BuildLogger interface.
 115   
      */
 116   
     private String loggerClassname = null;
 117   
 
 118   
     /**
 119   
      * The Ant InputHandler class.  There may be only one input
 120   
      * handler.
 121   
      */
 122   
     private String inputHandlerClassname = null;
 123   
 
 124   
     /**
 125   
      * Whether or not output to the log is to be unadorned.
 126   
      */
 127   
     private boolean emacsMode = false;
 128   
 
 129   
     /**
 130   
      * Whether or not this instance has successfully been
 131   
      * constructed and is ready to run.
 132   
      */
 133   
     private boolean readyToRun = false;
 134   
 
 135   
     /**
 136   
      * Whether or not we should only parse and display the project help
 137   
      * information.
 138   
      */
 139   
     private boolean projectHelp = false;
 140   
 
 141   
     /**
 142   
      * Whether or not a logfile is being used. This is used to
 143   
      * check if the output streams must be closed.
 144   
      */
 145   
     private static boolean isLogFileUsed = false;
 146   
 
 147   
     /**
 148   
      * Prints the message of the Throwable if it (the message) is not
 149   
      * <code>null</code>.
 150   
      *
 151   
      * @param t Throwable to print the message of.
 152   
      *          Must not be <code>null</code>.
 153   
      */
 154  0
     private static void printMessage(Throwable t) {
 155  0
         String message = t.getMessage();
 156  0
         if (message != null) {
 157  0
             System.err.println(message);
 158   
         }
 159   
     }
 160   
 
 161   
     /**
 162   
      * Creates a new instance of this class using the
 163   
      * arguments specified, gives it any extra user properties which have been
 164   
      * specified, and then runs the build using the classloader provided.
 165   
      *
 166   
      * @param args Command line arguments. Must not be <code>null</code>.
 167   
      * @param additionalUserProperties Any extra properties to use in this
 168   
      *        build. May be <code>null</code>, which is the equivalent to
 169   
      *        passing in an empty set of properties.
 170   
      * @param coreLoader Classloader used for core classes. May be
 171   
      *        <code>null</code> in which case the system classloader is used.
 172   
      */
 173  1
     public static void start(String[] args, Properties additionalUserProperties,
 174   
                              ClassLoader coreLoader) {
 175  1
         Main m = null;
 176   
 
 177  1
         try {
 178  1
             Diagnostics.validateVersion();
 179  1
             m = new Main(args);
 180   
         } catch (Throwable exc) {
 181  0
             handleLogfile();
 182  0
             printMessage(exc);
 183  0
             System.exit(1);
 184   
         }
 185   
         
 186  1
         if (additionalUserProperties != null) {
 187  0
             for (Enumeration e = additionalUserProperties.keys();
 188  0
                     e.hasMoreElements();) {
 189  0
                 String key = (String) e.nextElement();
 190  0
                 String property = additionalUserProperties.getProperty(key);
 191  0
                 m.definedProps.put(key, property);
 192   
             }
 193   
         }
 194   
 
 195   
         // expect the worst
 196  1
         int exitCode = 1;
 197  1
         try {
 198  1
             m.runBuild(coreLoader);
 199  0
             exitCode = 0;
 200   
         } catch (BuildException be) {
 201  1
             if (m.err != System.err) {
 202  0
                 printMessage(be);
 203   
             }
 204   
         } catch (Throwable exc) {
 205  0
             exc.printStackTrace();
 206  0
             printMessage(exc);
 207   
         } finally {
 208  1
             handleLogfile();
 209   
         }
 210  1
         System.exit(exitCode);
 211   
     }
 212   
 
 213   
     /**
 214   
      * Close logfiles, if we have been writing to them.
 215   
      *
 216   
      * @since Ant 1.6
 217   
      */
 218  1
     private static void handleLogfile() {
 219  1
         if (isLogFileUsed) {
 220  0
             if (out != null) {
 221  0
                 try {
 222  0
                     out.close();
 223   
                 } catch (final Exception e) {
 224   
                     //ignore
 225   
                 }
 226   
             }
 227  0
             if (err != null) {
 228  0
                 try {
 229  0
                     err.close();
 230   
                 } catch (final Exception e) {
 231   
                     //ignore
 232   
                 }
 233   
             }
 234   
         }
 235   
     }
 236   
 
 237   
     /**
 238   
      * Command line entry point. This method kicks off the building
 239   
      * of a project object and executes a build using either a given
 240   
      * target or the default target.
 241   
      *
 242   
      * @param args Command line arguments. Must not be <code>null</code>.
 243   
      */
 244  1
     public static void main(String[] args) {
 245  1
         start(args, null, null);
 246   
     }
 247   
 
 248   
     /**
 249   
      * Sole constructor, which parses and deals with command line
 250   
      * arguments.
 251   
      *
 252   
      * @param args Command line arguments. Must not be <code>null</code>.
 253   
      *
 254   
      * @exception BuildException if the specified build file doesn't exist
 255   
      *                           or is a directory.
 256   
      */
 257  1
     protected Main(String[] args) throws BuildException {
 258  1
         String searchForThis = null;
 259  1
         PrintStream logTo = null;
 260   
 
 261   
         // cycle through given args
 262   
 
 263  1
         for (int i = 0; i < args.length; i++) {
 264  2
             String arg = args[i];
 265   
 
 266  2
             if (arg.equals("-help")) {
 267  0
                 printUsage();
 268  0
                 return;
 269  2
             } else if (arg.equals("-version")) {
 270  0
                 printVersion();
 271  0
                 return;
 272  2
             } else if (arg.equals("-diagnostics")){
 273  0
                 Diagnostics.doReport(System.out);
 274  0
                 return;
 275  2
             } else if (arg.equals("-quiet") || arg.equals("-q")) {
 276  0
                 msgOutputLevel = Project.MSG_WARN;
 277  2
             } else if (arg.equals("-verbose") || arg.equals("-v")) {
 278  0
                 printVersion();
 279  0
                 msgOutputLevel = Project.MSG_VERBOSE;
 280  2
             } else if (arg.equals("-debug")) {
 281  0
                 printVersion();
 282  0
                 msgOutputLevel = Project.MSG_DEBUG;
 283  2
             } else if (arg.equals("-logfile") || arg.equals("-l")) {
 284  0
                 try {
 285  0
                     File logFile = new File(args[i + 1]);
 286  0
                     i++;
 287  0
                     logTo = new PrintStream(new FileOutputStream(logFile));
 288  0
                     isLogFileUsed = true;
 289   
                 } catch (IOException ioe) {
 290  0
                     String msg = "Cannot write on the specified log file. "
 291   
                         + "Make sure the path exists and you have write "
 292   
                         + "permissions.";
 293  0
                     throw new BuildException(msg);
 294   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 295  0
                     String msg = "You must specify a log file when " +
 296   
                         "using the -log argument";
 297  0
                     throw new BuildException(msg);
 298   
                 }
 299  2
             } else if (arg.equals("-buildfile") || arg.equals("-file")
 300   
                        || arg.equals("-f")) {
 301  0
                 try {
 302  0
                     buildFile = new File(args[i + 1].replace('/', File.separatorChar));
 303  0
                     i++;
 304   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 305  0
                     String msg = "You must specify a buildfile when " +
 306   
                         "using the -buildfile argument";
 307  0
                     throw new BuildException(msg);
 308   
                 }
 309  2
             } else if (arg.equals("-listener")) {
 310  0
                 try {
 311  0
                     listeners.addElement(args[i + 1]);
 312  0
                     i++;
 313   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 314  0
                     String msg = "You must specify a classname when " +
 315   
                         "using the -listener argument";
 316  0
                     throw new BuildException(msg);
 317   
                 }
 318  2
             } else if (arg.startsWith("-D")) {
 319   
 
 320   
                 /* Interestingly enough, we get to here when a user
 321   
                  * uses -Dname=value. However, in some cases, the JDK
 322   
                  * goes ahead and parses this out to args
 323   
                  *   {"-Dname", "value"}
 324   
                  * so instead of parsing on "=", we just make the "-D"
 325   
                  * characters go away and skip one argument forward.
 326   
                  *
 327   
                  * I don't know how to predict when the JDK is going
 328   
                  * to help or not, so we simply look for the equals sign.
 329   
                  */
 330   
 
 331  1
                 String name = arg.substring(2, arg.length());
 332  1
                 String value = null;
 333  1
                 int posEq = name.indexOf("=");
 334  1
                 if (posEq > 0) {
 335  1
                     value = name.substring(posEq + 1);
 336  1
                     name = name.substring(0, posEq);
 337  0
                 } else if (i < args.length - 1) {
 338  0
                     value = args[++i];
 339   
                 }
 340   
 
 341  1
                 definedProps.put(name, value);
 342  1
             } else if (arg.equals("-logger")) {
 343  0
                 if (loggerClassname != null) {
 344  0
                     throw new BuildException("Only one logger class may "
 345   
                         + " be specified.");
 346   
                 }
 347  0
                 try {
 348  0
                     loggerClassname = args[++i];
 349   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 350  0
                     throw new BuildException("You must specify a classname when"
 351   
                                              + " using the -logger argument");
 352   
                 }
 353  1
             } else if (arg.equals("-inputhandler")) {
 354  0
                 if (inputHandlerClassname != null) {
 355  0
                     throw new BuildException("Only one input handler class may "
 356   
                                              + "be specified.");
 357   
                 }
 358  0
                 try {
 359  0
                     inputHandlerClassname = args[++i];
 360   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 361  0
                     throw new BuildException("You must specify a classname when"
 362   
                                              + " using the -inputhandler"
 363   
                                              + " argument");
 364   
                 }
 365  1
             } else if (arg.equals("-emacs")) {
 366  0
                 emacsMode = true;
 367  1
             } else if (arg.equals("-projecthelp")) {
 368   
                 // set the flag to display the targets and quit
 369  0
                 projectHelp = true;
 370  1
             } else if (arg.equals("-find")) {
 371   
                 // eat up next arg if present, default to build.xml
 372  0
                 if (i < args.length - 1) {
 373  0
                     searchForThis = args[++i];
 374   
                 } else {
 375  0
                     searchForThis = DEFAULT_BUILD_FILENAME;
 376   
                 }
 377  1
             } else if (arg.startsWith("-propertyfile")) {
 378  0
                 try {
 379  0
                     propertyFiles.addElement(args[i + 1]);
 380  0
                     i++;
 381   
                 } catch (ArrayIndexOutOfBoundsException aioobe) {
 382  0
                     String msg = "You must specify a property filename when " +
 383   
                         "using the -propertyfile argument";
 384  0
                     throw new BuildException(msg);
 385   
                 }
 386  1
             } else if (arg.startsWith("-")) {
 387   
                 // we don't have any more args to recognize!
 388  0
                 String msg = "Unknown argument: " + arg;
 389  0
                 System.out.println(msg);
 390  0
                 printUsage();
 391  0
                 throw new BuildException("");
 392   
             } else {
 393   
                 // if it's no other arg, it may be the target
 394  1
                 targets.addElement(arg);
 395   
             }
 396   
         }
 397   
 
 398   
         // if buildFile was not specified on the command line,
 399  1
         if (buildFile == null) {
 400   
             // but -find then search for it
 401  1
             if (searchForThis != null) {
 402  0
                 buildFile = findBuildFile(System.getProperty("user.dir"),
 403   
                                           searchForThis);
 404   
             } else {
 405  1
                 buildFile = new File(DEFAULT_BUILD_FILENAME);
 406   
             }
 407   
         }
 408   
 
 409   
         // make sure buildfile exists
 410  1
         if (!buildFile.exists()) {
 411  0
             System.out.println("Buildfile: " + buildFile + " does not exist!");
 412  0
             throw new BuildException("Build failed");
 413   
         }
 414   
 
 415   
         // make sure it's not a directory (this falls into the ultra
 416   
         // paranoid lets check everything catagory
 417   
 
 418  1
         if (buildFile.isDirectory()) {
 419  0
             System.out.println("What? Buildfile: " + buildFile + " is a dir!");
 420  0
             throw new BuildException("Build failed");
 421   
         }
 422   
 
 423   
         // Load the property files specified by -propertyfile
 424  1
         for (int propertyFileIndex = 0;
 425  1
              propertyFileIndex < propertyFiles.size();
 426   
              propertyFileIndex++) {
 427  0
             String filename
 428   
                 = (String) propertyFiles.elementAt(propertyFileIndex);
 429  0
             Properties props = new Properties();
 430  0
             FileInputStream fis = null;
 431  0
             try {
 432  0
                 fis = new FileInputStream(filename);
 433  0
                 props.load(fis);
 434   
             } catch (IOException e) {
 435  0
                 System.out.println("Could not load property file "
 436   
                    + filename + ": " + e.getMessage());
 437   
             } finally {
 438  0
                 if (fis != null) {
 439  0
                     try {
 440  0
                         fis.close();
 441   
                     } catch (IOException e){
 442   
                     }
 443   
                 }
 444   
             }
 445   
 
 446   
             // ensure that -D properties take precedence
 447  0
             Enumeration propertyNames = props.propertyNames();
 448  0
             while (propertyNames.hasMoreElements()) {
 449  0
                 String name = (String) propertyNames.nextElement();
 450  0
                 if (definedProps.getProperty(name) == null) {
 451  0
                     definedProps.put(name, props.getProperty(name));
 452   
                 }
 453   
             }
 454   
         }
 455   
 
 456  1
         if (msgOutputLevel >= Project.MSG_INFO) {
 457  1
             System.out.println("Buildfile: " + buildFile);
 458   
         }
 459   
 
 460  1
         if (logTo != null) {
 461  0
             out = err = logTo;
 462  0
             System.setOut(out);
 463  0
             System.setErr(out);
 464   
         }
 465  1
         readyToRun = true;
 466   
     }
 467   
 
 468   
     /**
 469   
      * Helper to get the parent file for a given file.
 470   
      * <p>
 471   
      * Added to simulate File.getParentFile() from JDK 1.2.
 472   
      *
 473   
      * @param file   File to find parent of. Must not be <code>null</code>.
 474   
      * @return       Parent file or null if none
 475   
      */
 476  0
     private File getParentFile(File file) {
 477  0
         String filename = file.getAbsolutePath();
 478  0
         file = new File(filename);
 479  0
         filename = file.getParent();
 480   
 
 481  0
         if (filename != null && msgOutputLevel >= Project.MSG_VERBOSE) {
 482  0
             System.out.println("Searching in " + filename);
 483   
         }
 484   
 
 485  0
         return (filename == null) ? null : new File(filename);
 486   
     }
 487   
 
 488   
     /**
 489   
      * Search parent directories for the build file.
 490   
      * <p>
 491   
      * Takes the given target as a suffix to append to each
 492   
      * parent directory in seach of a build file.  Once the
 493   
      * root of the file-system has been reached an exception
 494   
      * is thrown.
 495   
      *
 496   
      * @param start  Leaf directory of search.
 497   
      *               Must not be <code>null</code>.
 498   
      * @param suffix  Suffix filename to look for in parents.
 499   
      *                Must not be <code>null</code>.
 500   
      *
 501   
      * @return A handle to the build file if one is found
 502   
      *
 503   
      * @exception BuildException if no build file is found
 504   
      */
 505  0
     private File findBuildFile(String start, String suffix)
 506   
          throws BuildException {
 507  0
         if (msgOutputLevel >= Project.MSG_INFO) {
 508  0
             System.out.println("Searching for " + suffix + " ...");
 509   
         }
 510   
 
 511  0
         File parent = new File(new File(start).getAbsolutePath());
 512  0
         File file = new File(parent, suffix);
 513   
 
 514   
         // check if the target file exists in the current directory
 515  0
         while (!file.exists()) {
 516   
             // change to parent directory
 517  0
             parent = getParentFile(parent);
 518   
 
 519   
             // if parent is null, then we are at the root of the fs,
 520   
             // complain that we can't find the build file.
 521  0
             if (parent == null) {
 522  0
                 throw new BuildException("Could not locate a build file!");
 523   
             }
 524   
 
 525   
             // refresh our file handle
 526  0
             file = new File(parent, suffix);
 527   
         }
 528   
 
 529  0
         return file;
 530   
     }
 531   
 
 532   
     /**
 533   
      * Executes the build. If the constructor for this instance failed
 534   
      * (e.g. returned after issuing a warning), this method returns
 535   
      * immediately.
 536   
      *
 537   
      * @param coreLoader The classloader to use to find core classes.
 538   
      *                   May be <code>null</code>, in which case the
 539   
      *                   system classloader is used.
 540   
      *
 541   
      * @exception BuildException if the build fails
 542   
      */
 543  1
     private void runBuild(ClassLoader coreLoader) throws BuildException {
 544   
 
 545  1
         if (!readyToRun) {
 546  0
             return;
 547   
         }
 548   
 
 549  1
         final Project project = new Project();
 550  1
         project.setCoreLoader(coreLoader);
 551   
 
 552  1
         Throwable error = null;
 553   
 
 554  1
         try {
 555  1
             addBuildListeners(project);
 556  1
             addInputHandler(project);
 557   
 
 558  1
             PrintStream err = System.err;
 559  1
             PrintStream out = System.out;
 560   
 
 561   
             // use a system manager that prevents from System.exit()
 562   
             // only in JDK > 1.1
 563  1
             SecurityManager oldsm = null;
 564  1
             if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0) &&
 565   
                 !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)){
 566  1
                 oldsm = System.getSecurityManager();
 567   
 
 568   
                 //SecurityManager can not be installed here for backwards
 569   
                 //compatability reasons (PD). Needs to be loaded prior to
 570   
                 //ant class if we are going to implement it.
 571   
                 //System.setSecurityManager(new NoExitSecurityManager());
 572   
             }
 573  1
             try {
 574  1
                 project.setDefaultInputStream(System.in);
 575  1
                 System.setIn(new DemuxInputStream(project));
 576  1
                 System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
 577  1
                 System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
 578   
 
 579  1
                 if (!projectHelp) {
 580  1
                     project.fireBuildStarted();
 581   
                 }
 582  1
                 project.init();
 583  1
                 project.setUserProperty("ant.version", getAntVersion());
 584   
 
 585   
                 // set user-define properties
 586  1
                 Enumeration e = definedProps.keys();
 587  1
                 while (e.hasMoreElements()) {
 588  1
                     String arg = (String) e.nextElement();
 589  1
                     String value = (String) definedProps.get(arg);
 590  1
                     project.setUserProperty(arg, value);
 591   
                 }
 592   
 
 593  1
                 project.setUserProperty("ant.file",
 594   
                                         buildFile.getAbsolutePath());
 595   
 
 596  1
                 ProjectHelper.configureProject(project, buildFile);
 597   
 
 598  1
                 if (projectHelp) {
 599  0
                     printDescription(project);
 600  0
                     printTargets(project, msgOutputLevel > Project.MSG_INFO);
 601  0
                     return;
 602   
                 }
 603   
 
 604   
                 // make sure that we have a target to execute
 605  1
                 if (targets.size() == 0) {
 606  0
                     if (project.getDefaultTarget() != null) {
 607  0
                         targets.addElement(project.getDefaultTarget());
 608   
                     }
 609   
                 }
 610   
 
 611  1
                 project.executeTargets(targets);
 612   
             } finally {
 613   
                 // put back the original security manager
 614   
                 //The following will never eval to true. (PD)
 615  1
                 if (oldsm != null){
 616  0
                     System.setSecurityManager(oldsm);
 617   
                 }
 618   
 
 619  1
                 System.setOut(out);
 620  1
                 System.setErr(err);
 621   
             }
 622   
         } catch (RuntimeException exc) {
 623  1
             error = exc;
 624  1
             throw exc;
 625   
         } catch (Error err) {
 626  0
             error = err;
 627  0
             throw err;
 628   
         } finally {
 629  1
             if (!projectHelp) {
 630  1
                 project.fireBuildFinished(error);
 631   
             }
 632   
         }
 633   
     }
 634   
 
 635   
     /**
 636   
      * Adds the listeners specified in the command line arguments,
 637   
      * along with the default listener, to the specified project.
 638   
      *
 639   
      * @param project The project to add listeners to.
 640   
      *                Must not be <code>null</code>.
 641   
      */
 642  1
     protected void addBuildListeners(Project project) {
 643   
 
 644   
         // Add the default listener
 645  1
         project.addBuildListener(createLogger());
 646   
 
 647  1
         for (int i = 0; i < listeners.size(); i++) {
 648  0
             String className = (String) listeners.elementAt(i);
 649  0
             try {
 650  0
                 BuildListener listener =
 651   
                     (BuildListener) Class.forName(className).newInstance();
 652  0
                 project.addBuildListener(listener);
 653   
             } catch (Throwable exc) {
 654  0
                 throw new BuildException("Unable to instantiate listener "
 655   
                     + className, exc);
 656   
             }
 657   
         }
 658   
     }
 659   
 
 660   
     /**
 661   
      * Creates the InputHandler and adds it to the project.
 662   
      *
 663   
      * @exception BuildException if a specified InputHandler
 664   
      *                           implementation could not be loaded.
 665   
      */
 666  1
     private void addInputHandler(Project project) throws BuildException {
 667  1
         InputHandler handler = null;
 668  1
         if (inputHandlerClassname == null) {
 669  1
             handler = new DefaultInputHandler();
 670   
         } else {
 671  0
             try {
 672  0
                 handler = (InputHandler)
 673   
                     (Class.forName(inputHandlerClassname).newInstance());
 674   
             } catch (ClassCastException e) {
 675  0
                 String msg = "The specified input handler class "
 676   
                     + inputHandlerClassname
 677   
                     + " does not implement the InputHandler interface";
 678  0
                 throw new BuildException(msg);
 679   
             } catch (Exception e) {
 680  0
                 String msg = "Unable to instantiate specified input handler "
 681   
                     + "class " + inputHandlerClassname + " : "
 682   
                     + e.getClass().getName();
 683  0
                 throw new BuildException(msg);
 684   
             }
 685   
         }
 686  1
         project.setInputHandler(handler);
 687   
     }
 688   
 
 689   
     // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
 690   
     // RuntimeException rather than just using a BuildException here? Is it
 691   
     // in case the message could end up being written to no loggers (as the
 692   
     // loggers could have failed to be created due to this failure)?
 693   
     /**
 694   
      * Creates the default build logger for sending build events to the ant
 695   
      * log.
 696   
      *
 697   
      * @return the logger instance for this build.
 698   
      */
 699  1
     private BuildLogger createLogger() {
 700  1
         BuildLogger logger = null;
 701  1
         if (loggerClassname != null) {
 702  0
             try {
 703  0
                 logger = (BuildLogger) (Class.forName(loggerClassname).newInstance());
 704   
             } catch (ClassCastException e) {
 705  0
                 System.err.println("The specified logger class "
 706   
                     + loggerClassname
 707   
                     + " does not implement the BuildLogger interface");
 708  0
                 throw new RuntimeException();
 709   
             } catch (Exception e) {
 710  0
                 System.err.println("Unable to instantiate specified logger "
 711   
                     + "class " + loggerClassname + " : "
 712   
                     + e.getClass().getName());
 713  0
                 throw new RuntimeException();
 714   
             }
 715   
         } else {
 716  1
             logger = new DefaultLogger();
 717   
         }
 718   
 
 719  1
         logger.setMessageOutputLevel(msgOutputLevel);
 720  1
         logger.setOutputPrintStream(out);
 721  1
         logger.setErrorPrintStream(err);
 722  1
         logger.setEmacsMode(emacsMode);
 723   
 
 724  1
         return logger;
 725   
     }
 726   
 
 727   
     /**
 728   
      * Prints the usage information for this class to <code>System.out</code>.
 729   
      */
 730  0
     private static void printUsage() {
 731  0
         String lSep = System.getProperty("line.separator");
 732  0
         StringBuffer msg = new StringBuffer();
 733  0
         msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
 734  0
         msg.append("Options: " + lSep);
 735  0
         msg.append("  -help                  print this message" + lSep);
 736  0
         msg.append("  -projecthelp           print project help information" + lSep);
 737  0
         msg.append("  -version               print the version information and exit" + lSep);
 738  0
         msg.append("  -diagnostics           print information that might be helpful to" + lSep);
 739  0
         msg.append("                         diagnose or report problems." + lSep);
 740  0
         msg.append("  -quiet, -q             be extra quiet" + lSep);
 741  0
         msg.append("  -verbose, -v           be extra verbose" + lSep);
 742  0
         msg.append("  -debug                 print debugging information" + lSep);
 743  0
         msg.append("  -emacs                 produce logging information without adornments" + lSep);
 744  0
         msg.append("  -logfile <file>        use given file for log" + lSep);
 745  0
         msg.append("    -l     <file>                ''" + lSep);
 746  0
         msg.append("  -logger <classname>    the class which is to perform logging" + lSep);
 747  0
         msg.append("  -listener <classname>  add an instance of class as a project listener" + lSep);
 748  0
         msg.append("  -buildfile <file>      use given buildfile" + lSep);
 749  0
         msg.append("    -file    <file>              ''" + lSep);
 750  0
         msg.append("    -f       <file>              ''" + lSep);
 751  0
         msg.append("  -D<property>=<value>   use value for given property" + lSep);
 752  0
         msg.append("  -propertyfile <name>   load all properties from file with -D" + lSep);
 753  0
         msg.append("                         properties taking precedence" + lSep);
 754  0
         msg.append("  -inputhandler <class>  the class which will handle input requests" + lSep);
 755  0
         msg.append("  -find <file>           search for buildfile towards the root of the" + lSep);
 756  0
         msg.append("                         filesystem and use it" + lSep);
 757  0
         System.out.println(msg.toString());
 758   
     }
 759   
 
 760   
     /**
 761   
      * Prints the Ant version information to <code>System.out</code>.
 762   
      *
 763   
      * @exception BuildException if the version information is unavailable
 764   
      */
 765  0
     private static void printVersion() throws BuildException {
 766  0
         System.out.println(getAntVersion());
 767   
     }
 768   
 
 769   
     /**
 770   
      * Cache of the Ant version information when it has been loaded.
 771   
      */
 772   
     private static String antVersion = null;
 773   
 
 774   
     /**
 775   
      * Returns the Ant version information, if available. Once the information
 776   
      * has been loaded once, it's cached and returned from the cache on future
 777   
      * calls.
 778   
      *
 779   
      * @return the Ant version information as a String
 780   
      *         (always non-<code>null</code>)
 781   
      *
 782   
      * @exception BuildException if the version information is unavailable
 783   
      */
 784  2
     public static synchronized String getAntVersion() throws BuildException {
 785  2
         if (antVersion == null) {
 786  1
             try {
 787  1
                 Properties props = new Properties();
 788  1
                 InputStream in =
 789   
                     Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
 790  1
                 props.load(in);
 791  1
                 in.close();
 792   
 
 793  1
                 StringBuffer msg = new StringBuffer();
 794  1
                 msg.append("Apache Ant version ");
 795  1
                 msg.append(props.getProperty("VERSION"));
 796  1
                 msg.append(" compiled on ");
 797  1
                 msg.append(props.getProperty("DATE"));
 798  1
                 antVersion = msg.toString();
 799   
             } catch (IOException ioe) {
 800  0
                 throw new BuildException("Could not load the version information:"
 801   
                                          + ioe.getMessage());
 802   
             } catch (NullPointerException npe) {
 803  0
                 throw new BuildException("Could not load the version information.");
 804   
             }
 805   
         }
 806  2
         return antVersion;
 807   
     }
 808   
 
 809   
      /**
 810   
       * Prints the description of a project (if there is one) to
 811   
       * <code>System.out</code>.
 812   
       *
 813   
       * @param project The project to display a description of.
 814   
       *                Must not be <code>null</code>.
 815   
       */
 816  0
     private static void printDescription(Project project) {
 817  0
        if (project.getDescription() != null) {
 818  0
           project.log(project.getDescription());
 819   
        }
 820   
     }
 821   
 
 822   
     /**
 823   
      * Prints a list of all targets in the specified project to
 824   
      * <code>System.out</code>, optionally including subtargets.
 825   
      *
 826   
      * @param project The project to display a description of.
 827   
      *                Must not be <code>null</code>.
 828   
      * @param printSubTargets Whether or not subtarget names should also be
 829   
      *                        printed.
 830   
      */
 831  0
     private static void printTargets(Project project, boolean printSubTargets) {
 832   
         // find the target with the longest name
 833  0
         int maxLength = 0;
 834  0
         Enumeration ptargets = project.getTargets().elements();
 835  0
         String targetName;
 836  0
         String targetDescription;
 837  0
         Target currentTarget;
 838   
         // split the targets in top-level and sub-targets depending
 839   
         // on the presence of a description
 840  0
         Vector topNames = new Vector();
 841  0
         Vector topDescriptions = new Vector();
 842  0
         Vector subNames = new Vector();
 843   
 
 844  0
         while (ptargets.hasMoreElements()) {
 845  0
             currentTarget = (Target) ptargets.nextElement();
 846  0
             targetName = currentTarget.getName();
 847  0
             if (targetName.equals("")) {
 848  0
                 continue;
 849   
             }
 850  0
             targetDescription = currentTarget.getDescription();
 851   
             // maintain a sorted list of targets
 852  0
             if (targetDescription == null) {
 853  0
                 int pos = findTargetPosition(subNames, targetName);
 854  0
                 subNames.insertElementAt(targetName, pos);
 855   
             } else {
 856  0
                 int pos = findTargetPosition(topNames, targetName);
 857  0
                 topNames.insertElementAt(targetName, pos);
 858  0
                 topDescriptions.insertElementAt(targetDescription, pos);
 859  0
                 if (targetName.length() > maxLength) {
 860  0
                     maxLength = targetName.length();
 861   
                 }
 862   
             }
 863   
         }
 864   
 
 865  0
         printTargets(project, topNames, topDescriptions, "Main targets:",
 866   
                      maxLength);
 867   
         //if there were no main targets, we list all subtargets
 868   
         //as it means nothing has a description
 869  0
         if (topNames.size() == 0) {
 870  0
             printSubTargets = true;
 871   
         }
 872  0
         if (printSubTargets) {
 873  0
             printTargets(project, subNames, null, "Subtargets:", 0);
 874   
         }
 875   
 
 876  0
         String defaultTarget = project.getDefaultTarget();
 877  0
         if (defaultTarget != null && !"".equals(defaultTarget)) {
 878   
             // shouldn't need to check but...
 879  0
             project.log("Default target: " + defaultTarget);
 880   
         }
 881   
     }
 882   
 
 883   
     /**
 884   
      * Searches for the correct place to insert a name into a list so as
 885   
      * to keep the list sorted alphabetically.
 886   
      *
 887   
      * @param names The current list of names. Must not be <code>null</code>.
 888   
      * @param name  The name to find a place for.
 889   
      *              Must not be <code>null</code>.
 890   
      *
 891   
      * @return the correct place in the list for the given name
 892   
      */
 893  0
     private static int findTargetPosition(Vector names, String name) {
 894  0
         int res = names.size();
 895  0
         for (int i = 0; i < names.size() && res == names.size(); i++) {
 896  0
             if (name.compareTo((String) names.elementAt(i)) < 0) {
 897  0
                 res = i;
 898   
             }
 899   
         }
 900  0
         return res;
 901   
     }
 902   
 
 903   
     /**
 904   
      * Writes a formatted list of target names to <code>System.out</code>
 905   
      * with an optional description.
 906   
      *
 907   
      * @param names The names to be printed.
 908   
      *              Must not be <code>null</code>.
 909   
      * @param descriptions The associated target descriptions.
 910   
      *                     May be <code>null</code>, in which case
 911   
      *                     no descriptions are displayed.
 912   
      *                     If non-<code>null</code>, this should have
 913   
      *                     as many elements as <code>names</code>.
 914   
      * @param heading The heading to display.
 915   
      *                Should not be <code>null</code>.
 916   
      * @param maxlen The maximum length of the names of the targets.
 917   
      *               If descriptions are given, they are padded to this
 918   
      *               position so they line up (so long as the names really
 919   
      *               <i>are</i> shorter than this).
 920   
      */
 921  0
     private static void printTargets(Project project, Vector names,
 922   
                                      Vector descriptions, String heading,
 923   
                                      int maxlen) {
 924   
         // now, start printing the targets and their descriptions
 925  0
         String lSep = System.getProperty("line.separator");
 926   
         // got a bit annoyed that I couldn't find a pad function
 927  0
         String spaces = "    ";
 928  0
         while (spaces.length() <= maxlen) {
 929  0
             spaces += spaces;
 930   
         }
 931  0
         StringBuffer msg = new StringBuffer();
 932  0
         msg.append(heading + lSep + lSep);
 933  0
         for (int i = 0; i < names.size(); i++) {
 934  0
             msg.append(" ");
 935  0
             msg.append(names.elementAt(i));
 936  0
             if (descriptions != null) {
 937  0
                 msg.append(spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2));
 938  0
                 msg.append(descriptions.elementAt(i));
 939   
             }
 940  0
             msg.append(lSep);
 941   
         }
 942  0
         project.log(msg.toString());
 943   
     }
 944   
 }
 945