View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.scm.provider.git.gitexe.command.update;
20  
21  import java.io.File;
22  
23  import org.apache.maven.scm.ScmBranch;
24  import org.apache.maven.scm.ScmException;
25  import org.apache.maven.scm.ScmFileSet;
26  import org.apache.maven.scm.ScmVersion;
27  import org.apache.maven.scm.command.changelog.ChangeLogCommand;
28  import org.apache.maven.scm.command.update.AbstractUpdateCommand;
29  import org.apache.maven.scm.command.update.UpdateScmResult;
30  import org.apache.maven.scm.command.update.UpdateScmResultWithRevision;
31  import org.apache.maven.scm.provider.ScmProviderRepository;
32  import org.apache.maven.scm.provider.git.command.GitCommand;
33  import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
34  import org.apache.maven.scm.provider.git.gitexe.command.changelog.GitChangeLogCommand;
35  import org.apache.maven.scm.provider.git.gitexe.command.diff.GitDiffCommand;
36  import org.apache.maven.scm.provider.git.gitexe.command.diff.GitDiffRawConsumer;
37  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
38  import org.codehaus.plexus.util.cli.CommandLineUtils;
39  import org.codehaus.plexus.util.cli.Commandline;
40  
41  /**
42   * @author Olivier Lamy
43   * @author <a href="mailto:struberg@yahoo.de">struberg</a>
44   * @since 10 august 2008
45   */
46  public class GitUpdateCommand extends AbstractUpdateCommand implements GitCommand {
47      /**
48       * {@inheritDoc}
49       */
50      protected UpdateScmResult executeUpdateCommand(
51              ScmProviderRepository repo, ScmFileSet fileSet, ScmVersion scmVersion) throws ScmException {
52          GitScmProviderRepository repository = (GitScmProviderRepository) repo;
53  
54          if (GitScmProviderRepository.PROTOCOL_FILE.equals(
55                          repository.getFetchInfo().getProtocol())
56                  && repository
57                                  .getFetchInfo()
58                                  .getPath()
59                                  .indexOf(fileSet.getBasedir().getPath())
60                          >= 0) {
61              throw new ScmException("remote repository must not be the working directory");
62          }
63  
64          int exitCode;
65  
66          CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
67          CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
68  
69          // fir we need to get the current reversion
70          Commandline clRev = createLatestRevisionCommandLine(repository, fileSet.getBasedir(), scmVersion);
71          GitLatestRevisionCommandConsumer consumerRev = new GitLatestRevisionCommandConsumer();
72          exitCode = GitCommandLineUtils.execute(clRev, consumerRev, stderr);
73          if (exitCode != 0) {
74              return new UpdateScmResult(clRev.toString(), "The git-log command failed.", stderr.getOutput(), false);
75          }
76          String origSha1 = consumerRev.getLatestRevision();
77  
78          Commandline cl = createCommandLine(repository, fileSet.getBasedir(), scmVersion);
79          exitCode = GitCommandLineUtils.execute(cl, stdout, stderr);
80          if (exitCode != 0) {
81              return new UpdateScmResult(cl.toString(), "The git-pull command failed.", stderr.getOutput(), false);
82          }
83  
84          // we also need to log exactly what has been updated
85          GitDiffRawConsumer diffRawConsumer = new GitDiffRawConsumer();
86          Commandline clDiffRaw = GitDiffCommand.createDiffRawCommandLine(fileSet.getBasedir(), origSha1);
87          exitCode = GitCommandLineUtils.execute(clDiffRaw, diffRawConsumer, stderr);
88          if (exitCode != 0) {
89              return new UpdateScmResult(
90                      clDiffRaw.toString(), "The git-diff --raw command failed.", stderr.getOutput(), false);
91          }
92  
93          // now let's get the latest version
94          consumerRev = new GitLatestRevisionCommandConsumer();
95          exitCode = GitCommandLineUtils.execute(clRev, consumerRev, stderr);
96          if (exitCode != 0) {
97              return new UpdateScmResult(clRev.toString(), "The git-log command failed.", stderr.getOutput(), false);
98          }
99          String latestRevision = consumerRev.getLatestRevision();
100 
101         return new UpdateScmResultWithRevision(cl.toString(), diffRawConsumer.getChangedFiles(), latestRevision);
102     }
103 
104     /**
105      * {@inheritDoc}
106      */
107     protected ChangeLogCommand getChangeLogCommand() {
108         return new GitChangeLogCommand();
109     }
110 
111     /**
112      * Create the command line for updating the current branch with the info from the foreign repository.
113      */
114     public static Commandline createCommandLine(
115             GitScmProviderRepository repository, File workingDirectory, ScmVersion scmVersion) {
116         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "pull");
117 
118         cl.createArg().setLine(repository.getFetchUrl());
119 
120         // now set the branch where we would like to pull from
121         if (scmVersion instanceof ScmBranch) {
122             cl.createArg().setLine(scmVersion.getName());
123         }
124 
125         return cl;
126     }
127 
128     /**
129      * @param scmVersion a valid branch or <code>null</code> if the master branch should be taken
130      * @return CommandLine for getting the latest commit on the given branch
131      */
132     public static Commandline createLatestRevisionCommandLine(
133             GitScmProviderRepository repository, File workingDirectory, ScmVersion scmVersion) {
134         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "log");
135 
136         // only show exactly 1 commit
137         cl.createArg().setValue("-n1");
138 
139         // same as --topo-order, but ensure ordering of merges
140         cl.createArg().setValue("--date-order");
141 
142         if (scmVersion instanceof ScmBranch
143                 && scmVersion.getName() != null
144                 && scmVersion.getName().length() > 0) {
145             // if any branch is given, lets take em
146             cl.createArg().setValue(scmVersion.getName());
147         }
148         // otherwise we work on HEAD/current branch
149 
150         return cl;
151     }
152 }