001    package org.apache.maven.scm.provider.git.gitexe.command.update;
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    
024    import org.apache.maven.scm.ScmBranch;
025    import org.apache.maven.scm.ScmException;
026    import org.apache.maven.scm.ScmFileSet;
027    import org.apache.maven.scm.ScmVersion;
028    import org.apache.maven.scm.command.changelog.ChangeLogCommand;
029    import org.apache.maven.scm.command.update.AbstractUpdateCommand;
030    import org.apache.maven.scm.command.update.UpdateScmResult;
031    import org.apache.maven.scm.command.update.UpdateScmResultWithRevision;
032    import org.apache.maven.scm.provider.ScmProviderRepository;
033    import org.apache.maven.scm.provider.git.command.GitCommand;
034    import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
035    import org.apache.maven.scm.provider.git.gitexe.command.changelog.GitChangeLogCommand;
036    import org.apache.maven.scm.provider.git.gitexe.command.diff.GitDiffCommand;
037    import org.apache.maven.scm.provider.git.gitexe.command.diff.GitDiffRawConsumer;
038    import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
039    import org.codehaus.plexus.util.cli.CommandLineUtils;
040    import org.codehaus.plexus.util.cli.Commandline;
041    
042    /**
043     * @author <a href="mailto:olamy@apache.org">olamy</a>
044     * @author <a href="mailto:struberg@yahoo.de">struberg</a>
045     * @since 10 august 2008
046     * @version $Id: GitUpdateCommand.java 1241527 2012-02-07 17:29:40Z struberg $
047     */
048    public class GitUpdateCommand
049        extends AbstractUpdateCommand
050        implements GitCommand
051    {
052        /** {@inheritDoc} */
053        protected UpdateScmResult executeUpdateCommand( ScmProviderRepository repo, ScmFileSet fileSet,
054                                                        ScmVersion scmVersion )
055            throws ScmException
056        {
057            GitScmProviderRepository repository = (GitScmProviderRepository) repo;
058    
059            if ( GitScmProviderRepository.PROTOCOL_FILE.equals( repository.getFetchInfo().getProtocol() )
060                && repository.getFetchInfo().getPath().indexOf( fileSet.getBasedir().getPath() ) >= 0 )
061            {
062                throw new ScmException( "remote repository must not be the working directory" );
063            }
064    
065            int exitCode;
066    
067            CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
068            CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
069    
070            // fir we need to get the current reversion
071            Commandline clRev = createLatestRevisionCommandLine( repository, fileSet.getBasedir(), scmVersion );
072            GitLatestRevisionCommandConsumer consumerRev = new GitLatestRevisionCommandConsumer( getLogger() );
073            exitCode = GitCommandLineUtils.execute( clRev, consumerRev, stderr, getLogger() );
074            if ( exitCode != 0 )
075            {
076                return new UpdateScmResult( clRev.toString(), "The git-log command failed.",
077                        stderr.getOutput(), false );
078            }
079            String origSha1 = consumerRev.getLatestRevision();
080    
081            Commandline cl = createCommandLine( repository, fileSet.getBasedir(), scmVersion );
082            exitCode = GitCommandLineUtils.execute( cl, stdout, stderr, getLogger() );
083            if ( exitCode != 0 )
084            {
085                return new UpdateScmResult( cl.toString(), "The git-pull command failed.",
086                                            stderr.getOutput(), false );
087            }
088    
089            // we also need to log exactly what has been updated
090            GitDiffRawConsumer diffRawConsumer = new GitDiffRawConsumer( getLogger() );
091            Commandline clDiffRaw = GitDiffCommand.createDiffRawCommandLine( fileSet.getBasedir(), origSha1 );
092            exitCode = GitCommandLineUtils.execute( clDiffRaw, diffRawConsumer, stderr, getLogger() );
093            if ( exitCode != 0 )
094            {
095                return new UpdateScmResult( clDiffRaw.toString(), "The git-diff --raw command failed.",
096                        stderr.getOutput(), false );
097            }
098    
099            
100            // now let's get the latest version
101            consumerRev = new GitLatestRevisionCommandConsumer( getLogger() );
102            exitCode = GitCommandLineUtils.execute( clRev, consumerRev, stderr, getLogger() );
103            if ( exitCode != 0 )
104            {
105                return new UpdateScmResult( clRev.toString(), "The git-log command failed.",
106                                            stderr.getOutput(), false );
107            }
108            String latestRevision = consumerRev.getLatestRevision();
109            
110            return new UpdateScmResultWithRevision( cl.toString(), diffRawConsumer.getChangedFiles(), latestRevision );
111        }
112    
113        /** {@inheritDoc} */
114        protected ChangeLogCommand getChangeLogCommand()
115        {
116            GitChangeLogCommand changelogCmd = new GitChangeLogCommand();
117            changelogCmd.setLogger( getLogger() );
118            
119            return changelogCmd;
120        }
121        
122        /**
123         * create the command line for updating the current branch with the info from the foreign repository. 
124         */
125        public static Commandline createCommandLine( GitScmProviderRepository repository, File workingDirectory, ScmVersion scmVersion ) 
126        {
127            Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "pull" );
128            
129            cl.createArg().setLine( repository.getFetchUrl() );
130    
131            // now set the branch where we would like to pull from
132            if ( scmVersion instanceof ScmBranch )
133            {
134                cl.createArg().setLine( scmVersion.getName() );
135            }
136            else
137            {
138                cl.createArg().setLine( "master" );
139            }            
140            
141            return cl;
142        }
143        
144        /**
145         * @param scmVersion a valid branch or <code>null</code> if the master branch should be taken
146         * @return CommandLine for getting the latest commit on the given branch
147         */
148        public static Commandline createLatestRevisionCommandLine(GitScmProviderRepository repository, File workingDirectory,
149                                                                   ScmVersion scmVersion)
150        {
151            Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "log" );
152            
153            // only show exactly 1 commit
154            cl.createArg().setValue( "-n1" ); 
155            
156            // same as --topo-order, but ensure ordering of merges
157            cl.createArg().setValue( "--date-order" );
158            
159            if ( scmVersion != null && scmVersion instanceof ScmBranch && 
160                 scmVersion.getName() != null && scmVersion.getName().length() > 0 )
161            {
162                // if any branch is given, lets take em
163                cl.createArg().setValue( scmVersion.getName() );
164            }
165            else
166            {
167                // otherwise we work on the master branch
168                cl.createArg().setValue( "master" );
169            }
170            
171            return cl;
172        }
173    }