Added groups support to repo subcommand.

Change-Id: Id0e7663b6ac4f6938fdcacaf2158107b6285fc25
Signed-off-by: Yuxuan 'fishy' Wang <fishywang@google.com>
This commit is contained in:
Yuxuan 'fishy' Wang 2014-03-24 12:40:04 -07:00
parent 1f3b75c9ee
commit a44a687fed
5 changed files with 279 additions and 33 deletions

View File

@ -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.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 void testAddRepoManifest() throws Exception {
.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;
}
}
}

View File

@ -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

View File

@ -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 @@ protected void run() throws Exception {
new RepoCommand(db)
.setURI(uri)
.setPath(path)
.setGroups(groups)
.call();
}
}

View File

@ -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 @@
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 void testAddRepoManifest() throws Exception {
.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 void testAddRepoManifest() throws Exception {
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;
}
}
}

View File

@ -48,9 +48,12 @@
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 @@
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 @@ private static class XmlManifest extends DefaultHandler {
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 void startElement(
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,10 +188,30 @@ public void endDocument() throws SAXException {
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;
}
}
private static class ManifestErrorException extends GitAPIException {
@ -204,6 +250,17 @@ public RepoCommand setURI(final String uri) {
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 Void call() throws GitAPIException {
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 Void call() throws GitAPIException {
}
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);
}