KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > Main


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant;
20
21 import java.io.File JavaDoc;
22 import java.io.FileInputStream JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.PrintStream JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.Properties JavaDoc;
29 import java.util.Vector JavaDoc;
30 import java.util.HashMap JavaDoc;
31
32 import org.apache.tools.ant.input.DefaultInputHandler;
33 import org.apache.tools.ant.input.InputHandler;
34 import org.apache.tools.ant.launch.AntMain;
35 import org.apache.tools.ant.util.ClasspathUtils;
36 import org.apache.tools.ant.util.FileUtils;
37 import org.apache.tools.ant.util.ProxySetup;
38
39
40 /**
41  * Command line entry point into Ant. This class is entered via the
42  * canonical `public static void main` entry point and reads the
43  * command line arguments. It then assembles and executes an Ant
44  * project.
45  * <p>
46  * If you integrating Ant into some other tool, this is not the class
47  * to use as an entry point. Please see the source code of this
48  * class to see how it manipulates the Ant project classes.
49  *
50  */

51 public class Main implements AntMain {
52
53     /** The default build file name. {@value} */
54     public static final String JavaDoc DEFAULT_BUILD_FILENAME = "build.xml";
55
56     /** Our current message output status. Follows Project.MSG_XXX. */
57     private int msgOutputLevel = Project.MSG_INFO;
58
59     /** File that we are using for configuration. */
60     private File JavaDoc buildFile; /* null */
61
62     /** Stream to use for logging. */
63     private static PrintStream JavaDoc out = System.out;
64
65     /** Stream that we are using for logging error messages. */
66     private static PrintStream JavaDoc err = System.err;
67
68     /** The build targets. */
69     private Vector JavaDoc targets = new Vector JavaDoc();
70
71     /** Set of properties that can be used by tasks. */
72     private Properties JavaDoc definedProps = new Properties JavaDoc();
73
74     /** Names of classes to add as listeners to project. */
75     private Vector JavaDoc listeners = new Vector JavaDoc(1);
76
77     /** File names of property files to load on startup. */
78     private Vector JavaDoc propertyFiles = new Vector JavaDoc(1);
79
80     /** Indicates whether this build is to support interactive input */
81     private boolean allowInput = true;
82
83     /** keep going mode */
84     private boolean keepGoingMode = false;
85
86     /**
87      * The Ant logger class. There may be only one logger. It will have
88      * the right to use the 'out' PrintStream. The class must implements the
89      * BuildLogger interface.
90      */

91     private String JavaDoc loggerClassname = null;
92
93     /**
94      * The Ant InputHandler class. There may be only one input
95      * handler.
96      */

97     private String JavaDoc inputHandlerClassname = null;
98
99     /**
100      * Whether or not output to the log is to be unadorned.
101      */

102     private boolean emacsMode = false;
103
104     /**
105      * Whether or not this instance has successfully been
106      * constructed and is ready to run.
107      */

108     private boolean readyToRun = false;
109
110     /**
111      * Whether or not we should only parse and display the project help
112      * information.
113      */

114     private boolean projectHelp = false;
115
116     /**
117      * Whether or not a logfile is being used. This is used to
118      * check if the output streams must be closed.
119      */

120     private static boolean isLogFileUsed = false;
121
122     /**
123      * optional thread priority
124      */

125     private Integer JavaDoc threadPriority = null;
126
127     /**
128      * proxy flag: default is false
129      */

130     private boolean proxy = false;
131
132     /**
133      * Prints the message of the Throwable if it (the message) is not
134      * <code>null</code>.
135      *
136      * @param t Throwable to print the message of.
137      * Must not be <code>null</code>.
138      */

139     private static void printMessage(Throwable JavaDoc t) {
140         String JavaDoc message = t.getMessage();
141         if (message != null) {
142             System.err.println(message);
143         }
144     }
145
146     /**
147      * Creates a new instance of this class using the
148      * arguments specified, gives it any extra user properties which have been
149      * specified, and then runs the build using the classloader provided.
150      *
151      * @param args Command line arguments. Must not be <code>null</code>.
152      * @param additionalUserProperties Any extra properties to use in this
153      * build. May be <code>null</code>, which is the equivalent to
154      * passing in an empty set of properties.
155      * @param coreLoader Classloader used for core classes. May be
156      * <code>null</code> in which case the system classloader is used.
157      */

158     public static void start(String JavaDoc[] args, Properties JavaDoc additionalUserProperties,
159                              ClassLoader JavaDoc coreLoader) {
160         Main m = new Main();
161         m.startAnt(args, additionalUserProperties, coreLoader);
162     }
163
164     /**
165      * Start Ant
166      * @param args command line args
167      * @param additionalUserProperties properties to set beyond those that
168      * may be specified on the args list
169      * @param coreLoader - not used
170      *
171      * @since Ant 1.6
172      */

173     public void startAnt(String JavaDoc[] args, Properties JavaDoc additionalUserProperties,
174                          ClassLoader JavaDoc coreLoader) {
175
176         try {
177             Diagnostics.validateVersion();
178             processArgs(args);
179         } catch (Throwable JavaDoc exc) {
180             handleLogfile();
181             printMessage(exc);
182             exit(1);
183             return;
184         }
185
186         if (additionalUserProperties != null) {
187             for (Enumeration JavaDoc e = additionalUserProperties.keys();
188                     e.hasMoreElements();) {
189                 String JavaDoc key = (String JavaDoc) e.nextElement();
190                 String JavaDoc property = additionalUserProperties.getProperty(key);
191                 definedProps.put(key, property);
192             }
193         }
194
195         // expect the worst
196
int exitCode = 1;
197         try {
198             try {
199                 runBuild(coreLoader);
200                 exitCode = 0;
201             } catch (ExitStatusException ese) {
202                 exitCode = ese.getStatus();
203                 if (exitCode != 0) {
204                     throw ese;
205                 }
206             }
207         } catch (BuildException be) {
208             if (err != System.err) {
209                 printMessage(be);
210             }
211         } catch (Throwable JavaDoc exc) {
212             exc.printStackTrace();
213             printMessage(exc);
214         } finally {
215             handleLogfile();
216         }
217         exit(exitCode);
218     }
219
220     /**
221      * This operation is expected to call {@link System#exit(int)}, which
222      * is what the base version does.
223      * However, it is possible to do something else.
224      * @param exitCode code to exit with
225      */

226     protected void exit(int exitCode) {
227         System.exit(exitCode);
228     }
229
230     /**
231      * Close logfiles, if we have been writing to them.
232      *
233      * @since Ant 1.6
234      */

235     private static void handleLogfile() {
236         if (isLogFileUsed) {
237             FileUtils.close(out);
238             FileUtils.close(err);
239         }
240     }
241
242     /**
243      * Command line entry point. This method kicks off the building
244      * of a project object and executes a build using either a given
245      * target or the default target.
246      *
247      * @param args Command line arguments. Must not be <code>null</code>.
248      */

249     public static void main(String JavaDoc[] args) {
250         start(args, null, null);
251     }
252
253     /**
254      * Constructor used when creating Main for later arg processing
255      * and startup
256      */

257     public Main() {
258     }
259
260     /**
261      * Sole constructor, which parses and deals with command line
262      * arguments.
263      *
264      * @param args Command line arguments. Must not be <code>null</code>.
265      *
266      * @exception BuildException if the specified build file doesn't exist
267      * or is a directory.
268      *
269      * @deprecated since 1.6.x
270      */

271     protected Main(String JavaDoc[] args) throws BuildException {
272         processArgs(args);
273     }
274
275     /**
276      * Process command line arguments.
277      * When ant is started from Launcher, launcher-only arguments doe not get
278      * passed through to this routine.
279      *
280      * @param args the command line arguments.
281      *
282      * @since Ant 1.6
283      */

284     private void processArgs(String JavaDoc[] args) {
285         String JavaDoc searchForThis = null;
286         PrintStream JavaDoc logTo = null;
287
288         //this is the list of lu
289
HashMap JavaDoc launchCommands = new HashMap JavaDoc();
290         launchCommands.put("-lib", "");
291         launchCommands.put("-cp", "");
292         launchCommands.put("-noclasspath", "");
293         launchCommands.put("--noclasspath", "");
294         launchCommands.put("-nouserlib", "");
295         launchCommands.put("--nouserlib", "");
296         launchCommands.put("-main", "");
297         // cycle through given args
298

299         for (int i = 0; i < args.length; i++) {
300             String JavaDoc arg = args[i];
301
302             if (arg.equals("-help") || arg.equals("-h")) {
303                 printUsage();
304                 return;
305             } else if (arg.equals("-version")) {
306                 printVersion();
307                 return;
308             } else if (arg.equals("-diagnostics")) {
309                 Diagnostics.doReport(System.out);
310                 return;
311             } else if (arg.equals("-quiet") || arg.equals("-q")) {
312                 msgOutputLevel = Project.MSG_WARN;
313             } else if (arg.equals("-verbose") || arg.equals("-v")) {
314                 printVersion();
315                 msgOutputLevel = Project.MSG_VERBOSE;
316             } else if (arg.equals("-debug") || arg.equals("-d")) {
317                 printVersion();
318                 msgOutputLevel = Project.MSG_DEBUG;
319             } else if (arg.equals("-noinput")) {
320                 allowInput = false;
321             } else if (arg.equals("-logfile") || arg.equals("-l")) {
322                 try {
323                     File JavaDoc logFile = new File JavaDoc(args[i + 1]);
324                     i++;
325                     logTo = new PrintStream JavaDoc(new FileOutputStream JavaDoc(logFile));
326                     isLogFileUsed = true;
327                 } catch (IOException JavaDoc ioe) {
328                     String JavaDoc msg = "Cannot write on the specified log file. "
329                         + "Make sure the path exists and you have write "
330                         + "permissions.";
331                     throw new BuildException(msg);
332                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
333                     String JavaDoc msg = "You must specify a log file when "
334                         + "using the -log argument";
335                     throw new BuildException(msg);
336                 }
337             } else if (arg.equals("-buildfile") || arg.equals("-file")
338                        || arg.equals("-f")) {
339                 try {
340                     buildFile = new File JavaDoc(args[i + 1].replace('/', File.separatorChar));
341                     i++;
342                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
343                     String JavaDoc msg = "You must specify a buildfile when "
344                         + "using the -buildfile argument";
345                     throw new BuildException(msg);
346                 }
347             } else if (arg.equals("-listener")) {
348                 try {
349                     listeners.addElement(args[i + 1]);
350                     i++;
351                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
352                     String JavaDoc msg = "You must specify a classname when "
353                         + "using the -listener argument";
354                     throw new BuildException(msg);
355                 }
356             } else if (arg.startsWith("-D")) {
357
358                 /* Interestingly enough, we get to here when a user
359                  * uses -Dname=value. However, in some cases, the OS
360                  * goes ahead and parses this out to args
361                  * {"-Dname", "value"}
362                  * so instead of parsing on "=", we just make the "-D"
363                  * characters go away and skip one argument forward.
364                  *
365                  * I don't know how to predict when the JDK is going
366                  * to help or not, so we simply look for the equals sign.
367                  */

368
369                 String JavaDoc name = arg.substring(2, arg.length());
370                 String JavaDoc value = null;
371                 int posEq = name.indexOf("=");
372                 if (posEq > 0) {
373                     value = name.substring(posEq + 1);
374                     name = name.substring(0, posEq);
375                 } else if (i < args.length - 1) {
376                     value = args[++i];
377                 } else {
378                     throw new BuildException("Missing value for property "
379                                              + name);
380                 }
381
382                 definedProps.put(name, value);
383             } else if (arg.equals("-logger")) {
384                 if (loggerClassname != null) {
385                     throw new BuildException("Only one logger class may "
386                         + " be specified.");
387                 }
388                 try {
389                     loggerClassname = args[++i];
390                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
391                     throw new BuildException("You must specify a classname when"
392                                              + " using the -logger argument");
393                 }
394             } else if (arg.equals("-inputhandler")) {
395                 if (inputHandlerClassname != null) {
396                     throw new BuildException("Only one input handler class may "
397                                              + "be specified.");
398                 }
399                 try {
400                     inputHandlerClassname = args[++i];
401                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
402                     throw new BuildException("You must specify a classname when"
403                                              + " using the -inputhandler"
404                                              + " argument");
405                 }
406             } else if (arg.equals("-emacs") || arg.equals("-e")) {
407                 emacsMode = true;
408             } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
409                 // set the flag to display the targets and quit
410
projectHelp = true;
411             } else if (arg.equals("-find") || arg.equals("-s")) {
412                 // eat up next arg if present, default to build.xml
413
if (i < args.length - 1) {
414                     searchForThis = args[++i];
415                 } else {
416                     searchForThis = DEFAULT_BUILD_FILENAME;
417                 }
418             } else if (arg.startsWith("-propertyfile")) {
419                 try {
420                     propertyFiles.addElement(args[i + 1]);
421                     i++;
422                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
423                     String JavaDoc msg = "You must specify a property filename when "
424                         + "using the -propertyfile argument";
425                     throw new BuildException(msg);
426                 }
427             } else if (arg.equals("-k") || arg.equals("-keep-going")) {
428                 keepGoingMode = true;
429             } else if (arg.equals("-nice")) {
430                 try {
431                     threadPriority = Integer.decode(args[i + 1]);
432                 } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
433                     throw new BuildException(
434                             "You must supply a niceness value (1-10)"
435                             + " after the -nice option");
436                 } catch (NumberFormatException JavaDoc e) {
437                     throw new BuildException("Unrecognized niceness value: "
438                                              + args[i + 1]);
439                 }
440                 i++;
441                 if (threadPriority.intValue() < Thread.MIN_PRIORITY
442                     || threadPriority.intValue() > Thread.MAX_PRIORITY) {
443                     throw new BuildException(
444                             "Niceness value is out of the range 1-10");
445                 }
446             } else if (launchCommands.get(arg) != null) {
447                 //catch script/ant mismatch with a meaningful message
448
//we could ignore it, but there are likely to be other
449
//version problems, so we stamp down on the configuration now
450
String JavaDoc msg = "Ant's Main method is being handed "
451                         + "an option " + arg + " that is only for the launcher class."
452                         + "\nThis can be caused by a version mismatch between "
453                         + "the ant script/.bat file and Ant itself.";
454                 throw new BuildException(msg);
455             } else if (arg.equals("-autoproxy")) {
456                 proxy = false;
457             } else if (arg.startsWith("-")) {
458                 // we don't have any more args to recognize!
459
String JavaDoc msg = "Unknown argument: " + arg;
460                 System.err.println(msg);
461                 printUsage();
462                 throw new BuildException("");
463             } else {
464                 // if it's no other arg, it may be the target
465
targets.addElement(arg);
466             }
467         }
468
469         // if buildFile was not specified on the command line,
470
if (buildFile == null) {
471             // but -find then search for it
472
if (searchForThis != null) {
473                 buildFile = findBuildFile(System.getProperty("user.dir"),
474                                           searchForThis);
475             } else {
476                 buildFile = new File JavaDoc(DEFAULT_BUILD_FILENAME);
477             }
478         }
479
480         // make sure buildfile exists
481
if (!buildFile.exists()) {
482             System.out.println("Buildfile: " + buildFile + " does not exist!");
483             throw new BuildException("Build failed");
484         }
485
486         // make sure it's not a directory (this falls into the ultra
487
// paranoid lets check everything category
488

