001    package 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    
022    import org.apache.maven.scm.command.blame.BlameLine;
023    import org.apache.maven.scm.log.ScmLogger;
024    import org.apache.maven.scm.util.AbstractConsumer;
025    import org.apache.regexp.RE;
026    import org.apache.regexp.RESyntaxException;
027    
028    import java.text.ParseException;
029    import java.text.SimpleDateFormat;
030    import java.util.ArrayList;
031    import java.util.Date;
032    import java.util.List;
033    import java.util.TimeZone;
034    
035    /**
036     * @author Evgeny Mandrikov
037     * @author Olivier Lamy
038     * @since 1.4
039     */
040    public 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    }