package com.arrizza.ant.taskdefs;
/**
* com.optiron.ant.ConcatenateFiles
* Copyright (c) 2001 Optiron, Inc. All Rights Reserved.
*
* This software is licenced under the Apache Software License. See:
*
* http://www.apache.org/LICENSE.txt
*
* for the license contents.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
/**
* This class implements a new task for Ant: ConcatenateFiles. As the name
* states, the purpose of this task is to concatenate two or more files into a
* single file with a new name. You can also subsitute a message for one or
* both of the 'begin' and 'end' files.
*
* Note that this will automatically overwrite the destFile until we create
* some forceOverride methods.
*
* <p>Arguments for this task:</p>
* <ul>
* <li>file: new filename
* <li>fileset: set of files that are concatenated for the new file
* </ul>
*
* <p>The next two arguments are mutually exclusive:</p>
* <ul>
* <li>beginfile: file that begins the new file
* <li>beginmessage: message that begins the new file
* </ul>
*
* <p>The next two arguments are mutually exclusive:</p>
* <ul>
* <li>endfile: file that ends the new file
* <li>endmessage: message that ends the new file
* </ul>
*
* <p>Usage:</p>
* <p>First define the taskdef:</p>
* <pre>
* <taskdef name="concatenate"
* classname="com.optiron.ant.ConcatenateFiles"/>
* </pre>
* <p>Now define some actions:</p>
*
* <p>Concatenate all the files beginning with 'Plumbing' in the base
* directory to a file called <tt>concat.txt</tt>:</p>
* <code>
* <concatenate file="concat.txt">
* <fileset dir="${basedir}" includes="Plumbing*.*"/>
* </concatenate>
* </code>
* <p>Concatenate all XML files in the <code>deployment</code> subdirectory into
* a file called <code>main.xml</code>:
* <code>
* <concatenate file="main.xml">
* <fileset dir="${basedir}/deployment" includes="**\/xml"/>
* </concatenate>
* </code>
*
* <p>More about Ant:
* <a href="http://jakarta.apache.org/ant/">http://jakarta.apache.org/ant/</a></p>
*
* @author Chris Winters <a href="mailto:cwinters@optiron.com">cwinters@optiron.com</a>
* @version $Revision: 1.3 $
*/
public class ConcatenateFiles
extends Task
{
protected File file = null;
protected File destFile = null;
protected File beginFile = null;
protected File endFile = null;
protected String beginMessage = null;
protected String endMessage = null;
protected List filesets = new ArrayList();
protected int verbosity = Project.MSG_VERBOSE;
protected boolean forceBuild = false;
public void setFile( File _set )
{
file = _set;
}
public void setBeginfile( File _set )
{
beginFile = _set;
}
public void setEndfile( File _set )
{
endFile = _set;
}
public void setBeginmessage( String _set )
{
beginMessage = _set;
}
public void setEndmessage( String _set )
{
endMessage = _set;
}
public void addFileset( FileSet set )
{
filesets.add( set );
}
public void setVerbose( boolean _set )
{
if ( _set )
{
verbosity = Project.MSG_INFO;
}
else
{
verbosity = Project.MSG_VERBOSE;
}
}
public void setDepends( boolean _set )
{
this.forceBuild = !_set;
}
/**
* Perform the actual action. First validate the parameters passed
* to the task to ensure everything is sane, then open up the
* output file. Next do the beginning file/message, process the
* fileset and then do the ending file/message.
*
* @exception BuildException for any IO problems (can't read file,
* can't open file, can't write to file, etc.)
*/
public void execute() //throws BuildException
{
// Ensure everything is set correctly
validateAttributes();
FileWriter out = null;
try
{
destFile = new File( file.getAbsolutePath() );
if (forceBuild || outOfDate())
processAllFiles(out);
else
log("No files are out-of-date.", verbosity);
}
catch ( IOException ioe )
{
throw new BuildException( "Error with the filesystem: " + ioe.getMessage() );
}
finally
{
try
{
if ( out != null )
{
out.close();
}
}
catch ( IOException ioe )
{
throw new BuildException( "Cannot close output buffer! Error: " + ioe.getMessage() );
}
}
}
//------------------------------------
//-- private from here on
//------------------------------------
//------------------------------------
private boolean outOfDate()
throws IOException
{
long destTimeStamp = 0;
if ( destFile.exists() )
destTimeStamp = destFile.lastModified();
if (destTimeStamp == 0)
{
log( "Destination file " + destFile.getCanonicalPath() + " does not exist. building...", verbosity );
return true;
}
boolean doit = false;
if ( beginFile != null )
{
if (beginFile.lastModified() > destTimeStamp)
{
log( "Beginning file " + beginFile.getCanonicalPath() + " is out-of-date. building...", verbosity );
doit = true;
}
}
if ( endFile != null )
{
if (endFile.lastModified() > destTimeStamp)
{
log( "Ending file " + endFile.getCanonicalPath() + " is out-of-date. building...", verbosity );
doit = true;
}
}
// Now do the filesets specified
Iterator fsi = filesets.iterator();
while ( fsi.hasNext() )
{
FileSet fs = (FileSet)fsi.next();
DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
String[] srcFiles = ds.getIncludedFiles();
File baseDir = ds.getBasedir().getAbsoluteFile();
for ( int i = 0; i < srcFiles.length; i++ )
{
File readFile = new File( baseDir, srcFiles[i] );
if (readFile.lastModified() > destTimeStamp)
{
doit = true;
log( "Fileset file " + readFile.getCanonicalPath() + " is out-of-date. building...", verbosity );
}
}
}
return doit;
}
//------------------------------------------------
private void processAllFiles(FileWriter out)
throws IOException
{
// Open up the new file and a writer to it.
if ( destFile.exists() )
{
log( "File " + destFile.getCanonicalPath() + " exists; removing.", verbosity );
destFile.delete();
destFile.createNewFile();
}
out = new FileWriter( destFile.getAbsolutePath() );
// If the beginFile is defined, contatenate it
if ( beginFile != null )
{
concatenate( out, beginFile );
log( "Beginning file " + beginFile.getCanonicalPath() + " ok", verbosity );
}
if ( beginMessage != null )
{
concatenate( out, beginMessage );
log( "Beginning message ok", verbosity );
}
Iterator fsi = filesets.iterator();
while ( fsi.hasNext() )
{
FileSet fs = (FileSet)fsi.next();
DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
String[] srcFiles = ds.getIncludedFiles();
File baseDir = ds.getBasedir().getAbsoluteFile();
for ( int i = 0; i < srcFiles.length; i++ )
{
File readFile = new File( baseDir, srcFiles[i] );
concatenate( out, readFile );
log( "Fileset file " + readFile.getCanonicalPath() + " ok", verbosity );
}
}
// And if the endFile is defined, do it
if ( endFile != null )
{
concatenate( out, endFile );
log( "Ending file " + endFile.getCanonicalPath() + " ok", verbosity );
}
if ( endMessage != null )
{
concatenate( out, endMessage );
log( "Ending message ok", verbosity );
}
log( "Created new file (" + destFile.getCanonicalPath() + ") successfully" );
out.close();
}
/**
* Ensure we have the right attributes. Failure conditions are:
*
* <ul>
* <li>destination file is not specified</li>
* <li>both 'beginmessage' and 'beginfile' are specified</li>
* <li>both 'endmessage' and 'endfile' are specified</li>
* <li>no messages or files are specified at all</li>
* </ul>
*
* @throws BuildException if one of the specifications is not met.
*/
protected void validateAttributes() //throws BuildException
{
if ( file == null )
{
throw new BuildException("You must specify a destfile." );
}
if ( beginMessage != null && beginFile != null )
{
throw new BuildException( "You cannot specify both 'beginmessage' and 'beginfile'" );
}
if ( endMessage != null && endFile != null )
{
throw new BuildException( "You cannot specify both 'endmessage' and 'endfile'" );
}
boolean hasMessage = ( beginMessage != null || endMessage != null );
boolean hasFile = ( beginFile != null || endFile != null || filesets.size() > 0 );
if ( ! hasMessage && ! hasFile )
{
throw new BuildException( "You must specify one or more messages or files." );
}
}
/**
* Concatenate two text files
*
* @param to file object appending to
* @param from file whose contents we're appending
* @throws IOException if we can't read the file or if the actual
* write fails
*/
private static void concatenate( FileWriter to, File from )
throws IOException
{
BufferedReader in = new BufferedReader( new FileReader( from ) );
String inBuf = new String();
StringBuffer contents = new StringBuffer();
while ( ( inBuf = in.readLine() ) != null )
{
contents.append( inBuf + "\r\n" );
}
in.close();
concatenate( to, contents.toString() );
}
/**
* Concatenate a string to a text file
*
* @param to file object appending to
* @param from string we're appending
* @throws IOException if the write fails
*/
private static void concatenate( FileWriter to, String from )
throws IOException
{
to.write( from );
}
}
|