001package org.apache.maven.scm.provider.svn.svnexe.command.blame;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.scm.command.blame.BlameLine;
023import org.apache.maven.scm.log.ScmLogger;
024import org.apache.maven.scm.util.AbstractConsumer;
025import org.apache.regexp.RE;
026import org.apache.regexp.RESyntaxException;
027
028import java.text.ParseException;
029import java.text.SimpleDateFormat;
030import java.util.ArrayList;
031import java.util.Date;
032import java.util.List;
033import java.util.TimeZone;
034
035/**
036 * @author Evgeny Mandrikov
037 * @author Olivier Lamy
038 * @since 1.4
039 */
040public class SvnBlameConsumer
041    extends AbstractConsumer
042{
043    private static final String SVN_TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss";
044
045    private static final String LINE_PATTERN = "line-number=\"(.*)\"";
046
047    private static final String REVISION_PATTERN = "revision=\"(.*)\"";
048
049    private static final String AUTHOR_PATTERN = "<author>(.*)</author>";
050
051    private static final String DATE_PATTERN = "<date>(.*)T(.*)\\.(.*)Z</date>";
052
053    /**
054     * @see #LINE_PATTERN
055     */
056    private RE lineRegexp;
057
058    /**
059     * @see #REVISION_PATTERN
060     */
061    private RE revisionRegexp;
062
063    /**
064     * @see #AUTHOR_PATTERN
065     */
066    private RE authorRegexp;
067
068    /**
069     * @see #DATE_PATTERN
070     */
071    private RE dateRegexp;
072
073    private SimpleDateFormat dateFormat;
074
075    private List<BlameLine> lines = new ArrayList<BlameLine>();
076
077    public SvnBlameConsumer( ScmLogger logger )
078    {
079        super( logger );
080
081        dateFormat = new SimpleDateFormat( SVN_TIMESTAMP_PATTERN );
082        dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
083
084        try
085        {
086            lineRegexp = new RE( LINE_PATTERN );
087            revisionRegexp = new RE( REVISION_PATTERN );
088            authorRegexp = new RE( AUTHOR_PATTERN );
089            dateRegexp = new RE( DATE_PATTERN );
090        }
091        catch ( RESyntaxException ex )
092        {
093            throw new RuntimeException(
094                "INTERNAL ERROR: Could not create regexp to parse git log file. This shouldn't happen. Something is probably wrong with the oro installation.",
095                ex );
096        }
097    }
098
099    private int lineNumber;
100
101    private String revision;
102
103    private String author;
104
105    public void consumeLine( String line )
106    {
107        if ( lineRegexp.match( line ) )
108        {
109            String lineNumberStr = lineRegexp.getParen( 1 );
110            lineNumber = Integer.parseInt( lineNumberStr );
111        }
112        else if ( revisionRegexp.match( line ) )
113        {
114            revision = revisionRegexp.getParen( 1 );
115        }
116        else if ( authorRegexp.match( line ) )
117        {
118            author = authorRegexp.getParen( 1 );
119        }
120        else if ( dateRegexp.match( line ) )
121        {
122            String date = dateRegexp.getParen( 1 );
123            String time = dateRegexp.getParen( 2 );
124            Date dateTime = parseDateTime( date + " " + time );
125            lines.add( new BlameLine( dateTime, revision, author ) );
126            if ( getLogger().isDebugEnabled() )
127            {
128                getLogger().debug( "Author of line " + lineNumber + ": " + author + " (" + date + ")" );
129            }
130        }
131    }
132
133    protected Date parseDateTime( String dateTimeStr )
134    {
135        try
136        {
137            return dateFormat.parse( dateTimeStr );
138        }
139        catch ( ParseException e )
140        {
141            getLogger().error( "skip ParseException: " + e.getMessage() + " during parsing date " + dateTimeStr, e );
142            return null;
143        }
144    }
145
146    public List<BlameLine> getLines()
147    {
148        return lines;
149    }
150}