489         if (buildFile.isDirectory()) {
490             System.out.println("What? Buildfile: " + buildFile + " is a dir!");
491             throw new BuildException("Build failed");
492         }
493
494         // Load the property files specified by -propertyfile
495
for (int propertyFileIndex = 0;
496              propertyFileIndex < propertyFiles.size();
497              propertyFileIndex++) {
498             String JavaDoc filename
499                 = (String JavaDoc) propertyFiles.elementAt(propertyFileIndex);
500             Properties JavaDoc props = new Properties JavaDoc();
501             FileInputStream JavaDoc fis = null;
502             try {
503                 fis = new FileInputStream JavaDoc(filename);
504                 props.load(fis);
505             } catch (IOException JavaDoc e) {
506                 System.out.println("Could not load property file "
507                    + filename + ": " + e.getMessage());
508             } finally {
509                 FileUtils.close(fis);
510             }
511
512             // ensure that -D properties take precedence
513
Enumeration JavaDoc propertyNames = props.propertyNames();
514             while (propertyNames.hasMoreElements()) {
515                 String JavaDoc name = (String JavaDoc) propertyNames.nextElement();
516                 if (definedProps.getProperty(name) == null) {
517                     definedProps.put(name, props.getProperty(name));
518                 }
519             }
520         }
521
522         if (msgOutputLevel >= Project.MSG_INFO) {
523             System.out.println("Buildfile: " + buildFile);
524         }
525
526         if (logTo != null) {
527             out = logTo;
528             err = logTo;
529             System.setOut(out);
530             System.setErr(err);
531         }
532         readyToRun = true;
533     }
534
535     /**
536      * Helper to get the parent file for a given file.
537      * <p>
538      * Added to simulate File.getParentFile() from JDK 1.2.
539      * @deprecated since 1.6.x
540      *
541      * @param file File to find parent of. Must not be <code>null</code>.
542      * @return Parent file or null if none
543      */

