blob: 35898a4155cc205951ce2e9686fcd54163d6050a [file] [log] [blame]
/*
* 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 file.
*/
package org.apache.ant.project;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import org.apache.ant.AntException;
import org.apache.ant.configuration.Configuration;
import org.apache.ant.configuration.ConfigurationBuilder;
import org.apache.ant.util.Condition;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.ConfigurationException;
import org.apache.avalon.util.StringUtil;
import org.apache.log.Logger;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Default implementation to construct project from a build file.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultProjectBuilder
extends AbstractLoggable
implements ProjectBuilder
{
protected ConfigurationBuilder m_builder;
public DefaultProjectBuilder()
{
m_builder = new ConfigurationBuilder();
}
/**
* build a project from file.
*
* @param source the source
* @return the constructed Project
* @exception IOException if an error occurs
* @exception AntException if an error occurs
*/
public Project build( final File projectFile )
throws IOException, AntException
{
try
{
final String location = projectFile.getCanonicalFile().toString();
final Configuration configuration = buildConfiguration( location );
return build( projectFile, configuration );
}
catch( final ConfigurationException ce )
{
throw new AntException( "ConfigurationException: " + ce.getMessage(), ce );
}
}
/**
* Utility method to build a Configuration tree from a source.
* Overide this in sub-classes if you want to provide extra
* functionality (ie xslt/css).
*
* @param location the location
* @return the created Configuration
* @exception AntException if an error occurs
* @exception IOException if an error occurs
*/
protected Configuration buildConfiguration( final String location )
throws AntException, IOException, ConfigurationException
{
try
{
return (Configuration)m_builder.build( location );
}
catch( final SAXException se )
{
throw new AntException( "SAXEception: " + se.getMessage(), se );
}
}
/**
* build project from configuration.
*
* @param file the file from which configuration was loaded
* @param configuration the configuration loaded
* @return the created Project
* @exception IOException if an error occurs
* @exception AntException if an error occurs
* @exception ConfigurationException if an error occurs
*/
protected Project build( final File file, final Configuration configuration )
throws IOException, AntException, ConfigurationException
{
if( !configuration.getName().equals("project") )
{
throw new AntException( "Project file must be enclosed in project element" );
}
//get project-level attributes
final String baseDirectoryName = configuration.getAttribute( "basedir" );
final String defaultTarget = configuration.getAttribute( "default" );
final String projectName = configuration.getAttribute( "name" );
//determine base directory for project
final File baseDirectory =
(new File( file.getParentFile(), baseDirectoryName )).getAbsoluteFile();
getLogger().debug( "Project " + projectName + " base directory: " + baseDirectory );
//create project and ...
final DefaultProject project = new DefaultProject();
project.setDefaultTargetName( defaultTarget );
//setup basic context of project
final TaskletContext context = project.getContext();
context.setProperty( TaskletContext.BASE_DIRECTORY, baseDirectory );
context.setProperty( Project.PROJECT_FILE, file );
context.setProperty( Project.PROJECT, projectName );
//build using all top-level attributes
buildTopLevelProject( project, configuration );
return project;
}
/**
* Handle all top level elements in configuration.
*
* @param project the project
* @param configuration the Configuration
* @exception AntException if an error occurs
*/
protected void buildTopLevelProject( final DefaultProject project,
final Configuration configuration )
throws AntException
{
final Iterator elements = configuration.getChildren();
while( elements.hasNext() )
{
final Configuration element = (Configuration)elements.next();
final String name = element.getName();
//handle individual elements
if( name.equals( "target" ) ) buildTarget( project, element );
else if( name.equals( "property" ) ) buildImplicitTask( project, element );
else
{
throw new AntException( "Unknown top-level element " + name +
" at " + element.getLocation() );
}
}
}
/**
* Build a target from configuration.
*
* @param project the project
* @param task the Configuration
*/
protected void buildTarget( final DefaultProject project, final Configuration target )
{
final String name = target.getAttribute( "name", null );
final String depends = target.getAttribute( "depends", null );
final String ifCondition = target.getAttribute( "if", null );
final String unlessCondition = target.getAttribute( "unless", null );
if( null == name )
{
throw new AntException( "Discovered un-named target at " +
target.getLocation() );
}
getLogger().debug( "Parsing target: " + name );
if( null != ifCondition && null != unlessCondition )
{
throw new AntException( "Discovered invalid target that has both a if and " +
"unless condition at " + target.getLocation() );
}
Condition condition = null;
if( null != ifCondition )
{
getLogger().debug( "Target if condition: " + ifCondition );
condition = new Condition( true, ifCondition );
}
else if( null != unlessCondition )
{
getLogger().debug( "Target unless condition: " + unlessCondition );
condition = new Condition( false, unlessCondition );
}
final DefaultTarget defaultTarget = new DefaultTarget( condition );
//apply depends attribute
if( null != depends )
{
final String[] elements = StringUtil.splitString( depends, "," );
for( int i = 0; i < elements.length; i++ )
{
final String dependency = elements[ i ].trim();
if( 0 == dependency.length() )
{
throw new AntException( "Discovered empty dependency in target " +
target.getName() + " at " + target.getLocation() );
}
getLogger().debug( "Target dependency: " + dependency );
defaultTarget.addDependency( dependency );
}
}
//add all the targets from element
final Iterator tasks = target.getChildren();
while( tasks.hasNext() )
{
final Configuration task = (Configuration)tasks.next();
getLogger().debug( "Parsed task: " + task.getName() );
defaultTarget.addTask( task );
}
//add target to project
project.addTarget( name, defaultTarget );
}
/**
* Create an implict task from configuration
*
* @param project the project
* @param task the configuration
*/
protected void buildImplicitTask( final DefaultProject project, final Configuration task )
{
DefaultTarget target = (DefaultTarget)project.getImplicitTarget();
if( null == target )
{
target = new DefaultTarget();
project.setImplicitTarget( target );
}
getLogger().debug( "Parsed implicit task: " + task.getName() );
target.addTask( task );
}
}