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