View Javadoc
1   /*
2    * Copyright (C) 2014, Google 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.gitrepo;
44  
45  import static java.nio.charset.StandardCharsets.UTF_8;
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertFalse;
48  import static org.junit.Assert.assertNull;
49  import static org.junit.Assert.assertTrue;
50  import static org.junit.Assert.fail;
51  
52  import java.io.BufferedReader;
53  import java.io.ByteArrayInputStream;
54  import java.io.File;
55  import java.io.FileReader;
56  import java.io.IOException;
57  import java.net.URI;
58  import java.util.HashMap;
59  import java.util.Map;
60  
61  import org.eclipse.jgit.api.Git;
62  import org.eclipse.jgit.api.errors.GitAPIException;
63  import org.eclipse.jgit.api.errors.InvalidRemoteException;
64  import org.eclipse.jgit.api.errors.RefNotFoundException;
65  import org.eclipse.jgit.junit.JGitTestUtil;
66  import org.eclipse.jgit.junit.RepositoryTestCase;
67  import org.eclipse.jgit.lib.BlobBasedConfig;
68  import org.eclipse.jgit.lib.Config;
69  import org.eclipse.jgit.lib.Constants;
70  import org.eclipse.jgit.lib.ObjectId;
71  import org.eclipse.jgit.lib.ObjectReader;
72  import org.eclipse.jgit.lib.Ref;
73  import org.eclipse.jgit.lib.Repository;
74  import org.eclipse.jgit.revwalk.RevCommit;
75  import org.eclipse.jgit.storage.file.FileBasedConfig;
76  import org.eclipse.jgit.util.FS;
77  import org.junit.Test;
78  
79  public class RepoCommandTest extends RepositoryTestCase {
80  
81  	private static final String BRANCH = "branch";
82  	private static final String TAG = "release";
83  
84  	private Repository defaultDb;
85  	private Repository notDefaultDb;
86  	private Repository groupADb;
87  	private Repository groupBDb;
88  
89  	private String rootUri;
90  	private String defaultUri;
91  	private String notDefaultUri;
92  	private String groupAUri;
93  	private String groupBUri;
94  
95  	private ObjectId oldCommitId;
96  
97  	@Override
98  	public void setUp() throws Exception {
99  		super.setUp();
100 
101 		defaultDb = createWorkRepository();
102 		try (Git git = new Git(defaultDb)) {
103 			JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "branch world");
104 			git.add().addFilepattern("hello.txt").call();
105 			oldCommitId = git.commit().setMessage("Initial commit").call().getId();
106 			git.checkout().setName(BRANCH).setCreateBranch(true).call();
107 			git.checkout().setName("master").call();
108 			git.tag().setName(TAG).call();
109 			JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "master world");
110 			git.add().addFilepattern("hello.txt").call();
111 			git.commit().setMessage("Second commit").call();
112 			addRepoToClose(defaultDb);
113 		}
114 
115 		notDefaultDb = createWorkRepository();
116 		try (Git git = new Git(notDefaultDb)) {
117 			JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello");
118 			git.add().addFilepattern("world.txt").call();
119 			git.commit().setMessage("Initial commit").call();
120 			addRepoToClose(notDefaultDb);
121 		}
122 
123 		groupADb = createWorkRepository();
124 		try (Git git = new Git(groupADb)) {
125 			JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world");
126 			git.add().addFilepattern("a.txt").call();
127 			git.commit().setMessage("Initial commit").call();
128 			addRepoToClose(groupADb);
129 		}
130 
131 		groupBDb = createWorkRepository();
132 		try (Git git = new Git(groupBDb)) {
133 			JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world");
134 			git.add().addFilepattern("b.txt").call();
135 			git.commit().setMessage("Initial commit").call();
136 			addRepoToClose(groupBDb);
137 		}
138 
139 		resolveRelativeUris();
140 	}
141 
142 	class IndexedRepos implements RepoCommand.RemoteReader {
143 		Map<String, Repository> uriRepoMap;
144 		IndexedRepos() {
145 			uriRepoMap = new HashMap<>();
146 		}
147 
148 		void put(String u, Repository r) {
149 			uriRepoMap.put(u, r);
150 		}
151 
152 		@Override
153 		public ObjectId sha1(String uri, String refname) throws GitAPIException {
154 			if (!uriRepoMap.containsKey(uri)) {
155 				return null;
156 			}
157 
158 			Repository r = uriRepoMap.get(uri);
159 			try {
160 				Ref ref = r.findRef(refname);
161 				if (ref == null) return null;
162 
163 				ref = r.getRefDatabase().peel(ref);
164 				ObjectId id = ref.getObjectId();
165 				return id;
166 			} catch (IOException e) {
167 				throw new InvalidRemoteException("", e);
168 			}
169 		}
170 
171 		@Override
172 		public byte[] readFile(String uri, String refName, String path)
173 			throws GitAPIException, IOException {
174 			Repository repo = uriRepoMap.get(uri);
175 
176 			String idStr = refName + ":" + path;
177 			ObjectId id = repo.resolve(idStr);
178 			if (id == null) {
179 				throw new RefNotFoundException(
180 					String.format("repo %s does not have %s", repo.toString(), idStr));
181 			}
182 			try (ObjectReader reader = repo.newObjectReader()) {
183 				return reader.open(id).getCachedBytes(Integer.MAX_VALUE);
184 			}
185 		}
186 	}
187 
188 	private Repository cloneRepository(Repository repo, boolean bare)
189 			throws Exception {
190 		Repository r = Git.cloneRepository()
191 				.setURI(repo.getDirectory().toURI().toString())
192 				.setDirectory(createUniqueTestGitDir(true)).setBare(bare).call()
193 				.getRepository();
194 		if (bare) {
195 			assertTrue(r.isBare());
196 		} else {
197 			assertFalse(r.isBare());
198 		}
199 		return r;
200 	}
201 
202 	@Test
203 	public void runTwiceIsNOP() throws Exception {
204 		try (Repository child = cloneRepository(groupADb, true);
205 				Repository dest = cloneRepository(db, true)) {
206 			StringBuilder xmlContent = new StringBuilder();
207 			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
208 					.append("<manifest>")
209 					.append("<remote name=\"remote1\" fetch=\"..\" />")
210 					.append("<default revision=\"master\" remote=\"remote1\" />")
211 					.append("<project path=\"base\" name=\"platform/base\" />")
212 					.append("</manifest>");
213 			RepoCommand cmd = new RepoCommand(dest);
214 
215 			IndexedRepos repos = new IndexedRepos();
216 			repos.put("platform/base", child);
217 
218 			RevCommit commit = cmd
219 					.setInputStream(new ByteArrayInputStream(
220 							xmlContent.toString().getBytes(UTF_8)))
221 					.setRemoteReader(repos).setURI("platform/")
222 					.setTargetURI("platform/superproject")
223 					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
224 					.call();
225 
226 			String firstIdStr = commit.getId().name() + ":" + ".gitmodules";
227 			commit = new RepoCommand(dest)
228 					.setInputStream(new ByteArrayInputStream(
229 							xmlContent.toString().getBytes(UTF_8)))
230 					.setRemoteReader(repos).setURI("platform/")
231 					.setTargetURI("platform/superproject")
232 					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
233 					.call();
234 			String idStr = commit.getId().name() + ":" + ".gitmodules";
235 			assertEquals(firstIdStr, idStr);
236 		}
237 	}
238 
239 	@Test
240 	public void androidSetup() throws Exception {
241 		try (Repository child = cloneRepository(groupADb, true);
242 				Repository dest = cloneRepository(db, true)) {
243 			StringBuilder xmlContent = new StringBuilder();
244 			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
245 					.append("<manifest>")
246 					.append("<remote name=\"remote1\" fetch=\"..\" />")
247 					.append("<default revision=\"master\" remote=\"remote1\" />")
248 					.append("<project path=\"base\" name=\"platform/base\" />")
249 					.append("</manifest>");
250 			RepoCommand cmd = new RepoCommand(dest);
251 
252 			IndexedRepos repos = new IndexedRepos();
253 			repos.put("platform/base", child);
254 
255 			RevCommit commit = cmd
256 					.setInputStream(new ByteArrayInputStream(
257 							xmlContent.toString().getBytes(UTF_8)))
258 					.setRemoteReader(repos).setURI("platform/")
259 					.setTargetURI("platform/superproject")
260 					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
261 					.call();
262 
263 			String idStr = commit.getId().name() + ":" + ".gitmodules";
264 			ObjectId modId = dest.resolve(idStr);
265 
266 			try (ObjectReader reader = dest.newObjectReader()) {
267 				byte[] bytes = reader.open(modId)
268 						.getCachedBytes(Integer.MAX_VALUE);
269 				Config base = new Config();
270 				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
271 				String subUrl = cfg.getString("submodule", "platform/base",
272 						"url");
273 				assertEquals(subUrl, "../base");
274 			}
275 		}
276 	}
277 
278 	@Test
279 	public void recordUnreachableRemotes() throws Exception {
280 		StringBuilder xmlContent = new StringBuilder();
281 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
282 			.append("<manifest>")
283 			.append("<remote name=\"remote1\" fetch=\"https://host.com/\" />")
284 			.append("<default revision=\"master\" remote=\"remote1\" />")
285 			.append("<project path=\"base\" name=\"platform/base\" />")
286 			.append("</manifest>");
287 
288 		try (Repository dest = cloneRepository(db, true)) {
289 			RevCommit commit = new RepoCommand(dest)
290 					.setInputStream(new ByteArrayInputStream(
291 							xmlContent.toString().getBytes(UTF_8)))
292 					.setRemoteReader(new IndexedRepos()).setURI("platform/")
293 					.setTargetURI("platform/superproject")
294 					.setRecordRemoteBranch(true).setIgnoreRemoteFailures(true)
295 					.setRecordSubmoduleLabels(true).call();
296 
297 			String idStr = commit.getId().name() + ":" + ".gitmodules";
298 			ObjectId modId = dest.resolve(idStr);
299 
300 			try (ObjectReader reader = dest.newObjectReader()) {
301 				byte[] bytes = reader.open(modId)
302 						.getCachedBytes(Integer.MAX_VALUE);
303 				Config base = new Config();
304 				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
305 				String subUrl = cfg.getString("submodule", "platform/base",
306 						"url");
307 				assertEquals(subUrl, "https://host.com/platform/base");
308 			}
309 		}
310 	}
311 
312 	@Test
313 	public void gerritSetup() throws Exception {
314 		try (Repository child = cloneRepository(groupADb, true);
315 				Repository dest = cloneRepository(db, true)) {
316 			StringBuilder xmlContent = new StringBuilder();
317 			xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
318 					.append("<manifest>")
319 					.append("<remote name=\"remote1\" fetch=\".\" />")
320 					.append("<default revision=\"master\" remote=\"remote1\" />")
321 					.append("<project path=\"plugins/cookbook\" name=\"plugins/cookbook\" />")
322 					.append("</manifest>");
323 			RepoCommand cmd = new RepoCommand(dest);
324 
325 			IndexedRepos repos = new IndexedRepos();
326 			repos.put("plugins/cookbook", child);
327 
328 			RevCommit commit = cmd
329 					.setInputStream(new ByteArrayInputStream(
330 							xmlContent.toString().getBytes(UTF_8)))
331 					.setRemoteReader(repos).setURI("").setTargetURI("gerrit")
332 					.setRecordRemoteBranch(true).setRecordSubmoduleLabels(true)
333 					.call();
334 
335 			String idStr = commit.getId().name() + ":" + ".gitmodules";
336 			ObjectId modId = dest.resolve(idStr);
337 
338 			try (ObjectReader reader = dest.newObjectReader()) {
339 				byte[] bytes = reader.open(modId)
340 						.getCachedBytes(Integer.MAX_VALUE);
341 				Config base = new Config();
342 				BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
343 				String subUrl = cfg.getString("submodule", "plugins/cookbook",
344 						"url");
345 				assertEquals(subUrl, "../plugins/cookbook");
346 			}
347 		}
348 	}
349 
350 	@Test
351 	public void absoluteRemoteURL() throws Exception {
352 		try (Repository child = cloneRepository(groupADb, true);
353 				Repository dest = cloneRepository(db, true)) {
354 			String abs = "https://chromium.googlesource.com";
355 			String repoUrl = "https://chromium.googlesource.com/chromium/src";
356 			boolean fetchSlash = false;
357 			boolean baseSlash = false;
358 			do {
359 				do {
360 					String fetchUrl = fetchSlash ? abs + "/" : abs;
361 					String baseUrl = baseSlash ? abs + "/" : abs;
362 
363 					StringBuilder xmlContent = new StringBuilder();
364 					xmlContent.append(
365 							"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
366 							.append("<manifest>")
367 							.append("<remote name=\"origin\" fetch=\""
368 									+ fetchUrl + "\" />")
369 							.append("<default revision=\"master\" remote=\"origin\" />")
370 							.append("<project path=\"src\" name=\"chromium/src\" />")
371 							.append("</manifest>");
372 					RepoCommand cmd = new RepoCommand(dest);
373 
374 					IndexedRepos repos = new IndexedRepos();
375 					repos.put(repoUrl, child);
376 
377 					RevCommit commit = cmd
378 							.setInputStream(new ByteArrayInputStream(
379 									xmlContent.toString().getBytes(UTF_8)))
380 							.setRemoteReader(repos).setURI(baseUrl)
381 							.setTargetURI("gerrit").setRecordRemoteBranch(true)
382 							.setRecordSubmoduleLabels(true).call();
383 
384 					String idStr = commit.getId().name() + ":" + ".gitmodules";
385 					ObjectId modId = dest.resolve(idStr);
386 
387 					try (ObjectReader reader = dest.newObjectReader()) {
388 						byte[] bytes = reader.open(modId)
389 								.getCachedBytes(Integer.MAX_VALUE);
390 						Config base = new Config();
391 						BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
392 						String subUrl = cfg.getString("submodule",
393 								"chromium/src", "url");
394 						assertEquals(
395 								"https://chromium.googlesource.com/chromium/src",
396 								subUrl);
397 					}
398 					fetchSlash = !fetchSlash;
399 				} while (fetchSlash);
400 				baseSlash = !baseSlash;
401 			} while (baseSlash);
402 		}
403 	}
404 
405 	@Test
406 	public void absoluteRemoteURLAbsoluteTargetURL() throws Exception {
407 		try (Repository child = cloneRepository(groupADb, true);
408 				Repository dest = cloneRepository(db, true)) {
409 			String abs = "https://chromium.googlesource.com";
410 			String repoUrl = "https://chromium.googlesource.com/chromium/src";
411 			boolean fetchSlash = false;
412 			boolean baseSlash = false;
413 			do {
414 				do {
415 					String fetchUrl = fetchSlash ? abs + "/" : abs;
416 					String baseUrl = baseSlash ? abs + "/" : abs;
417 
418 					StringBuilder xmlContent = new StringBuilder();
419 					xmlContent.append(
420 							"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
421 							.append("<manifest>")
422 							.append("<remote name=\"origin\" fetch=\""
423 									+ fetchUrl + "\" />")
424 							.append("<default revision=\"master\" remote=\"origin\" />")
425 							.append("<project path=\"src\" name=\"chromium/src\" />")
426 							.append("</manifest>");
427 					RepoCommand cmd = new RepoCommand(dest);
428 
429 					IndexedRepos repos = new IndexedRepos();
430 					repos.put(repoUrl, child);
431 
432 					RevCommit commit = cmd
433 							.setInputStream(new ByteArrayInputStream(
434 									xmlContent.toString().getBytes(UTF_8)))
435 							.setRemoteReader(repos).setURI(baseUrl)
436 							.setTargetURI(abs + "/superproject")
437 							.setRecordRemoteBranch(true)
438 							.setRecordSubmoduleLabels(true).call();
439 
440 					String idStr = commit.getId().name() + ":" + ".gitmodules";
441 					ObjectId modId = dest.resolve(idStr);
442 
443 					try (ObjectReader reader = dest.newObjectReader()) {
444 						byte[] bytes = reader.open(modId)
445 								.getCachedBytes(Integer.MAX_VALUE);
446 						Config base = new Config();
447 						BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
448 						String subUrl = cfg.getString("submodule",
449 								"chromium/src", "url");
450 						assertEquals("../chromium/src", subUrl);
451 					}
452 					fetchSlash = !fetchSlash;
453 				} while (fetchSlash);
454 				baseSlash = !baseSlash;
455 			} while (baseSlash);
456 		}
457 	}
458 
459 	@Test
460 	public void testAddRepoManifest() throws Exception {
461 		StringBuilder xmlContent = new StringBuilder();
462 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
463 			.append("<manifest>")
464 			.append("<remote name=\"remote1\" fetch=\".\" />")
465 			.append("<default revision=\"master\" remote=\"remote1\" />")
466 			.append("<project path=\"foo\" name=\"")
467 			.append(defaultUri)
468 			.append("\" />")
469 			.append("</manifest>");
470 		writeTrashFile("manifest.xml", xmlContent.toString());
471 		RepoCommand command = new RepoCommand(db);
472 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
473 			.setURI(rootUri)
474 			.call();
475 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
476 		assertTrue("submodule should be checked out", hello.exists());
477 		try (BufferedReader reader = new BufferedReader(
478 				new FileReader(hello))) {
479 			String content = reader.readLine();
480 			assertEquals("submodule content should be as expected",
481 					"master world", content);
482 		}
483 	}
484 
485 	@Test
486 	public void testRepoManifestGroups() throws Exception {
487 		StringBuilder xmlContent = new StringBuilder();
488 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
489 			.append("<manifest>")
490 			.append("<remote name=\"remote1\" fetch=\".\" />")
491 			.append("<default revision=\"master\" remote=\"remote1\" />")
492 			.append("<project path=\"foo\" name=\"")
493 			.append(defaultUri)
494 			.append("\" groups=\"a,test\" />")
495 			.append("<project path=\"bar\" name=\"")
496 			.append(notDefaultUri)
497 			.append("\" groups=\"notdefault\" />")
498 			.append("<project path=\"a\" name=\"")
499 			.append(groupAUri)
500 			.append("\" groups=\"a\" />")
501 			.append("<project path=\"b\" name=\"")
502 			.append(groupBUri)
503 			.append("\" groups=\"b\" />")
504 			.append("</manifest>");
505 
506 		// default should have foo, a & b
507 		Repository localDb = createWorkRepository();
508 		JGitTestUtil.writeTrashFile(
509 				localDb, "manifest.xml", xmlContent.toString());
510 		RepoCommand command = new RepoCommand(localDb);
511 		command
512 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
513 			.setURI(rootUri)
514 			.call();
515 		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
516 		assertTrue("default should have foo", file.exists());
517 		file = new File(localDb.getWorkTree(), "bar/world.txt");
518 		assertFalse("default shouldn't have bar", file.exists());
519 		file = new File(localDb.getWorkTree(), "a/a.txt");
520 		assertTrue("default should have a", file.exists());
521 		file = new File(localDb.getWorkTree(), "b/b.txt");
522 		assertTrue("default should have b", file.exists());
523 
524 		// all,-a should have bar & b
525 		localDb = createWorkRepository();
526 		JGitTestUtil.writeTrashFile(
527 				localDb, "manifest.xml", xmlContent.toString());
528 		command = new RepoCommand(localDb);
529 		command
530 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
531 			.setURI(rootUri)
532 			.setGroups("all,-a")
533 			.call();
534 		file = new File(localDb.getWorkTree(), "foo/hello.txt");
535 		assertFalse("\"all,-a\" shouldn't have foo", file.exists());
536 		file = new File(localDb.getWorkTree(), "bar/world.txt");
537 		assertTrue("\"all,-a\" should have bar", file.exists());
538 		file = new File(localDb.getWorkTree(), "a/a.txt");
539 		assertFalse("\"all,-a\" shuoldn't have a", file.exists());
540 		file = new File(localDb.getWorkTree(), "b/b.txt");
541 		assertTrue("\"all,-a\" should have b", file.exists());
542 	}
543 
544 	@Test
545 	public void testRepoManifestCopyFile() throws Exception {
546 		Repository localDb = createWorkRepository();
547 		StringBuilder xmlContent = new StringBuilder();
548 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
549 			.append("<manifest>")
550 			.append("<remote name=\"remote1\" fetch=\".\" />")
551 			.append("<default revision=\"master\" remote=\"remote1\" />")
552 			.append("<project path=\"foo\" name=\"")
553 			.append(defaultUri)
554 			.append("\">")
555 			.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
556 			.append("</project>")
557 			.append("</manifest>");
558 		JGitTestUtil.writeTrashFile(
559 				localDb, "manifest.xml", xmlContent.toString());
560 		RepoCommand command = new RepoCommand(localDb);
561 		command
562 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
563 			.setURI(rootUri)
564 			.call();
565 		// The original file should exist
566 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
567 		assertTrue("The original file should exist", hello.exists());
568 		try (BufferedReader reader = new BufferedReader(
569 				new FileReader(hello))) {
570 			String content = reader.readLine();
571 			assertEquals("The original file should have expected content",
572 					"master world", content);
573 		}
574 		// The dest file should also exist
575 		hello = new File(localDb.getWorkTree(), "Hello");
576 		assertTrue("The destination file should exist", hello.exists());
577 		try (BufferedReader reader = new BufferedReader(
578 				new FileReader(hello))) {
579 			String content = reader.readLine();
580 			assertEquals("The destination file should have expected content",
581 					"master world", content);
582 		}
583 	}
584 
585 	@Test
586 	public void testBareRepo() throws Exception {
587 		Repository remoteDb = createBareRepository();
588 		Repository tempDb = createWorkRepository();
589 
590 		StringBuilder xmlContent = new StringBuilder();
591 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
592 				.append("<manifest>")
593 				.append("<remote name=\"remote1\" fetch=\".\" />")
594 				.append("<default revision=\"master\" remote=\"remote1\" />")
595 				.append("<project path=\"foo\" name=\"").append(defaultUri)
596 				.append("\" />").append("</manifest>");
597 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
598 				xmlContent.toString());
599 		RepoCommand command = new RepoCommand(remoteDb);
600 		command.setPath(
601 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
602 				.setURI(rootUri).call();
603 		// Clone it
604 		File directory = createTempDirectory("testBareRepo");
605 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
606 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
607 				.getRepository()) {
608 			// The .gitmodules file should exist
609 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
610 			assertTrue("The .gitmodules file should exist",
611 					gitmodules.exists());
612 			// The first line of .gitmodules file should be expected
613 			try (BufferedReader reader = new BufferedReader(
614 					new FileReader(gitmodules))) {
615 				String content = reader.readLine();
616 				assertEquals(
617 						"The first line of .gitmodules file should be as expected",
618 						"[submodule \"" + defaultUri + "\"]", content);
619 			}
620 			// The gitlink should be the same as remote head sha1
621 			String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
622 			String remote = defaultDb.resolve(Constants.HEAD).name();
623 			assertEquals("The gitlink should be the same as remote head",
624 					remote, gitlink);
625 		}
626 	}
627 
628 	@Test
629 	public void testRevision() throws Exception {
630 		StringBuilder xmlContent = new StringBuilder();
631 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
632 			.append("<manifest>")
633 			.append("<remote name=\"remote1\" fetch=\".\" />")
634 			.append("<default revision=\"master\" remote=\"remote1\" />")
635 			.append("<project path=\"foo\" name=\"")
636 			.append(defaultUri)
637 			.append("\" revision=\"")
638 			.append(oldCommitId.name())
639 			.append("\" />")
640 			.append("</manifest>");
641 		writeTrashFile("manifest.xml", xmlContent.toString());
642 		RepoCommand command = new RepoCommand(db);
643 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
644 			.setURI(rootUri)
645 			.call();
646 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
647 		try (BufferedReader reader = new BufferedReader(
648 				new FileReader(hello))) {
649 			String content = reader.readLine();
650 			assertEquals("submodule content should be as expected",
651 					"branch world", content);
652 		}
653 	}
654 
655 	@Test
656 	public void testRevisionBranch() throws Exception {
657 		StringBuilder xmlContent = new StringBuilder();
658 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
659 			.append("<manifest>")
660 			.append("<remote name=\"remote1\" fetch=\".\" />")
661 			.append("<default revision=\"")
662 			.append(BRANCH)
663 			.append("\" remote=\"remote1\" />")
664 			.append("<project path=\"foo\" name=\"")
665 			.append(defaultUri)
666 			.append("\" />")
667 			.append("</manifest>");
668 		writeTrashFile("manifest.xml", xmlContent.toString());
669 		RepoCommand command = new RepoCommand(db);
670 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
671 			.setURI(rootUri)
672 			.call();
673 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
674 		try (BufferedReader reader = new BufferedReader(
675 				new FileReader(hello))) {
676 			String content = reader.readLine();
677 			assertEquals("submodule content should be as expected",
678 					"branch world", content);
679 		}
680 	}
681 
682 	@Test
683 	public void testRevisionTag() throws Exception {
684 		StringBuilder xmlContent = new StringBuilder();
685 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
686 			.append("<manifest>")
687 			.append("<remote name=\"remote1\" fetch=\".\" />")
688 			.append("<default revision=\"master\" remote=\"remote1\" />")
689 			.append("<project path=\"foo\" name=\"")
690 			.append(defaultUri)
691 			.append("\" revision=\"")
692 			.append(TAG)
693 			.append("\" />")
694 			.append("</manifest>");
695 		writeTrashFile("manifest.xml", xmlContent.toString());
696 		RepoCommand command = new RepoCommand(db);
697 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
698 			.setURI(rootUri)
699 			.call();
700 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
701 		try (BufferedReader reader = new BufferedReader(
702 				new FileReader(hello))) {
703 			String content = reader.readLine();
704 			assertEquals("submodule content should be as expected",
705 					"branch world", content);
706 		}
707 	}
708 
709 	@Test
710 	public void testRevisionBare() throws Exception {
711 		Repository remoteDb = createBareRepository();
712 		Repository tempDb = createWorkRepository();
713 
714 		StringBuilder xmlContent = new StringBuilder();
715 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
716 				.append("<manifest>")
717 				.append("<remote name=\"remote1\" fetch=\".\" />")
718 				.append("<default revision=\"").append(BRANCH)
719 				.append("\" remote=\"remote1\" />")
720 				.append("<project path=\"foo\" name=\"").append(defaultUri)
721 				.append("\" />").append("</manifest>");
722 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
723 				xmlContent.toString());
724 		RepoCommand command = new RepoCommand(remoteDb);
725 		command.setPath(
726 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
727 				.setURI(rootUri).call();
728 		// Clone it
729 		File directory = createTempDirectory("testRevisionBare");
730 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
731 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
732 				.getRepository()) {
733 			// The gitlink should be the same as oldCommitId
734 			String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
735 			assertEquals("The gitlink is same as remote head",
736 					oldCommitId.name(), gitlink);
737 		}
738 	}
739 
740 	@Test
741 	public void testCopyFileBare() throws Exception {
742 		Repository remoteDb = createBareRepository();
743 		Repository tempDb = createWorkRepository();
744 
745 		StringBuilder xmlContent = new StringBuilder();
746 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
747 				.append("<manifest>")
748 				.append("<remote name=\"remote1\" fetch=\".\" />")
749 				.append("<default revision=\"master\" remote=\"remote1\" />")
750 				.append("<project path=\"foo\" name=\"").append(defaultUri)
751 				.append("\" revision=\"").append(BRANCH).append("\" >")
752 				.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
753 				.append("<copyfile src=\"hello.txt\" dest=\"foo/Hello\" />")
754 				.append("</project>").append("</manifest>");
755 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
756 				xmlContent.toString());
757 		RepoCommand command = new RepoCommand(remoteDb);
758 		command.setPath(
759 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
760 				.setURI(rootUri).call();
761 		// Clone it
762 		File directory = createTempDirectory("testCopyFileBare");
763 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
764 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
765 				.getRepository()) {
766 			// The Hello file should exist
767 			File hello = new File(localDb.getWorkTree(), "Hello");
768 			assertTrue("The Hello file should exist", hello.exists());
769 			// The foo/Hello file should be skipped.
770 			File foohello = new File(localDb.getWorkTree(), "foo/Hello");
771 			assertFalse("The foo/Hello file should be skipped",
772 					foohello.exists());
773 			// The content of Hello file should be expected
774 			try (BufferedReader reader = new BufferedReader(
775 					new FileReader(hello))) {
776 				String content = reader.readLine();
777 				assertEquals("The Hello file should have expected content",
778 						"branch world", content);
779 			}
780 		}
781 	}
782 
783 	@Test
784 	public void testReplaceManifestBare() throws Exception {
785 		Repository remoteDb = createBareRepository();
786 		Repository tempDb = createWorkRepository();
787 
788 		StringBuilder xmlContent = new StringBuilder();
789 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
790 				.append("<manifest>")
791 				.append("<remote name=\"remote1\" fetch=\".\" />")
792 				.append("<default revision=\"master\" remote=\"remote1\" />")
793 				.append("<project path=\"foo\" name=\"").append(defaultUri)
794 				.append("\" revision=\"").append(BRANCH).append("\" >")
795 				.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
796 				.append("</project>").append("</manifest>");
797 		JGitTestUtil.writeTrashFile(tempDb, "old.xml", xmlContent.toString());
798 		RepoCommand command = new RepoCommand(remoteDb);
799 		command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/old.xml")
800 				.setURI(rootUri).call();
801 		xmlContent = new StringBuilder();
802 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
803 				.append("<manifest>")
804 				.append("<remote name=\"remote1\" fetch=\".\" />")
805 				.append("<default revision=\"master\" remote=\"remote1\" />")
806 				.append("<project path=\"bar\" name=\"").append(notDefaultUri)
807 				.append("\" >")
808 				.append("<copyfile src=\"world.txt\" dest=\"World.txt\" />")
809 				.append("</project>").append("</manifest>");
810 		JGitTestUtil.writeTrashFile(tempDb, "new.xml", xmlContent.toString());
811 		command = new RepoCommand(remoteDb);
812 		command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/new.xml")
813 				.setURI(rootUri).call();
814 		// Clone it
815 		File directory = createTempDirectory("testReplaceManifestBare");
816 		File dotmodules;
817 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
818 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
819 				.getRepository()) {
820 			// The Hello file should not exist
821 			File hello = new File(localDb.getWorkTree(), "Hello");
822 			assertFalse("The Hello file shouldn't exist", hello.exists());
823 			// The Hello.txt file should exist
824 			File hellotxt = new File(localDb.getWorkTree(), "World.txt");
825 			assertTrue("The World.txt file should exist", hellotxt.exists());
826 			dotmodules = new File(localDb.getWorkTree(),
827 					Constants.DOT_GIT_MODULES);
828 		}
829 		// The .gitmodules file should have 'submodule "bar"' and shouldn't
830 		// have
831 		// 'submodule "foo"' lines.
832 		try (BufferedReader reader = new BufferedReader(
833 				new FileReader(dotmodules))) {
834 			boolean foo = false;
835 			boolean bar = false;
836 			while (true) {
837 				String line = reader.readLine();
838 				if (line == null)
839 					break;
840 				if (line.contains("submodule \"" + defaultUri + "\""))
841 					foo = true;
842 				if (line.contains("submodule \"" + notDefaultUri + "\""))
843 					bar = true;
844 			}
845 			assertTrue("The bar submodule should exist", bar);
846 			assertFalse("The foo submodule shouldn't exist", foo);
847 		}
848 	}
849 
850 	@Test
851 	public void testRemoveOverlappingBare() throws Exception {
852 		Repository remoteDb = createBareRepository();
853 		Repository tempDb = createWorkRepository();
854 
855 		StringBuilder xmlContent = new StringBuilder();
856 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
857 				.append("<manifest>")
858 				.append("<remote name=\"remote1\" fetch=\".\" />")
859 				.append("<default revision=\"master\" remote=\"remote1\" />")
860 				.append("<project path=\"foo/bar\" name=\"").append(groupBUri)
861 				.append("\" />").append("<project path=\"a\" name=\"")
862 				.append(groupAUri).append("\" />")
863 				.append("<project path=\"foo\" name=\"").append(defaultUri)
864 				.append("\" />").append("</manifest>");
865 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
866 				xmlContent.toString());
867 		RepoCommand command = new RepoCommand(remoteDb);
868 		command.setPath(
869 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
870 				.setURI(rootUri).call();
871 		// Clone it
872 		File directory = createTempDirectory("testRemoveOverlappingBare");
873 		File dotmodules;
874 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
875 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
876 				.getRepository()) {
877 			dotmodules = new File(localDb.getWorkTree(),
878 				Constants.DOT_GIT_MODULES);
879 		}
880 
881 		// Check .gitmodules file
882 		try (BufferedReader reader = new BufferedReader(
883 				new FileReader(dotmodules))) {
884 			boolean foo = false;
885 			boolean foobar = false;
886 			boolean a = false;
887 			while (true) {
888 				String line = reader.readLine();
889 				if (line == null)
890 					break;
891 				if (line.contains("submodule \"" + defaultUri + "\""))
892 					foo = true;
893 				if (line.contains("submodule \"" + groupBUri + "\""))
894 					foobar = true;
895 				if (line.contains("submodule \"" + groupAUri + "\""))
896 					a = true;
897 			}
898 			assertTrue("The " + defaultUri + " submodule should exist", foo);
899 			assertFalse("The " + groupBUri + " submodule shouldn't exist",
900 					foobar);
901 			assertTrue("The " + groupAUri + " submodule should exist", a);
902 		}
903 	}
904 
905 	@Test
906 	public void testIncludeTag() throws Exception {
907 		Repository localDb = createWorkRepository();
908 		Repository tempDb = createWorkRepository();
909 
910 		StringBuilder xmlContent = new StringBuilder();
911 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
912 			.append("<manifest>")
913 			.append("<include name=\"_include.xml\" />")
914 			.append("<default revision=\"master\" remote=\"remote1\" />")
915 			.append("</manifest>");
916 		JGitTestUtil.writeTrashFile(
917 				tempDb, "manifest.xml", xmlContent.toString());
918 
919 		xmlContent = new StringBuilder();
920 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
921 			.append("<manifest>")
922 			.append("<remote name=\"remote1\" fetch=\".\" />")
923 			.append("<default revision=\"master\" remote=\"remote1\" />")
924 			.append("<project path=\"foo\" name=\"")
925 			.append(defaultUri)
926 			.append("\" />")
927 			.append("</manifest>");
928 		JGitTestUtil.writeTrashFile(
929 				tempDb, "_include.xml", xmlContent.toString());
930 
931 		RepoCommand command = new RepoCommand(localDb);
932 		command
933 			.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
934 			.setURI(rootUri)
935 			.call();
936 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
937 		assertTrue("submodule should be checked out", hello.exists());
938 		try (BufferedReader reader = new BufferedReader(
939 				new FileReader(hello))) {
940 			String content = reader.readLine();
941 			assertEquals("submodule content should be as expected",
942 					"master world", content);
943 		}
944 	}
945 	@Test
946 	public void testRemoteAlias() throws Exception {
947 		StringBuilder xmlContent = new StringBuilder();
948 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
949 			.append("<manifest>")
950 			.append("<remote name=\"remote1\" fetch=\".\" alias=\"remote2\" />")
951 			.append("<default revision=\"master\" remote=\"remote2\" />")
952 			.append("<project path=\"foo\" name=\"")
953 			.append(defaultUri)
954 			.append("\" />")
955 			.append("</manifest>");
956 
957 		Repository localDb = createWorkRepository();
958 		JGitTestUtil.writeTrashFile(
959 				localDb, "manifest.xml", xmlContent.toString());
960 		RepoCommand command = new RepoCommand(localDb);
961 		command
962 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
963 			.setURI(rootUri)
964 			.call();
965 		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
966 		assertTrue("We should have foo", file.exists());
967 	}
968 
969 	@Test
970 	public void testTargetBranch() throws Exception {
971 		Repository remoteDb1 = createBareRepository();
972 		Repository remoteDb2 = createBareRepository();
973 		Repository tempDb = createWorkRepository();
974 
975 		StringBuilder xmlContent = new StringBuilder();
976 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
977 				.append("<manifest>")
978 				.append("<remote name=\"remote1\" fetch=\".\" />")
979 				.append("<default revision=\"master\" remote=\"remote1\" />")
980 				.append("<project path=\"foo\" name=\"").append(defaultUri)
981 				.append("\" />").append("</manifest>");
982 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
983 				xmlContent.toString());
984 		RepoCommand command = new RepoCommand(remoteDb1);
985 		command.setPath(
986 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
987 				.setURI(rootUri).setTargetBranch("test").call();
988 		ObjectId branchId = remoteDb1
989 				.resolve(Constants.R_HEADS + "test^{tree}");
990 		command = new RepoCommand(remoteDb2);
991 		command.setPath(
992 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
993 				.setURI(rootUri).call();
994 		ObjectId defaultId = remoteDb2.resolve(Constants.HEAD + "^{tree}");
995 		assertEquals(
996 				"The tree id of branch db and default db should be the same",
997 				branchId, defaultId);
998 	}
999 
1000 	@Test
1001 	public void testRecordRemoteBranch() throws Exception {
1002 		Repository remoteDb = createBareRepository();
1003 		Repository tempDb = createWorkRepository();
1004 
1005 		StringBuilder xmlContent = new StringBuilder();
1006 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1007 				.append("<manifest>")
1008 				.append("<remote name=\"remote1\" fetch=\".\" />")
1009 				.append("<default revision=\"master\" remote=\"remote1\" />")
1010 				.append("<project path=\"with-branch\" ")
1011 				.append("revision=\"master\" ").append("name=\"")
1012 				.append(notDefaultUri).append("\" />")
1013 				.append("<project path=\"with-long-branch\" ")
1014 				.append("revision=\"refs/heads/master\" ").append("name=\"")
1015 				.append(defaultUri).append("\" />").append("</manifest>");
1016 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
1017 				xmlContent.toString());
1018 
1019 		RepoCommand command = new RepoCommand(remoteDb);
1020 		command.setPath(
1021 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
1022 				.setURI(rootUri).setRecordRemoteBranch(true).call();
1023 		// Clone it
1024 		File directory = createTempDirectory("testBareRepo");
1025 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
1026 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
1027 				.getRepository();) {
1028 			// The .gitmodules file should exist
1029 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
1030 			assertTrue("The .gitmodules file should exist",
1031 					gitmodules.exists());
1032 			FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
1033 			c.load();
1034 			assertEquals(
1035 					"Recording remote branches should work for short branch descriptions",
1036 					"master",
1037 					c.getString("submodule", notDefaultUri, "branch"));
1038 			assertEquals(
1039 					"Recording remote branches should work for full ref specs",
1040 					"refs/heads/master",
1041 					c.getString("submodule", defaultUri, "branch"));
1042 		}
1043 	}
1044 
1045 
1046 	@Test
1047 	public void testRecordSubmoduleLabels() throws Exception {
1048 		Repository remoteDb = createBareRepository();
1049 		Repository tempDb = createWorkRepository();
1050 
1051 		StringBuilder xmlContent = new StringBuilder();
1052 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1053 				.append("<manifest>")
1054 				.append("<remote name=\"remote1\" fetch=\".\" />")
1055 				.append("<default revision=\"master\" remote=\"remote1\" />")
1056 				.append("<project path=\"test\" ")
1057 				.append("revision=\"master\" ").append("name=\"")
1058 				.append(notDefaultUri).append("\" ")
1059 				.append("groups=\"a1,a2\" />").append("</manifest>");
1060 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
1061 				xmlContent.toString());
1062 
1063 		RepoCommand command = new RepoCommand(remoteDb);
1064 		command.setPath(
1065 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
1066 				.setURI(rootUri).setRecordSubmoduleLabels(true).call();
1067 		// Clone it
1068 		File directory = createTempDirectory("testBareRepo");
1069 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
1070 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
1071 				.getRepository();) {
1072 			// The .gitattributes file should exist
1073 			File gitattributes = new File(localDb.getWorkTree(),
1074 					".gitattributes");
1075 			assertTrue("The .gitattributes file should exist",
1076 					gitattributes.exists());
1077 			try (BufferedReader reader = new BufferedReader(
1078 					new FileReader(gitattributes));) {
1079 				String content = reader.readLine();
1080 				assertEquals(".gitattributes content should be as expected",
1081 						"/test a1 a2", content);
1082 			}
1083 		}
1084 	}
1085 
1086 	@Test
1087 	public void testRecordShallowRecommendation() throws Exception {
1088 		Repository remoteDb = createBareRepository();
1089 		Repository tempDb = createWorkRepository();
1090 
1091 		StringBuilder xmlContent = new StringBuilder();
1092 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1093 				.append("<manifest>")
1094 				.append("<remote name=\"remote1\" fetch=\".\" />")
1095 				.append("<default revision=\"master\" remote=\"remote1\" />")
1096 				.append("<project path=\"shallow-please\" ").append("name=\"")
1097 				.append(defaultUri).append("\" ").append("clone-depth=\"1\" />")
1098 				.append("<project path=\"non-shallow\" ").append("name=\"")
1099 				.append(notDefaultUri).append("\" />").append("</manifest>");
1100 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
1101 				xmlContent.toString());
1102 
1103 		RepoCommand command = new RepoCommand(remoteDb);
1104 		command.setPath(
1105 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
1106 				.setURI(rootUri).setRecommendShallow(true).call();
1107 		// Clone it
1108 		File directory = createTempDirectory("testBareRepo");
1109 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
1110 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
1111 				.getRepository();) {
1112 			// The .gitmodules file should exist
1113 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
1114 			assertTrue("The .gitmodules file should exist",
1115 					gitmodules.exists());
1116 			FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
1117 			c.load();
1118 			assertEquals("Recording shallow configuration should work", "true",
1119 					c.getString("submodule", defaultUri, "shallow"));
1120 			assertNull("Recording non shallow configuration should work",
1121 					c.getString("submodule", notDefaultUri, "shallow"));
1122 		}
1123 	}
1124 
1125 	@Test
1126 	public void testRemoteRevision() throws Exception {
1127 		StringBuilder xmlContent = new StringBuilder();
1128 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1129 			.append("<manifest>")
1130 			.append("<remote name=\"remote1\" fetch=\".\" />")
1131 			.append("<remote name=\"remote2\" fetch=\".\" revision=\"")
1132 			.append(BRANCH)
1133 			.append("\" />")
1134 			.append("<default remote=\"remote1\" revision=\"master\" />")
1135 			.append("<project path=\"foo\" remote=\"remote2\" name=\"")
1136 			.append(defaultUri)
1137 			.append("\" />")
1138 			.append("</manifest>");
1139 		writeTrashFile("manifest.xml", xmlContent.toString());
1140 		RepoCommand command = new RepoCommand(db);
1141 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
1142 			.setURI(rootUri)
1143 			.call();
1144 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
1145 		try (BufferedReader reader = new BufferedReader(
1146 				new FileReader(hello))) {
1147 			String content = reader.readLine();
1148 			assertEquals("submodule content should be as expected",
1149 					"branch world", content);
1150 		}
1151 	}
1152 
1153 	@Test
1154 	public void testDefaultRemoteRevision() throws Exception {
1155 		StringBuilder xmlContent = new StringBuilder();
1156 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1157 			.append("<manifest>")
1158 			.append("<remote name=\"remote1\" fetch=\".\" revision=\"")
1159 			.append(BRANCH)
1160 			.append("\" />")
1161 			.append("<default remote=\"remote1\" />")
1162 			.append("<project path=\"foo\" name=\"")
1163 			.append(defaultUri)
1164 			.append("\" />")
1165 			.append("</manifest>");
1166 		writeTrashFile("manifest.xml", xmlContent.toString());
1167 		RepoCommand command = new RepoCommand(db);
1168 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
1169 			.setURI(rootUri)
1170 			.call();
1171 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
1172 		try (BufferedReader reader = new BufferedReader(
1173 				new FileReader(hello))) {
1174 			String content = reader.readLine();
1175 			assertEquals("submodule content should be as expected",
1176 					"branch world", content);
1177 		}
1178 	}
1179 
1180 	@Test
1181 	public void testTwoPathUseTheSameName() throws Exception {
1182 		Repository remoteDb = createBareRepository();
1183 		Repository tempDb = createWorkRepository();
1184 
1185 		StringBuilder xmlContent = new StringBuilder();
1186 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1187 				.append("<manifest>")
1188 				.append("<remote name=\"remote1\" fetch=\".\" />")
1189 				.append("<default revision=\"master\" remote=\"remote1\" />")
1190 				.append("<project path=\"path1\" ").append("name=\"")
1191 				.append(defaultUri).append("\" />")
1192 				.append("<project path=\"path2\" ").append("name=\"")
1193 				.append(defaultUri).append("\" />").append("</manifest>");
1194 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
1195 				xmlContent.toString());
1196 
1197 		RepoCommand command = new RepoCommand(remoteDb);
1198 		command.setPath(
1199 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
1200 				.setURI(rootUri).setRecommendShallow(true).call();
1201 		File directory = createTempDirectory("testBareRepo");
1202 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
1203 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
1204 				.getRepository();) {
1205 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
1206 			assertTrue("The .gitmodules file should exist",
1207 					gitmodules.exists());
1208 			FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
1209 			c.load();
1210 			assertEquals("A module should exist for path1", "path1",
1211 					c.getString("submodule", defaultUri + "/path1", "path"));
1212 			assertEquals("A module should exist for path2", "path2",
1213 					c.getString("submodule", defaultUri + "/path2", "path"));
1214 		}
1215 	}
1216 
1217 	private void resolveRelativeUris() {
1218 		// Find the longest common prefix ends with "/" as rootUri.
1219 		defaultUri = defaultDb.getDirectory().toURI().toString();
1220 		notDefaultUri = notDefaultDb.getDirectory().toURI().toString();
1221 		groupAUri = groupADb.getDirectory().toURI().toString();
1222 		groupBUri = groupBDb.getDirectory().toURI().toString();
1223 		int start = 0;
1224 		while (start <= defaultUri.length()) {
1225 			int newStart = defaultUri.indexOf('/', start + 1);
1226 			String prefix = defaultUri.substring(0, newStart);
1227 			if (!notDefaultUri.startsWith(prefix) ||
1228 					!groupAUri.startsWith(prefix) ||
1229 					!groupBUri.startsWith(prefix)) {
1230 				start++;
1231 				rootUri = defaultUri.substring(0, start) + "manifest";
1232 				defaultUri = defaultUri.substring(start);
1233 				notDefaultUri = notDefaultUri.substring(start);
1234 				groupAUri = groupAUri.substring(start);
1235 				groupBUri = groupBUri.substring(start);
1236 				return;
1237 			}
1238 			start = newStart;
1239 		}
1240 	}
1241 
1242 	void testRelative(String a, String b, String want) {
1243 		String got = RepoCommand.relativize(URI.create(a), URI.create(b)).toString();
1244 
1245 		if (!got.equals(want)) {
1246 			fail(String.format("relative('%s', '%s') = '%s', want '%s'", a, b, got, want));
1247 		}
1248 	}
1249 
1250 	@Test
1251 	public void relative() {
1252 		testRelative("a/b/", "a/", "../");
1253 		// Normalization:
1254 		testRelative("a/p/..//b/", "a/", "../");
1255 		testRelative("a/b", "a/", "");
1256 		testRelative("a/", "a/b/", "b/");
1257 		testRelative("a/", "a/b", "b");
1258 		testRelative("/a/b/c", "/b/c", "../../b/c");
1259 		testRelative("/abc", "bcd", "bcd");
1260 		testRelative("abc", "def", "def");
1261 		testRelative("abc", "/bcd", "/bcd");
1262 		testRelative("http://a", "a/b", "a/b");
1263 		testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
1264 		testRelative("http://base.com/a/", "http://base.com/a/b", "b");
1265 	}
1266 }