aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java1317
1 files changed, 1317 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java
new file mode 100644
index 00000000..a9c23a53
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/Main.java
@@ -0,0 +1,1317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.launch.AntMain;
+import org.apache.tools.ant.listener.SilentLogger;
+import org.apache.tools.ant.property.GetProperty;
+import org.apache.tools.ant.property.ResolvePropertyMap;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ProxySetup;
+
+
+/**
+ * Command line entry point into Ant. This class is entered via the
+ * canonical `public static void main` entry point and reads the
+ * command line arguments. It then assembles and executes an Ant
+ * project.
+ * <p>
+ * If you integrating Ant into some other tool, this is not the class
+ * to use as an entry point. Please see the source code of this
+ * class to see how it manipulates the Ant project classes.
+ *
+ */
+public class Main implements AntMain {
+
+ /**
+ * A Set of args that are handled by the launcher and should
+ * not be seen by Main.
+ */
+ private static final Set<String> LAUNCH_COMMANDS = Collections
+ .unmodifiableSet(new HashSet<String>(Arrays.asList("-lib", "-cp", "-noclasspath",
+ "--noclasspath", "-nouserlib", "-main")));
+
+ /** The default build file name. {@value} */
+ public static final String DEFAULT_BUILD_FILENAME = "build.xml";
+
+ /** Our current message output status. Follows Project.MSG_XXX. */
+ private int msgOutputLevel = Project.MSG_INFO;
+
+ /** File that we are using for configuration. */
+ private File buildFile; /* null */
+
+ /** Stream to use for logging. */
+ private static PrintStream out = System.out;
+
+ /** Stream that we are using for logging error messages. */
+ private static PrintStream err = System.err;
+
+ /** The build targets. */
+ private final Vector<String> targets = new Vector<String>();
+
+ /** Set of properties that can be used by tasks. */
+ private final Properties definedProps = new Properties();
+
+ /** Names of classes to add as listeners to project. */
+ private final Vector<String> listeners = new Vector<String>(1);
+
+ /** File names of property files to load on startup. */
+ private final Vector<String> propertyFiles = new Vector<String>(1);
+
+ /** Indicates whether this build is to support interactive input */
+ private boolean allowInput = true;
+
+ /** keep going mode */
+ private boolean keepGoingMode = false;
+
+ /**
+ * The Ant logger class. There may be only one logger. It will have
+ * the right to use the 'out' PrintStream. The class must implements the
+ * BuildLogger interface.
+ */
+ private String loggerClassname = null;
+
+ /**
+ * The Ant InputHandler class. There may be only one input
+ * handler.
+ */
+ private String inputHandlerClassname = null;
+
+ /**
+ * Whether or not output to the log is to be unadorned.
+ */
+ private boolean emacsMode = false;
+
+ /**
+ * Whether or not log output should be reduced to the minimum
+ */
+ private boolean silent = false;
+
+ /**
+ * Whether or not this instance has successfully been
+ * constructed and is ready to run.
+ */
+ private boolean readyToRun = false;
+
+ /**
+ * Whether or not we should only parse and display the project help
+ * information.
+ */
+ private boolean projectHelp = false;
+
+ /**
+ * Whether or not a logfile is being used. This is used to
+ * check if the output streams must be closed.
+ */
+ private static boolean isLogFileUsed = false;
+
+ /**
+ * optional thread priority
+ */
+ private Integer threadPriority = null;
+
+ /**
+ * proxy flag: default is false
+ */
+ private boolean proxy = false;
+
+ private final Map<Class<?>, List<String>> extraArguments = new HashMap<Class<?>, List<String>>();
+
+ private static final GetProperty NOPROPERTIES = new GetProperty() {
+ public Object getProperty(final String aName) {
+ // No existing property takes precedence
+ return null;
+ }
+ };
+
+
+
+
+ /**
+ * Prints the message of the Throwable if it (the message) is not
+ * <code>null</code>.
+ *
+ * @param t Throwable to print the message of.
+ * Must not be <code>null</code>.
+ */
+ private static void printMessage(final Throwable t) {
+ final String message = t.getMessage();
+ if (message != null) {
+ System.err.println(message);
+ }
+ }
+
+ /**
+ * Creates a new instance of this class using the
+ * arguments specified, gives it any extra user properties which have been
+ * specified, and then runs the build using the classloader provided.
+ *
+ * @param args Command line arguments. Must not be <code>null</code>.
+ * @param additionalUserProperties Any extra properties to use in this
+ * build. May be <code>null</code>, which is the equivalent to
+ * passing in an empty set of properties.
+ * @param coreLoader Classloader used for core classes. May be
+ * <code>null</code> in which case the system classloader is used.
+ */
+ public static void start(final String[] args, final Properties additionalUserProperties,
+ final ClassLoader coreLoader) {
+ final Main m = new Main();
+ m.startAnt(args, additionalUserProperties, coreLoader);
+ }
+
+ /**
+ * Start Ant
+ * @param args command line args
+ * @param additionalUserProperties properties to set beyond those that
+ * may be specified on the args list
+ * @param coreLoader - not used
+ *
+ * @since Ant 1.6
+ */
+ public void startAnt(final String[] args, final Properties additionalUserProperties,
+ final ClassLoader coreLoader) {
+
+ try {
+ processArgs(args);
+ } catch (final Throwable exc) {
+ handleLogfile();
+ printMessage(exc);
+ exit(1);
+ return;
+ }
+
+ if (additionalUserProperties != null) {
+ for (final Enumeration<?> e = additionalUserProperties.keys();
+ e.hasMoreElements();) {
+ final String key = (String) e.nextElement();
+ final String property = additionalUserProperties.getProperty(key);
+ definedProps.put(key, property);
+ }
+ }
+
+ // expect the worst
+ int exitCode = 1;
+ try {
+ try {
+ runBuild(coreLoader);
+ exitCode = 0;
+ } catch (final ExitStatusException ese) {
+ exitCode = ese.getStatus();
+ if (exitCode != 0) {
+ throw ese;
+ }
+ }
+ } catch (final BuildException be) {
+ if (err != System.err) {
+ printMessage(be);
+ }
+ } catch (final Throwable exc) {
+ exc.printStackTrace();
+ printMessage(exc);
+ } finally {
+ handleLogfile();
+ }
+ exit(exitCode);
+ }
+
+ /**
+ * This operation is expected to call {@link System#exit(int)}, which
+ * is what the base version does.
+ * However, it is possible to do something else.
+ * @param exitCode code to exit with
+ */
+ protected void exit(final int exitCode) {
+ System.exit(exitCode);
+ }
+
+ /**
+ * Close logfiles, if we have been writing to them.
+ *
+ * @since Ant 1.6
+ */
+ private static void handleLogfile() {
+ if (isLogFileUsed) {
+ FileUtils.close(out);
+ FileUtils.close(err);
+ }
+ }
+
+ /**
+ * Command line entry point. This method kicks off the building
+ * of a project object and executes a build using either a given
+ * target or the default target.
+ *
+ * @param args Command line arguments. Must not be <code>null</code>.
+ */
+ public static void main(final String[] args) {
+ start(args, null, null);
+ }
+
+ /**
+ * Constructor used when creating Main for later arg processing
+ * and startup
+ */
+ public Main() {
+ }
+
+ /**
+ * Sole constructor, which parses and deals with command line
+ * arguments.
+ *
+ * @param args Command line arguments. Must not be <code>null</code>.
+ *
+ * @exception BuildException if the specified build file doesn't exist
+ * or is a directory.
+ *
+ * @deprecated since 1.6.x
+ */
+ @Deprecated
+ protected Main(final String[] args) throws BuildException {
+ processArgs(args);
+ }
+
+ /**
+ * Process command line arguments.
+ * When ant is started from Launcher, launcher-only arguments do not get
+ * passed through to this routine.
+ *
+ * @param args the command line arguments.
+ *
+ * @since Ant 1.6
+ */
+ private void processArgs(final String[] args) {
+ String searchForThis = null;
+ boolean searchForFile = false;
+ PrintStream logTo = null;
+
+ // cycle through given args
+
+ boolean justPrintUsage = false;
+ boolean justPrintVersion = false;
+ boolean justPrintDiagnostics = false;
+
+ final ArgumentProcessorRegistry processorRegistry = ArgumentProcessorRegistry.getInstance();
+
+ for (int i = 0; i < args.length; i++) {
+ final String arg = args[i];
+
+ if (arg.equals("-help") || arg.equals("-h")) {
+ justPrintUsage = true;
+ } else if (arg.equals("-version")) {
+ justPrintVersion = true;
+ } else if (arg.equals("-diagnostics")) {
+ justPrintDiagnostics = true;
+ } else if (arg.equals("-quiet") || arg.equals("-q")) {
+ msgOutputLevel = Project.MSG_WARN;
+ } else if (arg.equals("-verbose") || arg.equals("-v")) {
+ msgOutputLevel = Project.MSG_VERBOSE;
+ } else if (arg.equals("-debug") || arg.equals("-d")) {
+ msgOutputLevel = Project.MSG_DEBUG;
+ } else if (arg.equals("-silent") || arg.equals("-S")) {
+ silent = true;
+ } else if (arg.equals("-noinput")) {
+ allowInput = false;
+ } else if (arg.equals("-logfile") || arg.equals("-l")) {
+ try {
+ final File logFile = new File(args[i + 1]);
+ i++;
+ logTo = new PrintStream(new FileOutputStream(logFile));
+ isLogFileUsed = true;
+ } catch (final IOException ioe) {
+ final String msg = "Cannot write on the specified log file. "
+ + "Make sure the path exists and you have write "
+ + "permissions.";
+ throw new BuildException(msg);
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ final String msg = "You must specify a log file when "
+ + "using the -log argument";
+ throw new BuildException(msg);
+ }
+ } else if (arg.equals("-buildfile") || arg.equals("-file")
+ || arg.equals("-f")) {
+ i = handleArgBuildFile(args, i);
+ } else if (arg.equals("-listener")) {
+ i = handleArgListener(args, i);
+ } else if (arg.startsWith("-D")) {
+ i = handleArgDefine(args, i);
+ } else if (arg.equals("-logger")) {
+ i = handleArgLogger(args, i);
+ } else if (arg.equals("-inputhandler")) {
+ i = handleArgInputHandler(args, i);
+ } else if (arg.equals("-emacs") || arg.equals("-e")) {
+ emacsMode = true;
+ } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
+ // set the flag to display the targets and quit
+ projectHelp = true;
+ } else if (arg.equals("-find") || arg.equals("-s")) {
+ searchForFile = true;
+ // eat up next arg if present, default to build.xml
+ if (i < args.length - 1) {
+ searchForThis = args[++i];
+ }
+ } else if (arg.startsWith("-propertyfile")) {
+ i = handleArgPropertyFile(args, i);
+ } else if (arg.equals("-k") || arg.equals("-keep-going")) {
+ keepGoingMode = true;
+ } else if (arg.equals("-nice")) {
+ i = handleArgNice(args, i);
+ } else if (LAUNCH_COMMANDS.contains(arg)) {
+ //catch script/ant mismatch with a meaningful message
+ //we could ignore it, but there are likely to be other
+ //version problems, so we stamp down on the configuration now
+ final String msg = "Ant's Main method is being handed "
+ + "an option " + arg + " that is only for the launcher class."
+ + "\nThis can be caused by a version mismatch between "
+ + "the ant script/.bat file and Ant itself.";
+ throw new BuildException(msg);
+ } else if (arg.equals("-autoproxy")) {
+ proxy = true;
+ } else if (arg.startsWith("-")) {
+ boolean processed = false;
+ for (final ArgumentProcessor processor : processorRegistry.getProcessors()) {
+ final int newI = processor.readArguments(args, i);
+ if (newI != -1) {
+ List<String> extraArgs = extraArguments.get(processor.getClass());
+ if (extraArgs == null) {
+ extraArgs = new ArrayList<String>();
+ extraArguments.put(processor.getClass(), extraArgs);
+ }
+ for (; i < newI && i < args.length; i++) {
+ extraArgs.add(args[i]);
+ }
+ processed = true;
+ break;
+ }
+ }
+ if (!processed) {
+ // we don't have any more args to recognize!
+ final String msg = "Unknown argument: " + arg;
+ System.err.println(msg);
+ printUsage();
+ throw new BuildException("");
+ }
+ } else {
+ // if it's no other arg, it may be the target
+ targets.addElement(arg);
+ }
+ }
+
+ if (msgOutputLevel >= Project.MSG_VERBOSE || justPrintVersion) {
+ printVersion(msgOutputLevel);
+ }
+
+ if (justPrintUsage || justPrintVersion || justPrintDiagnostics) {
+ if (justPrintUsage) {
+ printUsage();
+ }
+ if (justPrintDiagnostics) {
+ Diagnostics.doReport(System.out, msgOutputLevel);
+ }
+ return;
+ }
+
+ // if buildFile was not specified on the command line,
+ if (buildFile == null) {
+ // but -find then search for it
+ if (searchForFile) {
+ if (searchForThis != null) {
+ buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis);
+ if (buildFile == null) {
+ throw new BuildException("Could not locate a build file!");
+ }
+ } else {
+ // no search file specified: so search an existing default file
+ final Iterator<ProjectHelper> it = ProjectHelperRepository.getInstance().getHelpers();
+ do {
+ final ProjectHelper helper = it.next();
+ searchForThis = helper.getDefaultBuildFile();
+ if (msgOutputLevel >= Project.MSG_VERBOSE) {
+ System.out.println("Searching the default build file: " + searchForThis);
+ }
+ buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis);
+ } while (buildFile == null && it.hasNext());
+ if (buildFile == null) {
+ throw new BuildException("Could not locate a build file!");
+ }
+ }
+ } else {
+ // no build file specified: so search an existing default file
+ final Iterator<ProjectHelper> it = ProjectHelperRepository.getInstance().getHelpers();
+ do {
+ final ProjectHelper helper = it.next();
+ buildFile = new File(helper.getDefaultBuildFile());
+ if (msgOutputLevel >= Project.MSG_VERBOSE) {
+ System.out.println("Trying the default build file: " + buildFile);
+ }
+ } while (!buildFile.exists() && it.hasNext());
+ }
+ }
+
+ // make sure buildfile exists
+ if (!buildFile.exists()) {
+ System.out.println("Buildfile: " + buildFile + " does not exist!");
+ throw new BuildException("Build failed");
+ }
+
+ if (buildFile.isDirectory()) {
+ final File whatYouMeant = new File(buildFile, "build.xml");
+ if (whatYouMeant.isFile()) {
+ buildFile = whatYouMeant;
+ } else {
+ System.out.println("What? Buildfile: " + buildFile + " is a dir!");
+ throw new BuildException("Build failed");
+ }
+ }
+
+ // Normalize buildFile for re-import detection
+ buildFile =
+ FileUtils.getFileUtils().normalize(buildFile.getAbsolutePath());
+
+ // Load the property files specified by -propertyfile
+ loadPropertyFiles();
+
+ if (msgOutputLevel >= Project.MSG_INFO) {
+ System.out.println("Buildfile: " + buildFile);
+ }
+
+ if (logTo != null) {
+ out = logTo;
+ err = logTo;
+ System.setOut(out);
+ System.setErr(err);
+ }
+ readyToRun = true;
+ }
+
+ // --------------------------------------------------------
+ // Methods for handling the command line arguments
+ // --------------------------------------------------------
+
+ /** Handle the -buildfile, -file, -f argument */
+ private int handleArgBuildFile(final String[] args, int pos) {
+ try {
+ buildFile = new File(
+ args[++pos].replace('/', File.separatorChar));
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ throw new BuildException(
+ "You must specify a buildfile when using the -buildfile argument");
+ }
+ return pos;
+ }
+
+ /** Handle -listener argument */
+ private int handleArgListener(final String[] args, int pos) {
+ try {
+ listeners.addElement(args[pos + 1]);
+ pos++;
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ final String msg = "You must specify a classname when "
+ + "using the -listener argument";
+ throw new BuildException(msg);
+ }
+ return pos;
+ }
+
+ /** Handler -D argument */
+ private int handleArgDefine(final String[] args, int argPos) {
+ /* Interestingly enough, we get to here when a user
+ * uses -Dname=value. However, in some cases, the OS
+ * goes ahead and parses this out to args
+ * {"-Dname", "value"}
+ * so instead of parsing on "=", we just make the "-D"
+ * characters go away and skip one argument forward.
+ *
+ * I don't know how to predict when the JDK is going
+ * to help or not, so we simply look for the equals sign.
+ */
+ final String arg = args[argPos];
+ String name = arg.substring(2, arg.length());
+ String value = null;
+ final int posEq = name.indexOf("=");
+ if (posEq > 0) {
+ value = name.substring(posEq + 1);
+ name = name.substring(0, posEq);
+ } else if (argPos < args.length - 1) {
+ value = args[++argPos];
+ } else {
+ throw new BuildException("Missing value for property "
+ + name);
+ }
+ definedProps.put(name, value);
+ return argPos;
+ }
+
+ /** Handle the -logger argument. */
+ private int handleArgLogger(final String[] args, int pos) {
+ if (loggerClassname != null) {
+ throw new BuildException(
+ "Only one logger class may be specified.");
+ }
+ try {
+ loggerClassname = args[++pos];
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ throw new BuildException(
+ "You must specify a classname when using the -logger argument");
+ }
+ return pos;
+ }
+
+ /** Handle the -inputhandler argument. */
+ private int handleArgInputHandler(final String[] args, int pos) {
+ if (inputHandlerClassname != null) {
+ throw new BuildException("Only one input handler class may "
+ + "be specified.");
+ }
+ try {
+ inputHandlerClassname = args[++pos];
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ throw new BuildException("You must specify a classname when"
+ + " using the -inputhandler"
+ + " argument");
+ }
+ return pos;
+ }
+
+ /** Handle the -propertyfile argument. */
+ private int handleArgPropertyFile(final String[] args, int pos) {
+ try {
+ propertyFiles.addElement(args[++pos]);
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ final String msg = "You must specify a property filename when "
+ + "using the -propertyfile argument";
+ throw new BuildException(msg);
+ }
+ return pos;
+ }
+
+ /** Handle the -nice argument. */
+ private int handleArgNice(final String[] args, int pos) {
+ try {
+ threadPriority = Integer.decode(args[++pos]);
+ } catch (final ArrayIndexOutOfBoundsException aioobe) {
+ throw new BuildException(
+ "You must supply a niceness value (1-10)"
+ + " after the -nice option");
+ } catch (final NumberFormatException e) {
+ throw new BuildException("Unrecognized niceness value: "
+ + args[pos]);
+ }
+
+ if (threadPriority.intValue() < Thread.MIN_PRIORITY
+ || threadPriority.intValue() > Thread.MAX_PRIORITY) {
+ throw new BuildException(
+ "Niceness value is out of the range 1-10");
+ }
+ return pos;
+ }
+
+ // --------------------------------------------------------
+ // other methods
+ // --------------------------------------------------------
+
+ /** Load the property files specified by -propertyfile */
+ private void loadPropertyFiles() {
+ for (final String filename : propertyFiles) {
+ final Properties props = new Properties();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(filename);
+ props.load(fis);
+ } catch (final IOException e) {
+ System.out.println("Could not load property file "
+ + filename + ": " + e.getMessage());
+ } finally {
+ FileUtils.close(fis);
+ }
+
+ // ensure that -D properties take precedence
+ final Enumeration<?> propertyNames = props.propertyNames();
+ while (propertyNames.hasMoreElements()) {
+ final String name = (String) propertyNames.nextElement();
+ if (definedProps.getProperty(name) == null) {
+ definedProps.put(name, props.getProperty(name));
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper to get the parent file for a given file.
+ * <p>
+ * Added to simulate File.getParentFile() from JDK 1.2.
+ * @deprecated since 1.6.x
+ *
+ * @param file File to find parent of. Must not be <code>null</code>.
+ * @return Parent file or null if none
+ */
+ @Deprecated
+ private File getParentFile(final File file) {
+ final File parent = file.getParentFile();
+
+ if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
+ System.out.println("Searching in " + parent.getAbsolutePath());
+ }
+
+ return parent;
+ }
+
+ /**
+ * Search parent directories for the build file.
+ * <p>
+ * Takes the given target as a suffix to append to each
+ * parent directory in search of a build file. Once the
+ * root of the file-system has been reached <code>null</code>
+ * is returned.
+ *
+ * @param start Leaf directory of search.
+ * Must not be <code>null</code>.
+ * @param suffix Suffix filename to look for in parents.
+ * Must not be <code>null</code>.
+ *
+ * @return A handle to the build file if one is found, <code>null</code> if not
+ */
+ private File findBuildFile(final String start, final String suffix) {
+ if (msgOutputLevel >= Project.MSG_INFO) {
+ System.out.println("Searching for " + suffix + " ...");
+ }
+
+ File parent = new File(new File(start).getAbsolutePath());
+ File file = new File(parent, suffix);
+
+ // check if the target file exists in the current directory
+ while (!file.exists()) {
+ // change to parent directory
+ parent = getParentFile(parent);
+
+ // if parent is null, then we are at the root of the fs,
+ // complain that we can't find the build file.
+ if (parent == null) {
+ return null;
+ }
+
+ // refresh our file handle
+ file = new File(parent, suffix);
+ }
+
+ return file;
+ }
+
+ /**
+ * Executes the build. If the constructor for this instance failed
+ * (e.g. returned after issuing a warning), this method returns
+ * immediately.
+ *
+ * @param coreLoader The classloader to use to find core classes.
+ * May be <code>null</code>, in which case the
+ * system classloader is used.
+ *
+ * @exception BuildException if the build fails
+ */
+ private void runBuild(final ClassLoader coreLoader) throws BuildException {
+
+ if (!readyToRun) {
+ return;
+ }
+
+ final ArgumentProcessorRegistry processorRegistry = ArgumentProcessorRegistry.getInstance();
+
+ for (final ArgumentProcessor processor : processorRegistry.getProcessors()) {
+ final List<String> extraArgs = extraArguments.get(processor.getClass());
+ if (extraArgs != null) {
+ if (processor.handleArg(extraArgs)) {
+ return;
+ }
+ }
+ }
+
+ final Project project = new Project();
+ project.setCoreLoader(coreLoader);
+
+ Throwable error = null;
+
+ try {
+ addBuildListeners(project);
+ addInputHandler(project);
+
+ final PrintStream savedErr = System.err;
+ final PrintStream savedOut = System.out;
+ final InputStream savedIn = System.in;
+
+ // use a system manager that prevents from System.exit()
+ SecurityManager oldsm = null;
+ oldsm = System.getSecurityManager();
+
+ //SecurityManager can not be installed here for backwards
+ //compatibility reasons (PD). Needs to be loaded prior to
+ //ant class if we are going to implement it.
+ //System.setSecurityManager(new NoExitSecurityManager());
+ try {
+ if (allowInput) {
+ project.setDefaultInputStream(System.in);
+ }
+ System.setIn(new DemuxInputStream(project));
+ System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
+ System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
+
+
+ if (!projectHelp) {
+ project.fireBuildStarted();
+ }
+
+ // set the thread priorities
+ if (threadPriority != null) {
+ try {
+ project.log("Setting Ant's thread priority to "
+ + threadPriority, Project.MSG_VERBOSE);
+ Thread.currentThread().setPriority(threadPriority.intValue());
+ } catch (final SecurityException swallowed) {
+ //we cannot set the priority here.
+ project.log("A security manager refused to set the -nice value");
+ }
+ }
+
+ setProperties(project);
+
+ project.setKeepGoingMode(keepGoingMode);
+ if (proxy) {
+ //proxy setup if enabled
+ final ProxySetup proxySetup = new ProxySetup(project);
+ proxySetup.enableProxies();
+ }
+
+ for (final ArgumentProcessor processor : processorRegistry.getProcessors()) {
+ final List<String> extraArgs = extraArguments.get(processor.getClass());
+ if (extraArgs != null) {
+ processor.prepareConfigure(project, extraArgs);
+ }
+ }
+
+ ProjectHelper.configureProject(project, buildFile);
+
+ for (final ArgumentProcessor processor : processorRegistry.getProcessors()) {
+ final List<String> extraArgs = extraArguments.get(processor.getClass());
+ if (extraArgs != null) {
+ if (processor.handleArg(project, extraArgs)) {
+ return;
+ }
+ }
+ }
+
+ if (projectHelp) {
+ printDescription(project);
+ printTargets(project, msgOutputLevel > Project.MSG_INFO,
+ msgOutputLevel > Project.MSG_VERBOSE);
+ return;
+ }
+
+ // make sure that we have a target to execute
+ if (targets.size() == 0) {
+ if (project.getDefaultTarget() != null) {
+ targets.addElement(project.getDefaultTarget());
+ }
+ }
+
+ project.executeTargets(targets);
+ } finally {
+ // put back the original security manager
+ //The following will never eval to true. (PD)
+ if (oldsm != null) {
+ System.setSecurityManager(oldsm);
+ }
+
+ System.setOut(savedOut);
+ System.setErr(savedErr);
+ System.setIn(savedIn);
+ }
+ } catch (final RuntimeException exc) {
+ error = exc;
+ throw exc;
+ } catch (final Error e) {
+ error = e;
+ throw e;
+ } finally {
+ if (!projectHelp) {
+ try {
+ project.fireBuildFinished(error);
+ } catch (final Throwable t) {
+ // yes, I know it is bad style to catch Throwable,
+ // but if we don't, we lose valuable information
+ System.err.println("Caught an exception while logging the"
+ + " end of the build. Exception was:");
+ t.printStackTrace();
+ if (error != null) {
+ System.err.println("There has been an error prior to"
+ + " that:");
+ error.printStackTrace();
+ }
+ throw new BuildException(t);
+ }
+ } else if (error != null) {
+ project.log(error.toString(), Project.MSG_ERR);
+ }
+ }
+ }
+
+ private void setProperties(final Project project) {
+
+ project.init();
+
+ // resolve properties
+ final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project);
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ final Map raw = new HashMap(definedProps);
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> props = raw;
+
+ final ResolvePropertyMap resolver = new ResolvePropertyMap(project,
+ NOPROPERTIES, propertyHelper.getExpanders());
+ resolver.resolveAllProperties(props, null, false);
+
+ // set user-define properties
+ for (final Entry<String, Object> ent : props.entrySet()) {
+ final String arg = ent.getKey();
+ final Object value = ent.getValue();
+ project.setUserProperty(arg, String.valueOf(value));
+ }
+
+ project.setUserProperty(MagicNames.ANT_FILE,
+ buildFile.getAbsolutePath());
+ project.setUserProperty(MagicNames.ANT_FILE_TYPE,
+ MagicNames.ANT_FILE_TYPE_FILE);
+ }
+
+ /**
+ * Adds the listeners specified in the command line arguments,
+ * along with the default listener, to the specified project.
+ *
+ * @param project The project to add listeners to.
+ * Must not be <code>null</code>.
+ */
+ protected void addBuildListeners(final Project project) {
+
+ // Add the default listener
+ project.addBuildListener(createLogger());
+
+ final int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ final String className = listeners.elementAt(i);
+ final BuildListener listener =
+ (BuildListener) ClasspathUtils.newInstance(className,
+ Main.class.getClassLoader(), BuildListener.class);
+ project.setProjectReference(listener);
+
+ project.addBuildListener(listener);
+ }
+ }
+
+ /**
+ * Creates the InputHandler and adds it to the project.
+ *
+ * @param project the project instance.
+ *
+ * @exception BuildException if a specified InputHandler
+ * implementation could not be loaded.
+ */
+ private void addInputHandler(final Project project) throws BuildException {
+ InputHandler handler = null;
+ if (inputHandlerClassname == null) {
+ handler = new DefaultInputHandler();
+ } else {
+ handler = (InputHandler) ClasspathUtils.newInstance(
+ inputHandlerClassname, Main.class.getClassLoader(),
+ InputHandler.class);
+ project.setProjectReference(handler);
+ }
+ project.setInputHandler(handler);
+ }
+
+ // TODO: (Jon Skeet) Any reason for writing a message and then using a bare
+ // RuntimeException rather than just using a BuildException here? Is it
+ // in case the message could end up being written to no loggers (as the
+ // loggers could have failed to be created due to this failure)?
+ /**
+ * Creates the default build logger for sending build events to the ant
+ * log.
+ *
+ * @return the logger instance for this build.
+ */
+ private BuildLogger createLogger() {
+ BuildLogger logger = null;
+ if (silent) {
+ logger = new SilentLogger();
+ msgOutputLevel = Project.MSG_WARN;
+ emacsMode = true;
+ } else if (loggerClassname != null) {
+ try {
+ logger = (BuildLogger) ClasspathUtils.newInstance(
+ loggerClassname, Main.class.getClassLoader(),
+ BuildLogger.class);
+ } catch (final BuildException e) {
+ System.err.println("The specified logger class "
+ + loggerClassname
+ + " could not be used because " + e.getMessage());
+ throw new RuntimeException();
+ }
+ } else {
+ logger = new DefaultLogger();
+ }
+
+ logger.setMessageOutputLevel(msgOutputLevel);
+ logger.setOutputPrintStream(out);
+ logger.setErrorPrintStream(err);
+ logger.setEmacsMode(emacsMode);
+
+ return logger;
+ }
+
+ /**
+ * Prints the usage information for this class to <code>System.out</code>.
+ */
+ private static void printUsage() {
+ System.out.println("ant [options] [target [target2 [target3] ...]]");
+ System.out.println("Options: ");
+ System.out.println(" -help, -h print this message and exit");
+ System.out.println(" -projecthelp, -p print project help information and exit");
+ System.out.println(" -version print the version information and exit");
+ System.out.println(" -diagnostics print information that might be helpful to");
+ System.out.println(" diagnose or report problems and exit");
+ System.out.println(" -quiet, -q be extra quiet");
+ System.out.println(" -silent, -S print nothing but task outputs and build failures");
+ System.out.println(" -verbose, -v be extra verbose");
+ System.out.println(" -debug, -d print debugging information");
+ System.out.println(" -emacs, -e produce logging information without adornments");
+ System.out.println(" -lib <path> specifies a path to search for jars and classes");
+ System.out.println(" -logfile <file> use given file for log");
+ System.out.println(" -l <file> ''");
+ System.out.println(" -logger <classname> the class which is to perform logging");
+ System.out.println(" -listener <classname> add an instance of class as a project listener");
+ System.out.println(" -noinput do not allow interactive input");
+ System.out.println(" -buildfile <file> use given buildfile");
+ System.out.println(" -file <file> ''");
+ System.out.println(" -f <file> ''");
+ System.out.println(" -D<property>=<value> use value for given property");
+ System.out.println(" -keep-going, -k execute all targets that do not depend");
+ System.out.println(" on failed target(s)");
+ System.out.println(" -propertyfile <name> load all properties from file with -D");
+ System.out.println(" properties taking precedence");
+ System.out.println(" -inputhandler <class> the class which will handle input requests");
+ System.out.println(" -find <file> (s)earch for buildfile towards the root of");
+ System.out.println(" -s <file> the filesystem and use it");
+ System.out.println(" -nice number A niceness value for the main thread:"
+ + " 1 (lowest) to 10 (highest); 5 is the default");
+ System.out.println(" -nouserlib Run ant without using the jar files from"
+ + " ${user.home}/.ant/lib");
+ System.out.println(" -noclasspath Run ant without using CLASSPATH");
+ System.out.println(" -autoproxy Java1.5+: use the OS proxy settings");
+ System.out.println(" -main <class> override Ant's normal entry point");
+ for (final ArgumentProcessor processor : ArgumentProcessorRegistry.getInstance().getProcessors()) {
+ processor.printUsage(System.out);
+ }
+ }
+
+ /**
+ * Prints the Ant version information to <code>System.out</code>.
+ *
+ * @exception BuildException if the version information is unavailable
+ */
+ private static void printVersion(final int logLevel) throws BuildException {
+ System.out.println(getAntVersion());
+ }
+
+ /**
+ * Cache of the Ant version information when it has been loaded.
+ */
+ private static String antVersion = null;
+
+ /**
+ * Cache of the short Ant version information when it has been loaded.
+ */
+ private static String shortAntVersion = null;
+
+ /**
+ * Returns the Ant version information, if available. Once the information
+ * has been loaded once, it's cached and returned from the cache on future
+ * calls.
+ *
+ * @return the Ant version information as a String
+ * (always non-<code>null</code>)
+ *
+ * @exception BuildException if the version information is unavailable
+ */
+ public static synchronized String getAntVersion() throws BuildException {
+ if (antVersion == null) {
+ try {
+ final Properties props = new Properties();
+ final InputStream in =
+ Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
+ props.load(in);
+ in.close();
+ shortAntVersion = props.getProperty("VERSION");
+
+ final StringBuffer msg = new StringBuffer();
+ msg.append("Apache Ant(TM) version ");
+ msg.append(shortAntVersion);
+ msg.append(" compiled on ");
+ msg.append(props.getProperty("DATE"));
+ antVersion = msg.toString();
+ } catch (final IOException ioe) {
+ throw new BuildException("Could not load the version information:"
+ + ioe.getMessage());
+ } catch (final NullPointerException npe) {
+ throw new BuildException("Could not load the version information.");
+ }
+ }
+ return antVersion;
+ }
+
+ /**
+ * Returns the short Ant version information, if available. Once the information
+ * has been loaded once, it's cached and returned from the cache on future
+ * calls.
+ *
+ * @return the short Ant version information as a String
+ * (always non-<code>null</code>)
+ *
+ * @throws BuildException BuildException if the version information is unavailable
+ * @since Ant 1.9.3
+ */
+ public static String getShortAntVersion() throws BuildException {
+ if (shortAntVersion == null) {
+ getAntVersion();
+ }
+ return shortAntVersion;
+ }
+
+ /**
+ * Prints the description of a project (if there is one) to
+ * <code>System.out</code>.
+ *
+ * @param project The project to display a description of.
+ * Must not be <code>null</code>.
+ */
+ private static void printDescription(final Project project) {
+ if (project.getDescription() != null) {
+ project.log(project.getDescription());
+ }
+ }
+
+ /**
+ * Targets in imported files with a project name
+ * and not overloaded by the main build file will
+ * be in the target map twice. This method
+ * removes the duplicate target.
+ * @param targets the targets to filter.
+ * @return the filtered targets.
+ */
+ private static Map<String, Target> removeDuplicateTargets(final Map<String, Target> targets) {
+ final Map<Location, Target> locationMap = new HashMap<Location, Target>();
+ for (final Entry<String, Target> entry : targets.entrySet()) {
+ final String name = entry.getKey();
+ final Target target = entry.getValue();
+ final Target otherTarget = locationMap.get(target.getLocation());
+ // Place this entry in the location map if
+ // a) location is not in the map
+ // b) location is in map, but its name is longer
+ // (an imported target will have a name. prefix)
+ if (otherTarget == null
+ || otherTarget.getName().length() > name.length()) {
+ locationMap.put(
+ target.getLocation(), target); // Smallest name wins
+ }
+ }
+ final Map<String, Target> ret = new HashMap<String, Target>();
+ for (final Target target : locationMap.values()) {
+ ret.put(target.getName(), target);
+ }
+ return ret;
+ }
+
+ /**
+ * Prints a list of all targets in the specified project to
+ * <code>System.out</code>, optionally including subtargets.
+ *
+ * @param project The project to display a description of.
+ * Must not be <code>null</code>.
+ * @param printSubTargets Whether or not subtarget names should also be
+ * printed.
+ */
+ private static void printTargets(final Project project, boolean printSubTargets,
+ final boolean printDependencies) {
+ // find the target with the longest name
+ int maxLength = 0;
+ final Map<String, Target> ptargets = removeDuplicateTargets(project.getTargets());
+ // split the targets in top-level and sub-targets depending
+ // on the presence of a description
+ final Vector<String> topNames = new Vector<String>();
+ final Vector<String> topDescriptions = new Vector<String>();
+ final Vector<Enumeration<String>> topDependencies = new Vector<Enumeration<String>>();
+ final Vector<String> subNames = new Vector<String>();
+ final Vector<Enumeration<String>> subDependencies = new Vector<Enumeration<String>>();
+
+ for (final Target currentTarget : ptargets.values()) {
+ final String targetName = currentTarget.getName();
+ if (targetName.equals("")) {
+ continue;
+ }
+ final String targetDescription = currentTarget.getDescription();
+ // maintain a sorted list of targets
+ if (targetDescription == null) {
+ final int pos = findTargetPosition(subNames, targetName);
+ subNames.insertElementAt(targetName, pos);
+ if (printDependencies) {
+ subDependencies.insertElementAt(currentTarget.getDependencies(), pos);
+ }
+ } else {
+ final int pos = findTargetPosition(topNames, targetName);
+ topNames.insertElementAt(targetName, pos);
+ topDescriptions.insertElementAt(targetDescription, pos);
+ if (targetName.length() > maxLength) {
+ maxLength = targetName.length();
+ }
+ if (printDependencies) {
+ topDependencies.insertElementAt(currentTarget.getDependencies(), pos);
+ }
+ }
+ }
+
+ printTargets(project, topNames, topDescriptions, topDependencies,
+ "Main targets:", maxLength);
+ //if there were no main targets, we list all subtargets
+ //as it means nothing has a description
+ if (topNames.size() == 0) {
+ printSubTargets = true;
+ }
+ if (printSubTargets) {
+ printTargets(project, subNames, null, subDependencies, "Other targets:", 0);
+ }
+
+ final String defaultTarget = project.getDefaultTarget();
+ if (defaultTarget != null && !"".equals(defaultTarget)) {
+ // shouldn't need to check but...
+ project.log("Default target: " + defaultTarget);
+ }
+ }
+
+ /**
+ * Searches for the correct place to insert a name into a list so as
+ * to keep the list sorted alphabetically.
+ *
+ * @param names The current list of names. Must not be <code>null</code>.
+ * @param name The name to find a place for.
+ * Must not be <code>null</code>.
+ *
+ * @return the correct place in the list for the given name
+ */
+ private static int findTargetPosition(final Vector<String> names, final String name) {
+ final int size = names.size();
+ int res = size;
+ for (int i = 0; i < size && res == size; i++) {
+ if (name.compareTo(names.elementAt(i)) < 0) {
+ res = i;
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Writes a formatted list of target names to <code>System.out</code>
+ * with an optional description.
+ *
+ *
+ * @param project the project instance.
+ * @param names The names to be printed.
+ * Must not be <code>null</code>.
+ * @param descriptions The associated target descriptions.
+ * May be <code>null</code>, in which case
+ * no descriptions are displayed.
+ * If non-<code>null</code>, this should have
+ * as many elements as <code>names</code>.
+ * @param topDependencies The list of dependencies for each target.
+ * The dependencies are listed as a non null
+ * enumeration of String.
+ * @param heading The heading to display.
+ * Should not be <code>null</code>.
+ * @param maxlen The maximum length of the names of the targets.
+ * If descriptions are given, they are padded to this
+ * position so they line up (so long as the names really
+ * <i>are</i> shorter than this).
+ */
+ private static void printTargets(final Project project, final Vector<String> names,
+ final Vector<String> descriptions, final Vector<Enumeration<String>> dependencies,
+ final String heading,
+ final int maxlen) {
+ // now, start printing the targets and their descriptions
+ final String lSep = System.getProperty("line.separator");
+ // got a bit annoyed that I couldn't find a pad function
+ String spaces = " ";
+ while (spaces.length() <= maxlen) {
+ spaces += spaces;
+ }
+ final StringBuilder msg = new StringBuilder();
+ msg.append(heading + lSep + lSep);
+ final int size = names.size();
+ for (int i = 0; i < size; i++) {
+ msg.append(" ");
+ msg.append(names.elementAt(i));
+ if (descriptions != null) {
+ msg.append(
+ spaces.substring(0, maxlen - names.elementAt(i).length() + 2));
+ msg.append(descriptions.elementAt(i));
+ }
+ msg.append(lSep);
+ if (!dependencies.isEmpty()) {
+ final Enumeration<String> deps = dependencies.elementAt(i);
+ if (deps.hasMoreElements()) {
+ msg.append(" depends on: ");
+ while (deps.hasMoreElements()) {
+ msg.append(deps.nextElement());
+ if (deps.hasMoreElements()) {
+ msg.append(", ");
+ }
+ }
+ msg.append(lSep);
+ }
+ }
+ }
+ project.log(msg.toString(), Project.MSG_WARN);
+ }
+}