View Javadoc
1   /*
2    * Copyright (C) 2017, Two Sigma Open Source 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.submodule;
11  
12  import java.io.File;
13  import java.io.IOException;
14  import java.util.Collection;
15  
16  import org.eclipse.jgit.api.Git;
17  import org.eclipse.jgit.api.SubmoduleDeinitCommand;
18  import org.eclipse.jgit.api.SubmoduleDeinitResult;
19  import org.eclipse.jgit.api.SubmoduleUpdateCommand;
20  import org.eclipse.jgit.api.errors.GitAPIException;
21  import org.eclipse.jgit.dircache.DirCache;
22  import org.eclipse.jgit.dircache.DirCacheEditor;
23  import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
24  import org.eclipse.jgit.dircache.DirCacheEntry;
25  import org.eclipse.jgit.junit.JGitTestUtil;
26  import org.eclipse.jgit.junit.RepositoryTestCase;
27  import org.eclipse.jgit.lib.ConfigConstants;
28  import org.eclipse.jgit.lib.Constants;
29  import org.eclipse.jgit.lib.FileMode;
30  import org.eclipse.jgit.lib.Repository;
31  import org.eclipse.jgit.lib.StoredConfig;
32  import org.eclipse.jgit.revwalk.RevCommit;
33  import org.eclipse.jgit.storage.file.FileBasedConfig;
34  import org.junit.Test;
35  
36  import static org.junit.Assert.assertEquals;
37  import static org.junit.Assert.assertNotEquals;
38  import static org.junit.Assert.assertNotNull;
39  import static org.junit.Assert.assertTrue;
40  
41  /**
42   * Unit tests of {@link SubmoduleDeinitCommand}
43   */
44  public class SubmoduleDeinitTest extends RepositoryTestCase {
45  
46  	@Test
47  	public void repositoryWithNoSubmodules() throws GitAPIException {
48  		SubmoduleDeinitCommand command = new SubmoduleDeinitCommand(db);
49  		Collection<SubmoduleDeinitResult> modules = command.call();
50  		assertNotNull(modules);
51  		assertTrue(modules.isEmpty());
52  	}
53  
54  	@Test
55  	public void alreadyClosedSubmodule() throws Exception {
56  		final String path = "sub";
57  		Git git = Git.wrap(db);
58  
59  		commitSubmoduleCreation(path, git);
60  
61  		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
62  		assertEquals(path, result.getPath());
63  		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.ALREADY_DEINITIALIZED, result.getStatus());
64  	}
65  
66  	@Test
67  	public void dirtySubmoduleBecauseUntracked() throws Exception {
68  		final String path = "sub";
69  		Git git = Git.wrap(db);
70  
71  		commitSubmoduleCreation(path, git);
72  
73  		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
74  		assertEquals(1, updated.size());
75  
76  		File submoduleDir = assertSubmoduleIsInitialized();
77  
78  		write(new File(submoduleDir, "untracked"), "untracked");
79  
80  		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
81  		assertEquals(path, result.getPath());
82  		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus());
83  
84  		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
85  			assertTrue(generator.next());
86  		}
87  		assertTrue(submoduleDir.isDirectory());
88  		assertNotEquals(0, submoduleDir.list().length);
89  	}
90  
91  	@Test
92  	public void dirtySubmoduleBecauseNewCommit() throws Exception {
93  		final String path = "sub";
94  		Git git = Git.wrap(db);
95  
96  		commitSubmoduleCreation(path, git);
97  
98  		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
99  		assertEquals(1, updated.size());
100 
101 		File submoduleDir = assertSubmoduleIsInitialized();
102 		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
103 			generator.next();
104 
105 			// want to create a commit inside the repo...
106 			try (Repository submoduleLocalRepo = generator.getRepository()) {
107 				JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt",
108 						"new data");
109 				Git.wrap(submoduleLocalRepo).commit().setAll(true)
110 						.setMessage("local commit").call();
111 			}
112 		}
113 		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
114 		assertEquals(path, result.getPath());
115 		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus());
116 
117 		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
118 			assertTrue(generator.next());
119 		}
120 		assertTrue(submoduleDir.isDirectory());
121 		assertNotEquals(0, submoduleDir.list().length);
122 	}
123 
124 	private File assertSubmoduleIsInitialized() throws IOException {
125 		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
126 			assertTrue(generator.next());
127 			File submoduleDir = new File(db.getWorkTree(), generator.getPath());
128 			assertTrue(submoduleDir.isDirectory());
129 			assertNotEquals(0, submoduleDir.list().length);
130 			return submoduleDir;
131 		}
132 	}
133 
134 	@Test
135 	public void dirtySubmoduleWithForce() throws Exception {
136 		final String path = "sub";
137 		Git git = Git.wrap(db);
138 
139 		commitSubmoduleCreation(path, git);
140 
141 		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
142 		assertEquals(1, updated.size());
143 
144 		File submoduleDir = assertSubmoduleIsInitialized();
145 
146 		write(new File(submoduleDir, "untracked"), "untracked");
147 
148 		SubmoduleDeinitCommand command = new SubmoduleDeinitCommand(db).addPath("sub").setForce(true);
149 		SubmoduleDeinitResult result = runDeinit(command);
150 		assertEquals(path, result.getPath());
151 		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.FORCED, result.getStatus());
152 
153 		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
154 			assertTrue(generator.next());
155 		}
156 		assertTrue(submoduleDir.isDirectory());
157 		assertEquals(0, submoduleDir.list().length);
158 	}
159 
160 	@Test
161 	public void cleanSubmodule() throws Exception {
162 		final String path = "sub";
163 		Git git = Git.wrap(db);
164 
165 		commitSubmoduleCreation(path, git);
166 
167 		Collection<String> updated = new SubmoduleUpdateCommand(db).addPath(path).setFetch(false).call();
168 		assertEquals(1, updated.size());
169 
170 		File submoduleDir = assertSubmoduleIsInitialized();
171 
172 		SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub"));
173 		assertEquals(path, result.getPath());
174 		assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.SUCCESS, result.getStatus());
175 
176 		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
177 			assertTrue(generator.next());
178 		}
179 		assertTrue(submoduleDir.isDirectory());
180 		assertEquals(0, submoduleDir.list().length);
181 	}
182 
183 	private SubmoduleDeinitResult runDeinit(SubmoduleDeinitCommand command) throws GitAPIException {
184 		Collection<SubmoduleDeinitResult> deinitialized = command.call();
185 		assertNotNull(deinitialized);
186 		assertEquals(1, deinitialized.size());
187 		return deinitialized.iterator().next();
188 	}
189 
190 
191 	private RevCommit commitSubmoduleCreation(String path, Git git) throws IOException, GitAPIException {
192 		writeTrashFile("file.txt", "content");
193 		git.add().addFilepattern("file.txt").call();
194 		final RevCommit commit = git.commit().setMessage("create file").call();
195 
196 		DirCache cache = db.lockDirCache();
197 		DirCacheEditor editor = cache.editor();
198 		editor.add(new PathEdit(path) {
199 
200 			@Override
201 			public void apply(DirCacheEntry ent) {
202 				ent.setFileMode(FileMode.GITLINK);
203 				ent.setObjectId(commit);
204 			}
205 		});
206 		editor.commit();
207 
208 		StoredConfig config = db.getConfig();
209 		config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
210 				ConfigConstants.CONFIG_KEY_URL, db.getDirectory().toURI()
211 						.toString());
212 		config.save();
213 
214 		FileBasedConfig modulesConfig = new FileBasedConfig(new File(
215 				db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
216 		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
217 				ConfigConstants.CONFIG_KEY_PATH, path);
218 		modulesConfig.save();
219 
220 		new File(db.getWorkTree(), "sub").mkdir();
221 		git.add().addFilepattern(Constants.DOT_GIT_MODULES).call();
222 		git.commit().setMessage("create submodule").call();
223 		return commit;
224 	}
225 }