001    package 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    
022    import java.io.File;
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Map;
027    
028    import org.apache.maven.scm.ScmFile;
029    import org.apache.maven.scm.ScmFileStatus;
030    import org.apache.maven.scm.log.ScmLogger;
031    import org.codehaus.plexus.util.cli.StreamConsumer;
032    
033    /**
034     * @author <a href="mailto:dantran@gmail.com">Dan T. Tran</a>
035     * @version $Id: StarteamDiffConsumer.java 1306867 2012-03-29 13:45:10Z olamy $
036     */
037    public 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    }