001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.scm.provider.git.gitexe.command.add; 020 021import java.io.File; 022import java.net.URI; 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.List; 026 027import org.apache.commons.io.FilenameUtils; 028import org.apache.maven.scm.ScmException; 029import org.apache.maven.scm.ScmFile; 030import org.apache.maven.scm.ScmFileSet; 031import org.apache.maven.scm.ScmResult; 032import org.apache.maven.scm.command.add.AbstractAddCommand; 033import org.apache.maven.scm.command.add.AddScmResult; 034import org.apache.maven.scm.provider.ScmProviderRepository; 035import org.apache.maven.scm.provider.git.command.GitCommand; 036import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils; 037import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand; 038import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusConsumer; 039import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; 040import org.codehaus.plexus.util.Os; 041import org.codehaus.plexus.util.cli.CommandLineUtils; 042import org.codehaus.plexus.util.cli.Commandline; 043 044/** 045 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a> 046 */ 047public class GitAddCommand extends AbstractAddCommand implements GitCommand { 048 /** 049 * {@inheritDoc} 050 */ 051 protected ScmResult executeAddCommand( 052 ScmProviderRepository repo, ScmFileSet fileSet, String message, boolean binary) throws ScmException { 053 GitScmProviderRepository repository = (GitScmProviderRepository) repo; 054 055 if (fileSet.getFileList().isEmpty()) { 056 throw new ScmException("You must provide at least one file/directory to add"); 057 } 058 059 AddScmResult result = executeAddFileSet(fileSet); 060 061 if (result != null) { 062 return result; 063 } 064 065 // SCM-709: statusCommand uses repositoryRoot instead of workingDirectory, adjust it with relativeRepositoryPath 066 URI relativeRepositoryPath = GitStatusCommand.getRelativeCWD(logger, fileSet); 067 068 int exitCode; 069 CommandLineUtils.StringStreamConsumer stderr; 070 071 // git-add doesn't show single files, but only summary :/ 072 // so we must run git-status and consume the output 073 // borrow a few things from the git-status command 074 Commandline clStatus = GitStatusCommand.createCommandLine(repository, fileSet); 075 076 GitStatusConsumer statusConsumer = new GitStatusConsumer(fileSet.getBasedir(), relativeRepositoryPath); 077 stderr = new CommandLineUtils.StringStreamConsumer(); 078 exitCode = GitCommandLineUtils.execute(clStatus, statusConsumer, stderr); 079 if (exitCode != 0) { 080 // git-status returns non-zero if nothing to do 081 if (logger.isInfoEnabled()) { 082 logger.info("nothing added to commit but untracked files present (use \"git add\" to track)"); 083 } 084 } 085 086 List<ScmFile> changedFiles = new ArrayList<>(); 087 088 // rewrite all detected files to now have status 'checked_in' 089 for (ScmFile scmfile : statusConsumer.getChangedFiles()) { 090 // if a specific fileSet is given, we have to check if the file is really tracked 091 for (File f : fileSet.getFileList()) { 092 if (FilenameUtils.separatorsToUnix(f.getPath()).equals(scmfile.getPath())) { 093 changedFiles.add(scmfile); 094 } 095 } 096 } 097 098 Commandline cl = createCommandLine(fileSet.getBasedir(), fileSet.getFileList()); 099 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}