source: release-kits/lirk3/resources/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/Main.java@ 14982

Last change on this file since 14982 was 14982, checked in by oranfry, 16 years ago

initial import of LiRK3

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