001package 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 022import org.apache.maven.scm.ScmFile; 023import org.apache.maven.scm.ScmFileStatus; 024import org.apache.maven.scm.log.ScmLogger; 025import org.apache.maven.scm.provider.bazaar.command.BazaarConsumer; 026 027import java.io.File; 028import java.util.ArrayList; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032 033/** 034 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a> 035 * 036 */ 037public 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}