From b36b67d9e2f4304e706efad7d4090dcfdf03e215 Mon Sep 17 00:00:00 2001 From: Conor MacNeill Date: Fri, 27 Jun 2003 11:19:22 +0000 Subject: [PATCH] New Launch facility. Separate jar now can be used to launch Ant which takes over some of the functionality traditionally found in the Ant launch scripts. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274724 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 95 ++++++-- src/main/org/apache/tools/ant/Main.java | 61 ++++- .../org/apache/tools/ant/launch/AntMain.java | 79 ++++++ .../org/apache/tools/ant/launch/Launcher.java | 168 +++++++++++++ .../org/apache/tools/ant/launch/Locator.java | 226 ++++++++++++++++++ 5 files changed, 599 insertions(+), 30 deletions(-) create mode 100644 src/main/org/apache/tools/ant/launch/AntMain.java create mode 100644 src/main/org/apache/tools/ant/launch/Launcher.java create mode 100644 src/main/org/apache/tools/ant/launch/Locator.java diff --git a/build.xml b/build.xml index cf01d3c06..0b91775b5 100644 --- a/build.xml +++ b/build.xml @@ -18,12 +18,31 @@ + - + + + + + + + + + + + @@ -33,6 +52,8 @@ + + @@ -90,7 +103,8 @@ - + + @@ -113,8 +127,6 @@ - - + + + + + + + + @@ -675,6 +731,7 @@ + diff --git a/src/main/org/apache/tools/ant/Main.java b/src/main/org/apache/tools/ant/Main.java index 802cde583..bd4d0e133 100644 --- a/src/main/org/apache/tools/ant/Main.java +++ b/src/main/org/apache/tools/ant/Main.java @@ -66,6 +66,8 @@ import java.util.Vector; import org.apache.tools.ant.input.DefaultInputHandler; import org.apache.tools.ant.input.InputHandler; import org.apache.tools.ant.util.JavaEnvUtils; +import org.apache.tools.ant.launch.AntMain; + /** * Command line entry point into Ant. This class is entered via the @@ -79,7 +81,7 @@ import org.apache.tools.ant.util.JavaEnvUtils; * * @author duncan@x180.com */ -public class Main { +public class Main implements AntMain { /** The default build file name. */ public static final String DEFAULT_BUILD_FILENAME = "build.xml"; @@ -175,11 +177,25 @@ public class Main { */ public static void start(String[] args, Properties additionalUserProperties, ClassLoader coreLoader) { - Main m = null; + 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(String[] args, Properties additionalUserProperties, + ClassLoader coreLoader) { try { Diagnostics.validateVersion(); - m = new Main(args); + processArgs(args); } catch (Throwable exc) { handleLogfile(); printMessage(exc); @@ -191,17 +207,17 @@ public class Main { e.hasMoreElements();) { String key = (String) e.nextElement(); String property = additionalUserProperties.getProperty(key); - m.definedProps.put(key, property); + definedProps.put(key, property); } } // expect the worst int exitCode = 1; try { - m.runBuild(coreLoader); + runBuild(coreLoader); exitCode = 0; } catch (BuildException be) { - if (m.err != System.err) { + if (err != System.err) { printMessage(be); } } catch (Throwable exc) { @@ -248,6 +264,13 @@ public class Main { 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. @@ -258,6 +281,17 @@ public class Main { * or is a directory. */ protected Main(String[] args) throws BuildException { + processArgs(args); + } + + /** + * Process command line arguments + * + * @param args the command line arguments. + * + * @since Ant 1.6 + */ + private void processArgs(String[] args) { String searchForThis = null; PrintStream logTo = null; @@ -656,8 +690,8 @@ public class Main { try { BuildListener listener = (BuildListener) Class.forName(className).newInstance(); - if ( project != null ) { - project.setProjectReference( listener ); + if (project != null) { + project.setProjectReference(listener); } project.addBuildListener(listener); } catch (Throwable exc) { @@ -670,6 +704,8 @@ public class Main { /** * 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. */ @@ -681,8 +717,8 @@ public class Main { try { handler = (InputHandler) (Class.forName(inputHandlerClassname).newInstance()); - if ( project != null ) { - project.setProjectReference( handler ); + if (project != null) { + project.setProjectReference(handler); } } catch (ClassCastException e) { String msg = "The specified input handler class " @@ -713,7 +749,8 @@ public class Main { BuildLogger logger = null; if (loggerClassname != null) { try { - logger = (BuildLogger) (Class.forName(loggerClassname).newInstance()); + Class loggerClass = Class.forName(loggerClassname); + logger = (BuildLogger) (loggerClass.newInstance()); } catch (ClassCastException e) { System.err.println("The specified logger class " + loggerClassname @@ -918,6 +955,8 @@ public class Main { * Writes a formatted list of target names to System.out * with an optional description. * + * + * @param project the project instance. * @param names The names to be printed. * Must not be null. * @param descriptions The associated target descriptions. diff --git a/src/main/org/apache/tools/ant/launch/AntMain.java b/src/main/org/apache/tools/ant/launch/AntMain.java new file mode 100644 index 000000000..fe2ea8317 --- /dev/null +++ b/src/main/org/apache/tools/ant/launch/AntMain.java @@ -0,0 +1,79 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.launch; + +import java.util.Properties; + +/** + * Interface used to bridge to the actual Main class without any + * messy reflection + * + * @author Conor MacNeill + * @since Ant 1.6 + */ +public interface AntMain { + /** + * 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 + */ + void startAnt(String[] args, Properties additionalUserProperties, + ClassLoader coreLoader); +} + diff --git a/src/main/org/apache/tools/ant/launch/Launcher.java b/src/main/org/apache/tools/ant/launch/Launcher.java new file mode 100644 index 000000000..019ba04ee --- /dev/null +++ b/src/main/org/apache/tools/ant/launch/Launcher.java @@ -0,0 +1,168 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.launch; + +import java.net.URL; +import java.net.URLClassLoader; +import java.net.MalformedURLException; +import java.io.File; + +/** + * This is a launcher for Ant. + * + * @author Conor MacNeill + * @since Ant 1.6 + */ +public class Launcher { + /** The Ant Home property */ + public static final String ANTHOME_PROPERTY = "ant.home"; + + /** The location of a per-user library directory */ + public static final String USER_LIBDIR = ".ant/lib"; + + /** The startup class that is to be run */ + public static final String MAIN_CLASS = "org.apache.tools.ant.Main"; + + /** + * Entry point for starting command line Ant + * + * @param args commandline arguments + */ + public static void main(String[] args) { + try { + Launcher launcher = new Launcher(); + launcher.run(args); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + + /** + * Run the launcher to launch Ant + * + * @param args the command line arguments + * + * @exception MalformedURLException if the URLs required for the classloader + * cannot be created. + */ + private void run(String[] args) throws MalformedURLException { + String antHomeProperty = System.getProperty(ANTHOME_PROPERTY); + File antHome = null; + + URL launchJarURL = Locator.getClassLocationURL(getClass()); + File jarDir = new File(launchJarURL.getFile()).getParentFile(); + + if (antHomeProperty != null) { + antHome = new File(antHomeProperty); + } + + if (antHome == null || !antHome.exists()) { + URL antHomeURL = new URL(launchJarURL, ".."); + antHome = new File(antHomeURL.getFile()); + System.setProperty(ANTHOME_PROPERTY, antHome.getAbsolutePath()); + } + + if (!antHome.exists()) { + throw new IllegalStateException("Ant home is set incorrectly or " + + "ant could not be located"); + } + + + // Now try and find JAVA_HOME + File toolsJar = Locator.getToolsJar(); + + URL[] systemJars = Locator.getLocationURLs(jarDir); + + File userLibDir + = new File(System.getProperty("user.home"), USER_LIBDIR); + URL[] userJars = Locator.getLocationURLs(userLibDir); + + + int numJars = userJars.length + systemJars.length; + if (toolsJar != null) { + numJars++; + } + URL[] jars = new URL[numJars]; + System.arraycopy(userJars, 0, jars, 0, userJars.length); + System.arraycopy(systemJars, 0, jars, userJars.length, + systemJars.length); + + if (toolsJar != null) { + jars[jars.length - 1] = toolsJar.toURL(); + } + + + // now update the class.path property + StringBuffer baseClassPath + = new StringBuffer(System.getProperty("java.class.path")); + + for (int i = 0; i < jars.length; ++i) { + baseClassPath.append(File.pathSeparatorChar); + baseClassPath.append(jars[i].getFile()); + } + + System.setProperty("java.class.path", baseClassPath.toString()); + + URLClassLoader loader = new URLClassLoader(jars); + try { + Class mainClass = loader.loadClass(MAIN_CLASS); + AntMain main = (AntMain) mainClass.newInstance(); + main.startAnt(args, null, null); + } catch (Throwable t) { + t.printStackTrace(); + } + } +} + diff --git a/src/main/org/apache/tools/ant/launch/Locator.java b/src/main/org/apache/tools/ant/launch/Locator.java new file mode 100644 index 000000000..44163120e --- /dev/null +++ b/src/main/org/apache/tools/ant/launch/Locator.java @@ -0,0 +1,226 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.launch; + +import java.net.MalformedURLException; + +import java.net.URL; +import java.io.File; +import java.io.FilenameFilter; + +/** + * The Locator is a utility class which is used to find certain items + * in the environment + * + * @author Conor MacNeill + * @since Ant 1.6 + */ +public class Locator { + /** + * Get the URL for the given class's load location. + * + * @param theClass the class whose load URL is desired. + * @return a URL which identifies the component from which this class + * was loaded. + * @throws MalformedURLException if the class' URL cannot be + * constructed. + */ + public static URL getClassLocationURL(Class theClass) + throws MalformedURLException { + String className = theClass.getName().replace('.', '/') + ".class"; + URL classRawURL = theClass.getClassLoader().getResource(className); + + String fileComponent = classRawURL.getFile(); + if (classRawURL.getProtocol().equals("file")) { + // Class comes from a directory of class files rather than + // from a jar. + int classFileIndex = fileComponent.lastIndexOf(className); + if (classFileIndex != -1) { + fileComponent = fileComponent.substring(0, classFileIndex); + } + + return new URL("file:" + fileComponent); + } else if (classRawURL.getProtocol().equals("jar")) { + // Class is coming from a jar. The file component of the URL + // is actually the URL of the jar file + int classSeparatorIndex = fileComponent.lastIndexOf("!"); + if (classSeparatorIndex != -1) { + fileComponent = fileComponent.substring(0, classSeparatorIndex); + } + + return new URL(fileComponent); + } else { + // its running out of something besides a jar. + // We just return the Raw URL as a best guess + return classRawURL; + } + } + + /** + * Get the URL necessary to load the Sun compiler tools. If the classes + * are available to this class, then no additional URL is required and + * null is returned. This may be because the classes are explcitly in the + * class path or provided by the JVM directly + * + * @return the tools jar as a File if required, null otherwise + */ + public static File getToolsJar() { + // firstly check if the tols jar is alreayd n the classpath + boolean toolsJarAvailable = false; + + try { + // just check whether this throws an exception + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } catch (Exception e) { + try { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } catch (Exception e2) { + // ignore + } + } + + if (toolsJarAvailable) { + return null; + } + + // couldn't find compiler - try to find tools.jar + // based on java.home setting + String javaHome = System.getProperty("java.home"); + if (javaHome.endsWith("jre")) { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + File toolsJar = new File(javaHome + "/lib/tools.jar"); + if (!toolsJar.exists()) { + System.out.println("Unable to locate tools.jar. " + + "Expected to find it in " + toolsJar.getPath()); + return null; + } + return toolsJar; + } + + /** + * Get an array or URLs representing all of the jar files in the + * given location. If the location is a file, it is returned as the only + * element of the array. If the location is a directory, it is scanned for + * jar files + * + * @param location the location to scan for Jars + * + * @return an array of URLs for all jars in the given location. + * + * @exception MalformedURLException if the URLs for the jars cannot be + * formed + */ + public static URL[] getLocationURLs(File location) + throws MalformedURLException { + return getLocationURLs(location, new String[]{".jar"}); + } + + /** + * Get an array or URLs representing all of the files of a given set of + * extensions in the given location. If the location is a file, it is + * returned as the only element of the array. If the location is a + * directory, it is scanned for matching files + * + * @param location the location to scan for files + * @param extensions an array of extension that are to match in the + * directory search + * + * @return an array of URLs of matching files + * @exception MalformedURLException if the URLs for the files cannot be + * formed + */ + public static URL[] getLocationURLs(File location, + final String[] extensions) + throws MalformedURLException { + URL[] urls = new URL[0]; + + if (!location.exists()) { + return urls; + } + + if (!location.isDirectory()) { + urls = new URL[1]; + String path = location.getPath(); + for (int i = 0; i < extensions.length; ++i) { + if (path.endsWith(extensions[i])) { + urls[0] = location.toURL(); + break; + } + } + return urls; + } + + File[] matches = location.listFiles( + new FilenameFilter() { + public boolean accept(File dir, String name) { + for (int i = 0; i < extensions.length; ++i) { + if (name.endsWith(extensions[i])) { + return true; + } + } + return false; + } + }); + + urls = new URL[matches.length]; + for (int i = 0; i < matches.length; ++i) { + urls[i] = matches[i].toURL(); + } + return urls; + } +} +