View Javadoc

1   package org.apache.maven.scm.provider.git.gitexe.command.checkin;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.io.FilenameUtils;
23  import org.apache.maven.scm.ScmException;
24  import org.apache.maven.scm.ScmFile;
25  import org.apache.maven.scm.ScmFileSet;
26  import org.apache.maven.scm.ScmFileStatus;
27  import org.apache.maven.scm.ScmVersion;
28  import org.apache.maven.scm.command.checkin.AbstractCheckInCommand;
29  import org.apache.maven.scm.command.checkin.CheckInScmResult;
30  import org.apache.maven.scm.log.ScmLogger;
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.repository.GitScmProviderRepository;
34  import org.apache.maven.scm.provider.git.util.GitUtil;
35  import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
36  import org.apache.maven.scm.provider.git.gitexe.command.add.GitAddCommand;
37  import org.apache.maven.scm.provider.git.gitexe.command.branch.GitBranchCommand;
38  import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand;
39  import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusConsumer;
40  import org.codehaus.plexus.util.FileUtils;
41  import org.codehaus.plexus.util.cli.CommandLineUtils;
42  import org.codehaus.plexus.util.cli.Commandline;
43  
44  import java.io.File;
45  import java.io.IOException;
46  import java.util.ArrayList;
47  import java.util.List;
48  
49  /**
50   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
51   * @author Olivier Lamy
52   *
53   */
54  public class GitCheckInCommand
55      extends AbstractCheckInCommand
56      implements GitCommand
57  {
58      /** {@inheritDoc} */
59      protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message,
60                                                        ScmVersion version )
61          throws ScmException
62      {
63          GitScmProviderRepository repository = (GitScmProviderRepository) repo;
64  
65          CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
66          CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
67  
68          int exitCode;
69  
70          File messageFile = FileUtils.createTempFile( "maven-scm-", ".commit", null );
71          try
72          {
73              FileUtils.fileWrite( messageFile.getAbsolutePath(), message );
74          }
75          catch ( IOException ex )
76          {
77              return new CheckInScmResult( null, "Error while making a temporary file for the commit message: "
78                  + ex.getMessage(), null, false );
79          }
80  
81          try
82          {
83              if ( !fileSet.getFileList().isEmpty() )
84              {
85                  // if specific fileSet is given, we have to git-add them first
86                  // otherwise we will use 'git-commit -a' later
87  
88                  Commandline clAdd = GitAddCommand.createCommandLine( fileSet.getBasedir(), fileSet.getFileList() );
89  
90                  exitCode = GitCommandLineUtils.execute( clAdd, stdout, stderr, getLogger() );
91  
92                  if ( exitCode != 0 )
93                  {
94                      return new CheckInScmResult( clAdd.toString(), "The git-add command failed.", stderr.getOutput(),
95                                                   false );
96                  }
97  
98              }
99  
100             // git-commit doesn't show single files, but only summary :/
101             // so we must run git-status and consume the output
102             // borrow a few things from the git-status command
103             Commandline clStatus = GitStatusCommand.createCommandLine( repository, fileSet );
104 
105             GitStatusConsumer statusConsumer = new GitStatusConsumer( getLogger(), fileSet.getBasedir() );
106             exitCode = GitCommandLineUtils.execute( clStatus, statusConsumer, stderr, getLogger() );
107             if ( exitCode != 0 )
108             {
109                 // git-status returns non-zero if nothing to do
110                 if ( getLogger().isInfoEnabled() )
111                 {
112                     getLogger().info( "nothing added to commit but untracked files present (use \"git add\" to " +
113                             "track)" );
114                 }
115             }
116             
117             if ( statusConsumer.getChangedFiles().isEmpty() )
118             {
119                 return new CheckInScmResult( null, statusConsumer.getChangedFiles() );
120             }
121 
122             Commandline clCommit = createCommitCommandLine( repository, fileSet, messageFile );
123 
124             exitCode = GitCommandLineUtils.execute( clCommit, stdout, stderr, getLogger() );
125             if ( exitCode != 0 )
126             {
127                 return new CheckInScmResult( clCommit.toString(), "The git-commit command failed.", stderr.getOutput(),
128                                              false );
129             }
130 
131             if( repo.isPushChanges() ) 
132             {
133                 Commandline cl = createPushCommandLine( getLogger(), repository, fileSet, version );
134 
135                 exitCode = GitCommandLineUtils.execute( cl, stdout, stderr, getLogger() );
136                 if ( exitCode != 0 )
137                 {
138                     return new CheckInScmResult( cl.toString(), "The git-push command failed.", stderr.getOutput(), false );
139                 }                
140             }
141 
142             List<ScmFile> checkedInFiles = new ArrayList<ScmFile>( statusConsumer.getChangedFiles().size() );
143 
144             // rewrite all detected files to now have status 'checked_in'
145             for ( ScmFile changedFile : statusConsumer.getChangedFiles() )
146             {
147                 ScmFile scmfile = new ScmFile( changedFile.getPath(), ScmFileStatus.CHECKED_IN );
148 
149                 if ( fileSet.getFileList().isEmpty() )
150                 {
151                     checkedInFiles.add( scmfile );
152                 }
153                 else
154                 {
155                     // if a specific fileSet is given, we have to check if the file is really tracked
156                     for ( File f : fileSet.getFileList() )
157                     {
158                         if ( FilenameUtils.separatorsToUnix( f.getPath() ).equals( scmfile.getPath() ) )
159                         {
160                             checkedInFiles.add( scmfile );
161                         }
162 
163                     }
164                 }
165             }
166 
167             return new CheckInScmResult( clCommit.toString(), checkedInFiles );
168         }
169         finally
170         {
171             try
172             {
173                 FileUtils.forceDelete( messageFile );
174             }
175             catch ( IOException ex )
176             {
177                 // ignore
178             }
179         }
180 
181     }
182 
183     // ----------------------------------------------------------------------
184     //
185     // ----------------------------------------------------------------------
186 
187     public static Commandline createPushCommandLine( ScmLogger logger, GitScmProviderRepository repository,
188                                                      ScmFileSet fileSet, ScmVersion version )
189         throws ScmException
190     {
191         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "push" );
192 
193         String branch = GitBranchCommand.getCurrentBranch( logger, repository, fileSet );
194         
195         if ( branch == null || branch.length() == 0 )
196         {
197             throw new ScmException( "Could not detect the current branch. Don't know where I should push to!" );
198         }
199         
200         cl.createArg().setValue( repository.getPushUrl() );
201         
202         cl.createArg().setValue( branch + ":" + branch );
203 
204         return cl;
205     }
206 
207     public static Commandline createCommitCommandLine( GitScmProviderRepository repository, ScmFileSet fileSet,
208                                                        File messageFile )
209         throws ScmException
210     {
211         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "commit" );
212 
213         cl.createArg().setValue( "--verbose" );
214 
215         cl.createArg().setValue( "-F" );
216 
217         cl.createArg().setValue( messageFile.getAbsolutePath() );
218 
219         if ( fileSet.getFileList().isEmpty() )
220         {
221             // commit all tracked files
222             cl.createArg().setValue( "-a" );
223         }
224         else
225         {
226             // specify exactly which files to commit
227             GitCommandLineUtils.addTarget( cl, fileSet.getFileList() );
228         }
229 
230         if ( GitUtil.getSettings().isCommitNoVerify() )
231         {
232             cl.createArg().setValue( "--no-verify" );
233         }
234 
235         return cl;
236     }
237 
238 }