544     private File JavaDoc getParentFile(File JavaDoc file) {
545         File JavaDoc parent = file.getParentFile();
546
547         if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
548             System.out.println("Searching in " + parent.getAbsolutePath());
549         }
550
551         return parent;
552     }
553
554     /**
555      * Search parent directories for the build file.
556      * <p>
557      * Takes the given target as a suffix to append to each
558      * parent directory in search of a build file. Once the
559      * root of the file-system has been reached an exception
560      * is thrown.
561      *
562      * @param start Leaf directory of search.
563      * Must not be <code>null</code>.
564      * @param suffix Suffix filename to look for in parents.
565      * Must not be <code>null</code>.
566      *
567      * @return A handle to the build file if one is found
568      *
569      * @exception BuildException if no build file is found
570      */

571     private File JavaDoc findBuildFile(String JavaDoc start, String JavaDoc suffix)
572          throws BuildException {
573         if (msgOutputLevel >= Project.MSG_INFO) {
574             System.out.println("Searching for " + suffix + " ...");
575         }
576
577         File JavaDoc parent = new File JavaDoc(new File JavaDoc(start).getAbsolutePath());
578         File JavaDoc file = new File JavaDoc(parent, suffix);
579
580         // check if the target file exists in the current directory
581
while (!file.exists()) {
582             // change to parent directory
583
parent = getParentFile(parent);
584
585             // if parent is null, then we are at the root of the fs,
586
// complain that we can't find the build file.
587
if (parent == null) {
588                 throw new BuildException("Could not locate a build file!");
589             }
590
591             // refresh our file handle
592
file = new File JavaDoc(parent, suffix);
593         }
594
595         return file;
596     }
597
598     /**
599      * Executes the build. If the constructor for this instance failed
600      * (e.g. returned after issuing a warning), this method returns
601      * immediately.
602      *
603      * @param coreLoader The classloader to use to find core classes.
604      * May be <code>null</code>, in which case the
605      * system classloader is used.
606      *
607      * @exception BuildException if the build fails
608      */

