* Use modified version of Path.java, to provide all available classes in Path.systemClasspath. (Uses LoaderUtils.java taken from Mutant proposal, for obtaining complete classpath from a ClassLoader.) * Removed <ant> and <antcall> from ant1compat.atl descriptor, since they don't work. * Modified build so that xdoclet.jar and jdepend.jar aren't included in dist/lib. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271907 13f79535-47bb-0310-9956-ffa450edef68master
@@ -1,7 +1,7 @@ | |||
<project name="ant1-compatibility" default="main"> | |||
<property name="ant1compat.source" value="src/ant1compat"/> | |||
<property name="manifest.dir" value="src/manifest"/> | |||
<property name="java.dir" value="src/java"/> | |||
@@ -10,7 +10,7 @@ | |||
<property name="build.classes" value="${build.dir}/classes"/> | |||
<property name="custom-tasks-dir" value="build/tasks"/> | |||
<path id="project.class.path"> | |||
<pathelement location="build/classes"/> | |||
<fileset dir="lib"> | |||
@@ -18,7 +18,8 @@ | |||
</fileset> | |||
</path> | |||
<taskdef name="antlib-jar" classname="org.apache.myrmidon.build.AntlibJarTask"> | |||
<taskdef name="antlib-jar" | |||
classname="org.apache.myrmidon.build.AntlibJarTask"> | |||
<classpath location="${custom-tasks-dir}"/> | |||
</taskdef> | |||
@@ -31,11 +32,11 @@ | |||
<!-- Builds the Ant1 compatibility layer --> | |||
<target name="antlib" | |||
description="Builds the Ant1 compatibility layer."> | |||
<property name="ant1compat.dir" value="src/ant1compat"/> | |||
<property name="ant1.jar" value="${ant1compat.dir}/jar/ant.jar"/> | |||
<property name="ant1optional.jar" value="${ant1compat.dir}/jar/optional.jar"/> | |||
<property name="ant1.package" value="org/apache/tools"/> | |||
<property name="build.ant1classes" value="${build.dir}/ant1classes"/> | |||
@@ -57,16 +58,17 @@ | |||
<src location="${ant1compat.dir}"/> | |||
<include name="${ant1.package}/**"/> | |||
</javac> | |||
<patternset id="ant1.omit"> | |||
<exclude name="${ant1.package}/ant/Main.class"/> | |||
<exclude name="${ant1.package}/ant/Task.class"/> | |||
<exclude name="${ant1.package}/ant/taskdefs/Ant.class"/> | |||
<exclude name="${ant1.package}/ant/taskdefs/CallTarget.class"/> | |||
<exclude name="${ant1.package}/ant/types/Path.class"/> | |||
</patternset> | |||
<property name="antlib.file" value="${build.lib}/ant1compat.atl"/> | |||
<!-- Create the ant1compat antlib --> | |||
<antlib-jar jarfile="${build.lib}/ant1compat.atl" | |||
<antlib-jar jarfile="${antlib.file}" | |||
descriptor="${ant1compat.dir}/ant-descriptor.xml" | |||
rolesDescriptor="${manifest.dir}/empty-roles.xml" | |||
manifest="${ant1compat.dir}/ant1compat.mf"> | |||
@@ -79,7 +81,7 @@ | |||
</fileset> | |||
</antlib-jar> | |||
<copy todir="dist/lib" file="${build.lib}/ant1compat.atl"/> | |||
<copy todir="dist/lib" file="${antlib.file}"/> | |||
</target> | |||
<!-- Runs the supplied build file through the XSL converter --> | |||
@@ -621,7 +621,10 @@ Legal: | |||
</copy> | |||
<copy todir="${dist.lib}"> | |||
<fileset dir="${lib.dir}"/> | |||
<fileset dir="${lib.dir}"> | |||
<exclude name="xdoclet.jar"/> | |||
<exclude name="jdepend.jar"/> | |||
</fileset> | |||
</copy> | |||
<copy todir="${dist.bin}"> | |||
@@ -56,5 +56,5 @@ TODO | |||
to register tasks? (similar for DataTypes) | |||
* Get a version of <ant> and <antcall> working | |||
* Test heaps more tasks | |||
* Fix problem with classloaders and <taskdef> | |||
* Check that "if" and "unless" conversions are working. | |||
@@ -6,11 +6,21 @@ | |||
classname="org.apache.tools.ant.Ant1CompatTypeInstanceTask" /> | |||
<task name="ant1.patternset" | |||
classname="org.apache.tools.ant.Ant1CompatTypeInstanceTask" /> | |||
<task name="ant1.filterset" | |||
classname="org.apache.tools.ant.Ant1CompatTypeInstanceTask" /> | |||
<!-- TaskAdapter tasks --> | |||
<task name="ant1.condition" | |||
classname="org.apache.tools.ant.Ant1CompatTaskAdapter" /> | |||
<!-- Tasks not currently supported. | |||
<task name="ant1.antcall" | |||
classname="org.apache.tools.ant.taskdefs.CallTarget" /> | |||
<task name="ant1.ant" | |||
classname="org.apache.tools.ant.taskdefs.Ant" /> | |||
--> | |||
<!-- standard ant tasks --> | |||
<task name="ant1.mkdir" | |||
classname="org.apache.tools.ant.taskdefs.Mkdir" /> | |||
@@ -58,8 +68,6 @@ | |||
classname="org.apache.tools.ant.taskdefs.Property" /> | |||
<task name="ant1.taskdef" | |||
classname="org.apache.tools.ant.taskdefs.Taskdef" /> | |||
<task name="ant1.ant" | |||
classname="org.apache.tools.ant.taskdefs.Ant" /> | |||
<task name="ant1.exec" | |||
classname="org.apache.tools.ant.taskdefs.ExecTask" /> | |||
<task name="ant1.tar" | |||
@@ -86,8 +94,6 @@ | |||
classname="org.apache.tools.ant.taskdefs.AntStructure" /> | |||
<task name="ant1.execon" | |||
classname="org.apache.tools.ant.taskdefs.ExecuteOn" /> | |||
<task name="ant1.antcall" | |||
classname="org.apache.tools.ant.taskdefs.CallTarget" /> | |||
<task name="ant1.sql" | |||
classname="org.apache.tools.ant.taskdefs.SQLExec" /> | |||
<task name="ant1.mail" | |||
@@ -35,6 +35,12 @@ public class Ant1CompatProject extends Project | |||
super(); | |||
m_context = context; | |||
setBaseDir( m_context.getBaseDirectory() ); | |||
String projectName = (String) | |||
m_context.getProperty( org.apache.myrmidon.interfaces.model.Project.PROJECT ); | |||
if( projectName != null ) | |||
{ | |||
setName( projectName ); | |||
} | |||
} | |||
/** | |||
@@ -238,105 +244,4 @@ public class Ant1CompatProject extends Project | |||
typeManager.registerType( roleType, typeName, factory ); | |||
} | |||
// /** | |||
// * Sets a property. Any existing property of the same name | |||
// * is overwritten, unless it is a user property. | |||
// * @param name The name of property to set. | |||
// * Must not be <code>null</code>. | |||
// * @param value The new value of the property. | |||
// * Must not be <code>null</code>. | |||
// */ | |||
// public void setProperty( String name, String value ) | |||
// { | |||
// if( null != getProperty( name ) ) | |||
// { | |||
// log( "Overriding previous definition of property " + name, | |||
// MSG_VERBOSE ); | |||
// } | |||
// | |||
// doSetProperty( name, value ); | |||
// } | |||
// | |||
// /** | |||
// * Sets a property if no value currently exists. If the property | |||
// * exists already, a message is logged and the method returns with | |||
// * no other effect. | |||
// * | |||
// * @param name The name of property to set. | |||
// * Must not be <code>null</code>. | |||
// * @param value The new value of the property. | |||
// * Must not be <code>null</code>. | |||
// * @since 1.5 | |||
// */ | |||
// public void setNewProperty( String name, String value ) | |||
// { | |||
// if( null != getProperty( name ) ) | |||
// { | |||
// log( "Override ignored for property " + name, MSG_VERBOSE ); | |||
// return; | |||
// } | |||
// log( "Setting project property: " + name + " -> " + | |||
// value, MSG_DEBUG ); | |||
// doSetProperty( name, value ); | |||
// } | |||
// | |||
// private void doSetProperty( String name, String value ) | |||
// { | |||
// try | |||
// { | |||
// m_context.setProperty( name, value ); | |||
// } | |||
// catch( TaskException e ) | |||
// { | |||
// throw new BuildException( e ); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * Returns the value of a property, if it is set. | |||
// * | |||
// * @param name The name of the property. | |||
// * May be <code>null</code>, in which case | |||
// * the return value is also <code>null</code>. | |||
// * @return the property value, or <code>null</code> for no match | |||
// * or if a <code>null</code> name is provided. | |||
// */ | |||
// public String getProperty( String name ) | |||
// { | |||
// if( name == null ) | |||
// { | |||
// return null; | |||
// } | |||
// Object value = m_context.getProperty( name ); | |||
// if( value == null ) | |||
// { | |||
// return null; | |||
// } | |||
// return String.valueOf( value ); | |||
// } | |||
// | |||
// /** | |||
// * Returns a copy of the properties table. | |||
// * @return a hashtable containing all properties | |||
// * (including user properties). | |||
// */ | |||
// public Hashtable getProperties() | |||
// { | |||
// Map properties = m_context.getProperties(); | |||
// Hashtable propertiesCopy = new Hashtable(); | |||
// | |||
// Iterator iterator = properties.keySet().iterator(); | |||
// while( iterator.hasNext() ) | |||
// { | |||
// String key = (String)iterator.next(); | |||
// String value = (String)properties.get( key ); | |||
// | |||
// propertiesCopy.put( key, value ); | |||
// | |||
// } | |||
// | |||
// return propertiesCopy; | |||
// } | |||
} |
@@ -0,0 +1,286 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2002 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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FilenameFilter; | |||
import java.io.IOException; | |||
import java.io.InputStreamReader; | |||
import java.io.PrintStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* LoaderUtils is a utility class with methods for configuring a class | |||
* loader from a URL. | |||
* | |||
* @author Conor MacNeill | |||
* @created 9 January 2002 | |||
*/ | |||
public class LoaderUtils { | |||
/** | |||
* This is the file that is consulted on remote systems to specify | |||
* available jars | |||
*/ | |||
public static final String LIST_FILE = "file.list"; | |||
/** | |||
* Get the URLs of a set of libraries in the given location | |||
* | |||
* @param location the location to be searched | |||
* @param defaultFile default file if none can be found | |||
* @return an array of URLs for the relevant jars | |||
* @exception MalformedURLException the URLs cannot be created | |||
*/ | |||
public static URL[] getLocationURLs(URL location, String defaultFile) | |||
throws MalformedURLException { | |||
return getLocationURLs(location, defaultFile, new String[]{".jar"}); | |||
} | |||
/** | |||
* Get the URLs of a set of libraries in the given location | |||
* | |||
* @param location the location to be searched | |||
* @param extensions array of allowable file extensions | |||
* @param defaultFile default file if none can be found | |||
* @return an array of URLs for the relevant jars | |||
* @exception MalformedURLException if the URL to the jars could not be | |||
* formed | |||
*/ | |||
public static URL[] getLocationURLs(URL location, String defaultFile, | |||
String[] extensions) | |||
throws MalformedURLException { | |||
URL[] urls = null; | |||
if (location.getProtocol().equals("file")) { | |||
// URL is local filesystem. | |||
urls = getLocalURLs(new File(location.getFile()), extensions); | |||
} else { | |||
// URL is remote - try to read a file with the list of jars | |||
URL jarListURL = new URL(location, LIST_FILE); | |||
BufferedReader reader = null; | |||
List jarList = new ArrayList(); | |||
try { | |||
InputStreamReader isr | |||
= new InputStreamReader(jarListURL.openStream()); | |||
reader = new BufferedReader(isr); | |||
String line = null; | |||
while ((line = reader.readLine().trim()) != null) { | |||
for (int i = 0; i < extensions.length; ++i) { | |||
if (line.endsWith(extensions[i])) { | |||
jarList.add(new URL(location, line)); | |||
break; | |||
} | |||
} | |||
} | |||
urls = (URL[])jarList.toArray(new URL[0]); | |||
} catch (IOException e) { | |||
// use the default location | |||
if (defaultFile != null) { | |||
urls = new URL[]{new URL(location, defaultFile)}; | |||
} | |||
} finally { | |||
if (reader != null) { | |||
try { | |||
reader.close(); | |||
} catch (IOException e) { | |||
} | |||
} | |||
} | |||
} | |||
return urls; | |||
} | |||
/** | |||
* Get the classpath from a classloader. This can only extract path | |||
* components from the loaders which are instances of URLClassLoaders | |||
* | |||
* @param loader the loader whose path is required | |||
* @return the loader's configuration expressed as a classpath | |||
*/ | |||
public static String getClasspath(ClassLoader loader) { | |||
StringBuffer pathBuffer = null; | |||
if (loader instanceof URLClassLoader) { | |||
URLClassLoader urlLoader = (URLClassLoader)loader; | |||
URL[] urls = urlLoader.getURLs(); | |||
for (int i = 0; i < urls.length; ++i) { | |||
if (!urls[i].getProtocol().equals("file")) { | |||
continue; | |||
} | |||
String pathElement = urls[i].getFile(); | |||
if (pathBuffer == null) { | |||
pathBuffer = new StringBuffer(pathElement); | |||
} else { | |||
pathBuffer.append(File.pathSeparatorChar); | |||
pathBuffer.append(pathElement); | |||
} | |||
} | |||
} | |||
String path = pathBuffer == null ? "" : pathBuffer.toString(); | |||
ClassLoader parentLoader = loader.getParent(); | |||
if (parentLoader != null) { | |||
String parentPath = getClasspath(parentLoader); | |||
if (parentPath.length() != 0) { | |||
path = parentPath + File.pathSeparator + path; | |||
} | |||
} | |||
return path; | |||
} | |||
/** | |||
* Debug method to dump a class loader hierarchy to a PrintStream | |||
* URLClassLoaders dump their URLs | |||
* | |||
* @param loader the class loaders whose configuration is dumped | |||
* @param ps PrintStream to which info is sent | |||
*/ | |||
public static void dumpLoader(PrintStream ps, ClassLoader loader) { | |||
if (loader instanceof URLClassLoader) { | |||
URLClassLoader urlLoader = (URLClassLoader)loader; | |||
URL[] urls = urlLoader.getURLs(); | |||
if (urls.length == 0) { | |||
ps.println(" No URLs"); | |||
} else { | |||
for (int i = 0; i < urls.length; ++i) { | |||
ps.println(" URL: " + urls[i]); | |||
} | |||
} | |||
} else { | |||
ps.println("Class Loader: " + loader.getClass().getName()); | |||
} | |||
ps.println(); | |||
ClassLoader parentLoader = loader.getParent(); | |||
if (parentLoader != null) { | |||
ps.println("Parent Loader:"); | |||
dumpLoader(ps, parentLoader); | |||
} | |||
} | |||
/** | |||
* Get an array of URLs for each file in the filesystem. If the given | |||
* location is a directory, it is searched for files of the given | |||
* extension. If it is a file, it is returned as a URL if it matches the | |||
* given extension list. | |||
* | |||
* @param location the location within the local filesystem to be | |||
* searched | |||
* @param extensions an array of file extensions to be considered in the | |||
* search | |||
* @return an array of URLs for the file found in the directory. | |||
* @exception MalformedURLException if the URLs to the jars cannot be | |||
* formed | |||
*/ | |||
private static URL[] getLocalURLs(File location, | |||
final String[] extensions) | |||
throws MalformedURLException { | |||
URL[] urls = new URL[0]; | |||
if (!location.exists()) { | |||
return urls; | |||
} | |||
if (!location.isDirectory()) { | |||
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[] jars = 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[jars.length]; | |||
for (int i = 0; i < jars.length; ++i) { | |||
urls[i] = jars[i].toURL(); | |||
} | |||
return urls; | |||
} | |||
/** | |||
* Set the context loader of the current thread and returns the existing | |||
* classloader | |||
* | |||
* @param newLoader the new context loader | |||
* @return the old context loader | |||
*/ | |||
public static ClassLoader setContextLoader(ClassLoader newLoader) { | |||
Thread thread = Thread.currentThread(); | |||
ClassLoader currentLoader = thread.getContextClassLoader(); | |||
thread.setContextClassLoader(newLoader); | |||
return currentLoader; | |||
} | |||
} | |||
@@ -27,7 +27,7 @@ import org.apache.myrmidon.api.TaskException; | |||
public class Task extends OriginalAnt1Task | |||
implements org.apache.myrmidon.api.Task, Configurable | |||
{ | |||
private TaskContext m_context; | |||
protected TaskContext m_context; | |||
/** | |||
* Specify the context in which the task operates in. | |||
@@ -62,6 +62,7 @@ public class Task extends OriginalAnt1Task | |||
public void configure( Configuration configuration ) throws ConfigurationException | |||
{ | |||
configure( this, configuration ); | |||
this.init(); | |||
} | |||
protected void configure( Object target, Configuration configuration ) throws ConfigurationException | |||
@@ -115,30 +116,6 @@ public class Task extends OriginalAnt1Task | |||
helper.storeElement( project, target, nestedElement, name ); | |||
} | |||
/* | |||
task.setLocation(new Location(helperImpl.buildFile.toString(), helperImpl.locator.getLineNumber(), | |||
helperImpl.locator.getColumnNumber())); | |||
String id = attr.getValue("id"); | |||
if (id != null) { | |||
project.addReference(id, target); | |||
} | |||
// Top level tasks don't have associated targets | |||
if (target != null) { | |||
task.setOwningTarget(target); | |||
container.addTask(task); | |||
task.init(); | |||
wrapper = task.getRuntimeConfigurableWrapper(); | |||
wrapper.setAttributes(attrs); | |||
if (parentWrapper != null) { | |||
parentWrapper.addChild(wrapper); | |||
} | |||
} else { | |||
task.init(); | |||
configure(task, attrs, helperImpl.project); | |||
} | |||
*/ | |||
} | |||
protected String getAnt1Name( String fullName ) | |||
@@ -0,0 +1,625 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2000-2002 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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.types; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.PathTokenizer; | |||
import org.apache.tools.ant.LoaderUtils; | |||
import java.io.File; | |||
import java.util.Enumeration; | |||
import java.util.Locale; | |||
import java.util.Stack; | |||
import java.util.Vector; | |||
/** | |||
* *********************************************************************** | |||
* Ant1Compatibility Layer version of Path, hacked to provide Ant1 runtime | |||
* files in System Classpath. | |||
* *********************************************************************** | |||
* | |||
* This object represents a path as used by CLASSPATH or PATH | |||
* environment variable. | |||
* <p> | |||
* <code> | |||
* <sometask><br> | |||
* <somepath><br> | |||
* <pathelement location="/path/to/file.jar" /><br> | |||
* <pathelement path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /><br> | |||
* <pathelement location="/path/to/file3.jar" /><br> | |||
* <pathelement location="/path/to/file4.jar" /><br> | |||
* </somepath><br> | |||
* </sometask><br> | |||
* </code> | |||
* <p> | |||
* The object implemention <code>sometask</code> must provide a method called | |||
* <code>createSomepath</code> which returns an instance of <code>Path</code>. | |||
* Nested path definitions are handled by the Path object and must be labeled | |||
* <code>pathelement</code>.<p> | |||
* | |||
* The path element takes a parameter <code>path</code> which will be parsed | |||
* and split into single elements. It will usually be used | |||
* to define a path from an environment variable. | |||
* | |||
* @author Thomas.Haas@softwired-inc.com | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class Path extends DataType implements Cloneable { | |||
private Vector elements; | |||
public static Path systemClasspath = | |||
new Path(null, System.getProperty("java.class.path")); | |||
//Modified from original source. | |||
//Append Ant1 codebase to systemclasspath. | |||
// ------------------Modified-------------------------------- | |||
static | |||
{ | |||
String classpath = LoaderUtils.getClasspath( Path.class.getClassLoader() ); | |||
systemClasspath.append( new Path( null, classpath ) ); | |||
} | |||
//-----------------End Modified------------------------------ | |||
/** | |||
* Helper class, holds the nested <code><pathelement></code> values. | |||
*/ | |||
public class PathElement { | |||
private String[] parts; | |||
public void setLocation(File loc) { | |||
parts = new String[] {translateFile(loc.getAbsolutePath())}; | |||
} | |||
public void setPath(String path) { | |||
parts = Path.translatePath(getProject(), path); | |||
} | |||
public String[] getParts() { | |||
return parts; | |||
} | |||
} | |||
/** | |||
* Invoked by IntrospectionHelper for <code>setXXX(Path p)</code> | |||
* attribute setters. | |||
*/ | |||
public Path(Project p, String path) { | |||
this(p); | |||
createPathElement().setPath(path); | |||
} | |||
public Path(Project project) { | |||
setProject(project); | |||
elements = new Vector(); | |||
} | |||
/** | |||
* Adds a element definition to the path. | |||
* @param location the location of the element to add (must not be | |||
* <code>null</code> nor empty. | |||
*/ | |||
public void setLocation(File location) throws BuildException { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
createPathElement().setLocation(location); | |||
} | |||
/** | |||
* Parses a path definition and creates single PathElements. | |||
* @param path the path definition. | |||
*/ | |||
public void setPath(String path) throws BuildException { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
createPathElement().setPath(path); | |||
} | |||
/** | |||
* Makes this instance in effect a reference to another Path instance. | |||
* | |||
* <p>You must not set another attribute or nest elements inside | |||
* this element if you make it a reference.</p> | |||
*/ | |||
public void setRefid(Reference r) throws BuildException { | |||
if (!elements.isEmpty()) { | |||
throw tooManyAttributes(); | |||
} | |||
elements.addElement(r); | |||
super.setRefid(r); | |||
} | |||
/** | |||
* Creates the nested <code><pathelement></code> element. | |||
*/ | |||
public PathElement createPathElement() throws BuildException { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
PathElement pe = new PathElement(); | |||
elements.addElement(pe); | |||
return pe; | |||
} | |||
/** | |||
* Adds a nested <code><fileset></code> element. | |||
*/ | |||
public void addFileset(FileSet fs) throws BuildException { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
elements.addElement(fs); | |||
checked = false; | |||
} | |||
/** | |||
* Creates a nested <code><path></code> element. | |||
*/ | |||
public Path createPath() throws BuildException { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
Path p = new Path(getProject()); | |||
elements.addElement(p); | |||
checked = false; | |||
return p; | |||
} | |||
/** | |||
* Append the contents of the other Path instance to this. | |||
*/ | |||
public void append(Path other) { | |||
if (other == null) { | |||
return; | |||
} | |||
String[] l = other.list(); | |||
for (int i=0; i<l.length; i++) { | |||
if (elements.indexOf(l[i]) == -1) { | |||
elements.addElement(l[i]); | |||
} | |||
} | |||
} | |||
/** | |||
* Adds the components on the given path which exist to this | |||
* Path. Components that don't exist, aren't added. | |||
* | |||
* @param source - source path whose components are examined for existence | |||
*/ | |||
public void addExisting(Path source) { | |||
String[] list = source.list(); | |||
for (int i=0; i<list.length; i++) { | |||
File f = null; | |||
if (getProject() != null) { | |||
f = getProject().resolveFile(list[i]); | |||
} | |||
else { | |||
f = new File(list[i]); | |||
} | |||
if (f.exists()) { | |||
setLocation(f); | |||
} else { | |||
log("dropping " + f + " from path as it doesn't exist", | |||
Project.MSG_VERBOSE); | |||
} | |||
} | |||
} | |||
/** | |||
* Returns all path elements defined by this and nested path objects. | |||
* @return list of path elements. | |||
*/ | |||
public String[] list() { | |||
if (!checked) { | |||
// make sure we don't have a circular reference here | |||
Stack stk = new Stack(); | |||
stk.push(this); | |||
dieOnCircularReference(stk, getProject()); | |||
} | |||
Vector result = new Vector(2*elements.size()); | |||
for (int i=0; i<elements.size(); i++) { | |||
Object o = elements.elementAt(i); | |||
if (o instanceof Reference) { | |||
Reference r = (Reference) o; | |||
o = r.getReferencedObject(getProject()); | |||
// we only support references to paths right now | |||
if (!(o instanceof Path)) { | |||
String msg = r.getRefId()+" doesn\'t denote a path"; | |||
throw new BuildException(msg); | |||
} | |||
} | |||
if (o instanceof String) { | |||
// obtained via append | |||
addUnlessPresent(result, (String) o); | |||
} else if (o instanceof PathElement) { | |||
String[] parts = ((PathElement) o).getParts(); | |||
if (parts == null) { | |||
throw new BuildException("You must either set location or path on <pathelement>"); | |||
} | |||
for (int j=0; j<parts.length; j++) { | |||
addUnlessPresent(result, parts[j]); | |||
} | |||
} else if (o instanceof Path) { | |||
Path p = (Path) o; | |||
if (p.getProject() == null) { | |||
p.setProject(getProject()); | |||
} | |||
String[] parts = p.list(); | |||
for (int j=0; j<parts.length; j++) { | |||
addUnlessPresent(result, parts[j]); | |||
} | |||
} else if (o instanceof FileSet) { | |||
FileSet fs = (FileSet) o; | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
String[] s = ds.getIncludedFiles(); | |||
File dir = fs.getDir(getProject()); | |||
for (int j=0; j<s.length; j++) { | |||
File f = new File(dir, s[j]); | |||
String absolutePath = f.getAbsolutePath(); | |||
addUnlessPresent(result, translateFile(absolutePath)); | |||
} | |||
} | |||
} | |||
String[] res = new String[result.size()]; | |||
result.copyInto(res); | |||
return res; | |||
} | |||
/** | |||
* Returns a textual representation of the path, which can be used as | |||
* CLASSPATH or PATH environment variable definition. | |||
* @return a textual representation of the path. | |||
*/ | |||
public String toString() { | |||
final String[] list = list(); | |||
// empty path return empty string | |||
if (list.length == 0) { | |||
return ""; | |||
} | |||
// path containing one or more elements | |||
final StringBuffer result = new StringBuffer(list[0].toString()); | |||
for (int i=1; i < list.length; i++) { | |||
result.append(File.pathSeparatorChar); | |||
result.append(list[i]); | |||
} | |||
return result.toString(); | |||
} | |||
/** | |||
* Splits a PATH (with : or ; as separators) into its parts. | |||
*/ | |||
public static String[] translatePath(Project project, String source) { | |||
final Vector result = new Vector(); | |||
if (source == null) { | |||
return new String[0]; | |||
} | |||
PathTokenizer tok = new PathTokenizer(source); | |||
StringBuffer element = new StringBuffer(); | |||
while (tok.hasMoreTokens()) { | |||
element.setLength(0); | |||
String pathElement = tok.nextToken(); | |||
try { | |||
element.append(resolveFile(project, pathElement)); | |||
} | |||
catch (BuildException e) { | |||
project.log("Dropping path element " + pathElement + " as it is not valid relative to the project", | |||
Project.MSG_VERBOSE); | |||
} | |||
for (int i=0; i<element.length(); i++) { | |||
translateFileSep(element, i); | |||
} | |||
result.addElement(element.toString()); | |||
} | |||
String[] res = new String[result.size()]; | |||
result.copyInto(res); | |||
return res; | |||
} | |||
/** | |||
* Returns its argument with all file separator characters | |||
* replaced so that they match the local OS conventions. | |||
*/ | |||
public static String translateFile(String source) { | |||
if (source == null) { | |||
return ""; | |||
} | |||
final StringBuffer result = new StringBuffer(source); | |||
for (int i=0; i < result.length(); i++) { | |||
translateFileSep(result, i); | |||
} | |||
return result.toString(); | |||
} | |||
/** | |||
* Translates all occurrences of / or \ to correct separator of the | |||
* current platform and returns whether it had to do any | |||
* replacements. | |||
*/ | |||
protected static boolean translateFileSep(StringBuffer buffer, int pos) { | |||
if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') { | |||
buffer.setCharAt(pos, File.separatorChar); | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* How many parts does this Path instance consist of. | |||
*/ | |||
public int size() { | |||
return list().length; | |||
} | |||
/** | |||
* Return a Path that holds the same elements as this instance. | |||
*/ | |||
public Object clone() { | |||
Path p = new Path(getProject()); | |||
p.append(this); | |||
return p; | |||
} | |||
/** | |||
* Overrides the version of DataType to recurse on all DataType | |||
* child elements that may have been added. | |||
*/ | |||
protected void dieOnCircularReference(Stack stk, Project p) | |||
throws BuildException { | |||
if (checked) { | |||
return; | |||
} | |||
Enumeration enum = elements.elements(); | |||
while (enum.hasMoreElements()) { | |||
Object o = enum.nextElement(); | |||
if (o instanceof Reference) { | |||
o = ((Reference) o).getReferencedObject(p); | |||
} | |||
if (o instanceof DataType) { | |||
if (stk.contains(o)) { | |||
throw circularReference(); | |||
} else { | |||
stk.push(o); | |||
((DataType) o).dieOnCircularReference(stk, p); | |||
stk.pop(); | |||
} | |||
} | |||
} | |||
checked = true; | |||
} | |||
/** | |||
* Resolve a filename with Project's help - if we know one that is. | |||
* | |||
* <p>Assume the filename is absolute if project is null.</p> | |||
*/ | |||
private static String resolveFile(Project project, String relativeName) { | |||
if (project != null) { | |||
File f = project.resolveFile(relativeName); | |||
return f.getAbsolutePath(); | |||
} | |||
return relativeName; | |||
} | |||
/** | |||
* Adds a String to the Vector if it isn't already included. | |||
*/ | |||
private static void addUnlessPresent(Vector v, String s) { | |||
if (v.indexOf(s) == -1) { | |||
v.addElement(s); | |||
} | |||
} | |||
/** | |||
* Concatenates the system class path in the order specified by | |||
* the ${build.sysclasspath} property - using "last" as | |||
* default value. | |||
*/ | |||
public Path concatSystemClasspath() { | |||
return concatSystemClasspath("last"); | |||
} | |||
/** | |||
* Concatenates the system class path in the order specified by | |||
* the ${build.sysclasspath} property - using the supplied value | |||
* if ${build.sysclasspath} has not been set. | |||
*/ | |||
public Path concatSystemClasspath(String defValue) { | |||
Path result = new Path(getProject()); | |||
String order = defValue; | |||
if (getProject() != null) { | |||
String o = getProject().getProperty("build.sysclasspath"); | |||
if (o != null) { | |||
order = o; | |||
} | |||
} | |||
if (order.equals("only")) { | |||
// only: the developer knows what (s)he is doing | |||
result.addExisting(Path.systemClasspath); | |||
} else if (order.equals("first")) { | |||
// first: developer could use a little help | |||
result.addExisting(Path.systemClasspath); | |||
result.addExisting(this); | |||
} else if (order.equals("ignore")) { | |||
// ignore: don't trust anyone | |||
result.addExisting(this); | |||
} else { | |||
// last: don't trust the developer | |||
if (!order.equals("last")) { | |||
log("invalid value for build.sysclasspath: " + order, | |||
Project.MSG_WARN); | |||
} | |||
result.addExisting(this); | |||
result.addExisting(Path.systemClasspath); | |||
} | |||
return result; | |||
} | |||
/** | |||
* Add the Java Runtime classes to this Path instance. | |||
*/ | |||
public void addJavaRuntime() { | |||
if (System.getProperty("java.vendor").toLowerCase(Locale.US).indexOf("microsoft") >= 0) { | |||
// Pull in *.zip from packages directory | |||
FileSet msZipFiles = new FileSet(); | |||
msZipFiles.setDir(new File(System.getProperty("java.home") + File.separator + "Packages")); | |||
msZipFiles.setIncludes("*.ZIP"); | |||
addFileset(msZipFiles); | |||
} else if("Kaffe".equals(System.getProperty("java.vm.name"))) { | |||
FileSet kaffeJarFiles = new FileSet(); | |||
kaffeJarFiles.setDir(new File(System.getProperty("java.home") | |||
+ File.separator + "share" | |||
+ File.separator + "kaffe")); | |||
kaffeJarFiles.setIncludes("*.jar"); | |||
addFileset(kaffeJarFiles); | |||
} | |||
else if (Project.getJavaVersion() == Project.JAVA_1_1) { | |||
addExisting(new Path(null, | |||
System.getProperty("java.home") | |||
+ File.separator + "lib" | |||
+ File.separator | |||
+ "classes.zip")); | |||
} else { | |||
// JDK > 1.1 seems to set java.home to the JRE directory. | |||
addExisting(new Path(null, | |||
System.getProperty("java.home") | |||
+ File.separator + "lib" | |||
+ File.separator + "rt.jar")); | |||
// Just keep the old version as well and let addExisting | |||
// sort it out. | |||
addExisting(new Path(null, | |||
System.getProperty("java.home") | |||
+ File.separator +"jre" | |||
+ File.separator + "lib" | |||
+ File.separator + "rt.jar")); | |||
// Added for MacOS X | |||
addExisting(new Path(null, | |||
System.getProperty("java.home") | |||
+ File.separator + ".." | |||
+ File.separator + "Classes" | |||
+ File.separator + "classes.jar")); | |||
addExisting(new Path(null, | |||
System.getProperty("java.home") | |||
+ File.separator + ".." | |||
+ File.separator + "Classes" | |||
+ File.separator + "ui.jar")); | |||
} | |||
} | |||
/** | |||
* Emulation of extdirs feature in java >= 1.2. | |||
* This method adds all files in the given | |||
* directories (but not in sub-directories!) to the classpath, | |||
* so that you don't have to specify them all one by one. | |||
* @param extdirs - Path to append files to | |||
*/ | |||
public void addExtdirs(Path extdirs) { | |||
if (extdirs == null) { | |||
String extProp = System.getProperty("java.ext.dirs"); | |||
if (extProp != null) { | |||
extdirs = new Path(getProject(), extProp); | |||
} else { | |||
return; | |||
} | |||
} | |||
String[] dirs = extdirs.list(); | |||
for (int i=0; i<dirs.length; i++) { | |||
File dir = getProject().resolveFile(dirs[i]); | |||
if (dir.exists() && dir.isDirectory()) { | |||
FileSet fs = new FileSet(); | |||
fs.setDir(dir); | |||
fs.setIncludes("*"); | |||
addFileset(fs); | |||
} | |||
} | |||
} | |||
} |