1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.submodule;
11
12 import static java.nio.charset.StandardCharsets.UTF_8;
13 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
14 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_URL;
15 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION;
16 import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
17 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.assertFalse;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22
23 import java.io.BufferedWriter;
24 import java.io.File;
25 import java.io.IOException;
26 import java.nio.file.Files;
27
28 import org.eclipse.jgit.api.Git;
29 import org.eclipse.jgit.api.Status;
30 import org.eclipse.jgit.api.errors.GitAPIException;
31 import org.eclipse.jgit.dircache.DirCache;
32 import org.eclipse.jgit.dircache.DirCacheEditor;
33 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
34 import org.eclipse.jgit.dircache.DirCacheEntry;
35 import org.eclipse.jgit.errors.ConfigInvalidException;
36 import org.eclipse.jgit.errors.NoWorkTreeException;
37 import org.eclipse.jgit.internal.storage.file.FileRepository;
38 import org.eclipse.jgit.junit.RepositoryTestCase;
39 import org.eclipse.jgit.junit.TestRepository;
40 import org.eclipse.jgit.lib.Config;
41 import org.eclipse.jgit.lib.Constants;
42 import org.eclipse.jgit.lib.FileMode;
43 import org.eclipse.jgit.lib.ObjectId;
44 import org.eclipse.jgit.lib.Repository;
45 import org.eclipse.jgit.revwalk.RevBlob;
46 import org.eclipse.jgit.revwalk.RevCommit;
47 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
48 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
49 import org.eclipse.jgit.treewalk.filter.PathFilter;
50 import org.junit.Before;
51 import org.junit.Test;
52
53
54
55
56 public class SubmoduleWalkTest extends RepositoryTestCase {
57 private TestRepository<Repository> testDb;
58
59 @Override
60 @Before
61 public void setUp() throws Exception {
62 super.setUp();
63 testDb = new TestRepository<>(db);
64 }
65
66 @Test
67 public void repositoryWithNoSubmodules() throws IOException {
68 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
69 assertFalse(gen.next());
70 assertNull(gen.getPath());
71 assertEquals(ObjectId.zeroId(), gen.getObjectId());
72 }
73 }
74
75 @Test
76 public void bareRepositoryWithNoSubmodules() throws IOException {
77 FileRepository bareRepo = createBareRepository();
78 boolean result = SubmoduleWalk.containsGitModulesFile(bareRepo);
79 assertFalse(result);
80 }
81
82 @Test
83 public void repositoryWithRootLevelSubmodule() throws IOException,
84 ConfigInvalidException, NoWorkTreeException, GitAPIException {
85 final ObjectId id = ObjectId
86 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
87 final String path = "sub";
88 DirCache cache = db.lockDirCache();
89 DirCacheEditor editor = cache.editor();
90 editor.add(new PathEdit(path) {
91
92 @Override
93 public void apply(DirCacheEntry ent) {
94 ent.setFileMode(FileMode.GITLINK);
95 ent.setObjectId(id);
96 }
97 });
98 editor.commit();
99
100 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
101 assertTrue(gen.next());
102 assertEquals(path, gen.getPath());
103 assertEquals(id, gen.getObjectId());
104 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
105 assertNull(gen.getConfigUpdate());
106 assertNull(gen.getConfigUrl());
107 assertNull(gen.getModulesPath());
108 assertNull(gen.getModulesUpdate());
109 assertNull(gen.getModulesUrl());
110 assertNull(gen.getRepository());
111 assertFalse(gen.next());
112 }
113 Status status = Git.wrap(db).status().call();
114 assertFalse(status.isClean());
115 }
116
117 @Test
118 public void repositoryWithRootLevelSubmoduleAbsoluteRef()
119 throws IOException, ConfigInvalidException {
120 final ObjectId id = ObjectId
121 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
122 final String path = "sub";
123 File dotGit = new File(db.getWorkTree(), path + File.separatorChar
124 + Constants.DOT_GIT);
125 if (!dotGit.getParentFile().exists())
126 dotGit.getParentFile().mkdirs();
127
128 File modulesGitDir = new File(db.getDirectory(),
129 "modules" + File.separatorChar + path);
130 try (BufferedWriter fw = Files.newBufferedWriter(dotGit.toPath(),
131 UTF_8)) {
132 fw.append("gitdir: " + modulesGitDir.getAbsolutePath());
133 }
134 FileRepositoryBuilder builder = new FileRepositoryBuilder();
135 builder.setWorkTree(new File(db.getWorkTree(), path));
136 builder.build().create();
137
138 DirCache cache = db.lockDirCache();
139 DirCacheEditor editor = cache.editor();
140 editor.add(new PathEdit(path) {
141
142 @Override
143 public void apply(DirCacheEntry ent) {
144 ent.setFileMode(FileMode.GITLINK);
145 ent.setObjectId(id);
146 }
147 });
148 editor.commit();
149
150 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
151 assertTrue(gen.next());
152 assertEquals(path, gen.getPath());
153 assertEquals(id, gen.getObjectId());
154 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
155 assertNull(gen.getConfigUpdate());
156 assertNull(gen.getConfigUrl());
157 assertNull(gen.getModulesPath());
158 assertNull(gen.getModulesUpdate());
159 assertNull(gen.getModulesUrl());
160 try (Repository subRepo = gen.getRepository()) {
161 assertNotNull(subRepo);
162 assertEquals(modulesGitDir.getAbsolutePath(),
163 subRepo.getDirectory().getAbsolutePath());
164 assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(),
165 subRepo.getWorkTree().getAbsolutePath());
166 }
167 assertFalse(gen.next());
168 }
169 }
170
171 @Test
172 public void repositoryWithRootLevelSubmoduleRelativeRef()
173 throws IOException, ConfigInvalidException {
174 final ObjectId id = ObjectId
175 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
176 final String path = "sub";
177 File dotGit = new File(db.getWorkTree(), path + File.separatorChar
178 + Constants.DOT_GIT);
179 if (!dotGit.getParentFile().exists())
180 dotGit.getParentFile().mkdirs();
181
182 File modulesGitDir = new File(db.getDirectory(), "modules"
183 + File.separatorChar + path);
184 try (BufferedWriter fw = Files.newBufferedWriter(dotGit.toPath(),
185 UTF_8)) {
186 fw.append("gitdir: " + "../" + Constants.DOT_GIT + "/modules/"
187 + path);
188 }
189 FileRepositoryBuilder builder = new FileRepositoryBuilder();
190 builder.setWorkTree(new File(db.getWorkTree(), path));
191 builder.build().create();
192
193 DirCache cache = db.lockDirCache();
194 DirCacheEditor editor = cache.editor();
195 editor.add(new PathEdit(path) {
196
197 @Override
198 public void apply(DirCacheEntry ent) {
199 ent.setFileMode(FileMode.GITLINK);
200 ent.setObjectId(id);
201 }
202 });
203 editor.commit();
204
205 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
206 assertTrue(gen.next());
207 assertEquals(path, gen.getPath());
208 assertEquals(id, gen.getObjectId());
209 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
210 assertNull(gen.getConfigUpdate());
211 assertNull(gen.getConfigUrl());
212 assertNull(gen.getModulesPath());
213 assertNull(gen.getModulesUpdate());
214 assertNull(gen.getModulesUrl());
215 try (Repository subRepo = gen.getRepository()) {
216 assertNotNull(subRepo);
217 assertEqualsFile(modulesGitDir, subRepo.getDirectory());
218 assertEqualsFile(new File(db.getWorkTree(), path),
219 subRepo.getWorkTree());
220 subRepo.close();
221 assertFalse(gen.next());
222 }
223 }
224 }
225
226 @Test
227 public void repositoryWithNestedSubmodule() throws IOException,
228 ConfigInvalidException {
229 final ObjectId id = ObjectId
230 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
231 final String path = "sub/dir/final";
232 DirCache cache = db.lockDirCache();
233 DirCacheEditor editor = cache.editor();
234 editor.add(new PathEdit(path) {
235
236 @Override
237 public void apply(DirCacheEntry ent) {
238 ent.setFileMode(FileMode.GITLINK);
239 ent.setObjectId(id);
240 }
241 });
242 editor.commit();
243
244 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
245 assertTrue(gen.next());
246 assertEquals(path, gen.getPath());
247 assertEquals(id, gen.getObjectId());
248 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
249 assertNull(gen.getConfigUpdate());
250 assertNull(gen.getConfigUrl());
251 assertNull(gen.getModulesPath());
252 assertNull(gen.getModulesUpdate());
253 assertNull(gen.getModulesUrl());
254 assertNull(gen.getRepository());
255 assertFalse(gen.next());
256 }
257 }
258
259 @Test
260 public void generatorFilteredToOneOfTwoSubmodules() throws IOException {
261 final ObjectId id1 = ObjectId
262 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
263 final String path1 = "sub1";
264 final ObjectId id2 = ObjectId
265 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1235");
266 final String path2 = "sub2";
267 DirCache cache = db.lockDirCache();
268 DirCacheEditor editor = cache.editor();
269 editor.add(new PathEdit(path1) {
270
271 @Override
272 public void apply(DirCacheEntry ent) {
273 ent.setFileMode(FileMode.GITLINK);
274 ent.setObjectId(id1);
275 }
276 });
277 editor.add(new PathEdit(path2) {
278
279 @Override
280 public void apply(DirCacheEntry ent) {
281 ent.setFileMode(FileMode.GITLINK);
282 ent.setObjectId(id2);
283 }
284 });
285 editor.commit();
286
287 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
288 gen.setFilter(PathFilter.create(path1));
289 assertTrue(gen.next());
290 assertEquals(path1, gen.getPath());
291 assertEquals(id1, gen.getObjectId());
292 assertFalse(gen.next());
293 }
294 }
295
296 @Test
297 public void indexWithGitmodules() throws Exception {
298 final ObjectId subId = ObjectId
299 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
300 final String path = "sub";
301
302 final Config gitmodules = new Config();
303 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
304 "sub");
305
306 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
307 "git://example.com/bad");
308 final RevBlob gitmodulesBlob = testDb.blob(gitmodules.toText());
309
310 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
311 "git://example.com/sub");
312 writeTrashFile(DOT_GIT_MODULES, gitmodules.toText());
313
314 DirCache cache = db.lockDirCache();
315 DirCacheEditor editor = cache.editor();
316 editor.add(new PathEdit(path) {
317
318 @Override
319 public void apply(DirCacheEntry ent) {
320 ent.setFileMode(FileMode.GITLINK);
321 ent.setObjectId(subId);
322 }
323 });
324 editor.add(new PathEdit(DOT_GIT_MODULES) {
325
326 @Override
327 public void apply(DirCacheEntry ent) {
328 ent.setFileMode(FileMode.REGULAR_FILE);
329 ent.setObjectId(gitmodulesBlob);
330 }
331 });
332 editor.commit();
333
334 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
335 assertTrue(gen.next());
336 assertEquals(path, gen.getPath());
337 assertEquals(subId, gen.getObjectId());
338 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
339 assertNull(gen.getConfigUpdate());
340 assertNull(gen.getConfigUrl());
341 assertEquals("sub", gen.getModulesPath());
342 assertNull(gen.getModulesUpdate());
343 assertEquals("git://example.com/sub", gen.getModulesUrl());
344 assertNull(gen.getRepository());
345 assertFalse(gen.next());
346 }
347 }
348
349 @Test
350 public void treeIdWithGitmodules() throws Exception {
351 final ObjectId subId = ObjectId
352 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
353 final String path = "sub";
354
355 final Config gitmodules = new Config();
356 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
357 "sub");
358 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
359 "git://example.com/sub");
360
361 RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
362 .noParents()
363 .add(DOT_GIT_MODULES, gitmodules.toText())
364 .edit(new PathEdit(path) {
365
366 @Override
367 public void apply(DirCacheEntry ent) {
368 ent.setFileMode(FileMode.GITLINK);
369 ent.setObjectId(subId);
370 }
371 })
372 .create());
373
374 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, commit.getTree(),
375 "sub")) {
376 assertEquals(path, gen.getPath());
377 assertEquals(subId, gen.getObjectId());
378 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
379 assertNull(gen.getConfigUpdate());
380 assertNull(gen.getConfigUrl());
381 assertEquals("sub", gen.getModulesPath());
382 assertNull(gen.getModulesUpdate());
383 assertEquals("git://example.com/sub", gen.getModulesUrl());
384 assertNull(gen.getRepository());
385 assertFalse(gen.next());
386 }
387 }
388
389 @Test
390 public void testTreeIteratorWithGitmodules() throws Exception {
391 final ObjectId subId = ObjectId
392 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
393 final String path = "sub";
394
395 final Config gitmodules = new Config();
396 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
397 "sub");
398 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
399 "git://example.com/sub");
400
401 RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
402 .noParents()
403 .add(DOT_GIT_MODULES, gitmodules.toText())
404 .edit(new PathEdit(path) {
405
406 @Override
407 public void apply(DirCacheEntry ent) {
408 ent.setFileMode(FileMode.GITLINK);
409 ent.setObjectId(subId);
410 }
411 })
412 .create());
413
414 final CanonicalTreeParser p = new CanonicalTreeParser();
415 p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
416 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) {
417 assertEquals(path, gen.getPath());
418 assertEquals(subId, gen.getObjectId());
419 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
420 assertNull(gen.getConfigUpdate());
421 assertNull(gen.getConfigUrl());
422 assertEquals("sub", gen.getModulesPath());
423 assertNull(gen.getModulesUpdate());
424 assertEquals("git://example.com/sub", gen.getModulesUrl());
425 assertNull(gen.getRepository());
426 assertFalse(gen.next());
427 }
428 }
429
430 @Test
431 public void testTreeIteratorWithGitmodulesNameNotPath() throws Exception {
432 final ObjectId subId = ObjectId
433 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
434 final String path = "sub";
435 final String arbitraryName = "x";
436
437 final Config gitmodules = new Config();
438 gitmodules.setString(CONFIG_SUBMODULE_SECTION, arbitraryName,
439 CONFIG_KEY_PATH, "sub");
440 gitmodules.setString(CONFIG_SUBMODULE_SECTION, arbitraryName,
441 CONFIG_KEY_URL, "git://example.com/sub");
442
443 RevCommit commit = testDb.getRevWalk()
444 .parseCommit(testDb.commit().noParents()
445 .add(DOT_GIT_MODULES, gitmodules.toText())
446 .edit(new PathEdit(path) {
447
448 @Override
449 public void apply(DirCacheEntry ent) {
450 ent.setFileMode(FileMode.GITLINK);
451 ent.setObjectId(subId);
452 }
453 }).create());
454
455 final CanonicalTreeParser p = new CanonicalTreeParser();
456 p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
457 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) {
458 assertEquals(arbitraryName, gen.getModuleName());
459 assertEquals(path, gen.getPath());
460 assertEquals(subId, gen.getObjectId());
461 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
462 assertNull(gen.getConfigUpdate());
463 assertNull(gen.getConfigUrl());
464 assertEquals("sub", gen.getModulesPath());
465 assertNull(gen.getModulesUpdate());
466 assertEquals("git://example.com/sub", gen.getModulesUrl());
467 assertNull(gen.getRepository());
468 assertFalse(gen.next());
469 }
470 }
471 }