0001: /*
0002: * Copyright 2000-2004 The Apache Software Foundation
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: *
0016: */
0017: package org.tp23.antinstaller.antmod;
0018:
0019: import java.io.File;
0020: import java.io.FileInputStream;
0021: import java.io.FileOutputStream;
0022: import java.io.IOException;
0023: import java.io.InputStream;
0024: import java.io.PrintStream;
0025: import java.util.Enumeration;
0026: import java.util.Properties;
0027: import java.util.Vector;
0028:
0029: import org.apache.tools.ant.BuildException;
0030: import org.apache.tools.ant.BuildListener;
0031: import org.apache.tools.ant.BuildLogger;
0032: import org.apache.tools.ant.DefaultLogger;
0033: import org.apache.tools.ant.Diagnostics;
0034: import org.apache.tools.ant.ExitStatusException;
0035: import org.apache.tools.ant.Project;
0036: import org.apache.tools.ant.ProjectHelper;
0037: import org.apache.tools.ant.Target;
0038: import org.apache.tools.ant.input.DefaultInputHandler;
0039: import org.apache.tools.ant.input.InputHandler;
0040: import org.apache.tools.ant.launch.AntMain;
0041: import org.apache.tools.ant.util.JavaEnvUtils;
0042: import org.tp23.antinstaller.InstallerContext;
0043: import org.tp23.antinstaller.PropertiesFileRenderer;
0044: import org.tp23.antinstaller.antmod.taskdefs.CallTargetTask;
0045: import org.tp23.antinstaller.antmod.taskdefs.GetResourceTask;
0046: import org.tp23.antinstaller.antmod.taskdefs.TickTask;
0047:
0048: /**
0049: * Command line entry point into Ant. This class is entered via the
0050: * canonical `public static void main` entry point and reads the
0051: * command line arguments. It then assembles and executes an Ant
0052: * project.
0053: * <p>
0054: * If you integrating Ant into some other tool, this is not the class
0055: * to use as an entry point. Please see the source code of this
0056: * class to see how it manipulates the Ant project classes.
0057: *
0058: * This file has been modified by Paul Hinds for Antinstaller and is not the same
0059: * as the one delivered with Ant 1.6
0060: * @version $Id: Main.java,v 1.5 2007/01/12 10:41:48 anothermwilson Exp $
0061: */
0062: public class Main implements AntMain {
0063:
0064: /** The default build file name. */
0065: public static final String DEFAULT_BUILD_FILENAME = "build.xml";
0066:
0067: /** Our current message output status. Follows Project.MSG_XXX. */
0068: private int msgOutputLevel = Project.MSG_INFO;
0069:
0070: /** File that we are using for configuration. */
0071: private File buildFile; /* null */
0072:
0073: /** Stream to use for logging. */
0074: private static PrintStream out = System.out;
0075:
0076: /** Stream that we are using for logging error messages. */
0077: private static PrintStream err = System.err;
0078:
0079: /** The build targets. */
0080: private Vector targets = new Vector();
0081:
0082: /** Set of properties that can be used by tasks. */
0083: private Properties definedProps = new Properties();
0084:
0085: /** Names of classes to add as listeners to project. */
0086: private Vector listeners = new Vector(1);
0087:
0088: /** File names of property files to load on startup. */
0089: private Vector propertyFiles = new Vector(1);
0090:
0091: /** Indicates whether this build is to support interactive input */
0092: private boolean allowInput = true;
0093:
0094: /** keep going mode */
0095: private boolean keepGoingMode = false;
0096:
0097: /**
0098: * The Ant logger class. There may be only one logger. It will have
0099: * the right to use the 'out' PrintStream. The class must implements the
0100: * BuildLogger interface.
0101: */
0102: private String loggerClassname = null;
0103:
0104: /**
0105: * The Ant InputHandler class. There may be only one input
0106: * handler.
0107: */
0108: private String inputHandlerClassname = null;
0109:
0110: /**
0111: * Whether or not output to the log is to be unadorned.
0112: */
0113: private boolean emacsMode = false;
0114:
0115: /**
0116: * Whether or not this instance has successfully been
0117: * constructed and is ready to run.
0118: */
0119: private boolean readyToRun = false;
0120:
0121: /**
0122: * Whether or not we should only parse and display the project help
0123: * information.
0124: */
0125: private boolean projectHelp = false;
0126:
0127: /**
0128: * Whether or not a logfile is being used. This is used to
0129: * check if the output streams must be closed.
0130: */
0131: private static boolean isLogFileUsed = false;
0132:
0133: /**
0134: * optional thread priority
0135: */
0136: private Integer threadPriority = null;
0137: /**
0138: * Installer Context
0139: */
0140: private InstallerContext ctx = null;
0141:
0142: /**
0143: * Prints the message of the Throwable if it (the message) is not
0144: * <code>null</code>.
0145: *
0146: * @param t Throwable to print the message of.
0147: * Must not be <code>null</code>.
0148: */
0149: private static void printMessage(Throwable t) {
0150: String message = t.getMessage();
0151: if (message != null) {
0152: System.err.println(message);
0153: }
0154: }
0155:
0156: /**
0157: * Creates a new instance of this class using the
0158: * arguments specified, gives it any extra user properties which have been
0159: * specified, and then runs the build using the classloader provided.
0160: *
0161: * @param args Command line arguments. Must not be <code>null</code>.
0162: * @param additionalUserProperties Any extra properties to use in this
0163: * build. May be <code>null</code>, which is the equivalent to
0164: * passing in an empty set of properties.
0165: * @param coreLoader Classloader used for core classes. May be
0166: * <code>null</code> in which case the system classloader is used.
0167: */
0168: public static void start(String[] args,
0169: Properties additionalUserProperties, ClassLoader coreLoader) {
0170: throw new UnsupportedOperationException(
0171: "Required by Ant interface but not used");
0172: //Main m = new Main();
0173: //m.startAnt(args, additionalUserProperties, coreLoader);
0174: }
0175:
0176: public void startAnt(String[] args,
0177: Properties additionalUserProperties, ClassLoader coreLoader) {
0178: throw new UnsupportedOperationException(
0179: "Required by Ant interface but not used");
0180: //startAnt(args, additionalUserProperties, coreLoader, null); // FindBugs does not like this
0181: }
0182:
0183: /**
0184: * Start Ant
0185: * @param args command line args
0186: * @param additionalUserProperties properties to set beyond those that
0187: * may be specified on the args list
0188: * @param coreLoader - not used
0189: * @return the return code that was used for System.exit() in the original Ant
0190: *
0191: * @since Ant 1.6
0192: */
0193: public int startAnt(String[] args,
0194: Properties additionalUserProperties,
0195: ClassLoader coreLoader, InstallerContext ctx) {
0196: this .ctx = ctx;
0197: out = ctx.getAntOutputRenderer().getOut();
0198: err = ctx.getAntOutputRenderer().getErr();
0199: try {
0200: Diagnostics.validateVersion();
0201: processArgs(args);
0202: } catch (Throwable exc) {
0203: handleLogfile();
0204: printMessage(exc);
0205: return 1;
0206: }
0207:
0208: if (additionalUserProperties != null) {
0209: for (Enumeration e = additionalUserProperties.keys(); e
0210: .hasMoreElements();) {
0211: String key = (String) e.nextElement();
0212: String property = additionalUserProperties
0213: .getProperty(key);
0214: definedProps.put(key, property);
0215: }
0216: }
0217:
0218: // expect the worst
0219: int exitCode = 1;
0220: try {
0221: try {
0222: runBuild(coreLoader);
0223: exitCode = 0;
0224: } catch (ExitStatusException ese) {
0225: exitCode = ese.getStatus();
0226: if (exitCode != 0) {
0227: throw ese;
0228: }
0229: }
0230: } catch (BuildException be) {
0231: if (err != System.err) {
0232: printMessage(be);
0233: }
0234: } catch (Throwable exc) {
0235: exc.printStackTrace();
0236: printMessage(exc);
0237: } finally {
0238: handleLogfile();
0239: }
0240: //mod by Paul Hinds
0241: return exitCode;
0242: //System.exit(exitCode);
0243: }
0244:
0245: /**
0246: * Close logfiles, if we have been writing to them.
0247: *
0248: * @since Ant 1.6
0249: */
0250: private static void handleLogfile() {
0251: if (isLogFileUsed) {
0252: if (out != null) {
0253: try {
0254: out.close();
0255: } catch (final Exception e) {
0256: //ignore
0257: }
0258: }
0259: if (err != null) {
0260: try {
0261: err.close();
0262: } catch (final Exception e) {
0263: //ignore
0264: }
0265: }
0266: }
0267: }
0268:
0269: /**
0270: * Command line entry point. This method kicks off the building
0271: * of a project object and executes a build using either a given
0272: * target or the default target.
0273: *
0274: * @param args Command line arguments. Must not be <code>null</code>.
0275: */
0276: // public static void main(String[] args) {
0277: // start(args, null, null);
0278: // }
0279: //
0280: /**
0281: * Constructor used when creating Main for later arg processing
0282: * and startup
0283: */
0284: public Main() {
0285: }
0286:
0287: /**
0288: * Sole constructor, which parses and deals with command line
0289: * arguments.
0290: *
0291: * @param args Command line arguments. Must not be <code>null</code>.
0292: *
0293: * @exception BuildException if the specified build file doesn't exist
0294: * or is a directory.
0295: *
0296: * @deprecated
0297: */
0298: protected Main(String[] args) throws BuildException {
0299: processArgs(args);
0300: }
0301:
0302: /**
0303: * Process command line arguments.
0304: * When ant is started from Launcher, the -lib argument does not get
0305: * passed through to this routine.
0306: *
0307: * @param args the command line arguments.
0308: *
0309: * @since Ant 1.6
0310: */
0311: private void processArgs(String[] args) {
0312: String searchForThis = null;
0313: PrintStream logTo = null;
0314:
0315: // cycle through given args
0316:
0317: for (int i = 0; i < args.length; i++) {
0318: String arg = args[i];
0319:
0320: if (arg.equals("-help") || arg.equals("-h")) {
0321: printUsage();
0322: return;
0323: } else if (arg.equals("-version")) {
0324: printVersion();
0325: return;
0326: } else if (arg.equals("-diagnostics")) {
0327: Diagnostics.doReport(System.out);
0328: return;
0329: } else if (arg.equals("-quiet") || arg.equals("-q")) {
0330: msgOutputLevel = Project.MSG_WARN;
0331: } else if (arg.equals("-verbose") || arg.equals("-v")) {
0332: printVersion();
0333: msgOutputLevel = Project.MSG_VERBOSE;
0334: } else if (arg.equals("-debug") || arg.equals("-d")) {
0335: printVersion();
0336: msgOutputLevel = Project.MSG_DEBUG;
0337: } else if (arg.equals("-noinput")) {
0338: allowInput = false;
0339: } else if (arg.equals("-logfile") || arg.equals("-l")) {
0340: try {
0341: File logFile = new File(args[i + 1]);
0342: i++;
0343: logTo = new PrintStream(new FileOutputStream(
0344: logFile));
0345: isLogFileUsed = true;
0346: } catch (IOException ioe) {
0347: String msg = "Cannot write on the specified log file. "
0348: + "Make sure the path exists and you have write "
0349: + "permissions.";
0350: throw new BuildException(msg);
0351: } catch (ArrayIndexOutOfBoundsException aioobe) {
0352: String msg = "You must specify a log file when "
0353: + "using the -log argument";
0354: throw new BuildException(msg);
0355: }
0356: } else if (arg.equals("-buildfile") || arg.equals("-file")
0357: || arg.equals("-f")) {
0358: try {
0359: buildFile = new File(args[i + 1].replace('/',
0360: File.separatorChar));
0361: i++;
0362: } catch (ArrayIndexOutOfBoundsException aioobe) {
0363: String msg = "You must specify a buildfile when "
0364: + "using the -buildfile argument";
0365: throw new BuildException(msg);
0366: }
0367: } else if (arg.equals("-listener")) {
0368: try {
0369: listeners.addElement(args[i + 1]);
0370: i++;
0371: } catch (ArrayIndexOutOfBoundsException aioobe) {
0372: String msg = "You must specify a classname when "
0373: + "using the -listener argument";
0374: throw new BuildException(msg);
0375: }
0376: } else if (arg.startsWith("-D")) {
0377:
0378: /* Interestingly enough, we get to here when a user
0379: * uses -Dname=value. However, in some cases, the OS
0380: * goes ahead and parses this out to args
0381: * {"-Dname", "value"}
0382: * so instead of parsing on "=", we just make the "-D"
0383: * characters go away and skip one argument forward.
0384: *
0385: * I don't know how to predict when the JDK is going
0386: * to help or not, so we simply look for the equals sign.
0387: */
0388:
0389: String name = arg.substring(2, arg.length());
0390: String value = null;
0391: int posEq = name.indexOf("=");
0392: if (posEq > 0) {
0393: value = name.substring(posEq + 1);
0394: name = name.substring(0, posEq);
0395: } else if (i < args.length - 1) {
0396: value = args[++i];
0397: } else {
0398: throw new BuildException(
0399: "Missing value for property " + name);
0400: }
0401:
0402: definedProps.put(name, value);
0403: } else if (arg.equals("-logger")) {
0404: if (loggerClassname != null) {
0405: throw new BuildException(
0406: "Only one logger class may "
0407: + " be specified.");
0408: }
0409: try {
0410: loggerClassname = args[++i];
0411: } catch (ArrayIndexOutOfBoundsException aioobe) {
0412: throw new BuildException(
0413: "You must specify a classname when"
0414: + " using the -logger argument");
0415: }
0416: } else if (arg.equals("-inputhandler")) {
0417: if (inputHandlerClassname != null) {
0418: throw new BuildException(
0419: "Only one input handler class may "
0420: + "be specified.");
0421: }
0422: try {
0423: inputHandlerClassname = args[++i];
0424: } catch (ArrayIndexOutOfBoundsException aioobe) {
0425: throw new BuildException(
0426: "You must specify a classname when"
0427: + " using the -inputhandler"
0428: + " argument");
0429: }
0430: } else if (arg.equals("-emacs") || arg.equals("-e")) {
0431: emacsMode = true;
0432: } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
0433: // set the flag to display the targets and quit
0434: projectHelp = true;
0435: } else if (arg.equals("-find") || arg.equals("-s")) {
0436: // eat up next arg if present, default to build.xml
0437: if (i < args.length - 1) {
0438: searchForThis = args[++i];
0439: } else {
0440: searchForThis = DEFAULT_BUILD_FILENAME;
0441: }
0442: } else if (arg.startsWith("-propertyfile")) {
0443: try {
0444: propertyFiles.addElement(args[i + 1]);
0445: i++;
0446: } catch (ArrayIndexOutOfBoundsException aioobe) {
0447: String msg = "You must specify a property filename when "
0448: + "using the -propertyfile argument";
0449: throw new BuildException(msg);
0450: }
0451: } else if (arg.equals("-k") || arg.equals("-keep-going")) {
0452: keepGoingMode = true;
0453: } else if (arg.equals("-nice")) {
0454: try {
0455: threadPriority = Integer.decode(args[i + 1]);
0456: } catch (ArrayIndexOutOfBoundsException aioobe) {
0457: throw new BuildException(
0458: "You must supply a niceness value (1-10)"
0459: + " after the -nice option");
0460: } catch (NumberFormatException e) {
0461: throw new BuildException(
0462: "Unrecognized niceness value: "
0463: + args[i + 1]);
0464: }
0465: i++;
0466: if (threadPriority.intValue() < Thread.MIN_PRIORITY
0467: || threadPriority.intValue() > Thread.MAX_PRIORITY) {
0468: throw new BuildException(
0469: "Niceness value is out of the range 1-10");
0470: }
0471: } else if (arg.startsWith("-")) {
0472: // we don't have any more args to recognize!
0473: String msg = "Unknown argument: " + arg;
0474: System.out.println(msg);
0475: printUsage();
0476: throw new BuildException("");
0477: } else {
0478: // if it's no other arg, it may be the target
0479: targets.addElement(arg);
0480: }
0481: }
0482:
0483: // if buildFile was not specified on the command line,
0484: if (buildFile == null) {
0485: // but -find then search for it
0486: if (searchForThis != null) {
0487: buildFile = findBuildFile(System
0488: .getProperty("user.dir"), searchForThis);
0489: } else {
0490: buildFile = new File(DEFAULT_BUILD_FILENAME);
0491: }
0492: }
0493:
0494: // make sure buildfile exists
0495: if (!buildFile.exists()) {
0496: System.out.println("Buildfile: " + buildFile
0497: + " does not exist!");
0498: throw new BuildException("Build failed");
0499: }
0500:
0501: // make sure it's not a directory (this falls into the ultra
0502: // paranoid lets check everything category
0503:
0504: if (buildFile.isDirectory()) {
0505: System.out.println("What? Buildfile: " + buildFile
0506: + " is a dir!");
0507: throw new BuildException("Build failed");
0508: }
0509:
0510: // Load the property files specified by -propertyfile
0511: for (int propertyFileIndex = 0; propertyFileIndex < propertyFiles
0512: .size(); propertyFileIndex++) {
0513: String filename = (String) propertyFiles
0514: .elementAt(propertyFileIndex);
0515: Properties props = new Properties();
0516: FileInputStream fis = null;
0517: try {
0518: fis = new FileInputStream(filename);
0519: props.load(fis);
0520: } catch (IOException e) {
0521: System.out.println("Could not load property file "
0522: + filename + ": " + e.getMessage());
0523: } finally {
0524: if (fis != null) {
0525: try {
0526: fis.close();
0527: } catch (IOException e) {
0528: // ignore
0529: }
0530: }
0531: }
0532:
0533: // ensure that -D properties take precedence
0534: Enumeration propertyNames = props.propertyNames();
0535: while (propertyNames.hasMoreElements()) {
0536: String name = (String) propertyNames.nextElement();
0537: if (definedProps.getProperty(name) == null) {
0538: definedProps.put(name, props.getProperty(name));
0539: }
0540: }
0541: }
0542:
0543: if (msgOutputLevel >= Project.MSG_INFO) {
0544: System.out.println("Buildfile: " + buildFile);
0545: }
0546:
0547: if (logTo != null) {
0548: out = logTo;
0549: err = logTo;
0550: System.setOut(out);
0551: System.setErr(err);
0552: }
0553: readyToRun = true;
0554: }
0555:
0556: /**
0557: * Helper to get the parent file for a given file.
0558: * <p>
0559: * Added to simulate File.getParentFile() from JDK 1.2.
0560: * @deprecated
0561: *
0562: * @param file File to find parent of. Must not be <code>null</code>.
0563: * @return Parent file or null if none
0564: */
0565: private File getParentFile(File file) {
0566: File parent = file.getParentFile();
0567:
0568: if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
0569: System.out.println("Searching in "
0570: + parent.getAbsolutePath());
0571: }
0572:
0573: return parent;
0574: }
0575:
0576: /**
0577: * Search parent directories for the build file.
0578: * <p>
0579: * Takes the given target as a suffix to append to each
0580: * parent directory in search of a build file. Once the
0581: * root of the file-system has been reached an exception
0582: * is thrown.
0583: *
0584: * @param start Leaf directory of search.
0585: * Must not be <code>null</code>.
0586: * @param suffix Suffix filename to look for in parents.
0587: * Must not be <code>null</code>.
0588: *
0589: * @return A handle to the build file if one is found
0590: *
0591: * @exception BuildException if no build file is found
0592: */
0593: private File findBuildFile(String start, String suffix)
0594: throws BuildException {
0595: if (msgOutputLevel >= Project.MSG_INFO) {
0596: System.out.println("Searching for " + suffix + " ...");
0597: }
0598:
0599: File parent = new File(new File(start).getAbsolutePath());
0600: File file = new File(parent, suffix);
0601:
0602: // check if the target file exists in the current directory
0603: while (!file.exists()) {
0604: // change to parent directory
0605: parent = getParentFile(parent);
0606:
0607: // if parent is null, then we are at the root of the fs,
0608: // complain that we can't find the build file.
0609: if (parent == null) {
0610: throw new BuildException(
0611: "Could not locate a build file!");
0612: }
0613:
0614: // refresh our file handle
0615: file = new File(parent, suffix);
0616: }
0617:
0618: return file;
0619: }
0620:
0621: /**
0622: * Executes the build. If the constructor for this instance failed
0623: * (e.g. returned after issuing a warning), this method returns
0624: * immediately.
0625: *
0626: * @param coreLoader The classloader to use to find core classes.
0627: * May be <code>null</code>, in which case the
0628: * system classloader is used.
0629: *
0630: * @exception BuildException if the build fails
0631: */
0632: private void runBuild(ClassLoader coreLoader) throws BuildException {
0633:
0634: if (!readyToRun) {
0635: return;
0636: }
0637:
0638: final Project project = new Project();
0639: project.setCoreLoader(coreLoader);
0640:
0641: Throwable error = null;
0642:
0643: try {
0644: addBuildListeners(project);
0645: addInputHandler(project);
0646:
0647: PrintStream err = System.err;
0648: PrintStream out = System.out;
0649: InputStream in = System.in;
0650: project
0651: .addReference(RuntimeLauncher.CONTEXT_REFERENCE,
0652: ctx);
0653: // use a system manager that prevents from System.exit()
0654: // only in JDK > 1.1
0655: SecurityManager oldsm = null;
0656: if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0)
0657: && !JavaEnvUtils
0658: .isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
0659: oldsm = System.getSecurityManager();
0660:
0661: //SecurityManager can not be installed here for backwards
0662: //compatibility reasons (PD). Needs to be loaded prior to
0663: //ant class if we are going to implement it.
0664: //System.setSecurityManager(new NoExitSecurityManager());
0665: }
0666: try {
0667: if (allowInput) {
0668: project.setDefaultInputStream(System.in);
0669: }
0670: //System.setIn(new DemuxInputStream(project));
0671: //System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
0672: //System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
0673:
0674: if (!projectHelp) {
0675: project.fireBuildStarted();
0676: }
0677:
0678: // set the thread priorities
0679: if (threadPriority != null) {
0680: try {
0681: project.log("Setting Ant's thread priority to "
0682: + threadPriority, Project.MSG_VERBOSE);
0683: Thread.currentThread().setPriority(
0684: threadPriority.intValue());
0685: } catch (SecurityException swallowed) {
0686: //we cannot set the priority here.
0687: project
0688: .log("A security manager refused to set the -nice value");
0689: }
0690: }
0691:
0692: project.init();
0693: project.setUserProperty("ant.version", getAntVersion());
0694:
0695: // set user-define properties
0696: Enumeration e = definedProps.keys();
0697: while (e.hasMoreElements()) {
0698: String arg = (String) e.nextElement();
0699: String value = (String) definedProps.get(arg);
0700: project.setUserProperty(arg, value);
0701: }
0702:
0703: project.setUserProperty("ant.file", buildFile
0704: .getAbsolutePath());
0705: project.setKeepGoingMode(keepGoingMode);
0706:
0707: ProjectHelper.configureProject(project, buildFile);
0708:
0709: project
0710: .setBasedir(definedProps
0711: .getProperty(PropertiesFileRenderer.FILE_ROOT_PROPERTY));
0712: project.addTaskDefinition("antinstaller-calltarget",
0713: CallTargetTask.class);
0714: project.addTaskDefinition("antinstaller-tick",
0715: TickTask.class);
0716: project.addTaskDefinition("antinstaller-getresource",
0717: GetResourceTask.class);
0718:
0719: if (projectHelp) {
0720: printDescription(project);
0721: printTargets(project,
0722: msgOutputLevel > Project.MSG_INFO);
0723: return;
0724: }
0725:
0726: // make sure that we have a target to execute
0727: if (targets.size() == 0) {
0728: if (project.getDefaultTarget() != null) {
0729: targets.addElement(project.getDefaultTarget());
0730: }
0731: }
0732: project.executeTargets(targets);
0733: } finally {
0734: // put back the original security manager
0735: //The following will never eval to true. (PD)
0736: if (oldsm != null) {
0737: System.setSecurityManager(oldsm);
0738: }
0739:
0740: System.setOut(out);
0741: System.setErr(err);
0742: System.setIn(in);
0743: }
0744: } catch (RuntimeException exc) {
0745: error = exc;
0746: throw exc;
0747: } catch (Error err) {
0748: error = err;
0749: throw err;
0750: } finally {
0751: if (!projectHelp) {
0752: project.fireBuildFinished(error);
0753: } else if (error != null) {
0754: project.log(error.toString(), Project.MSG_ERR);
0755: }
0756: }
0757: }
0758:
0759: /**
0760: * Adds the listeners specified in the command line arguments,
0761: * along with the default listener, to the specified project.
0762: *
0763: * @param project The project to add listeners to.
0764: * Must not be <code>null</code>.
0765: */
0766: protected void addBuildListeners(Project project) {
0767:
0768: // Add the default listener
0769: project.addBuildListener(createLogger());
0770:
0771: //Add the AntInstaller Listener
0772: if (ctx.getBuildListener() != null) {
0773: project.addBuildListener(ctx.getBuildListener());
0774: }
0775:
0776: for (int i = 0; i < listeners.size(); i++) {
0777: String className = (String) listeners.elementAt(i);
0778: try {
0779: BuildListener listener = (BuildListener) Class.forName(
0780: className).newInstance();
0781: if (project != null) {
0782: project.setProjectReference(listener);
0783: }
0784: project.addBuildListener(listener);
0785: } catch (Throwable exc) {
0786: throw new BuildException(
0787: "Unable to instantiate listener " + className,
0788: exc);
0789: }
0790: }
0791: }
0792:
0793: /**
0794: * Creates the InputHandler and adds it to the project.
0795: *
0796: * @param project the project instance.
0797: *
0798: * @exception BuildException if a specified InputHandler
0799: * implementation could not be loaded.
0800: */
0801: private void addInputHandler(Project project) throws BuildException {
0802: InputHandler handler = null;
0803: if (inputHandlerClassname == null) {
0804: handler = new DefaultInputHandler();
0805: } else {
0806: try {
0807: handler = (InputHandler) (Class
0808: .forName(inputHandlerClassname).newInstance());
0809: if (project != null) {
0810: project.setProjectReference(handler);
0811: }
0812: } catch (ClassCastException e) {
0813: String msg = "The specified input handler class "
0814: + inputHandlerClassname
0815: + " does not implement the InputHandler interface";
0816: throw new BuildException(msg);
0817: } catch (Exception e) {
0818: String msg = "Unable to instantiate specified input handler "
0819: + "class "
0820: + inputHandlerClassname
0821: + " : "
0822: + e.getClass().getName();
0823: throw new BuildException(msg);
0824: }
0825: }
0826: project.setInputHandler(handler);
0827: }
0828:
0829: // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
0830: // RuntimeException rather than just using a BuildException here? Is it
0831: // in case the message could end up being written to no loggers (as the
0832: // loggers could have failed to be created due to this failure)?
0833: /**
0834: * Creates the default build logger for sending build events to the ant
0835: * log.
0836: *
0837: * @return the logger instance for this build.
0838: */
0839: private BuildLogger createLogger() {
0840: BuildLogger logger = null;
0841: if (loggerClassname != null) {
0842: try {
0843: Class loggerClass = Class.forName(loggerClassname);
0844: logger = (BuildLogger) (loggerClass.newInstance());
0845: } catch (ClassCastException e) {
0846: System.err
0847: .println("The specified logger class "
0848: + loggerClassname
0849: + " does not implement the BuildLogger interface");
0850: throw new RuntimeException();
0851: } catch (Exception e) {
0852: System.err
0853: .println("Unable to instantiate specified logger "
0854: + "class "
0855: + loggerClassname
0856: + " : "
0857: + e.getClass().getName());
0858: throw new RuntimeException();
0859: }
0860: } else {
0861: logger = new DefaultLogger();
0862: }
0863:
0864: logger.setMessageOutputLevel(msgOutputLevel);
0865: logger.setOutputPrintStream(out);
0866: logger.setErrorPrintStream(err);
0867: logger.setEmacsMode(emacsMode);
0868:
0869: return logger;
0870: }
0871:
0872: /**
0873: * Prints the usage information for this class to <code>System.out</code>.
0874: */
0875: private static void printUsage() {
0876: String lSep = System.getProperty("line.separator");
0877: StringBuffer msg = new StringBuffer();
0878: msg.append("ant [options] [target [target2 [target3] ...]]"
0879: + lSep);
0880: msg.append("Options: " + lSep);
0881: msg
0882: .append(" -help, -h print this message"
0883: + lSep);
0884: msg
0885: .append(" -projecthelp, -p print project help information"
0886: + lSep);
0887: msg
0888: .append(" -version print the version information and exit"
0889: + lSep);
0890: msg
0891: .append(" -diagnostics print information that might be helpful to"
0892: + lSep);
0893: msg
0894: .append(" diagnose or report problems."
0895: + lSep);
0896: msg.append(" -quiet, -q be extra quiet" + lSep);
0897: msg.append(" -verbose, -v be extra verbose" + lSep);
0898: msg
0899: .append(" -debug, -d print debugging information"
0900: + lSep);
0901: msg
0902: .append(" -emacs, -e produce logging information without adornments"
0903: + lSep);
0904: msg
0905: .append(" -lib <path> specifies a path to search for jars and classes"
0906: + lSep);
0907: msg.append(" -logfile <file> use given file for log"
0908: + lSep);
0909: msg.append(" -l <file> ''" + lSep);
0910: msg
0911: .append(" -logger <classname> the class which is to perform logging"
0912: + lSep);
0913: msg
0914: .append(" -listener <classname> add an instance of class as a project listener"
0915: + lSep);
0916: msg
0917: .append(" -noinput do not allow interactive input"
0918: + lSep);
0919: msg.append(" -buildfile <file> use given buildfile"
0920: + lSep);
0921: msg.append(" -file <file> ''" + lSep);
0922: msg.append(" -f <file> ''" + lSep);
0923: msg
0924: .append(" -D<property>=<value> use value for given property"
0925: + lSep);
0926: msg
0927: .append(" -keep-going, -k execute all targets that do not depend"
0928: + lSep);
0929: msg.append(" on failed target(s)"
0930: + lSep);
0931: msg
0932: .append(" -propertyfile <name> load all properties from file with -D"
0933: + lSep);
0934: msg
0935: .append(" properties taking precedence"
0936: + lSep);
0937: msg
0938: .append(" -inputhandler <class> the class which will handle input requests"
0939: + lSep);
0940: msg
0941: .append(" -find <file> (s)earch for buildfile towards the root of"
0942: + lSep);
0943: msg.append(" -s <file> the filesystem and use it"
0944: + lSep);
0945: msg
0946: .append(" -nice number A niceness value for the main thread:"
0947: + lSep
0948: + " 1 (lowest) to 10 (highest); 5 is the default"
0949: + lSep);
0950: System.out.println(msg.toString());
0951: }
0952:
0953: /**
0954: * Prints the Ant version information to <code>System.out</code>.
0955: *
0956: * @exception BuildException if the version information is unavailable
0957: */
0958: private static void printVersion() throws BuildException {
0959: System.out.println(getAntVersion());
0960: }
0961:
0962: /**
0963: * Cache of the Ant version information when it has been loaded.
0964: */
0965: private static String antVersion = null;
0966:
0967: /**
0968: * Returns the Ant version information, if available. Once the information
0969: * has been loaded once, it's cached and returned from the cache on future
0970: * calls.
0971: *
0972: * @return the Ant version information as a String
0973: * (always non-<code>null</code>)
0974: *
0975: * @exception BuildException if the version information is unavailable
0976: */
0977: public static synchronized String getAntVersion()
0978: throws BuildException {
0979: if (antVersion == null) {
0980: try {
0981: Properties props = new Properties();
0982: InputStream in = Main.class
0983: .getResourceAsStream("/org/apache/tools/ant/version.txt");
0984: props.load(in);
0985: in.close();
0986:
0987: StringBuffer msg = new StringBuffer();
0988: msg.append("Apache Ant version ");
0989: msg.append(props.getProperty("VERSION"));
0990: msg.append(" compiled on ");
0991: msg.append(props.getProperty("DATE"));
0992: antVersion = msg.toString();
0993: } catch (IOException ioe) {
0994: throw new BuildException(
0995: "Could not load the version information:"
0996: + ioe.getMessage());
0997: } catch (NullPointerException npe) {
0998: throw new BuildException(
0999: "Could not load the version information.");
1000: }
1001: }
1002: return antVersion;
1003: }
1004:
1005: /**
1006: * Prints the description of a project (if there is one) to
1007: * <code>System.out</code>.
1008: *
1009: * @param project The project to display a description of.
1010: * Must not be <code>null</code>.
1011: */
1012: private static void printDescription(Project project) {
1013: if (project.getDescription() != null) {
1014: project.log(project.getDescription());
1015: }
1016: }
1017:
1018: /**
1019: * Prints a list of all targets in the specified project to
1020: * <code>System.out</code>, optionally including subtargets.
1021: *
1022: * @param project The project to display a description of.
1023: * Must not be <code>null</code>.
1024: * @param printSubTargets Whether or not subtarget names should also be
1025: * printed.
1026: */
1027: private static void printTargets(Project project,
1028: boolean printSubTargets) {
1029: // find the target with the longest name
1030: int maxLength = 0;
1031: Enumeration ptargets = project.getTargets().elements();
1032: String targetName;
1033: String targetDescription;
1034: Target currentTarget;
1035: // split the targets in top-level and sub-targets depending
1036: // on the presence of a description
1037: Vector topNames = new Vector();
1038: Vector topDescriptions = new Vector();
1039: Vector subNames = new Vector();
1040:
1041: while (ptargets.hasMoreElements()) {
1042: currentTarget = (Target) ptargets.nextElement();
1043: targetName = currentTarget.getName();
1044: if (targetName.equals("")) {
1045: continue;
1046: }
1047: targetDescription = currentTarget.getDescription();
1048: // maintain a sorted list of targets
1049: if (targetDescription == null) {
1050: int pos = findTargetPosition(subNames, targetName);
1051: subNames.insertElementAt(targetName, pos);
1052: } else {
1053: int pos = findTargetPosition(topNames, targetName);
1054: topNames.insertElementAt(targetName, pos);
1055: topDescriptions.insertElementAt(targetDescription, pos);
1056: if (targetName.length() > maxLength) {
1057: maxLength = targetName.length();
1058: }
1059: }
1060: }
1061:
1062: printTargets(project, topNames, topDescriptions,
1063: "Main targets:", maxLength);
1064: //if there were no main targets, we list all subtargets
1065: //as it means nothing has a description
1066: if (topNames.size() == 0) {
1067: printSubTargets = true;
1068: }
1069: if (printSubTargets) {
1070: printTargets(project, subNames, null, "Other targets:", 0);
1071: }
1072:
1073: String defaultTarget = project.getDefaultTarget();
1074: if (defaultTarget != null && !"".equals(defaultTarget)) {
1075: // shouldn't need to check but...
1076: project.log("Default target: " + defaultTarget);
1077: }
1078: }
1079:
1080: /**
1081: * Searches for the correct place to insert a name into a list so as
1082: * to keep the list sorted alphabetically.
1083: *
1084: * @param names The current list of names. Must not be <code>null</code>.
1085: * @param name The name to find a place for.
1086: * Must not be <code>null</code>.
1087: *
1088: * @return the correct place in the list for the given name
1089: */
1090: private static int findTargetPosition(Vector names, String name) {
1091: int res = names.size();
1092: for (int i = 0; i < names.size() && res == names.size(); i++) {
1093: if (name.compareTo((String) names.elementAt(i)) < 0) {
1094: res = i;
1095: }
1096: }
1097: return res;
1098: }
1099:
1100: /**
1101: * Writes a formatted list of target names to <code>System.out</code>
1102: * with an optional description.
1103: *
1104: *
1105: * @param project the project instance.
1106: * @param names The names to be printed.
1107: * Must not be <code>null</code>.
1108: * @param descriptions The associated target descriptions.
1109: * May be <code>null</code>, in which case
1110: * no descriptions are displayed.
1111: * If non-<code>null</code>, this should have
1112: * as many elements as <code>names</code>.
1113: * @param heading The heading to display.
1114: * Should not be <code>null</code>.
1115: * @param maxlen The maximum length of the names of the targets.
1116: * If descriptions are given, they are padded to this
1117: * position so they line up (so long as the names really
1118: * <i>are</i> shorter than this).
1119: */
1120: private static void printTargets(Project project, Vector names,
1121: Vector descriptions, String heading, int maxlen) {
1122: // now, start printing the targets and their descriptions
1123: String lSep = System.getProperty("line.separator");
1124: // got a bit annoyed that I couldn't find a pad function
1125: String spaces = " ";
1126: while (spaces.length() <= maxlen) {
1127: spaces += spaces;
1128: }
1129: StringBuffer msg = new StringBuffer();
1130: msg.append(heading);
1131: msg.append(lSep);
1132: msg.append(lSep);
1133: for (int i = 0; i < names.size(); i++) {
1134: msg.append(" ");
1135: msg.append(names.elementAt(i));
1136: if (descriptions != null) {
1137: msg.append(spaces.substring(0, maxlen
1138: - ((String) names.elementAt(i)).length() + 2));
1139: msg.append(descriptions.elementAt(i));
1140: }
1141: msg.append(lSep);
1142: }
1143: project.log(msg.toString());
1144: }
1145: }
|