609     private void runBuild(ClassLoader JavaDoc coreLoader) throws BuildException {
610
611         if (!readyToRun) {
612             return;
613         }
614
615         final Project project = new Project();
616         project.setCoreLoader(coreLoader);
617
618         Throwable JavaDoc error = null;
619
620         try {
621             addBuildListeners(project);
622             addInputHandler(project);
623
624             PrintStream JavaDoc savedErr = System.err;
625             PrintStream JavaDoc savedOut = System.out;
626             InputStream JavaDoc savedIn = System.in;
627
628             // use a system manager that prevents from System.exit()
629
SecurityManager JavaDoc oldsm = null;
630             oldsm = System.getSecurityManager();
631
632                 //SecurityManager can not be installed here for backwards
633
//compatibility reasons (PD). Needs to be loaded prior to
634
//ant class if we are going to implement it.
635
//System.setSecurityManager(new NoExitSecurityManager());
636
try {
637                 if (allowInput) {
638                     project.setDefaultInputStream(System.in);
639                 }
640                 System.setIn(new DemuxInputStream(project));
641                 System.setOut(new PrintStream JavaDoc(new DemuxOutputStream(project, false)));
642                 System.setErr(new PrintStream JavaDoc(new DemuxOutputStream(project, true)));
643
644
645                 if (!projectHelp) {
646                     project.fireBuildStarted();
647                 }
648
649                 // set the thread priorities
650
if (threadPriority != null) {
651                     try {
652                         project.log("Setting Ant's thread priority to "
653                                 + threadPriority, Project.MSG_VERBOSE);
654                         Thread.currentThread().setPriority(threadPriority.intValue());
655                     } catch (SecurityException JavaDoc swallowed) {
656                         //we cannot set the priority here.
657
project.log("A security manager refused to set the -nice value");
658                     }
659                 }
660
661
662
663                 project.init();
664
665                 // set user-define properties
666
Enumeration JavaDoc e = definedProps.keys();
667                 while (e.hasMoreElements()) {
668                     String JavaDoc arg = (String JavaDoc) e.nextElement();
669                     String JavaDoc value = (String JavaDoc) definedProps.get(arg);
670                     project.setUserProperty(arg, value);
671                 }
672
673                 project.setUserProperty(MagicNames.ANT_FILE,
674                                         buildFile.getAbsolutePath());
675
676                 project.setKeepGoingMode(keepGoingMode);
677                 if (proxy) {
678                     //proxy setup if enabled
679
ProxySetup proxySetup = new ProxySetup(project);
680                     proxySetup.enableProxies();
681                 }
682
683                 ProjectHelper.configureProject(project, buildFile);
684
685                 if (projectHelp) {
686                     printDescription(project);
687                     printTargets(project, msgOutputLevel > Project.MSG_INFO);
688                     return;
689                 }
690
691                 // make sure that we have a target to execute
692
if (targets.size() == 0) {
693                     if (project.getDefaultTarget() != null) {
694                         targets.addElement(project.getDefaultTarget());
695                     }
696                 }
697
698                 project.executeTargets(targets);
699             } finally {
700                 // put back the original security manager
701
//The following will never eval to true. (PD)
702
if (oldsm != null) {
703                     System.setSecurityManager(oldsm);
704                 }
705
706                 System.setOut(savedOut);
707                 System.setErr(savedErr);
708                 System.setIn(savedIn);
709             }
710         } catch (RuntimeException JavaDoc exc) {
711             error = exc;
712             throw exc;
713         } catch (Error JavaDoc e) {
714             error = e;
715             throw e;
716         } finally {
717             if (!projectHelp) {
718                 project.fireBuildFinished(error);
719             } else if (error != null) {
720                 project.log(error.toString(), Project.MSG_ERR);
721             }
722         }
723     }
724
725     /**
726      * Adds the listeners specified in the command line arguments,
727      * along with the default listener, to the specified project.
728      *
729      * @param project The project to add listeners to.
730      * Must not be <code>null</code>.
731      */

