001package org.apache.maven.scm.provider.starteam.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 java.io.File;
023import java.util.ArrayList;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.maven.scm.ScmFile;
029import org.apache.maven.scm.ScmFileStatus;
030import org.apache.maven.scm.log.ScmLogger;
031import org.codehaus.plexus.util.cli.StreamConsumer;
032
033/**
034 * @author <a href="mailto:dantran@gmail.com">Dan T. Tran</a>
035 *
036 */
037public class StarteamDiffConsumer
038    implements StreamConsumer
039{
040    private static final String WORKING_DIR_TOKEN = "(working dir: ";
041
042    private static final String PATCH_SEPARATOR_TOKEN = "--------------";
043
044    private static final String REVISION_TOKEN = " Revision: ";
045
046    private static final String ONDISK_TOKEN = " (on disk)";
047
048    private static final String ADDED_LINE_TOKEN = "+";
049
050    private static final String REMOVED_LINE_TOKEN = "-";
051
052    private static final String UNCHANGED_LINE_TOKEN = " ";
053
054    private ScmLogger logger;
055
056    @SuppressWarnings( "unused" )
057    private String currentDir = "";
058
059    private boolean diffBlockProcessingStarted = false;
060
061    private boolean revisionBlockStarted = false;
062
063    private String currentFile;
064
065    private StringBuilder currentDifference;
066
067    private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
068
069    private Map<String,CharSequence> differences = new HashMap<String,CharSequence>();
070
071    private StringBuilder patch = new StringBuilder();
072
073    // ----------------------------------------------------------------------
074    //
075    // ----------------------------------------------------------------------
076
077    public StarteamDiffConsumer( ScmLogger logger, File workingDirectory )
078    {
079        this.logger = logger;
080    }
081
082    // ----------------------------------------------------------------------
083    // StreamConsumer Implementation
084    // ----------------------------------------------------------------------
085
086    /** {@inheritDoc} */
087    public void consumeLine( String line )
088    {
089        int pos = 0;
090
091        if ( logger.isDebugEnabled() )
092        {
093            logger.debug( line );
094        }
095
096        patch.append( line ).append( "\n" );
097
098        if ( line.trim().length() == 0 )
099        {
100            return;
101        }
102
103        if ( ( pos = line.indexOf( WORKING_DIR_TOKEN ) ) != -1 )
104        {
105            processGetDir( line, pos );
106
107            return;
108        }
109
110        if ( line.startsWith( PATCH_SEPARATOR_TOKEN ) )
111        {
112            diffBlockProcessingStarted = !diffBlockProcessingStarted;
113
114            if ( diffBlockProcessingStarted )
115            {
116                if ( revisionBlockStarted )
117                {
118                    throw new IllegalStateException( "Missing second Revision line or local copy line " );
119                }
120            }
121
122            return;
123        }
124
125        if ( ( pos = line.indexOf( REVISION_TOKEN ) ) != -1 )
126        {
127            if ( revisionBlockStarted )
128            {
129                revisionBlockStarted = false;
130            }
131            else
132            {
133                extractCurrentFile( line, pos );
134
135                revisionBlockStarted = true;
136            }
137
138            return;
139        }
140
141        if ( ( pos = line.indexOf( ONDISK_TOKEN ) ) != -1 )
142        {
143            if ( revisionBlockStarted )
144            {
145                revisionBlockStarted = false;
146            }
147            else
148            {
149                throw new IllegalStateException( "Working copy line found at the wrong state " );
150            }
151
152            return;
153        }
154
155        if ( !diffBlockProcessingStarted )
156        {
157            if ( logger.isWarnEnabled() )
158            {
159                logger.warn( "Unparseable line: '" + line + "'" );
160            }
161
162            return;
163        }
164
165        if ( line.startsWith( ADDED_LINE_TOKEN ) || line.startsWith( REMOVED_LINE_TOKEN )
166            || line.startsWith( UNCHANGED_LINE_TOKEN ) )
167        {
168            // add to buffer
169            currentDifference.append( line ).append( "\n" );
170        }
171        else
172        {
173            if ( logger.isWarnEnabled() )
174            {
175                logger.warn( "Unparseable line: '" + line + "'" );
176            }
177        }
178    }
179
180    /**
181     * Process the current input line in the Get Directory
182     *
183     * @param line a line of text from the Starteam log output
184     */
185    private void processGetDir( String line, int pos )
186    {
187        String dirPath = line.substring( pos + WORKING_DIR_TOKEN.length(), line.length() - 1 ).replace( '\\', '/' );
188
189        this.currentDir = dirPath;
190    }
191
192    private void extractCurrentFile( String line, int pos )
193    {
194        currentFile = line.substring( 0, pos );
195
196        changedFiles.add( new ScmFile( currentFile, ScmFileStatus.MODIFIED ) );
197
198        currentDifference = new StringBuilder();
199
200        differences.put( currentFile, currentDifference );
201    }
202
203    public List<ScmFile> getChangedFiles()
204    {
205        return changedFiles;
206    }
207
208    public Map<String,CharSequence> getDifferences()
209    {
210        return differences;
211    }
212
213    public String getPatch()
214    {
215        return patch.toString();
216    }
217
218}