/*
 *  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
 *
 *      https://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.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
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.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.stream.Collectors;

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;
import org.apache.tools.ant.util.StreamUtils;

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.

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.

/** * 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.
/** * 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<>(Arrays.asList("-lib", "-cp", "-noclasspath", "--noclasspath", "-nouserlib", "-main")));
The default build file name. "build.xml"
/** The default build file name. {@value} */
public static final String DEFAULT_BUILD_FILENAME = "build.xml";
Our current message output status. Follows Project.MSG_XXX.
/** Our current message output status. Follows Project.MSG_XXX. */
private int msgOutputLevel = Project.MSG_INFO;
File that we are using for configuration.
/** File that we are using for configuration. */
private File buildFile; /* null */
Stream to use for logging.
/** Stream to use for logging. */
private PrintStream out = System.out;
Stream that we are using for logging error messages.
/** Stream that we are using for logging error messages. */
private PrintStream err = System.err;
The build targets.
/** The build targets. */
private final Vector<String> targets = new Vector<>();
Set of properties that can be used by tasks.
/** Set of properties that can be used by tasks. */
private final Properties definedProps = new Properties();
Names of classes to add as listeners to project.
/** Names of classes to add as listeners to project. */
private final Vector<String> listeners = new Vector<>(1);
File names of property files to load on startup.
/** File names of property files to load on startup. */
private final Vector<String> propertyFiles = new Vector<>(1);
Indicates whether this build is to support interactive input
/** Indicates whether this build is to support interactive input */
private boolean allowInput = true;
keep going mode
/** 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.
/** * 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.
/** * 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.
/** * 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
/** * 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.
/** * 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.
/** * 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.
/** * Whether or not a logfile is being used. This is used to * check if the output streams must be closed. */
private boolean isLogFileUsed = false;
optional thread priority
/** * optional thread priority */
private Integer threadPriority = null;
proxy flag: default is false
/** * proxy flag: default is false */
private boolean proxy = false; private final Map<Class<?>, List<String>> extraArguments = new HashMap<>(); private static final GetProperty NOPROPERTIES = aName -> null;
Prints the message of the Throwable if it (the message) is not null.
Params:
  • t – Throwable to print the message of. Must not be 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.
Params:
  • args – Command line arguments. Must not be null.
  • additionalUserProperties – Any extra properties to use in this build. May be null, which is the equivalent to passing in an empty set of properties.
  • coreLoader – Classloader used for core classes. May be null in which case the system classloader is used.
/** * 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
Params:
  • args – command line args
  • additionalUserProperties – properties to set beyond those that may be specified on the args list
  • coreLoader – - not used
Since:Ant 1.6
/** * 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) { additionalUserProperties.stringPropertyNames() .forEach(key -> definedProps.put(key, additionalUserProperties.getProperty(key))); } // 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(); //NOSONAR printMessage(exc); } finally { handleLogfile(); } exit(exitCode); }
This operation is expected to call System.exit(int), which is what the base version does. However, it is possible to do something else.
Params:
  • exitCode – code to exit with
/** * 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
/** * Close logfiles, if we have been writing to them. * * @since Ant 1.6 */
private 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.
Params:
  • args – Command line arguments. Must not be null.
/** * 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
/** * Constructor used when creating Main for later arg processing * and startup */
public Main() { }
Sole constructor, which parses and deals with command line arguments.
Params:
  • args – Command line arguments. Must not be null.
Throws:
  • BuildException – if the specified build file doesn't exist or is a directory.
