package org.codehaus.mojo.fitnesse;
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import org.apache.maven.doxia.siterenderer.Renderer;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.reporting.MavenReportException;
/**
* Generates a <a href="http://fitnesse.org">FitNesse</a> report from a FitNesse web server. The generated report is an
* external report generated FitNesse itself. If the project use Clover for code coverage and if FitNesse has clover
* dependency (ie use the <i>ArtifactId-Version-clover.jar</i>), the code executed during the FitNesse execution (phase
* integration-test) will be had to the unit-test code coverage. See the <a href="examples/multiproject.html">clover
* example</a>.
*
* @goal fitnesse
* @aggregator
*/
public class FitnesseReportMojo
extends AbstractMavenReport
{
/**
* The Maven project instance for the executing project.
* <p>
* Note: This is passed by Maven and must not be configured by the user.
* </p>
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* Report output directory. It should be defined in the reporting section of the pom.
*
* @parameter expression="${project.build.directory}/generated-site/xdoc/fitnesse"
* @required
*/
private File xmlOutputDirectory;
/**
* The directory where the Fitnesse report will be generated.
* @parameter expression="${project.reporting.outputDirectory}/fitnesse"
* @required
*/
private File outputDirectory;
/**
* The directory where the Fitnesse report has be generated. It must be defined when it's not the default value
* (${project.build.directory}/fitnesse. It's the case for exemple with the clover plugin (that use
* ${project.build.directory}/clover/fitnesse).
*
* @parameter
*/
private File fitnesseOutputDirectory;
/**
* @parameter expression="${project.build.directory}"
* @required
*/
private File workingDir;
/**
* <p>
* Note: This is passed by Maven and must not be configured by the user.
* </p>
*
* @component
*/
private Renderer siteRenderer;
/**
* @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale)
*/
protected void executeReport( Locale pArg0 )
throws MavenReportException
{
// Ensure the output directory exists
getLog().info( "outputDirectory="+outputDirectory );
this.outputDirectory.mkdirs();
this.xmlOutputDirectory.mkdirs();
checkReport();
createReport();
createIndex();
copyAllResources( this.outputDirectory, getLog(), getClass().getClassLoader() );
getLog().info( "Fitnesse report finished" );
}
public static void copyAllResources( File pToDir, Log pLog, ClassLoader pLoader )
throws MavenReportException
{
copyResource( pToDir, "fitnesse.js", pLog, pLoader );
copyResource( pToDir, "fitnesse_base.css", pLog, pLoader );
copyResource( pToDir, "fitnesse_print.css", pLog, pLoader );
// images
new File( pToDir + "/images" ).mkdir();
copyResource( pToDir, "images/collapsableClosed.gif", pLog, pLoader );
copyResource( pToDir, "images/collapsableOpen.gif", pLog, pLoader );
copyResource( pToDir, "images/FitNesseLogo.gif", pLog, pLoader );
copyResource( pToDir, "images/FitNesseLogoMedium.jpg", pLog, pLoader );
copyResource( pToDir, "images/folder.gif", pLog, pLoader );
copyResource( pToDir, "images/importedPage.jpg", pLog, pLoader );
copyResource( pToDir, "images/virtualPage.jpg", pLog, pLoader );
new File( pToDir + "/images/executionStatus" ).mkdir();
copyResource( pToDir, "images/executionStatus/error.gif", pLog, pLoader );
copyResource( pToDir, "images/executionStatus/ok.gif", pLog, pLoader );
copyResource( pToDir, "images/executionStatus/output.gif", pLog, pLoader );
}
private static void copyResource( File pToDir, String pFileName, Log pLog, ClassLoader pLoader )
throws MavenReportException
{
File tDest = new File( pToDir + "/" + pFileName );
copyFile( pLog, pLoader.getResourceAsStream( "fitnesse_resources/" + pFileName ), tDest );
}
private void createReport()
throws MavenReportException
{
File curFile;
File[] tFileArray = getFitnesseReportDir().listFiles();
for ( int i = 0; i < tFileArray.length; i++ )
{
curFile = tFileArray[i];
if ( !curFile.exists() )
{
throw new MavenReportException( "Unable to find Fitnesse report for server " + curFile );
}
if ( curFile.getName().startsWith( FitnesseRunnerMojo.FITNESSE_RESULT_PREFIX ) )
{
File tDestFile = new File( outputDirectory + "/" + curFile.getName() );
try
{
copyFile( getLog(), new FileInputStream( curFile ), tDestFile );
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to create File [" + curFile.getAbsolutePath() + "].", e );
}
}
}
}
void checkReport()
throws MavenReportException
{
if ( getFitnesseReportDir().listFiles().length == 0 )
{
getLog().error(
"Your should configure at least one Fitnesse server. "
+ "Check your Fitnesse plugin configuration." );
throw new MavenReportException( "Your should configure at least one Fitnesse server. "
+ "Check your Fitnesse plugin configuration." );
}
}
static void copyFile( Log pLogger, InputStream pIn, File pDestFile )
throws MavenReportException
{
FileOutputStream tOut = null;
try
{
if ( !pDestFile.exists() )
{
pDestFile.createNewFile();
}
tOut = new FileOutputStream( pDestFile );
byte[] tBuff = new byte[100];
int tRead = pIn.read( tBuff );
while ( tRead >= 0 )
{
tOut.write( tBuff, 0, tRead );
tRead = pIn.read( tBuff );
}
pLogger.debug( "File copied to " + pDestFile );
pLogger.debug( "File exist " + pDestFile.exists() );
}
catch ( FileNotFoundException e )
{
throw new MavenReportException( "File doesn't exist", e );
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to write into file...", e );
}
finally
{
try
{
if ( tOut != null )
{
tOut.close();
}
if ( pIn != null )
{
pIn.close();
}
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to close report file report...", e );
}
}
}
File getFitnesseReportDir()
throws MavenReportException
{
File tExecutionFile;
if ( fitnesseOutputDirectory != null )
{
getLog().info( "Using the specified fitnesse outpout directory " + fitnesseOutputDirectory );
tExecutionFile = fitnesseOutputDirectory;
}
else
{
getLog().debug( "Trying to find the fitnesse default dir..." );
tExecutionFile = new File( workingDir + "/fitnesse" );
if ( !tExecutionFile.exists() )
{
getLog().info( "Fitnesse default report not found, " + tExecutionFile );
getLog().debug( "Trying to find the fitnesse with clover dir..." );
tExecutionFile = new File( workingDir + "/clover/fitnesse" );
}
}
FilenameFilter filterSvnDirectory = new FilenameFilter()
{
public boolean accept( File dir, String name )
{
return !name.equals( ".svn" );
}
};
if ( !tExecutionFile.exists() || !tExecutionFile.isDirectory() || tExecutionFile.list(filterSvnDirectory).length == 0 )
{
String tError =
"Can't find any report in the following folder: [" + fitnesseOutputDirectory.getAbsolutePath() + "], ["
+ new File( workingDir + "/fitnesse" ).getAbsolutePath() + "] or ["
+ tExecutionFile.getAbsolutePath() + "]";
throw new MavenReportException( tError );
}
else
{
return tExecutionFile;
}
}
void createIndex()
throws MavenReportException
{
if ( outputDirectory.listFiles().length > 1 )
{
File tIndex = new File( this.xmlOutputDirectory + "/index.xml" );
FileWriter tWriter = null;
int tNbPage = 0;
try
{
tIndex.createNewFile();
tWriter = new FileWriter( tIndex );
tWriter.write( "<document>\n" );
tWriter.write( " <properties>\n" );
tWriter.write( " <title>maven-fitnesse-plugin - execution report</title>\n" );
tWriter.write( " </properties>\n" );
tWriter.write( " <body>\n" );
tWriter.write( "<section name=\"List of the Fitnesse Pages:\">\n" );
tWriter.write( "<ul>\n" );
FitnessePage curChil;
File[] tFileArray = outputDirectory.listFiles();
for ( int i = 0; i < tFileArray.length; i++ )
{
curChil = new FitnessePage( tFileArray[i] );
if ( curChil.isFitnessePageResult() )
{
tWriter.write( "<li><a href=\"" + curChil.getName() + "\">" + curChil.getFitnessePageName()
+ ".html</a></li>\n" );
tNbPage++;
}
}
tWriter.write( "</ul>\n" );
tWriter.write( "</section>\n" );
tWriter.write( "</body>\n" );
tWriter.write( "</document>\n" );
tWriter.flush();
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to create index file " + tIndex.getAbsolutePath(), e );
}
finally
{
if ( tWriter != null )
{
try
{
tWriter.close();
}
catch ( IOException e )
{
throw new MavenReportException( "Unable to close index file " + tIndex.getAbsolutePath(), e );
}
}
}
if ( tNbPage == 1 )
{
tIndex.delete();
}
}
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
*/
protected String getOutputDirectory()
{
return this.outputDirectory.getAbsoluteFile().toString();
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getProject()
*/
protected MavenProject getProject()
{
return project;
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
*/
protected Renderer getSiteRenderer()
{
return this.siteRenderer;
}
/**
* @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
*/
public String getDescription( Locale locale )
{
return "Fitnesse report";
}
/**
* @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
*/
public String getName( Locale locale )
{
return "Fitnesse report";
}
/**
* @see org.apache.maven.reporting.MavenReport#getOutputName()
*/
public String getOutputName()
{
File tDir;
FitnessePage curChild = null, tGoodFile = null;
try
{
tDir = getFitnesseReportDir();
String[] tChildren = tDir.list();
int tNbPage = 0;
for ( int i = 0; i < tChildren.length; i++ )
{
curChild = new FitnessePage( new File( tChildren[i] ) );
if ( curChild.isFitnessePageResult() )
{
tNbPage++;
tGoodFile = curChild;
}
}
if ( tNbPage == 1 )
{
return "fitnesse/" + FitnesseRunnerMojo.FITNESSE_RESULT_PREFIX + "_" + tGoodFile.getFitnessePageName();
}
else
{
return "fitnesse/index";
}
}
catch ( MavenReportException e )
{
throw new RuntimeException( e );
}
}
/**
* Always return true as we're using the report generated by Clover rather than creating our own report.
*
* @return true
*/
public boolean isExternalReport()
{
return true;
}
void setWorkingDir( File pWorkingDir )
{
workingDir = pWorkingDir;
}
void setFitnesseOutputDirectory( File pFitnesseOutputDirectory )
{
fitnesseOutputDirectory = pFitnesseOutputDirectory;
}
void setOutputDirectory( File pOutputDirectory )
{
outputDirectory = pOutputDirectory;
}
public void setXmlOutputDirectory( File xmlOutputDirectory )
{
this.xmlOutputDirectory = xmlOutputDirectory;
}
}