Change-Id: Id0e7663b6ac4f6938fdcacaf2158107b6285fc25 Signed-off-by: Yuxuan 'fishy' Wang <fishywang@google.com>tags/v3.4.0.201405051725-m7
@@ -43,6 +43,7 @@ | |||
package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.BufferedReader; | |||
@@ -57,17 +58,47 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
public class RepoTest extends CLIRepositoryTestCase { | |||
private Repository remoteDb; | |||
private Repository defaultDb; | |||
private Repository notDefaultDb; | |||
private Repository groupADb; | |||
private Repository groupBDb; | |||
private String rootUri; | |||
private String defaultUri; | |||
private String notDefaultUri; | |||
private String groupAUri; | |||
private String groupBUri; | |||
@Override | |||
@Before | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
remoteDb = createWorkRepository(); | |||
Git git = new Git(remoteDb); | |||
JGitTestUtil.writeTrashFile(remoteDb, "hello.txt", "world"); | |||
defaultDb = createWorkRepository(); | |||
Git git = new Git(defaultDb); | |||
JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world"); | |||
git.add().addFilepattern("hello.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
notDefaultDb = createWorkRepository(); | |||
git = new Git(notDefaultDb); | |||
JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello"); | |||
git.add().addFilepattern("world.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
groupADb = createWorkRepository(); | |||
git = new Git(groupADb); | |||
JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world"); | |||
git.add().addFilepattern("a.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
groupBDb = createWorkRepository(); | |||
git = new Git(groupBDb); | |||
JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world"); | |||
git.add().addFilepattern("b.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
resolveRelativeUris(); | |||
} | |||
@Test | |||
@@ -77,20 +108,59 @@ public class RepoTest extends CLIRepositoryTestCase { | |||
.append("<manifest>") | |||
.append("<remote name=\"remote1\" fetch=\".\" />") | |||
.append("<default revision=\"master\" remote=\"remote1\" />") | |||
.append("<project path=\"foo\" name=\".\" />") | |||
.append("<project path=\"foo\" name=\"") | |||
.append(defaultUri) | |||
.append("\" groups=\"a,test\" />") | |||
.append("<project path=\"bar\" name=\"") | |||
.append(notDefaultUri) | |||
.append("\" groups=\"notdefault\" />") | |||
.append("<project path=\"a\" name=\"") | |||
.append(groupAUri) | |||
.append("\" groups=\"a\" />") | |||
.append("<project path=\"b\" name=\"") | |||
.append(groupBUri) | |||
.append("\" groups=\"b\" />") | |||
.append("</manifest>"); | |||
writeTrashFile("manifest.xml", xmlContent.toString()); | |||
StringBuilder cmd = new StringBuilder("git repo --base-uri=\"") | |||
.append(remoteDb.getDirectory().toURI().toString()) | |||
.append("\" \"") | |||
.append(rootUri) | |||
.append("\" --groups=\"all,-a\" \"") | |||
.append(db.getWorkTree().getAbsolutePath()) | |||
.append("/manifest.xml\""); | |||
execute(cmd.toString()); | |||
File hello = new File(db.getWorkTree(), "foo/hello.txt"); | |||
assertTrue("submodule was checked out.", hello.exists()); | |||
BufferedReader reader = new BufferedReader(new FileReader(hello)); | |||
String content = reader.readLine(); | |||
reader.close(); | |||
assertEquals("submodule content is as expected.", "world", content); | |||
File file = new File(db.getWorkTree(), "foo/hello.txt"); | |||
assertFalse("\"all,-a\" doesn't have foo", file.exists()); | |||
file = new File(db.getWorkTree(), "bar/world.txt"); | |||
assertTrue("\"all,-a\" has bar", file.exists()); | |||
file = new File(db.getWorkTree(), "a/a.txt"); | |||
assertFalse("\"all,-a\" doesn't have a", file.exists()); | |||
file = new File(db.getWorkTree(), "b/b.txt"); | |||
assertTrue("\"all,-a\" has have b", file.exists()); | |||
} | |||
private void resolveRelativeUris() { | |||
// Find the longest common prefix ends with "/" as rootUri. | |||
defaultUri = defaultDb.getDirectory().toURI().toString(); | |||
notDefaultUri = notDefaultDb.getDirectory().toURI().toString(); | |||
groupAUri = groupADb.getDirectory().toURI().toString(); | |||
groupBUri = groupBDb.getDirectory().toURI().toString(); | |||
int start = 0; | |||
while (start <= defaultUri.length()) { | |||
int newStart = defaultUri.indexOf('/', start + 1); | |||
String prefix = defaultUri.substring(0, newStart); | |||
if (!notDefaultUri.startsWith(prefix) || | |||
!groupAUri.startsWith(prefix) || | |||
!groupBUri.startsWith(prefix)) { | |||
start++; | |||
rootUri = defaultUri.substring(0, start); | |||
defaultUri = defaultUri.substring(start); | |||
notDefaultUri = notDefaultUri.substring(start); | |||
groupAUri = groupAUri.substring(start); | |||
groupBUri = groupBUri.substring(start); | |||
return; | |||
} | |||
start = newStart; | |||
} | |||
} | |||
} |
@@ -278,6 +278,7 @@ usage_forceCheckout=when switching branches, proceed even if the index or the wo | |||
usage_forceCreateBranchEvenExists=force create branch even exists | |||
usage_forceReplacingAnExistingTag=force replacing an existing tag | |||
usage_getAndSetOptions=Get and set repository or global options | |||
usage_groups=Restrict manifest projects to ones with specified group(s), use "-" for excluding [default|all|G1,G2,G3|G4,-G5,-G6] | |||
usage_hostnameOrIpToListenOn=hostname (or ip) to listen on | |||
usage_indexFileFormatToCreate=index file format to create | |||
usage_ignoreWhitespace=ignore all whitespace |
@@ -52,6 +52,9 @@ class Repo extends TextBuiltin { | |||
@Option(name = "--base-uri", aliases = { "-u" }, usage = "usage_baseUri") | |||
private String uri; | |||
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups") | |||
private String groups = "default"; //$NON-NLS-1$ | |||
@Argument(required = true, usage = "usage_pathToXml") | |||
private String path; | |||
@@ -60,6 +63,7 @@ class Repo extends TextBuiltin { | |||
new RepoCommand(db) | |||
.setURI(uri) | |||
.setPath(path) | |||
.setGroups(groups) | |||
.call(); | |||
} | |||
} |
@@ -43,6 +43,7 @@ | |||
package org.eclipse.jgit.gitrepo; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.BufferedReader; | |||
@@ -57,16 +58,45 @@ import org.junit.Test; | |||
public class RepoCommandTest extends RepositoryTestCase { | |||
private Repository remoteDb; | |||
private Repository defaultDb; | |||
private Repository notDefaultDb; | |||
private Repository groupADb; | |||
private Repository groupBDb; | |||
private String rootUri; | |||
private String defaultUri; | |||
private String notDefaultUri; | |||
private String groupAUri; | |||
private String groupBUri; | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
remoteDb = createWorkRepository(); | |||
Git git = new Git(remoteDb); | |||
JGitTestUtil.writeTrashFile(remoteDb, "hello.txt", "world"); | |||
defaultDb = createWorkRepository(); | |||
Git git = new Git(defaultDb); | |||
JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world"); | |||
git.add().addFilepattern("hello.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
notDefaultDb = createWorkRepository(); | |||
git = new Git(notDefaultDb); | |||
JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello"); | |||
git.add().addFilepattern("world.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
groupADb = createWorkRepository(); | |||
git = new Git(groupADb); | |||
JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world"); | |||
git.add().addFilepattern("a.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
groupBDb = createWorkRepository(); | |||
git = new Git(groupBDb); | |||
JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world"); | |||
git.add().addFilepattern("b.txt").call(); | |||
git.commit().setMessage("Initial commit").call(); | |||
resolveRelativeUris(); | |||
} | |||
@Test | |||
@@ -76,12 +106,14 @@ public class RepoCommandTest extends RepositoryTestCase { | |||
.append("<manifest>") | |||
.append("<remote name=\"remote1\" fetch=\".\" />") | |||
.append("<default revision=\"master\" remote=\"remote1\" />") | |||
.append("<project path=\"foo\" name=\".\" />") | |||
.append("<project path=\"foo\" name=\"") | |||
.append(defaultUri) | |||
.append("\" />") | |||
.append("</manifest>"); | |||
writeTrashFile("manifest.xml", xmlContent.toString()); | |||
RepoCommand command = new RepoCommand(db); | |||
command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml") | |||
.setURI(remoteDb.getDirectory().toURI().toString()) | |||
.setURI(rootUri) | |||
.call(); | |||
File hello = new File(db.getWorkTree(), "foo/hello.txt"); | |||
assertTrue("submodule was checked out", hello.exists()); | |||
@@ -90,4 +122,84 @@ public class RepoCommandTest extends RepositoryTestCase { | |||
reader.close(); | |||
assertEquals("submodule content is as expected.", "world", content); | |||
} | |||
@Test | |||
public void testRepoManifestGroups() throws Exception { | |||
StringBuilder xmlContent = new StringBuilder(); | |||
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") | |||
.append("<manifest>") | |||
.append("<remote name=\"remote1\" fetch=\".\" />") | |||
.append("<default revision=\"master\" remote=\"remote1\" />") | |||
.append("<project path=\"foo\" name=\"") | |||
.append(defaultUri) | |||
.append("\" groups=\"a,test\" />") | |||
.append("<project path=\"bar\" name=\"") | |||
.append(notDefaultUri) | |||
.append("\" groups=\"notdefault\" />") | |||
.append("<project path=\"a\" name=\"") | |||
.append(groupAUri) | |||
.append("\" groups=\"a\" />") | |||
.append("<project path=\"b\" name=\"") | |||
.append(groupBUri) | |||
.append("\" groups=\"b\" />") | |||
.append("</manifest>"); | |||
// default should have foo, a & b | |||
Repository localDb = createWorkRepository(); | |||
JGitTestUtil.writeTrashFile(localDb, "manifest.xml", xmlContent.toString()); | |||
RepoCommand command = new RepoCommand(localDb); | |||
command.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml") | |||
.setURI(rootUri) | |||
.call(); | |||
File file = new File(localDb.getWorkTree(), "foo/hello.txt"); | |||
assertTrue("default has foo", file.exists()); | |||
file = new File(localDb.getWorkTree(), "bar/world.txt"); | |||
assertFalse("default doesn't have bar", file.exists()); | |||
file = new File(localDb.getWorkTree(), "a/a.txt"); | |||
assertTrue("default has a", file.exists()); | |||
file = new File(localDb.getWorkTree(), "b/b.txt"); | |||
assertTrue("default has b", file.exists()); | |||
// all,-a should have bar & b | |||
localDb = createWorkRepository(); | |||
JGitTestUtil.writeTrashFile(localDb, "manifest.xml", xmlContent.toString()); | |||
command = new RepoCommand(localDb); | |||
command.setPath(localDb.getWorkTree().getAbsolutePath() + "/manifest.xml") | |||
.setURI(rootUri) | |||
.setGroups("all,-a") | |||
.call(); | |||
file = new File(localDb.getWorkTree(), "foo/hello.txt"); | |||
assertFalse("\"all,-a\" doesn't have foo", file.exists()); | |||
file = new File(localDb.getWorkTree(), "bar/world.txt"); | |||
assertTrue("\"all,-a\" has bar", file.exists()); | |||
file = new File(localDb.getWorkTree(), "a/a.txt"); | |||
assertFalse("\"all,-a\" doesn't have a", file.exists()); | |||
file = new File(localDb.getWorkTree(), "b/b.txt"); | |||
assertTrue("\"all,-a\" has have b", file.exists()); | |||
} | |||
private void resolveRelativeUris() { | |||
// Find the longest common prefix ends with "/" as rootUri. | |||
defaultUri = defaultDb.getDirectory().toURI().toString(); | |||
notDefaultUri = notDefaultDb.getDirectory().toURI().toString(); | |||
groupAUri = groupADb.getDirectory().toURI().toString(); | |||
groupBUri = groupBDb.getDirectory().toURI().toString(); | |||
int start = 0; | |||
while (start <= defaultUri.length()) { | |||
int newStart = defaultUri.indexOf('/', start + 1); | |||
String prefix = defaultUri.substring(0, newStart); | |||
if (!notDefaultUri.startsWith(prefix) || | |||
!groupAUri.startsWith(prefix) || | |||
!groupBUri.startsWith(prefix)) { | |||
start++; | |||
rootUri = defaultUri.substring(0, start); | |||
defaultUri = defaultUri.substring(start); | |||
notDefaultUri = notDefaultUri.substring(start); | |||
groupAUri = groupAUri.substring(start); | |||
groupBUri = groupBUri.substring(start); | |||
return; | |||
} | |||
start = newStart; | |||
} | |||
} | |||
} |
@@ -48,9 +48,12 @@ import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.eclipse.jgit.api.GitCommand; | |||
import org.eclipse.jgit.api.SubmoduleAddCommand; | |||
@@ -79,18 +82,22 @@ import org.xml.sax.helpers.XMLReaderFactory; | |||
public class RepoCommand extends GitCommand<Void> { | |||
private String path; | |||
private String uri; | |||
private String groups; | |||
private ProgressMonitor monitor; | |||
private static class Project { | |||
final String name; | |||
final String path; | |||
final Set<String> groups; | |||
Project(String name, String path) { | |||
Project(String name, String path, String groups) { | |||
this.name = name; | |||
this.path = path; | |||
this.groups = new HashSet<String>(); | |||
if (groups != null && groups.length() > 0) | |||
this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$ | |||
} | |||
} | |||
@@ -100,14 +107,29 @@ public class RepoCommand extends GitCommand<Void> { | |||
private final String baseUrl; | |||
private final Map<String, String> remotes; | |||
private final List<Project> projects; | |||
private final Set<String> plusGroups; | |||
private final Set<String> minusGroups; | |||
private String defaultRemote; | |||
XmlManifest(RepoCommand command, String filename, String baseUrl) { | |||
XmlManifest(RepoCommand command, String filename, String baseUrl, String groups) { | |||
this.command = command; | |||
this.filename = filename; | |||
this.baseUrl = baseUrl; | |||
remotes = new HashMap<String, String>(); | |||
projects = new ArrayList<Project>(); | |||
plusGroups = new HashSet<String>(); | |||
minusGroups = new HashSet<String>(); | |||
if (groups == null || groups.length() == 0 || groups.equals("default")) { //$NON-NLS-1$ | |||
// default means "all,-notdefault" | |||
minusGroups.add("notdefault"); //$NON-NLS-1$ | |||
} else { | |||
for (String group : groups.split(",")) { //$NON-NLS-1$ | |||
if (group.startsWith("-")) //$NON-NLS-1$ | |||
minusGroups.add(group.substring(1)); | |||
else | |||
plusGroups.add(group); | |||
} | |||
} | |||
} | |||
void read() throws IOException { | |||
@@ -137,13 +159,17 @@ public class RepoCommand extends GitCommand<Void> { | |||
String localName, | |||
String qName, | |||
Attributes attributes) throws SAXException { | |||
if ("project".equals(qName)) //$NON-NLS-1$ | |||
projects.add(new Project(attributes.getValue("name"), attributes.getValue("path"))); //$NON-NLS-1$ //$NON-NLS-2$ | |||
else if ("remote".equals(qName)) //$NON-NLS-1$ | |||
remotes.put(attributes.getValue("name"), attributes.getValue("fetch")); //$NON-NLS-1$ //$NON-NLS-2$ | |||
else if ("default".equals(qName)) //$NON-NLS-1$ | |||
if ("project".equals(qName)) { //$NON-NLS-1$ | |||
projects.add(new Project( //$NON-NLS-1$ | |||
attributes.getValue("name"), //$NON-NLS-1$ | |||
attributes.getValue("path"), //$NON-NLS-1$ | |||
attributes.getValue("groups"))); //$NON-NLS-1$ | |||
} else if ("remote".equals(qName)) { //$NON-NLS-1$ | |||
remotes.put(attributes.getValue("name"), //$NON-NLS-1$ | |||
attributes.getValue("fetch")); //$NON-NLS-1$ | |||
} else if ("default".equals(qName)) { //$NON-NLS-1$ | |||
defaultRemote = attributes.getValue("remote"); //$NON-NLS-1$ | |||
else if ("copyfile".equals(qName)) { //$NON-NLS-1$ | |||
} else if ("copyfile".equals(qName)) { //$NON-NLS-1$ | |||
// TODO(fishywang): Handle copyfile. Do nothing for now. | |||
} | |||
} | |||
@@ -162,9 +188,29 @@ public class RepoCommand extends GitCommand<Void> { | |||
throw new SAXException(e); | |||
} | |||
for (Project proj : projects) { | |||
String url = remoteUrl + proj.name; | |||
command.addSubmodule(url, proj.path); | |||
if (inGroups(proj)) { | |||
String url = remoteUrl + proj.name; | |||
command.addSubmodule(url, proj.path); | |||
} | |||
} | |||
} | |||
boolean inGroups(Project proj) { | |||
for (String group : minusGroups) { | |||
if (proj.groups.contains(group)) { | |||
// minus groups have highest priority. | |||
return false; | |||
} | |||
} | |||
if (plusGroups.isEmpty() || plusGroups.contains("all")) { //$NON-NLS-1$ | |||
// empty plus groups means "all" | |||
return true; | |||
} | |||
for (String group : plusGroups) { | |||
if (proj.groups.contains(group)) | |||
return true; | |||
} | |||
return false; | |||
} | |||
} | |||
@@ -204,6 +250,17 @@ public class RepoCommand extends GitCommand<Void> { | |||
return this; | |||
} | |||
/** | |||
* Set groups to sync | |||
* | |||
* @param groups groups separated by comma, examples: default|all|G1,-G2,-G3 | |||
* @return this command | |||
*/ | |||
public RepoCommand setGroups(final String groups) { | |||
this.groups = groups; | |||
return this; | |||
} | |||
/** | |||
* The progress monitor associated with the clone operation. By default, | |||
* this is set to <code>NullProgressMonitor</code> | |||
@@ -225,7 +282,7 @@ public class RepoCommand extends GitCommand<Void> { | |||
if (uri == null || uri.length() == 0) | |||
throw new IllegalArgumentException(JGitText.get().uriNotConfigured); | |||
XmlManifest manifest = new XmlManifest(this, path, uri); | |||
XmlManifest manifest = new XmlManifest(this, path, uri, groups); | |||
try { | |||
manifest.read(); | |||
} catch (IOException e) { | |||
@@ -236,11 +293,13 @@ public class RepoCommand extends GitCommand<Void> { | |||
} | |||
private void addSubmodule(String url, String name) throws SAXException { | |||
SubmoduleAddCommand add = new SubmoduleAddCommand(repo); | |||
SubmoduleAddCommand add = new SubmoduleAddCommand(repo) | |||
.setPath(name) | |||
.setURI(url); | |||
if (monitor != null) | |||
add.setProgressMonitor(monitor); | |||
try { | |||
add.setPath(name).setURI(url).call(); | |||
add.call(); | |||
} catch (GitAPIException e) { | |||
throw new SAXException(e); | |||
} |