1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.api;
45
46 import java.io.File;
47 import java.io.IOException;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.List;
51
52 import org.eclipse.jgit.api.errors.CheckoutConflictException;
53 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
54 import org.eclipse.jgit.api.errors.GitAPIException;
55 import org.eclipse.jgit.api.errors.InvalidConfigurationException;
56 import org.eclipse.jgit.api.errors.InvalidMergeHeadsException;
57 import org.eclipse.jgit.api.errors.JGitInternalException;
58 import org.eclipse.jgit.api.errors.NoHeadException;
59 import org.eclipse.jgit.api.errors.NoMessageException;
60 import org.eclipse.jgit.api.errors.RefNotFoundException;
61 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
62 import org.eclipse.jgit.dircache.DirCacheCheckout;
63 import org.eclipse.jgit.errors.ConfigInvalidException;
64 import org.eclipse.jgit.lib.ConfigConstants;
65 import org.eclipse.jgit.lib.Constants;
66 import org.eclipse.jgit.lib.NullProgressMonitor;
67 import org.eclipse.jgit.lib.ProgressMonitor;
68 import org.eclipse.jgit.lib.RefUpdate;
69 import org.eclipse.jgit.lib.Repository;
70 import org.eclipse.jgit.merge.MergeStrategy;
71 import org.eclipse.jgit.revwalk.RevCommit;
72 import org.eclipse.jgit.revwalk.RevWalk;
73 import org.eclipse.jgit.submodule.SubmoduleWalk;
74 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
75
76
77
78
79
80
81
82
83 public class SubmoduleUpdateCommand extends
84 TransportCommand<SubmoduleUpdateCommand, Collection<String>> {
85
86 private ProgressMonitor monitor;
87
88 private final Collection<String> paths;
89
90 private MergeStrategy strategy = MergeStrategy.RECURSIVE;
91
92 private CloneCommand.Callback callback;
93
94 private FetchCommand.Callback fetchCallback;
95
96 private boolean fetch = false;
97
98
99
100
101
102
103
104
105
106 public SubmoduleUpdateCommand(Repository repo) {
107 super(repo);
108 paths = new ArrayList<>();
109 }
110
111
112
113
114
115
116
117
118
119
120 public SubmoduleUpdateCommand setProgressMonitor(
121 final ProgressMonitor monitor) {
122 this.monitor = monitor;
123 return this;
124 }
125
126
127
128
129
130
131
132
133
134
135 public SubmoduleUpdateCommand setFetch(boolean fetch) {
136 this.fetch = fetch;
137 return this;
138 }
139
140
141
142
143
144
145
146
147 public SubmoduleUpdateCommand addPath(String path) {
148 paths.add(path);
149 return this;
150 }
151
152 private Repository getOrCloneSubmodule(SubmoduleWalk generator, String url)
153 throws IOException, GitAPIException {
154 Repository repository = generator.getRepository();
155 if (repository == null) {
156 if (callback != null) {
157 callback.cloningSubmodule(generator.getPath());
158 }
159 CloneCommand clone = Git.cloneRepository();
160 configure(clone);
161 clone.setURI(url);
162 clone.setDirectory(generator.getDirectory());
163 clone.setGitDir(
164 new File(new File(repo.getDirectory(), Constants.MODULES),
165 generator.getPath()));
166 if (monitor != null) {
167 clone.setProgressMonitor(monitor);
168 }
169 repository = clone.call().getRepository();
170 } else if (this.fetch) {
171 if (fetchCallback != null) {
172 fetchCallback.fetchingSubmodule(generator.getPath());
173 }
174 FetchCommand fetchCommand = Git.wrap(repository).fetch();
175 if (monitor != null) {
176 fetchCommand.setProgressMonitor(monitor);
177 }
178 configure(fetchCommand);
179 fetchCommand.call();
180 }
181 return repository;
182 }
183
184
185
186
187
188
189 @Override
190 public Collection<String> call() throws InvalidConfigurationException,
191 NoHeadException, ConcurrentRefUpdateException,
192 CheckoutConflictException, InvalidMergeHeadsException,
193 WrongRepositoryStateException, NoMessageException, NoHeadException,
194 RefNotFoundException, GitAPIException {
195 checkCallable();
196
197 try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
198 if (!paths.isEmpty())
199 generator.setFilter(PathFilterGroup.createFromStrings(paths));
200 List<String> updated = new ArrayList<>();
201 while (generator.next()) {
202
203 if (generator.getModulesPath() == null)
204 continue;
205
206 String url = generator.getConfigUrl();
207 if (url == null)
208 continue;
209
210 try (Repository submoduleRepo = getOrCloneSubmodule(generator,
211 url); RevWalk walk = new RevWalk(submoduleRepo)) {
212 RevCommit commit = walk
213 .parseCommit(generator.getObjectId());
214
215 String update = generator.getConfigUpdate();
216 if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) {
217 MergeCommand merge = new MergeCommand(submoduleRepo);
218 merge.include(commit);
219 merge.setProgressMonitor(monitor);
220 merge.setStrategy(strategy);
221 merge.call();
222 } else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) {
223 RebaseCommand rebase = new RebaseCommand(submoduleRepo);
224 rebase.setUpstream(commit);
225 rebase.setProgressMonitor(monitor);
226 rebase.setStrategy(strategy);
227 rebase.call();
228 } else {
229
230
231 DirCacheCheckout co = new DirCacheCheckout(
232 submoduleRepo, submoduleRepo.lockDirCache(),
233 commit.getTree());
234 co.setFailOnConflict(true);
235 co.setProgressMonitor(monitor);
236 co.checkout();
237 RefUpdate refUpdate = submoduleRepo.updateRef(
238 Constants.HEAD, true);
239 refUpdate.setNewObjectId(commit);
240 refUpdate.forceUpdate();
241 if (callback != null) {
242 callback.checkingOut(commit,
243 generator.getPath());
244 }
245 }
246 }
247 updated.add(generator.getPath());
248 }
249 return updated;
250 } catch (IOException e) {
251 throw new JGitInternalException(e.getMessage(), e);
252 } catch (ConfigInvalidException e) {
253 throw new InvalidConfigurationException(e.getMessage(), e);
254 }
255 }
256
257
258
259
260
261
262
263
264
265 public SubmoduleUpdateCommand setStrategy(MergeStrategy strategy) {
266 this.strategy = strategy;
267 return this;
268 }
269
270
271
272
273
274
275
276
277
278 public SubmoduleUpdateCommand setCallback(CloneCommand.Callback callback) {
279 this.callback = callback;
280 return this;
281 }
282
283
284
285
286
287
288
289
290
291 public SubmoduleUpdateCommand setFetchCallback(
292 FetchCommand.Callback callback) {
293 this.fetchCallback = callback;
294 return this;
295 }
296 }