001 package org.apache.maven.scm.provider.bazaar.command.diff;
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.ScmFile;
023 import org.apache.maven.scm.ScmFileStatus;
024 import org.apache.maven.scm.log.ScmLogger;
025 import org.apache.maven.scm.provider.bazaar.command.BazaarConsumer;
026
027 import java.io.File;
028 import java.util.ArrayList;
029 import java.util.HashMap;
030 import java.util.List;
031 import java.util.Map;
032
033 /**
034 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
035 *
036 */
037 public class BazaarDiffConsumer
038 extends BazaarConsumer
039 {
040
041 private static final String MODIFIED_FILE_TOKEN = "=== modified file ";
042
043 private static final String ADDED_FILE_TOKEN = "=== added file ";
044
045 private static final String DELETED_FILE_TOKEN = "=== deleted file ";
046
047 private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
048
049 private static final String FROM_FILE_TOKEN = "---";
050
051 private static final String TO_FILE_TOKEN = "+++";
052
053 private static final String ADDED_LINE_TOKEN = "+";
054
055 private static final String REMOVED_LINE_TOKEN = "-";
056
057 private static final String UNCHANGED_LINE_TOKEN = " ";
058
059 private static final String RANGE_TOKEN = "@@";
060
061 private ScmLogger logger;
062
063 private File workingDirectory;
064
065 private String currentFile;
066
067 private StringBuilder currentDifference;
068
069 private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
070
071 private Map<String,CharSequence> differences = new HashMap<String,CharSequence>();
072
073 private StringBuilder patch = new StringBuilder();
074
075 public BazaarDiffConsumer( ScmLogger logger, File workingDirectory )
076 {
077 super( logger );
078 this.logger = logger;
079 this.workingDirectory = workingDirectory;
080 }
081
082 /** {@inheritDoc} */
083 public void doConsume( ScmFileStatus status, String line )
084 {
085 String tmpLine = new String( line );
086 patch.append( line ).append( "\n" );
087
088 // Parse line
089 if ( line.startsWith( MODIFIED_FILE_TOKEN ) )
090 {
091 tmpLine = line.substring( MODIFIED_FILE_TOKEN.length() );
092 tmpLine = tmpLine.trim();
093 status = ScmFileStatus.MODIFIED;
094 addChangedFile( status, line, tmpLine );
095 }
096 else if ( line.startsWith( ADDED_FILE_TOKEN ) )
097 {
098 tmpLine = line.substring( ADDED_FILE_TOKEN.length() );
099 tmpLine = tmpLine.trim();
100 status = ScmFileStatus.ADDED;
101 addChangedFile( status, line, tmpLine );
102 }
103 else if ( line.startsWith( DELETED_FILE_TOKEN ) )
104 {
105 tmpLine = line.substring( DELETED_FILE_TOKEN.length() );
106 tmpLine = tmpLine.trim();
107 status = ScmFileStatus.DELETED;
108 addChangedFile( status, line, tmpLine );
109 }
110 else if ( line.startsWith( TO_FILE_TOKEN ) || line.startsWith( FROM_FILE_TOKEN ) )
111 {
112 // ignore (to avoid conflicts with add and remove tokens)
113 }
114 else if ( line.startsWith( ADDED_LINE_TOKEN ) || line.startsWith( REMOVED_LINE_TOKEN )
115 || line.startsWith( UNCHANGED_LINE_TOKEN ) || line.startsWith( RANGE_TOKEN )
116 || line.startsWith( NO_NEWLINE_TOKEN ) )
117 {
118 currentDifference.append( line ).append( "\n" );
119 }
120 }
121
122 /**
123 * This method takes into account two types of diff output. <br>
124 * - Bazaar 0.7 format: dir/dir/myfile <br>
125 * - Bazaar 0.8 format: a/dir/dir/myfile <br>
126 *
127 * @param status Eg. modified or added
128 * @param line The original bazaar output to process (for logging)
129 * @param tmpLine The bazaar output to process
130 */
131 private void addChangedFile( ScmFileStatus status, String line, String tmpLine )
132 {
133 tmpLine = tmpLine.substring( 1, tmpLine.length() - 1 );
134 boolean ok = addChangedFile( status, tmpLine );
135
136 if ( !ok )
137 {
138 int index = tmpLine.indexOf( '/' );
139 if ( index > -1 )
140 {
141 tmpLine = tmpLine.substring( index + 1 );
142 ok = addChangedFile( status, tmpLine );
143 }
144 }
145
146 if ( !ok )
147 {
148 if ( logger.isWarnEnabled() )
149 {
150 logger.warn( "Could not figure out of line: " + line );
151 }
152 }
153 }
154
155 /**
156 * @param status
157 * @param tmpLine
158 * @return True if tmpLine was a valid file and thus added to the changeset
159 */
160 private boolean addChangedFile( ScmFileStatus status, String tmpLine )
161 {
162 File tmpFile = new File( workingDirectory, tmpLine );
163 if ( status.equals( ScmFileStatus.DELETED ) )
164 {
165 return true;
166 }
167
168 if ( tmpFile.isFile() )
169 {
170 currentFile = tmpLine;
171 currentDifference = new StringBuilder();
172 differences.put( currentFile, currentDifference );
173 changedFiles.add( new ScmFile( tmpLine, status ) );
174 return true;
175 }
176
177 return false;
178 }
179
180 public List<ScmFile> getChangedFiles()
181 {
182 return changedFiles;
183 }
184
185 public Map<String,CharSequence> getDifferences()
186 {
187 return differences;
188 }
189
190 public String getPatch()
191 {
192 return patch.toString();
193 }
194 }