Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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