001    package org.apache.maven.scm.provider.cvslib.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.codehaus.plexus.util.cli.StreamConsumer;
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:brett@apache.org">Brett Porter</a>
035     * @author Olivier Lamy
036     * @version $Id: CvsDiffConsumer.java 1056981 2011-01-09 17:24:53Z olamy $
037     * @todo share with SVN (3 extra lines can be ignored)
038     */
039    public class CvsDiffConsumer
040        implements StreamConsumer
041    {
042        //
043        // Index: plugin.jelly
044        // ===================================================================
045        // RCS file: /home/cvs/maven-scm/maven-scm-providers/maven-scm-provider-cvs/
046        //           src/main/resources/META-INF/plexus/components.xml,v
047        // retrieving revision 1.2
048        // diff -u -r1.2 components.xml
049        // --- plugin.jelly        (revision 124799)
050        // +++ plugin.jelly        (working copy)
051        //
052    
053        private static final String RCS_TOKEN = "RCS file: ";
054    
055        private static final String RETRIEVING_TOKEN = "retrieving revision ";
056    
057        private static final String DIFF_TOKEN = "diff ";
058    
059        private static final String INDEX_TOKEN = "Index: ";
060    
061        private static final String FILE_SEPARATOR_TOKEN = "===";
062    
063        private static final String START_REVISION_TOKEN = "---";
064    
065        private static final String END_REVISION_TOKEN = "+++";
066    
067        private static final String ADDED_LINE_TOKEN = "+";
068    
069        private static final String REMOVED_LINE_TOKEN = "-";
070    
071        private static final String UNCHANGED_LINE_TOKEN = " ";
072    
073        private static final String CHANGE_SEPARATOR_TOKEN = "@@";
074    
075        private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
076    
077        private ScmLogger logger;
078    
079        private String currentFile;
080    
081        private StringBuilder currentDifference;
082    
083        private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
084    
085        private Map<String,CharSequence> differences = new HashMap<String,CharSequence>();
086    
087        private StringBuilder patch = new StringBuilder();
088    
089        // ----------------------------------------------------------------------
090        //
091        // ----------------------------------------------------------------------
092    
093        public CvsDiffConsumer( ScmLogger logger, File workingDirectory )
094        {
095            this.logger = logger;
096        }
097    
098        // ----------------------------------------------------------------------
099        // StreamConsumer Implementation
100        // ----------------------------------------------------------------------
101    
102        /** {@inheritDoc} */
103        public void consumeLine( String line )
104        {
105            if ( logger.isDebugEnabled() )
106            {
107                logger.debug( line );
108            }
109    
110            if ( line.startsWith( INDEX_TOKEN ) )
111            {
112                // start a new file
113                currentFile = line.substring( INDEX_TOKEN.length() );
114    
115                changedFiles.add( new ScmFile( currentFile, ScmFileStatus.MODIFIED ) );
116    
117                currentDifference = new StringBuilder();
118    
119                differences.put( currentFile, currentDifference );
120    
121                patch.append( line ).append( "\n" );
122    
123                return;
124            }
125    
126            if ( currentFile == null )
127            {
128                if ( logger.isWarnEnabled() )
129                {
130                    logger.warn( "Unparseable line: '" + line + "'" );
131                }
132                patch.append( line ).append( "\n" );
133                return;
134            }
135    
136            if ( line.startsWith( FILE_SEPARATOR_TOKEN ) )
137            {
138                // skip
139                patch.append( line ).append( "\n" );
140            }
141            else if ( line.startsWith( START_REVISION_TOKEN ) )
142            {
143                // skip, though could parse to verify filename, start revision
144                patch.append( line ).append( "\n" );
145            }
146            else if ( line.startsWith( END_REVISION_TOKEN ) )
147            {
148                // skip, though could parse to verify filename, end revision
149                patch.append( line ).append( "\n" );
150            }
151            else if ( line.startsWith( RCS_TOKEN ) )
152            {
153                // skip, though could parse to verify filename
154            }
155            else if ( line.startsWith( RETRIEVING_TOKEN ) )
156            {
157                // skip, though could parse to verify version
158            }
159            else if ( line.startsWith( DIFF_TOKEN ) )
160            {
161                // skip, though could parse to verify command
162            }
163            else if ( line.startsWith( ADDED_LINE_TOKEN ) || line.startsWith( REMOVED_LINE_TOKEN )
164                || line.startsWith( UNCHANGED_LINE_TOKEN ) || line.startsWith( CHANGE_SEPARATOR_TOKEN )
165                || line.equals( NO_NEWLINE_TOKEN ) )
166            {
167                // add to buffer
168                currentDifference.append( line ).append( "\n" );
169                patch.append( line ).append( "\n" );
170            }
171            else
172            {
173                if ( logger.isWarnEnabled() )
174                {
175                    logger.warn( "Unparseable line: '" + line + "'" );
176                }
177                patch.append( line ).append( "\n" );
178                // skip to next file
179                currentFile = null;
180                currentDifference = null;
181            }
182        }
183    
184        public List<ScmFile> getChangedFiles()
185        {
186            return changedFiles;
187        }
188    
189        public Map<String,CharSequence> getDifferences()
190        {
191            return differences;
192        }
193    
194        public String getPatch()
195        {
196            return patch.toString();
197        }
198    
199    }