Author: olamy Date: Wed Dec 7 21:08:29 2011 New Revision: 1211635 URL: http://svn.apache.org/viewvc?rev=1211635&view=rev Log: [SCM-649] Enhance SCM changelog model to hold more data about changes patch regarding git implementation. patch modified with using maven codestyle Submitted by Petr Kozelka.
Modified: maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumer.java maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumerTest.java Modified: maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumer.java URL: http://svn.apache.org/viewvc/maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumer.java?rev=1211635&r1=1211634&r2=1211635&view=diff ============================================================================== --- maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumer.java (original) +++ maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumer.java Wed Dec 7 21:08:29 2011 @@ -19,18 +19,21 @@ package org.apache.maven.scm.provider.gi * under the License. */ -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; - import org.apache.maven.scm.ChangeFile; import org.apache.maven.scm.ChangeSet; +import org.apache.maven.scm.ScmFileStatus; import org.apache.maven.scm.log.ScmLogger; import org.apache.maven.scm.util.AbstractConsumer; import org.apache.regexp.RE; import org.apache.regexp.RESyntaxException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + /** * @author <a href="mailto:strub...@yahoo.de">Mark Struberg</a> * @author Olivier Lamy @@ -56,6 +59,26 @@ public class GitChangeLogConsumer private static final int STATUS_GET_AUTHOR = 2; /** + * State machine constant: expecting parent hash information + */ + private static final int STATUS_RAW_TREE = 21; + + /** + * State machine constant: expecting parent hash information + */ + private static final int STATUS_RAW_PARENT = 22; + + /** + * State machine constant: expecting author name, email and timestamp information + */ + private static final int STATUS_RAW_AUTHOR = 23; + + /** + * State machine constant: expecting committer name, email and timestamp information + */ + private static final int STATUS_RAW_COMMITTER = 24; + + /** * State machine constant: expecting date information */ private static final int STATUS_GET_DATE = 3; @@ -81,6 +104,26 @@ public class GitChangeLogConsumer private static final String AUTHOR_PATTERN = "^Author: (.*)"; /** + * The pattern used to match git tree hash lines (raw mode) + */ + private static final String RAW_TREE_PATTERN = "^tree ([:xdigit:]+)"; + + /** + * The pattern used to match git parent hash lines (raw mode) + */ + private static final String RAW_PARENT_PATTERN = "^parent ([:xdigit:]+)"; + + /** + * The pattern used to match git author lines (raw mode) + */ + private static final String RAW_AUTHOR_PATTERN = "^author (.+ <.+>) ([:digit:]+) (.*)"; + + /** + * The pattern used to match git author lines (raw mode) + */ + private static final String RAW_COMMITTER_PATTERN = "^committer (.+ <.+>) ([:digit:]+) (.*)"; + + /** * The pattern used to match git date lines */ private static final String DATE_PATTERN = "^Date:\\s*(.*)"; @@ -88,7 +131,8 @@ public class GitChangeLogConsumer /** * The pattern used to match git file lines */ - private static final String FILE_PATTERN = "^:\\d* \\d* [:xdigit:]*\\.* [:xdigit:]*\\.* ([:upper:])\\t(.*)"; + private static final String FILE_PATTERN = + "^:\\d* \\d* [:xdigit:]*\\.* [:xdigit:]*\\.* ([:upper:])[:digit:]*\\t([^\\t]*)(\\t(.*))?"; /** * Current status of the parser @@ -126,6 +170,26 @@ public class GitChangeLogConsumer private RE authorRegexp; /** + * The regular expression used to match tree hash lines in raw mode + */ + private RE rawTreeRegexp; + + /** + * The regular expression used to match parent hash lines in raw mode + */ + private RE rawParentRegexp; + + /** + * The regular expression used to match author lines in raw mode + */ + private RE rawAuthorRegexp; + + /** + * The regular expression used to match committer lines in raw mode + */ + private RE rawCommitterRegexp; + + /** * The regular expression used to match date lines */ private RE dateRegexp; @@ -152,12 +216,16 @@ public class GitChangeLogConsumer authorRegexp = new RE( AUTHOR_PATTERN ); dateRegexp = new RE( DATE_PATTERN ); fileRegexp = new RE( FILE_PATTERN ); + rawTreeRegexp = new RE( RAW_TREE_PATTERN ); + rawParentRegexp = new RE( RAW_PARENT_PATTERN ); + rawAuthorRegexp = new RE( RAW_AUTHOR_PATTERN ); + rawCommitterRegexp = new RE( RAW_COMMITTER_PATTERN ); } catch ( RESyntaxException ex ) { throw new RuntimeException( - "INTERNAL ERROR: Could not create regexp to parse git log file. This shouldn't happen. Something is probably wrong with the oro installation.", - ex ); + "INTERNAL ERROR: Could not create regexp to parse git log file. This shouldn't happen. Something is probably wrong with the oro installation.", + ex ); } } @@ -173,7 +241,9 @@ public class GitChangeLogConsumer // StreamConsumer Implementation // ---------------------------------------------------------------------- - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public void consumeLine( String line ) { switch ( status ) @@ -193,6 +263,18 @@ public class GitChangeLogConsumer case STATUS_GET_FILE: processGetFile( line ); break; + case STATUS_RAW_TREE: + processGetRawTree( line ); + break; + case STATUS_RAW_PARENT: + processGetRawParent( line ); + break; + case STATUS_RAW_AUTHOR: + processGetRawAuthor( line ); + break; + case STATUS_RAW_COMMITTER: + processGetRawCommitter( line ); + break; default: throw new IllegalStateException( "Unknown state: " + status ); } @@ -235,6 +317,14 @@ public class GitChangeLogConsumer */ private void processGetAuthor( String line ) { + // this autodetects 'raw' format + if ( rawTreeRegexp.match( line ) ) + { + status = STATUS_RAW_TREE; + processGetRawTree( line ); + return; + } + if ( !authorRegexp.match( line ) ) { return; @@ -247,6 +337,102 @@ public class GitChangeLogConsumer } /** + * Process the current input line in the STATUS_RAW_TREE state. This + * state gathers tree hash part of a log entry. + * + * @param line a line of text from the git log output + */ + private void processGetRawTree( String line ) + { + if ( !rawTreeRegexp.match( line ) ) + { + return; + } + //here we could set treeHash if it appears in the model: currentChange.setTreeHash( rawTreeRegexp.getParen( 1 ) ); + status = STATUS_RAW_PARENT; + } + + /** + * Process the current input line in the STATUS_RAW_PARENT state. This + * state gathers parent revisions of a log entry. + * + * @param line a line of text from the git log output + */ + private void processGetRawParent( String line ) + { + if ( !rawParentRegexp.match( line ) ) + { + status = STATUS_RAW_AUTHOR; + processGetRawAuthor( line ); + return; + } + String parentHash = rawParentRegexp.getParen( 1 ); + + addParentRevision( parentHash ); + } + + /** + * In git log, both parent and merged revisions are called parent. Fortunately, the real parent comes first in the log. + * This method takes care of the difference. + * + * @param hash - + */ + private void addParentRevision( String hash ) + { + if ( currentChange.getParentRevision() == null ) + { + currentChange.setParentRevision( hash ); + } + else + { + currentChange.addMergedRevision( hash ); + } + } + + /** + * Process the current input line in the STATUS_RAW_AUTHOR state. This + * state gathers all the author information of a log entry. + * + * @param line a line of text from the git log output + */ + private void processGetRawAuthor( String line ) + { + if ( !rawAuthorRegexp.match( line ) ) + { + return; + } + String author = rawAuthorRegexp.getParen( 1 ); + currentChange.setAuthor( author ); + + String datestring = rawAuthorRegexp.getParen( 2 ); + String tz = rawAuthorRegexp.getParen( 3 ); + + // with --format=raw option (which gets us to this methods), date is always in seconds since beginning of time + // even explicit --date=iso is ignored, so we ignore both userDateFormat and GIT_TIMESTAMP_PATTERN here + Calendar c = Calendar.getInstance( TimeZone.getTimeZone( tz ) ); + c.setTimeInMillis( Long.parseLong( datestring ) * 1000 ); + currentChange.setDate( c.getTime() ); + + status = STATUS_RAW_COMMITTER; + } + + /** + * Process the current input line in the STATUS_RAW_AUTHOR state. This + * state gathers all the committer information of a log entry. + * + * @param line a line of text from the git log output + */ + private void processGetRawCommitter( String line ) + { + if ( !rawCommitterRegexp.match( line ) ) + { + return; + } + // here we could set committer and committerDate, the same way as in processGetRawAuthor + status = STATUS_GET_COMMENT; + } + + /** * Process the current input line in the STATUS_GET_DATE state. This * state gathers all of the date information that are part of a log entry. * @@ -326,12 +512,48 @@ public class GitChangeLogConsumer { return; } - // String action = fileRegexp.getParen( 1 ); + final String actionChar = fileRegexp.getParen( 1 ); // action is currently not used - + final ScmFileStatus action; String name = fileRegexp.getParen( 2 ); + String originalName = null; + String originalRevision = null; + if ( "A".equals( actionChar ) ) + { + action = ScmFileStatus.ADDED; + } + else if ( "M".equals( actionChar ) ) + { + action = ScmFileStatus.MODIFIED; + } + else if ( "D".equals( actionChar ) ) + { + action = ScmFileStatus.DELETED; + } + else if ( "R".equals( actionChar ) ) + { + action = ScmFileStatus.RENAMED; + originalName = name; + name = fileRegexp.getParen( 4 ); + originalRevision = currentChange.getParentRevision(); + } + else if ( "C".equals( actionChar ) ) + { + action = ScmFileStatus.COPIED; + originalName = name; + name = fileRegexp.getParen( 4 ); + originalRevision = currentChange.getParentRevision(); + } + else + { + action = ScmFileStatus.UNKNOWN; + } - currentChange.addFile( new ChangeFile( name, currentRevision ) ); + final ChangeFile changeFile = new ChangeFile( name, currentRevision ); + changeFile.setAction( action ); + changeFile.setOriginalName( originalName ); + changeFile.setOriginalRevision( originalRevision ); + currentChange.addFile( changeFile ); } } Modified: maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumerTest.java URL: http://svn.apache.org/viewvc/maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumerTest.java?rev=1211635&r1=1211634&r2=1211635&view=diff ============================================================================== --- maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumerTest.java (original) +++ maven/scm/trunk/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/changelog/GitChangeLogConsumerTest.java Wed Dec 7 21:08:29 2011 @@ -19,19 +19,24 @@ package org.apache.maven.scm.provider.gi * under the License. */ +import org.apache.maven.scm.ChangeFile; +import org.apache.maven.scm.ChangeSet; +import org.apache.maven.scm.ScmFileStatus; +import org.apache.maven.scm.log.DefaultLog; +import org.apache.regexp.RE; +import org.codehaus.plexus.PlexusTestCase; +import org.junit.Assert; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.text.SimpleDateFormat; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.TimeZone; - -import org.apache.maven.scm.ChangeFile; -import org.apache.maven.scm.ChangeSet; -import org.apache.maven.scm.log.DefaultLog; -import org.apache.regexp.RE; -import org.codehaus.plexus.PlexusTestCase; +import java.util.concurrent.atomic.AtomicInteger; /** * @author <a href="mailto:strub...@yahoo.de">Mark Struberg</a> @@ -39,7 +44,7 @@ import org.codehaus.plexus.PlexusTestCas public class GitChangeLogConsumerTest extends PlexusTestCase { - + public void testConsumer1() throws Exception { @@ -49,9 +54,9 @@ public class GitChangeLogConsumerTest boolean match = dateRegexp.match( "Date: 2007-11-24 01:13:10 +0100" ); String datestring = dateRegexp.getParen( 1 ); - assertEquals("2007-11-24 01:13:10 +0100", datestring); + assertEquals( "2007-11-24 01:13:10 +0100", datestring ); assertTrue( match ); - + GitChangeLogConsumer consumer = new GitChangeLogConsumer( new DefaultLog(), null ); File f = getTestFile( "/src/test/resources/git/changelog/gitwhatchanged.gitlog" ); @@ -123,6 +128,9 @@ public class GitChangeLogConsumerTest List<ChangeSet> modifications = consumer.getModifications(); + // must use *Linked* HashMap to have predictable toString + final Map<ScmFileStatus, AtomicInteger> summary = new LinkedHashMap<ScmFileStatus, AtomicInteger>(); + for ( Iterator<ChangeSet> i = modifications.iterator(); i.hasNext(); ) { ChangeSet entry = i.next(); @@ -137,7 +145,19 @@ public class GitChangeLogConsumerTest assertNotNull( entry.getFiles() ); assertFalse( entry.getFiles().isEmpty() ); + + for ( ChangeFile file : entry.getFiles() ) + { + final ScmFileStatus action = file.getAction(); + if ( !summary.containsKey( action ) ) + { + summary.put( action, new AtomicInteger() ); + } + summary.get( action ).incrementAndGet(); + } } + Assert.assertEquals( "Action summary differs from expectations", "{modified=21, added=88, deleted=1}", + summary.toString() ); assertEquals( 8, modifications.size() ); @@ -153,8 +173,8 @@ public class GitChangeLogConsumerTest assertEquals( "52733aa427041cafd760833cb068ffe897fd35db", entry.getRevision() ); - assertEquals( "fixed a GitCommandLineUtil and provice first version of the checkin command.", entry - .getComment() ); + assertEquals( "fixed a GitCommandLineUtil and provice first version of the checkin command.", + entry.getComment() ); assertNotNull( entry.getFiles() ); @@ -162,9 +182,9 @@ public class GitChangeLogConsumerTest ChangeFile cf = (ChangeFile) entry.getFiles().get( 0 ); assertEquals( - "maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java", - cf.getName() ); + "maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java", + cf.getName() ); assertTrue( cf.getRevision() != null && cf.getRevision().length() > 0 ); } - + }