View Javadoc
1   package org.apache.maven.scm.provider.git.gitexe.command.add;
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.ScmResult;
27  import org.apache.maven.scm.command.add.AbstractAddCommand;
28  import org.apache.maven.scm.command.add.AddScmResult;
29  import org.apache.maven.scm.provider.ScmProviderRepository;
30  import org.apache.maven.scm.provider.git.command.GitCommand;
31  import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
32  import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand;
33  import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusConsumer;
34  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
35  import org.codehaus.plexus.util.Os;
36  import org.codehaus.plexus.util.cli.CommandLineUtils;
37  import org.codehaus.plexus.util.cli.Commandline;
38  
39  import java.io.File;
40  import java.net.URI;
41  import java.util.ArrayList;
42  import java.util.Collections;
43  import java.util.List;
44  
45  /**
46   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
47   */
48  public class GitAddCommand
49      extends AbstractAddCommand
50      implements GitCommand
51  {
52      /**
53       * {@inheritDoc}
54       */
55      protected ScmResult executeAddCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message,
56                                             boolean binary )
57          throws ScmException
58      {
59          GitScmProviderRepository repository = (GitScmProviderRepository) repo;
60  
61          if ( fileSet.getFileList().isEmpty() )
62          {
63              throw new ScmException( "You must provide at least one file/directory to add" );
64          }
65  
66          AddScmResult result = executeAddFileSet( fileSet );
67  
68          if ( result != null )
69          {
70              return result;
71          }
72  
73          // SCM-709: statusCommand uses repositoryRoot instead of workingDirectory, adjust it with relativeRepositoryPath
74          URI relativeRepositoryPath = GitStatusCommand.getRelativeCWD( this, fileSet );
75  
76          int exitCode;
77          CommandLineUtils.StringStreamConsumer stderr;
78  
79          // git-add doesn't show single files, but only summary :/
80          // so we must run git-status and consume the output
81          // borrow a few things from the git-status command
82          Commandline clStatus = GitStatusCommand.createCommandLine( repository, fileSet );
83  
84          GitStatusConsumer statusConsumer =
85              new GitStatusConsumer( getLogger(), fileSet.getBasedir(), relativeRepositoryPath );
86          stderr = new CommandLineUtils.StringStreamConsumer();
87          exitCode = GitCommandLineUtils.execute( clStatus, statusConsumer, stderr, getLogger() );
88          if ( exitCode != 0 )
89          {
90              // git-status returns non-zero if nothing to do
91              if ( getLogger().isInfoEnabled() )
92              {
93                  getLogger().info( "nothing added to commit but untracked files present (use \"git add\" to track)" );
94              }
95          }
96  
97          List<ScmFile> changedFiles = new ArrayList<ScmFile>();
98  
99          // rewrite all detected files to now have status 'checked_in'
100         for ( ScmFile scmfile : statusConsumer.getChangedFiles() )
101         {
102             // if a specific fileSet is given, we have to check if the file is really tracked
103             for ( File f : fileSet.getFileList() )
104             {
105                 if ( FilenameUtils.separatorsToUnix( f.getPath() ).equals( scmfile.getPath() ) )
106                 {
107                     changedFiles.add( scmfile );
108                 }
109             }
110         }
111 
112         Commandline cl = createCommandLine( fileSet.getBasedir(), fileSet.getFileList() );
113         return new AddScmResult( cl.toString(), changedFiles );
114     }
115 
116     public static Commandline createCommandLine( File workingDirectory, List<File> files )
117         throws ScmException
118     {
119         Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "add" );
120 
121         // use this separator to make clear that the following parameters are files and not revision info.
122         cl.createArg().setValue( "--" );
123 
124         GitCommandLineUtils.addTarget( cl, files );
125 
126         return cl;
127     }
128 
129     private AddScmResult executeAddFileSet( ScmFileSet fileSet )
130         throws ScmException
131     {
132         File workingDirectory = fileSet.getBasedir();
133         List<File> files = fileSet.getFileList();
134 
135         // command line can be too long for windows so add files individually (see SCM-697)
136         if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
137         {
138             for ( File file : files )
139             {
140                 AddScmResult result = executeAddFiles( workingDirectory, Collections.singletonList( file ) );
141 
142                 if ( result != null )
143                 {
144                     return result;
145                 }
146             }
147         }
148         else
149         {
150             AddScmResult result = executeAddFiles( workingDirectory, files );
151 
152             if ( result != null )
153             {
154                 return result;
155             }
156         }
157 
158         return null;
159     }
160 
161     private AddScmResult executeAddFiles( File workingDirectory, List<File> files )
162         throws ScmException
163     {
164         Commandline cl = createCommandLine( workingDirectory, files );
165 
166         CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
167         CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
168 
169         int exitCode = GitCommandLineUtils.execute( cl, stdout, stderr, getLogger() );
170 
171         if ( exitCode != 0 )
172         {
173             return new AddScmResult( cl.toString(), "The git-add command failed.", stderr.getOutput(), false );
174         }
175 
176         return null;
177     }
178 }