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