001package org.apache.maven.scm.provider.svn.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.codehaus.plexus.util.cli.StreamConsumer;
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:brett@apache.org">Brett Porter</a>
035 * @author Olivier Lamy
036 *
037 */
038public class SvnDiffConsumer
039    implements StreamConsumer
040{
041    //
042    // Index: plugin.jelly
043    // ===================================================================
044    // --- plugin.jelly        (revision 124799)
045    // +++ plugin.jelly        (working copy)
046    //
047
048    private static final String INDEX_TOKEN = "Index: ";
049
050    private static final String FILE_SEPARATOR_TOKEN = "===";
051
052    private static final String START_REVISION_TOKEN = "---";
053
054    private static final String END_REVISION_TOKEN = "+++";
055
056    private static final String ADDED_LINE_TOKEN = "+";
057
058    private static final String REMOVED_LINE_TOKEN = "-";
059
060    private static final String UNCHANGED_LINE_TOKEN = " ";
061
062    private static final String CHANGE_SEPARATOR_TOKEN = "@@";
063
064    private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
065
066    private ScmLogger logger;
067
068    private String currentFile;
069
070    private StringBuilder currentDifference;
071
072    private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
073
074    private Map<String, CharSequence> differences = new HashMap<String, CharSequence>();
075
076    private StringBuilder patch = new StringBuilder();
077
078    // ----------------------------------------------------------------------
079    //
080    // ----------------------------------------------------------------------
081
082    public SvnDiffConsumer( ScmLogger logger, File workingDirectory )
083    {
084        this.logger = logger;
085    }
086
087    // ----------------------------------------------------------------------
088    // StreamConsumer Implementation
089    // ----------------------------------------------------------------------
090
091    /** {@inheritDoc} */
092    public void consumeLine( String line )
093    {
094        if ( line.startsWith( INDEX_TOKEN ) )
095        {
096            // start a new file
097            currentFile = line.substring( INDEX_TOKEN.length() );
098
099            changedFiles.add( new ScmFile( currentFile, ScmFileStatus.MODIFIED ) );
100
101            currentDifference = new StringBuilder();
102
103            differences.put( currentFile, currentDifference );
104
105            patch.append( line ).append( "\n" );
106
107            return;
108        }
109
110        if ( currentFile == null )
111        {
112            if ( logger.isWarnEnabled() )
113            {
114                logger.warn( "Unparseable line: '" + line + "'" );
115            }
116            patch.append( line ).append( "\n" );
117            return;
118        }
119
120        if ( line.startsWith( FILE_SEPARATOR_TOKEN ) )
121        {
122            // skip
123            patch.append( line ).append( "\n" );
124        }
125        else if ( line.startsWith( START_REVISION_TOKEN ) )
126        {
127            // skip, though could parse to verify filename, start revision
128            patch.append( line ).append( "\n" );
129        }
130        else if ( line.startsWith( END_REVISION_TOKEN ) )
131        {
132            // skip, though could parse to verify filename, end revision
133            patch.append( line ).append( "\n" );
134        }
135        else if ( line.startsWith( ADDED_LINE_TOKEN ) || line.startsWith( REMOVED_LINE_TOKEN )
136            || line.startsWith( UNCHANGED_LINE_TOKEN ) || line.startsWith( CHANGE_SEPARATOR_TOKEN )
137            || line.equals( NO_NEWLINE_TOKEN ) )
138        {
139            // add to buffer
140            currentDifference.append( line ).append( "\n" );
141            patch.append( line ).append( "\n" );
142        }
143        else
144        {
145            // TODO: handle property differences
146
147            if ( logger.isWarnEnabled() )
148            {
149                logger.warn( "Unparseable line: '" + line + "'" );
150            }
151            patch.append( line ).append( "\n" );
152            // skip to next file
153            currentFile = null;
154            currentDifference = null;
155        }
156    }
157
158    public List<ScmFile> getChangedFiles()
159    {
160        return changedFiles;
161    }
162
163    public Map<String, CharSequence> getDifferences()
164    {
165        return differences;
166    }
167
168    public String getPatch()
169    {
170        return patch.toString();
171    }
172
173}