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 org.junit.Assert.assertEquals;
46  import static org.junit.Assert.assertFalse;
47  import static org.junit.Assert.assertNull;
48  import static org.junit.Assert.assertTrue;
49  import static org.junit.Assert.fail;
50  
51  import java.io.BufferedReader;
52  import java.io.ByteArrayInputStream;
53  import java.io.File;
54  import java.io.FileReader;
55  import java.io.IOException;
56  import java.net.URI;
57  import java.nio.charset.StandardCharsets;
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.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 	@Test
189 	public void androidSetup() throws Exception {
190 		Repository child = Git.cloneRepository()
191 				.setURI(groupADb.getDirectory().toURI().toString())
192 				.setDirectory(createUniqueTestGitDir(true)).setBare(true).call()
193 				.getRepository();
194 
195 		Repository dest = Git.cloneRepository()
196 				.setURI(db.getDirectory().toURI().toString())
197 				.setDirectory(createUniqueTestGitDir(true)).setBare(true).call()
198 				.getRepository();
199 
200 		assertTrue(dest.isBare());
201 		assertTrue(child.isBare());
202 
203 		StringBuilder xmlContent = new StringBuilder();
204 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
205 			.append("<manifest>")
206 			.append("<remote name=\"remote1\" fetch=\"..\" />")
207 			.append("<default revision=\"master\" remote=\"remote1\" />")
208 			.append("<project path=\"base\" name=\"platform/base\" />")
209 			.append("</manifest>");
210 		RepoCommand cmd = new RepoCommand(dest);
211 
212 		IndexedRepos repos = new IndexedRepos();
213 		repos.put("platform/base", child);
214 
215 		RevCommit commit = cmd
216 			.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
217 			.setRemoteReader(repos)
218 			.setURI("platform/")
219 			.setTargetURI("platform/superproject")
220 			.setRecordRemoteBranch(true)
221 			.setRecordSubmoduleLabels(true)
222 			.call();
223 
224 		String idStr = commit.getId().name() + ":" + ".gitmodules";
225 		ObjectId modId = dest.resolve(idStr);
226 
227 		try (ObjectReader reader = dest.newObjectReader()) {
228 			byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
229 			Config base = new Config();
230 			BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
231 			String subUrl = cfg.getString("submodule", "base", "url");
232 			assertEquals(subUrl, "../base");
233 		}
234 
235 		child.close();
236 		dest.close();
237 	}
238 
239 	@Test
240 	public void gerritSetup() throws Exception {
241 		Repository child =
242 			Git.cloneRepository().setURI(groupADb.getDirectory().toURI().toString())
243 				.setDirectory(createUniqueTestGitDir(true))
244 				.setBare(true).call().getRepository();
245 
246 		Repository dest = Git.cloneRepository()
247 			.setURI(db.getDirectory().toURI().toString()).setDirectory(createUniqueTestGitDir(true))
248 			.setBare(true).call().getRepository();
249 
250 		assertTrue(dest.isBare());
251 		assertTrue(child.isBare());
252 
253 		StringBuilder xmlContent = new StringBuilder();
254 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
255 			.append("<manifest>")
256 			.append("<remote name=\"remote1\" fetch=\".\" />")
257 			.append("<default revision=\"master\" remote=\"remote1\" />")
258 			.append("<project path=\"plugins/cookbook\" name=\"plugins/cookbook\" />")
259 			.append("</manifest>");
260 		RepoCommand cmd = new RepoCommand(dest);
261 
262 		IndexedRepos repos = new IndexedRepos();
263 		repos.put("plugins/cookbook", child);
264 
265 		RevCommit commit = cmd
266 			.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
267 			.setRemoteReader(repos)
268 			.setURI("")
269 			.setTargetURI("gerrit")
270 			.setRecordRemoteBranch(true)
271 			.setRecordSubmoduleLabels(true)
272 			.call();
273 
274 		String idStr = commit.getId().name() + ":" + ".gitmodules";
275 		ObjectId modId = dest.resolve(idStr);
276 
277 		try (ObjectReader reader = dest.newObjectReader()) {
278 			byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
279 			Config base = new Config();
280 			BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
281 			String subUrl = cfg.getString("submodule", "plugins/cookbook", "url");
282 			assertEquals(subUrl, "../plugins/cookbook");
283 		}
284 
285 		child.close();
286 		dest.close();
287 	}
288 
289 	@Test
290 	public void absoluteRemoteURL() throws Exception {
291 		Repository child =
292 			Git.cloneRepository().setURI(groupADb.getDirectory().toURI().toString())
293 				.setDirectory(createUniqueTestGitDir(true))
294 				.setBare(true).call().getRepository();
295 		Repository dest = Git.cloneRepository()
296 			.setURI(db.getDirectory().toURI().toString()).setDirectory(createUniqueTestGitDir(true))
297 			.setBare(true).call().getRepository();
298 		String abs = "https://chromium.googlesource.com";
299 		String repoUrl = "https://chromium.googlesource.com/chromium/src";
300 		boolean fetchSlash = false;
301 		boolean baseSlash = false;
302 		do {
303 			do {
304 				String fetchUrl = fetchSlash ? abs + "/" : abs;
305 				String baseUrl = baseSlash ? abs + "/" : abs;
306 
307 				StringBuilder xmlContent = new StringBuilder();
308 				xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
309 					.append("<manifest>")
310 					.append("<remote name=\"origin\" fetch=\"" + fetchUrl + "\" />")
311 					.append("<default revision=\"master\" remote=\"origin\" />")
312 					.append("<project path=\"src\" name=\"chromium/src\" />")
313 					.append("</manifest>");
314 				RepoCommand cmd = new RepoCommand(dest);
315 
316 				IndexedRepos repos = new IndexedRepos();
317 				repos.put(repoUrl, child);
318 
319 				RevCommit commit = cmd
320 					.setInputStream(new ByteArrayInputStream(xmlContent.toString().getBytes(StandardCharsets.UTF_8)))
321 					.setRemoteReader(repos)
322 					.setURI(baseUrl)
323 					.setTargetURI("gerrit")
324 					.setRecordRemoteBranch(true)
325 					.setRecordSubmoduleLabels(true)
326 					.call();
327 
328 				String idStr = commit.getId().name() + ":" + ".gitmodules";
329 				ObjectId modId = dest.resolve(idStr);
330 
331 				try (ObjectReader reader = dest.newObjectReader()) {
332 					byte[] bytes = reader.open(modId).getCachedBytes(Integer.MAX_VALUE);
333 					Config base = new Config();
334 					BlobBasedConfig cfg = new BlobBasedConfig(base, bytes);
335 					String subUrl = cfg.getString("submodule", "src", "url");
336 					assertEquals("https://chromium.googlesource.com/chromium/src", subUrl);
337 				}
338 				fetchSlash = !fetchSlash;
339 			} while (fetchSlash);
340 			baseSlash = !baseSlash;
341 		} while (baseSlash);
342 		child.close();
343 		dest.close();
344 	}
345 
346 	@Test
347 	public void testAddRepoManifest() throws Exception {
348 		StringBuilder xmlContent = new StringBuilder();
349 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
350 			.append("<manifest>")
351 			.append("<remote name=\"remote1\" fetch=\".\" />")
352 			.append("<default revision=\"master\" remote=\"remote1\" />")
353 			.append("<project path=\"foo\" name=\"")
354 			.append(defaultUri)
355 			.append("\" />")
356 			.append("</manifest>");
357 		writeTrashFile("manifest.xml", xmlContent.toString());
358 		RepoCommand command = new RepoCommand(db);
359 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
360 			.setURI(rootUri)
361 			.call();
362 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
363 		assertTrue("submodule should be checked out", hello.exists());
364 		BufferedReader reader = new BufferedReader(new FileReader(hello));
365 		String content = reader.readLine();
366 		reader.close();
367 		assertEquals("submodule content should be as expected",
368 				"master world", content);
369 	}
370 
371 	@Test
372 	public void testRepoManifestGroups() throws Exception {
373 		StringBuilder xmlContent = new StringBuilder();
374 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
375 			.append("<manifest>")
376 			.append("<remote name=\"remote1\" fetch=\".\" />")
377 			.append("<default revision=\"master\" remote=\"remote1\" />")
378 			.append("<project path=\"foo\" name=\"")
379 			.append(defaultUri)
380 			.append("\" groups=\"a,test\" />")
381 			.append("<project path=\"bar\" name=\"")
382 			.append(notDefaultUri)
383 			.append("\" groups=\"notdefault\" />")
384 			.append("<project path=\"a\" name=\"")
385 			.append(groupAUri)
386 			.append("\" groups=\"a\" />")
387 			.append("<project path=\"b\" name=\"")
388 			.append(groupBUri)
389 			.append("\" groups=\"b\" />")
390 			.append("</manifest>");
391 
392 		// default should have foo, a & b
393 		Repository localDb = createWorkRepository();
394 		JGitTestUtil.writeTrashFile(
395 				localDb, "manifest.xml", xmlContent.toString());
396 		RepoCommand command = new RepoCommand(localDb);
397 		command
398 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
399 			.setURI(rootUri)
400 			.call();
401 		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
402 		assertTrue("default should have foo", file.exists());
403 		file = new File(localDb.getWorkTree(), "bar/world.txt");
404 		assertFalse("default shouldn't have bar", file.exists());
405 		file = new File(localDb.getWorkTree(), "a/a.txt");
406 		assertTrue("default should have a", file.exists());
407 		file = new File(localDb.getWorkTree(), "b/b.txt");
408 		assertTrue("default should have b", file.exists());
409 
410 		// all,-a should have bar & b
411 		localDb = createWorkRepository();
412 		JGitTestUtil.writeTrashFile(
413 				localDb, "manifest.xml", xmlContent.toString());
414 		command = new RepoCommand(localDb);
415 		command
416 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
417 			.setURI(rootUri)
418 			.setGroups("all,-a")
419 			.call();
420 		file = new File(localDb.getWorkTree(), "foo/hello.txt");
421 		assertFalse("\"all,-a\" shouldn't have foo", file.exists());
422 		file = new File(localDb.getWorkTree(), "bar/world.txt");
423 		assertTrue("\"all,-a\" should have bar", file.exists());
424 		file = new File(localDb.getWorkTree(), "a/a.txt");
425 		assertFalse("\"all,-a\" shuoldn't have a", file.exists());
426 		file = new File(localDb.getWorkTree(), "b/b.txt");
427 		assertTrue("\"all,-a\" should have b", file.exists());
428 	}
429 
430 	@Test
431 	public void testRepoManifestCopyFile() throws Exception {
432 		Repository localDb = createWorkRepository();
433 		StringBuilder xmlContent = new StringBuilder();
434 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
435 			.append("<manifest>")
436 			.append("<remote name=\"remote1\" fetch=\".\" />")
437 			.append("<default revision=\"master\" remote=\"remote1\" />")
438 			.append("<project path=\"foo\" name=\"")
439 			.append(defaultUri)
440 			.append("\">")
441 			.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
442 			.append("</project>")
443 			.append("</manifest>");
444 		JGitTestUtil.writeTrashFile(
445 				localDb, "manifest.xml", xmlContent.toString());
446 		RepoCommand command = new RepoCommand(localDb);
447 		command
448 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
449 			.setURI(rootUri)
450 			.call();
451 		// The original file should exist
452 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
453 		assertTrue("The original file should exist", hello.exists());
454 		BufferedReader reader = new BufferedReader(new FileReader(hello));
455 		String content = reader.readLine();
456 		reader.close();
457 		assertEquals("The original file should have expected content",
458 				"master world", content);
459 		// The dest file should also exist
460 		hello = new File(localDb.getWorkTree(), "Hello");
461 		assertTrue("The destination file should exist", hello.exists());
462 		reader = new BufferedReader(new FileReader(hello));
463 		content = reader.readLine();
464 		reader.close();
465 		assertEquals("The destination file should have expected content",
466 				"master world", content);
467 	}
468 
469 	@Test
470 	public void testBareRepo() throws Exception {
471 		Repository remoteDb = createBareRepository();
472 		Repository tempDb = createWorkRepository();
473 
474 		StringBuilder xmlContent = new StringBuilder();
475 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
476 				.append("<manifest>")
477 				.append("<remote name=\"remote1\" fetch=\".\" />")
478 				.append("<default revision=\"master\" remote=\"remote1\" />")
479 				.append("<project path=\"foo\" name=\"").append(defaultUri)
480 				.append("\" />").append("</manifest>");
481 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
482 				xmlContent.toString());
483 		RepoCommand command = new RepoCommand(remoteDb);
484 		command.setPath(
485 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
486 				.setURI(rootUri).call();
487 		// Clone it
488 		File directory = createTempDirectory("testBareRepo");
489 		Repository localDb = Git.cloneRepository().setDirectory(directory)
490 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
491 				.getRepository();
492 		// The .gitmodules file should exist
493 		File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
494 		assertTrue("The .gitmodules file should exist", gitmodules.exists());
495 		// The first line of .gitmodules file should be expected
496 		BufferedReader reader = new BufferedReader(new FileReader(gitmodules));
497 		String content = reader.readLine();
498 		reader.close();
499 		assertEquals("The first line of .gitmodules file should be as expected",
500 				"[submodule \"foo\"]", content);
501 		// The gitlink should be the same as remote head sha1
502 		String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
503 		localDb.close();
504 		String remote = defaultDb.resolve(Constants.HEAD).name();
505 		assertEquals("The gitlink should be the same as remote head", remote,
506 				gitlink);
507 	}
508 
509 	@Test
510 	public void testRevision() throws Exception {
511 		StringBuilder xmlContent = new StringBuilder();
512 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
513 			.append("<manifest>")
514 			.append("<remote name=\"remote1\" fetch=\".\" />")
515 			.append("<default revision=\"master\" remote=\"remote1\" />")
516 			.append("<project path=\"foo\" name=\"")
517 			.append(defaultUri)
518 			.append("\" revision=\"")
519 			.append(oldCommitId.name())
520 			.append("\" />")
521 			.append("</manifest>");
522 		writeTrashFile("manifest.xml", xmlContent.toString());
523 		RepoCommand command = new RepoCommand(db);
524 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
525 			.setURI(rootUri)
526 			.call();
527 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
528 		BufferedReader reader = new BufferedReader(new FileReader(hello));
529 		String content = reader.readLine();
530 		reader.close();
531 		assertEquals("submodule content should be as expected",
532 				"branch world", content);
533 	}
534 
535 	@Test
536 	public void testRevisionBranch() throws Exception {
537 		StringBuilder xmlContent = new StringBuilder();
538 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
539 			.append("<manifest>")
540 			.append("<remote name=\"remote1\" fetch=\".\" />")
541 			.append("<default revision=\"")
542 			.append(BRANCH)
543 			.append("\" remote=\"remote1\" />")
544 			.append("<project path=\"foo\" name=\"")
545 			.append(defaultUri)
546 			.append("\" />")
547 			.append("</manifest>");
548 		writeTrashFile("manifest.xml", xmlContent.toString());
549 		RepoCommand command = new RepoCommand(db);
550 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
551 			.setURI(rootUri)
552 			.call();
553 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
554 		BufferedReader reader = new BufferedReader(new FileReader(hello));
555 		String content = reader.readLine();
556 		reader.close();
557 		assertEquals("submodule content should be as expected",
558 				"branch world", content);
559 	}
560 
561 	@Test
562 	public void testRevisionTag() throws Exception {
563 		StringBuilder xmlContent = new StringBuilder();
564 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
565 			.append("<manifest>")
566 			.append("<remote name=\"remote1\" fetch=\".\" />")
567 			.append("<default revision=\"master\" remote=\"remote1\" />")
568 			.append("<project path=\"foo\" name=\"")
569 			.append(defaultUri)
570 			.append("\" revision=\"")
571 			.append(TAG)
572 			.append("\" />")
573 			.append("</manifest>");
574 		writeTrashFile("manifest.xml", xmlContent.toString());
575 		RepoCommand command = new RepoCommand(db);
576 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
577 			.setURI(rootUri)
578 			.call();
579 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
580 		BufferedReader reader = new BufferedReader(new FileReader(hello));
581 		String content = reader.readLine();
582 		reader.close();
583 		assertEquals("submodule content should be as expected",
584 				"branch world", content);
585 	}
586 
587 	@Test
588 	public void testRevisionBare() throws Exception {
589 		Repository remoteDb = createBareRepository();
590 		Repository tempDb = createWorkRepository();
591 
592 		StringBuilder xmlContent = new StringBuilder();
593 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
594 				.append("<manifest>")
595 				.append("<remote name=\"remote1\" fetch=\".\" />")
596 				.append("<default revision=\"").append(BRANCH)
597 				.append("\" remote=\"remote1\" />")
598 				.append("<project path=\"foo\" name=\"").append(defaultUri)
599 				.append("\" />").append("</manifest>");
600 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
601 				xmlContent.toString());
602 		RepoCommand command = new RepoCommand(remoteDb);
603 		command.setPath(
604 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
605 				.setURI(rootUri).call();
606 		// Clone it
607 		File directory = createTempDirectory("testRevisionBare");
608 		Repository localDb = Git.cloneRepository().setDirectory(directory)
609 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
610 				.getRepository();
611 		// The gitlink should be the same as oldCommitId
612 		String gitlink = localDb.resolve(Constants.HEAD + ":foo").name();
613 		localDb.close();
614 		assertEquals("The gitlink is same as remote head", oldCommitId.name(),
615 				gitlink);
616 	}
617 
618 	@Test
619 	public void testCopyFileBare() throws Exception {
620 		Repository remoteDb = createBareRepository();
621 		Repository tempDb = createWorkRepository();
622 
623 		StringBuilder xmlContent = new StringBuilder();
624 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
625 				.append("<manifest>")
626 				.append("<remote name=\"remote1\" fetch=\".\" />")
627 				.append("<default revision=\"master\" remote=\"remote1\" />")
628 				.append("<project path=\"foo\" name=\"").append(defaultUri)
629 				.append("\" revision=\"").append(BRANCH).append("\" >")
630 				.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
631 				.append("<copyfile src=\"hello.txt\" dest=\"foo/Hello\" />")
632 				.append("</project>").append("</manifest>");
633 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
634 				xmlContent.toString());
635 		RepoCommand command = new RepoCommand(remoteDb);
636 		command.setPath(
637 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
638 				.setURI(rootUri).call();
639 		// Clone it
640 		File directory = createTempDirectory("testCopyFileBare");
641 		Repository localDb = Git.cloneRepository().setDirectory(directory)
642 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
643 				.getRepository();
644 		// The Hello file should exist
645 		File hello = new File(localDb.getWorkTree(), "Hello");
646 		assertTrue("The Hello file should exist", hello.exists());
647 		// The foo/Hello file should be skipped.
648 		File foohello = new File(localDb.getWorkTree(), "foo/Hello");
649 		assertFalse("The foo/Hello file should be skipped", foohello.exists());
650 		localDb.close();
651 		// The content of Hello file should be expected
652 		BufferedReader reader = new BufferedReader(new FileReader(hello));
653 		String content = reader.readLine();
654 		reader.close();
655 		assertEquals("The Hello file should have expected content",
656 				"branch world", content);
657 	}
658 
659 	@Test
660 	public void testReplaceManifestBare() throws Exception {
661 		Repository remoteDb = createBareRepository();
662 		Repository tempDb = createWorkRepository();
663 
664 		StringBuilder xmlContent = new StringBuilder();
665 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
666 				.append("<manifest>")
667 				.append("<remote name=\"remote1\" fetch=\".\" />")
668 				.append("<default revision=\"master\" remote=\"remote1\" />")
669 				.append("<project path=\"foo\" name=\"").append(defaultUri)
670 				.append("\" revision=\"").append(BRANCH).append("\" >")
671 				.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
672 				.append("</project>").append("</manifest>");
673 		JGitTestUtil.writeTrashFile(tempDb, "old.xml", xmlContent.toString());
674 		RepoCommand command = new RepoCommand(remoteDb);
675 		command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/old.xml")
676 				.setURI(rootUri).call();
677 		xmlContent = new StringBuilder();
678 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
679 				.append("<manifest>")
680 				.append("<remote name=\"remote1\" fetch=\".\" />")
681 				.append("<default revision=\"master\" remote=\"remote1\" />")
682 				.append("<project path=\"bar\" name=\"").append(defaultUri)
683 				.append("\" revision=\"").append(BRANCH).append("\" >")
684 				.append("<copyfile src=\"hello.txt\" dest=\"Hello.txt\" />")
685 				.append("</project>").append("</manifest>");
686 		JGitTestUtil.writeTrashFile(tempDb, "new.xml", xmlContent.toString());
687 		command = new RepoCommand(remoteDb);
688 		command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/new.xml")
689 				.setURI(rootUri).call();
690 		// Clone it
691 		File directory = createTempDirectory("testReplaceManifestBare");
692 		Repository localDb = Git.cloneRepository().setDirectory(directory)
693 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
694 				.getRepository();
695 		// The Hello file should not exist
696 		File hello = new File(localDb.getWorkTree(), "Hello");
697 		assertFalse("The Hello file shouldn't exist", hello.exists());
698 		// The Hello.txt file should exist
699 		File hellotxt = new File(localDb.getWorkTree(), "Hello.txt");
700 		assertTrue("The Hello.txt file should exist", hellotxt.exists());
701 		// The .gitmodules file should have 'submodule "bar"' and shouldn't
702 		// have
703 		// 'submodule "foo"' lines.
704 		File dotmodules = new File(localDb.getWorkTree(),
705 				Constants.DOT_GIT_MODULES);
706 		localDb.close();
707 		BufferedReader reader = new BufferedReader(new FileReader(dotmodules));
708 		boolean foo = false;
709 		boolean bar = false;
710 		while (true) {
711 			String line = reader.readLine();
712 			if (line == null)
713 				break;
714 			if (line.contains("submodule \"foo\""))
715 				foo = true;
716 			if (line.contains("submodule \"bar\""))
717 				bar = true;
718 		}
719 		reader.close();
720 		assertTrue("The bar submodule should exist", bar);
721 		assertFalse("The foo submodule shouldn't exist", foo);
722 	}
723 
724 	@Test
725 	public void testRemoveOverlappingBare() throws Exception {
726 		Repository remoteDb = createBareRepository();
727 		Repository tempDb = createWorkRepository();
728 
729 		StringBuilder xmlContent = new StringBuilder();
730 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
731 				.append("<manifest>")
732 				.append("<remote name=\"remote1\" fetch=\".\" />")
733 				.append("<default revision=\"master\" remote=\"remote1\" />")
734 				.append("<project path=\"foo/bar\" name=\"").append(groupBUri)
735 				.append("\" />").append("<project path=\"a\" name=\"")
736 				.append(groupAUri).append("\" />")
737 				.append("<project path=\"foo\" name=\"").append(defaultUri)
738 				.append("\" />").append("</manifest>");
739 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
740 				xmlContent.toString());
741 		RepoCommand command = new RepoCommand(remoteDb);
742 		command.setPath(
743 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
744 				.setURI(rootUri).call();
745 		// Clone it
746 		File directory = createTempDirectory("testRemoveOverlappingBare");
747 		Repository localDb = Git.cloneRepository().setDirectory(directory)
748 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
749 				.getRepository();
750 		// The .gitmodules file should have 'submodule "foo"' and shouldn't
751 		// have
752 		// 'submodule "foo/bar"' lines.
753 		File dotmodules = new File(localDb.getWorkTree(),
754 				Constants.DOT_GIT_MODULES);
755 		localDb.close();
756 		BufferedReader reader = new BufferedReader(new FileReader(dotmodules));
757 		boolean foo = false;
758 		boolean foobar = false;
759 		boolean a = false;
760 		while (true) {
761 			String line = reader.readLine();
762 			if (line == null)
763 				break;
764 			if (line.contains("submodule \"foo\""))
765 				foo = true;
766 			if (line.contains("submodule \"foo/bar\""))
767 				foobar = true;
768 			if (line.contains("submodule \"a\""))
769 				a = true;
770 		}
771 		reader.close();
772 		assertTrue("The foo submodule should exist", foo);
773 		assertFalse("The foo/bar submodule shouldn't exist", foobar);
774 		assertTrue("The a submodule should exist", a);
775 	}
776 
777 	@Test
778 	public void testIncludeTag() throws Exception {
779 		Repository localDb = createWorkRepository();
780 		Repository tempDb = createWorkRepository();
781 
782 		StringBuilder xmlContent = new StringBuilder();
783 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
784 			.append("<manifest>")
785 			.append("<include name=\"_include.xml\" />")
786 			.append("<default revision=\"master\" remote=\"remote1\" />")
787 			.append("</manifest>");
788 		JGitTestUtil.writeTrashFile(
789 				tempDb, "manifest.xml", xmlContent.toString());
790 
791 		xmlContent = new StringBuilder();
792 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
793 			.append("<manifest>")
794 			.append("<remote name=\"remote1\" fetch=\".\" />")
795 			.append("<default revision=\"master\" remote=\"remote1\" />")
796 			.append("<project path=\"foo\" name=\"")
797 			.append(defaultUri)
798 			.append("\" />")
799 			.append("</manifest>");
800 		JGitTestUtil.writeTrashFile(
801 				tempDb, "_include.xml", xmlContent.toString());
802 
803 		RepoCommand command = new RepoCommand(localDb);
804 		command
805 			.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
806 			.setURI(rootUri)
807 			.call();
808 		File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
809 		assertTrue("submodule should be checked out", hello.exists());
810 		BufferedReader reader = new BufferedReader(new FileReader(hello));
811 		String content = reader.readLine();
812 		reader.close();
813 		assertEquals("submodule content should be as expected",
814 				"master world", content);
815 	}
816 
817 	@Test
818 	public void testNonDefaultRemotes() throws Exception {
819 		StringBuilder xmlContent = new StringBuilder();
820 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
821 			.append("<manifest>")
822 			.append("<remote name=\"remote1\" fetch=\".\" />")
823 			.append("<remote name=\"remote2\" fetch=\"")
824 			.append(notDefaultUri)
825 			.append("\" />")
826 			.append("<default revision=\"master\" remote=\"remote1\" />")
827 			.append("<project path=\"foo\" name=\"")
828 			.append(defaultUri)
829 			.append("\" />")
830 			.append("<project path=\"bar\" name=\".\" remote=\"remote2\" />")
831 			.append("</manifest>");
832 
833 		Repository localDb = createWorkRepository();
834 		JGitTestUtil.writeTrashFile(
835 				localDb, "manifest.xml", xmlContent.toString());
836 		RepoCommand command = new RepoCommand(localDb);
837 		command
838 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
839 			.setURI(rootUri)
840 			.call();
841 		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
842 		assertTrue("We should have foo", file.exists());
843 		file = new File(localDb.getWorkTree(), "bar/world.txt");
844 		assertTrue("We should have bar", file.exists());
845 	}
846 
847 	@Test
848 	public void testRemoteAlias() throws Exception {
849 		StringBuilder xmlContent = new StringBuilder();
850 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
851 			.append("<manifest>")
852 			.append("<remote name=\"remote1\" fetch=\".\" alias=\"remote2\" />")
853 			.append("<default revision=\"master\" remote=\"remote2\" />")
854 			.append("<project path=\"foo\" name=\"")
855 			.append(defaultUri)
856 			.append("\" />")
857 			.append("</manifest>");
858 
859 		Repository localDb = createWorkRepository();
860 		JGitTestUtil.writeTrashFile(
861 				localDb, "manifest.xml", xmlContent.toString());
862 		RepoCommand command = new RepoCommand(localDb);
863 		command
864 			.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
865 			.setURI(rootUri)
866 			.call();
867 		File file = new File(localDb.getWorkTree(), "foo/hello.txt");
868 		assertTrue("We should have foo", file.exists());
869 	}
870 
871 	@Test
872 	public void testTargetBranch() throws Exception {
873 		Repository remoteDb1 = createBareRepository();
874 		Repository remoteDb2 = createBareRepository();
875 		Repository tempDb = createWorkRepository();
876 
877 		StringBuilder xmlContent = new StringBuilder();
878 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
879 				.append("<manifest>")
880 				.append("<remote name=\"remote1\" fetch=\".\" />")
881 				.append("<default revision=\"master\" remote=\"remote1\" />")
882 				.append("<project path=\"foo\" name=\"").append(defaultUri)
883 				.append("\" />").append("</manifest>");
884 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
885 				xmlContent.toString());
886 		RepoCommand command = new RepoCommand(remoteDb1);
887 		command.setPath(
888 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
889 				.setURI(rootUri).setTargetBranch("test").call();
890 		ObjectId branchId = remoteDb1
891 				.resolve(Constants.R_HEADS + "test^{tree}");
892 		command = new RepoCommand(remoteDb2);
893 		command.setPath(
894 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
895 				.setURI(rootUri).call();
896 		ObjectId defaultId = remoteDb2.resolve(Constants.HEAD + "^{tree}");
897 		assertEquals(
898 				"The tree id of branch db and default db should be the same",
899 				branchId, defaultId);
900 	}
901 
902 	@Test
903 	public void testRecordRemoteBranch() throws Exception {
904 		Repository remoteDb = createBareRepository();
905 		Repository tempDb = createWorkRepository();
906 
907 		StringBuilder xmlContent = new StringBuilder();
908 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
909 				.append("<manifest>")
910 				.append("<remote name=\"remote1\" fetch=\".\" />")
911 				.append("<default revision=\"master\" remote=\"remote1\" />")
912 				.append("<project path=\"with-branch\" ")
913 				.append("revision=\"master\" ").append("name=\"")
914 				.append(notDefaultUri).append("\" />")
915 				.append("<project path=\"with-long-branch\" ")
916 				.append("revision=\"refs/heads/master\" ").append("name=\"")
917 				.append(defaultUri).append("\" />").append("</manifest>");
918 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
919 				xmlContent.toString());
920 
921 		RepoCommand command = new RepoCommand(remoteDb);
922 		command.setPath(
923 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
924 				.setURI(rootUri).setRecordRemoteBranch(true).call();
925 		// Clone it
926 		File directory = createTempDirectory("testBareRepo");
927 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
928 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
929 				.getRepository();) {
930 			// The .gitmodules file should exist
931 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
932 			assertTrue("The .gitmodules file should exist",
933 					gitmodules.exists());
934 			FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
935 			c.load();
936 			assertEquals(
937 					"Recording remote branches should work for short branch descriptions",
938 					"master",
939 					c.getString("submodule", "with-branch", "branch"));
940 			assertEquals(
941 					"Recording remote branches should work for full ref specs",
942 					"refs/heads/master",
943 					c.getString("submodule", "with-long-branch", "branch"));
944 		}
945 	}
946 
947 
948 	@Test
949 	public void testRecordSubmoduleLabels() throws Exception {
950 		Repository remoteDb = createBareRepository();
951 		Repository tempDb = createWorkRepository();
952 
953 		StringBuilder xmlContent = new StringBuilder();
954 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
955 				.append("<manifest>")
956 				.append("<remote name=\"remote1\" fetch=\".\" />")
957 				.append("<default revision=\"master\" remote=\"remote1\" />")
958 				.append("<project path=\"test\" ")
959 				.append("revision=\"master\" ").append("name=\"")
960 				.append(notDefaultUri).append("\" ")
961 				.append("groups=\"a1,a2\" />").append("</manifest>");
962 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
963 				xmlContent.toString());
964 
965 		RepoCommand command = new RepoCommand(remoteDb);
966 		command.setPath(
967 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
968 				.setURI(rootUri).setRecordSubmoduleLabels(true).call();
969 		// Clone it
970 		File directory = createTempDirectory("testBareRepo");
971 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
972 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
973 				.getRepository();) {
974 			// The .gitattributes file should exist
975 			File gitattributes = new File(localDb.getWorkTree(),
976 					".gitattributes");
977 			assertTrue("The .gitattributes file should exist",
978 					gitattributes.exists());
979 			try (BufferedReader reader = new BufferedReader(
980 					new FileReader(gitattributes));) {
981 				String content = reader.readLine();
982 				assertEquals(".gitattributes content should be as expected",
983 						"/test a1 a2", content);
984 			}
985 		}
986 	}
987 
988 	@Test
989 	public void testRecordShallowRecommendation() throws Exception {
990 		Repository remoteDb = createBareRepository();
991 		Repository tempDb = createWorkRepository();
992 
993 		StringBuilder xmlContent = new StringBuilder();
994 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
995 				.append("<manifest>")
996 				.append("<remote name=\"remote1\" fetch=\".\" />")
997 				.append("<default revision=\"master\" remote=\"remote1\" />")
998 				.append("<project path=\"shallow-please\" ").append("name=\"")
999 				.append(defaultUri).append("\" ").append("clone-depth=\"1\" />")
1000 				.append("<project path=\"non-shallow\" ").append("name=\"")
1001 				.append(defaultUri).append("\" />").append("</manifest>");
1002 		JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
1003 				xmlContent.toString());
1004 
1005 		RepoCommand command = new RepoCommand(remoteDb);
1006 		command.setPath(
1007 				tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
1008 				.setURI(rootUri).setRecommendShallow(true).call();
1009 		// Clone it
1010 		File directory = createTempDirectory("testBareRepo");
1011 		try (Repository localDb = Git.cloneRepository().setDirectory(directory)
1012 				.setURI(remoteDb.getDirectory().toURI().toString()).call()
1013 				.getRepository();) {
1014 			// The .gitmodules file should exist
1015 			File gitmodules = new File(localDb.getWorkTree(), ".gitmodules");
1016 			assertTrue("The .gitmodules file should exist",
1017 					gitmodules.exists());
1018 			FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED);
1019 			c.load();
1020 			assertEquals("Recording shallow configuration should work", "true",
1021 					c.getString("submodule", "shallow-please", "shallow"));
1022 			assertNull("Recording non shallow configuration should work",
1023 					c.getString("submodule", "non-shallow", "shallow"));
1024 		}
1025 	}
1026 
1027 	@Test
1028 	public void testRemoteRevision() throws Exception {
1029 		StringBuilder xmlContent = new StringBuilder();
1030 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1031 			.append("<manifest>")
1032 			.append("<remote name=\"remote1\" fetch=\".\" />")
1033 			.append("<remote name=\"remote2\" fetch=\".\" revision=\"")
1034 			.append(BRANCH)
1035 			.append("\" />")
1036 			.append("<default remote=\"remote1\" revision=\"master\" />")
1037 			.append("<project path=\"foo\" remote=\"remote2\" name=\"")
1038 			.append(defaultUri)
1039 			.append("\" />")
1040 			.append("</manifest>");
1041 		writeTrashFile("manifest.xml", xmlContent.toString());
1042 		RepoCommand command = new RepoCommand(db);
1043 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
1044 			.setURI(rootUri)
1045 			.call();
1046 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
1047 		BufferedReader reader = new BufferedReader(new FileReader(hello));
1048 		String content = reader.readLine();
1049 		reader.close();
1050 		assertEquals("submodule content should be as expected",
1051 				"branch world", content);
1052 	}
1053 
1054 	@Test
1055 	public void testDefaultRemoteRevision() throws Exception {
1056 		StringBuilder xmlContent = new StringBuilder();
1057 		xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
1058 			.append("<manifest>")
1059 			.append("<remote name=\"remote1\" fetch=\".\" revision=\"")
1060 			.append(BRANCH)
1061 			.append("\" />")
1062 			.append("<default remote=\"remote1\" />")
1063 			.append("<project path=\"foo\" name=\"")
1064 			.append(defaultUri)
1065 			.append("\" />")
1066 			.append("</manifest>");
1067 		writeTrashFile("manifest.xml", xmlContent.toString());
1068 		RepoCommand command = new RepoCommand(db);
1069 		command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
1070 			.setURI(rootUri)
1071 			.call();
1072 		File hello = new File(db.getWorkTree(), "foo/hello.txt");
1073 		BufferedReader reader = new BufferedReader(new FileReader(hello));
1074 		String content = reader.readLine();
1075 		reader.close();
1076 		assertEquals("submodule content should be as expected",
1077 				"branch world", content);
1078 	}
1079 
1080 	private void resolveRelativeUris() {
1081 		// Find the longest common prefix ends with "/" as rootUri.
1082 		defaultUri = defaultDb.getDirectory().toURI().toString();
1083 		notDefaultUri = notDefaultDb.getDirectory().toURI().toString();
1084 		groupAUri = groupADb.getDirectory().toURI().toString();
1085 		groupBUri = groupBDb.getDirectory().toURI().toString();
1086 		int start = 0;
1087 		while (start <= defaultUri.length()) {
1088 			int newStart = defaultUri.indexOf('/', start + 1);
1089 			String prefix = defaultUri.substring(0, newStart);
1090 			if (!notDefaultUri.startsWith(prefix) ||
1091 					!groupAUri.startsWith(prefix) ||
1092 					!groupBUri.startsWith(prefix)) {
1093 				start++;
1094 				rootUri = defaultUri.substring(0, start) + "manifest";
1095 				defaultUri = defaultUri.substring(start);
1096 				notDefaultUri = notDefaultUri.substring(start);
1097 				groupAUri = groupAUri.substring(start);
1098 				groupBUri = groupBUri.substring(start);
1099 				return;
1100 			}
1101 			start = newStart;
1102 		}
1103 	}
1104 
1105 	void testRelative(String a, String b, String want) {
1106 		String got = RepoCommand.relativize(URI.create(a), URI.create(b)).toString();
1107 
1108 		if (!got.equals(want)) {
1109 			fail(String.format("relative('%s', '%s') = '%s', want '%s'", a, b, got, want));
1110 		}
1111 	}
1112 
1113 	@Test
1114 	public void relative() {
1115 		testRelative("a/b/", "a/", "../");
1116 		// Normalization:
1117 		testRelative("a/p/..//b/", "a/", "../");
1118 		testRelative("a/b", "a/", "");
1119 		testRelative("a/", "a/b/", "b/");
1120 		testRelative("a/", "a/b", "b");
1121 		testRelative("/a/b/c", "/b/c", "../../b/c");
1122 		testRelative("/abc", "bcd", "bcd");
1123 		testRelative("abc", "def", "def");
1124 		testRelative("abc", "/bcd", "/bcd");
1125 		testRelative("http://a", "a/b", "a/b");
1126 		testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
1127 	}
1128 }