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