1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.lib;
12
13 import static org.junit.Assert.assertArrayEquals;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertFalse;
16 import static org.junit.Assert.assertTrue;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.util.Arrays;
21 import java.util.Set;
22
23 import org.eclipse.jgit.api.CloneCommand;
24 import org.eclipse.jgit.api.Git;
25 import org.eclipse.jgit.api.errors.GitAPIException;
26 import org.eclipse.jgit.errors.NoWorkTreeException;
27 import org.eclipse.jgit.internal.storage.file.FileRepository;
28 import org.eclipse.jgit.junit.JGitTestUtil;
29 import org.eclipse.jgit.junit.RepositoryTestCase;
30 import org.eclipse.jgit.storage.file.FileBasedConfig;
31 import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
32 import org.eclipse.jgit.treewalk.FileTreeIterator;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.experimental.theories.DataPoints;
36 import org.junit.experimental.theories.Theories;
37 import org.junit.experimental.theories.Theory;
38 import org.junit.runner.RunWith;
39
40 @RunWith(Theories.class)
41 public class IndexDiffSubmoduleTest extends RepositoryTestCase {
42
43 protected FileRepository submodule_db;
44
45
46 protected File submodule_trash;
47
48 @DataPoints
49 public static IgnoreSubmoduleMode allModes[] = IgnoreSubmoduleMode.values();
50
51 @Override
52 @Before
53 public void setUp() throws Exception {
54 super.setUp();
55 FileRepository submoduleStandalone = createWorkRepository();
56 JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule",
57 "submodule");
58 Git submoduleStandaloneGit = Git.wrap(submoduleStandalone);
59 submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call();
60 submoduleStandaloneGit.commit().setMessage("add file to submodule")
61 .call();
62
63 submodule_db = (FileRepository) Git.wrap(db).submoduleAdd()
64 .setPath("modules/submodule")
65 .setURI(submoduleStandalone.getDirectory().toURI().toString())
66 .call();
67 submodule_trash = submodule_db.getWorkTree();
68 addRepoToClose(submodule_db);
69 writeTrashFile("fileInRoot", "root");
70 Git rootGit = Git.wrap(db);
71 rootGit.add().addFilepattern("fileInRoot").call();
72 rootGit.commit().setMessage("add submodule and root file").call();
73 }
74
75 @Theory
76 public void testInitiallyClean(IgnoreSubmoduleMode mode)
77 throws IOException {
78 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
79 new FileTreeIterator(db));
80 indexDiff.setIgnoreSubmoduleMode(mode);
81 assertFalse(indexDiff.diff());
82 }
83
84 private Repository cloneWithoutCloningSubmodule() throws Exception {
85 File directory = createTempDirectory(
86 "testCloneWithoutCloningSubmodules");
87 CloneCommand clone = Git.cloneRepository();
88 clone.setDirectory(directory);
89 clone.setCloneSubmodules(false);
90 clone.setURI(db.getDirectory().toURI().toString());
91 Git git2 = clone.call();
92 addRepoToClose(git2.getRepository());
93 return git2.getRepository();
94 }
95
96 @Theory
97 public void testCleanAfterClone(IgnoreSubmoduleMode mode) throws Exception {
98 Repository db2 = cloneWithoutCloningSubmodule();
99 IndexDiff indexDiff = new IndexDiff(db2, Constants.HEAD,
100 new FileTreeIterator(db2));
101 indexDiff.setIgnoreSubmoduleMode(mode);
102 boolean changed = indexDiff.diff();
103 assertFalse(changed);
104 }
105
106 @Theory
107 public void testMissingIfDirectoryGone(IgnoreSubmoduleMode mode)
108 throws Exception {
109 recursiveDelete(submodule_trash);
110 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
111 new FileTreeIterator(db));
112 indexDiff.setIgnoreSubmoduleMode(mode);
113 boolean hasChanges = indexDiff.diff();
114 if (mode != IgnoreSubmoduleMode.ALL) {
115 assertTrue(hasChanges);
116 assertEquals("[modules/submodule]",
117 indexDiff.getMissing().toString());
118 } else {
119 assertFalse(hasChanges);
120 }
121 }
122
123 @Theory
124 public void testSubmoduleReplacedByFile(IgnoreSubmoduleMode mode)
125 throws Exception {
126 recursiveDelete(submodule_trash);
127 writeTrashFile("modules/submodule", "nonsense");
128 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
129 new FileTreeIterator(db));
130 indexDiff.setIgnoreSubmoduleMode(mode);
131 assertTrue(indexDiff.diff());
132 assertEquals("[]", indexDiff.getMissing().toString());
133 assertEquals("[]", indexDiff.getUntracked().toString());
134 assertEquals("[modules/submodule]", indexDiff.getModified().toString());
135 }
136
137 @Theory
138 public void testDirtyRootWorktree(IgnoreSubmoduleMode mode)
139 throws IOException {
140 writeTrashFile("fileInRoot", "2");
141
142 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
143 new FileTreeIterator(db));
144 indexDiff.setIgnoreSubmoduleMode(mode);
145 assertTrue(indexDiff.diff());
146 }
147
148 private void assertDiff(IndexDiff indexDiff, IgnoreSubmoduleMode mode,
149 IgnoreSubmoduleMode... expectedEmptyModes) throws IOException {
150 boolean diffResult = indexDiff.diff();
151 Set<String> submodulePaths = indexDiff
152 .getPathsWithIndexMode(FileMode.GITLINK);
153 boolean emptyExpected = false;
154 for (IgnoreSubmoduleMode empty : expectedEmptyModes) {
155 if (mode.equals(empty)) {
156 emptyExpected = true;
157 break;
158 }
159 }
160 if (emptyExpected) {
161 assertFalse("diff should be false with mode=" + mode,
162 diffResult);
163 assertEquals("should have no paths with FileMode.GITLINK", 0,
164 submodulePaths.size());
165 } else {
166 assertTrue("diff should be true with mode=" + mode,
167 diffResult);
168 assertTrue("submodule path should have FileMode.GITLINK",
169 submodulePaths.contains("modules/submodule"));
170 }
171 }
172
173 @Theory
174 public void testDirtySubmoduleWorktree(IgnoreSubmoduleMode mode)
175 throws IOException {
176 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
177 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
178 new FileTreeIterator(db));
179 indexDiff.setIgnoreSubmoduleMode(mode);
180 assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
181 IgnoreSubmoduleMode.DIRTY);
182 }
183
184 @Theory
185 public void testDirtySubmoduleHEAD(IgnoreSubmoduleMode mode)
186 throws IOException, GitAPIException {
187 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
188 Git submoduleGit = Git.wrap(submodule_db);
189 submoduleGit.add().addFilepattern("fileInSubmodule").call();
190 submoduleGit.commit().setMessage("Modified fileInSubmodule").call();
191
192 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
193 new FileTreeIterator(db));
194 indexDiff.setIgnoreSubmoduleMode(mode);
195 assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL);
196 }
197
198 @Theory
199 public void testDirtySubmoduleIndex(IgnoreSubmoduleMode mode)
200 throws IOException, GitAPIException {
201 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
202 Git submoduleGit = Git.wrap(submodule_db);
203 submoduleGit.add().addFilepattern("fileInSubmodule").call();
204
205 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
206 new FileTreeIterator(db));
207 indexDiff.setIgnoreSubmoduleMode(mode);
208 assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
209 IgnoreSubmoduleMode.DIRTY);
210 }
211
212 @Theory
213 public void testDirtySubmoduleIndexAndWorktree(IgnoreSubmoduleMode mode)
214 throws IOException, GitAPIException, NoWorkTreeException {
215 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
216 Git submoduleGit = Git.wrap(submodule_db);
217 submoduleGit.add().addFilepattern("fileInSubmodule").call();
218 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "3");
219
220 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
221 new FileTreeIterator(db));
222 indexDiff.setIgnoreSubmoduleMode(mode);
223 assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
224 IgnoreSubmoduleMode.DIRTY);
225 }
226
227 @Theory
228 public void testDirtySubmoduleWorktreeUntracked(IgnoreSubmoduleMode mode)
229 throws IOException {
230 JGitTestUtil.writeTrashFile(submodule_db, "additionalFileInSubmodule",
231 "2");
232 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
233 new FileTreeIterator(db));
234 indexDiff.setIgnoreSubmoduleMode(mode);
235 assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
236 IgnoreSubmoduleMode.DIRTY, IgnoreSubmoduleMode.UNTRACKED);
237 }
238
239 @Theory
240 public void testSubmoduleReplacedByMovedFile(IgnoreSubmoduleMode mode)
241 throws Exception {
242 Git git = Git.wrap(db);
243 git.rm().setCached(true).addFilepattern("modules/submodule").call();
244 recursiveDelete(submodule_trash);
245 JGitTestUtil.deleteTrashFile(db, "fileInRoot");
246
247 writeTrashFile("modules/submodule/fileInRoot", "root");
248 git.rm().addFilepattern("fileInRoot").addFilepattern("modules/").call();
249 git.add().addFilepattern("modules/").call();
250 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
251 new FileTreeIterator(db));
252 indexDiff.setIgnoreSubmoduleMode(mode);
253 assertTrue(indexDiff.diff());
254 String[] removed = indexDiff.getRemoved().toArray(new String[0]);
255 Arrays.sort(removed);
256 if (IgnoreSubmoduleMode.ALL.equals(mode)) {
257 assertArrayEquals(new String[] { "fileInRoot" }, removed);
258 } else {
259 assertArrayEquals(
260 new String[] { "fileInRoot", "modules/submodule" },
261 removed);
262 }
263 assertEquals("[modules/submodule/fileInRoot]",
264 indexDiff.getAdded().toString());
265 }
266
267 @Test
268 public void testIndexDiffTwoSubmodules() throws Exception {
269
270 try (Repository submodule2 = createWorkRepository()) {
271 JGitTestUtil.writeTrashFile(submodule2, "fileInSubmodule2",
272 "submodule2");
273 Git subGit = Git.wrap(submodule2);
274 subGit.add().addFilepattern("fileInSubmodule2").call();
275 subGit.commit().setMessage("add file to submodule2").call();
276
277 try (Repository sub2 = Git.wrap(db)
278 .submoduleAdd().setPath("modules/submodule2")
279 .setURI(submodule2.getDirectory().toURI().toString())
280 .call()) {
281 writeTrashFile("fileInRoot", "root+");
282 Git rootGit = Git.wrap(db);
283 rootGit.add().addFilepattern("fileInRoot").call();
284 rootGit.commit().setMessage("add submodule2 and root file")
285 .call();
286
287 JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule",
288 "submodule changed");
289 JGitTestUtil.writeTrashFile(sub2, "fileInSubmodule2",
290 "submodule2 changed");
291
292 FileBasedConfig gitmodules = new FileBasedConfig(
293 new File(db.getWorkTree(), Constants.DOT_GIT_MODULES),
294 db.getFS());
295 gitmodules.load();
296 gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
297 "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE,
298 "all");
299 gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
300 "modules/submodule2", ConfigConstants.CONFIG_KEY_IGNORE,
301 "none");
302 gitmodules.save();
303 IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
304 new FileTreeIterator(db));
305 assertTrue(indexDiff.diff());
306 String[] modified = indexDiff.getModified()
307 .toArray(new String[0]);
308 Arrays.sort(modified);
309 assertEquals("[.gitmodules, modules/submodule2]",
310 Arrays.toString(modified));
311
312 gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
313 "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE,
314 "dirty");
315 gitmodules.save();
316 indexDiff = new IndexDiff(db, Constants.HEAD,
317 new FileTreeIterator(db));
318 assertTrue(indexDiff.diff());
319 modified = indexDiff.getModified().toArray(new String[0]);
320 Arrays.sort(modified);
321 assertEquals("[.gitmodules, modules/submodule2]",
322 Arrays.toString(modified));
323
324 StoredConfig cfg = db.getConfig();
325 cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
326 "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE,
327 "none");
328 cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
329 "modules/submodule2", ConfigConstants.CONFIG_KEY_IGNORE,
330 "all");
331 cfg.save();
332 indexDiff = new IndexDiff(db, Constants.HEAD,
333 new FileTreeIterator(db));
334 assertTrue(indexDiff.diff());
335 modified = indexDiff.getModified().toArray(new String[0]);
336 Arrays.sort(modified);
337 assertEquals("[.gitmodules, modules/submodule]",
338 Arrays.toString(modified));
339 }
340 }
341 }
342 }