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 public SubmoduleUpdateCommand(final Repository repo) {
102 super(repo);
103 paths = new ArrayList<>();
104 }
105
106
107
108
109
110
111
112
113
114 public SubmoduleUpdateCommand setProgressMonitor(
115 final ProgressMonitor monitor) {
116 this.monitor = monitor;
117 return this;
118 }
119
120
121
122
123
124
125
126
127
128 public SubmoduleUpdateCommand setFetch(final boolean fetch) {
129 this.fetch = fetch;
130 return this;
131 }
132
133
134
135
136
137
138
139
140 public SubmoduleUpdateCommand addPath(final String path) {
141 paths.add(path);
142 return this;
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 @Override
160 public Collection<String> call() throws InvalidConfigurationException,
161 NoHeadException, ConcurrentRefUpdateException,
162 CheckoutConflictException, InvalidMergeHeadsException,
163 WrongRepositoryStateException, NoMessageException, NoHeadException,
164 RefNotFoundException, GitAPIException {
165 checkCallable();
166
167 try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
168 if (!paths.isEmpty())
169 generator.setFilter(PathFilterGroup.createFromStrings(paths));
170 List<String> updated = new ArrayList<>();
171 while (generator.next()) {
172
173 if (generator.getModulesPath() == null)
174 continue;
175
176 String url = generator.getConfigUrl();
177 if (url == null)
178 continue;
179
180 Repository submoduleRepo = generator.getRepository();
181
182 if (submoduleRepo == null) {
183 if (callback != null) {
184 callback.cloningSubmodule(generator.getPath());
185 }
186 CloneCommand clone = Git.cloneRepository();
187 configure(clone);
188 clone.setURI(url);
189 clone.setDirectory(generator.getDirectory());
190 clone.setGitDir(new File(new File(repo.getDirectory(),
191 Constants.MODULES), generator.getPath()));
192 if (monitor != null)
193 clone.setProgressMonitor(monitor);
194 submoduleRepo = clone.call().getRepository();
195 } else if (this.fetch) {
196 if (fetchCallback != null) {
197 fetchCallback.fetchingSubmodule(generator.getPath());
198 }
199 FetchCommand fetchCommand = Git.wrap(submoduleRepo).fetch();
200 if (monitor != null) {
201 fetchCommand.setProgressMonitor(monitor);
202 }
203 configure(fetchCommand);
204 fetchCommand.call();
205 }
206
207 try (RevWalk walk = new RevWalk(submoduleRepo)) {
208 RevCommit commit = walk
209 .parseCommit(generator.getObjectId());
210
211 String update = generator.getConfigUpdate();
212 if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) {
213 MergeCommand merge = new MergeCommand(submoduleRepo);
214 merge.include(commit);
215 merge.setProgressMonitor(monitor);
216 merge.setStrategy(strategy);
217 merge.call();
218 } else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) {
219 RebaseCommand rebase = new RebaseCommand(submoduleRepo);
220 rebase.setUpstream(commit);
221 rebase.setProgressMonitor(monitor);
222 rebase.setStrategy(strategy);
223 rebase.call();
224 } else {
225
226
227 DirCacheCheckout co = new DirCacheCheckout(
228 submoduleRepo, submoduleRepo.lockDirCache(),
229 commit.getTree());
230 co.setFailOnConflict(true);
231 co.checkout();
232 RefUpdate refUpdate = submoduleRepo.updateRef(
233 Constants.HEAD, true);
234 refUpdate.setNewObjectId(commit);
235 refUpdate.forceUpdate();
236 if (callback != null) {
237 callback.checkingOut(commit,
238 generator.getPath());
239 }
240 }
241 } finally {
242 submoduleRepo.close();
243 }
244 updated.add(generator.getPath());
245 }
246 return updated;
247 } catch (IOException e) {
248 throw new JGitInternalException(e.getMessage(), e);
249 } catch (ConfigInvalidException e) {
250 throw new InvalidConfigurationException(e.getMessage(), e);
251 }
252 }
253
254
255
256
257
258
259
260 public SubmoduleUpdateCommand setStrategy(MergeStrategy strategy) {
261 this.strategy = strategy;
262 return this;
263 }
264
265
266
267
268
269
270
271
272
273 public SubmoduleUpdateCommand setCallback(CloneCommand.Callback callback) {
274 this.callback = callback;
275 return this;
276 }
277
278
279
280
281
282
283
284
285
286 public SubmoduleUpdateCommand setFetchCallback(
287 FetchCommand.Callback callback) {
288 this.fetchCallback = callback;
289 return this;
290 }
291 }