| Main.java |
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 */
00 private String loggerClassname = null;
01
02 /**
03 * The Ant InputHandler class. There may be only one input
04 * handler.
05 */
06 private String inputHandlerClassname = null;
07
08 /**
09 * Whether or not output to the log is to be unadorned.
10 */
11 private boolean emacsMode = false;
12
13 /**
14 * Whether or not this instance has successfully been
15 * constructed and is ready to run.
16 */
17 private boolean readyToRun = false;
18
19 /**
20 * Whether or not we should only parse and display the project help
21 * information.
22 */
23 private boolean projectHelp = false;
24
25 /**
26 * Whether or not a logfile is being used. This is used to
27 * check if the output streams must be closed.
28 */
29 private static boolean isLogFileUsed = false;
30
31 /**
32 * optional thread priority
33 */
34 private Integer threadPriority = null;
35 /**
36 * Installer Context
37 */
38 private InstallerContext ctx = null;
39
40 /**
41 * Prints the message of the Throwable if it (the message) is not
42 * <code>null</code>.
43 *
44 * @param t Throwable to print the message of.
45 * Must not be <code>null</code>.
46 */
47 private static void printMessage(Throwable t) {
48 String message = t.getMessage();
49 if (message != null) {
50 System.err.println(message);
51 }
52 }
53
54 /**
55 * Creates a new instance of this class using the
56 * arguments specified, gives it any extra user properties which have been
57 * specified, and then runs the build using the classloader provided.
58 *
59 * @param args Command line arguments. Must not be <code>null</code>.
60 * @param additionalUserProperties Any extra properties to use in this
61 * build. May be <code>null</code>, which is the equivalent to
62 * passing in an empty set of properties.
63 * @param coreLoader Classloader used for core classes. May be
64 * <code>null</code> in which case the system classloader is used.
65 */
66 public static void start(String[] args, Properties additionalUserProperties,
67 ClassLoader coreLoader) {
68 throw new UnsupportedOperationException("Required by Ant interface but not used");
69 //Main m = new Main();
70 //m.startAnt(args, additionalUserProperties, coreLoader);
71 }
72
73
74 public void startAnt(String[] args, Properties additionalUserProperties,
75 ClassLoader coreLoader) {
76 throw new UnsupportedOperationException("Required by Ant interface but not used");
77 //startAnt(args, additionalUserProperties, coreLoader, null); // FindBugs does not like this
78 }
79 /**
80 * Start Ant
81 * @param args command line args
82 * @param additionalUserProperties properties to set beyond those that
83 * may be specified on the args list
84 * @param coreLoader - not used
85 * @return the return code that was used for System.exit() in the original Ant
86 *
87 * @since Ant 1.6
88 */
89 public int startAnt(String[] args, Properties additionalUserProperties,
90 ClassLoader coreLoader, InstallerContext ctx) {
91 this.ctx = ctx;
92 out = ctx.getAntOutputRenderer().getOut();
93 err = ctx.getAntOutputRenderer().getErr();
94 try {
95 Diagnostics.validateVersion();
96 processArgs(args);
97 } catch (Throwable exc) {
98 handleLogfile();
99 printMessage(exc);
00 return 1;
01 }
02
03 if (additionalUserProperties != null) {
04 for (Enumeration e = additionalUserProperties.keys();
05 e.hasMoreElements();) {
06 String key = (String) e.nextElement();
07 String property = additionalUserProperties.getProperty(key);
08 definedProps.put(key, property);
09 }
10 }
11
12 // expect the worst
13 int exitCode = 1;
14 try {
15 try {
16 runBuild(coreLoader);
17 exitCode = 0;
18 } catch (ExitStatusException ese) {
19 exitCode = ese.getStatus();
20 if (exitCode != 0) {
21 throw ese;
22 }
23 }
24 } catch (BuildException be) {
25 if (err != System.err) {
26 printMessage(be);
27 }
28 } catch (Throwable exc) {
29 exc.printStackTrace();
30 printMessage(exc);
31 } finally {
32 handleLogfile();
33 }
34 //mod by Paul Hinds
35 return exitCode;
36 //System.exit(exitCode);
37 }
38
39 /**
40 * Close logfiles, if we have been writing to them.
41 *
42 * @since Ant 1.6
43 */
44 private static void handleLogfile() {
45 if (isLogFileUsed) {
46 if (out != null) {
47 try {
48 out.close();
49 } catch (final Exception e) {
50 //ignore
51 }
52 }
53 if (err != null) {
54 try {
55 err.close();
56 } catch (final Exception e) {
57 //ignore
58 }
59 }
60 }
61 }
62
63 /**
64 * Command line entry point. This method kicks off the building
65 * of a project object and executes a build using either a given
66 * target or the default target.
67 *
68 * @param args Command line arguments. Must not be <code>null</code>.
69 */
70// public static void main(String[] args) {
71// start(args, null, null);
72// }
73//
74 /**
75 * Constructor used when creating Main for later arg processing
76 * and startup
77 */
78 public Main() {
79 }
80
81 /**
82 * Sole constructor, which parses and deals with command line
83 * arguments.
84 *
85 * @param args Command line arguments. Must not be <code>null</code>.
86 *
87 * @exception BuildException if the specified build file doesn't exist
88 * or is a directory.
89 *
90 * @deprecated
91 */
92 protected Main(String[] args) throws BuildException {
93 processArgs(args);
94 }
95
96 /**
97 * Process command line arguments.
98 * When ant is started from Launcher, the -lib argument does not get
99 * passed through to this routine.
00 *
01 * @param args the command line arguments.
02 *
03 * @since Ant 1.6
04 */
05 private void processArgs(String[] args) {
06 String searchForThis = null;
07 PrintStream logTo = null;
08
09 // cycle through given args
10
11 for (int i = 0; i < args.length; i++) {
12 String arg = args[i];
13
14 if (arg.equals("-help") || arg.equals("-h")) {
15 printUsage();
16 return;
17 } else if (arg.equals("-version")) {
18 printVersion();
19 return;
20 } else if (arg.equals("-diagnostics")) {
21 Diagnostics.doReport(System.out);
22 return;
23 } else if (arg.equals("-quiet") || arg.equals("-q")) {
24 msgOutputLevel = Project.MSG_WARN;
25 } else if (arg.equals("-verbose") || arg.equals("-v")) {
26 printVersion();
27 msgOutputLevel = Project.MSG_VERBOSE;
28 } else if (arg.equals("-debug") || arg.equals("-d")) {
29 printVersion();
30 msgOutputLevel = Project.MSG_DEBUG;
31 } else if (arg.equals("-noinput")) {
32 allowInput = false;
33 } else if (arg.equals("-logfile") || arg.equals("-l")) {
34 try {
35 File logFile = new File(args[i + 1]);
36 i++;
37 logTo = new PrintStream(new FileOutputStream(logFile));
38 isLogFileUsed = true;
39 } catch (IOException ioe) {
40 String msg = "Cannot write on the specified log file. "
41 + "Make sure the path exists and you have write "
42 + "permissions.";
43 throw new BuildException(msg);
44 } catch (ArrayIndexOutOfBoundsException aioobe) {
45 String msg = "You must specify a log file when "
46 + "using the -log argument";
47 throw new BuildException(msg);
48 }
49 } else if (arg.equals("-buildfile") || arg.equals("-file")
50 || arg.equals("-f")) {
51 try {
52 buildFile = new File(args[i + 1].replace('/', File.separatorChar));
53 i++;
54 } catch (ArrayIndexOutOfBoundsException aioobe) {
55 String msg = "You must specify a buildfile when "
56 + "using the -buildfile argument";
57 throw new BuildException(msg);
58 }
59 } else if (arg.equals("-listener")) {
60 try {
61 listeners.addElement(args[i + 1]);
62 i++;
63 } catch (ArrayIndexOutOfBoundsException aioobe) {
64 String msg = "You must specify a classname when "
65 + "using the -listener argument";
66 throw new BuildException(msg);
67 }
68 } else if (arg.startsWith("-D")) {
69
70 /* Interestingly enough, we get to here when a user
71 * uses -Dname=value. However, in some cases, the OS
72 * goes ahead and parses this out to args
73 * {"-Dname", "value"}
74 * so instead of parsing on "=", we just make the "-D"
75 * characters go away and skip one argument forward.
76 *
77 * I don't know how to predict when the JDK is going
78 * to help or not, so we simply look for the equals sign.
79 */
80
81 String name = arg.substring(2, arg.length());
82 String value = null;
83 int posEq = name.indexOf("=");
84 if (posEq > 0) {
85 value = name.substring(posEq + 1);
86 name = name.substring(0, posEq);
87 } else if (i < args.length - 1) {
88 value = args[++i];
89 } else {
90 throw new BuildException("Missing value for property "
91 + name);
92 }
93
94 definedProps.put(name, value);
95 } else if (arg.equals("-logger")) {
96 if (loggerClassname != null) {
97 throw new BuildException("Only one logger class may "
98 + " be specified.");
99 }
00 try {
01 loggerClassname = args[++i];
02 } catch (ArrayIndexOutOfBoundsException aioobe) {
03 throw new BuildException("You must specify a classname when"
04 + " using the -logger argument");
05 }
06 } else if (arg.equals("-inputhandler")) {
07 if (inputHandlerClassname != null) {
08 throw new BuildException("Only one input handler class may "
09 + "be specified.");
10 }
11 try {
12 inputHandlerClassname = args[++i];
13 } catch (ArrayIndexOutOfBoundsException aioobe) {
14 throw new BuildException("You must specify a classname when"
15 + " using the -inputhandler"
16 + " argument");
17 }
18 } else if (arg.equals("-emacs") || arg.equals("-e")) {
19 emacsMode = true;
20 } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
21 // set the flag to display the targets and quit
22 projectHelp = true;
23 } else if (arg.equals("-find") || arg.equals("-s")) {
24 // eat up next arg if present, default to build.xml
25 if (i < args.length - 1) {
26 searchForThis = args[++i];
27 } else {
28 searchForThis = DEFAULT_BUILD_FILENAME;
29 }
30 } else if (arg.startsWith("-propertyfile")) {
31 try {
32 propertyFiles.addElement(args[i + 1]);
33 i++;
34 } catch (ArrayIndexOutOfBoundsException aioobe) {
35 String msg = "You must specify a property filename when "
36 + "using the -propertyfile argument";
37 throw new BuildException(msg);
38 }
39 } else if (arg.equals("-k") || arg.equals("-keep-going")) {
40 keepGoingMode = true;
41 } else if (arg.equals("-nice")) {
42 try {
43 threadPriority=Integer.decode(args[i + 1]);
44 } catch (ArrayIndexOutOfBoundsException aioobe) {
45 throw new BuildException(
46 "You must supply a niceness value (1-10)"+
47 " after the -nice option");
48 } catch (NumberFormatException e) {
49 throw new BuildException("Unrecognized niceness value: " +
50 args[i + 1]);
51 }
52 i++;
53 if(threadPriority.intValue()<Thread.MIN_PRIORITY ||
54 threadPriority.intValue()>Thread.MAX_PRIORITY) {
55 throw new BuildException(
56 "Niceness value is out of the range 1-10");
57 }
58 } else if (arg.startsWith("-")) {
59 // we don't have any more args to recognize!
60 String msg = "Unknown argument: " + arg;
61 System.out.println(msg);
62 printUsage();
63 throw new BuildException("");
64 } else {
65 // if it's no other arg, it may be the target
66 targets.addElement(arg);
67 }
68 }
69
70 // if buildFile was not specified on the command line,
71 if (buildFile == null) {
72 // but -find then search for it
73 if (searchForThis != null) {
74 buildFile = findBuildFile(System.getProperty("user.dir"),
75 searchForThis);
76 } else {
77 buildFile = new File(DEFAULT_BUILD_FILENAME);
78 }
79 }
80
81 // make sure buildfile exists
82 if (!buildFile.exists()) {
83 System.out.println("Buildfile: " + buildFile + " does not exist!");
84 throw new BuildException("Build failed");
85 }
86
87 // make sure it's not a directory (this falls into the ultra
88 // paranoid lets check everything category
89
90 if (buildFile.isDirectory()) {
91 System.out.println("What? Buildfile: " + buildFile + " is a dir!");
92 throw new BuildException("Build failed");
93 }
94
95 // Load the property files specified by -propertyfile
96 for (int propertyFileIndex = 0;
97 propertyFileIndex < propertyFiles.size();
98 propertyFileIndex++) {
99 String filename
00 = (String) propertyFiles.elementAt(propertyFileIndex);
01 Properties props = new Properties();
02 FileInputStream fis = null;
03 try {
04 fis = new FileInputStream(filename);
05 props.load(fis);
06 } catch (IOException e) {
07 System.out.println("Could not load property file "
08 + filename + ": " + e.getMessage());
09 } finally {
10 if (fis != null) {
11 try {
12 fis.close();
13 } catch (IOException e) {
14 // ignore
15 }
16 }
17 }
18
19 // ensure that -D properties take precedence
20 Enumeration propertyNames = props.propertyNames();
21 while (propertyNames.hasMoreElements()) {
22 String name = (String) propertyNames.nextElement();
23 if (definedProps.getProperty(name) == null) {
24 definedProps.put(name, props.getProperty(name));
25 }
26 }
27 }
28
29 if (msgOutputLevel >= Project.MSG_INFO) {
30 System.out.println("Buildfile: " + buildFile);
31 }
32
33 if (logTo != null) {
34 out = logTo;
35 err = logTo;
36 System.setOut(out);
37 System.setErr(err);
38 }
39 readyToRun = true;
40 }
41
42 /**
43 * Helper to get the parent file for a given file.
44 * <p>
45 * Added to simulate File.getParentFile() from JDK 1.2.
46 * @deprecated
47 *
48 * @param file File to find parent of. Must not be <code>null</code>.
49 * @return Parent file or null if none
50 */
51 private File getParentFile(File file) {
52 File parent = file.getParentFile();
53
54 if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
55 System.out.println("Searching in " + parent.getAbsolutePath());
56 }
57
58 return parent;
59 }
60
61 /**
62 * Search parent directories for the build file.
63 * <p>
64 * Takes the given target as a suffix to append to each
65 * parent directory in search of a build file. Once the
66 * root of the file-system has been reached an exception
67 * is thrown.
68 *
69 * @param start Leaf directory of search.
70 * Must not be <code>null</code>.
71 * @param suffix Suffix filename to look for in parents.
72 * Must not be <code>null</code>.
73 *
74 * @return A handle to the build file if one is found
75 *
76 * @exception BuildException if no build file is found
77 */
78 private File findBuildFile(String start, String suffix)
79 throws BuildException {
80 if (msgOutputLevel >= Project.MSG_INFO) {
81 System.out.println("Searching for " + suffix + " ...");
82 }
83
84 File parent = new File(new File(start).getAbsolutePath());
85 File file = new File(parent, suffix);
86
87 // check if the target file exists in the current directory
88 while (!file.exists()) {
89 // change to parent directory
90 parent = getParentFile(parent);
91
92 // if parent is null, then we are at the root of the fs,
93 // complain that we can't find the build file.
94 if (parent == null) {
95 throw new BuildException("Could not locate a build file!");
96 }
97
98 // refresh our file handle
99 file = new File(parent, suffix);
00 }
01
02 return file;
03 }
04
05 /**
06 * Executes the build. If the constructor for this instance failed
07 * (e.g. returned after issuing a warning), this method returns
08 * immediately.
09 *
10 * @param coreLoader The classloader to use to find core classes.
11 * May be <code>null</code>, in which case the
12 * system classloader is used.
13 *
14 * @exception BuildException if the build fails
15 */
16 private void runBuild(ClassLoader coreLoader) throws BuildException {
17
18 if (!readyToRun) {
19 return;
20 }
21
22 final Project project = new Project();
23 project.setCoreLoader(coreLoader);
24
25 Throwable error = null;
26
27 try {
28 addBuildListeners(project);
29 addInputHandler(project);
30
31 PrintStream err = System.err;
32 PrintStream out = System.out;
33 InputStream in = System.in;
34
35 // use a system manager that prevents from System.exit()
36 // only in JDK > 1.1
37 SecurityManager oldsm = null;
38 if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0)
39 && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
40 oldsm = System.getSecurityManager();
41
42 //SecurityManager can not be installed here for backwards
43 //compatibility reasons (PD). Needs to be loaded prior to
44 //ant class if we are going to implement it.
45 //System.setSecurityManager(new NoExitSecurityManager());
46 }
47 try {
48 if (allowInput) {
49 project.setDefaultInputStream(System.in);
50 }
51 //System.setIn(new DemuxInputStream(project));
52 //System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
53 //System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
54
55
56 if (!projectHelp) {
57 project.fireBuildStarted();
58 }
59
60 // set the thread priorities
61 if (threadPriority != null) {
62 try {
63 project.log("Setting Ant's thread priority to "
64 + threadPriority,Project.MSG_VERBOSE);
65 Thread.currentThread().setPriority(threadPriority.intValue());
66 } catch (SecurityException swallowed) {
67 //we cannot set the priority here.
68 project.log("A security manager refused to set the -nice value");
69 }
70 }
71
72 project.init();
73 project.setUserProperty("ant.version", getAntVersion());
74
75 // set user-define properties
76 Enumeration e = definedProps.keys();
77 while (e.hasMoreElements()) {
78 String arg = (String) e.nextElement();
79 String value = (String) definedProps.get(arg);
80 project.setUserProperty(arg, value);
81 }
82
83 project.setUserProperty("ant.file",
84 buildFile.getAbsolutePath());
85 project.setKeepGoingMode(keepGoingMode);
86
87 ProjectHelper.configureProject(project, buildFile);
88
89 project.setBasedir(definedProps.getProperty(PropertiesFileRenderer.FILE_ROOT_PROPERTY));
90
91
92 if (projectHelp) {
93 printDescription(project);
94 printTargets(project, msgOutputLevel > Project.MSG_INFO);
95 return;
96 }
97
98 // make sure that we have a target to execute
99 if (targets.size() == 0) {
00 if (project.getDefaultTarget() != null) {
01 targets.addElement(project.getDefaultTarget());
02 }
03 }
04 project.executeTargets(targets);
05 } finally {
06 // put back the original security manager
07 //The following will never eval to true. (PD)
08 if (oldsm != null) {
09 System.setSecurityManager(oldsm);
10 }
11
12 System.setOut(out);
13 System.setErr(err);
14 System.setIn(in);
15 }
16 } catch (RuntimeException exc) {
17 error = exc;
18 throw exc;
19 } catch (Error err) {
20 error = err;
21 throw err;
22 } finally {
23 if (!projectHelp) {
24 project.fireBuildFinished(error);
25 } else if (error != null) {
26 project.log(error.toString(), Project.MSG_ERR);
27 }
28 }
29 }
30
31 /**
32 * Adds the listeners specified in the command line arguments,
33 * along with the default listener, to the specified project.
34 *
35 * @param project The project to add listeners to.
36 * Must not be <code>null</code>.
37 */
38 protected void addBuildListeners(Project project) {
39
40 // Add the default listener
41 project.addBuildListener(createLogger());
42
43 //Add the AntInstaller Listener
44 if(ctx.getBuildListener()!=null){
45 project.addBuildListener(ctx.getBuildListener());
46 }
47
48 for (int i = 0; i < listeners.size(); i++) {
49 String className = (String) listeners.elementAt(i);
50 try {
51 BuildListener listener =
52 (BuildListener) Class.forName(className).newInstance();
53 if (project != null) {
54 project.setProjectReference(listener);
55 }
56 project.addBuildListener(listener);
57 } catch (Throwable exc) {
58 throw new BuildException("Unable to instantiate listener "
59 + className, exc);
60 }
61 }
62 }
63
64 /**
65 * Creates the InputHandler and adds it to the project.
66 *
67 * @param project the project instance.
68 *
69 * @exception BuildException if a specified InputHandler
70 * implementation could not be loaded.
71 */
72 private void addInputHandler(Project project) throws BuildException {
73 InputHandler handler = null;
74 if (inputHandlerClassname == null) {
75 handler = new DefaultInputHandler();
76 } else {
77 try {
78 handler = (InputHandler)
79 (Class.forName(inputHandlerClassname).newInstance());
80 if (project != null) {
81 project.setProjectReference(handler);
82 }
83 } catch (ClassCastException e) {
84 String msg = "The specified input handler class "
85 + inputHandlerClassname
86 + " does not implement the InputHandler interface";
87 throw new BuildException(msg);
88 } catch (Exception e) {
89 String msg = "Unable to instantiate specified input handler "
90 + "class " + inputHandlerClassname + " : "
91 + e.getClass().getName();
92 throw new BuildException(msg);
93 }
94 }
95 project.setInputHandler(handler);
96 }
97
98 // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
99 // RuntimeException rather than just using a BuildException here? Is it
00 // in case the message could end up being written to no loggers (as the
01 // loggers could have failed to be created due to this failure)?
02 /**
03 * Creates the default build logger for sending build events to the ant
04 * log.
05 *
06 * @return the logger instance for this build.
07 */
08 private BuildLogger createLogger() {
09 BuildLogger logger = null;
10 if (loggerClassname != null) {
11 try {
12 Class loggerClass = Class.forName(loggerClassname);
13 logger = (BuildLogger) (loggerClass.newInstance());
14 } catch (ClassCastException e) {
15 System.err.println("The specified logger class "
16 + loggerClassname
17 + " does not implement the BuildLogger interface");
18 throw new RuntimeException();
19 } catch (Exception e) {
20 System.err.println("Unable to instantiate specified logger "
21 + "class " + loggerClassname + " : "
22 + e.getClass().getName());
23 throw new RuntimeException();
24 }
25 } else {
26 logger = new DefaultLogger();
27 }
28
29 logger.setMessageOutputLevel(msgOutputLevel);
30 logger.setOutputPrintStream(out);
31 logger.setErrorPrintStream(err);
32 logger.setEmacsMode(emacsMode);
33
34 return logger;
35 }
36
37 /**
38 * Prints the usage information for this class to <code>System.out</code>.
39 */
40 private static void printUsage() {
41 String lSep = System.getProperty("line.separator");
42 StringBuffer msg = new StringBuffer();
43 msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
44 msg.append("Options: " + lSep);
45 msg.append(" -help, -h print this message" + lSep);
46 msg.append(" -projecthelp, -p print project help information" + lSep);
47 msg.append(" -version print the version information and exit" + lSep);
48 msg.append(" -diagnostics print information that might be helpful to" + lSep);
49 msg.append(" diagnose or report problems." + lSep);
50 msg.append(" -quiet, -q be extra quiet" + lSep);
51 msg.append(" -verbose, -v be extra verbose" + lSep);
52 msg.append(" -debug, -d print debugging information" + lSep);
53 msg.append(" -emacs, -e produce logging information without adornments" + lSep);
54 msg.append(" -lib <path> specifies a path to search for jars and classes" + lSep);
55 msg.append(" -logfile <file> use given file for log" + lSep);
56 msg.append(" -l <file> ''" + lSep);
57 msg.append(" -logger <classname> the class which is to perform logging" + lSep);
58 msg.append(" -listener <classname> add an instance of class as a project listener" + lSep);
59 msg.append(" -noinput do not allow interactive input" + lSep);
60 msg.append(" -buildfile <file> use given buildfile" + lSep);
61 msg.append(" -file <file> ''" + lSep);
62 msg.append(" -f <file> ''" + lSep);
63 msg.append(" -D<property>=<value> use value for given property" + lSep);
64 msg.append(" -keep-going, -k execute all targets that do not depend" + lSep);
65 msg.append(" on failed target(s)" + lSep);
66 msg.append(" -propertyfile <name> load all properties from file with -D" + lSep);
67 msg.append(" properties taking precedence" + lSep);
68 msg.append(" -inputhandler <class> the class which will handle input requests" + lSep);
69 msg.append(" -find <file> (s)earch for buildfile towards the root of" + lSep);
70 msg.append(" -s <file> the filesystem and use it" + lSep);
71 msg.append(" -nice number A niceness value for the main thread:" + lSep +
72 " 1 (lowest) to 10 (highest); 5 is the default" + lSep);
73 System.out.println(msg.toString());
74 }
75
76 /**
77 * Prints the Ant version information to <code>System.out</code>.
78 *
79 * @exception BuildException if the version information is unavailable
80 */
81 private static void printVersion() throws BuildException {
82 System.out.println(getAntVersion());
83 }
84
85 /**
86 * Cache of the Ant version information when it has been loaded.
87 */
88 private static String antVersion = null;
89
90 /**
91 * Returns the Ant version information, if available. Once the information
92 * has been loaded once, it's cached and returned from the cache on future
93 * calls.
94 *
95 * @return the Ant version information as a String
96 * (always non-<code>null</code>)
97 *
98 * @exception BuildException if the version information is unavailable
99 */
00 public static synchronized String getAntVersion() throws BuildException {
01 if (antVersion == null) {
02 try {
03 Properties props = new Properties();
04 InputStream in =
05 Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
06 props.load(in);
07 in.close();
08
09 StringBuffer msg = new StringBuffer();
10 msg.append("Apache Ant version ");
11 msg.append(props.getProperty("VERSION"));
12 msg.append(" compiled on ");
13 msg.append(props.getProperty("DATE"));
14 antVersion = msg.toString();
15 } catch (IOException ioe) {
16 throw new BuildException("Could not load the version information:"
17 + ioe.getMessage());
18 } catch (NullPointerException npe) {
19 throw new BuildException("Could not load the version information.");
20 }
21 }
22 return antVersion;
23 }
24
25 /**
26 * Prints the description of a project (if there is one) to
27 * <code>System.out</code>.
28 *
29 * @param project The project to display a description of.
30 * Must not be <code>null</code>.
31 */
32 private static void printDescription(Project project) {
33 if (project.getDescription() != null) {
34 project.log(project.getDescription());
35 }
36 }
37
38 /**
39 * Prints a list of all targets in the specified project to
40 * <code>System.out</code>, optionally including subtargets.
41 *
42 * @param project The project to display a description of.
43 * Must not be <code>null</code>.
44 * @param printSubTargets Whether or not subtarget names should also be
45 * printed.
46 */
47 private static void printTargets(Project project, boolean printSubTargets) {
48 // find the target with the longest name
49 int maxLength = 0;
50 Enumeration ptargets = project.getTargets().elements();
51 String targetName;
52 String targetDescription;
53 Target currentTarget;
54 // split the targets in top-level and sub-targets depending
55 // on the presence of a description
56 Vector topNames = new Vector();
57 Vector topDescriptions = new Vector();
58 Vector subNames = new Vector();
59
60 while (ptargets.hasMoreElements()) {
61 currentTarget = (Target) ptargets.nextElement();
62 targetName = currentTarget.getName();
63 if (targetName.equals("")) {
64 continue;
65 }
66 targetDescription = currentTarget.getDescription();
67 // maintain a sorted list of targets
68 if (targetDescription == null) {
69 int pos = findTargetPosition(subNames, targetName);
70 subNames.insertElementAt(targetName, pos);
71 } else {
72 int pos = findTargetPosition(topNames, targetName);
73 topNames.insertElementAt(targetName, pos);
74 topDescriptions.insertElementAt(targetDescription, pos);
75 if (targetName.length() > maxLength) {
76 maxLength = targetName.length();
77 }
78 }
79 }
80
81 printTargets(project, topNames, topDescriptions, "Main targets:",
82 maxLength);
83 //if there were no main targets, we list all subtargets
84 //as it means nothing has a description
85 if (topNames.size() == 0) {
86 printSubTargets = true;
87 }
88 if (printSubTargets) {
89 printTargets(project, subNames, null, "Other targets:", 0);
90 }
91
92 String defaultTarget = project.getDefaultTarget();
93 if (defaultTarget != null && !"".equals(defaultTarget)) {
94 // shouldn't need to check but...
95 project.log("Default target: " + defaultTarget);
96 }
97 }
98
99 /**
00 * Searches for the correct place to insert a name into a list so as
01 * to keep the list sorted alphabetically.
02 *
03 * @param names The current list of names. Must not be <code>null</code>.
04 * @param name The name to find a place for.
05 * Must not be <code>null</code>.
06 *
07 * @return the correct place in the list for the given name
08 */
09 private static int findTargetPosition(Vector names, String name) {
10 int res = names.size();
11 for (int i = 0; i < names.size() && res == names.size(); i++) {
12 if (name.compareTo((String) names.elementAt(i)) < 0) {
13 res = i;
14 }
15 }
16 return res;
17 }
18
19 /**
20 * Writes a formatted list of target names to <code>System.out</code>
21 * with an optional description.
22 *
23 *
24 * @param project the project instance.
25 * @param names The names to be printed.
26 * Must not be <code>null</code>.
27 * @param descriptions The associated target descriptions.
28 * May be <code>null</code>, in which case
29 * no descriptions are displayed.
30 * If non-<code>null</code>, this should have
31 * as many elements as <code>names</code>.
32 * @param heading The heading to display.
33 * Should not be <code>null</code>.
34 * @param maxlen The maximum length of the names of the targets.
35 * If descriptions are given, they are padded to this
36 * position so they line up (so long as the names really
37 * <i>are</i> shorter than this).
38 */
39 private static void printTargets(Project project, Vector names,
40 Vector descriptions, String heading,
41 int maxlen) {
42 // now, start printing the targets and their descriptions
43 String lSep = System.getProperty("line.separator");
44 // got a bit annoyed that I couldn't find a pad function
45 String spaces = " ";
46 while (spaces.length() <= maxlen) {
47 spaces += spaces;
48 }
49 StringBuffer msg = new StringBuffer();
50 msg.append(heading);
51 msg.append(lSep);
52 msg.append(lSep);
53 for (int i = 0; i < names.size(); i++) {
54 msg.append(" ");
55 msg.append(names.elementAt(i));
56 if (descriptions != null) {
57 msg.append(spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2));
58 msg.append(descriptions.elementAt(i));
59 }
60 msg.append(lSep);
61 }
62 project.log(msg.toString());
63 }
64}
65