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   */
47  public class GitUpdateCommand extends AbstractUpdateCommand implements GitCommand {
48      /** {@inheritDoc} */
49      protected UpdateScmResult executeUpdateCommand(
50              ScmProviderRepository repo, ScmFileSet fileSet, ScmVersion scmVersion) throws ScmException {
51          GitScmProviderRepository repository = (GitScmProviderRepository) repo;
52  
53          if (GitScmProviderRepository.PROTOCOL_FILE.equals(
54                          repository.getFetchInfo().getProtocol())
55                  && repository
56                                  .getFetchInfo()
57                                  .getPath()
58                                  .indexOf(fileSet.getBasedir().getPath())
59                          >= 0) {
60              throw new ScmException("remote repository must not be the working directory");
61          }
62  
63          int exitCode;
64  
65          CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
66          CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
67  
68          // fir we need to get the current reversion
69          Commandline clRev = createLatestRevisionCommandLine(repository, fileSet.getBasedir(), scmVersion);
70          GitLatestRevisionCommandConsumer consumerRev = new GitLatestRevisionCommandConsumer();
71          exitCode = GitCommandLineUtils.execute(clRev, consumerRev, stderr);
72          if (exitCode != 0) {
73              return new UpdateScmResult(clRev.toString(), "The git-log command failed.", stderr.getOutput(), false);
74          }
75          String origSha1 = consumerRev.getLatestRevision();
76  
77          Commandline cl = createCommandLine(repository, fileSet.getBasedir(), scmVersion);
78          exitCode = GitCommandLineUtils.execute(cl, stdout, stderr);
79          if (exitCode != 0) {
80              return new UpdateScmResult(cl.toString(), "The git-pull command failed.", stderr.getOutput(), false);
81          }
82  
83          // we also need to log exactly what has been updated
84          GitDiffRawConsumer diffRawConsumer = new GitDiffRawConsumer();
85          Commandline clDiffRaw = GitDiffCommand.createDiffRawCommandLine(fileSet.getBasedir(), origSha1);
86          exitCode = GitCommandLineUtils.execute(clDiffRaw, diffRawConsumer, stderr);
87          if (exitCode != 0) {
88              return new UpdateScmResult(
89                      clDiffRaw.toString(), "The git-diff --raw command failed.", stderr.getOutput(), false);
90          }
91  
92          // now let's get the latest version
93          consumerRev = new GitLatestRevisionCommandConsumer();
94          exitCode = GitCommandLineUtils.execute(clRev, consumerRev, stderr);
95          if (exitCode != 0) {
96              return new UpdateScmResult(clRev.toString(), "The git-log command failed.", stderr.getOutput(), false);
97          }
98          String latestRevision = consumerRev.getLatestRevision();
99  
100         return new UpdateScmResultWithRevision(cl.toString(), diffRawConsumer.getChangedFiles(), latestRevision);
101     }
102 
103     /** {@inheritDoc} */
104     protected ChangeLogCommand getChangeLogCommand() {
105         return new GitChangeLogCommand();
106     }
107 
108     /**
109      * create the command line for updating the current branch with the info from the foreign repository.
110      */
111     public static Commandline createCommandLine(
112             GitScmProviderRepository repository, File workingDirectory, ScmVersion scmVersion) {
113         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "pull");
114 
115         cl.createArg().setLine(repository.getFetchUrl());
116 
117         // now set the branch where we would like to pull from
118         if (scmVersion instanceof ScmBranch) {
119             cl.createArg().setLine(scmVersion.getName());
120         }
121 
122         return cl;
123     }
124 
125     /**
126      * @param scmVersion a valid branch or <code>null</code> if the master branch should be taken
127      * @return CommandLine for getting the latest commit on the given branch
128      */
129     public static Commandline createLatestRevisionCommandLine(
130             GitScmProviderRepository repository, File workingDirectory, ScmVersion scmVersion) {
131         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine(workingDirectory, "log");
132 
133         // only show exactly 1 commit
134         cl.createArg().setValue("-n1");
135 
136         // same as --topo-order, but ensure ordering of merges
137         cl.createArg().setValue("--date-order");
138 
139         if (scmVersion != null
140                 && scmVersion instanceof ScmBranch
141                 && scmVersion.getName() != null
142                 && scmVersion.getName().length() > 0) {
143             // if any branch is given, lets take em
144             cl.createArg().setValue(scmVersion.getName());
145         }
146         // otherwise we work on HEAD/current branch
147 
148         return cl;
149     }
150 }