1 package org.apache.maven.scm.provider.git.jgit.command.checkout;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Set;
27 import java.util.function.BiFunction;
28
29 import org.apache.maven.scm.ScmException;
30 import org.apache.maven.scm.ScmFile;
31 import org.apache.maven.scm.ScmFileSet;
32 import org.apache.maven.scm.ScmFileStatus;
33 import org.apache.maven.scm.ScmTag;
34 import org.apache.maven.scm.ScmVersion;
35 import org.apache.maven.scm.command.checkout.AbstractCheckOutCommand;
36 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
37 import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult;
38 import org.apache.maven.scm.provider.ScmProviderRepository;
39 import org.apache.maven.scm.provider.git.command.GitCommand;
40 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
41 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
42 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
43 import org.apache.maven.scm.provider.git.jgit.command.branch.JGitBranchCommand;
44 import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
45 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
46 import org.codehaus.plexus.util.StringUtils;
47 import org.eclipse.jgit.api.CloneCommand;
48 import org.eclipse.jgit.api.FetchCommand;
49 import org.eclipse.jgit.api.Git;
50 import org.eclipse.jgit.api.PullCommand;
51 import org.eclipse.jgit.api.TransportConfigCallback;
52 import org.eclipse.jgit.lib.Constants;
53 import org.eclipse.jgit.lib.ProgressMonitor;
54 import org.eclipse.jgit.revwalk.RevCommit;
55 import org.eclipse.jgit.revwalk.RevWalk;
56 import org.eclipse.jgit.storage.file.WindowCacheConfig;
57 import org.eclipse.jgit.transport.CredentialsProvider;
58 import org.eclipse.jgit.treewalk.TreeWalk;
59 import org.slf4j.Logger;
60
61
62
63
64
65
66 public class JGitCheckOutCommand
67 extends AbstractCheckOutCommand
68 implements GitCommand
69 {
70 private BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier;
71
72 public JGitCheckOutCommand()
73 {
74 sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new;
75 }
76
77 public void setSshSessionFactorySupplier(
78 BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier )
79 {
80 this.sshSessionFactorySupplier = sshSessionFactorySupplier;
81 }
82
83
84
85
86
87
88
89 protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, ScmFileSet fileSet,
90 ScmVersion version, boolean recursive, boolean shallow )
91 throws ScmException
92 {
93 GitScmProviderRepository repository = (GitScmProviderRepository) repo;
94
95 if ( GitScmProviderRepository.PROTOCOL_FILE.equals( repository.getFetchInfo().getProtocol() )
96 && repository.getFetchInfo().getPath().indexOf( fileSet.getBasedir().getPath() ) >= 0 )
97 {
98 throw new ScmException( "remote repository must not be the working directory" );
99 }
100
101 Git git = null;
102 try
103 {
104
105 ProgressMonitor monitor = JGitUtils.getMonitor();
106
107 String branch = version != null ? version.getName() : null;
108
109 if ( StringUtils.isBlank( branch ) )
110 {
111 branch = Constants.MASTER;
112 }
113
114 TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
115 sshSessionFactorySupplier.apply( (GitScmProviderRepository) repo, logger ) );
116
117 logger.debug( "try checkout of branch: " + branch );
118
119 if ( !fileSet.getBasedir().exists() || !( new File( fileSet.getBasedir(), ".git" ).exists() ) )
120 {
121 if ( fileSet.getBasedir().exists() )
122 {
123
124 fileSet.getBasedir().delete();
125 }
126
127
128 WindowCacheConfig cfg = new WindowCacheConfig();
129 cfg.setPackedGitMMAP( false );
130 cfg.install();
131
132
133 CredentialsProvider credentials = JGitUtils.getCredentials( (GitScmProviderRepository) repo );
134 logger.info( "cloning [" + branch + "] to " + fileSet.getBasedir() );
135 CloneCommand command = Git.cloneRepository().setURI( repository.getFetchUrl() );
136
137 command.setCredentialsProvider( credentials ).setBranch( branch ).setDirectory( fileSet.getBasedir() );
138
139 command.setTransportConfigCallback( transportConfigCallback );
140
141 command.setProgressMonitor( monitor );
142 git = command.call();
143 }
144
145 JGitRemoteInfoCommand remoteInfoCommand = new JGitRemoteInfoCommand();
146 remoteInfoCommand.setSshSessionFactorySupplier( sshSessionFactorySupplier );
147 RemoteInfoScmResult result = remoteInfoCommand.executeRemoteInfoCommand( repository, fileSet, null );
148
149 if ( git == null )
150 {
151
152 git = Git.open( fileSet.getBasedir() );
153 }
154
155 if ( fileSet.getBasedir().exists() && new File( fileSet.getBasedir(), ".git" ).exists()
156 && result.getBranches().size() > 0 )
157 {
158
159 CredentialsProvider credentials = JGitUtils.prepareSession( git, repository );
160
161 if ( version != null && StringUtils.isNotEmpty( version.getName() ) && ( version instanceof ScmTag ) )
162 {
163
164
165
166
167
168 logger.debug( "fetch..." );
169 FetchCommand command = git.fetch().setCredentialsProvider( credentials )
170 .setProgressMonitor( monitor );
171 command.setTransportConfigCallback( transportConfigCallback );
172 command.call();
173
174 }
175 else
176 {
177 logger.debug( "pull..." );
178 PullCommand command = git.pull().setCredentialsProvider( credentials )
179 .setProgressMonitor( monitor );
180 command.setTransportConfigCallback( transportConfigCallback );
181 command.call();
182 }
183 }
184
185 Set<String> localBranchNames = JGitBranchCommand.getShortLocalBranchNames( git );
186 if ( version instanceof ScmTag )
187 {
188 logger.info( "checkout tag [" + branch + "] at " + fileSet.getBasedir() );
189 git.checkout().setName( branch ).call();
190 }
191 else if ( localBranchNames.contains( branch ) )
192 {
193 logger.info( "checkout [" + branch + "] at " + fileSet.getBasedir() );
194 git.checkout().setName( branch ).call();
195 }
196 else
197 {
198 logger.info( "checkout remote branch [" + branch + "] at " + fileSet.getBasedir() );
199 git.checkout().setName( branch ).setCreateBranch( true ).setStartPoint( Constants.DEFAULT_REMOTE_NAME
200 + "/" + branch ).call();
201 }
202
203 RevWalk revWalk = new RevWalk( git.getRepository() );
204 RevCommit commit = revWalk.parseCommit( git.getRepository().resolve( Constants.HEAD ) );
205 revWalk.close();
206
207 final TreeWalk walk = new TreeWalk( git.getRepository() );
208 walk.reset();
209 walk.setRecursive( true );
210 walk.addTree( commit.getTree() );
211
212 List<ScmFile> listedFiles = new ArrayList<>();
213 while ( walk.next() )
214 {
215 listedFiles.add( new ScmFile( walk.getPathString(), ScmFileStatus.CHECKED_OUT ) );
216 }
217 walk.close();
218
219 logger.debug( "current branch: " + git.getRepository().getBranch() );
220
221 return new CheckOutScmResult( "checkout via JGit", listedFiles );
222 }
223 catch ( Exception e )
224 {
225 throw new ScmException( "JGit checkout failure!", e );
226 }
227 finally
228 {
229 JGitUtils.closeRepo( git );
230 }
231 }
232
233 }