diff --git a/proposal/myrmidon/ant1compat.xml b/proposal/myrmidon/ant1compat.xml
index 94d3fae14..3d625bfb4 100644
--- a/proposal/myrmidon/ant1compat.xml
+++ b/proposal/myrmidon/ant1compat.xml
@@ -63,6 +63,8 @@
+ * <target name="foo" depends="init"> + * <ant antfile="build.xml" target="bar" > + * <property name="property1" value="aaaaa" /> + * <property name="foo" value="baz" /> + * </ant> + * </target> + * + * <target name="bar" depends="init"> + * <echo message="prop is ${property1} ${foo}" /> + * </target> + *+ * + * + * @author costin@dnt.ro + * @author Darrell DeBoer + */ +public class Ant extends Task { + + /** the basedir where is executed the build file */ + private File dir = null; + + /** the build.xml file (can be absolute) in this case dir will be ignored */ + private String antFile = null; + + /** the target to call if any */ + private String target = null; + + /** the output */ + private String output = null; + + /** should we inherit properties from the parent ? */ + private boolean inheritAll = true; + + /** should we inherit references from the parent ? */ + private boolean inheritRefs = false; + + /** the properties to pass to the new project */ + private Vector properties = new Vector(); + + /** the references to pass to the new project */ + private Vector references = new Vector(); + + /** + * If true, inherit all properties from parent Project + * If false, inherit only userProperties and those defined + * inside the ant call itself + */ + public void setInheritAll(boolean value) { + inheritAll = value; + } + + /** + * If true, inherit all references from parent Project + * If false, inherit only those defined + * inside the ant call itself + */ + public void setInheritRefs(boolean value) { + inheritRefs = value; + } + + /** + * ... + */ + public void setDir(File d) { + this.dir = d; + } + + /** + * set the build file, it can be either absolute or relative. + * If it is absolute, dir will be ignored, if it is + * relative it will be resolved relative to dir. + */ + public void setAntfile(String s) { + // @note: it is a string and not a file to handle relative/absolute + // otherwise a relative file will be resolved based on the current + // basedir. + this.antFile = s; + } + + /** + * set the target to execute. If none is defined it will + * execute the default target of the build file + */ + public void setTarget(String s) { + this.target = s; + } + + public void setOutput(String s) { + this.output = s; + } + + /** create a property to pass to the new project as a 'user property' */ + public Property createProperty() { + Property p = new Property(true); + properties.addElement( p ); + return p; + } + + /** + * create a reference element that identifies a data type that + * should be carried over to the new project. + */ + public void addReference(Reference r) { + references.addElement(r); + } + + /** + * Helper class that implements the nested <reference> + * element of <ant> and <antcall>. + */ + public static class Reference + extends org.apache.tools.ant.types.Reference { + + public Reference() {super();} + + private String targetid=null; + public void setToRefid(String targetid) { this.targetid=targetid; } + public String getToRefid() { return targetid; } + } + + /** + * Called by the project to let the task do its work. This method may be + * called more than once, if the task is invoked more than once. + * For example, + * if target1 and target2 both depend on target3, then running + * "ant target1 target2" will run all tasks in target3 twice. + * + * @exception BuildException if something goes wrong with the build + */ + public void execute() throws BuildException + { + Object ant1project = unsetProject(); + + try + { + Configuration antConfig = buildAntTaskConfiguration(); + + executeTask( antConfig ); + } + finally + { + resetProject( ant1project ); + } + } + + private void executeTask( Configuration antConfig ) + { + try + { + Executor executor = (Executor) m_context.getService( Executor.class ); + ExecutionFrame frame = + (ExecutionFrame) m_context.getService( ExecutionFrame.class ); + executor.execute( antConfig, frame ); + } + catch( TaskException e ) + { + throw new BuildException( e ); + } + } + + private Configuration buildAntTaskConfiguration() + { + DefaultConfiguration antConfig = new DefaultConfiguration( "ant", "" ); + + antConfig.setAttribute( "inherit-all", String.valueOf( inheritAll ) ); + + // Ignore inheritRefs for now ( inheritAll == inheritRefs ) + + if ( target != null ) + { + antConfig.setAttribute( "target", target ); + } + + // Get the "file" value. + if (antFile == null) { + antFile = "build.xml"; + } + + if ( dir == null ) + { + dir = project.getBaseDir(); + } + + File file = FileUtils.newFileUtils().resolveFile(dir, antFile); + antFile = file.getAbsolutePath(); + + antConfig.setAttribute( "file", antFile ); + + // Add all of the properties. + Iterator iter = properties.iterator(); + while( iter.hasNext() ) + { + DefaultConfiguration param = new DefaultConfiguration( "param", "" ); + Property property = (Property)iter.next(); + param.setAttribute( "name", property.getName() ); + param.setAttribute( "value", property.getValue() ); + antConfig.addChild( param ); + } + return antConfig; + } + + private void resetProject( Object ant1project ) throws BuildException + { + try + { + m_context.setProperty( "ant1.project", ant1project ); + } + catch( TaskException e ) + { + throw new BuildException( e ); + } + } + + private Object unsetProject() throws BuildException + { + Object ant1project = null; + try + { + ant1project = m_context.getProperty( "ant1.project" ); + m_context.setProperty( "ant1.project", null ); + } + catch( TaskException e ) + { + throw new BuildException( e ); + } + return ant1project; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/antlib/core/AbstractAntTask.java b/proposal/myrmidon/src/java/org/apache/antlib/core/AbstractAntTask.java new file mode 100644 index 000000000..a9910dbf8 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/antlib/core/AbstractAntTask.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.antlib.core; + +import org.apache.myrmidon.api.AbstractTask; +import org.apache.myrmidon.api.TaskException; +import org.apache.myrmidon.interfaces.model.Project; +import org.apache.myrmidon.interfaces.workspace.Workspace; +import org.apache.myrmidon.interfaces.embeddor.Embeddor; +import org.apache.avalon.framework.parameters.Parameters; +import java.util.Map; +import java.util.Iterator; +import java.util.ArrayList; + +/** + * Abstract base class for Tasks which execute targets. + * + * @author Peter Donald + * @author Darrell DeBoer + * @version $Revision$ $Date$ + */ +public abstract class AbstractAntTask extends AbstractTask +{ + /** + * If true, inherit all properties from parent Project + * If false, inherit only userProperties and those defined + * inside the ant call itself + */ + private boolean m_inheritAll; + /** + * The target to process in build file. If not specified + * will use default in specified build file. + */ + private String m_target; + private final ArrayList m_parameters = new ArrayList(); + + /** + * Specify whether should inherit properties in sub-build. + * + * @param inheritAll true to inherit else false + */ + public void setInheritAll( final boolean inheritAll ) + { + m_inheritAll = inheritAll; + } + + /** + * set the target to process. If none is defined it will + * execute the default target of the build file + */ + public void setTarget( final String target ) + { + m_target = target; + } + + /** + * Add a parameter to processing of build file. + * + * @param param the parameter + */ + public void addParam( final AntParam param ) + { + m_parameters.add( param ); + } + + /** + * Execute the specified build, with specified parameters. + * + * @throws TaskException if an error occurs. + */ + public void execute() + throws TaskException + { + try + { + Project project = getProject(); + + Embeddor embeddor = getEmbeddor(); + + final Workspace workspace = + embeddor.createWorkspace( buildParameters() ); + + workspace.addProjectListener( embeddor.createListener("default")); + + if( null == m_target ) + { + m_target = project.getDefaultTargetName(); + } + + workspace.executeProject( project, m_target ); + } + catch( final Exception e ) + { + throw new TaskException( e.toString(), e ); + } + } + + /** + * A convenience method for obtaining the Embeddor from the + * TaskContext. + * @return The Embeddor contained in the TaskContext + * @throws TaskException if the Embeddor could not be obtained. + */ + protected Embeddor getEmbeddor() throws TaskException + { + final Embeddor embeddor = + (Embeddor)getContext().getService( Embeddor.class ); + return embeddor; + } + + /** + * Get/create/build the project containing the target to be executed. + * Subclasses will override this method to provide different means + * of obtaining a project to execute. + * @return The project containing the target to execute. + * @throws Exception If a problem occurred building the project. + */ + protected abstract Project getProject() throws Exception; + + /** + * Build the parameters to pass to sub-project. + * These include the current tasks properties + * (if inheritall=true) and any supplied by the user. + * + * @return the created parameters + */ + private Parameters buildParameters() + throws TaskException + { + final Parameters parameters = new Parameters(); + + if( m_inheritAll ) + { + final Map properties = getContext().getProperties(); + final Iterator keys = properties.keySet().iterator(); + while( keys.hasNext() ) + { + final String key = (String)keys.next(); + final Object value = properties.get( key ); + setProperty( parameters, key, value ); + } + } + + final int size = m_parameters.size(); + for( int i = 0; i < size; i++ ) + { + final AntParam param = (AntParam)m_parameters.get( i ); + param.validate(); + final String name = param.getName(); + final String value = param.getValue().toString(); + setProperty( parameters, name, value ); + } + + return parameters; + } + + /** + * Utility method to add the property into parameters object. + * + * @param parameters where to put property + * @param name the property + * @param value the value of property + * @todo allow non-string params to be passed down + */ + private void setProperty( final Parameters parameters, + final String name, + final Object value ) + { + if( !name.startsWith( "myrmidon." ) ) + { + parameters.setParameter( name, value.toString() ); + } + } +} diff --git a/proposal/myrmidon/src/java/org/apache/antlib/core/AntCallTask.java b/proposal/myrmidon/src/java/org/apache/antlib/core/AntCallTask.java new file mode 100644 index 000000000..8acbff796 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/antlib/core/AntCallTask.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.antlib.core; + +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.myrmidon.api.TaskException; +import org.apache.myrmidon.interfaces.model.Project; + +/** + * A task which executes a target in the current project, + * or a referenced project. + * + * @author Darrell DeBoer + * @version $Revision$ $Date$ + * @ant.task name="ant-call" + */ +public class AntCallTask extends AbstractAntTask +{ + private final static Resources REZ = + ResourceManager.getPackageResources( AntCallTask.class ); + + private String m_project; + + /** + * Specifies the project to execute. If not specified, the current + * project is used. + * @param project the name of the Project to execute. + */ + public void setProject( String project ) + { + m_project = project; + } + + /** + * Get/create/build the project which will be executed. + * Subclasses will override this method to provide different means + * of obtaining a project to execute. + * @return The project containing the target to execute. + * @throws Exception If a problem occurred building the project. + */ + protected Project getProject() throws Exception + { + Project currentProject = + (Project)getContext().getService( Project.class ); + + // By default, use the current project. + Project referencedProject = currentProject; + + if( m_project != null ) + { + referencedProject = currentProject.getProject( m_project ); + if( referencedProject == null ) + { + final String message = + REZ.getString( "antcall.invalid-project.error" ); + throw new TaskException( message ); + } + } + + return referencedProject; + } +} \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java b/proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java index c1c58fdcb..ad9b9a426 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java @@ -8,66 +8,35 @@ package org.apache.antlib.core; import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; import org.apache.avalon.framework.parameters.Parameters; -import org.apache.myrmidon.api.AbstractTask; -import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.interfaces.embeddor.Embeddor; import org.apache.myrmidon.interfaces.model.Project; -import org.apache.myrmidon.interfaces.workspace.Workspace; /** - * Create a new Workspace and process a build in - * that new workspace. + * Executes a target in a named build file. * * @author Peter Donald * @ant.task name="ant" */ public class AntTask - extends AbstractTask + + extends AbstractAntTask { /** * Default build file. */ private static final String DEFAULT_BUILD_FILE = "build.ant"; - /** - * If true, inherit all properties from parent Project - * If false, inherit only userProperties and those defined - * inside the ant call itself - */ - private boolean m_inheritAll; - /** * The build file which to execute. If not set defaults to * using "build.ant" in the basedir of current project. */ private File m_file; - /** - * The target to process in build file. If not specified - * will use default in specified build file. - */ - private String m_target; - /** * The "type" of the build file. By default this is null which * means the type will be determined by the build file extension. */ private String m_type; - private final ArrayList m_parameters = new ArrayList(); - - /** - * Specify whether should inherit properties in sub-build. - * - * @param inheritAll true to inherit else false - */ - public void setInheritAll( final boolean inheritAll ) - { - m_inheritAll = inheritAll; - } /** * set the build file to process. @@ -90,114 +59,21 @@ public class AntTask } /** - * set the target to process. If none is defined it will - * execute the default target of the build file + * @return The project containing the target to execute. + * @throws Exception If a problem occurred building the project. */ - public void setTarget( final String target ) - { - m_target = target; - } - - /** - * Add a parameter to processing of build file. - * - * @param param the parameter - */ - public void addParam( final AntParam param ) - { - m_parameters.add( param ); - } - - /** - * Execute the specified build, with specified parameters. - * - * @throws TaskException if an error occurs. - */ - public void execute() - throws TaskException + protected Project getProject() throws Exception { if( null == m_file ) { m_file = getContext().resolveFile( DEFAULT_BUILD_FILE ); } - final Embeddor embeddor = - (Embeddor)getContext().getService( Embeddor.class ); - - try - { - final Project project = - embeddor.createProject( m_file.toString(), - m_type, - new Parameters() ); - final Workspace workspace = - embeddor.createWorkspace( buildParameters() ); - - if( null == m_target ) - { - m_target = project.getDefaultTargetName(); - } - - workspace.executeProject( project, m_target ); - } - catch( final Exception e ) - { - throw new TaskException( e.toString(), e ); - } - } - - /** - * Build the parameters to pass to sub-project. - * These include the current tasks properties - * (if inheritall=true) and any supplied by the user. - * - * @return the created parameters - */ - private Parameters buildParameters() - throws TaskException - { - final Parameters parameters = new Parameters(); - - if( m_inheritAll ) - { - final Map properties = getContext().getProperties(); - final Iterator keys = properties.keySet().iterator(); - while( keys.hasNext() ) - { - final String key = (String)keys.next(); - final Object value = properties.get( key ); - setProperty( parameters, key, value ); - } - } - - final int size = m_parameters.size(); - for( int i = 0; i < size; i++ ) - { - final AntParam param = (AntParam)m_parameters.get( i ); - param.validate(); - final String name = param.getName(); - final String value = param.getValue().toString(); - setProperty( parameters, name, value ); - } - - return parameters; + final Project project = + getEmbeddor().createProject( m_file.toString(), + m_type, + new Parameters() ); + return project; } - /** - * Utility method to add the property into parameters object. - * - * @param parameters where to put property - * @param name the property - * @param value the value of property - * @todo allow non-string params to be passed down - */ - private void setProperty( final Parameters parameters, - final String name, - final Object value ) - { - if( !name.startsWith( "myrmidon." ) ) - { - parameters.setParameter( name, value.toString() ); - } - } } diff --git a/proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties b/proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties index 4173a8808..757580ed6 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties @@ -34,4 +34,6 @@ filetokenset.not-a-file.error=File {0} does not exist, or is not a file. filetokenset.read-tokens.error=Could not read tokens from {0}. param.noname.error=Missing name from parameter. -param.novalue.error=Missing value from parameter "{0}". \ No newline at end of file +param.novalue.error=Missing value from parameter "{0}". + +antcall.invalid-project.error=Project-reference "{0}" not found. \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java index d9587aaa9..24ee439c9 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java @@ -155,7 +155,7 @@ public class DefaultClassLoaderManager private URL[] buildClasspath( final ArrayList files ) throws MalformedURLException { - final URL[] urls = new URL[ files.size() + 1 ]; + final URL[] urls = new URL[ files.size() ]; final int count = files.size(); for( int i = 0; i < count; i++ ) { diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java index 856490754..bfc80b82a 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java @@ -214,7 +214,15 @@ public class DefaultTaskContext { checkPropertyName( name ); checkPropertyValid( name, value ); - m_contextData.put( name, value ); + + if ( value == null ) + { + m_contextData.remove( name ); + } + else + { + m_contextData.put( name, value ); + } } /** diff --git a/proposal/myrmidon/src/make/sample.ant b/proposal/myrmidon/src/make/sample.ant index f32f4e44f..43fc34434 100644 --- a/proposal/myrmidon/src/make/sample.ant +++ b/proposal/myrmidon/src/make/sample.ant @@ -279,6 +279,32 @@ Legal: