View Javadoc

1   package org.apache.maven.scm.provider.git.command.diff;
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.ScmFile;
23  import org.apache.maven.scm.ScmFileStatus;
24  import org.apache.maven.scm.log.ScmLogger;
25  import org.apache.regexp.RE;
26  import org.apache.regexp.RESyntaxException;
27  import org.codehaus.plexus.util.cli.StreamConsumer;
28  
29  import java.io.File;
30  import java.util.ArrayList;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.Map;
34  
35  /**
36   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
37   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
38   * @author Olivier Lamy
39   * @version $Id: GitDiffConsumer.java 1056981 2011-01-09 17:24:53Z olamy $
40   */
41  public class GitDiffConsumer
42      implements StreamConsumer
43  {
44      // diff --git a/readme.txt b/readme.txt
45      // index fea1611..9e131cf 100644
46      // --- a/readme.txt
47      // +++ b/readme.txt
48      // @@ -1 +1 @@
49      // -/readme.txt
50      // \ No newline at end of file
51      // +new version of /readme.txt
52  
53  
54      /**
55       * patern matches the index line of the diff comparison
56       * paren.1 matches the first file
57       * paren.2 matches the 2nd file
58       */
59      private static final String DIFF_FILES_PATTERN = "^diff --git\\sa/(.*)\\sb/(.*)";
60  
61      private static final String START_REVISION_TOKEN = "---";
62  
63      private static final String END_REVISION_TOKEN = "+++";
64  
65      private static final String ADDED_LINE_TOKEN = "+";
66  
67      private static final String REMOVED_LINE_TOKEN = "-";
68  
69      private static final String UNCHANGED_LINE_TOKEN = " ";
70  
71      private static final String CHANGE_SEPARATOR_TOKEN = "@@";
72  
73      private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
74  
75      private static final String INDEX_LINE_TOKEN = "index ";
76  
77      private static final String NEW_FILE_MODE_TOKEN = "new file mode ";
78  
79      private static final String DELETED_FILE_MODE_TOKEN = "deleted file mode ";
80  
81      private ScmLogger logger;
82  
83      private String currentFile;
84  
85      private StringBuilder currentDifference;
86  
87      private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
88  
89      private Map<String,CharSequence> differences = new HashMap<String,CharSequence>();
90  
91      private StringBuilder patch = new StringBuilder();
92  
93      /**
94       * @see #DIFF_FILES_PATTERN
95       */
96      private RE filesRegexp;
97  
98      // ----------------------------------------------------------------------
99      //
100     // ----------------------------------------------------------------------
101 
102     public GitDiffConsumer( ScmLogger logger, File workingDirectory )
103     {
104         this.logger = logger;
105         try
106         {
107             filesRegexp = new RE( DIFF_FILES_PATTERN );
108         }
109         catch ( RESyntaxException ex )
110         {
111             throw new RuntimeException(
112                                         "INTERNAL ERROR: Could not create regexp to parse git log file. Something is probably wrong with the oro installation.",
113                                         ex );
114         }
115 
116     }
117 
118     // ----------------------------------------------------------------------
119     // StreamConsumer Implementation
120     // ----------------------------------------------------------------------
121 
122     /** {@inheritDoc} */
123     public void consumeLine( String line )
124     {
125         if ( filesRegexp.match( line ) )
126         {
127             // start a new file
128             currentFile = filesRegexp.getParen( 1 );
129 
130             changedFiles.add( new ScmFile( currentFile, ScmFileStatus.MODIFIED ) );
131 
132             currentDifference = new StringBuilder();
133 
134             differences.put( currentFile, currentDifference );
135 
136             patch.append( line ).append( "\n" );
137 
138             return;
139         }
140 
141         if ( currentFile == null )
142         {
143             if ( logger.isWarnEnabled() )
144             {
145                 logger.warn( "Unparseable line: '" + line + "'" );
146             }
147             patch.append( line ).append( "\n" );
148             return;
149         }
150         else if ( line.startsWith( INDEX_LINE_TOKEN ) )
151         {
152             // skip, though could parse to verify start revision and end revision
153             patch.append( line ).append( "\n" );
154         }
155         else if ( line.startsWith( NEW_FILE_MODE_TOKEN ) || line.startsWith( DELETED_FILE_MODE_TOKEN ) )
156         {
157             // skip, though could parse to verify file mode
158             patch.append( line ).append( "\n" );
159         }
160         else if ( line.startsWith( START_REVISION_TOKEN ) )
161         {
162             // skip, though could parse to verify filename, start revision
163             patch.append( line ).append( "\n" );
164         }
165         else if ( line.startsWith( END_REVISION_TOKEN ) )
166         {
167             // skip, though could parse to verify filename, end revision
168             patch.append( line ).append( "\n" );
169         }
170         else if ( line.startsWith( ADDED_LINE_TOKEN ) || line.startsWith( REMOVED_LINE_TOKEN )
171             || line.startsWith( UNCHANGED_LINE_TOKEN ) || line.startsWith( CHANGE_SEPARATOR_TOKEN )
172             || line.equals( NO_NEWLINE_TOKEN ) )
173         {
174             // add to buffer
175             currentDifference.append( line ).append( "\n" );
176             patch.append( line ).append( "\n" );
177         }
178         else
179         {
180             // TODO: handle property differences
181 
182             if ( logger.isWarnEnabled() )
183             {
184                 logger.warn( "Unparseable line: '" + line + "'" );
185             }
186             patch.append( line ).append( "\n" );
187             // skip to next file
188             currentFile = null;
189             currentDifference = null;
190         }
191     }
192 
193     public List<ScmFile> getChangedFiles()
194     {
195         return changedFiles;
196     }
197 
198     public Map<String,CharSequence> getDifferences()
199     {
200         return differences;
201     }
202 
203     public String getPatch()
204     {
205         return patch.toString();
206     }
207 
208 }