View Javadoc
1   package org.apache.maven.scm.provider.git.gitexe.command.blame;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.scm.command.blame.BlameLine;
23  import org.apache.maven.scm.log.ScmLogger;
24  import org.apache.maven.scm.util.AbstractConsumer;
25  
26  import java.text.DateFormat;
27  import java.text.SimpleDateFormat;
28  import java.util.*;
29  
30  /**
31   * Parses the --porcelain format of git-blame
32   *
33   * For more information about the porcelain format, please read the official
34   * <a href="http://www.kernel.org/pub/software/scm/git/docs/git-blame.html#_the_porcelain_format">
35   * GIT blame porcelain format</a> description.
36   *
37   * @author Evgeny Mandrikov
38   * @author Olivier Lamy
39   * @author Mark Struberg
40   * @since 1.4
41   */
42  public class GitBlameConsumer
43      extends AbstractConsumer
44  {
45      private final static String GIT_COMMITTER_PREFIX = "committer";
46      private final static String GIT_COMMITTER      = GIT_COMMITTER_PREFIX + " ";
47      private final static String GIT_COMMITTER_TIME = GIT_COMMITTER_PREFIX + "-time ";
48      private final static String GIT_AUTHOR         = "author ";
49  
50  
51      private List<BlameLine> lines = new ArrayList<BlameLine>();
52  
53      /**
54       * Since the porcelain format only contains the commit information
55       * the first time a specific sha-1 commit appears, we need to store
56       * this information somwehere.
57       *
58       * key: the sha-1 of the commit
59       * value: the {@link BlameLine} containing the full committer/author info
60       */
61      private Map<String, BlameLine> commitInfo = new HashMap<String, BlameLine>();
62  
63      private boolean expectRevisionLine = true;
64  
65      private String revision  = null;
66      private String author    = null;
67      private String committer = null;
68      private Date   time      = null;
69  
70      public GitBlameConsumer( ScmLogger logger )
71      {
72          super( logger );
73      }
74  
75      public void consumeLine( String line )
76      {
77          if ( line == null )
78          {
79              return;
80          }
81  
82          if (expectRevisionLine)
83          {
84              // this is the revision line
85              String parts[] = line.split( "\\s", 4 );
86  
87              if ( parts.length >= 1)
88              {
89                  revision = parts[0];
90  
91                  BlameLine oldLine = commitInfo.get( revision );
92  
93                  if ( oldLine != null )
94                  {
95                      // restore the commit info
96                      author    = oldLine.getAuthor();
97                      committer = oldLine.getCommitter();
98                      time      = oldLine.getDate();
99                  }
100 
101                 expectRevisionLine = false;
102             }
103         }
104         else
105         {
106             if ( line.startsWith( GIT_AUTHOR ) )
107             {
108                 author = line.substring( GIT_AUTHOR.length() );
109                 return;
110             }
111 
112             if ( line.startsWith( GIT_COMMITTER ) )
113             {
114                 committer = line.substring( GIT_COMMITTER.length() );
115                 return;
116             }
117 
118             if ( line.startsWith( GIT_COMMITTER_TIME ) )
119             {
120                 String timeStr = line.substring( GIT_COMMITTER_TIME.length() );
121                 time = new Date( Long.parseLong( timeStr ) * 1000L );
122                 return;
123             }
124 
125 
126             if ( line.startsWith( "\t" ) )
127             {
128                 // this is the content line.
129                 // we actually don't need the content, but this is the right time to add the blame line
130                 BlameLine blameLine = new BlameLine( time, revision, author, committer );
131                 getLines().add( blameLine );
132 
133                 // keep commitinfo for this sha-1
134                 commitInfo.put( revision, blameLine );
135 
136                 if ( getLogger().isDebugEnabled() )
137                 {
138                     DateFormat df = SimpleDateFormat.getDateTimeInstance();
139                     getLogger().debug( author + " " + df.format( time ) );
140                 }
141 
142                 expectRevisionLine = true;
143             }
144 
145         }
146     }
147 
148     public List<BlameLine> getLines()
149     {
150         return lines;
151     }
152 }