001package org.apache.maven.scm.provider.git.gitexe.command.checkout; 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 022import org.apache.maven.scm.ScmBranch; 023import org.apache.maven.scm.ScmException; 024import org.apache.maven.scm.ScmFileSet; 025import org.apache.maven.scm.ScmFileStatus; 026import org.apache.maven.scm.ScmTag; 027import org.apache.maven.scm.ScmVersion; 028import org.apache.maven.scm.command.checkout.AbstractCheckOutCommand; 029import org.apache.maven.scm.command.checkout.CheckOutScmResult; 030import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult; 031import org.apache.maven.scm.provider.ScmProviderRepository; 032import org.apache.maven.scm.provider.git.command.GitCommand; 033import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils; 034import org.apache.maven.scm.provider.git.gitexe.command.list.GitListCommand; 035import org.apache.maven.scm.provider.git.gitexe.command.list.GitListConsumer; 036import org.apache.maven.scm.provider.git.gitexe.command.remoteinfo.GitRemoteInfoCommand; 037import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; 038import org.codehaus.plexus.util.StringUtils; 039import org.codehaus.plexus.util.cli.CommandLineUtils; 040import org.codehaus.plexus.util.cli.Commandline; 041 042import java.io.File; 043 044/** 045 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a> 046 * 047 */ 048public class GitCheckOutCommand 049 extends AbstractCheckOutCommand 050 implements GitCommand 051{ 052 /** 053 * For git, the given repository is a remote one. 054 * We have to clone it first if the working directory does not contain a git repo yet, 055 * otherwise we have to git-pull it. 056 * <p/> 057 * TODO We currently assume a '.git' directory, so this does not work for --bare repos 058 * {@inheritDoc} 059 */ 060 protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, ScmFileSet fileSet, 061 ScmVersion version, boolean recursive ) 062 throws ScmException 063 { 064 GitScmProviderRepository repository = (GitScmProviderRepository) repo; 065 066 if ( GitScmProviderRepository.PROTOCOL_FILE.equals( repository.getFetchInfo().getProtocol() ) 067 && repository.getFetchInfo().getPath().indexOf( fileSet.getBasedir().getPath() ) >= 0 ) 068 { 069 throw new ScmException( "remote repository must not be the working directory" ); 070 } 071 072 int exitCode; 073 074 CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer(); 075 CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer(); 076 077 String lastCommandLine = "git-nothing-to-do"; 078 079 if ( !fileSet.getBasedir().exists() || !( new File( fileSet.getBasedir(), ".git" ).exists() ) ) 080 { 081 if ( fileSet.getBasedir().exists() ) 082 { 083 // git refuses to clone otherwise 084 fileSet.getBasedir().delete(); 085 } 086 087 // no git repo seems to exist, let's clone the original repo 088 Commandline clClone = createCloneCommand( repository, fileSet.getBasedir(), version ); 089 090 exitCode = GitCommandLineUtils.execute( clClone, stdout, stderr, getLogger() ); 091 if ( exitCode != 0 ) 092 { 093 return new CheckOutScmResult( clClone.toString(), "The git-clone command failed.", stderr.getOutput(), 094 false ); 095 } 096 lastCommandLine = clClone.toString(); 097 } 098 099 GitRemoteInfoCommand gitRemoteInfoCommand = new GitRemoteInfoCommand(); 100 gitRemoteInfoCommand.setLogger( getLogger() ); 101 RemoteInfoScmResult result = gitRemoteInfoCommand.executeRemoteInfoCommand( repository, null, null ); 102 103 if ( fileSet.getBasedir().exists() && new File( fileSet.getBasedir(), ".git" ).exists() 104 && result.getBranches().size() > 0 ) 105 { 106 // git repo exists, so we must git-pull the changes 107 Commandline clPull = createPullCommand( repository, fileSet.getBasedir(), version ); 108 109 exitCode = GitCommandLineUtils.execute( clPull, stdout, stderr, getLogger() ); 110 if ( exitCode != 0 ) 111 { 112 return new CheckOutScmResult( clPull.toString(), "The git-pull command failed.", stderr.getOutput(), 113 false ); 114 } 115 lastCommandLine = clPull.toString(); 116 117 // and now lets do the git-checkout itself 118 Commandline clCheckout = createCommandLine( repository, fileSet.getBasedir(), version ); 119 120 exitCode = GitCommandLineUtils.execute( clCheckout, stdout, stderr, getLogger() ); 121 if ( exitCode != 0 ) 122 { 123 return new CheckOutScmResult( clCheckout.toString(), "The git-checkout command failed.", 124 stderr.getOutput(), false ); 125 } 126 lastCommandLine = clCheckout.toString(); 127 } 128 129 // and now search for the files 130 GitListConsumer listConsumer = 131 new GitListConsumer( getLogger(), fileSet.getBasedir(), ScmFileStatus.CHECKED_IN ); 132 133 Commandline clList = GitListCommand.createCommandLine( repository, fileSet.getBasedir() ); 134 135 exitCode = GitCommandLineUtils.execute( clList, listConsumer, stderr, getLogger() ); 136 if ( exitCode != 0 ) 137 { 138 return new CheckOutScmResult( clList.toString(), "The git-ls-files command failed.", stderr.getOutput(), 139 false ); 140 } 141 142 return new CheckOutScmResult( lastCommandLine, listConsumer.getListedFiles() ); 143 } 144 145 // ---------------------------------------------------------------------- 146 // 147 // ---------------------------------------------------------------------- 148 149 public static Commandline createCommandLine( GitScmProviderRepository repository, File workingDirectory, 150 ScmVersion version ) 151 { 152 Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "checkout" ); 153 154 if ( version != null && StringUtils.isNotEmpty( version.getName() ) ) 155 { 156 cl.createArg().setValue( version.getName() ); 157 } 158 159 return cl; 160 } 161 162 /** 163 * create a git-clone repository command 164 */ 165 private Commandline createCloneCommand( GitScmProviderRepository repository, File workingDirectory, 166 ScmVersion version ) 167 { 168 Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory.getParentFile(), "clone" ); 169 170 if ( version != null && ( version instanceof ScmBranch ) ) 171 { 172 173 cl.createArg().setValue( "--branch" ); 174 175 cl.createArg().setValue( version.getName() ); 176 } 177 178 cl.createArg().setValue( repository.getFetchUrl() ); 179 180 cl.createArg().setFile( workingDirectory ); 181 182 return cl; 183 } 184 185 /** 186 * create a git-pull repository command 187 */ 188 private Commandline createPullCommand( GitScmProviderRepository repository, File workingDirectory, 189 ScmVersion version ) 190 { 191 Commandline cl; 192 193 if ( version != null && StringUtils.isNotEmpty( version.getName() ) ) 194 { 195 if ( version instanceof ScmTag ) 196 { 197 // A tag will not be pulled but we only fetch all the commits from the upstream repo 198 // This is done because checking out a tag might not happen on the current branch 199 // but create a 'detached HEAD'. 200 // In fact, a tag in git may be in multiple branches. This occurs if 201 // you create a branch after the tag has been created 202 cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "fetch" ); 203 204 cl.createArg().setValue( repository.getFetchUrl() ); 205 } 206 else 207 { 208 cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "pull" ); 209 210 cl.createArg().setValue( repository.getFetchUrl() ); 211 212 cl.createArg().setValue( version.getName() + ":" + version.getName() ); 213 } 214 } 215 else 216 { 217 cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "pull" ); 218 219 cl.createArg().setValue( repository.getFetchUrl() ); 220 cl.createArg().setValue( "master" ); 221 } 222 return cl; 223 } 224}