You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SubmoduleWalkTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright (C) 2011, GitHub Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.submodule;
  44. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
  45. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_URL;
  46. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION;
  47. import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
  48. import static org.junit.Assert.assertEquals;
  49. import static org.junit.Assert.assertFalse;
  50. import static org.junit.Assert.assertNotNull;
  51. import static org.junit.Assert.assertNull;
  52. import static org.junit.Assert.assertTrue;
  53. import java.io.File;
  54. import java.io.FileWriter;
  55. import java.io.IOException;
  56. import org.eclipse.jgit.api.Git;
  57. import org.eclipse.jgit.api.Status;
  58. import org.eclipse.jgit.api.errors.GitAPIException;
  59. import org.eclipse.jgit.dircache.DirCache;
  60. import org.eclipse.jgit.dircache.DirCacheEditor;
  61. import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
  62. import org.eclipse.jgit.dircache.DirCacheEntry;
  63. import org.eclipse.jgit.errors.ConfigInvalidException;
  64. import org.eclipse.jgit.errors.NoWorkTreeException;
  65. import org.eclipse.jgit.internal.storage.file.FileRepository;
  66. import org.eclipse.jgit.junit.RepositoryTestCase;
  67. import org.eclipse.jgit.junit.TestRepository;
  68. import org.eclipse.jgit.lib.Config;
  69. import org.eclipse.jgit.lib.Constants;
  70. import org.eclipse.jgit.lib.FileMode;
  71. import org.eclipse.jgit.lib.ObjectId;
  72. import org.eclipse.jgit.lib.Repository;
  73. import org.eclipse.jgit.revwalk.RevBlob;
  74. import org.eclipse.jgit.revwalk.RevCommit;
  75. import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
  76. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  77. import org.eclipse.jgit.treewalk.filter.PathFilter;
  78. import org.junit.Before;
  79. import org.junit.Test;
  80. /**
  81. * Unit tests of {@link SubmoduleWalk}
  82. */
  83. public class SubmoduleWalkTest extends RepositoryTestCase {
  84. private TestRepository<Repository> testDb;
  85. @Before
  86. public void setUp() throws Exception {
  87. super.setUp();
  88. testDb = new TestRepository<Repository>(db);
  89. }
  90. @Test
  91. public void repositoryWithNoSubmodules() throws IOException {
  92. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  93. assertFalse(gen.next());
  94. assertNull(gen.getPath());
  95. assertEquals(ObjectId.zeroId(), gen.getObjectId());
  96. }
  97. @Test
  98. public void bareRepositoryWithNoSubmodules() throws IOException {
  99. FileRepository bareRepo = createBareRepository();
  100. boolean result = SubmoduleWalk.containsGitModulesFile(bareRepo);
  101. assertFalse(result);
  102. }
  103. @Test
  104. public void repositoryWithRootLevelSubmodule() throws IOException,
  105. ConfigInvalidException, NoWorkTreeException, GitAPIException {
  106. final ObjectId id = ObjectId
  107. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  108. final String path = "sub";
  109. DirCache cache = db.lockDirCache();
  110. DirCacheEditor editor = cache.editor();
  111. editor.add(new PathEdit(path) {
  112. public void apply(DirCacheEntry ent) {
  113. ent.setFileMode(FileMode.GITLINK);
  114. ent.setObjectId(id);
  115. }
  116. });
  117. editor.commit();
  118. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  119. assertTrue(gen.next());
  120. assertEquals(path, gen.getPath());
  121. assertEquals(id, gen.getObjectId());
  122. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  123. assertNull(gen.getConfigUpdate());
  124. assertNull(gen.getConfigUrl());
  125. assertNull(gen.getModulesPath());
  126. assertNull(gen.getModulesUpdate());
  127. assertNull(gen.getModulesUrl());
  128. assertNull(gen.getRepository());
  129. Status status = Git.wrap(db).status().call();
  130. assertTrue(!status.isClean());
  131. assertFalse(gen.next());
  132. }
  133. @SuppressWarnings("resource" /* java 7 */)
  134. @Test
  135. public void repositoryWithRootLevelSubmoduleAbsoluteRef()
  136. throws IOException, ConfigInvalidException {
  137. final ObjectId id = ObjectId
  138. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  139. final String path = "sub";
  140. File dotGit = new File(db.getWorkTree(), path + File.separatorChar
  141. + Constants.DOT_GIT);
  142. if (!dotGit.getParentFile().exists())
  143. dotGit.getParentFile().mkdirs();
  144. File modulesGitDir = new File(db.getDirectory(), "modules"
  145. + File.separatorChar + path);
  146. new FileWriter(dotGit).append(
  147. "gitdir: " + modulesGitDir.getAbsolutePath()).close();
  148. FileRepositoryBuilder builder = new FileRepositoryBuilder();
  149. builder.setWorkTree(new File(db.getWorkTree(), path));
  150. builder.build().create();
  151. DirCache cache = db.lockDirCache();
  152. DirCacheEditor editor = cache.editor();
  153. editor.add(new PathEdit(path) {
  154. public void apply(DirCacheEntry ent) {
  155. ent.setFileMode(FileMode.GITLINK);
  156. ent.setObjectId(id);
  157. }
  158. });
  159. editor.commit();
  160. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  161. assertTrue(gen.next());
  162. assertEquals(path, gen.getPath());
  163. assertEquals(id, gen.getObjectId());
  164. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  165. assertNull(gen.getConfigUpdate());
  166. assertNull(gen.getConfigUrl());
  167. assertNull(gen.getModulesPath());
  168. assertNull(gen.getModulesUpdate());
  169. assertNull(gen.getModulesUrl());
  170. Repository subRepo = gen.getRepository();
  171. assertNotNull(subRepo);
  172. assertEquals(modulesGitDir.getAbsolutePath(),
  173. subRepo.getDirectory().getAbsolutePath());
  174. assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(),
  175. subRepo.getWorkTree().getAbsolutePath());
  176. subRepo.close();
  177. assertFalse(gen.next());
  178. }
  179. @SuppressWarnings("resource" /* java 7 */)
  180. @Test
  181. public void repositoryWithRootLevelSubmoduleRelativeRef()
  182. throws IOException, ConfigInvalidException {
  183. final ObjectId id = ObjectId
  184. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  185. final String path = "sub";
  186. File dotGit = new File(db.getWorkTree(), path + File.separatorChar
  187. + Constants.DOT_GIT);
  188. if (!dotGit.getParentFile().exists())
  189. dotGit.getParentFile().mkdirs();
  190. File modulesGitDir = new File(db.getDirectory(), "modules"
  191. + File.separatorChar + path);
  192. new FileWriter(dotGit).append(
  193. "gitdir: " + "../" + Constants.DOT_GIT + "/modules/" + path)
  194. .close();
  195. FileRepositoryBuilder builder = new FileRepositoryBuilder();
  196. builder.setWorkTree(new File(db.getWorkTree(), path));
  197. builder.build().create();
  198. DirCache cache = db.lockDirCache();
  199. DirCacheEditor editor = cache.editor();
  200. editor.add(new PathEdit(path) {
  201. public void apply(DirCacheEntry ent) {
  202. ent.setFileMode(FileMode.GITLINK);
  203. ent.setObjectId(id);
  204. }
  205. });
  206. editor.commit();
  207. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  208. assertTrue(gen.next());
  209. assertEquals(path, gen.getPath());
  210. assertEquals(id, gen.getObjectId());
  211. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  212. assertNull(gen.getConfigUpdate());
  213. assertNull(gen.getConfigUrl());
  214. assertNull(gen.getModulesPath());
  215. assertNull(gen.getModulesUpdate());
  216. assertNull(gen.getModulesUrl());
  217. Repository subRepo = gen.getRepository();
  218. assertNotNull(subRepo);
  219. assertEqualsFile(modulesGitDir, subRepo.getDirectory());
  220. assertEqualsFile(new File(db.getWorkTree(), path),
  221. subRepo.getWorkTree());
  222. subRepo.close();
  223. assertFalse(gen.next());
  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. public void apply(DirCacheEntry ent) {
  235. ent.setFileMode(FileMode.GITLINK);
  236. ent.setObjectId(id);
  237. }
  238. });
  239. editor.commit();
  240. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  241. assertTrue(gen.next());
  242. assertEquals(path, gen.getPath());
  243. assertEquals(id, gen.getObjectId());
  244. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  245. assertNull(gen.getConfigUpdate());
  246. assertNull(gen.getConfigUrl());
  247. assertNull(gen.getModulesPath());
  248. assertNull(gen.getModulesUpdate());
  249. assertNull(gen.getModulesUrl());
  250. assertNull(gen.getRepository());
  251. assertFalse(gen.next());
  252. }
  253. @Test
  254. public void generatorFilteredToOneOfTwoSubmodules() throws IOException {
  255. final ObjectId id1 = ObjectId
  256. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  257. final String path1 = "sub1";
  258. final ObjectId id2 = ObjectId
  259. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1235");
  260. final String path2 = "sub2";
  261. DirCache cache = db.lockDirCache();
  262. DirCacheEditor editor = cache.editor();
  263. editor.add(new PathEdit(path1) {
  264. public void apply(DirCacheEntry ent) {
  265. ent.setFileMode(FileMode.GITLINK);
  266. ent.setObjectId(id1);
  267. }
  268. });
  269. editor.add(new PathEdit(path2) {
  270. public void apply(DirCacheEntry ent) {
  271. ent.setFileMode(FileMode.GITLINK);
  272. ent.setObjectId(id2);
  273. }
  274. });
  275. editor.commit();
  276. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  277. gen.setFilter(PathFilter.create(path1));
  278. assertTrue(gen.next());
  279. assertEquals(path1, gen.getPath());
  280. assertEquals(id1, gen.getObjectId());
  281. assertFalse(gen.next());
  282. }
  283. @Test
  284. public void indexWithGitmodules() throws Exception {
  285. final ObjectId subId = ObjectId
  286. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  287. final String path = "sub";
  288. final Config gitmodules = new Config();
  289. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
  290. "sub");
  291. // Different config in the index should be overridden by the working tree.
  292. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
  293. "git://example.com/bad");
  294. final RevBlob gitmodulesBlob = testDb.blob(gitmodules.toText());
  295. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
  296. "git://example.com/sub");
  297. writeTrashFile(DOT_GIT_MODULES, gitmodules.toText());
  298. DirCache cache = db.lockDirCache();
  299. DirCacheEditor editor = cache.editor();
  300. editor.add(new PathEdit(path) {
  301. public void apply(DirCacheEntry ent) {
  302. ent.setFileMode(FileMode.GITLINK);
  303. ent.setObjectId(subId);
  304. }
  305. });
  306. editor.add(new PathEdit(DOT_GIT_MODULES) {
  307. public void apply(DirCacheEntry ent) {
  308. ent.setFileMode(FileMode.REGULAR_FILE);
  309. ent.setObjectId(gitmodulesBlob);
  310. }
  311. });
  312. editor.commit();
  313. SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
  314. assertTrue(gen.next());
  315. assertEquals(path, gen.getPath());
  316. assertEquals(subId, gen.getObjectId());
  317. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  318. assertNull(gen.getConfigUpdate());
  319. assertNull(gen.getConfigUrl());
  320. assertEquals("sub", gen.getModulesPath());
  321. assertNull(gen.getModulesUpdate());
  322. assertEquals("git://example.com/sub", gen.getModulesUrl());
  323. assertNull(gen.getRepository());
  324. assertFalse(gen.next());
  325. }
  326. @Test
  327. public void treeIdWithGitmodules() throws Exception {
  328. final ObjectId subId = ObjectId
  329. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  330. final String path = "sub";
  331. final Config gitmodules = new Config();
  332. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
  333. "sub");
  334. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
  335. "git://example.com/sub");
  336. RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
  337. .noParents()
  338. .add(DOT_GIT_MODULES, gitmodules.toText())
  339. .edit(new PathEdit(path) {
  340. public void apply(DirCacheEntry ent) {
  341. ent.setFileMode(FileMode.GITLINK);
  342. ent.setObjectId(subId);
  343. }
  344. })
  345. .create());
  346. SubmoduleWalk gen = SubmoduleWalk.forPath(db, commit.getTree(), "sub");
  347. assertEquals(path, gen.getPath());
  348. assertEquals(subId, gen.getObjectId());
  349. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  350. assertNull(gen.getConfigUpdate());
  351. assertNull(gen.getConfigUrl());
  352. assertEquals("sub", gen.getModulesPath());
  353. assertNull(gen.getModulesUpdate());
  354. assertEquals("git://example.com/sub", gen.getModulesUrl());
  355. assertNull(gen.getRepository());
  356. assertFalse(gen.next());
  357. }
  358. @Test
  359. public void testTreeIteratorWithGitmodules() throws Exception {
  360. final ObjectId subId = ObjectId
  361. .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
  362. final String path = "sub";
  363. final Config gitmodules = new Config();
  364. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_PATH,
  365. "sub");
  366. gitmodules.setString(CONFIG_SUBMODULE_SECTION, path, CONFIG_KEY_URL,
  367. "git://example.com/sub");
  368. RevCommit commit = testDb.getRevWalk().parseCommit(testDb.commit()
  369. .noParents()
  370. .add(DOT_GIT_MODULES, gitmodules.toText())
  371. .edit(new PathEdit(path) {
  372. public void apply(DirCacheEntry ent) {
  373. ent.setFileMode(FileMode.GITLINK);
  374. ent.setObjectId(subId);
  375. }
  376. })
  377. .create());
  378. final CanonicalTreeParser p = new CanonicalTreeParser();
  379. p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
  380. SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub");
  381. assertEquals(path, gen.getPath());
  382. assertEquals(subId, gen.getObjectId());
  383. assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
  384. assertNull(gen.getConfigUpdate());
  385. assertNull(gen.getConfigUrl());
  386. assertEquals("sub", gen.getModulesPath());
  387. assertNull(gen.getModulesUpdate());
  388. assertEquals("git://example.com/sub", gen.getModulesUrl());
  389. assertNull(gen.getRepository());
  390. assertFalse(gen.next());
  391. }
  392. }