001    package org.apache.maven.scm.provider.git.gitexe.command.status;
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.commons.lang.StringUtils;
023    import org.apache.maven.scm.ScmFile;
024    import org.apache.maven.scm.ScmFileStatus;
025    import org.apache.maven.scm.log.ScmLogger;
026    import org.apache.regexp.RE;
027    import org.apache.regexp.RESyntaxException;
028    import org.codehaus.plexus.util.cli.StreamConsumer;
029    
030    import java.io.File;
031    import java.util.ArrayList;
032    import java.util.List;
033    
034    /**
035     * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
036     */
037    public class GitStatusConsumer
038        implements StreamConsumer
039    {
040        /**
041         * The pattern used to match added file lines
042         */
043        private static final String ADDED_PATTERN = "^A[ M]* (.*)$";
044    
045        /**
046         * The pattern used to match modified file lines
047         */
048        private static final String MODIFIED_PATTERN = "^ *M[ M]* (.*)$";
049    
050        /**
051         * The pattern used to match deleted file lines
052         */
053        private static final String DELETED_PATTERN = "^ *D * (.*)$";
054    
055        /**
056         * The pattern used to match renamed file lines
057         */
058        private static final String RENAMED_PATTERN = "R (.*) -> (.*)$";
059    
060        /**
061         * @see #ADDED_PATTERN
062         */
063        private RE addedRegexp;
064    
065        /**
066         * @see #MODIFIED_PATTERN
067         */
068        private RE modifiedRegexp;
069    
070        /**
071         * @see #DELETED_PATTERN
072         */
073        private RE deletedRegexp;
074    
075        /**
076         * @see #RENAMED_PATTERN
077         */
078        private RE renamedRegexp;
079    
080        private ScmLogger logger;
081    
082        private File workingDirectory;
083    
084        private List<ScmFile> changedFiles = new ArrayList<ScmFile>();
085    
086        // ----------------------------------------------------------------------
087        //
088        // ----------------------------------------------------------------------
089    
090        public GitStatusConsumer( ScmLogger logger, File workingDirectory )
091        {
092            this.logger = logger;
093            this.workingDirectory = workingDirectory;
094    
095            try
096            {
097                addedRegexp = new RE( ADDED_PATTERN );
098                modifiedRegexp = new RE( MODIFIED_PATTERN );
099                deletedRegexp = new RE( DELETED_PATTERN );
100                renamedRegexp = new RE( RENAMED_PATTERN );
101            }
102            catch ( RESyntaxException ex )
103            {
104                throw new RuntimeException(
105                    "INTERNAL ERROR: Could not create regexp to parse git log file. This shouldn't happen. Something is probably wrong with the oro installation.",
106                    ex );
107            }
108        }
109    
110        // ----------------------------------------------------------------------
111        // StreamConsumer Implementation
112        // ----------------------------------------------------------------------
113    
114        /**
115         * {@inheritDoc}
116         */
117        public void consumeLine( String line )
118        {
119            if ( logger.isDebugEnabled() )
120            {
121                logger.debug( line );
122            }
123            if ( StringUtils.isEmpty( line ) )
124            {
125                return;
126            }
127    
128            ScmFileStatus status = null;
129    
130            List<String> files = new ArrayList<String>();
131    
132            if ( addedRegexp.match( line ) )
133            {
134                status = ScmFileStatus.ADDED;
135                files.add( addedRegexp.getParen( 1 ) );
136            }
137            else if ( modifiedRegexp.match( line ) )
138            {
139                status = ScmFileStatus.MODIFIED;
140                files.add( modifiedRegexp.getParen( 1 ) );
141            }
142            else if ( deletedRegexp.match( line ) )
143            {
144                status = ScmFileStatus.DELETED;
145                files.add( deletedRegexp.getParen( 1 ) );
146            }
147            else if ( renamedRegexp.match( line ) )
148            {
149                status = ScmFileStatus.RENAMED;
150                files.add( StringUtils.trim( renamedRegexp.getParen( 1 ) ) );
151                files.add( StringUtils.trim( renamedRegexp.getParen( 2 ) ) );
152                logger.debug( "RENAMED status for line '" + line + "' files added '" + renamedRegexp.getParen( 1 ) + "' '"
153                                  + renamedRegexp.getParen( 2 ) );
154            }
155    
156            // If the file isn't a file; don't add it.
157            if ( !files.isEmpty() && status != null )
158            {
159                if ( workingDirectory != null )
160                {
161                    if ( status == ScmFileStatus.RENAMED )
162                    {
163                        String oldFilePath = files.get( 0 );
164                        String newFilePath = files.get( 1 );
165                        if ( new File( workingDirectory, oldFilePath ).isFile() )
166                        {
167                            logger.debug(
168                                "file '" + new File( workingDirectory, oldFilePath ).getAbsolutePath() + "' is a file" );
169                            return;
170                        }
171                        else
172                        {
173                            logger.debug(
174                                "file '" + new File( workingDirectory, oldFilePath ).getAbsolutePath() + "' not a file" );
175                        }
176                        if ( !new File( workingDirectory, newFilePath ).isFile() )
177                        {
178                            logger.debug(
179                                "file '" + new File( workingDirectory, newFilePath ).getAbsolutePath() + "' not a file" );
180                            return;
181                        }
182                        else
183                        {
184                            logger.debug(
185                                "file '" + new File( workingDirectory, newFilePath ).getAbsolutePath() + "' is a file" );
186                        }
187                    }
188                    else if ( status == ScmFileStatus.DELETED )
189                    {
190                        if ( new File( workingDirectory, files.get( 0 ) ).isFile() )
191                        {
192                            return;
193                        }
194                    }
195                    else
196                    {
197                        if ( !new File( workingDirectory, files.get( 0 ) ).isFile() )
198                        {
199                            return;
200                        }
201                    }
202                }
203    
204                for ( String file : files )
205                {
206                    changedFiles.add( new ScmFile( file, status ) );
207                }
208            }
209        }
210    
211        public List<ScmFile> getChangedFiles()
212        {
213            return changedFiles;
214        }
215    }