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