732     protected void addBuildListeners(Project project) {
733
734         // Add the default listener
735
project.addBuildListener(createLogger());
736
737         for (int i = 0; i < listeners.size(); i++) {
738             String JavaDoc className = (String JavaDoc) listeners.elementAt(i);
739             BuildListener listener =
740                     (BuildListener) ClasspathUtils.newInstance(className,
741                             Main.class.getClassLoader(), BuildListener.class);
742             if (project != null) {
743                 project.setProjectReference(listener);
744             }
745             project.addBuildListener(listener);
746         }
747     }
748
749     /**
750      * Creates the InputHandler and adds it to the project.
751      *
752      * @param project the project instance.
753      *
754      * @exception BuildException if a specified InputHandler
755      * implementation could not be loaded.
756      */

757     private void addInputHandler(Project project) throws BuildException {
758         InputHandler handler = null;
759         if (inputHandlerClassname == null) {
760             handler = new DefaultInputHandler();
761         } else {
762             handler = (InputHandler) ClasspathUtils.newInstance(
763                     inputHandlerClassname, Main.class.getClassLoader(),
764                     InputHandler.class);
765             if (project != null) {
766                 project.setProjectReference(handler);
767             }
768         }
769         project.setInputHandler(handler);
770     }
771
772     // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
773
// RuntimeException rather than just using a BuildException here? Is it
774
// in case the message could end up being written to no loggers (as the
775
// loggers could have failed to be created due to this failure)?
776
/**
777      * Creates the default build logger for sending build events to the ant
778      * log.
779      *
780      * @return the logger instance for this build.
781      */

