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