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