package com.ice.jcvsweb.bean;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import com.ice.util.StringUtilities;
/**
* Encapsulates the revision information for a file in a CVS repository.
*
* The log information that is returned from the CVS server is
* unfortunately ascii text. To make it reasonable to work witrh,
* that ascii text is parsed into the information for each revision
* in the log, and encapsulated in this class.
*
* @author Tim Endres, <a href="mailto:time@jcvs.org">time@gjt.org</a>
* @see com.ice.cvsc
*/
public
class JCVSEntryLog
{
private static final boolean DEBUG = false;
private static SimpleDateFormat dateFmt = null;
private Set revSet;
private Map revMap;
private Set tagSet;
private Map tagMap;
private String rawLog;
private String name;
private String rcsFile;
private String workFile;
private String author;
private String state;
private String head;
private String branch;
private String locks;
private String access;
private String keysub;
private String desc;
public
JCVSEntryLog()
{
this( null, null );
}
public
JCVSEntryLog( String name )
{
this( name, null );
}
public
JCVSEntryLog( String name, String rawData )
{
this.name = name;
this.revMap = new HashMap();
this.revSet = new TreeSet();
this.tagMap = new HashMap();
this.tagSet = new TreeSet();
if ( rawData != null )
{
this.setRawLog( rawData );
}
}
public String
getName()
{
return this.name;
}
public void
setName( String name )
{
this.name = name;
}
public String
getRawLog()
{
return this.rawLog;
}
public void
setRawLog( String rawData )
{
this.rcsFile = null;
this.workFile = null;
this.state = null;
this.head = null;
this.branch = null;
this.locks = null;
this.access = null;
this.keysub = null;
this.desc = null;
this.tagMap.clear();
this.tagSet.clear();
this.revMap.clear();
this.revSet.clear();
this.rawLog = rawData;
if ( this.rawLog != null )
{
this.parseRawLog( this.rawLog );
}
}
public String
getRcsFilename()
{
return this.rcsFile;
}
public String
getWorkFilename()
{
return this.workFile;
}
public String
getAuthor()
{
return this.author;
}
public String
getState()
{
return this.state;
}
public String
getHead()
{
return this.head;
}
public String
getDefaultBranch()
{
return this.branch;
}
public String
getLocks()
{
return this.locks;
}
public String
getAccess()
{
return this.access;
}
public String
getKeySub()
{
return this.keysub;
}
public String
getDescription()
{
return this.desc;
}
public Iterator
getRevIterator()
{
return this.revSet.iterator();
}
public Iterator
getTagIterator()
{
return this.tagSet.iterator();
}
public Revision
getRevision( String revStr )
{
return (Revision) this.revMap.get( revStr );
}
public Set
getRevisions()
{
return this.revSet;
}
public Tag
getTag( String tagName )
{
return (Tag) this.tagMap.get( tagName );
}
public Set
getTags()
{
return this.tagSet;
}
private void
parseRawLog( String rawLog )
{
String[] lines = StringUtilities.splitString( rawLog, "\n" );
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() lines = " + lines.length );
Revision curRev = null;
boolean collectDesc = false;
boolean collectTags = false;
boolean parsingRevisions = false;
StringBuffer descBuf = new StringBuffer();
for ( int i = 0 ; i < lines.length ; ++i )
{
String line = lines[i];
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() LINE '" + line + "'" );
if ( parsingRevisions )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS " );
if ( collectDesc )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS Description: " );
if ( line.equals( "----------------------------" ) )
{
collectDesc = false;
curRev.setDescription( descBuf.toString() );
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() SET Description: " + descBuf );
}
else if ( line.equals( "=============================================================================" ) )
{
collectDesc = false;
curRev.setDescription( descBuf.toString() );
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() SET Description: " + descBuf );
}
else
{
descBuf.append( line + "\n" );
}
}
else if ( line.startsWith( "revision " ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS Revision: " );
curRev = this.new Revision( line.substring(8).trim() );
this.revSet.add( curRev );
this.revMap.put( curRev.getRevision(), curRev );
}
else if ( line.startsWith( "date:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS Date: " );
if ( curRev != null )
{
curRev.parseDateLine( line.substring(5).trim() );
}
}
else if ( line.startsWith( "branches:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS Branches: " );
if ( curRev != null )
{
curRev.parseBranchLine( line.substring(9).trim() );
}
}
else
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() PARSE REVS Collecting Description... " );
collectDesc = true;
descBuf.setLength(0);
descBuf.append( line );
}
}
else if ( collectDesc )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() COLLECT DESC " );
if ( line.equals( "----------------------------" ) )
{
collectDesc = false;
parsingRevisions = true;
this.desc = descBuf.toString();
}
else
{
descBuf.append( line );
descBuf.append( "\n" );
}
}
else if ( collectTags )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() COLLECT SYMBOLS " );
if ( line.startsWith( "\t" ) )
{
String symStr = line.substring(1);
String[] syms = StringUtilities.splitString( symStr, ":" );
if ( syms.length != 2 )
{
// UNDONE
}
else
{
String sym = syms[0].trim();
String rev = syms[1].trim();
Tag tag = this.new Tag( sym, rev );
this.tagSet.add( tag );
this.tagMap.put( sym, tag );
}
}
else
{
--i; // undo the consumption of this line...
collectTags = false;
}
}
else if ( line.startsWith( "RCS file:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() RCS file " );
this.rcsFile = line.substring(9).trim();
}
else if ( line.startsWith( "Working file:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() Working file " );
this.workFile = line.substring(13).trim();
}
else if ( line.startsWith( "head:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() head: " );
this.head = line.substring(5).trim();
}
else if ( line.startsWith( "branch:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() branch: " );
this.branch = line.substring(7).trim();
}
else if ( line.startsWith( "locks:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() locks: " );
this.locks = line.substring(6).trim();
}
else if ( line.startsWith( "access list:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() access list: " );
this.access = line.substring(7).trim();
}
else if ( line.startsWith( "symbolic names:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() symbolic names: " );
collectTags = true;
}
else if ( line.startsWith( "keyword substitution:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() keyword substitution: " );
this.keysub = line.substring(21).trim();
}
else if ( line.startsWith( "total revisions:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() total revisions: " );
// UNDONE
}
else if ( line.startsWith( "description:" ) )
{
if ( DEBUG )
System.err.println
( "JCVSletLog.parseRawLog() description: " );
collectDesc = true;
descBuf.setLength( 0 );
}
}
//
// Link revisions...
// NOTE They are sorted in REVERSE ORDER!
//
String revStr = null;
String prevRevStr = null;
Revision prevRev = null;
int numRevs = this.revSet.size();
Iterator iter = this.revSet.iterator();
for ( ; iter.hasNext() ; )
{
Revision r = (Revision) iter.next();
revStr = r.getRevision();
r.setNextRevision( prevRevStr );
if ( prevRev != null )
prevRev.setPrevRevision( revStr );
prevRev = r;
prevRevStr = revStr;
}
if ( DEBUG )
System.err.println( "JCVSletLog.parseRawLog() DONE " );
}
public Tag
getTagByRevision( String rev )
{
Iterator iter = this.tagSet.iterator();
for ( ; iter.hasNext() ; )
{
Tag t = (Tag) iter.next();
if ( t.getRevision().equals( rev ) )
return t;
}
return null;
}
public String
toString()
{
StringBuffer sBuf = new StringBuffer( 128 );
sBuf.append( "[ " );
sBuf.append( "name=" ).append( this.name ).append( ", " );
sBuf.append( "rcsFile=" ).append( this.rcsFile ).append( ", " );
sBuf.append( "workFile=" ).append( this.workFile ).append( ", " );
sBuf.append( "author=" ).append( this.author ).append( ", " );
sBuf.append( "state=" ).append( this.state ).append( ", " );
sBuf.append( "head=" ).append( this.head ).append( ", " );
sBuf.append( "branch=" ).append( this.branch ).append( ", " );
sBuf.append( "locks=" ).append( this.locks ).append( ", " );
sBuf.append( "access='" ).append( this.access ).append( "', " );
sBuf.append( "keysub='" ).append( this.keysub ).append( "', " );
sBuf.append( "numRevs=" ).append( this.revSet.size() ).append( "', " );
sBuf.append( "numTags=" ).append( this.tagSet.size() );
sBuf.append( " ]" );
return sBuf.toString();
}
public
class Tag
implements Comparable
{
private String name;
private String rev;
public
Tag( String name, String rev )
{
this.name = name;
this.rev = rev;
}
public int
compareTo( Object o )
{
return this.name.compareTo( ((Tag) o).name );
}
public String
getName()
{
return this.name;
}
public String
getRevision()
{
return this.rev;
}
}
public
class Revision
implements Comparable
{
private String revision;
private String nextRev;
private String prevRev;
private String nextTag;
private String prevTag;
private String author;
private String state;
private String lines;
private String description;
private String[] branches;
private String dateStr;
private Date date;
private double sortNumber = 0.0;
public
Revision( String revision )
{
// System.err.println( "[REV-INIT] '" + revision + "'" );
this.revision = revision;
this.computeSortNumber();
}
public int
compareTo( Object o )
{
Revision rev = (Revision) o;
return
(
(this.sortNumber > rev.sortNumber)
? -1
: ( (this.sortNumber < rev.sortNumber)
? 1
: 0 )
);
}
public void
computeSortNumber()
{
// System.err.println( "[REV-CSN] '" + this.revision + "'" );
try {
String sortStr = this.revision;
int idx = sortStr.indexOf( "." );
if ( idx != -1 )
{
int idx2 = sortStr.indexOf( ".", idx + 1 );
if ( idx2 == -1 )
{
// N.N
sortStr = sortStr.replace( '.', '0' ) + ".0";
}
else
{
// N.N.X.X...
sortStr =
sortStr.substring( 0, idx2 ).replace( '.', '0' ) +
"." +
sortStr.substring( idx2 + 1 ).replace( '.', '0' );
}
}
// System.err.println
// ( "[REV-CSN] '" + this.revision + "' --> '" + sortStr + "'" );
this.sortNumber = Double.parseDouble( sortStr );
}
catch ( NumberFormatException ex )
{
this.sortNumber = 0;
ex.printStackTrace( System.err );
}
}
public void
parseDateLine( String dateLine )
{
this.lines = "";
this.state = "";
this.author = "";
this.date = new Date();
this.dateStr = this.date.toString();
if ( dateLine == null )
return;
String[] flds = StringUtilities.splitString( dateLine, ";" );
if ( flds.length > 3 && flds[3].trim().startsWith( "lines:" ) )
{
this.lines = flds[3].trim().substring(6).trim();
}
if ( flds.length > 2 && flds[2].trim().startsWith( "state:" ) )
{
this.state = flds[2].trim().substring(6).trim();
}
if ( flds.length > 1 && flds[1].trim().startsWith( "author:" ) )
{
this.author = flds[1].trim().substring(7).trim();
}
if ( flds.length > 0 )
{
if ( JCVSEntryLog.dateFmt == null )
{
JCVSEntryLog.dateFmt =
new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
}
this.dateStr = flds[0].trim();
ParsePosition pos = new ParsePosition(0);
this.date = JCVSEntryLog.dateFmt.parse( this.dateStr, pos );
}
}
public void
parseBranchLine( String branchLine )
{
this.branches = StringUtilities.splitString( branchLine, ";" );
}
public void
setDescription( String desc )
{
this.description = desc;
}
public String
getRevision()
{
return this.revision;
}
public String
getNextRevision()
{
return this.nextRev;
}
public void
setNextRevision( String nextRev )
{
this.nextRev = nextRev;
}
public String
getPrevRevision()
{
return this.prevRev;
}
public void
setPrevRevision( String prevRev )
{
this.prevRev = prevRev;
}
//
// WARNING Tag chains are unimplemented!!!!
//
public String
getNextTag()
{
return this.nextTag;
}
public void
setNextTag( String nextTag )
{
this.nextTag = nextTag;
}
//
// WARNING Tag chains are unimplemented!!!!
//
public String
getPrevTag()
{
return this.prevTag;
}
public void
setPrevTag( String prevTag )
{
this.prevTag = prevTag;
}
public String
getAuthor()
{
return this.author;
}
public String
getState()
{
return this.state;
}
public String[]
getBranches()
{
return this.branches;
}
public String
getChangeLines()
{
return this.lines;
}
public Date
getDate()
{
return this.date;
}
public String
getDateStamp()
{
return this.dateStr;
}
public String
getDescription()
{
return this.description;
}
}
}
|