001 package org.apache.maven.scm.provider.git.gitexe.command.add;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.apache.commons.io.FilenameUtils;
023 import org.apache.maven.scm.ScmException;
024 import org.apache.maven.scm.ScmFile;
025 import org.apache.maven.scm.ScmFileSet;
026 import org.apache.maven.scm.ScmResult;
027 import org.apache.maven.scm.command.add.AbstractAddCommand;
028 import org.apache.maven.scm.command.add.AddScmResult;
029 import org.apache.maven.scm.provider.ScmProviderRepository;
030 import org.apache.maven.scm.provider.git.command.GitCommand;
031 import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
032 import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand;
033 import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusConsumer;
034 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
035 import org.codehaus.plexus.util.Os;
036 import org.codehaus.plexus.util.cli.CommandLineUtils;
037 import org.codehaus.plexus.util.cli.Commandline;
038
039 import java.io.File;
040 import java.util.ArrayList;
041 import java.util.Collections;
042 import java.util.List;
043
044 /**
045 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
046 */
047 public class GitAddCommand
048 extends AbstractAddCommand
049 implements GitCommand
050 {
051 /**
052 * {@inheritDoc}
053 */
054 protected ScmResult executeAddCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message,
055 boolean binary )
056 throws ScmException
057 {
058 GitScmProviderRepository repository = (GitScmProviderRepository) repo;
059
060 if ( fileSet.getFileList().isEmpty() )
061 {
062 throw new ScmException( "You must provide at least one file/directory to add" );
063 }
064
065 AddScmResult result = executeAddFileSet( fileSet );
066
067 if ( result != null )
068 {
069 return result;
070 }
071
072 // git-add doesn't show single files, but only summary :/
073 // so we must run git-status and consume the output
074 // borrow a few things from the git-status command
075 Commandline clStatus = GitStatusCommand.createCommandLine( repository, fileSet );
076
077 GitStatusConsumer statusConsumer = new GitStatusConsumer( getLogger(), fileSet.getBasedir() );
078 CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
079 int exitCode = GitCommandLineUtils.execute( clStatus, statusConsumer, stderr, getLogger() );
080 if ( exitCode != 0 )
081 {
082 // git-status returns non-zero if nothing to do
083 if ( getLogger().isInfoEnabled() )
084 {
085 getLogger().info( "nothing added to commit but untracked files present (use \"git add\" to track)" );
086 }
087 }
088
089 List<ScmFile> changedFiles = new ArrayList<ScmFile>();
090
091 // rewrite all detected files to now have status 'checked_in'
092 for ( ScmFile scmfile : statusConsumer.getChangedFiles() )
093 {
094 // if a specific fileSet is given, we have to check if the file is really tracked
095 for ( File f : fileSet.getFileList() )
096 {
097 if ( FilenameUtils.separatorsToUnix( f.getPath() ).equals( scmfile.getPath() ) )
098 {
099 changedFiles.add( scmfile );
100 }
101 }
102 }
103
104 Commandline cl = createCommandLine( fileSet.getBasedir(), fileSet.getFileList() );
105 return new AddScmResult( cl.toString(), changedFiles );
106 }
107
108 public static Commandline createCommandLine( File workingDirectory, List<File> files )
109 throws ScmException
110 {
111 Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "add" );
112
113 // use this separator to make clear that the following parameters are files and not revision info.
114 cl.createArg().setValue( "--" );
115
116 GitCommandLineUtils.addTarget( cl, files );
117
118 return cl;
119 }
120
121 private AddScmResult executeAddFileSet( ScmFileSet fileSet )
122 throws ScmException
123 {
124 File workingDirectory = fileSet.getBasedir();
125 List<File> files = fileSet.getFileList();
126
127 // command line can be too long for windows so add files individually (see SCM-697)
128 if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
129 {
130 for ( File file : files )
131 {
132 AddScmResult result = executeAddFiles( workingDirectory, Collections.singletonList( file ) );
133
134 if ( result != null )
135 {
136 return result;
137 }
138 }
139 }
140 else
141 {
142 AddScmResult result = executeAddFiles( workingDirectory, files );
143
144 if ( result != null )
145 {
146 return result;
147 }
148 }
149
150 return null;
151 }
152
153 private AddScmResult executeAddFiles( File workingDirectory, List<File> files )
154 throws ScmException
155 {
156 Commandline cl = createCommandLine( workingDirectory, files );
157
158 CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
159 CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
160
161 int exitCode = GitCommandLineUtils.execute( cl, stdout, stderr, getLogger() );
162
163 if ( exitCode != 0 )
164 {
165 return new AddScmResult( cl.toString(), "The git-add command failed.", stderr.getOutput(), false );
166 }
167
168 return null;
169 }
170 }