package org.ops4j.pax.construct.clone;
/*
* Copyright 2007 Stuart McCulloch
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.ops4j.pax.construct.util.StreamFactory;
/**
* Builder implementation for Pax-Construct based build scripts
*/
public class PaxScriptImpl
implements PaxScript
{
/**
* Sequence of Pax-Construct commands
*/
private final List m_commands;
/**
* Create a new Pax-Construct script builder
*/
public PaxScriptImpl()
{
m_commands = new ArrayList();
}
/**
* @return sequence of pax commands
*/
List getCommands()
{
return m_commands;
}
/**
* {@inheritDoc}
*/
public PaxCommandBuilder call( String command )
{
return new PaxCommand( command );
}
/**
* Represents a simple command flag, such as -x or -Dy
*/
private class Flag
{
/**
* Flag name
*/
private String m_flag;
/**
* @param flag name of the flag
*/
public Flag( String flag )
{
m_flag = flag;
}
/**
* {@inheritDoc}
*/
public String toString()
{
return '-' + m_flag;
}
}
/**
* Represents a simple command option, such as -w foo or -Dz=bar
*/
private class Option extends Flag
{
/**
* Option separator
*/
private char m_separator;
/**
* Specified value
*/
private String m_value;
/**
* @param option name of the option
* @param separator separator between option and value
* @param value specified value
*/
public Option( String option, char separator, String value )
{
super( option );
m_separator = separator;
m_value = value;
}
/**
* {@inheritDoc}
*/
public String toString()
{
if( ' ' == m_separator )
{
// just protect the value (works on Windows and UNIX)
return super.toString() + m_separator + '\"' + m_value + '\"';
}
// protect entire option (works on Windows and UNIX)
return '\"' + super.toString() + m_separator + m_value + '\"';
}
}
/**
* Builder implementation for Pax-Construct commands
*/
class PaxCommand
implements PaxCommandBuilder
{
/**
* Name of the Pax-Construct script
*/
private final String m_name;
/**
* Sequence of Pax-Construct options
*/
private final List m_paxOptions;
/**
* Sequence of Maven specific options
*/
private final List m_mvnOptions;
/**
* Target directory where the command should be run
*/
private String m_targetDir;
/**
* @param command name of the Pax-Construct command
*/
public PaxCommand( String command )
{
m_name = command;
m_mvnOptions = new ArrayList();
m_paxOptions = new ArrayList();
m_targetDir = "";
getCommands().add( this );
}
/**
* @return command name
*/
String getName()
{
return m_name;
}
/**
* @return sequence of maven options
*/
List getMvnOptions()
{
return m_mvnOptions;
}
/**
* @return sequence of pax options
*/
List getPaxOptions()
{
return m_paxOptions;
}
/**
* @return target directory for this command
*/
String getTargetDir()
{
return m_targetDir;
}
/**
* @param targetDir new target directory
*/
void setTargetDir( String targetDir )
{
m_targetDir = targetDir;
}
/**
* {@inheritDoc}
*/
public PaxCommandBuilder flag( char flag )
{
m_paxOptions.add( new Flag( "" + flag ) );
return this;
}
/**
* {@inheritDoc}
*/
public PaxCommandBuilder option( char option, String value )
{
m_paxOptions.add( new Option( "" + option, ' ', value ) );
return this;
}
/**
* {@inheritDoc}
*/
public MavenOptionBuilder maven()
{
return new MavenOption();
}
/**
* Builder implementation for Maven specific options
*/
class MavenOption
implements MavenOptionBuilder
{
/**
* {@inheritDoc}
*/
public MavenOptionBuilder flag( String flag )
{
getMvnOptions().add( new Flag( 'D' + flag ) );
return this;
}
/**
* {@inheritDoc}
*/
public MavenOptionBuilder option( String option, String value )
{
if( "targetDirectory".equals( option ) )
{
setTargetDir( value );
}
getMvnOptions().add( new Option( 'D' + option, '=', value ) );
return this;
}
}
/**
* {@inheritDoc}
*/
public String toString()
{
StringBuffer buf = new StringBuffer( "pax-" + m_name );
for( Iterator i = m_paxOptions.iterator(); i.hasNext(); )
{
buf.append( ' ' );
buf.append( i.next() );
}
// need option separator?
if( !m_mvnOptions.isEmpty() )
{
buf.append( " --" );
}
for( Iterator i = m_mvnOptions.iterator(); i.hasNext(); )
{
buf.append( ' ' );
buf.append( i.next() );
}
return buf.toString();
}
}
/**
* Sort Pax-Construct commands by their target directory, so projects are created before they are used
*/
static class ByTargetDir
implements Comparator
{
/**
* {@inheritDoc}
*/
public int compare( Object lhs, Object rhs )
{
if( lhs instanceof PaxCommand )
{
if( rhs instanceof PaxCommand )
{
return compare( (PaxCommand) lhs, (PaxCommand) rhs );
}
return 1;
}
else if( rhs instanceof PaxCommand )
{
return -1;
}
return 0;
}
/**
* Compare two Pax commands to decide which should go first
*
* @param lhsCommand Pax command
* @param rhsCommand Pax command
* @return -1 (lhs before rhs), 0 (lhs same time as rhs), or 1 (lhs after rhs)
*/
private int compare( PaxCommand lhsCommand, PaxCommand rhsCommand )
{
boolean lhsIsImport = IMPORT_BUNDLE.equals( lhsCommand.getName() );
boolean rhsIsImport = IMPORT_BUNDLE.equals( rhsCommand.getName() );
if( lhsIsImport && !rhsIsImport )
{
return 1;
}
else if( !lhsIsImport && rhsIsImport )
{
return -1;
}
else
{
return lhsCommand.getTargetDir().compareTo( rhsCommand.getTargetDir() );
}
}
}
/**
* {@inheritDoc}
*/
public void write( String title, File scriptFile, List setupCommands )
throws IOException
{
// Sort so projects are created before their bundles
Collections.sort( m_commands, new ByTargetDir() );
scriptFile.getParentFile().mkdirs();
BufferedWriter writer = new BufferedWriter( StreamFactory.newPlatformWriter( scriptFile ) );
boolean isBatchFile = scriptFile.getName().endsWith( ".bat" );
writeSnippet( writer, isBatchFile, "header" );
writer.newLine();
writeMessage( writer, "INSTALLING ARCHETYPES CLONED FROM [" + title + ']' );
writer.newLine();
writeCommands( writer, isBatchFile, setupCommands );
writer.newLine();
writeSnippet( writer, isBatchFile, "postsetup" );
writer.newLine();
writeMessage( writer, "RECREATING MAVEN PROJECT BASED ON [" + title + ']' );
writer.newLine();
writeCommands( writer, isBatchFile, m_commands );
IOUtil.close( writer );
}
/**
* Write script snippet
*
* @param writer script writer
* @param isBatchFile true if it's a batch file, false if it's a shell script
* @param snippet name of the snippet
* @throws IOException
*/
private static void writeSnippet( BufferedWriter writer, boolean isBatchFile, String snippet )
throws IOException
{
final String resourceName;
if( isBatchFile )
{
resourceName = "/snippets/" + snippet + ".bat";
}
else
{
resourceName = "/snippets/" + snippet + ".sh";
}
String snippetText = IOUtil.toString( PaxScriptImpl.class.getResourceAsStream( resourceName ) );
writer.write( snippetText );
}
/**
* @param writer script writer
* @param message the message
* @throws IOException
*/
private static void writeMessage( BufferedWriter writer, String message )
throws IOException
{
String border = "++++" + message.replaceAll( ".", "+" );
writer.write( "echo " + border );
writer.newLine();
writer.write( "echo + " + message + " +" );
writer.newLine();
writer.write( "echo " + border );
writer.newLine();
}
/**
* Write sequence of commands
*
* @param writer script writer
* @param isBatchFile true if it's a batch file, false if it's a shell script
* @param commands sequence of commands
* @throws IOException
*/
private static void writeCommands( BufferedWriter writer, boolean isBatchFile, List commands )
throws IOException
{
boolean standalone = ( commands.size() == 1 );
for( Iterator i = commands.iterator(); i.hasNext(); )
{
String cmd = i.next().toString();
if( isBatchFile )
{
// need this in batch files
writer.write( "call " );
// fix variable references to use %FOO% not ${FOO}
cmd = cmd.replaceAll( "\\$\\{([^}]*)\\}", "%$1%" );
}
if( standalone )
{
// allow customization
if( isBatchFile )
{
cmd = StringUtils.replace( cmd, " -- ", " %1 %2 %3 %4 %5 %6 %7 %8 %9 -- " );
}
else
{
cmd = StringUtils.replace( cmd, " -- ", " \"$@\" -- " );
}
}
writer.write( cmd );
writer.newLine();
}
}
}