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 assertFalse(gen.next());
221 }
222 }
223 }
224
225 @Test
226 public void repositoryWithNestedSubmodule() throws IOException,
227 ConfigInvalidException {
228 final ObjectId id = ObjectId
229 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
230 final String path = "sub/dir/final";
231 DirCache cache = db.lockDirCache();
232 DirCacheEditor editor = cache.editor();
233 editor.add(new PathEdit(path) {
234
235 @Override
236 public void apply(DirCacheEntry ent) {
237 ent.setFileMode(FileMode.GITLINK);
238 ent.setObjectId(id);
239 }
240 });
241 editor.commit();
242
243 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
244 assertTrue(gen.next());
245 assertEquals(path, gen.getPath());
246 assertEquals(id, gen.getObjectId());
247 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
248 assertNull(gen.getConfigUpdate());
249 assertNull(gen.getConfigUrl());
250 assertNull(gen.getModulesPath());
251 assertNull(gen.getModulesUpdate());
252 assertNull(gen.getModulesUrl());
253 assertNull(gen.getRepository());
254 assertFalse(gen.next());
255 }
256 }
257
258 @Test
259 public void generatorFilteredToOneOfTwoSubmodules() throws IOException {
260 final ObjectId id1 = ObjectId
261 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
262 final String path1 = "sub1";
263 final ObjectId id2 = ObjectId
264 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1235");
265 final String path2 = "sub2";
266 DirCache cache = db.lockDirCache();
267 DirCacheEditor editor = cache.editor();
268 editor.add(new PathEdit(path1) {
269
270 @Override
271 public void apply(DirCacheEntry ent) {
272 ent.setFileMode(FileMode.GITLINK);
273 ent.setObjectId(id1);
274 }
275 });
276 editor.add(new PathEdit(path2) {
277
278 @Override
279 public void apply(DirCacheEntry ent) {
280 ent.setFileMode(FileMode.GITLINK);
281 ent.setObjectId(id2);
282 }
283 });
284 editor.commit();
285
286 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
287 gen.setFilter(PathFilter.create(path1));
288 assertTrue(gen.next());
289 assertEquals(path1, gen.getPath());
290 assertEquals(id1, gen.getObjectId());
291 assertFalse(gen.next());
292 }
293 }
294
295 @Test
296 public void indexWithGitmodules() throws Exception {
297 final ObjectId subId = ObjectId
298 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
299 final String path = "sub";
300
301 final Config gitmodules = new Config();
302 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
303 "sub");
304
305 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
306 "git://example.com/bad");
307 final RevBlob gitmodulesBlob = testDb.blob(gitmodules.toText());
308
309 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
310 "git://example.com/sub");
311 writeTrashFile(DOT_GIT_MODULES, gitmodules.toText());
312
313 DirCache cache = db.lockDirCache();
314 DirCacheEditor editor = cache.editor();
315 editor.add(new PathEdit(path) {
316
317 @Override
318 public void apply(DirCacheEntry ent) {
319 ent.setFileMode(FileMode.GITLINK);
320 ent.setObjectId(subId);
321 }
322 });
323 editor.add(new PathEdit(DOT_GIT_MODULES) {
324
325 @Override
326 public void apply(DirCacheEntry ent) {
327 ent.setFileMode(FileMode.REGULAR_FILE);
328 ent.setObjectId(gitmodulesBlob);
329 }
330 });
331 editor.commit();
332
333 try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) {
334 assertTrue(gen.next());
335 assertEquals(path, gen.getPath());
336 assertEquals(subId, gen.getObjectId());
337 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
338 assertNull(gen.getConfigUpdate());
339 assertNull(gen.getConfigUrl());
340 assertEquals("sub", gen.getModulesPath());
341 assertNull(gen.getModulesUpdate());
342 assertEquals("git://example.com/sub", gen.getModulesUrl());
343 assertNull(gen.getRepository());
344 assertFalse(gen.next());
345 }
346 }
347
348 @Test
349 public void treeIdWithGitmodules() throws Exception {
350 final ObjectId subId = ObjectId
351 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
352 final String path = "sub";
353
354 final Config gitmodules = new Config();
355 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
356 "sub");
357 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
358 "git://example.com/sub");
359
360 RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
361 .noParents()
362 .add(DOT_GIT_MODULES, gitmodules.toText())
363 .edit(new PathEdit(path) {
364
365 @Override
366 public void apply(DirCacheEntry ent) {
367 ent.setFileMode(FileMode.GITLINK);
368 ent.setObjectId(subId);
369 }
370 })
371 .create());
372
373 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, commit.getTree(),
374 "sub")) {
375 assertEquals(path, gen.getPath());
376 assertEquals(subId, gen.getObjectId());
377 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
378 assertNull(gen.getConfigUpdate());
379 assertNull(gen.getConfigUrl());
380 assertEquals("sub", gen.getModulesPath());
381 assertNull(gen.getModulesUpdate());
382 assertEquals("git://example.com/sub", gen.getModulesUrl());
383 assertNull(gen.getRepository());
384 assertFalse(gen.next());
385 }
386 }
387
388 @Test
389 public void testTreeIteratorWithGitmodules() throws Exception {
390 final ObjectId subId = ObjectId
391 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
392 final String path = "sub";
393
394 final Config gitmodules = new Config();
395 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
396 "sub");
397 gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
398 "git://example.com/sub");
399
400 RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
401 .noParents()
402 .add(DOT_GIT_MODULES, gitmodules.toText())
403 .edit(new PathEdit(path) {
404
405 @Override
406 public void apply(DirCacheEntry ent) {
407 ent.setFileMode(FileMode.GITLINK);
408 ent.setObjectId(subId);
409 }
410 })
411 .create());
412
413 final CanonicalTreeParser p = new CanonicalTreeParser();
414 p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
415 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) {
416 assertEquals(path, gen.getPath());
417 assertEquals(subId, gen.getObjectId());
418 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
419 assertNull(gen.getConfigUpdate());
420 assertNull(gen.getConfigUrl());
421 assertEquals("sub", gen.getModulesPath());
422 assertNull(gen.getModulesUpdate());
423 assertEquals("git://example.com/sub", gen.getModulesUrl());
424 assertNull(gen.getRepository());
425 assertFalse(gen.next());
426 }
427 }
428
429 @Test
430 public void testTreeIteratorWithGitmodulesNameNotPath() throws Exception {
431 final ObjectId subId = ObjectId
432 .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
433 final String path = "sub";
434 final String arbitraryName = "x";
435
436 final Config gitmodules = new Config();
437 gitmodules.setString(CONFIG_SUBMODULE_SECTION, arbitraryName,
438 CONFIG_KEY_PATH, "sub");
439 gitmodules.setString(CONFIG_SUBMODULE_SECTION, arbitraryName,
440 CONFIG_KEY_URL, "git://example.com/sub");
441
442 RevCommit commit = testDb.getRevWalk()
443 .parseCommit(testDb.commit().noParents()
444 .add(DOT_GIT_MODULES, gitmodules.toText())
445 .edit(new PathEdit(path) {
446
447 @Override
448 public void apply(DirCacheEntry ent) {
449 ent.setFileMode(FileMode.GITLINK);
450 ent.setObjectId(subId);
451 }
452 }).create());
453
454 final CanonicalTreeParser p = new CanonicalTreeParser();
455 p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
456 try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) {
457 assertEquals(arbitraryName, gen.getModuleName());
458 assertEquals(path, gen.getPath());
459 assertEquals(subId, gen.getObjectId());
460 assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
461 assertNull(gen.getConfigUpdate());
462 assertNull(gen.getConfigUrl());
463 assertEquals("sub", gen.getModulesPath());
464 assertNull(gen.getModulesUpdate());
465 assertEquals("git://example.com/sub", gen.getModulesUrl());
466 assertNull(gen.getRepository());
467 assertFalse(gen.next());
468 }
469 }
470 }