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