Jalopy source code formatting - fix a bunch of pmd and checkstyle warnings

git-svn-id: https://svn.apache.org/repos/asf/maven/maven-1/plugins/trunk@370221 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
ltheussl committed 2006-01-18 19:12:42 +00:00
1 parent 6328abca7c
commit b8079e792e
32 files changed
+2352 -1903

No files matched your search

@@ -19,22 +19,26 @@ package org.apache.maven.changelog;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
// maven imports
import org.apache.maven.util.AsyncStreamReader;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// maven imports
import org.apache.maven.util.AsyncStreamReader;
import org.apache.tools.ant.taskdefs.Execute;
// ant imports
import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.types.Commandline;
/**
@@ -48,413 +52,447 @@ import org.apache.tools.ant.types.Commandline;
* @author <a href="mailto:bodewig@apache.org">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
* @version
* @version
* $Id$
*/
public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator, ExecuteStreamHandler
public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
ExecuteStreamHandler
{
/**
* The working directory.
*/
protected File base;
/** Log */
private static final Log LOG =
LogFactory.getLog( AbstractChangeLogGenerator.class );
/**
* Reference to the enclosing ChangeLog instance - used to obtain
* any necessary configuration information.
*/
protected ChangeLog changeLogExecutor;
/**
* The working directory.
*/
protected File base;
/**
* The parser that takes the log output and transforms it into a
* collection of ChangeLogEntry's.
*/
protected ChangeLogParser clParser;
/**
* Reference to the enclosing ChangeLog instance - used to obtain
* any necessary configuration information.
*/
protected ChangeLog changeLogExecutor;
/** The connection string from the project */
private String connection;
/** The log type (range, date, or tag). */
protected String type;
/**
* The parser that takes the log output and transforms it into a
* collection of ChangeLogEntry's.
*/
protected ChangeLogParser clParser;
/**
* The date range command line argument.
*/
protected String dateRange;
/** The tag command line argument. */
protected String tag;
/** Represents when this log starts (for the report). */
protected String logStart = "";
/** Represents when this log ends (for the report). */
protected String logEnd = "";
/** The connection string from the project */
private String connection;
/**
* The collection of ChangeLogEntry's returned from clParser.
*/
protected Collection entries;
/** The log type (range, date, or tag). */
protected String type;
/**
* Stderr stream eater.
*/
protected AsyncStreamReader errorReader;
/**
* The date range command line argument.
*/
protected String dateRange;
/**
* The scm process input stream.
*/
protected InputStream in;
/** The tag command line argument. */
protected String tag;
/**
* The comment format string used in interrogating the RCS.
*/
protected String commentFormat;
/** Represents when this log starts (for the report). */
protected String logStart = "";
/** Log */
private static final Log LOG = LogFactory.getLog(AbstractChangeLogGenerator.class);
/** Represents when this log ends (for the report). */
protected String logEnd = "";
/**
* Initialize the generator from the changelog controller.
*
* @param changeLog The invoking controller (useful for logging)
* @see ChangeLogGenerator#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
{
changeLogExecutor = changeLog;
/**
* The collection of ChangeLogEntry's returned from clParser.
*/
protected Collection entries;
base = changeLogExecutor.getBasedir();
type = changeLogExecutor.getType();
if (type.equalsIgnoreCase("tag"))
/**
* Stderr stream eater.
*/
protected AsyncStreamReader errorReader;
/**
* The scm process input stream.
*/
protected InputStream in;
/**
* The comment format string used in interrogating the RCS.
*/
protected String commentFormat;
/**
* Initialize the generator from the changelog controller.
*
* @param changeLog The invoking controller (useful for logging)
* @see ChangeLogGenerator#init(ChangeLog)
*/
public void init( ChangeLog changeLog )
{
tag = getScmTagArgument(changeLogExecutor.getMarkerStart(), changeLogExecutor.getMarkerEnd());
logStart = changeLogExecutor.getMarkerStart();
logEnd = (changeLogExecutor.getMarkerEnd() == null) ? "" : changeLogExecutor.getMarkerEnd();
}
else if (type.equalsIgnoreCase("date"))
{
setDateRangeFromAbsoluteDate(changeLogExecutor.getMarkerStart(), changeLogExecutor.getMarkerEnd());
}
else // type == "range" (the default)
{
// This lets the user 'not' set a limit on the log command. We
// need this cuz Subversion doesn't currently support date
// commands on web-based repositories, so it would be nice to
// let the user still use the changelog plugin.
if (changeLogExecutor.getRange() != null && changeLogExecutor.getRange().length() != 0)
changeLogExecutor = changeLog;
base = changeLogExecutor.getBasedir();
type = changeLogExecutor.getType();
if ( type.equalsIgnoreCase( "tag" ) )
{
setDateRange(changeLogExecutor.getRange());
tag = getScmTagArgument( changeLogExecutor.getMarkerStart(),
changeLogExecutor.getMarkerEnd() );
logStart = changeLogExecutor.getMarkerStart();
logEnd =
( changeLogExecutor.getMarkerEnd() == null ) ? ""
: changeLogExecutor
.getMarkerEnd();
}
else if ( type.equalsIgnoreCase( "date" ) )
{
setDateRangeFromAbsoluteDate( changeLogExecutor.getMarkerStart(),
changeLogExecutor.getMarkerEnd() );
}
else // type == "range" (the default)
{
// This lets the user 'not' set a limit on the log command. We
// need this cuz Subversion doesn't currently support date
// commands on web-based repositories, so it would be nice to
// let the user still use the changelog plugin.
if ( ( changeLogExecutor.getRange() != null )
&& ( changeLogExecutor.getRange().length() != 0 ) )
{
setDateRange( changeLogExecutor.getRange() );
}
}
setConnection( changeLogExecutor.getRepositoryConnection() );
// set the comment query string for the RCS.
setCommentFormat( changeLogExecutor.getCommentFormat() );
}
/**
* Set the dateRange member based on the number of days obtained
* from the ChangeLog.
*
* @param numDaysString The number of days of log output to
* generate.
*/
protected void setDateRange( String numDaysString )
{
int days = Integer.parseInt( numDaysString );
Date before =
new Date( System.currentTimeMillis()
- ( (long) days * 24 * 60 * 60 * 1000 ) );
Date to =
new Date( System.currentTimeMillis()
+ ( (long) 1 * 24 * 60 * 60 * 1000 ) );
dateRange = getScmDateArgument( before, to );
setLogStart( before );
setLogEnd( to );
}
/**
* Set the dateRange member based on an absolute date.
* @param startDate The start date for the range.
* @param endDate The end date for the range, or <code>null</code> to use the present time.
*/
protected void setDateRangeFromAbsoluteDate( String startDate,
String endDate )
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format =
( dateFormat == null ) ? new SimpleDateFormat( "yyyy-MM-dd" )
: new SimpleDateFormat( dateFormat );
Date before;
try
{
before = format.parse( startDate );
}
catch ( ParseException ex )
{
throw new IllegalArgumentException( "Unable to parse start date "
+ startDate + ": " + ex.getLocalizedMessage() );
}
Date to;
try
{
to = ( endDate != null ) ? format.parse( endDate )
: new Date( System.currentTimeMillis()
+ ( (long) 1 * 24 * 60 * 60 * 1000 ) );
}
catch ( ParseException ex )
{
throw new IllegalArgumentException( "Unable to parse end date "
+ endDate + ": " + ex.getLocalizedMessage() );
}
dateRange = getScmDateArgument( before, to );
setLogStart( before );
setLogEnd( to );
}
/**
* Sets the log start string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param start date the log started.
*/
protected void setLogStart( Date start )
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format =
( dateFormat == null ) ? new SimpleDateFormat( "yyyy-MM-dd" )
: new SimpleDateFormat( dateFormat );
logStart = format.format( start );
}
/**
* Sets the log end string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param end date the log ended.
*/
protected void setLogEnd( Date end )
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format =
( dateFormat == null ) ? new SimpleDateFormat( "yyyy-MM-dd" )
: new SimpleDateFormat( dateFormat );
logEnd = format.format( end );
}
/**
* Execute scm client driving the given parser.
*
* @param parser A {@link ChangeLogParser parser} to process the scm
* output.
* @return A collection of {@link ChangeLogEntry entries} parsed from
* the scm output.
* @throws IOException When there are issues executing scm.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries( ChangeLogParser parser )
throws IOException
{
if ( parser == null )
{
throw new NullPointerException( "parser cannot be null" );
}
if ( base == null )
{
throw new NullPointerException( "basedir must be set" );
}
if ( !base.exists() )
{
throw new FileNotFoundException( "Cannot find base dir "
+ base.getAbsolutePath() );
}
clParser = parser;
try
{
Execute exe = new Execute( this );
exe.setCommandline( getScmLogCommand().getCommandline() );
exe.setWorkingDirectory( base );
logExecute( exe, base );
exe.execute();
// log messages from stderr
String errors = errorReader.toString().trim();
if ( errors.length() > 0 )
{
LOG.error( errors );
}
}
catch ( IOException ioe )
{
handleParserException( ioe );
}
return entries;
}
/**
* Handle ChangeLogParser IOExceptions. The default implementation
* just throws the exception again.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the
* exception (the default behavior).
*/
protected void handleParserException( IOException ioe )
throws IOException
{
throw ioe;
}
/**
* @see ChangeLogGenerator#getLogStart()
*/
public String getLogStart()
{
return logStart;
}
/**
* @see ChangeLogGenerator#getLogEnd()
*/
public String getLogEnd()
{
// TODO: Auto-generated method stub
return logEnd;
}
/**
* Clean up any generated resources for this run.
*
* @see ChangeLogGenerator#cleanup()
*/
public void cleanup()
{
}
/**
* Constructs the appropriate command line to execute the scm's
* log command. This method must be implemented by subclasses.
*
* @return The command line to be executed.
*/
protected abstract Commandline getScmLogCommand();
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate date range.
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm
* system.
*/
protected abstract String getScmDateArgument( Date before, Date to );
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate tag.
*
* @param tagStart The tag name for the start of the log (log shouldn't actually contain the tag).
* @param tagEnd The tag name for the end of the log (the log can contain this tag), or <code>null</code> to
* log all changes since <code>tagStart</code>.
* @return A string that can be used to specify the tag range to a scm system.
*/
protected abstract String getScmTagArgument( String tagStart, String tagEnd );
/**
* Stop the process - currently unimplemented
*/
public void stop()
{
}
/**
* Set the input stream for the scm process.
* @param os An {@link java.io.OutputStream}
*/
public void setProcessInputStream( OutputStream os )
{
}
/**
* Set the error stream for reading from scm log. This stream will
* be read on a separate thread.
*
* @param is An {@link java.io.InputStream}
*/
public void setProcessErrorStream( InputStream is )
{
errorReader = new AsyncStreamReader( is );
}
/**
* Set the input stream used to read from scm log.
*
* @param is A stream of scm log output to be read from
*/
public void setProcessOutputStream( InputStream is )
{
in = is;
}
/**
* Start read from the scm log.
*
* @throws IOException When there are errors reading from the
* streams previously provided
*/
public void start() throws IOException
{
errorReader.start();
entries = clParser.parse( in );
}
/**
* Returns the connection.
* @return String
*/
public String getConnection()
{
return connection;
}
/**
* Sets the connection.
* @param connection The connection to set
*/
public void setConnection( String connection )
{
this.connection = connection;
}
/**
* Returns the commentFormat used to interrogate the RCS.
* @return String
*/
public String getCommentFormat()
{
return commentFormat;
}
/**
* Sets the commentFormat.
* @param commentFormat The commentFormat to set
*/
public void setCommentFormat( String commentFormat )
{
this.commentFormat = commentFormat;
}
/**
* Logs the pertinent details to the logging system (info level)
* @param exe The object to log
* @param base The working directory
*/
public static void logExecute( Execute exe, File base )
{
String[] c = exe.getCommandline();
LOG.info( "SCM Working Directory: " + base );
for ( int i = 0; i < c.length; i++ )
{
String string = c[i];
LOG.info( "SCM Command Line[" + i + "]: " + string );
}
}
setConnection(changeLogExecutor.getRepositoryConnection());
// set the comment query string for the RCS.
setCommentFormat(changeLogExecutor.getCommentFormat());
}
/**
* Set the dateRange member based on the number of days obtained
* from the ChangeLog.
*
* @param numDaysString The number of days of log output to
* generate.
*/
protected void setDateRange(String numDaysString)
{
int days = Integer.parseInt(numDaysString);
Date before = new Date(System.currentTimeMillis() - (long) days * 24 * 60 * 60 * 1000);
Date to = new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000);
dateRange = getScmDateArgument(before, to);
setLogStart(before);
setLogEnd(to);
}
/**
* Set the dateRange member based on an absolute date.
* @param startDate The start date for the range.
* @param endDate The end date for the range, or <code>null</code> to use the present time.
*/
protected void setDateRangeFromAbsoluteDate(String startDate, String endDate)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
Date before;
try
{
before = format.parse(startDate);
}
catch (ParseException ex)
{
throw new IllegalArgumentException("Unable to parse start date " + startDate + ": " + ex.getLocalizedMessage());
}
Date to;
try
{
to = (endDate != null) ? format.parse(endDate) : new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000);
}
catch (ParseException ex)
{
throw new IllegalArgumentException("Unable to parse end date " + endDate + ": " + ex.getLocalizedMessage());
}
dateRange = getScmDateArgument(before, to);
setLogStart(before);
setLogEnd(to);
}
/**
* Sets the log start string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param start date the log started.
*/
protected void setLogStart(Date start)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
logStart = format.format(start);
}
/**
* Sets the log end string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param end date the log ended.
*/
protected void setLogEnd(Date end)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
logEnd = format.format(end);
}
/**
* Execute scm client driving the given parser.
*
* @param parser A {@link ChangeLogParser parser} to process the scm
* output.
* @return A collection of {@link ChangeLogEntry entries} parsed from
* the scm output.
* @throws IOException When there are issues executing scm.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries(ChangeLogParser parser) throws IOException
{
if (parser == null)
{
throw new NullPointerException("parser cannot be null");
}
if (base == null)
{
throw new NullPointerException("basedir must be set");
}
if (!base.exists())
{
throw new FileNotFoundException("Cannot find base dir " + base.getAbsolutePath());
}
clParser = parser;
try
{
Execute exe = new Execute(this);
exe.setCommandline(getScmLogCommand().getCommandline());
exe.setWorkingDirectory(base);
logExecute(exe, base);
exe.execute();
// log messages from stderr
String errors = errorReader.toString().trim();
if (errors.length() > 0)
{
LOG.error(errors);
}
}
catch (IOException ioe)
{
handleParserException(ioe);
}
return entries;
}
/**
* Handle ChangeLogParser IOExceptions. The default implementation
* just throws the exception again.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the
* exception (the default behavior).
*/
protected void handleParserException(IOException ioe) throws IOException
{
throw ioe;
}
/**
* @see ChangeLogGenerator#getLogStart()
*/
public String getLogStart()
{
return logStart;
}
/**
* @see ChangeLogGenerator#getLogEnd()
*/
public String getLogEnd()
{
// TODO: Auto-generated method stub
return logEnd;
}
/**
* Clean up any generated resources for this run.
*
* @see ChangeLogGenerator#cleanup()
*/
public void cleanup()
{
}
/**
* Constructs the appropriate command line to execute the scm's
* log command. This method must be implemented by subclasses.
*
* @return The command line to be executed.
*/
protected abstract Commandline getScmLogCommand();
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate date range.
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm
* system.
*/
protected abstract String getScmDateArgument(Date before, Date to);
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate tag.
*
* @param tagStart The tag name for the start of the log (log shouldn't actually contain the tag).
* @param tagEnd The tag name for the end of the log (the log can contain this tag), or <code>null</code> to
* log all changes since <code>tagStart</code>.
* @return A string that can be used to specify the tag range to a scm system.
*/
protected abstract String getScmTagArgument(String tagStart, String tagEnd);
/**
* Stop the process - currently unimplemented
*/
public void stop()
{
}
/**
* Set the input stream for the scm process.
* @param os An {@link java.io.OutputStream}
*/
public void setProcessInputStream(OutputStream os)
{
}
/**
* Set the error stream for reading from scm log. This stream will
* be read on a separate thread.
*
* @param is An {@link java.io.InputStream}
*/
public void setProcessErrorStream(InputStream is)
{
errorReader = new AsyncStreamReader(is);
}
/**
* Set the input stream used to read from scm log.
*
* @param is A stream of scm log output to be read from
*/
public void setProcessOutputStream(InputStream is)
{
in = is;
}
/**
* Start read from the scm log.
*
* @throws IOException When there are errors reading from the
* streams previously provided
*/
public void start() throws IOException
{
errorReader.start();
entries = clParser.parse(in);
}
/**
* Returns the connection.
* @return String
*/
public String getConnection()
{
return connection;
}
/**
* Sets the connection.
* @param connection The connection to set
*/
public void setConnection(String connection)
{
this.connection = connection;
}
/**
* Returns the commentFormat used to interrogate the RCS.
* @return String
*/
public String getCommentFormat()
{
return commentFormat;
}
/**
* Sets the commentFormat.
* @param commentFormat The commentFormat to set
*/
public void setCommentFormat(String commentFormat)
{
this.commentFormat = commentFormat;
}
/**
* Logs the pertinent details to the logging system (info level)
* @param exe The object to log
* @param base The working directory
*/
public static void logExecute(Execute exe, File base)
{
String c[] = exe.getCommandline();
LOG.info("SCM Working Directory: " + base);
for (int i = 0; i < c.length; i++)
{
String string = c[i];
LOG.info("SCM Command Line[" + i + "]: " + string);
}
}
}
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -55,34 +56,52 @@ import org.apache.maven.project.Developer;
*/
public class ChangeLog
{
private static final Map FACTORIES = new HashMap();
/** Log */
private static final Log LOG = LogFactory.getLog( ChangeLog.class );
static
{
FACTORIES.put( "cvs", "org.apache.maven.cvslib.CvsChangeLogFactory" );
FACTORIES.put( "svn", "org.apache.maven.svnlib.SvnChangeLogFactory" );
FACTORIES.put( "clearcase",
"org.apache.maven.clearcaselib.ClearcaseChangeLogFactory" );
FACTORIES.put( "perforce",
"org.apache.maven.perforcelib.PerforceChangeLogFactory" );
FACTORIES.put( "starteam",
"org.apache.maven.starteamlib.StarteamChangeLogFactory" );
FACTORIES.put( "vss", "org.apache.maven.vsslib.VssChangeLogFactory" );
}
/** Used to specify whether to build the log from a range, absolute date, or tag. */
private String type;
/**
* Used to specify the range of log entries to retrieve.
*/
private String range;
/** Used to specify the absolute date (or list of dates) to start log entries from. */
private String date;
/** Used to specify the tag (or list of tags) to start log entries from. */
private String tag;
/** This will contain the date/tag for the start of the current change set. */
private String markerStart;
/** This will contain the date/tag for the end of the current change set. */
private String markerEnd;
/**
* Used to specify the date format of log entries to retrieve.
*/
/**
* Used to specify the date format of log entries to retrieve.
*/
private String dateFormat;
/**
* Specifies whether to quote date argument (used by CvsChangeLogGenerator).
*/
/**
* Specifies whether to quote date argument (used by CvsChangeLogGenerator).
*/
private boolean quoteDate;
/**
@@ -96,38 +115,23 @@ public class ChangeLog
*/
private String clFactoryClass = null;
private static final Map FACTORIES = new HashMap();
/** the connection string used to access the SCM */
private String connection;
/** the list of developers on the project */
private List developers;
/** change log sets parsed (sets of entries) */
private Collection sets;
/** Log */
private static final Log LOG = LogFactory.getLog(ChangeLog.class);
/**
* Output file for xml document
*/
private File output;
/** output encoding for the xml document */
private String outputEncoding;
static
{
FACTORIES.put( "cvs", "org.apache.maven.cvslib.CvsChangeLogFactory" );
FACTORIES.put( "svn", "org.apache.maven.svnlib.SvnChangeLogFactory" );
FACTORIES.put( "clearcase", "org.apache.maven.clearcaselib.ClearcaseChangeLogFactory" );
FACTORIES.put( "perforce", "org.apache.maven.perforcelib.PerforceChangeLogFactory" );
FACTORIES.put( "starteam", "org.apache.maven.starteamlib.StarteamChangeLogFactory" );
FACTORIES.put( "vss", "org.apache.maven.vsslib.VssChangeLogFactory" );
}
/**
* Comment format string used for interrogating
* the revision control system.
@@ -141,24 +145,24 @@ public class ChangeLog
*
* @param factoryClassName the fully qualified factory class name
*/
public void setFactory(String factoryClassName)
public void setFactory( String factoryClassName )
{
clFactoryClass = factoryClassName;
}
/**
* Set the type of log to generate (range, date, or tag).
*
*
* @param type one of "range", "date", or "tag".
*/
public void setType(String type)
public void setType( String type )
{
this.type = type;
}
/**
* Get the type of log to generate (range, date, or tag).
*
*
* @return the basis for the log.
*/
public String getType()
@@ -167,10 +171,10 @@ public class ChangeLog
{
type = "range";
}
return type;
}
/**
* Set the range of log entries to process; the interpretation of this
* parameter depends on the generator.
@@ -178,7 +182,7 @@ public class ChangeLog
*
* @param range the range of log entries.
*/
public void setRange(String range)
public void setRange( String range )
{
this.range = range;
}
@@ -193,45 +197,43 @@ public class ChangeLog
{
return range;
}
/**
* Set the date to start the log from.
* This is only used if the type is "date".
* The format is that given by the dateFormat property, if present. Otherwise, the format is "yyyy-MM-dd".
*
*
* @param date the date to use.
*/
public void setDate(String date)
public void setDate( String date )
{
this.date = date;
}
/**
* Get the date to start the log from.
*
*
* @return the start date.
*/
public String getDate()
{
return date;
}
/**
* Set the tag to start the log from.
* This is only used if the type is "tag".
*
*
* @param tag the tag to use.
*/
public void setTag(String tag)
public void setTag( String tag )
{
this.tag = tag;
}
/**
* Get the tag to start the log from.
*
*
* @return the tag.
*/
public String getTag()
@@ -239,22 +241,21 @@ public class ChangeLog
return tag;
}
/**
* Sets the marker (date or tag) for the start of the current change set.
* (This is only set internally, but also by test code.)
*
*
* @param marker start marker to use.
*/
public void setMarkerStart(String marker)
public void setMarkerStart( String marker )
{
markerStart = marker;
}
/**
* Returns the marker (date or tag) for the start of the current change set.
* Whether it's a date or tag depends on {@link #getType}.
*
*
* @return the marker (date or tag) for the start of the current change set.
*/
public String getMarkerStart()
@@ -265,18 +266,18 @@ public class ChangeLog
/**
* Sets the marker (date or tag) for the end of the current change set.
* (This is only set internally, but also by test code.)
*
*
* @param marker end marker to use, or <code>null</code> to specify all changes since the start.
*/
public void setMarkerEnd(String marker)
public void setMarkerEnd( String marker )
{
markerEnd = marker;
}
/**
* Returns the marker (date or tag) for the end of the current change set.
* Whether it's a date or tag depends on {@link #getType}.
*
*
* @return the marker (date or tag) for the end of the current change set, or <code>null</code> if there is no
* end (meaning the change set should show all changes from the start to the present time).
*/
@@ -285,14 +286,13 @@ public class ChangeLog
return markerEnd;
}
/**
* Set the date format of log entries to process; the
* interpretation of this parameter depends on the generator.
*
* @param dateFormat the dateFormat of log entries.
*/
public void setDateFormat(String dateFormat)
public void setDateFormat( String dateFormat )
{
this.dateFormat = dateFormat;
}
@@ -312,7 +312,7 @@ public class ChangeLog
* Set the quoteDate property.
* @param newQuoteDate the quoteDate property to set.
*/
public void setQuoteDate(boolean newQuoteDate)
public void setQuoteDate( boolean newQuoteDate )
{
this.quoteDate = newQuoteDate;
}
@@ -331,7 +331,7 @@ public class ChangeLog
* Set the base directory for the change log generator.
* @param base the base directory
*/
public void setBasedir(File base)
public void setBasedir( File base )
{
this.base = base;
}
@@ -350,7 +350,7 @@ public class ChangeLog
* Set the output file for the log.
* @param output the output file
*/
public void setOutput(File output)
public void setOutput( File output )
{
this.output = output;
}
@@ -369,11 +369,11 @@ public class ChangeLog
* @param aString a string containing the project's repository
* connection
*/
public void setRepositoryConnection(String aString)
public void setRepositoryConnection( String aString )
{
connection = aString;
}
/**
* Execute task.
* @throws FileNotFoundException if the base diretory
@@ -382,34 +382,36 @@ public class ChangeLog
* @throws UnsupportedEncodingException if the underlying platform doesn't
* support ISO-8859-1 encoding
*/
public void doExecute() throws FileNotFoundException, IOException,
UnsupportedEncodingException
public void doExecute()
throws FileNotFoundException, IOException, UnsupportedEncodingException
{
if (output == null)
if ( output == null )
{
throw new NullPointerException("output must be set");
throw new NullPointerException( "output must be set" );
}
generateSets();
replaceAuthorIdWithName();
createDocument();
}
/**
* Create the change log entries.
* @throws IOException if there is a problem creating the change log
* entries.
*/
private void generateSets() throws IOException
private void generateSets()
throws IOException
{
ChangeLogFactory factory = createFactory();
String markers = "";
if (getType().equalsIgnoreCase("tag"))
if ( getType().equalsIgnoreCase( "tag" ) )
{
markers = getTag();
}
else if (getType().equalsIgnoreCase("date"))
else if ( getType().equalsIgnoreCase( "date" ) )
{
markers = getDate();
}
@@ -417,39 +419,49 @@ public class ChangeLog
{
markers = getRange();
}
try
{
StringTokenizer tokens = new StringTokenizer(markers, ",");
sets = new ArrayList(tokens.countTokens());
StringTokenizer tokens = new StringTokenizer( markers, "," );
sets = new ArrayList( tokens.countTokens() );
String end = tokens.nextToken();
do
{
String start = end;
end = (tokens.hasMoreTokens()) ? tokens.nextToken() : null;
setMarkerStart(start);
setMarkerEnd(end);
end = ( tokens.hasMoreTokens() ) ? tokens.nextToken() : null;
setMarkerStart( start );
setMarkerEnd( end );
ChangeLogParser parser = factory.createParser();
if (getDateFormat() != null)
if ( getDateFormat() != null )
{
parser.setDateFormatInFile(getDateFormat());
parser.setDateFormatInFile( getDateFormat() );
}
parser.init(this);
parser.init( this );
ChangeLogGenerator generator = factory.createGenerator();
generator.init(this);
generator.init( this );
Collection entries;
String logStart;
String logEnd;
try
{
entries = generator.getEntries(parser);
entries = generator.getEntries( parser );
logStart = generator.getLogStart();
logEnd = generator.getLogEnd();
} catch (IOException e) {
LOG.warn(e.getLocalizedMessage(), e);
}
catch ( IOException e )
{
LOG.warn( e.getLocalizedMessage(), e );
throw e;
}
finally
@@ -463,12 +475,15 @@ public class ChangeLog
entries = Collections.EMPTY_LIST;
}
sets.add(new ChangeLogSet(entries, logStart, logEnd));
if (LOG.isInfoEnabled()) {
LOG.info("ChangeSet between " + logStart + " and " + logEnd + ": "
+ entries.size() + " entries");
sets.add( new ChangeLogSet( entries, logStart, logEnd ) );
if ( LOG.isInfoEnabled() )
{
LOG.info( "ChangeSet between " + logStart + " and "
+ logEnd + ": " + entries.size() + " entries" );
}
} while (end != null);
}
while ( end != null );
}
finally
{
@@ -482,48 +497,54 @@ public class ChangeLog
* @return the new ChangeLogFactory instance
* @throws IOException if there is a problem creating the instance.
*/
private ChangeLogFactory createFactory() throws IOException
private ChangeLogFactory createFactory()
throws IOException
{
if ( clFactoryClass == null )
{
if ( connection == null || connection.length() < 7 || !connection.startsWith( "scm:" ) )
if ( ( connection == null ) || ( connection.length() < 7 )
|| !connection.startsWith( "scm:" ) )
{
LOG.warn( "Connection does not appear valid" );
}
else
{
clFactoryClass = (String) FACTORIES.get( connection.substring( 4, 7 ) );
clFactoryClass =
(String) FACTORIES.get( connection.substring( 4, 7 ) );
}
if ( clFactoryClass == null )
{
LOG.warn( "Could not derive factory from connection: using CVS (valid factories are: " + FACTORIES.keySet() + ")" );
LOG.warn(
"Could not derive factory from connection: using CVS (valid factories are: "
+ FACTORIES.keySet() + ")" );
clFactoryClass = "org.apache.maven.cvslib.CvsChangeLogFactory";
}
}
try
{
Class clazz = Class.forName(clFactoryClass);
Class clazz = Class.forName( clFactoryClass );
return (ChangeLogFactory) clazz.newInstance();
}
catch (ClassNotFoundException cnfe)
catch ( ClassNotFoundException cnfe )
{
throw new IOException("Cannot find class " + clFactoryClass
+ " " + cnfe.toString());
throw new IOException( "Cannot find class " + clFactoryClass + " "
+ cnfe.toString() );
}
catch (IllegalAccessException iae)
catch ( IllegalAccessException iae )
{
throw new IOException("Cannot access class " + clFactoryClass
+ " " + iae.toString());
throw new IOException( "Cannot access class " + clFactoryClass
+ " " + iae.toString() );
}
catch (InstantiationException ie)
catch ( InstantiationException ie )
{
throw new IOException("Cannot instantiate class " + clFactoryClass
+ " " + ie.toString());
throw new IOException( "Cannot instantiate class " + clFactoryClass
+ " " + ie.toString() );
}
}
/**
* Set up list of developers mapping id to name.
* @task This should be a facility on the maven project itself
@@ -532,14 +553,15 @@ public class ChangeLog
private Properties getUserList()
{
Properties userList = new Properties();
Developer developer = null;
for (Iterator i = getDevelopers().iterator(); i.hasNext();)
for ( Iterator i = getDevelopers().iterator(); i.hasNext(); )
{
developer = (Developer) i.next();
userList.put(developer.getId(), developer.getName());
userList.put( developer.getId(), developer.getName() );
}
return userList;
}
@@ -550,21 +572,25 @@ public class ChangeLog
{
Properties userList = getUserList();
ChangeLogEntry entry = null;
for (final Iterator iSets = getChangeSets().iterator() ; iSets.hasNext() ;)
for ( Iterator iSets = getChangeSets().iterator();
iSets.hasNext(); )
{
final ChangeLogSet set = (ChangeLogSet)iSets.next();
for (Iterator iEntries = set.getEntries().iterator(); iEntries.hasNext();)
final ChangeLogSet set = (ChangeLogSet) iSets.next();
for ( Iterator iEntries = set.getEntries().iterator();
iEntries.hasNext(); )
{
entry = (ChangeLogEntry) iEntries.next();
if (userList.containsKey(entry.getAuthor()))
if ( userList.containsKey( entry.getAuthor() ) )
{
entry.setAuthor(userList.getProperty(entry.getAuthor()));
entry.setAuthor( userList.getProperty( entry.getAuthor() ) );
}
}
}
}
/**
* Create the XML document from the currently available details
* @throws FileNotFoundException when the output file previously provided
@@ -572,64 +598,69 @@ public class ChangeLog
* @throws UnsupportedEncodingException when the platform doesn't support
* ISO-8859-1 encoding
*/
private void createDocument() throws FileNotFoundException,
UnsupportedEncodingException
private void createDocument()
throws FileNotFoundException, UnsupportedEncodingException
{
File dir = output.getParentFile();
if (dir != null) {
if ( dir != null )
{
dir.mkdirs();
}
PrintWriter out = new PrintWriter(new OutputStreamWriter(
new FileOutputStream(output), getOutputEncoding()));
out.println(toXML());
PrintWriter out =
new PrintWriter( new OutputStreamWriter(
new FileOutputStream( output ), getOutputEncoding() ) );
out.println( toXML() );
out.flush();
out.close();
}
/**
* @return an XML document representing this change log and it's entries
* @return an XML document representing this change log and it's entries
*/
private String toXML()
{
StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"")
.append(getOutputEncoding())
.append("\" ?>\n")
.append("<changelog>\n");
for (Iterator i = getChangeSets().iterator(); i.hasNext();)
buffer.append( "<?xml version=\"1.0\" encoding=\"" )
.append( getOutputEncoding() ).append( "\" ?>\n" ).append( "<changelog>\n" );
for ( Iterator i = getChangeSets().iterator(); i.hasNext(); )
{
buffer.append(((ChangeLogSet) i.next()).toXML());
buffer.append( ( (ChangeLogSet) i.next() ).toXML() );
}
buffer.append("</changelog>\n");
buffer.append( "</changelog>\n" );
return buffer.toString();
}
/**
* Gets the collection of change sets.
*
*
* @return collection of {@link ChangeLogSet} objects.
*/
public Collection getChangeSets()
{
if (sets == null)
if ( sets == null )
{
sets = Collections.EMPTY_LIST;
}
return sets;
}
/**
/**
* Sets the collection of change sets.
* @param sets New value of property sets.
*/
public void setChangeSets(Collection sets)
public void setChangeSets( Collection sets )
{
this.sets = sets;
}
/**
* Returns the developers.
* @return List
@@ -643,7 +674,7 @@ public class ChangeLog
* Sets the developers.
* @param developers The developers to set
*/
public void setDevelopers(List developers)
public void setDevelopers( List developers )
{
this.developers = developers;
}
@@ -661,7 +692,7 @@ public class ChangeLog
* Sets the outputEncoding.
* @param outputEncoding The outputEncoding to set
*/
public void setOutputEncoding(String outputEncoding)
public void setOutputEncoding( String outputEncoding )
{
this.outputEncoding = outputEncoding;
}
@@ -679,9 +710,9 @@ public class ChangeLog
* Sets the commentFormat.
* @param commentFormat The commentFormat to set
*/
public void setCommentFormat(String commentFormat)
public void setCommentFormat( String commentFormat )
{
this.commentFormat = commentFormat;
}
} // end of ChangeLog
}
// end of ChangeLog
@@ -18,6 +18,7 @@ package org.apache.maven.changelog;
*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
@@ -36,76 +37,75 @@ public class ChangeLogEntry
* Escaped <code>&lt;</code> entity
*/
public static final String LESS_THAN_ENTITY = "&lt;";
/**
* Escaped <code>&gt;</code> entity
*/
public static final String GREATER_THAN_ENTITY = "&gt;";
/**
* Escaped <code>&amp;</code> entity
*/
public static final String AMPERSAND_ENTITY = "&amp;";
/**
* Escaped <code>'</code> entity
*/
public static final String APOSTROPHE_ENTITY = "&apos;";
/**
* Escaped <code>"</code> entity
*/
public static final String QUOTE_ENTITY = "&quot;";
/**
* Formatter used by the getDateFormatted method.
*/
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat( "yyyy-MM-dd" );
/**
* Formatter used by the getTimeFormatted method.
*/
private static final SimpleDateFormat TIME_FORMAT =
new SimpleDateFormat("HH:mm:ss");
private static final SimpleDateFormat TIME_FORMAT =
new SimpleDateFormat( "HH:mm:ss" );
/** Date the changes were committed */
private Date date;
/** User who made changes */
private String author;
/** comment provided at commit time */
private String comment = "";
/** ChangeLogFiles committed on the date, by the author, with comment*/
private Vector files = new Vector();
/**
* Constructor used when attributes aren't available until later
*/
public ChangeLogEntry()
public ChangeLogEntry()
{
}
/**
* Adds a file to the list for this entry
* @param file a {@link ChangeLogFile}
*/
public void addFile(ChangeLogFile file)
public void addFile( ChangeLogFile file )
{
files.addElement(file);
files.addElement( file );
}
/**
/**
* Adds a feature to the File attribute of the Entry object.
* @param file the file name committed
* @param revision the revision of the latest change
*/
public void addFile(String file, String revision)
public void addFile( String file, String revision )
{
files.addElement(new ChangeLogFile(file, revision));
files.addElement( new ChangeLogFile( file, revision ) );
}
/**
@@ -118,7 +118,7 @@ public class ChangeLogEntry
/**
* Provide the changelog entry as an XML snippet.
*
*
* @task make sure comment doesn't contain CDATA tags - MAVEN114
* @return a changelog-entry in xml format
*/
@@ -126,37 +126,30 @@ public class ChangeLogEntry
{
StringBuffer buffer = new StringBuffer();
buffer.append("\t<changelog-entry>\n")
.append("\t\t<date>")
.append(getDateFormatted())
.append("</date>\n")
.append("\t\t<time>")
.append(getTimeFormatted())
.append("</time>\n")
.append("\t\t<author><![CDATA[")
.append(author)
.append("]]></author>\n");
for (Enumeration e = files.elements(); e.hasMoreElements();)
buffer.append( "\t<changelog-entry>\n" ).append( "\t\t<date>" )
.append( getDateFormatted() ).append( "</date>\n" )
.append( "\t\t<time>" ).append( getTimeFormatted() )
.append( "</time>\n" ).append( "\t\t<author><![CDATA[" )
.append( author ).append( "]]></author>\n" );
for ( Enumeration e = files.elements(); e.hasMoreElements(); )
{
ChangeLogFile file = (ChangeLogFile) e.nextElement();
buffer.append("\t\t<file>\n")
.append("\t\t\t<name>")
.append(escapeValue(file.getName()))
.append("</name>\n")
.append("\t\t\t<revision>")
.append(file.getRevision())
.append("</revision>\n");
buffer.append("\t\t</file>\n");
buffer.append( "\t\t<file>\n" ).append( "\t\t\t<name>" )
.append( escapeValue( file.getName() ) ).append( "</name>\n" )
.append( "\t\t\t<revision>" ).append( file.getRevision() )
.append( "</revision>\n" );
buffer.append( "\t\t</file>\n" );
}
buffer.append("\t\t<msg><![CDATA[")
.append(removeCDataEnd(comment))
.append("]]></msg>\n");
buffer.append("\t</changelog-entry>\n");
buffer.append( "\t\t<msg><![CDATA[" ).append( removeCDataEnd( comment ) )
.append( "]]></msg>\n" );
buffer.append( "\t</changelog-entry>\n" );
return buffer.toString();
}
/**
* Getter for property author.
* @return Value of property author.
@@ -165,16 +158,16 @@ public class ChangeLogEntry
{
return author;
}
/**
* Setter for property author.
* @param author New value of property author.
*/
public void setAuthor(String author)
public void setAuthor( String author )
{
this.author = author;
}
/**
* Getter for property comment.
* @return Value of property comment.
@@ -183,16 +176,16 @@ public class ChangeLogEntry
{
return comment;
}
/**
* Setter for property comment.
* @param comment New value of property comment.
*/
public void setComment(String comment)
public void setComment( String comment )
{
this.comment = comment;
}
/**
* Getter for property date.
* @return Value of property date.
@@ -201,14 +194,14 @@ public class ChangeLogEntry
{
return (Date) date.clone();
}
/**
* Setter for property date.
* @param date New value of property date.
*/
public void setDate(Date date)
public void setDate( Date date )
{
this.date = new Date(date.getTime());
this.date = new Date( date.getTime() );
}
/**
@@ -216,73 +209,92 @@ public class ChangeLogEntry
*/
public String getDateFormatted()
{
return DATE_FORMAT.format(getDate());
return DATE_FORMAT.format( getDate() );
}
/**
* @return time in HH:mm:ss format
*/
public String getTimeFormatted()
{
return TIME_FORMAT.format(getDate());
return TIME_FORMAT.format( getDate() );
}
/**
* remove a <code>]]></code> from comments (replace it with <code>] ] ></code>).
* @param message
* @return
*/
private String removeCDataEnd(String message)
private String removeCDataEnd( String message )
{
// check for invalid sequence ]]>
int endCdata;
while (message != null && (endCdata = message.indexOf("]]>")) > -1)
while ( ( message != null )
&& ( ( endCdata = message.indexOf( "]]>" ) ) > -1 ) )
{
message = message.substring(0, endCdata) + "] ] >" + message.substring(endCdata + 3, message.length());
message =
message.substring( 0, endCdata ) + "] ] >"
+ message.substring( endCdata + 3, message.length() );
}
return message;
}
/**
* <p>Escape the <code>toString</code> of the given object.
* For use in an attribute value.</p>
*
* swiped from jakarta-commons/betwixt -- XMLUtils.java
*
* @param value escape <code>value.toString()</code>
* @return text with characters restricted (for use in attributes) escaped
*/
public static final String escapeValue(Object value) {
StringBuffer buffer = new StringBuffer(value.toString());
for (int i=0, size = buffer.length(); i <size; i++) {
switch (buffer.charAt(i)) {
case '<':
buffer.replace(i, i+1, LESS_THAN_ENTITY);
size += 3;
i+=3;
break;
case '>':
buffer.replace(i, i+1, GREATER_THAN_ENTITY);
size += 3;
i += 3;
break;
case '&':
buffer.replace(i, i+1, AMPERSAND_ENTITY);
size += 4;
i += 4;
break;
case '\'':
buffer.replace(i, i+1, APOSTROPHE_ENTITY);
size += 4;
i += 4;
break;
case '\"':
buffer.replace(i, i+1, QUOTE_ENTITY);
size += 5;
i += 5;
break;
}
}
return buffer.toString();
/**
* <p>Escape the <code>toString</code> of the given object.
* For use in an attribute value.</p>
*
* swiped from jakarta-commons/betwixt -- XMLUtils.java
*
* @param value escape <code>value.toString()</code>
* @return text with characters restricted (for use in attributes) escaped
*/
public static final String escapeValue( Object value )
{
StringBuffer buffer = new StringBuffer( value.toString() );
for ( int i = 0, size = buffer.length(); i < size; i++ )
{
switch ( buffer.charAt( i ) )
{
case '<' :
buffer.replace( i, i + 1, LESS_THAN_ENTITY );
size += 3;
i += 3;
break;
case '>' :
buffer.replace( i, i + 1, GREATER_THAN_ENTITY );
size += 3;
i += 3;
break;
case '&' :
buffer.replace( i, i + 1, AMPERSAND_ENTITY );
size += 4;
i += 4;
break;
case '\'' :
buffer.replace( i, i + 1, APOSTROPHE_ENTITY );
size += 4;
i += 4;
break;
case '\"' :
buffer.replace( i, i + 1, QUOTE_ENTITY );
size += 5;
i += 5;
break;
}
}
return buffer.toString();
}
}
@@ -28,6 +28,7 @@ public class ChangeLogFile
{
/** the name of the file relative to the project directory. */
private String name;
/** the latest revision of the file. */
private String revision;
@@ -35,21 +36,21 @@ public class ChangeLogFile
* Constructor for the ChangeLogFile object without all details available
* @param name file name
*/
public ChangeLogFile(String name)
public ChangeLogFile( String name )
{
setName(name);
setName( name );
}
/**
* Constructor for the ChangeLogFile object
*
* @param name file name
* @param rev latest revision of the file
*/
public ChangeLogFile(String name, String rev)
public ChangeLogFile( String name, String rev )
{
setName(name);
setRevision(rev);
setName( name );
setRevision( rev );
}
/**
@@ -74,16 +75,16 @@ public class ChangeLogFile
* Setter for property name.
* @param name New value of property name.
*/
public void setName(String name)
public void setName( String name )
{
this.name = name;
}
/**
* Setter for property revision.
* @param revision New value of property revision.
*/
public void setRevision(String revision)
public void setRevision( String revision )
{
this.revision = revision;
}
@@ -92,15 +93,16 @@ public class ChangeLogFile
* Provide a version of the object as a string for debugging purposes
* @return a {@link String} made up of the properties of the object
*/
public String toString()
public String toString()
{
StringBuffer buffer = new StringBuffer(getName());
if (getRevision() != null)
StringBuffer buffer = new StringBuffer( getName() );
if ( getRevision() != null )
{
buffer.append(", ").append(getRevision());
buffer.append( ", " ).append( getRevision() );
}
return buffer.toString();
}
} // end of ChangeLogFile
}
// end of ChangeLogFile
@@ -18,13 +18,14 @@ package org.apache.maven.changelog;
*/
import java.io.IOException;
import java.util.Collection;
/**
* Instances of <code>ChangeLogGenerator</code> are intended to provide an
* {@link java.io.InputStream} for a {@link ChangeLogParser} to parse into
* {@link java.io.InputStream} for a {@link ChangeLogParser} to parse into
* individual {@link ChangeLogEntry} objects.
*
*
* @author Glenn McAllister
* @author dion
* @version $Id$
@@ -34,12 +35,12 @@ public interface ChangeLogGenerator
/**
* Initialize the ChangeLogGenerator instance with in the controlling
* {@link ChangeLog} instance. Any configuration required for the generator
* should be obtained from the <code>changeLog</code>. This method is
* should be obtained from the <code>changeLog</code>. This method is
* guaranteed to be called before {@link #getEntries}.
*
* @param changeLog the controlling ChangeLog instance
*/
void init(ChangeLog changeLog);
void init( ChangeLog changeLog );
/**
* Return a Collection of ChangeLogEntry objects. This method should
@@ -57,24 +58,25 @@ public interface ChangeLogGenerator
* @throws IOException if there is an error while creating the
* ChangeLogEntry objects
*/
Collection getEntries(ChangeLogParser parser) throws IOException;
Collection getEntries( ChangeLogParser parser )
throws IOException;
/**
* Return a string indicating the start of the entries.
* This will usually be a date or a tag.
*
*
* @return a string indicating the start of the entries.
*/
String getLogStart();
/**
* Return a string indicating the end of the entries.
* This will usually be a date or a tag.
*
*
* @return a string indicating the end of the entries.
*/
String getLogEnd();
/**
* Provides the opportunity for the generator to do any required cleanup.
* This method is guaranteed to be called after the getEntries method even
@@ -17,8 +17,9 @@ package org.apache.maven.changelog;
* ====================================================================
*/
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
/**
@@ -39,7 +40,7 @@ public interface ChangeLogParser
*
* @param changeLog the controlling ChangeLog instance
*/
void init(ChangeLog changeLog);
void init( ChangeLog changeLog );
/**
* Returns a {@link java.util.Collection} of ChangeLogEntry objects, parsed
@@ -52,7 +53,8 @@ public interface ChangeLogParser
* @return a Collection of ChangeLogEntry objects
* @throws IOException if there is an error while parsing the input stream
*/
Collection parse(InputStream in) throws IOException;
Collection parse( InputStream in )
throws IOException;
/**
* Provides the opportunity for the parser to do any required cleanup.
@@ -17,11 +17,9 @@ package org.apache.maven.changelog;
* ====================================================================
*/
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
/**
* Change Log Set - holds details about a set of change log entries.
*
@@ -33,76 +31,68 @@ public class ChangeLogSet
private final Collection entries;
private final String start;
private final String end;
/**
* Initializes a new instance of this class.
*
*
* @param entries collection of {@link ChangeLogEntry} objects for this set.
* @param start the start date/tag for this set.
* @param end the end date/tag for this set, or <code>null</code> if this set goes to the present time.
*/
public ChangeLogSet(Collection entries, String start, String end)
public ChangeLogSet( Collection entries, String start, String end )
{
this.entries = entries;
this.start = start;
this.end = end;
}
/**
* Returns the collection of entries for this set.
*
*
* @return the collection of {@link ChangeLogEntry} objects for this set.
*/
public Collection getEntries()
{
return entries;
}
/**
* Returns the start date/tag for this set.
*
*
* @return the start date/tag for this set.
*/
public String getStart()
{
return start;
}
/**
* Returns the end date/tag for this set.
*
*
* @return the end date/tag for this set, or <code>null</code> if this set goes to the present time.
*/
public String getEnd()
{
return end;
}
/**
* Creates an XML representation of this change log set.
*/
public String toXML()
{
StringBuffer buffer = new StringBuffer();
buffer.append("<changeset start=\"")
.append(start)
.append("\" end=\"")
.append(end)
.append("\">\n");
buffer.append( "<changeset start=\"" ).append( start )
.append( "\" end=\"" ).append( end ).append( "\">\n" );
// Write out the entries
for (Iterator i = getEntries().iterator(); i.hasNext();)
for ( Iterator i = getEntries().iterator(); i.hasNext(); )
{
buffer.append(((ChangeLogEntry) i.next()).toXML());
buffer.append( ( (ChangeLogEntry) i.next() ).toXML() );
}
buffer.append("</changeset>\n");
buffer.append( "</changeset>\n" );
return buffer.toString();
}
@@ -21,14 +21,15 @@ import org.apache.maven.changelog.ChangeLogFactory;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides Clearcase specific instances of the ChangeLogGenerator and
* ChangeLogParser interfaces.
*
* @author <a href="mailto:aldarion@virgilio.it">Simone Zorzetti</a>
*/
public class ClearcaseChangeLogFactory implements ChangeLogFactory {
public class ClearcaseChangeLogFactory implements ChangeLogFactory
{
/* (non-Javadoc)
* @see org.apache.maven.changelog.ChangeLogFactory#createGenerator()
*/
@@ -42,7 +43,6 @@ public class ClearcaseChangeLogFactory implements ChangeLogFactory {
*/
public ChangeLogParser createParser()
{
return new ClearcaseChangeLogParser();
return new ClearcaseChangeLogParser();
}
}
@@ -18,103 +18,108 @@ package org.apache.maven.clearcaselib;
*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.AbstractChangeLogGenerator;
// ant imports
import org.apache.tools.ant.types.Commandline;
import org.apache.maven.changelog.AbstractChangeLogGenerator;
/**
* A Clearcase implementation of the {@link org.apache.maven.changelog.ChangeLogGenerator}
* interface realized extending the {@link org.apache.maven.changelog.AbstractChangeLogGenerator}.
*
*
* The command line build by this class uses the <code>lshistory</code> clearcase command
* and formats the output in a way the ClearcaseChangeLogParser can understand. Due to this
* fact this implementations works only if used within a clearcase view.
*
*
* The command looks like this: <p>
* cleartool lshistory -recurse -nco -since SAMEDATE
* cleartool lshistory -recurse -nco -since SAMEDATE
* -fmt "NAME:%En\\nDATE:%Nd\\nCOMM:%-12.12o - %o - %c - Activity: %[activity]p\\nUSER:%-8.8u\\n"
*
* @author <a href="mailto:aldarion@virgilio.it">Simone Zorzetti</a>
*/
public class ClearcaseChangeLogGenerator extends AbstractChangeLogGenerator {
public class ClearcaseChangeLogGenerator extends AbstractChangeLogGenerator
{
/** Log */
private static final Log LOG = LogFactory.getLog(
ClearcaseChangeLogGenerator.class);
private static final Log LOG =
LogFactory.getLog( ClearcaseChangeLogGenerator.class );
/**
* Constructs the appropriate command line to execute the scm's
* log command. For Clearcase it's lshistory.
*
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmLogCommand()
* @return The command line to be executed.
*/
protected Commandline getScmLogCommand()
{
Commandline command = new Commandline();
command.setExecutable("cleartool");
command.createArgument().setValue("lshistory");
command.setExecutable( "cleartool" );
command.createArgument().setValue( "lshistory" );
StringBuffer format = new StringBuffer();
format.append("NAME:%En\\n");
format.append("DATE:%Nd\\n");
format.append("COMM:%-12.12o - ");
format.append( "NAME:%En\\n" );
format.append( "DATE:%Nd\\n" );
format.append( "COMM:%-12.12o - " );
String commentFormat = getCommentFormat();
if (commentFormat == null)
if ( commentFormat == null )
{
format.append("%Sn - %c - Activity: %[activity]p\\n");
format.append( "%Sn - %c - Activity: %[activity]p\\n" );
}
else
{
format.append(commentFormat);
format.append( commentFormat );
}
format.append("USER:%-8.8u\\n");
command.createArgument().setValue("-fmt");
command.createArgument().setValue(format.toString());
command.createArgument().setValue("-recurse");
command.createArgument().setValue("-nco");
command.createArgument().setValue("-since");
command.createArgument().setValue(dateRange);
format.append( "USER:%-8.8u\\n" );
return command;
command.createArgument().setValue( "-fmt" );
command.createArgument().setValue( format.toString() );
command.createArgument().setValue( "-recurse" );
command.createArgument().setValue( "-nco" );
command.createArgument().setValue( "-since" );
command.createArgument().setValue( dateRange );
return command;
}
/**
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate date range.
*
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm
* system.
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmDateArgument(java.util.Date, java.util.Date)
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmDateArgument(java.util.Date, java.util.Date)
*/
protected String getScmDateArgument(Date before, Date to)
protected String getScmDateArgument( Date before, Date to )
{
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
String argument = sdf.format(before);
SimpleDateFormat sdf =
new SimpleDateFormat( "dd-MMM-yyyy", Locale.ENGLISH );
String argument = sdf.format( before );
return argument;
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Clearcase.");
throw new UnsupportedOperationException(
"This plugin currently does not support generating logs from tags with Clearcase." );
}
}
@@ -18,80 +18,83 @@ package org.apache.maven.clearcaselib;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Clearcase specific implementation of ChangeLogParser interface.
*
* Clearcase specific implementation of ChangeLogParser interface.
*
* @author <a href="mailto:aldarion@virgilio.it">Simone Zorzetti</a>
*/
public class ClearcaseChangeLogParser implements ChangeLogParser {
public class ClearcaseChangeLogParser implements ChangeLogParser
{
/** Log */
private static final Log LOG = LogFactory.getLog(
ClearcaseChangeLogParser.class);
private static final Log LOG =
LogFactory.getLog( ClearcaseChangeLogParser.class );
/**
* Formatter used to parse Clearcase date/timestamp.
*/
private static final SimpleDateFormat CLEARCASE_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyyMMdd.HHmmss");
new SimpleDateFormat( "yyyyMMdd.HHmmss" );
private static final String NAME_TAG = "NAME:";
private static final String USER_TAG = "USER:";
private static final String DATE_TAG = "DATE:";
private static final String COMMENT_TAG = "COMM:";
/**
* Custom date/time formatter. Rounds ChangeLogEntry times to the nearest
* minute.
*/
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyyMMddHHmm");
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat( "yyyyMMddHHmm" );
/**
* Custom date/time formatter. Rounds ChangeLogEntry to date
*/
private static final SimpleDateFormat GROUPED_ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyyMMdd");
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
private static final SimpleDateFormat GROUPED_ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat( "yyyyMMdd" );
// state machine constants for reading clearcase lshistory command output
/** expecting file information */
private static final int GET_FILE = 1;
/** expecting date */
private static final int GET_DATE = 2;
/** expecting comments */
private static final int GET_COMMENT = 3;
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap( Collections.reverseOrder() );
/** current status of the parser */
private int status = GET_FILE;
/** the current log entry being processed by the parser*/
private ChangeLogEntry currentLogEntry = null;
/** the current file being processed by the parser */
private ChangeLogFile currentFile = null;
@@ -106,29 +109,30 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
* initialize the parser from the change log
* @param changeLog the controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
*/
public void init( ChangeLog changeLog )
{
}
/**
* Clean up any parser resources
* @see ChangeLogParser#cleanup()
*/
*/
public void cleanup()
{
}
/**
* Parse the input stream into a collection.
* @param anInputStream an input stream containing clearcase log output
* @return a collection of ChangeLogEntry's
* @throws IOException when there are errors reading the provided stream
*/
public Collection parse(InputStream anInputStream) throws IOException
public Collection parse( InputStream anInputStream )
throws IOException
{
BufferedReader stream = new BufferedReader(
new InputStreamReader(anInputStream));
BufferedReader stream =
new BufferedReader( new InputStreamReader( anInputStream ) );
// Read the tags in the order they are produced by the command setup
// by ClearcaseChangeLogGenerator
@@ -137,28 +141,34 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
// Comment
// User Name (author)
String line = null;
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
switch (getStatus())
switch ( getStatus() )
{
case GET_FILE:
processGetFile(line);
break;
case GET_DATE:
processGetDate(line);
break;
case GET_COMMENT:
processGetCommentAndUser(line);
break;
default:
throw new IllegalStateException("Unknown state: " + status);
case GET_FILE :
processGetFile( line );
break;
case GET_DATE :
processGetDate( line );
break;
case GET_COMMENT :
processGetCommentAndUser( line );
break;
default :
throw new IllegalStateException( "Unknown state: " + status );
}
}
return entries.values();
}
}
/**
* Add a change log entry to the list (if it's not already there)
* with the given file.
@@ -167,101 +177,106 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
* is null, the entry wont be added
* @param file a {@link ChangeLogFile} to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file)
private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
{
// do not add if entry is not populated
if (entry.getAuthor() == null)
if ( entry.getAuthor() == null )
{
return;
}
// do not add if the operation is not checkin
if (entry.getComment().indexOf("checkin ") == -1)
{
return;
}
String key = ENTRY_KEY_TIMESTAMP_FORMAT.format(entry.getDate())
+ entry.getAuthor() + entry.getComment();
file.setRevision("");
if (!entries.containsKey(key))
// do not add if the operation is not checkin
if ( entry.getComment().indexOf( "checkin " ) == -1 )
{
entry.addFile(file);
entries.put(key, entry);
return;
}
String key =
ENTRY_KEY_TIMESTAMP_FORMAT.format( entry.getDate() )
+ entry.getAuthor() + entry.getComment();
file.setRevision( "" );
if ( !entries.containsKey( key ) )
{
entry.addFile( file );
entries.put( key, entry );
}
else
{
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
existingEntry.addFile( file );
}
}
/**
* Process the current input line in the Get File state.
* @param line a line of text from the clearcase log output
*/
private void processGetFile(String line)
private void processGetFile( String line )
{
if (line.startsWith(NAME_TAG))
if ( line.startsWith( NAME_TAG ) )
{
setCurrentLogEntry(new ChangeLogEntry());
setCurrentFile(new ChangeLogFile(line.substring(NAME_TAG.length(),
line.length())));
setStatus(GET_DATE);
setCurrentLogEntry( new ChangeLogEntry() );
setCurrentFile( new ChangeLogFile( line.substring(
NAME_TAG.length(), line.length() ) ) );
setStatus( GET_DATE );
}
}
/**
* Process the current input line in the Get Date state.
* @param line a line of text from the clearcase log output
*/
private void processGetDate(String line)
private void processGetDate( String line )
{
if (line.startsWith(DATE_TAG))
if ( line.startsWith( DATE_TAG ) )
{
try
{
getCurrentLogEntry().setDate(CLEARCASE_TIMESTAMP_FORMAT.parse(line.substring(DATE_TAG.length())));
getCurrentLogEntry().setDate( CLEARCASE_TIMESTAMP_FORMAT
.parse( line.substring( DATE_TAG.length() ) ) );
}
catch (ParseException e)
catch ( ParseException e )
{
// TODO Auto-generated catch block
e.printStackTrace();
}
setStatus(GET_COMMENT);
setStatus( GET_COMMENT );
}
}
/**
* Process the current input line in the Get Comment state.
* @param line a line of text from the clearcase log output
*/
private void processGetCommentAndUser(String line)
private void processGetCommentAndUser( String line )
{
if (line.startsWith(COMMENT_TAG))
if ( line.startsWith( COMMENT_TAG ) )
{
String comm = line.substring(COMMENT_TAG.length());
getCurrentLogEntry().setComment(
getCurrentLogEntry().getComment() + comm + "\n");
String comm = line.substring( COMMENT_TAG.length() );
getCurrentLogEntry().setComment( getCurrentLogEntry()
.getComment() + comm
+ "\n" );
}
else if (line.startsWith(USER_TAG))
else if ( line.startsWith( USER_TAG ) )
{
getCurrentLogEntry().setAuthor(line.substring(USER_TAG.length()).trim());
getCurrentLogEntry().setAuthor( line.substring(
USER_TAG.length() ).trim() );
// add entry, and set state to get file
addEntry(getCurrentLogEntry(), getCurrentFile());
setStatus(GET_FILE);
addEntry( getCurrentLogEntry(), getCurrentFile() );
setStatus( GET_FILE );
}
else
{
// keep gathering comments
getCurrentLogEntry().setComment(
getCurrentLogEntry().getComment() + line + "\n");
getCurrentLogEntry().setComment( getCurrentLogEntry()
.getComment() + line
+ "\n" );
}
}
@@ -273,16 +288,16 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
{
return currentFile;
}
/**
* Setter for property currentFile.
* @param currentFile New value of property currentFile.
*/
private void setCurrentFile(ChangeLogFile currentFile)
private void setCurrentFile( ChangeLogFile currentFile )
{
this.currentFile = currentFile;
}
/**
* Getter for property currentLogEntry.
* @return Value of property currentLogEntry.
@@ -291,16 +306,16 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
{
return currentLogEntry;
}
/**
* Setter for property currentLogEntry.
* @param currentLogEntry New value of property currentLogEntry.
*/
private void setCurrentLogEntry(ChangeLogEntry currentLogEntry)
private void setCurrentLogEntry( ChangeLogEntry currentLogEntry )
{
this.currentLogEntry = currentLogEntry;
}
/**
* Getter for property status.
* @return Value of property status.
@@ -309,12 +324,12 @@ public class ClearcaseChangeLogParser implements ChangeLogParser {
{
return status;
}
/**
* Setter for property status.
* @param status New value of property status.
*/
private void setStatus(int status)
private void setStatus( int status )
{
this.status = status;
}
@@ -21,6 +21,7 @@ import org.apache.maven.changelog.ChangeLogFactory;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides CVS specific instances of the ChangeLogGenerator and
* ChangeLogParser interfaces.
@@ -36,7 +37,7 @@ public class CvsChangeLogFactory implements ChangeLogFactory
public CvsChangeLogFactory()
{
}
/**
* Create a CVS specific ChangeLogGenerator.
*
@@ -16,12 +16,13 @@ package org.apache.maven.cvslib;
* limitations under the License.
* ====================================================================
*/
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
@@ -34,10 +35,11 @@ import org.apache.maven.util.AsyncStreamReader;
import org.apache.maven.util.RepositoryUtils;
import org.apache.tools.ant.types.Commandline;
/**
* A CVS implementation of the {@link org.apache.maven.changelog.ChangeLog}
* interface.
*
*
* @author Glenn McAllister
* @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
* @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a>
@@ -53,23 +55,20 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
{
/** Log */
private static final Log LOG =
LogFactory.getLog(CvsChangeLogGenerator.class);
private boolean quoteDate;
LogFactory.getLog( CvsChangeLogGenerator.class );
public static final int POS_SCM = 0;
public static final int POS_SCM_TYPE = 1;
public static final int POS_SCM_SUBTYPE = 2;
public static final int POS_SCM_USERHOST = 3;
public static final int POS_SCM_PATH = 4;
public static final int POS_SCM_MODULE = 5;
private boolean quoteDate;
/**
* Set the quoteDate property.
* @param newQuoteDate the quoteDate property to set.
*/
public void setQuoteDate(boolean newQuoteDate)
public void setQuoteDate( boolean newQuoteDate )
{
this.quoteDate = newQuoteDate;
}
@@ -84,99 +83,98 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
return quoteDate;
}
/**
* Initialize the generator from the changelog controller.
*
* @param changeLog The invoking controller (useful for logging)
* @see ChangeLogGenerator#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
public void init( ChangeLog changeLog )
{
setQuoteDate(changeLog.getQuoteDate());
super.init(changeLog);
setQuoteDate( changeLog.getQuoteDate() );
super.init( changeLog );
}
/**
* Execute cvslib client driving the given parser. @todo Currently the
* output from the logListener is a String, which is then converted to an
* InputStream. The output of logListener really should be an input stream.
*
* @param parser A {@link ChangeLogParser parser}to process the scm
* output.
* @return A collection of {@link ChangeLogEntry entries}parsed from the
* scm output.
* @throws IOException When there are issues executing scm.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries(ChangeLogParser parser) throws IOException
* Execute cvslib client driving the given parser. @todo Currently the
* output from the logListener is a String, which is then converted to an
* InputStream. The output of logListener really should be an input stream.
*
* @param parser A {@link ChangeLogParser parser}to process the scm
* output.
* @return A collection of {@link ChangeLogEntry entries}parsed from the
* scm output.
* @throws IOException When there are issues executing scm.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries( ChangeLogParser parser )
throws IOException
{
if (parser == null)
if ( parser == null )
{
throw new NullPointerException("parser cannot be null");
throw new NullPointerException( "parser cannot be null" );
}
if (base == null)
if ( base == null )
{
throw new NullPointerException("basedir must be set");
throw new NullPointerException( "basedir must be set" );
}
if (!base.exists())
if ( !base.exists() )
{
throw new FileNotFoundException(
"Cannot find base dir " + base.getAbsolutePath());
throw new FileNotFoundException( "Cannot find base dir "
+ base.getAbsolutePath() );
}
clParser = parser;
String[] args = getScmLogCommand().getArguments();
CvsLogListener logListener = new CvsLogListener();
try
{
CvsConnection.processCommand(
args,
this.changeLogExecutor.getBasedir().toString(),
logListener);
CvsConnection.processCommand( args,
this.changeLogExecutor.getBasedir().toString(), logListener );
entries =
clParser.parse(
new ByteArrayInputStream(
logListener.getStdout().toString().getBytes()));
clParser.parse( new ByteArrayInputStream(
logListener.getStdout().toString().getBytes() ) );
}
catch (IllegalArgumentException iae)
catch ( IllegalArgumentException iae )
{
entries = super.getEntries(parser);
entries = super.getEntries( parser );
}
catch (Exception e){
LOG.error("Error processing command", e);
catch ( Exception e )
{
LOG.error( "Error processing command", e );
}
return entries;
}
/**
* @return the cvs command line to be executed.
*/
* @return the cvs command line to be executed.
*/
protected Commandline getScmLogCommand()
{
String tokens[] = RepositoryUtils.splitSCMConnection(getConnection());
String[] tokens =
RepositoryUtils.splitSCMConnection( getConnection() );
if (!tokens[POS_SCM_TYPE].equals("cvs"))
if ( !tokens[POS_SCM_TYPE].equals( "cvs" ) )
{
throw new IllegalArgumentException(
"repository connection string"
+ " does not specify 'cvs' as the scm"
+ System.getProperty("line.separator")
+ "If using another scm, maven.changelog.factory"
+ " must be set."
+ System.getProperty("line.separator")
+ "See the maven changelog plugin documentation"
+ " for correct settings." );
throw new IllegalArgumentException( "repository connection string"
+ " does not specify 'cvs' as the scm"
+ System.getProperty( "line.separator" )
+ "If using another scm, maven.changelog.factory"
+ " must be set." + System.getProperty( "line.separator" )
+ "See the maven changelog plugin documentation"
+ " for correct settings." );
}
Commandline command = new Commandline();
command.setExecutable("cvs");
command.createArgument().setValue("-d");
command.setExecutable( "cvs" );
command.createArgument().setValue( "-d" );
// from format:
// scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-turbine-maven/src/plugins-build/changelog/
// to format:
@@ -184,12 +182,12 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
// use tokens 3+4+5
String connectionBuffer = "";
if (tokens[POS_SCM_SUBTYPE].equalsIgnoreCase("local"))
if ( tokens[POS_SCM_SUBTYPE].equalsIgnoreCase( "local" ) )
{
// use the local repository directory eg. '/home/cvspublic'
connectionBuffer = tokens[POS_SCM_PATH];
}
else if (tokens[POS_SCM_SUBTYPE].equalsIgnoreCase("lserver"))
else if ( tokens[POS_SCM_SUBTYPE].equalsIgnoreCase( "lserver" ) )
{
//create the cvsroot as the local socket cvsroot
connectionBuffer =
@@ -199,71 +197,71 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
{
//create the cvsroot as the remote cvsroot
connectionBuffer =
":"
+ tokens[POS_SCM_SUBTYPE]
+ ":"
+ tokens[POS_SCM_USERHOST]
+ ":"
+ tokens[POS_SCM_PATH];
":" + tokens[POS_SCM_SUBTYPE] + ":" + tokens[POS_SCM_USERHOST]
+ ":" + tokens[POS_SCM_PATH];
}
command.createArgument().setValue(connectionBuffer.toString());
command.createArgument().setValue("log");
command.createArgument().setValue( connectionBuffer.toString() );
command.createArgument().setValue( "log" );
if (dateRange != null)
if ( dateRange != null )
{
command.createArgument().setValue(dateRange);
command.createArgument().setValue( dateRange );
}
else if (tag != null)
else if ( tag != null )
{
command.createArgument().setValue(tag);
command.createArgument().setValue( tag );
}
return command;
}
/**
* Construct the CVS command-line argument that is used to specify the
* appropriate date range.
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm system.
*/
protected String getScmDateArgument(Date before, Date to)
* Construct the CVS command-line argument that is used to specify the
* appropriate date range.
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm system.
*/
protected String getScmDateArgument( Date before, Date to )
{
SimpleDateFormat outputDate = new SimpleDateFormat("yyyy-MM-dd");
String cmd = outputDate.format(before) + "<" + outputDate.format(to);
SimpleDateFormat outputDate = new SimpleDateFormat( "yyyy-MM-dd" );
String cmd =
outputDate.format( before ) + "<" + outputDate.format( to );
if ( getQuoteDate() )
{
cmd = "\"" + cmd + "\"";
}
return "-d " + cmd;
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
return "-r" + tagStart + "::" + (tagEnd != null ? tagEnd : "");
}
/**
* Handle ChangeLogParser IOExceptions.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the exception.
*/
protected void handleParserException(IOException ioe) throws IOException
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument( String tagStart, String tagEnd )
{
if (ioe.getMessage().indexOf("CreateProcess") != -1
|| ioe.getMessage().indexOf("cvs: not found") != -1)
return "-r" + tagStart + "::" + ( ( tagEnd != null ) ? tagEnd : "" );
}
/**
* Handle ChangeLogParser IOExceptions.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the exception.
*/
protected void handleParserException( IOException ioe )
throws IOException
{
if ( ( ioe.getMessage().indexOf( "CreateProcess" ) != -1 )
|| ( ioe.getMessage().indexOf( "cvs: not found" ) != -1 ) )
{
// can't find CVS on Win32 or Linux...
if (LOG.isWarnEnabled())
if ( LOG.isWarnEnabled() )
{
LOG.warn(
LOG.warn(
"Unable to find cvs executable. Please check that it is in your path, and avoid using spaces in the path name. Changelog will be empty" );
}
}
@@ -274,43 +272,43 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
}
/**
* Set the error stream for reading from cvs log. This stream will be read
* on a separate thread.
*
* @param is - an {@link java.io.InputStream}
*/
public void setProcessErrorStream(InputStream is)
* Set the error stream for reading from cvs log. This stream will be read
* on a separate thread.
*
* @param is - an {@link java.io.InputStream}
*/
public void setProcessErrorStream( InputStream is )
{
errorReader = new CvsAsyncErrorReader(is);
errorReader = new CvsAsyncErrorReader( is );
}
/**
* A private AsyncStreamReader class that "swallows" the "cvs server:
* Logging" lines.
*/
* A private AsyncStreamReader class that "swallows" the "cvs server:
* Logging" lines.
*/
private static class CvsAsyncErrorReader extends AsyncStreamReader
{
/**
* The obvious constructor.
*
* @param anInputStream the input stream to consume
*/
public CvsAsyncErrorReader(InputStream anInputStream)
* The obvious constructor.
*
* @param anInputStream the input stream to consume
*/
public CvsAsyncErrorReader( InputStream anInputStream )
{
super(anInputStream);
super( anInputStream );
}
/**
* If the line does not start with "cvs server: Logging", it's ok to
* consume it.
*
* @param line the line to check
* @return <code>true</code> if the line does not start with "cvs
* server: Logging"
*/
protected boolean okToConsume(String line)
* If the line does not start with "cvs server: Logging", it's ok to
* consume it.
*
* @param line the line to check
* @return <code>true</code> if the line does not start with "cvs
* server: Logging"
*/
protected boolean okToConsume( String line )
{
return !line.startsWith("cvs server: Logging");
return !line.startsWith( "cvs server: Logging" );
}
}
}
@@ -18,11 +18,13 @@ package org.apache.maven.cvslib;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -31,9 +33,10 @@ import java.util.StringTokenizer;
import java.util.TreeMap;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
/**
* A class to parse cvs log output
@@ -43,58 +46,67 @@ import org.apache.maven.changelog.ChangeLogFile;
*/
class CvsChangeLogParser implements ChangeLogParser
{
/**
* Old formatter used to parse CVS date/timestamp.
*/
private static final SimpleDateFormat OLD_CVS_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
/**
* New formatter used to parse CVS date/timestamp.
*/
private static final SimpleDateFormat NEW_CVS_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss Z" );
/**
* Custom date/time formatter. Rounds ChangeLogEntry times to the nearest
* minute.
*/
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyyMMddHHmm");
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat( "yyyyMMddHHmm" );
// state machine constants for reading cvs output
/** expecting file information */
private static final int GET_FILE = 1;
/** expecting date */
private static final int GET_DATE = 2;
/** expecting comments */
private static final int GET_COMMENT = 3;
/** expecting revision */
private static final int GET_REVISION = 4;
/** Marks start of file data*/
private static final String START_FILE = "Working file: ";
/** Marks end of file */
private static final String END_FILE = "==================================="
private static final String END_FILE =
"==================================="
+ "==========================================";
/** Marks start of revision */
private static final String START_REVISION = "----------------------------";
/** Marks revision data */
private static final String REVISION_TAG = "revision ";
/** Marks date data */
private static final String DATE_TAG = "date: ";
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap( Collections.reverseOrder() );
/** current status of the parser */
private int status = GET_FILE;
/** the current log entry being processed by the parser*/
private ChangeLogEntry currentLogEntry = null;
/** the current file being processed by the parser */
private ChangeLogFile currentFile = null;
@@ -109,29 +121,30 @@ class CvsChangeLogParser implements ChangeLogParser
* initialize the parser from the change log
* @param changeLog the controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
*/
public void init( ChangeLog changeLog )
{
}
/**
* Clean up any parser resources
* @see ChangeLogParser#cleanup()
*/
*/
public void cleanup()
{
}
/**
* Parse the input stream into a collection.
* @param anInputStream an input stream containing cvs log output
* @return a collection of ChangeLogEntry's
* @throws IOException when there are errors reading the provided stream
*/
public Collection parse(InputStream anInputStream) throws IOException
public Collection parse( InputStream anInputStream )
throws IOException
{
BufferedReader stream = new BufferedReader(
new InputStreamReader(anInputStream));
BufferedReader stream =
new BufferedReader( new InputStreamReader( anInputStream ) );
// current state transitions in the state machine - starts with Get File
// Get File -> Get Revision
@@ -139,30 +152,39 @@ class CvsChangeLogParser implements ChangeLogParser
// Get Date -> Get Comment
// Get Comment -> Get Comment or Get Revision
String line = null;
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
switch (getStatus())
switch ( getStatus() )
{
case GET_FILE:
processGetFile(line);
break;
case GET_REVISION:
processGetRevision(line);
break;
case GET_DATE:
processGetDate(line);
break;
case GET_COMMENT:
processGetComment(line);
break;
default:
throw new IllegalStateException("Unknown state: " + status);
case GET_FILE :
processGetFile( line );
break;
case GET_REVISION :
processGetRevision( line );
break;
case GET_DATE :
processGetDate( line );
break;
case GET_COMMENT :
processGetComment( line );
break;
default :
throw new IllegalStateException( "Unknown state: " + status );
}
}
return entries.values();
}
}
/**
* Add a change log entry to the list (if it's not already there)
* with the given file.
@@ -171,41 +193,43 @@ class CvsChangeLogParser implements ChangeLogParser
* is null, the entry wont be added
* @param file a {@link ChangeLogFile} to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file)
private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
{
// do not add if entry is not populated
if (entry.getAuthor() == null)
if ( entry.getAuthor() == null )
{
return;
}
String key = ENTRY_KEY_TIMESTAMP_FORMAT.format(entry.getDate())
String key =
ENTRY_KEY_TIMESTAMP_FORMAT.format( entry.getDate() )
+ entry.getAuthor() + entry.getComment();
if (!entries.containsKey(key))
if ( !entries.containsKey( key ) )
{
entry.addFile(file);
entries.put(key, entry);
entry.addFile( file );
entries.put( key, entry );
}
else
{
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
existingEntry.addFile( file );
}
}
/**
* Process the current input line in the Get File state.
* @param line a line of text from the cvs log output
*/
private void processGetFile(String line)
private void processGetFile( String line )
{
if (line.startsWith(START_FILE))
if ( line.startsWith( START_FILE ) )
{
setCurrentLogEntry(new ChangeLogEntry());
setCurrentFile(new ChangeLogFile(line.substring(START_FILE.length(),
line.length())));
setStatus(GET_REVISION);
setCurrentLogEntry( new ChangeLogEntry() );
setCurrentFile( new ChangeLogFile( line.substring(
START_FILE.length(), line.length() ) ) );
setStatus( GET_REVISION );
}
}
@@ -213,20 +237,21 @@ class CvsChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Revision state.
* @param line a line of text from the cvs log output
*/
private void processGetRevision(String line)
private void processGetRevision( String line )
{
if (line.startsWith(REVISION_TAG))
if ( line.startsWith( REVISION_TAG ) )
{
getCurrentFile().setRevision(line.substring(REVISION_TAG.length()));
setStatus(GET_DATE);
getCurrentFile().setRevision( line.substring(
REVISION_TAG.length() ) );
setStatus( GET_DATE );
}
else if (line.startsWith(END_FILE))
else if ( line.startsWith( END_FILE ) )
{
// If we encounter an end of file line, it means there
// are no more revisions for the current file.
// there could also be a file still being processed.
setStatus(GET_FILE);
addEntry(getCurrentLogEntry(), getCurrentFile());
setStatus( GET_FILE );
addEntry( getCurrentLogEntry(), getCurrentFile() );
}
}
@@ -234,50 +259,57 @@ class CvsChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Date state.
* @param line a line of text from the cvs log output
*/
private void processGetDate(String line)
private void processGetDate( String line )
{
if (line.startsWith(DATE_TAG))
if ( line.startsWith( DATE_TAG ) )
{
//date: YYYY/mm/dd HH:mm:ss; author: name
//or date: YYYY-mm-dd HH:mm:ss Z; author: name
StringTokenizer tokenizer = new StringTokenizer(line, ";");
StringTokenizer tokenizer = new StringTokenizer( line, ";" );
String dateToken = tokenizer.nextToken();
String dateString =
dateToken.trim().substring("date: ".length()).trim();
getCurrentLogEntry().setDate(parseDate(dateString));
String dateString =
dateToken.trim().substring( "date: ".length() ).trim();
getCurrentLogEntry().setDate( parseDate( dateString ) );
String authorToken = tokenizer.nextToken();
String author =
authorToken.trim().substring("author: ".length()).trim();
getCurrentLogEntry().setAuthor(author);
setStatus(GET_COMMENT);
String author =
authorToken.trim().substring( "author: ".length() ).trim();
getCurrentLogEntry().setAuthor( author );
setStatus( GET_COMMENT );
}
}
/**
* Tries to parse the given String according to all known CVS timeformats.
*
*
* @param dateString String to parse
* @return <code>java.util.Date</code> representing the time.
* @throws IllegalArgumentException if it's not possible to parse the date.
*/
private Date parseDate(String dateString)
private Date parseDate( String dateString )
{
Date date;
try
{
date = OLD_CVS_TIMESTAMP_FORMAT.parse(dateString);
date = OLD_CVS_TIMESTAMP_FORMAT.parse( dateString );
}
catch (ParseException e)
catch ( ParseException e )
{
//try other format
try {
date = NEW_CVS_TIMESTAMP_FORMAT.parse(dateString);
} catch (ParseException e1) {
throw new IllegalArgumentException("I don't understand this date: "
+ dateString);
try
{
date = NEW_CVS_TIMESTAMP_FORMAT.parse( dateString );
}
catch ( ParseException e1 )
{
throw new IllegalArgumentException(
"I don't understand this date: " + dateString );
}
}
return date;
}
@@ -285,28 +317,31 @@ class CvsChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Comment state.
* @param line a line of text from the cvs log output
*/
private void processGetComment(String line)
private void processGetComment( String line )
{
if (line.startsWith(START_REVISION))
if ( line.startsWith( START_REVISION ) )
{
// add entry, and set state to get revision
addEntry(getCurrentLogEntry(), getCurrentFile());
addEntry( getCurrentLogEntry(), getCurrentFile() );
// new change log entry
setCurrentLogEntry(new ChangeLogEntry());
setCurrentLogEntry( new ChangeLogEntry() );
// same file name, but different rev
setCurrentFile(new ChangeLogFile(getCurrentFile().getName()));
setStatus(GET_REVISION);
setCurrentFile( new ChangeLogFile( getCurrentFile().getName() ) );
setStatus( GET_REVISION );
}
else if (line.startsWith(END_FILE))
else if ( line.startsWith( END_FILE ) )
{
addEntry(getCurrentLogEntry(), getCurrentFile());
setStatus(GET_FILE);
addEntry( getCurrentLogEntry(), getCurrentFile() );
setStatus( GET_FILE );
}
else
{
// keep gathering comments
getCurrentLogEntry().setComment(
getCurrentLogEntry().getComment() + line + "\n");
getCurrentLogEntry().setComment( getCurrentLogEntry()
.getComment() + line
+ "\n" );
}
}
@@ -318,16 +353,16 @@ class CvsChangeLogParser implements ChangeLogParser
{
return currentFile;
}
/**
* Setter for property currentFile.
* @param currentFile New value of property currentFile.
*/
private void setCurrentFile(ChangeLogFile currentFile)
private void setCurrentFile( ChangeLogFile currentFile )
{
this.currentFile = currentFile;
}
/**
* Getter for property currentLogEntry.
* @return Value of property currentLogEntry.
@@ -336,16 +371,16 @@ class CvsChangeLogParser implements ChangeLogParser
{
return currentLogEntry;
}
/**
* Setter for property currentLogEntry.
* @param currentLogEntry New value of property currentLogEntry.
*/
private void setCurrentLogEntry(ChangeLogEntry currentLogEntry)
private void setCurrentLogEntry( ChangeLogEntry currentLogEntry )
{
this.currentLogEntry = currentLogEntry;
}
/**
* Getter for property status.
* @return Value of property status.
@@ -354,12 +389,12 @@ class CvsChangeLogParser implements ChangeLogParser
{
return status;
}
/**
* Setter for property status.
* @param status New value of property status.
*/
private void setStatus(int status)
private void setStatus( int status )
{
this.status = status;
}
@@ -21,6 +21,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Vector;
import org.apache.commons.logging.Log;
@@ -42,16 +43,17 @@ import org.netbeans.lib.cvsclient.connection.PServerConnection;
import org.netbeans.lib.cvsclient.connection.StandardScrambler;
import org.netbeans.lib.cvsclient.event.CVSListener;
/**
* A Cvs connection that simulates a command line interface.
*
*
* @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
*/
public class CvsConnection
{
/** Log */
private static final Log LOG = LogFactory.getLog(CvsConnection.class);
private static final Log LOG = LogFactory.getLog( CvsConnection.class );
/**
* The path to the repository on the server
*/
@@ -80,27 +82,27 @@ public class CvsConnection
/**
* Execute a configured CVS command
*
*
* @param command the command to execute
* @throws CommandException if there is an error running the command
*/
public void executeCommand(Command command)
public void executeCommand( Command command )
throws CommandException, AuthenticationException
{
client.executeCommand(command, globalOptions);
client.executeCommand( command, globalOptions );
}
public void setRepository(String repository)
public void setRepository( String repository )
{
this.repository = repository;
}
public void setLocalPath(String localPath)
public void setLocalPath( String localPath )
{
this.localPath = localPath;
}
public void setGlobalOptions(GlobalOptions globalOptions)
public void setGlobalOptions( GlobalOptions globalOptions )
{
this.globalOptions = globalOptions;
}
@@ -108,54 +110,60 @@ public class CvsConnection
/**
* Creates the connection and the client and connects.
*/
private void connect(CVSRoot root, String password)
throws IllegalArgumentException, AuthenticationException, CommandAbortedException
private void connect( CVSRoot root, String password )
throws IllegalArgumentException, AuthenticationException,
CommandAbortedException
{
connection = ConnectionFactory.getConnection(root);
if (CVSRoot.METHOD_PSERVER.equals(root.getMethod()))
connection = ConnectionFactory.getConnection( root );
if ( CVSRoot.METHOD_PSERVER.equals( root.getMethod() ) )
{
((PServerConnection) connection).setEncodedPassword(password);
( (PServerConnection) connection ).setEncodedPassword( password );
}
connection.open();
client = new Client(connection, new StandardAdminHandler());
client.setLocalPath(localPath);
client = new Client( connection, new StandardAdminHandler() );
client.setLocalPath( localPath );
}
private void addListener(CVSListener listener)
private void addListener( CVSListener listener )
{
if (client != null)
if ( client != null )
{
// add a listener to the client
client.getEventManager().addCVSListener(listener);
client.getEventManager().addCVSListener( listener );
}
}
/**
* Obtain the CVS root, either from the -D option cvs.root or from the CVS
* directory
*
*
* @return the CVSRoot string
*/
private static String getCVSRoot(String workingDir)
private static String getCVSRoot( String workingDir )
{
String root = null;
BufferedReader r = null;
if (workingDir == null)
if ( workingDir == null )
{
workingDir = System.getProperty("user.dir");
workingDir = System.getProperty( "user.dir" );
}
try
{
File f = new File(workingDir);
File rootFile = new File(f, "CVS/Root");
if (rootFile.exists())
File f = new File( workingDir );
File rootFile = new File( f, "CVS/Root" );
if ( rootFile.exists() )
{
r = new BufferedReader(new FileReader(rootFile));
r = new BufferedReader( new FileReader( rootFile ) );
root = r.readLine();
}
}
catch (IOException e)
catch ( IOException e )
{
// ignore
}
@@ -163,46 +171,51 @@ public class CvsConnection
{
try
{
if (r != null)
if ( r != null )
{
r.close();
}
}
catch (IOException e)
catch ( IOException e )
{
System.err.println("Warning: could not close CVS/Root file!");
System.err.println( "Warning: could not close CVS/Root file!" );
}
}
if (root == null)
if ( root == null )
{
root = System.getProperty("cvs.root");
root = System.getProperty( "cvs.root" );
}
return root;
}
/**
* Process global options passed into the application
*
*
* @param args the argument list, complete
* @param globalOptions the global options structure that will be passed to
* the command
*/
private static int processGlobalOptions(
String[] args,
GlobalOptions globalOptions)
private static int processGlobalOptions( String[] args,
GlobalOptions globalOptions )
{
final String getOptString = globalOptions.getOptString();
GetOpt go = new GetOpt(args, getOptString);
GetOpt go = new GetOpt( args, getOptString );
int ch = -1;
while ((ch = go.getopt()) != GetOpt.optEOF)
while ( ( ch = go.getopt() ) != GetOpt.optEOF )
{
//System.out.println("Global option '"+((char) ch)+"',
// '"+go.optArgGet()+"'");
String arg = go.optArgGet();
boolean success =
globalOptions.setCVSCommand((char) ch, arg);
if (!success)
throw new IllegalArgumentException( "Failed to set CVS Command: -" + ch + " = " + arg );
boolean success = globalOptions.setCVSCommand( (char) ch, arg );
if ( !success )
{
throw new IllegalArgumentException(
"Failed to set CVS Command: -" + ch + " = " + arg );
}
}
return go.optIndexGet();
@@ -211,135 +224,151 @@ public class CvsConnection
/**
* Lookup the password in the .cvspass file. This file is looked for in the
* user.home directory if the option cvs.passfile is not set
*
*
* @param cvsRoot the CVS root for which the password is being searched
* @return the password, scrambled
*/
private static String lookupPassword(String cvsRoot)
private static String lookupPassword( String cvsRoot )
{
File passFile =
new File(
System.getProperty(
"cvs.passfile",
System.getProperty("user.home") + "/.cvspass"));
new File( System.getProperty( "cvs.passfile",
System.getProperty( "user.home" ) + "/.cvspass" ) );
BufferedReader reader = null;
String password = null;
try
{
reader = new BufferedReader(new FileReader(passFile));
password = processCvspass(cvsRoot, reader);
reader = new BufferedReader( new FileReader( passFile ) );
password = processCvspass( cvsRoot, reader );
}
catch (IOException e)
catch ( IOException e )
{
LOG.warn("Could not read password for '" + cvsRoot + "' from '" + passFile + "'", e);
LOG.warn( "Could not read password for '" + cvsRoot + "' from '"
+ passFile + "'", e );
return null;
}
finally
{
if (reader != null)
if ( reader != null )
{
try
{
reader.close();
}
catch (IOException e)
catch ( IOException e )
{
LOG.error("Warning: could not close password file.");
LOG.error( "Warning: could not close password file." );
}
}
}
if (password == null)
if ( password == null )
{
LOG.error("Didn't find password for CVSROOT '" + cvsRoot + "'.");
LOG.error( "Didn't find password for CVSROOT '" + cvsRoot + "'." );
}
return password;
}
/**
* Read in a list of return delimited lines from .cvspass and retreive
* the password. Return null if the cvsRoot can't be found.
*
* @param cvsRoot the CVS root for which the password is being searched
* @param reader A buffered reader of lines of cvspass information
* @return The password, or null if it can't be found.
* @throws IOException
*/
static String processCvspass(String cvsRoot, BufferedReader reader) throws IOException {
String line;
String password = null;
while ((line = reader.readLine()) != null)
{
if (line.startsWith("/"))
{
Vector cvspass = StringUtils.split(line, ' ');
String cvspassRoot = (String)cvspass.get(1);
if (compareCvsRoot(cvsRoot, cvspassRoot)) {
int index = line.indexOf(cvspassRoot) + cvspassRoot.length()+1;
password = line.substring(index);
break;
}
}
else if (line.startsWith(cvsRoot))
{
password = line.substring(cvsRoot.length() + 1);
break;
}
}
return password;
}
static boolean compareCvsRoot(String cvsRoot, String target)
*
* @param cvsRoot the CVS root for which the password is being searched
* @param reader A buffered reader of lines of cvspass information
* @return The password, or null if it can't be found.
* @throws IOException
*/
static String processCvspass( String cvsRoot, BufferedReader reader )
throws IOException
{
String s1 = completeCvsRootPort(cvsRoot);
String s2 = completeCvsRootPort(target);
if (s1 != null && s1.equals(s2))
String line;
String password = null;
while ( ( line = reader.readLine() ) != null )
{
if ( line.startsWith( "/" ) )
{
Vector cvspass = StringUtils.split( line, ' ' );
String cvspassRoot = (String) cvspass.get( 1 );
if ( compareCvsRoot( cvsRoot, cvspassRoot ) )
{
int index =
line.indexOf( cvspassRoot ) + cvspassRoot.length()
+ 1;
password = line.substring( index );
break;
}
}
else if ( line.startsWith( cvsRoot ) )
{
password = line.substring( cvsRoot.length() + 1 );
break;
}
}
return password;
}
static boolean compareCvsRoot( String cvsRoot, String target )
{
String s1 = completeCvsRootPort( cvsRoot );
String s2 = completeCvsRootPort( target );
if ( ( s1 != null ) && s1.equals( s2 ) )
{
return true;
}
return false;
}
private static String completeCvsRootPort(String cvsRoot)
private static String completeCvsRootPort( String cvsRoot )
{
String result = cvsRoot;
int idx = cvsRoot.indexOf(':');
for (int i=0; i < 2 && idx != -1; i++)
int idx = cvsRoot.indexOf( ':' );
for ( int i = 0; ( i < 2 ) && ( idx != -1 ); i++ )
{
idx = cvsRoot.indexOf(':', idx+1);
idx = cvsRoot.indexOf( ':', idx + 1 );
}
if (idx != -1 && cvsRoot.charAt(idx+1) == '/')
if ( ( idx != -1 ) && ( cvsRoot.charAt( idx + 1 ) == '/' ) )
{
StringBuffer sb = new StringBuffer();
sb.append(cvsRoot.substring(0, idx+1));
sb.append("2401");
sb.append(cvsRoot.substring(idx+1));
sb.append( cvsRoot.substring( 0, idx + 1 ) );
sb.append( "2401" );
sb.append( cvsRoot.substring( idx + 1 ) );
result = sb.toString();
}
return result;
return result;
}
/**
* Process the CVS command passed in args[] array with all necessary
* options. The only difference from main() method is, that this method
* does not exit the JVM and provides command output.
*
*
* @param args The command with options
*/
public static boolean processCommand(
String[] args,
String localPath,
CVSListener listener) throws Exception
public static boolean processCommand( String[] args, String localPath,
CVSListener listener )
throws Exception
{
// Set up the CVSRoot. Note that it might still be null after this
// call if the user has decided to set it with the -d command line
// global option
GlobalOptions globalOptions = new GlobalOptions();
globalOptions.setCVSRoot(getCVSRoot(localPath));
globalOptions.setCVSRoot( getCVSRoot( localPath ) );
// Set up any global options specified. These occur before the
// name of the command to run
@@ -347,37 +376,39 @@ public class CvsConnection
try
{
commandIndex = processGlobalOptions(args, globalOptions);
commandIndex = processGlobalOptions( args, globalOptions );
}
catch (IllegalArgumentException e)
catch ( IllegalArgumentException e )
{
LOG.error("Invalid argument: " + e);
LOG.error( "Invalid argument: " + e );
return false;
}
// if we don't have a CVS root by now, the user has messed up
if (globalOptions.getCVSRoot() == null)
if ( globalOptions.getCVSRoot() == null )
{
LOG.error(
"No CVS root is set. Check your <repository> information in the POM.");
LOG.error(
"No CVS root is set. Check your <repository> information in the POM." );
return false;
}
// parse the CVS root into its constituent parts
CVSRoot root = null;
final String cvsRoot = globalOptions.getCVSRoot();
try
{
root = CVSRoot.parse(cvsRoot);
root = CVSRoot.parse( cvsRoot );
}
catch (IllegalArgumentException e)
catch ( IllegalArgumentException e )
{
LOG.error(
"Incorrect format for CVSRoot: "
+ cvsRoot
+ "\nThe correct format is: "
+ "[:method:][[user][:password]@][hostname:[port]]/path/to/repository"
+ "\nwhere \"method\" is pserver.");
LOG.error( "Incorrect format for CVSRoot: " + cvsRoot
+ "\nThe correct format is: "
+ "[:method:][[user][:password]@][hostname:[port]]/path/to/repository"
+ "\nwhere \"method\" is pserver." );
return false;
}
@@ -385,58 +416,59 @@ public class CvsConnection
// this is not login, but a 'real' cvs command, so construct it,
// set the options, and then connect to the server and execute it
Command c = null;
try
{
c =
CommandFactory.getDefault().createCommand(
command,
args,
++commandIndex,
globalOptions,
localPath);
c = CommandFactory.getDefault().createCommand( command, args,
++commandIndex, globalOptions, localPath );
}
catch (IllegalArgumentException e)
catch ( IllegalArgumentException e )
{
LOG.error("Illegal argument: " + e.getMessage());
LOG.error( "Illegal argument: " + e.getMessage() );
return false;
}
String password = null;
if (CVSRoot.METHOD_PSERVER.equals(root.getMethod()))
if ( CVSRoot.METHOD_PSERVER.equals( root.getMethod() ) )
{
password = root.getPassword();
if (password != null)
if ( password != null )
{
password = StandardScrambler.getInstance().scramble(password);
password =
StandardScrambler.getInstance().scramble( password );
}
else
{
password = lookupPassword(cvsRoot);
if (password == null)
password = lookupPassword( cvsRoot );
if ( password == null )
{
password = StandardScrambler.getInstance().scramble("");
password = StandardScrambler.getInstance().scramble( "" );
// an empty password
}
}
}
CvsConnection cvsCommand = new CvsConnection();
cvsCommand.setGlobalOptions(globalOptions);
cvsCommand.setRepository(root.getRepository());
cvsCommand.setGlobalOptions( globalOptions );
cvsCommand.setRepository( root.getRepository() );
// the local path is just the path where we executed the
// command. This is the case for command-line CVS but not
// usually for GUI front-ends
cvsCommand.setLocalPath(localPath);
cvsCommand.connect(root, password);
cvsCommand.addListener(listener);
LOG.debug("Executing CVS command: " + c.getCVSCommand());
cvsCommand.executeCommand(c);
cvsCommand.setLocalPath( localPath );
cvsCommand.connect( root, password );
cvsCommand.addListener( listener );
LOG.debug( "Executing CVS command: " + c.getCVSCommand() );
cvsCommand.executeCommand( c );
return true;
}
}
@@ -20,10 +20,11 @@ package org.apache.maven.cvslib;
import org.netbeans.lib.cvsclient.event.CVSAdapter;
import org.netbeans.lib.cvsclient.event.MessageEvent;
/**
* A basic implementation of a CVS listener. It merely saves up
* into StringBuffers the stdout and stderr printstreams.
*
*
* @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
*/
public class CvsLogListener extends CVSAdapter
@@ -33,33 +34,32 @@ public class CvsLogListener extends CVSAdapter
private StringBuffer stderr = new StringBuffer();
/**
* Called when the server wants to send a message to be displayed to the
* user. The message is only for information purposes and clients can
* choose to ignore these messages if they wish.
*
* @param e the event
*/
public void messageSent(MessageEvent e)
* Called when the server wants to send a message to be displayed to the
* user. The message is only for information purposes and clients can
* choose to ignore these messages if they wish.
*
* @param e the event
*/
public void messageSent( MessageEvent e )
{
String line = e.getMessage();
StringBuffer stream = e.isError() ? stderr : stdout;
if (e.isTagged())
if ( e.isTagged() )
{
String message =
MessageEvent.parseTaggedMessage(taggedLine, e.getMessage());
if (message != null)
MessageEvent.parseTaggedMessage( taggedLine, e.getMessage() );
if ( message != null )
{
//stream.println(message);
stream.append(message+"\n");
stream.append( message + "\n" );
}
}
else
{
//stream.println(line);
stream.append(line+"\n");
stream.append( line + "\n" );
}
}
@@ -70,5 +70,4 @@ public class CvsLogListener extends CVSAdapter
{
return stdout;
}
}
}
@@ -21,6 +21,7 @@ import org.apache.maven.changelog.ChangeLogFactory;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides Perforce specific instances of the ChangeLogGenerator and
* ChangeLogParser interfaces.
@@ -37,7 +38,7 @@ import org.apache.maven.changelog.ChangeLogParser;
* instance. The portion of the URL following the host:port should
* match the FILESPEC in the repository connection element, sans the
* '...'. It must end with a '/'.
*
*
* For example,
* <pre>
* &lt;repository&gt;
@@ -51,7 +52,7 @@ import org.apache.maven.changelog.ChangeLogParser;
* </pre>
*
* @author <a href="mailto:jim@crossleys.org">Jim Crossley</a>
* @version $Id:
* @version $Id:
*/
public class PerforceChangeLogFactory implements ChangeLogFactory
{
@@ -61,7 +62,7 @@ public class PerforceChangeLogFactory implements ChangeLogFactory
public PerforceChangeLogFactory()
{
}
/**
* Create a Perforce specific ChangeLogGenerator.
*
@@ -81,4 +82,4 @@ public class PerforceChangeLogFactory implements ChangeLogFactory
{
return new PerforceChangeLogParser();
}
}
}
@@ -18,26 +18,30 @@ package org.apache.maven.perforcelib;
*/
import java.io.IOException;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.AbstractChangeLogGenerator;
import org.apache.tools.ant.types.Commandline;
/**
* A Perforce implementation of the {@link org.apache.maven.changelog.ChangeLog}
* interface.
*
* @author <a href="mailto:jim@crossleys.org">Jim Crossley</a>
* @version $Id:
* @version $Id:
*/
class PerforceChangeLogGenerator extends AbstractChangeLogGenerator
{
/** The position after the connection prefix, 'scm:perforce:' */
private static final int POS_PARAMS = 13;
/** Log */
private static final Log LOG = LogFactory.getLog(PerforceChangeLogGenerator.class);
/** Log */
private static final Log LOG =
LogFactory.getLog( PerforceChangeLogGenerator.class );
/**
* Constructs the appropriate command line to execute the perforce
@@ -48,61 +52,67 @@ class PerforceChangeLogGenerator extends AbstractChangeLogGenerator
*
* @return the cvs command line to be executed.
*/
protected Commandline getScmLogCommand()
protected Commandline getScmLogCommand()
{
String conn = getConnection();
if (!conn.startsWith("scm:perforce:"))
if ( !conn.startsWith( "scm:perforce:" ) )
{
throw new IllegalArgumentException(
"repository connection string"
+ " does not specify 'perforce' as the scm");
throw new IllegalArgumentException( "repository connection string"
+ " does not specify 'perforce' as the scm" );
}
int lastColon = conn.lastIndexOf(':');
String fileSpec = conn.substring(lastColon+1);
String p4port = (POS_PARAMS>lastColon) ? null : conn.substring(POS_PARAMS, lastColon);
int lastColon = conn.lastIndexOf( ':' );
String fileSpec = conn.substring( lastColon + 1 );
String p4port =
( POS_PARAMS > lastColon ) ? null
: conn.substring( POS_PARAMS, lastColon );
Commandline command = new Commandline();
command.setExecutable("p4");
if (p4port != null) {
command.createArgument().setValue("-p");
command.createArgument().setValue(p4port);
command.setExecutable( "p4" );
if ( p4port != null )
{
command.createArgument().setValue( "-p" );
command.createArgument().setValue( p4port );
}
command.createArgument().setValue("filelog");
command.createArgument().setValue("-tl");
command.createArgument().setValue(fileSpec);
command.createArgument().setValue( "filelog" );
command.createArgument().setValue( "-tl" );
command.createArgument().setValue( fileSpec );
return command;
}
/**
/**
* The Perforce filelog doesn't support a revision, i.e. date,
* range
*
*
* @param before The starting point.
* @param to The ending point.
* @return An empty string
*/
protected String getScmDateArgument(Date before, Date to)
protected String getScmDateArgument( Date before, Date to )
{
return "";
}
/**
* Handle ChangeLogParser IOExceptions.
*
/**
* Handle ChangeLogParser IOExceptions.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the
* exception.
*/
protected void handleParserException(IOException ioe)
protected void handleParserException( IOException ioe )
throws IOException
{
if (ioe.getMessage().indexOf("CreateProcess") != -1
|| ioe.getMessage().indexOf("p4: not found") != -1)
if ( ( ioe.getMessage().indexOf( "CreateProcess" ) != -1 )
|| ( ioe.getMessage().indexOf( "p4: not found" ) != -1 ) )
{
// can't find p4 on Win32 or Linux...
LOG.error(
"Unable to find p4 executable. Changelog will be empty");
LOG.error( "Unable to find p4 executable. Changelog will be empty" );
}
else
{
@@ -113,8 +123,9 @@ class PerforceChangeLogGenerator extends AbstractChangeLogGenerator
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Perforce.");
throw new UnsupportedOperationException(
"This plugin currently does not support generating logs from tags with Perforce." );
}
}
@@ -18,45 +18,45 @@ package org.apache.maven.perforcelib;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
/**
* A class to parse the log output from the Perforce 'filelog'
* command.
*
* @author <a href="mailto:jim@crossleys.org">Jim Crossley</a>
* @version $Id:
* @version $Id:
*/
class PerforceChangeLogParser implements ChangeLogParser
{
/** Date formatter for perforce timestamp */
private static final SimpleDateFormat PERFORCE_TIMESTAMP =
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
/** Log */
private static final Log LOG = LogFactory.getLog (PerforceChangeLogParser.class);
/**
* RCS entries, in reverse changelist number order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
/** Log */
private static final Log LOG =
LogFactory.getLog( PerforceChangeLogParser.class );
/** State machine constant: expecting revision and/or file information */
private static final int GET_REVISION = 1;
@@ -72,16 +72,26 @@ class PerforceChangeLogParser implements ChangeLogParser
/** A file line begins with two slashes */
private static final String FILE_BEGIN_TOKEN = "//";
private static final String pattern =
"^\\.\\.\\. #(\\d+) " // revision number
+ "change (\\d+) .* " // changelist number
+ "on (.*) " // date
+ "by (.*)@"; // author
/**
* RCS entries, in reverse changelist number order
*/
private Map entries = new TreeMap( Collections.reverseOrder() );
/** Current status of the parser */
private int status = GET_REVISION;
/** The current log entry being processed by the parser */
private ChangeLogEntry currentLogEntry;
/** the current file being processed by the parser */
private String currentFile;
/** The regular expression used to match header lines */
private RE revisionRegexp;
@@ -93,22 +103,20 @@ class PerforceChangeLogParser implements ChangeLogParser
/** The depot filespec will be stripped from each filename */
private int prefixLength;
private static final String pattern =
"^\\.\\.\\. #(\\d+) " + // revision number
"change (\\d+) .* " + // changelist number
"on (.*) " + // date
"by (.*)@"; // author
/**
/**
* Default constructor.
*/
public PerforceChangeLogParser()
{
try {
revisionRegexp = new RE(pattern);
} catch (RESyntaxException ignored) {
LOG.error("Could not create regexp to parse perforce log file", ignored);
try
{
revisionRegexp = new RE( pattern );
}
catch ( RESyntaxException ignored )
{
LOG.error( "Could not create regexp to parse perforce log file",
ignored );
}
}
@@ -117,25 +125,27 @@ class PerforceChangeLogParser implements ChangeLogParser
*
* @param changeLog The controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
*/
public void init( ChangeLog changeLog )
{
this.changeLog = changeLog;
setDateRange();
String conn = changeLog.getRepositoryConnection();
String filespec = conn.substring(conn.lastIndexOf(':')+1);
this.prefixLength = 1 + filespec.lastIndexOf ('/');
String filespec = conn.substring( conn.lastIndexOf( ':' ) + 1 );
this.prefixLength = 1 + filespec.lastIndexOf( '/' );
}
/**
* Clean up any parser resources.
*
* @see ChangeLogParser#cleanup()
*/
*/
public void cleanup()
{
}
/**
* Parse the input stream into a collection of entries
*
@@ -143,31 +153,41 @@ class PerforceChangeLogParser implements ChangeLogParser
* @return A collection of ChangeLogEntry's
* @throws IOException When there are errors reading the provided stream
*/
public Collection parse(InputStream anInputStream) throws IOException
public Collection parse( InputStream anInputStream )
throws IOException
{
BufferedReader stream = new BufferedReader(new InputStreamReader(anInputStream));
BufferedReader stream =
new BufferedReader( new InputStreamReader( anInputStream ) );
String line = null;
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
switch (status)
switch ( status )
{
case GET_REVISION:
processGetRevision(line);
break;
case GET_COMMENT_BEGIN:
status = GET_COMMENT;
break;
case GET_COMMENT:
processGetComment(line);
break;
default:
throw new IllegalStateException("Unknown state: " + status);
case GET_REVISION :
processGetRevision( line );
break;
case GET_COMMENT_BEGIN :
status = GET_COMMENT;
break;
case GET_COMMENT :
processGetComment( line );
break;
default :
throw new IllegalStateException( "Unknown state: " + status );
}
}
return entries.values();
}
}
/**
* Add a change log entry to the list (if it's not already there)
* with the given file.
@@ -175,43 +195,54 @@ class PerforceChangeLogParser implements ChangeLogParser
* with the same key (p4 change number) doesn't exist already.
* @param file a {@link ChangeLogFile} to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file)
private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
{
if (beforeDate != null) {
if (entry.getDate().before(beforeDate)) {
if ( beforeDate != null )
{
if ( entry.getDate().before( beforeDate ) )
{
return;
}
}
Integer key = new Integer(revisionRegexp.getParen(2));
if (!entries.containsKey(key)) {
entry.addFile(file);
entries.put(key, entry);
} else {
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
Integer key = new Integer( revisionRegexp.getParen( 2 ) );
if ( !entries.containsKey( key ) )
{
entry.addFile( file );
entries.put( key, entry );
}
else
{
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
existingEntry.addFile( file );
}
}
/**
* Most of the relevant info is on the revision line matching the
* 'pattern' string.
*
* @param line A line of text from the perforce log output
*/
private void processGetRevision(String line)
private void processGetRevision( String line )
{
if (line.startsWith(FILE_BEGIN_TOKEN)) {
currentFile = line.substring (this.prefixLength);
if ( line.startsWith( FILE_BEGIN_TOKEN ) )
{
currentFile = line.substring( this.prefixLength );
return;
}
if (!revisionRegexp.match(line)) {
if ( !revisionRegexp.match( line ) )
{
return;
}
currentLogEntry = new ChangeLogEntry();
currentLogEntry.setDate(parseDate(revisionRegexp.getParen(3)));
currentLogEntry.setAuthor(revisionRegexp.getParen(4));
currentLogEntry.setDate( parseDate( revisionRegexp.getParen( 3 ) ) );
currentLogEntry.setAuthor( revisionRegexp.getParen( 4 ) );
status = GET_COMMENT_BEGIN;
}
@@ -222,29 +253,38 @@ class PerforceChangeLogParser implements ChangeLogParser
*
* @param line a line of text from the perforce log output
*/
private void processGetComment(String line)
private void processGetComment( String line )
{
if (line.equals(COMMENT_DELIMITER)) {
addEntry(currentLogEntry, new ChangeLogFile(currentFile, revisionRegexp.getParen(1)));
if ( line.equals( COMMENT_DELIMITER ) )
{
addEntry( currentLogEntry,
new ChangeLogFile( currentFile, revisionRegexp.getParen( 1 ) ) );
status = GET_REVISION;
} else {
currentLogEntry.setComment(currentLogEntry.getComment() + line + "\n");
}
else
{
currentLogEntry.setComment( currentLogEntry.getComment() + line
+ "\n" );
}
}
/**
/**
* Converts the date timestamp from the perforce output into a date
* object.
*
*
* @return A date representing the timestamp of the log entry.
*/
private Date parseDate(String date)
private Date parseDate( String date )
{
try {
return PERFORCE_TIMESTAMP.parse(date);
} catch (ParseException e) {
LOG.error("ParseException Caught", e);
return null;
try
{
return PERFORCE_TIMESTAMP.parse( date );
}
catch ( ParseException e )
{
LOG.error( "ParseException Caught", e );
return null;
}
}
@@ -257,14 +297,18 @@ class PerforceChangeLogParser implements ChangeLogParser
*/
private void setDateRange()
{
if (this.changeLog == null ||
this.changeLog.getRange() == null ||
this.changeLog.getRange().length() == 0)
if ( ( this.changeLog == null )
|| ( this.changeLog.getRange() == null )
|| ( this.changeLog.getRange().length() == 0 ) )
{
return;
}
int days = Integer.parseInt(this.changeLog.getRange());
beforeDate = new Date(System.currentTimeMillis() - (long) days * 24 * 60 * 60 * 1000);
int days = Integer.parseInt( this.changeLog.getRange() );
beforeDate =
new Date( System.currentTimeMillis()
- ( (long) days * 24 * 60 * 60 * 1000 ) );
}
public void setDateFormatInFile( String dateFormat )
@@ -21,6 +21,7 @@ import org.apache.maven.changelog.ChangeLogFactory;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides Starteam specific instances of the ChangeLogGenerator and
* ChangeLogParser interfaces.
@@ -36,7 +37,7 @@ public class StarteamChangeLogFactory implements ChangeLogFactory
public StarteamChangeLogFactory()
{
}
/**
* Create a Starteam specific ChangeLogGenerator.
*
@@ -18,15 +18,20 @@ package org.apache.maven.starteamlib;
*/
import java.io.IOException;
import java.util.Date;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// maven imports
import org.apache.maven.changelog.AbstractChangeLogGenerator;
// ant imports
import org.apache.tools.ant.types.Commandline;
/**
* A Starteam implementation of the {@link org.apache.maven.changelog.ChangeLog}
* interface.
@@ -37,44 +42,47 @@ import org.apache.tools.ant.types.Commandline;
class StarteamChangeLogGenerator extends AbstractChangeLogGenerator
{
/** Log */
private static final Log LOG = LogFactory.getLog(
StarteamChangeLogGenerator.class);
private static final Log LOG =
LogFactory.getLog( StarteamChangeLogGenerator.class );
/**
* Constructs the appropriate command line to execute the starteam
* log command whose output is then later parsed.
*
* @return the starteam command line to be executed.
*/
protected Commandline getScmLogCommand()
protected Commandline getScmLogCommand()
{
Commandline command = new Commandline();
command.setExecutable("stcmd");
command.createArgument().setValue("hist");
command.createArgument().setValue("-x");
command.createArgument().setValue("-nologo");
command.createArgument().setValue("-is");
command.createArgument().setValue("-p");
command.setExecutable( "stcmd" );
command.createArgument().setValue( "hist" );
command.createArgument().setValue( "-x" );
command.createArgument().setValue( "-nologo" );
command.createArgument().setValue( "-is" );
command.createArgument().setValue( "-p" );
String repo = changeLogExecutor.getRepositoryConnection();
if ("starteam".equals(repo.substring(4, 12)))
if ( "starteam".equals( repo.substring( 4, 12 ) ) )
{
repo = repo.substring(13);
command.createArgument().setValue(repo);
repo = repo.substring( 13 );
command.createArgument().setValue( repo );
}
return command;
}
/**
/**
* Construct the Starteam command-line argument that is used to specify
* the appropriate date range. This date option doesn't supported with
* Starteam
*
*
* @param before The starting point.
* @param to The ending point.
* @return An empty string
*/
protected String getScmDateArgument(Date before, Date to)
protected String getScmDateArgument( Date before, Date to )
{
return "";
}
@@ -82,27 +90,29 @@ class StarteamChangeLogGenerator extends AbstractChangeLogGenerator
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Starteam.");
throw new UnsupportedOperationException(
"This plugin currently does not support generating logs from tags with Starteam." );
}
/**
* Handle ChangeLogParser IOExceptions.
*
/**
* Handle ChangeLogParser IOExceptions.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the
* exception.
*/
protected void handleParserException(IOException ioe)
protected void handleParserException( IOException ioe )
throws IOException
{
if (ioe.getMessage().indexOf("CreateProcess") != -1
|| ioe.getMessage().indexOf("Starteam: not found") != -1)
if ( ( ioe.getMessage().indexOf( "CreateProcess" ) != -1 )
|| ( ioe.getMessage().indexOf( "Starteam: not found" ) != -1 ) )
{
// can't find Starteam on Win32 or Linux...
LOG.error(
"Unable to find Starteam executable. Changelog will be empty("+ioe+")");
LOG.error(
"Unable to find Starteam executable. Changelog will be empty("
+ ioe + ")" );
}
else
{
@@ -18,24 +18,27 @@ package org.apache.maven.starteamlib;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
/**
* A class to parse starteam log output
@@ -49,48 +52,59 @@ class StarteamChangeLogParser implements ChangeLogParser
* Custom date/time formatter. Rounds ChangeLogEntry times to the nearest
* minute.
*/
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyyMMddHHmm");
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat( "yyyyMMddHHmm" );
/** Log */
private static final Log LOG =
LogFactory.getLog( StarteamChangeLogGenerator.class );
// state machine constants for reading Starteam output
/** expecting file information */
private static final int GET_FILE = 1;
/** expecting date */
private static final int GET_AUTHOR = 2;
/** expecting comments */
private static final int GET_COMMENT = 3;
/** expecting revision */
private static final int GET_REVISION = 4;
/** Marks start of file data*/
private static final String START_FILE = "History for: ";
/** Marks end of file */
private static final String END_FILE =
"==================================="
+ "==========================================";
/** Marks start of revision */
private static final String START_REVISION = "----------------------------";
/** Marks revision data */
private static final String REVISION_TAG = "Branch Revision: ";
/** Marks author data */
private static final String AUTHOR_TAG = "Author: ";
/** Marks date data */
private static final String DATE_TAG = " Date: ";
private SimpleDateFormat localFormat = new SimpleDateFormat();
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
/** Log */
private static final Log LOG = LogFactory.getLog(
StarteamChangeLogGenerator.class);
// state machine constants for reading Starteam output
/** expecting file information */
private static final int GET_FILE = 1;
/** expecting date */
private static final int GET_AUTHOR = 2;
/** expecting comments */
private static final int GET_COMMENT = 3;
/** expecting revision */
private static final int GET_REVISION = 4;
/** Marks start of file data*/
private static final String START_FILE = "History for: ";
/** Marks end of file */
private static final String END_FILE = "==================================="
+ "==========================================";
/** Marks start of revision */
private static final String START_REVISION = "----------------------------";
/** Marks revision data */
private static final String REVISION_TAG = "Branch Revision: ";
/** Marks author data */
private static final String AUTHOR_TAG = "Author: ";
/** Marks date data */
private static final String DATE_TAG = " Date: ";
private Map entries = new TreeMap( Collections.reverseOrder() );
/** current status of the parser */
private int status = GET_FILE;
/** the current log entry being processed by the parser*/
private ChangeLogEntry currentLogEntry = null;
/** the current file being processed by the parser */
private ChangeLogFile currentFile = null;
@@ -117,25 +131,27 @@ class StarteamChangeLogParser implements ChangeLogParser
* initialize the parser from the change log
* @param changeLog the controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
*/
public void init( ChangeLog changeLog )
{
this.changeLog = changeLog;
if (changeLog.getRange() != null &&
changeLog.getRange().length() != 0)
if ( ( changeLog.getRange() != null )
&& ( changeLog.getRange().length() != 0 ) )
{
setDateRange(changeLog.getRange());
setDateRange( changeLog.getRange() );
}
if (changeLog.getDateFormat() != null)
if ( changeLog.getDateFormat() != null )
{
localFormat = new SimpleDateFormat(changeLog.getDateFormat());
localFormat = new SimpleDateFormat( changeLog.getDateFormat() );
}
}
/**
* Clean up any parser resources
* @see ChangeLogParser#cleanup()
*/
*/
public void cleanup()
{
}
@@ -156,17 +172,18 @@ class StarteamChangeLogParser implements ChangeLogParser
{
localFormat = new SimpleDateFormat( dateFormat );
}
/**
* Parse the input stream into a collection.
* @param anInputStream an input stream containing Starteam log output
* @return a collection of ChangeLogEntry's
* @throws IOException when there are errors reading the provided stream
*/
public Collection parse(InputStream anInputStream) throws IOException
public Collection parse( InputStream anInputStream )
throws IOException
{
BufferedReader stream = new BufferedReader(
new InputStreamReader(anInputStream));
BufferedReader stream =
new BufferedReader( new InputStreamReader( anInputStream ) );
// current state transitions in the state machine - starts with Get File
// Get File -> Get Revision
@@ -174,30 +191,39 @@ class StarteamChangeLogParser implements ChangeLogParser
// Get Date -> Get Comment
// Get Comment -> Get Comment or Get Revision
String line = null;
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
switch (getStatus())
switch ( getStatus() )
{
case GET_FILE:
processGetFile(line);
break;
case GET_REVISION:
processGetRevision(line);
break;
case GET_AUTHOR:
processGetAuthor(line);
break;
case GET_COMMENT:
processGetComment(line);
break;
default:
throw new IllegalStateException("Unknown state: " + status);
case GET_FILE :
processGetFile( line );
break;
case GET_REVISION :
processGetRevision( line );
break;
case GET_AUTHOR :
processGetAuthor( line );
break;
case GET_COMMENT :
processGetComment( line );
break;
default :
throw new IllegalStateException( "Unknown state: " + status );
}
}
return entries.values();
}
}
/**
* Add a change log entry to the list (if it's not already there)
* with the given file.
@@ -206,53 +232,56 @@ class StarteamChangeLogParser implements ChangeLogParser
* is null, the entry wont be added
* @param file a {@link ChangeLogFile} to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file)
private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
{
// do not add if entry is not populated
if (entry.getAuthor() == null)
if ( entry.getAuthor() == null )
{
return;
}
// do not add if entry is out of date range
if (!testMode)
if ( !testMode )
{
if (beforeDate != null && toDate != null)
if ( ( beforeDate != null ) && ( toDate != null ) )
{
if (entry.getDate().before(beforeDate) || entry.getDate().after(toDate))
if ( entry.getDate().before( beforeDate )
|| entry.getDate().after( toDate ) )
{
return;
}
}
}
String key = ENTRY_KEY_TIMESTAMP_FORMAT.format(entry.getDate())
String key =
ENTRY_KEY_TIMESTAMP_FORMAT.format( entry.getDate() )
+ entry.getAuthor() + entry.getComment();
if (!entries.containsKey(key))
if ( !entries.containsKey( key ) )
{
entry.addFile(file);
entries.put(key, entry);
entry.addFile( file );
entries.put( key, entry );
}
else
{
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
existingEntry.addFile( file );
}
}
/**
* Process the current input line in the Get File state.
* @param line a line of text from the Starteam log output
*/
private void processGetFile(String line)
private void processGetFile( String line )
{
if (line.startsWith(START_FILE))
if ( line.startsWith( START_FILE ) )
{
setCurrentLogEntry(new ChangeLogEntry());
setCurrentFile(new ChangeLogFile(line.substring(START_FILE.length(),
line.length())));
setStatus(GET_REVISION);
setCurrentLogEntry( new ChangeLogEntry() );
setCurrentFile( new ChangeLogFile( line.substring(
START_FILE.length(), line.length() ) ) );
setStatus( GET_REVISION );
}
}
@@ -260,21 +289,23 @@ class StarteamChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Revision state.
* @param line a line of text from the Starteam log output
*/
private void processGetRevision(String line)
private void processGetRevision( String line )
{
int pos;
if ((pos=line.indexOf(REVISION_TAG)) != -1)
if ( ( pos = line.indexOf( REVISION_TAG ) ) != -1 )
{
getCurrentFile().setRevision(line.substring(pos + REVISION_TAG.length()));
setStatus(GET_AUTHOR);
getCurrentFile().setRevision( line.substring( pos
+ REVISION_TAG.length() ) );
setStatus( GET_AUTHOR );
}
else if (line.startsWith(END_FILE))
else if ( line.startsWith( END_FILE ) )
{
// If we encounter an end of file line, it means there
// are no more revisions for the current file.
// there could also be a file still being processed.
setStatus(GET_FILE);
addEntry(getCurrentLogEntry(), getCurrentFile());
setStatus( GET_FILE );
addEntry( getCurrentLogEntry(), getCurrentFile() );
}
}
@@ -282,16 +313,19 @@ class StarteamChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Author/Date state.
* @param line a line of text from the Starteam log output
*/
private void processGetAuthor(String line)
private void processGetAuthor( String line )
{
if (line.startsWith(AUTHOR_TAG))
if ( line.startsWith( AUTHOR_TAG ) )
{
int posDateTag = line.indexOf(DATE_TAG);
String author = line.substring(AUTHOR_TAG.length(), posDateTag);
getCurrentLogEntry().setAuthor(author);
String date = line.substring(posDateTag + DATE_TAG.length());
getCurrentLogEntry().setDate(parseDate(date));
setStatus(GET_COMMENT);
int posDateTag = line.indexOf( DATE_TAG );
String author = line.substring( AUTHOR_TAG.length(), posDateTag );
getCurrentLogEntry().setAuthor( author );
String date = line.substring( posDateTag + DATE_TAG.length() );
getCurrentLogEntry().setDate( parseDate( date ) );
setStatus( GET_COMMENT );
}
}
@@ -299,28 +333,31 @@ class StarteamChangeLogParser implements ChangeLogParser
* Process the current input line in the Get Comment state.
* @param line a line of text from the Starteam log output
*/
private void processGetComment(String line)
private void processGetComment( String line )
{
if (line.startsWith(START_REVISION))
if ( line.startsWith( START_REVISION ) )
{
// add entry, and set state to get revision
addEntry(getCurrentLogEntry(), getCurrentFile());
addEntry( getCurrentLogEntry(), getCurrentFile() );
// new change log entry
setCurrentLogEntry(new ChangeLogEntry());
setCurrentLogEntry( new ChangeLogEntry() );
// same file name, but different rev
setCurrentFile(new ChangeLogFile(getCurrentFile().getName()));
setStatus(GET_REVISION);
setCurrentFile( new ChangeLogFile( getCurrentFile().getName() ) );
setStatus( GET_REVISION );
}
else if (line.startsWith(END_FILE))
else if ( line.startsWith( END_FILE ) )
{
addEntry(getCurrentLogEntry(), getCurrentFile());
setStatus(GET_FILE);
addEntry( getCurrentLogEntry(), getCurrentFile() );
setStatus( GET_FILE );
}
else
{
// keep gathering comments
getCurrentLogEntry().setComment(
getCurrentLogEntry().getComment() + line + "\n");
getCurrentLogEntry().setComment( getCurrentLogEntry()
.getComment() + line
+ "\n" );
}
}
@@ -332,16 +369,16 @@ class StarteamChangeLogParser implements ChangeLogParser
{
return currentFile;
}
/**
* Setter for property currentFile.
* @param currentFile New value of property currentFile.
*/
private void setCurrentFile(ChangeLogFile currentFile)
private void setCurrentFile( ChangeLogFile currentFile )
{
this.currentFile = currentFile;
}
/**
* Getter for property currentLogEntry.
* @return Value of property currentLogEntry.
@@ -350,16 +387,16 @@ class StarteamChangeLogParser implements ChangeLogParser
{
return currentLogEntry;
}
/**
* Setter for property currentLogEntry.
* @param currentLogEntry New value of property currentLogEntry.
*/
private void setCurrentLogEntry(ChangeLogEntry currentLogEntry)
private void setCurrentLogEntry( ChangeLogEntry currentLogEntry )
{
this.currentLogEntry = currentLogEntry;
}
/**
* Getter for property status.
* @return Value of property status.
@@ -368,32 +405,33 @@ class StarteamChangeLogParser implements ChangeLogParser
{
return status;
}
/**
* Setter for property status.
* @param status New value of property status.
*/
private void setStatus(int status)
private void setStatus( int status )
{
this.status = status;
}
/**
/**
* Converts the date timestamp from the svn output into a date
* object.
*
*
* @return A date representing the timestamp of the log entry.
*/
private Date parseDate(String date)
private Date parseDate( String date )
{
try
{
return localFormat.parse(date.toString());
return localFormat.parse( date.toString() );
}
catch (ParseException e)
catch ( ParseException e )
{
LOG.error("ParseException Caught", e);
return null;
LOG.error( "ParseException Caught", e );
return null;
}
}
@@ -404,13 +442,15 @@ class StarteamChangeLogParser implements ChangeLogParser
* @param numDaysString The number of days of log output to
* generate.
*/
private void setDateRange(String numDaysString)
private void setDateRange( String numDaysString )
{
int days = Integer.parseInt(numDaysString);
int days = Integer.parseInt( numDaysString );
beforeDate = new Date(
System.currentTimeMillis() - (long) days * 24 * 60 * 60 * 1000);
toDate = new Date(
System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000);
beforeDate =
new Date( System.currentTimeMillis()
- ( (long) days * 24 * 60 * 60 * 1000 ) );
toDate =
new Date( System.currentTimeMillis()
+ ( (long) 1 * 24 * 60 * 60 * 1000 ) );
}
}
@@ -21,6 +21,7 @@ import org.apache.maven.changelog.ChangeLogFactory;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides Subversion specific instances of the ChangeLogGenerator and
* ChangeLogParser interfaces.
@@ -36,7 +37,7 @@ public class SvnChangeLogFactory implements ChangeLogFactory
public SvnChangeLogFactory()
{
}
/**
* Create a Subversion specific ChangeLogGenerator.
*
@@ -18,16 +18,22 @@ package org.apache.maven.svnlib;
*/
import java.io.IOException;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Date;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// maven imports
import org.apache.maven.changelog.AbstractChangeLogGenerator;
// ant imports
import org.apache.tools.ant.types.Commandline;
/**
* A Subversion implementation of the {@link org.apache.maven.changelog.ChangeLog}
* interface.
@@ -40,83 +46,88 @@ import org.apache.tools.ant.types.Commandline;
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
* @author Daniel Rall
* @version
* @version
* $Id$
*/
class SvnChangeLogGenerator extends AbstractChangeLogGenerator
{
/** Log */
private static final Log LOG = LogFactory.getLog(
SvnChangeLogGenerator.class);
/** Log */
private static final Log LOG =
LogFactory.getLog( SvnChangeLogGenerator.class );
/**
* Constructs the appropriate command line to execute the subversion
* log command whose output is then later parsed.
*
* @return the cvs command line to be executed.
*/
protected Commandline getScmLogCommand()
protected Commandline getScmLogCommand()
{
Commandline command = new Commandline();
command.setExecutable("svn");
command.createArgument().setValue("log");
command.createArgument().setValue("-v");
command.setExecutable( "svn" );
command.createArgument().setValue( "log" );
command.createArgument().setValue( "-v" );
if (dateRange != null)
if ( dateRange != null )
{
command.createArgument().setValue(dateRange);
command.createArgument().setValue( dateRange );
}
return command;
}
/**
/**
* Construct the svn command-line argument that is used to specify
* the appropriate date range. This date option takes the format
* of <code>-r{start}:{end}</code> in the case of Subversion.
*
*
* @param before The starting point.
* @param to The ending point.
* @return A string that can be used to specify a date to a scm
* system.
*/
protected String getScmDateArgument(Date before, Date to)
protected String getScmDateArgument( Date before, Date to )
{
SimpleDateFormat outputDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat outputDate = new SimpleDateFormat( "yyyy-MM-dd" );
// Tell SVN to sort log entries from newest to oldest.
String cmd = "-r{" + outputDate.format(to) + "}:{" +
outputDate.format(before) + "}";
String cmd =
"-r{" + outputDate.format( to ) + "}:{"
+ outputDate.format( before ) + "}";
if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
{
cmd = "\"" + cmd + "\"";
}
return cmd;
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Subversion.");
throw new UnsupportedOperationException(
"This plugin currently does not support generating logs from tags with Subversion." );
}
/**
* Handle ChangeLogParser IOExceptions.
*
/**
* Handle ChangeLogParser IOExceptions.
*
* @param ioe The IOException thrown.
* @throws IOException If the handler doesn't wish to handle the
* exception.
*/
protected void handleParserException(IOException ioe)
protected void handleParserException( IOException ioe )
throws IOException
{
if (ioe.getMessage().indexOf("CreateProcess") != -1
|| ioe.getMessage().indexOf("svn: not found") != -1)
if ( ( ioe.getMessage().indexOf( "CreateProcess" ) != -1 )
|| ( ioe.getMessage().indexOf( "svn: not found" ) != -1 ) )
{
// can't find svn on Win32 or Linux...
LOG.error(
"Unable to find svn executable. Changelog will be empty");
LOG.error( "Unable to find svn executable. Changelog will be empty" );
}
else
{
@@ -18,26 +18,32 @@ package org.apache.maven.svnlib;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.ArrayList;
// commons imports
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// maven
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
// regexp
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
/**
* A class to parse the log output from Subversion.
*
@@ -50,12 +56,12 @@ class SvnChangeLogParser implements ChangeLogParser
{
/** Date formatter for svn timestamp (after a little massaging) */
private static final SimpleDateFormat SVN_TIMESTAMP =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzzzzzzz");
new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss zzzzzzzzz" );
/** Log */
private static final Log LOG =
LogFactory.getLog( SvnChangeLogParser.class );
/** Log */
private static final Log LOG = LogFactory.getLog(
SvnChangeLogParser.class);
/** State machine constant: expecting header */
private static final int GET_HEADER = 1;
@@ -75,21 +81,21 @@ class SvnChangeLogParser implements ChangeLogParser
private static final int FILE_START_INDEX = 5;
/** The comment section ends with a dashed line */
private static final String COMMENT_END_TOKEN =
"------------------------------------" +
"------------------------------------";
private static final String COMMENT_END_TOKEN =
"------------------------------------"
+ "------------------------------------";
/** The pattern used to match svn header lines */
private static final String pattern =
"^r(\\d+)\\s+\\|\\s+" + // revision number
"([^|]+)\\|\\s+" + // author username
"(\\d+-\\d+-\\d+ " + // date 2002-08-24
"\\d+:\\d+:\\d+) " + // time 16:01:00
"([\\-+])(\\d\\d)(\\d\\d)"; // gmt offset -0400
"^r(\\d+)\\s+\\|\\s+" // revision number
+ "([^|]+)\\|\\s+" // author username
+ "(\\d+-\\d+-\\d+ " // date 2002-08-24
+ "\\d+:\\d+:\\d+) " // time 16:01:00
+ "([\\-+])(\\d\\d)(\\d\\d)"; // gmt offset -0400
/** Current status of the parser */
private int status = GET_HEADER;
/** List of change log entries */
private Collection entries = new ArrayList();
@@ -108,18 +114,18 @@ class SvnChangeLogParser implements ChangeLogParser
/** The invoking changelog controller (useful to log messages) */
private ChangeLog changeLog;
/**
/**
* Default constructor.
*/
public SvnChangeLogParser()
{
try
{
headerRegexp = new RE(pattern);
headerRegexp = new RE( pattern );
}
catch (RESyntaxException ignored)
catch ( RESyntaxException ignored )
{
LOG.error("Could not create regexp to parse svn log file", ignored);
LOG.error( "Could not create regexp to parse svn log file", ignored );
}
}
@@ -128,8 +134,8 @@ class SvnChangeLogParser implements ChangeLogParser
*
* @param changeLog The controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog)
*/
public void init( ChangeLog changeLog )
{
this.changeLog = changeLog;
}
@@ -138,11 +144,11 @@ class SvnChangeLogParser implements ChangeLogParser
* Clean up any parser resources.
*
* @see ChangeLogParser#cleanup()
*/
*/
public void cleanup()
{
}
/**
* Parse the input stream into a collection.
*
@@ -150,57 +156,67 @@ class SvnChangeLogParser implements ChangeLogParser
* @return A collection of ChangeLogEntry's
* @throws IOException When there are errors reading the provided stream
*/
public Collection parse(InputStream anInputStream) throws IOException
public Collection parse( InputStream anInputStream )
throws IOException
{
BufferedReader stream = new BufferedReader(
new InputStreamReader(anInputStream));
BufferedReader stream =
new BufferedReader( new InputStreamReader( anInputStream ) );
// Current state transitions in the parser's state machine:
// Get Header -> Get File
// Get File -> Get Comment or Get (another) File
// Get Comment -> Get (another) Comment
String line = null;
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
switch (status)
switch ( status )
{
case GET_HEADER:
processGetHeader(line);
break;
case GET_FILE:
processGetFile(line);
break;
case GET_COMMENT:
processGetComment(line);
break;
default:
throw new IllegalStateException("Unknown state: " + status);
case GET_HEADER :
processGetHeader( line );
break;
case GET_FILE :
processGetFile( line );
break;
case GET_COMMENT :
processGetComment( line );
break;
default :
throw new IllegalStateException( "Unknown state: " + status );
}
}
return entries;
}
}
/**
* Process the current input line in the GET_HEADER state. The
* author, date, and the revision of the entry are gathered. Note,
* Subversion does not have per-file revisions, instead, the entire
* repository is given a single revision number, which is used for
* the revision number of each file.
* the revision number of each file.
*
* @param line A line of text from the svn log output
*/
private void processGetHeader(String line)
private void processGetHeader( String line )
{
if (!headerRegexp.match(line))
if ( !headerRegexp.match( line ) )
{
return;
}
currentRevision = headerRegexp.getParen(1);
currentRevision = headerRegexp.getParen( 1 );
currentLogEntry = new ChangeLogEntry();
/* set author to be trimmed author field */
currentLogEntry.setAuthor(headerRegexp.getParen(2).trim());
currentLogEntry.setDate(parseDate());
currentLogEntry.setAuthor( headerRegexp.getParen( 2 ).trim() );
currentLogEntry.setDate( parseDate() );
status = GET_FILE;
}
@@ -213,17 +229,18 @@ class SvnChangeLogParser implements ChangeLogParser
*
* @param line A line of text from the svn log output
*/
private void processGetFile(String line)
private void processGetFile( String line )
{
if (line.startsWith(FILE_BEGIN_TOKEN))
if ( line.startsWith( FILE_BEGIN_TOKEN ) )
{
// Skip the status flags and just get the name of the file
String name = line.substring(FILE_START_INDEX);
currentLogEntry.addFile(new ChangeLogFile(name, currentRevision));
String name = line.substring( FILE_START_INDEX );
currentLogEntry.addFile( new ChangeLogFile( name, currentRevision ) );
status = GET_FILE;
}
else if (line.equals(FILE_END_TOKEN))
else if ( line.equals( FILE_END_TOKEN ) )
{
// Create a buffer for the collection of the comment now
// that we are leaving the GET_FILE state.
@@ -239,45 +256,46 @@ class SvnChangeLogParser implements ChangeLogParser
*
* @param line a line of text from the svn log output
*/
private void processGetComment(String line)
private void processGetComment( String line )
{
if (line.equals(COMMENT_END_TOKEN))
if ( line.equals( COMMENT_END_TOKEN ) )
{
currentLogEntry.setComment(currentComment.toString());
entries.add(currentLogEntry);
currentLogEntry.setComment( currentComment.toString() );
entries.add( currentLogEntry );
status = GET_HEADER;
}
else
{
currentComment.append(line).append('\n');
currentComment.append( line ).append( '\n' );
}
}
/**
/**
* Converts the date timestamp from the svn output into a date
* object.
*
*
* @return A date representing the timestamp of the log entry.
*/
private Date parseDate()
{
try
{
StringBuffer date = new StringBuffer()
.append(headerRegexp.getParen(3))
.append(" GMT")
.append(headerRegexp.getParen(4))
.append(headerRegexp.getParen(5))
.append(':')
.append(headerRegexp.getParen(6));
StringBuffer date =
new StringBuffer().append( headerRegexp.getParen( 3 ) )
.append( " GMT" )
.append( headerRegexp.getParen( 4 ) )
.append( headerRegexp.getParen( 5 ) )
.append( ':' ).append( headerRegexp
.getParen( 6 ) );
return SVN_TIMESTAMP.parse(date.toString());
return SVN_TIMESTAMP.parse( date.toString() );
}
catch (ParseException e)
catch ( ParseException e )
{
LOG.error("ParseException Caught", e);
return null;
LOG.error( "ParseException Caught", e );
return null;
}
}
@@ -18,9 +18,10 @@ package org.apache.maven.util;
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
/**
* A class to asynchronously read the provided InputStream and
@@ -33,7 +34,7 @@ public class AsyncStreamReader extends Thread
{
/** buffer to dump output to */
private StringBuffer streamBuffer = new StringBuffer();
/** stream to read from */
private BufferedReader stream;
@@ -41,34 +42,36 @@ public class AsyncStreamReader extends Thread
* Create a reader to process the provided stream
* @param anInputStream any input stream
*/
public AsyncStreamReader(InputStream anInputStream)
public AsyncStreamReader( InputStream anInputStream )
{
if (anInputStream == null)
if ( anInputStream == null )
{
throw new NullPointerException("input stream parameter is null");
throw new NullPointerException( "input stream parameter is null" );
}
stream = new BufferedReader(new InputStreamReader(anInputStream));
stream = new BufferedReader( new InputStreamReader( anInputStream ) );
}
/**
* Read lines from the input stream provided, appending to a buffer
* for retrieval via the toString() method
* for retrieval via the toString() method
*/
public void run()
{
String line;
try
{
while ((line = stream.readLine()) != null)
while ( ( line = stream.readLine() ) != null )
{
if (okToConsume(line))
if ( okToConsume( line ) )
{
streamBuffer.append(line);
streamBuffer.append('\n');
streamBuffer.append( line );
streamBuffer.append( '\n' );
}
}
}
catch (IOException ioe)
catch ( IOException ioe )
{
ioe.printStackTrace();
}
@@ -89,9 +92,9 @@ public class AsyncStreamReader extends Thread
* @param line the line to check.
* @return if its ok to add this line to the buffer.
*/
protected boolean okToConsume(String line)
protected boolean okToConsume( String line )
{
return true;
}
} // end of AsyncStreamReader
}
// end of AsyncStreamReader
@@ -20,6 +20,7 @@ package org.apache.maven.util;
import java.util.ArrayList;
import java.util.List;
/**
* NOTE: This is very CVS specific, but I would like to try additional SCM
* package like subversion ASAP.
@@ -31,48 +32,54 @@ import java.util.List;
public final class RepositoryUtils
{
/**
* Splits an SCM string into parts
* Splits an SCM string into parts
* @param connection
* @return String[]
*/
public static String[] splitSCMConnection(String connection)
public static String[] splitSCMConnection( String connection )
{
if (connection == null)
if ( connection == null )
{
throw new NullPointerException("repository connection is null");
throw new NullPointerException( "repository connection is null" );
}
if (connection.length() < 4)
if ( connection.length() < 4 )
{
throw new IllegalArgumentException("repository connection is too short");
throw new IllegalArgumentException(
"repository connection is too short" );
}
if (!connection.startsWith("scm"))
if ( !connection.startsWith( "scm" ) )
{
throw new IllegalArgumentException("repository connection must start with scm[delim]");
throw new IllegalArgumentException(
"repository connection must start with scm[delim]" );
}
String delimiter = "" + connection.charAt(3);
EnhancedStringTokenizer tok = new EnhancedStringTokenizer(connection, delimiter);
String delimiter = "" + connection.charAt( 3 );
String[] tokens = tokenizerToArray(tok);
EnhancedStringTokenizer tok =
new EnhancedStringTokenizer( connection, delimiter );
String[] tokens = tokenizerToArray( tok );
// for a valid repository, it should be scm:<provider> at least
if (tokens.length >= 1 && tokens[1].equals("cvs"))
if ( ( tokens.length >= 1 ) && tokens[1].equals( "cvs" ) )
{
if (tokens.length >= 2 && tokens[2].equals("local"))
if ( ( tokens.length >= 2 ) && tokens[2].equals( "local" ) )
{
if (tokens.length == 6)
if ( tokens.length == 6 )
{
if (tokens[3].length() > 0 && !tokens[3].equals("local"))
if ( ( tokens[3].length() > 0 )
&& !tokens[3].equals( "local" ) )
{
throw new IllegalArgumentException("cvs local repository connection string must specify 5 tokens, or an empty 3rd token if 6");
throw new IllegalArgumentException(
"cvs local repository connection string must specify 5 tokens, or an empty 3rd token if 6" );
}
}
else if (tokens.length == 5)
else if ( tokens.length == 5 )
{
String[] newTokens = new String[6];
newTokens[0] = tokens[0];
newTokens[1] = tokens[1];
newTokens[2] = tokens[2];
@@ -83,14 +90,18 @@ public final class RepositoryUtils
}
else
{
throw new IllegalArgumentException("cvs local repository connection string doesn't contain five tokens");
throw new IllegalArgumentException(
"cvs local repository connection string doesn't contain five tokens" );
}
}
if (tokens.length != 6)
if ( tokens.length != 6 )
{
throw new IllegalArgumentException("cvs repository connection string doesn't contain six tokens");
throw new IllegalArgumentException(
"cvs repository connection string doesn't contain six tokens" );
}
}
return tokens;
}
@@ -100,14 +111,15 @@ public final class RepositoryUtils
* @param tok
* @return String[]
*/
public static String[] tokenizerToArray(EnhancedStringTokenizer tok)
public static String[] tokenizerToArray( EnhancedStringTokenizer tok )
{
List l = new ArrayList();
while (tok.hasMoreTokens())
{
l.add(tok.nextToken());
}
return (String[]) l.toArray(new String[l.size()]);
}
while ( tok.hasMoreTokens() )
{
l.add( tok.nextToken() );
}
return (String[]) l.toArray( new String[l.size()] );
}
}
@@ -3,13 +3,13 @@ package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
*
* 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
@@ -21,36 +21,40 @@ package org.apache.maven.vsslib;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides VSS specific instances of the ChangeLogGenerator and ChangeLogParser
* interfaces.
*
*
* @author Freddy Mallet
*/
public class VssChangeLogFactory implements
org.apache.maven.changelog.ChangeLogFactory {
public class VssChangeLogFactory
implements org.apache.maven.changelog.ChangeLogFactory
{
/**
* Default no-arg constructor.
*/
public VssChangeLogFactory() {
public VssChangeLogFactory()
{
}
/**
* Create a VSS specific ChangeLogGenerator.
*
*
* @return a VSS specific ChangeLogGenerator.
*/
public ChangeLogGenerator createGenerator() {
public ChangeLogGenerator createGenerator()
{
return new VssChangeLogGenerator();
}
/**
* Create a VSS specific ChangeLogParser.
*
*
* @return a VSS specific ChangeLogParser.
*/
public ChangeLogParser createParser() {
public ChangeLogParser createParser()
{
return new VssChangeLogParser();
}
}
}
@@ -3,13 +3,13 @@ package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
*
* 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
@@ -20,7 +20,9 @@ package org.apache.maven.vsslib;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
@@ -28,110 +30,126 @@ import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.AbstractChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.types.Commandline;
/*******************************************************************************
* A Visual Source Safe implementation of the
* {@link org.apache.maven.changelog.ChangeLogGenerator}interface realized
* extending the {@link org.apache.maven.changelog.AbstractChangeLogGenerator}.
*
*
* The command line build by this class uses the <code>ss History</code> VSS
* command and formats the output in a way the VssChangeLogParser can
* understand. Due to this fact this implementations works only if used within a
* vss view.
*
*
* The command looks like this:
* <p>
* set ssdir=vssRepositoryPath ss History vssProject -YvssUserId,vssUserPassword
* -R -Vd01/12/04~23/11/04 -I-Y
*
*
* @author Freddy Mallet
*/
public class VssChangeLogGenerator extends AbstractChangeLogGenerator {
public class VssChangeLogGenerator extends AbstractChangeLogGenerator
{
/**
* Log
*/
private static final Log LOG = LogFactory
.getLog(VssChangeLogGenerator.class);
private static final Log LOG =
LogFactory.getLog( VssChangeLogGenerator.class );
/***************************************************************************
* Constructs the appropriate command line to execute the scm's log command.
* For Clearcase it's lshistory.
*
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmLogCommand()
* @return The command line to be executed.
*/
protected Commandline getScmLogCommand() {
VssConnection vssConnection = new VssConnection(getConnection());
protected Commandline getScmLogCommand()
{
VssConnection vssConnection = new VssConnection( getConnection() );
Commandline command = new Commandline();
command.setExecutable("ss");
command.createArgument().setValue("History");
command.createArgument().setValue("$" + vssConnection.getVssProject());
command.setExecutable( "ss" );
command.createArgument().setValue( "History" );
command.createArgument().setValue( "$"
+ vssConnection.getVssProject() );
//User identification to get access to vss repository
if(vssConnection.getVssUserInf() != null){
command.createArgument().setValue("-Y" + vssConnection.getVssUserInf());
if ( vssConnection.getVssUserInf() != null )
{
command.createArgument().setValue( "-Y"
+ vssConnection.getVssUserInf() );
}
//Display the history of an entire project list
command.createArgument().setValue("-R");
command.createArgument().setValue( "-R" );
//Ignore: Do not ask for input under any circumstances.
command.createArgument().setValue("-I-");
command.createArgument().setValue( "-I-" );
//Display only versions that fall within specified data range.
if (dateRange != null) {
command.createArgument().setValue("-Vd" + dateRange);
if ( dateRange != null )
{
command.createArgument().setValue( "-Vd" + dateRange );
}
return command;
}
/***************************************************************************
* Construct the command-line argument that is passed to the scm client to
* specify the appropriate date range.
*
*
* @param before
* The starting point.
* @param to
* The ending point.
* @return A string that can be used to specify a date to a scm system.
*
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmDateArgument(java.util.Date,
* java.util.Date)
*/
protected String getScmDateArgument(Date before, Date to) {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy",
Locale.ENGLISH);
String result = sdf.format(to) + "~" + sdf.format(before);
protected String getScmDateArgument( Date before, Date to )
{
SimpleDateFormat sdf =
new SimpleDateFormat( "dd/MM/yyyy", Locale.ENGLISH );
String result = sdf.format( to ) + "~" + sdf.format( before );
return result;
}
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException( "Cannot presently use tags for SCM operations on VSS" );
throw new UnsupportedOperationException(
"Cannot presently use tags for SCM operations on VSS" );
}
/**
* Convert date range from 'number of days' format to 'date to date' format
*
*
* @param numDaysString
* String
*/
public void setDateRange(String numDaysString) {
int days = Integer.parseInt(numDaysString);
public void setDateRange( String numDaysString )
{
int days = Integer.parseInt( numDaysString );
Date before = new Date(System.currentTimeMillis() - (long) days * 24
* 60 * 60 * 1000);
Date to = new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60
* 1000);
Date before =
new Date( System.currentTimeMillis()
- ( (long) days * 24 * 60 * 60 * 1000 ) );
Date to =
new Date( System.currentTimeMillis()
+ ( (long) 1 * 24 * 60 * 60 * 1000 ) );
}
/***************************************************************************
* Execute vss client driving the given parser. This method has been
* overwritten to be able to set 'SSDIR' environment variable. This variable
* set the vss repository
*
*
* @param parser
* A {@link ChangeLogParser parser}to process the vss output.
* @return A collection of {@link ChangeLogEntry entries}parsed from the
@@ -140,51 +158,70 @@ public class VssChangeLogGenerator extends AbstractChangeLogGenerator {
* When there are issues executing vss.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries(ChangeLogParser parser) throws IOException {
if (parser == null) {
throw new NullPointerException("parser cannot be null");
public Collection getEntries( ChangeLogParser parser )
throws IOException
{
if ( parser == null )
{
throw new NullPointerException( "parser cannot be null" );
}
if (base == null) {
throw new NullPointerException("basedir must be set");
if ( base == null )
{
throw new NullPointerException( "basedir must be set" );
}
if (!base.exists()) {
throw new FileNotFoundException("Cannot find base dir "
+ base.getAbsolutePath());
if ( !base.exists() )
{
throw new FileNotFoundException( "Cannot find base dir "
+ base.getAbsolutePath() );
}
clParser = parser;
try {
VssConnection vssConnection = new VssConnection(getConnection());
Execute exe = new Execute(this);
try
{
VssConnection vssConnection =
new VssConnection( getConnection() );
Execute exe = new Execute( this );
String[] env = exe.getEnvironment();
if (env == null) {
if ( env == null )
{
env = new String[0];
}
String[] newEnv = new String[env.length + 1];
for (int i = 0; i < env.length; i++) {
for ( int i = 0; i < env.length; i++ )
{
newEnv[i] = env[i];
}
newEnv[env.length] = "SSDIR=" + vssConnection.getVssDir();
exe.setEnvironment(newEnv);
exe.setCommandline(getScmLogCommand().getCommandline());
exe.setEnvironment( newEnv );
exe.setCommandline( getScmLogCommand().getCommandline() );
//exe.setVMLauncher(false);
exe.setWorkingDirectory(base);
logExecute(exe, base);
exe.setWorkingDirectory( base );
logExecute( exe, base );
exe.execute();
// log messages from stderr
String errors = errorReader.toString().trim();
if (errors.length() > 0) {
LOG.error(errors);
if ( errors.length() > 0 )
{
LOG.error( errors );
}
} catch (IOException ioe) {
handleParserException(ioe);
}
catch ( IOException ioe )
{
handleParserException( ioe );
}
return entries;
@@ -3,13 +3,13 @@ package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
*
* 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
@@ -22,8 +22,10 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -36,32 +38,29 @@ import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Visual Source Safe specific implementation of ChangeLogParser interface.
*
*
* @author Freddy Mallet
*/
public class VssChangeLogParser implements
org.apache.maven.changelog.ChangeLogParser {
public class VssChangeLogParser
implements org.apache.maven.changelog.ChangeLogParser
{
/** * Log */
private static final Log LOG = LogFactory.getLog(VssChangeLogParser.class);
private static final Log LOG =
LogFactory.getLog( VssChangeLogParser.class );
/**
* Custom date/time formatter. Rounds ChangeLogEntry times to the nearest
* minute.
*/
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT = new SimpleDateFormat(
"yyyyMMddHHmm");
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT =
new SimpleDateFormat( "yyyyMMddHHmm" );
// state machine constants for reading Starteam output
/** * expecting file information */
private static final int GET_FILE = 1;
@@ -95,6 +94,11 @@ public class VssChangeLogParser implements
/** * Marks comment data */
private static final String START_COMMENT = "Comment: ";
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap( Collections.reverseOrder() );
/** * last status of the parser */
private int lastStatus = GET_FILE;
@@ -110,178 +114,236 @@ public class VssChangeLogParser implements
/**
* Create a new ChangeLogParser.
*/
public VssChangeLogParser() {
public VssChangeLogParser()
{
}
/**
* initialize the parser from the change log
*
*
* @param changeLog
* the controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog) {
public void init( ChangeLog changeLog )
{
String connection = changeLog.getRepositoryConnection();
try {
vssConnection = new VssConnection(connection);
} catch (Exception e) {
String message = "Unable to parse vss connection string : "
+ connection;
throw new IllegalArgumentException(message);
try
{
vssConnection = new VssConnection( connection );
}
catch ( Exception e )
{
String message =
"Unable to parse vss connection string : " + connection;
throw new IllegalArgumentException( message );
}
}
/**
* Parse the input stream into a collection.
*
*
* @param inputStream
* an input stream containing clearcase log output
* @return a collection of ChangeLogEntry's
* @throws IOException
* when there are errors reading the provided stream
*/
public Collection parse(InputStream inputStream) throws IOException {
BufferedReader stream = new BufferedReader(new InputStreamReader(
inputStream));
public Collection parse( InputStream inputStream )
throws IOException
{
BufferedReader stream =
new BufferedReader( new InputStreamReader( inputStream ) );
String line;
while ((line = stream.readLine()) != null) {
switch (getLineStatus(line)) {
case GET_FILE:
processGetFile(line);
while ( ( line = stream.readLine() ) != null )
{
switch ( getLineStatus( line ) )
{
case GET_FILE :
processGetFile( line );
break;
case GET_REVISION:
processGetRevision(line);
case GET_REVISION :
processGetRevision( line );
break;
case GET_AUTHOR:
processGetAuthor(line);
case GET_AUTHOR :
processGetAuthor( line );
break;
case GET_FILE_PATH:
processGetFilePath(line);
case GET_FILE_PATH :
processGetFilePath( line );
break;
case GET_COMMENT:
processGetComment(line);
case GET_COMMENT :
processGetComment( line );
break;
default:
default :
break;
}
}
return entries.values();
}
/**
* Process the current input line in the Get Comment state.
*
*
* @param line
* a line of text from the VSS log output
*/
private void processGetComment(String line) {
String[] commentLine = line.split(":");
if (commentLine.length == 2) {
getCurrentLogEntry().setComment(commentLine[1]);
private void processGetComment( String line )
{
String[] commentLine = line.split( ":" );
if ( commentLine.length == 2 )
{
getCurrentLogEntry().setComment( commentLine[1] );
}
//Comment suite on a new line
else {
else
{
String comment = getCurrentLogEntry().getComment();
comment = comment + " " + line;
getCurrentLogEntry().setComment(comment);
getCurrentLogEntry().setComment( comment );
}
}
/**
* Process the current input line in the Get Author state.
*
*
* @param line
* a line of text from the VSS log output
*/
private void processGetAuthor(String line) {
String[] result = line.split("\\s");
private void processGetAuthor( String line )
{
String[] result = line.split( "\\s" );
Vector vector = new Vector();
for (int i = 0; i < result.length; i++) {
if (!result[i].equals("")) {
vector.add(result[i]);
for ( int i = 0; i < result.length; i++ )
{
if ( !result[i].equals( "" ) )
{
vector.add( result[i] );
}
}
ChangeLogEntry entry = getCurrentLogEntry();
entry.setAuthor((String) vector.get(1));
entry.setDate(parseDate((String) vector.get(3) + " "
+ (String) vector.get(5)));
entry.setAuthor( (String) vector.get( 1 ) );
entry.setDate( parseDate( (String) vector.get( 3 ) + " "
+ (String) vector.get( 5 ) ) );
}
/**
* Process the current input line in the Get File state.
*
*
* @param line
* a line of text from the VSS log output
*/
private void processGetFile(String line) {
setCurrentLogEntry(new ChangeLogEntry());
String[] fileLine = line.split(" ");
setCurrentFile(new ChangeLogFile(fileLine[2]));
private void processGetFile( String line )
{
setCurrentLogEntry( new ChangeLogEntry() );
String[] fileLine = line.split( " " );
setCurrentFile( new ChangeLogFile( fileLine[2] ) );
}
/**
* Process the current input line in the Get File Path state.
*
*
* @param line
* a line of text from the VSS log output
*/
private void processGetFilePath(String line) {
if (getCurrentFile() != null) {
private void processGetFilePath( String line )
{
if ( getCurrentFile() != null )
{
String fileName = getCurrentFile().getName();
String path = line.substring(line.indexOf("$"), line.length());
String longPath = path.substring(vssConnection.getVssProject()
.length() + 1, path.length())
+ "/" + fileName;
getCurrentFile().setName(longPath);
addEntry(getCurrentLogEntry(), getCurrentFile());
String path =
line.substring( line.indexOf( "$" ), line.length() );
String longPath =
path.substring( vssConnection.getVssProject().length() + 1,
path.length() ) + "/" + fileName;
getCurrentFile().setName( longPath );
addEntry( getCurrentLogEntry(), getCurrentFile() );
}
}
/**
* Process the current input line in the Get Revision state.
*
*
* @param line
* a line of text from the VSS log output
*/
private void processGetRevision(String line) {
String[] revisionLine = line.split(" ");
getCurrentFile().setRevision(revisionLine[1]);
private void processGetRevision( String line )
{
String[] revisionLine = line.split( " " );
getCurrentFile().setRevision( revisionLine[1] );
}
/**
* Identify the status of a vss history line
*
*
* @param the
* line to process
* @return status
*/
private int getLineStatus(String line) {
private int getLineStatus( String line )
{
int argument = GET_UNKNOWN;
if (line.startsWith(START_FILE)) {
if ( line.startsWith( START_FILE ) )
{
argument = GET_FILE;
} else if (line.startsWith(START_REVISION)) {
}
else if ( line.startsWith( START_REVISION ) )
{
argument = GET_REVISION;
} else if (line.startsWith(START_AUTHOR)) {
}
else if ( line.startsWith( START_AUTHOR ) )
{
argument = GET_AUTHOR;
} else if (line.indexOf(START_FILE_PATH) != -1) {
}
else if ( line.indexOf( START_FILE_PATH ) != -1 )
{
argument = GET_FILE_PATH;
} else if (line.startsWith(START_COMMENT)) {
}
else if ( line.startsWith( START_COMMENT ) )
{
argument = GET_COMMENT;
} else if (getLastStatus() == GET_COMMENT) {
}
else if ( getLastStatus() == GET_COMMENT )
{
//Comment suite on a new line
argument = getLastStatus();
}
setLastStatus(argument);
setLastStatus( argument );
return argument;
}
/**
* Add a change log entry to the list (if it's not already there) with the
* given file.
*
*
* @param entry
* a {@link ChangeLogEntry}to be added to the list if another
* with the same key doesn't exist already. If the entry's author
@@ -289,110 +351,131 @@ public class VssChangeLogParser implements
* @param file
* a {@link ChangeLogFile}to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file) {
private void addEntry( ChangeLogEntry entry, ChangeLogFile file )
{
// do not add if entry is not populated
if (entry.getAuthor() == null) {
if ( entry.getAuthor() == null )
{
return;
}
String key = ENTRY_KEY_TIMESTAMP_FORMAT.format(entry.getDate())
+ entry.getAuthor() + entry.getComment();
String key =
ENTRY_KEY_TIMESTAMP_FORMAT.format( entry.getDate() )
+ entry.getAuthor() + entry.getComment();
if (!entries.containsKey(key)) {
entry.addFile(file);
entries.put(key, entry);
} else {
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
if ( !entries.containsKey( key ) )
{
entry.addFile( file );
entries.put( key, entry );
}
else
{
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get( key );
existingEntry.addFile( file );
}
}
/**
* Converts the date timestamp from the svn output into a date object.
*
*
* @return A date representing the timestamp of the log entry.
*/
private Date parseDate(String dateString) {
try {
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yy HH:mm");
Date date = format.parse(dateString);
private Date parseDate( String dateString )
{
try
{
SimpleDateFormat format = new SimpleDateFormat( "dd.MM.yy HH:mm" );
Date date = format.parse( dateString );
return date;
} catch (ParseException e) {
LOG.error("ParseException Caught", e);
}
catch ( ParseException e )
{
LOG.error( "ParseException Caught", e );
return null;
}
}
/**
* Getter for property currentFile.
*
*
* @return Value of property currentFile.
*/
private ChangeLogFile getCurrentFile() {
private ChangeLogFile getCurrentFile()
{
return currentFile;
}
/**
* Setter for property currentFile.
*
*
* @param currentFile
* New value of property currentFile.
*/
private void setCurrentFile(ChangeLogFile currentFile) {
private void setCurrentFile( ChangeLogFile currentFile )
{
this.currentFile = currentFile;
}
/**
* Getter for property currentLogEntry.
*
*
* @return Value of property currentLogEntry.
*/
private ChangeLogEntry getCurrentLogEntry() {
private ChangeLogEntry getCurrentLogEntry()
{
return currentLogEntry;
}
/**
* Setter for property currentLogEntry.
*
*
* @param currentLogEntry
* New value of property currentLogEntry.
*/
private void setCurrentLogEntry(ChangeLogEntry currentLogEntry) {
private void setCurrentLogEntry( ChangeLogEntry currentLogEntry )
{
this.currentLogEntry = currentLogEntry;
}
/**
* Getter for property status.
*
*
* @return Value of property status.
*/
private int getLastStatus() {
private int getLastStatus()
{
return lastStatus;
}
/**
* Setter for property status.
*
*
* @param status
* New value of property status.
*/
private void setLastStatus(int status) {
private void setLastStatus( int status )
{
this.lastStatus = status;
}
/**
* Clean up any parser resources
*
*
* @see ChangeLogParser#cleanup()
*/
public void cleanup() {
public void cleanup()
{
}
/**
* Defined in ChangeLogParser interface
*
*
* @see ChangeLogParser
*/
public void setDateFormatInFile(String s) {
public void setDateFormatInFile( String s )
{
}
}
@@ -3,13 +3,13 @@ package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
*
* 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
@@ -21,16 +21,17 @@ package org.apache.maven.vsslib;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean representation of the vss connection string
*
*
* @author Freddy Mallet
*/
public class VssConnection {
public class VssConnection
{
/** Log */
private static final Log LOG = LogFactory
.getLog(VssChangeLogGenerator.class);
private static final Log LOG =
LogFactory.getLog( VssChangeLogGenerator.class );
/**
* VSS repository path
@@ -52,54 +53,68 @@ public class VssConnection {
* string. Here is an example:
* scm:vss:\\lancelot\Vss_EApplications\:guest,password:/Security/LOSCProduction
* the password is not madatory
*
*
* @param connection
* the vss connection string
*/
public VssConnection(String connection) {
if (!connection.startsWith("scm:vss")) {
throw new IllegalArgumentException(
"repositoy connection string does not specify 'vss' as the scm");
public VssConnection( String connection )
{
if ( !connection.startsWith( "scm:vss" ) )
{
throw new IllegalArgumentException(
"repositoy connection string does not specify 'vss' as the scm" );
}
try {
String[] splitedConnection = connection.split(":");
try
{
String[] splitedConnection = connection.split( ":" );
vssDir = splitedConnection[2];
if(!splitedConnection[3].equals("")){
if ( !splitedConnection[3].equals( "" ) )
{
vssUserInf = splitedConnection[3];
}
vssProject = splitedConnection[4];
} catch (Exception e) {
String message = "Unable to parse VSS connection string :"
+ connection;
LOG.error(message, e);
throw new IllegalArgumentException(message);
}
catch ( Exception e )
{
String message =
"Unable to parse VSS connection string :" + connection;
LOG.error( message, e );
throw new IllegalArgumentException( message );
}
}
/**
* Get the vss directory
*
*
* @return vss directory
*/
public String getVssDir() {
public String getVssDir()
{
return vssDir;
}
/**
* Get the vss project
*
*
* @return vss project
*/
public String getVssProject() {
public String getVssProject()
{
return vssProject;
}
/**
* Get the vss user information
*
*
* @return vss user information
*/
public String getVssUserInf() {
public String getVssUserInf()
{
return vssUserInf;
}
}
}
@@ -18,10 +18,8 @@ package org.apache.maven.starteamlib;
*/
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import junit.framework.TestCase;
import org.apache.maven.changelog.ChangeLogEntry;
@@ -18,10 +18,8 @@ package org.apache.maven.starteamlib;
*/
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import junit.framework.TestCase;
import org.apache.maven.changelog.ChangeLogEntry;