782     private BuildLogger createLogger() {
783         BuildLogger logger = null;
784         if (loggerClassname != null) {
785             try {
786                 logger = (BuildLogger) ClasspathUtils.newInstance(
787                         loggerClassname, Main.class.getClassLoader(),
788                         BuildLogger.class);
789             } catch (BuildException e) {
790                 System.err.println("The specified logger class "
791                     + loggerClassname
792                     + " could not be used because " + e.getMessage());
793                 throw new RuntimeException JavaDoc();
794             }
795         } else {
796             logger = new DefaultLogger();
797         }
798
799         logger.setMessageOutputLevel(msgOutputLevel);
800         logger.setOutputPrintStream(out);
801         logger.setErrorPrintStream(err);
802         logger.setEmacsMode(emacsMode);
803
804         return logger;
805     }
806
807     /**
808      * Prints the usage information for this class to <code>System.out</code>.
809      */

810     private static void printUsage() {
811         String JavaDoc lSep = System.getProperty("line.separator");
812         StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
813         msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
814         msg.append("Options: " + lSep);
815         msg.append(" -help, -h print this message" + lSep);
816         msg.append(" -projecthelp, -p print project help information" + lSep);
817         msg.append(" -version print the version information and exit" + lSep);
818         msg.append(" -diagnostics print information that might be helpful to" + lSep);
819         msg.append(" diagnose or report problems." + lSep);
820         msg.append(" -quiet, -q be extra quiet" + lSep);
821         msg.append(" -verbose, -v be extra verbose" + lSep);
822         msg.append(" -debug, -d print debugging information" + lSep);
823         msg.append(" -emacs, -e produce logging information without adornments"
824                    + lSep);
825         msg.append(" -lib <path> specifies a path to search for jars and classes"
826                    + lSep);
827         msg.append(" -logfile <file> use given file for log" + lSep);
828         msg.append(" -l <file> ''" + lSep);
829         msg.append(" -logger <classname> the class which is to perform logging" + lSep);
830         msg.append(" -listener <classname> add an instance of class as a project listener"
831                    + lSep);
832         msg.append(" -noinput do not allow interactive input" + lSep);
833         msg.append(" -buildfile <file> use given buildfile" + lSep);
834         msg.append(" -file <file> ''" + lSep);
835         msg.append(" -f <file> ''" + lSep);
836         msg.append(" -D<property>=<value> use value for given property" + lSep);
837         msg.append(" -keep-going, -k execute all targets that do not depend" + lSep);
838         msg.append(" on failed target(s)" + lSep);
839         msg.append(" -propertyfile <name> load all properties from file with -D" + lSep);
840         msg.append(" properties taking precedence" + lSep);
841         msg.append(" -inputhandler <class> the class which will handle input requests" + lSep);
842         msg.append(" -find <file> (s)earch for buildfile towards the root of" + lSep);
843         msg.append(" -s <file> the filesystem and use it" + lSep);
844         msg.append(" -nice number A niceness value for the main thread:" + lSep
845                    + " 1 (lowest) to 10 (highest); 5 is the default"
846                    + lSep);
847         msg.append(" -nouserlib Run ant without using the jar files from" + lSep
848                    + " ${user.home}/.ant/lib" + lSep);
849         msg.append(" -noclasspath Run ant without using CLASSPATH" + lSep);
850         msg.append(" -autoproxy Java1.5+: use the OS proxy settings"
851                 + lSep);
852         msg.append(" -main <class> override Ant's normal entry point");
853         System.out.println(msg.toString());
854     }
855
856     /**
857      * Prints the Ant version information to <code>System.out</code>.
858      *
859      * @exception BuildException if the version information is unavailable
860      */

