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