Deprecated:since 1.6.x
/** * 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.
Params:
  • args – the command line arguments.
Since:Ant 1.6
/** * 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++; // life-cycle of OutputStream is controlled by // logTo which becomes "out" and is closed in // handleLogfile logTo = new PrintStream(Files.newOutputStream(logFile.toPath())); //NOSONAR 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.computeIfAbsent(processor.getClass(), k -> new ArrayList<>()); extraArgs.addAll(Arrays.asList(args).subList(newI, args.length)); 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
/** 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
/** 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
/** 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); String value; 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.
/** 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.
/** 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.
/** 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.
/** 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 < Thread.MIN_PRIORITY || threadPriority > 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
/** Load the property files specified by -propertyfile */
private void loadPropertyFiles() { for (final String filename : propertyFiles) { final Properties props = new Properties(); try (InputStream fis = Files.newInputStream(Paths.get(filename))) { props.load(fis); } catch (final IOException e) { System.out.println("Could not load property file " + filename + ": " + e.getMessage()); } // ensure that -D properties take precedence props.stringPropertyNames().stream() .filter(name -> definedProps.getProperty(name) == null) .forEach(name -> definedProps.put(name, props.getProperty(name))); } }
Helper to get the parent file for a given file.

Added to simulate File.getParentFile() from JDK 1.2.

Params:
  • file – File to find parent of. Must not be null.
Deprecated:since 1.6.x
Returns: Parent file or null if none
/** * 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.

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 null is returned.

Params:
  • start – Leaf directory of search. Must not be null.
  • suffix – Suffix filename to look for in parents. Must not be null.
Returns:A handle to the build file if one is found, null if not
/** * 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.
Params:
  • coreLoader – The classloader to use to find core classes. May be null, in which case the system classloader is used.
Throws:
/** * 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); } 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.isEmpty()) { 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 | Error exc) { error = exc; throw exc; } 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(); //NOSONAR if (error != null) { System.err.println("There has been an error prior to" + " that:"); error.printStackTrace(); //NOSONAR } throw new BuildException(t); //NOSONAR } } 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 props.forEach((arg, value) -> project.setUserProperty(arg, String.valueOf(value))); project.setUserProperty(MagicNames.ANT_FILE, buildFile.getAbsolutePath()); project.setUserProperty(MagicNames.ANT_FILE_TYPE, MagicNames.ANT_FILE_TYPE_FILE); // this list doesn't contain the build files default target, // which may be added later unless targets have been specified // on the command line. Therefore the property gets set again // in Project#executeTargets when we can be sure the list is // complete. // Setting it here allows top-level tasks to access the // property. project.setUserProperty(MagicNames.PROJECT_INVOKED_TARGETS, String.join(",", targets)); }
Adds the listeners specified in the command line arguments, along with the default listener, to the specified project.
Params:
  • project – The project to add listeners to. Must not be null.
/** * 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 = ClasspathUtils.newInstance(className, Main.class.getClassLoader(), BuildListener.class); project.setProjectReference(listener); project.addBuildListener(listener); } }
Creates the InputHandler and adds it to the project.
Params:
  • project – the project instance.
Throws:
  • BuildException – if a specified InputHandler implementation could not be loaded.
/** * 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 = ClasspathUtils.newInstance( inputHandlerClassname, Main.class.getClassLoader(), InputHandler.class); project.setProjectReference(handler); } project.setInputHandler(handler); }
Creates the default build logger for sending build events to the ant log.
Returns:the logger instance for this build.
/** * 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 = 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 e; } } 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 System.out.
/** * 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:"); System.out.println(" 1 (lowest) to 10 (highest); 5 is the default"); System.out.println(" -nouserlib Run ant without using the jar files from"); System.out.println(" ${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 System.out.
Throws:
  • BuildException – if the version information is unavailable
/** * 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.
/** * 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.
/** * 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.
Throws:
Returns:the Ant version information as a String (always non-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"); antVersion = "Apache Ant(TM) version " + shortAntVersion + " compiled on " + props.getProperty("DATE"); } 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.
Throws:
  • BuildException – BuildException if the version information is unavailable
Returns:the short Ant version information as a String (always non-null)
Since:Ant 1.9.3
/** * 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 System.out.
Params:
  • project – The project to display a description of. Must not be null.
/** * 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.
Params:
  • targets – the targets to filter.
Returns:the filtered targets.
/** * 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<>(); targets.forEach((name, target) -> { 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 } }); return locationMap.values().stream() .collect(Collectors.toMap(Target::getName, target -> target, (a, b) -> b)); }
Prints a list of all targets in the specified project to System.out, optionally including subtargets.
Params:
  • project – The project to display a description of. Must not be null.
  • printSubTargets – Whether or not subtarget names should also be printed.
/** * 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<>(); final Vector<String> topDescriptions = new Vector<>(); final Vector<Enumeration<String>> topDependencies = new Vector<>(); final Vector<String> subNames = new Vector<>(); final Vector<Enumeration<String>> subDependencies = new Vector<>(); for (final Target currentTarget : ptargets.values()) { final String targetName = currentTarget.getName(); if (targetName.isEmpty()) { 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.isEmpty()) { printSubTargets = true; } if (printSubTargets) { printTargets(project, subNames, null, subDependencies, "Other targets:", 0); } final String defaultTarget = project.getDefaultTarget(); if (defaultTarget != null && !defaultTarget.isEmpty()) { // 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.
Params:
  • names – The current list of names. Must not be null.
  • name – The name to find a place for. Must not be null.
Returns:the correct place in the list for the given name
/** * 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 System.out with an optional description.
Params:
  • project – the project instance.
  • names – The names to be printed. Must not be null.
  • descriptions – The associated target descriptions. May be null, in which case no descriptions are displayed. If non-null, this should have as many elements as names.
  • heading – The heading to display. Should not be null.
  • 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 are shorter than this).
/** * 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 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 eol = System.lineSeparator(); // got a bit annoyed that I couldn't find a pad function StringBuilder spaces = new StringBuilder(" "); while (spaces.length() <= maxlen) { spaces.append(spaces); } final StringBuilder msg = new StringBuilder(); msg.append(heading).append(eol).append(eol); 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(eol); if (!dependencies.isEmpty() && dependencies.elementAt(i).hasMoreElements()) { msg.append(StreamUtils.enumerationAsStream(dependencies.elementAt(i)) .collect(Collectors.joining(", ", " depends on: ", eol))); } } project.log(msg.toString(), Project.MSG_WARN); } }