861     private static void printVersion() throws BuildException {
862         System.out.println(getAntVersion());
863     }
864
865     /**
866      * Cache of the Ant version information when it has been loaded.
867      */

868     private static String JavaDoc antVersion = null;
869
870     /**
871      * Returns the Ant version information, if available. Once the information
872      * has been loaded once, it's cached and returned from the cache on future
873      * calls.
874      *
875      * @return the Ant version information as a String
876      * (always non-<code>null</code>)
877      *
878      * @exception BuildException if the version information is unavailable
879      */

880     public static synchronized String JavaDoc getAntVersion() throws BuildException {
881         if (antVersion == null) {
882             try {
883                 Properties JavaDoc props = new Properties JavaDoc();
884                 InputStream JavaDoc in =
885                     Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
886                 props.load(in);
887                 in.close();
888
889                 StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
890                 msg.append("Apache Ant version ");
891                 msg.append(props.getProperty("VERSION"));
892                 msg.append(" compiled on ");
893                 msg.append(props.getProperty("DATE"));
894                 antVersion = msg.toString();
895             } catch (IOException JavaDoc ioe) {
896                 throw new BuildException("Could not load the version information:"
897                                          + ioe.getMessage());
898             } catch (NullPointerException JavaDoc npe) {
899                 throw new BuildException("Could not load the version information.");
900             }
901         }
902         return antVersion;
903     }
904
905      /**
906       * Prints the description of a project (if there is one) to
907       * <code>System.out</code>.
908       *
909       * @param project The project to display a description of.
910       * Must not be <code>null</code>.
911       */

912     private static void printDescription(Project project) {
913        if (project.getDescription() != null) {
914           project.log(project.getDescription());
915        }
916     }
917
918     /**
919      * Prints a list of all targets in the specified project to
920      * <code>System.out</code>, optionally including subtargets.
921      *
922      * @param project The project to display a description of.
923      * Must not be <code>null</code>.
924      * @param printSubTargets Whether or not subtarget names should also be
925      * printed.
926      */

927     private static void printTargets(Project project, boolean printSubTargets) {
928         // find the target with the longest name
929
int maxLength = 0;
930         Enumeration JavaDoc ptargets = project.getTargets().elements();
931         String JavaDoc targetName;
932         String JavaDoc targetDescription;
933         Target currentTarget;
934         // split the targets in top-level and sub-targets depending
935
// on the presence of a description
936
Vector JavaDoc topNames = new Vector JavaDoc();
937         Vector JavaDoc topDescriptions = new Vector JavaDoc();
938         Vector JavaDoc subNames = new Vector JavaDoc();
939
940         while (ptargets.hasMoreElements()) {
941             currentTarget = (Target) ptargets.nextElement();
942             targetName = currentTarget.getName();
943             if (targetName.equals("")) {
944                 continue;
945             }
946             targetDescription = currentTarget.getDescription();
947             // maintain a sorted list of targets
948
if (targetDescription == null) {
949                 int pos = findTargetPosition(subNames, targetName);
950                 subNames.insertElementAt(targetName, pos);
951             } else {
952                 int pos = findTargetPosition(topNames, targetName);
953                 topNames.insertElementAt(targetName, pos);
954                 topDescriptions.insertElementAt(targetDescription, pos);
955                 if (targetName.length() > maxLength) {
956                     maxLength = targetName.length();
957                 }
958             }
959         }
960
961         printTargets(project, topNames, topDescriptions, "Main targets:",
962                      maxLength);
963         //if there were no main targets, we list all subtargets
964
//as it means nothing has a description
965
if (topNames.size() == 0) {
966             printSubTargets = true;
967         }
968         if (printSubTargets) {
969             printTargets(project, subNames, null, "Other targets:", 0);
970         }
971
972         String JavaDoc defaultTarget = project.getDefaultTarget();
973         if (defaultTarget != null && !"".equals(defaultTarget)) {
974             // shouldn't need to check but...
975
project.log("Default target: " + defaultTarget);
976         }
977     }
978
979     /**
980      * Searches for the correct place to insert a name into a list so as
981      * to keep the list sorted alphabetically.
982      *
983      * @param names The current list of names. Must not be <code>null</code>.
984      * @param name The name to find a place for.
985      * Must not be <code>null</code>.
986      *
987      * @return the correct place in the list for the given name
988      */

989     private static int findTargetPosition(Vector JavaDoc names, String JavaDoc name) {
990         int res = names.size();
991         for (int i = 0; i < names.size() && res == names.size(); i++) {
992             if (name.compareTo((String JavaDoc) names.elementAt(i)) < 0) {
993                 res = i;
994             }
995         }
996         return res;
997     }
998
999     /**
1000     * Writes a formatted list of target names to <code>System.out</code>
1001     * with an optional description.
1002     *
1003     *
1004     * @param project the project instance.
1005     * @param names The names to be printed.
1006     * Must not be <code>null</code>.
1007     * @param descriptions The associated target descriptions.
1008     * May be <code>null</code>, in which case
1009     * no descriptions are displayed.
1010     * If non-<code>null</code>, this should have
1011     * as many elements as <code>names</code>.
1012     * @param heading The heading to display.
1013     * Should not be <code>null</code>.
1014     * @param maxlen The maximum length of the names of the targets.
1015     * If descriptions are given, they are padded to this
1016     * position so they line up (so long as the names really
1017     * <i>are</i> shorter than this).
1018     */

1019    private static void printTargets(Project project, Vector JavaDoc names,
1020                                     Vector JavaDoc descriptions, String JavaDoc heading,
1021                                     int maxlen) {
1022        // now, start printing the targets and their descriptions
1023
String JavaDoc lSep = System.getProperty("line.separator");
1024        // got a bit annoyed that I couldn't find a pad function
1025
String JavaDoc spaces = " ";
1026        while (spaces.length() <= maxlen) {
1027            spaces += spaces;
1028        }
1029        StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
1030        msg.append(heading + lSep + lSep);
1031        for (int i = 0; i < names.size(); i++) {
1032            msg.append(" ");
1033            msg.append(names.elementAt(i));
1034            if (descriptions != null) {
1035                msg.append(
1036                    spaces.substring(0, maxlen - ((String JavaDoc) names.elementAt(i)).length() + 2));
1037                msg.append(descriptions.elementAt(i));
1038            }
1039            msg.append(lSep);
1040        }
1041        project.log(msg.toString(), Project.MSG_WARN);
1042    }
1043}
1044
Popular Tags