Browse Source

Added groups support to repo subcommand.

Change-Id: Id0e7663b6ac4f6938fdcacaf2158107b6285fc25
Signed-off-by: Yuxuan 'fishy' Wang <fishywang@google.com>
stable-3.4
Yuxuan 'fishy' Wang 11 years ago
parent
commit
a44a687fed
  1. 96
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java
  2. 1
      org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
  3. 4
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
  4. 124
      org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
  5. 83
      org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java

96
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java

@ -43,6 +43,7 @@
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -57,17 +58,47 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class RepoTest extends CLIRepositoryTestCase { 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 @Override
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
remoteDb = createWorkRepository();
Git git = new Git(remoteDb); defaultDb = createWorkRepository();
JGitTestUtil.writeTrashFile(remoteDb, "hello.txt", "world"); Git git = new Git(defaultDb);
JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world");
git.add().addFilepattern("hello.txt").call(); git.add().addFilepattern("hello.txt").call();
git.commit().setMessage("Initial commit").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 @Test
@ -77,20 +108,59 @@ public class RepoTest extends CLIRepositoryTestCase {
.append("<manifest>") .append("<manifest>")
.append("<remote name=\"remote1\" fetch=\".\" />") .append("<remote name=\"remote1\" fetch=\".\" />")
.append("<default revision=\"master\" remote=\"remote1\" />") .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>"); .append("</manifest>");
writeTrashFile("manifest.xml", xmlContent.toString()); writeTrashFile("manifest.xml", xmlContent.toString());
StringBuilder cmd = new StringBuilder("git repo --base-uri=\"") StringBuilder cmd = new StringBuilder("git repo --base-uri=\"")
.append(remoteDb.getDirectory().toURI().toString()) .append(rootUri)
.append("\" \"") .append("\" --groups=\"all,-a\" \"")
.append(db.getWorkTree().getAbsolutePath()) .append(db.getWorkTree().getAbsolutePath())
.append("/manifest.xml\""); .append("/manifest.xml\"");
execute(cmd.toString()); execute(cmd.toString());
File hello = new File(db.getWorkTree(), "foo/hello.txt");
assertTrue("submodule was checked out.", hello.exists()); File file = new File(db.getWorkTree(), "foo/hello.txt");
BufferedReader reader = new BufferedReader(new FileReader(hello)); assertFalse("\"all,-a\" doesn't have foo", file.exists());
String content = reader.readLine(); file = new File(db.getWorkTree(), "bar/world.txt");
reader.close(); assertTrue("\"all,-a\" has bar", file.exists());
assertEquals("submodule content is as expected.", "world", content); 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;
}
} }
} }

1
org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties

@ -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_forceCreateBranchEvenExists=force create branch even exists
usage_forceReplacingAnExistingTag=force replacing an existing tag usage_forceReplacingAnExistingTag=force replacing an existing tag
usage_getAndSetOptions=Get and set repository or global options 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_hostnameOrIpToListenOn=hostname (or ip) to listen on
usage_indexFileFormatToCreate=index file format to create usage_indexFileFormatToCreate=index file format to create
usage_ignoreWhitespace=ignore all whitespace usage_ignoreWhitespace=ignore all whitespace

4
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java

@ -52,6 +52,9 @@ class Repo extends TextBuiltin {
@Option(name = "--base-uri", aliases = { "-u" }, usage = "usage_baseUri") @Option(name = "--base-uri", aliases = { "-u" }, usage = "usage_baseUri")
private String uri; private String uri;
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups")
private String groups = "default"; //$NON-NLS-1$
@Argument(required = true, usage = "usage_pathToXml") @Argument(required = true, usage = "usage_pathToXml")
private String path; private String path;
@ -60,6 +63,7 @@ class Repo extends TextBuiltin {
new RepoCommand(db) new RepoCommand(db)
.setURI(uri) .setURI(uri)
.setPath(path) .setPath(path)
.setGroups(groups)
.call(); .call();
} }
} }

124
org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java

@ -43,6 +43,7 @@
package org.eclipse.jgit.gitrepo; package org.eclipse.jgit.gitrepo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -57,16 +58,45 @@ import org.junit.Test;
public class RepoCommandTest extends RepositoryTestCase { 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 { public void setUp() throws Exception {
super.setUp(); super.setUp();
remoteDb = createWorkRepository(); defaultDb = createWorkRepository();
Git git = new Git(remoteDb); Git git = new Git(defaultDb);
JGitTestUtil.writeTrashFile(remoteDb, "hello.txt", "world"); JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world");
git.add().addFilepattern("hello.txt").call(); git.add().addFilepattern("hello.txt").call();
git.commit().setMessage("Initial commit").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 @Test
@ -76,12 +106,14 @@ public class RepoCommandTest extends RepositoryTestCase {
.append("<manifest>") .append("<manifest>")
.append("<remote name=\"remote1\" fetch=\".\" />") .append("<remote name=\"remote1\" fetch=\".\" />")
.append("<default revision=\"master\" remote=\"remote1\" />") .append("<default revision=\"master\" remote=\"remote1\" />")
.append("<project path=\"foo\" name=\".\" />") .append("<project path=\"foo\" name=\"")
.append(defaultUri)
.append("\" />")
.append("</manifest>"); .append("</manifest>");
writeTrashFile("manifest.xml", xmlContent.toString()); writeTrashFile("manifest.xml", xmlContent.toString());
RepoCommand command = new RepoCommand(db); RepoCommand command = new RepoCommand(db);
command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml") command.setPath(db.getWorkTree().getAbsolutePath() + "/manifest.xml")
.setURI(remoteDb.getDirectory().toURI().toString()) .setURI(rootUri)
.call(); .call();
File hello = new File(db.getWorkTree(), "foo/hello.txt"); File hello = new File(db.getWorkTree(), "foo/hello.txt");
assertTrue("submodule was checked out", hello.exists()); assertTrue("submodule was checked out", hello.exists());
@ -90,4 +122,84 @@ public class RepoCommandTest extends RepositoryTestCase {
reader.close(); reader.close();
assertEquals("submodule content is as expected.", "world", content); 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;
}
}
} }

83
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java

@ -48,9 +48,12 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.api.GitCommand; import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.SubmoduleAddCommand; import org.eclipse.jgit.api.SubmoduleAddCommand;
@ -79,18 +82,22 @@ import org.xml.sax.helpers.XMLReaderFactory;
public class RepoCommand extends GitCommand<Void> { public class RepoCommand extends GitCommand<Void> {
private String path; private String path;
private String uri; private String uri;
private String groups;
private ProgressMonitor monitor; private ProgressMonitor monitor;
private static class Project { private static class Project {
final String name; final String name;
final String path; final String path;
final Set<String> groups;
Project(String name, String path) { Project(String name, String path, String groups) {
this.name = name; this.name = name;
this.path = path; 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 String baseUrl;
private final Map<String, String> remotes; private final Map<String, String> remotes;
private final List<Project> projects; private final List<Project> projects;
private final Set<String> plusGroups;
private final Set<String> minusGroups;
private String defaultRemote; private String defaultRemote;
XmlManifest(RepoCommand command, String filename, String baseUrl) { XmlManifest(RepoCommand command, String filename, String baseUrl, String groups) {
this.command = command; this.command = command;
this.filename = filename; this.filename = filename;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
remotes = new HashMap<String, String>(); remotes = new HashMap<String, String>();
projects = new ArrayList<Project>(); 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 { void read() throws IOException {
@ -137,13 +159,17 @@ public class RepoCommand extends GitCommand<Void> {
String localName, String localName,
String qName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if ("project".equals(qName)) //$NON-NLS-1$ if ("project".equals(qName)) { //$NON-NLS-1$
projects.add(new Project(attributes.getValue("name"), attributes.getValue("path"))); //$NON-NLS-1$ //$NON-NLS-2$ projects.add(new Project( //$NON-NLS-1$
else if ("remote".equals(qName)) //$NON-NLS-1$ attributes.getValue("name"), //$NON-NLS-1$
remotes.put(attributes.getValue("name"), attributes.getValue("fetch")); //$NON-NLS-1$ //$NON-NLS-2$ attributes.getValue("path"), //$NON-NLS-1$
else if ("default".equals(qName)) //$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$ 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. // TODO(fishywang): Handle copyfile. Do nothing for now.
} }
} }
@ -162,12 +188,32 @@ public class RepoCommand extends GitCommand<Void> {
throw new SAXException(e); throw new SAXException(e);
} }
for (Project proj : projects) { for (Project proj : projects) {
if (inGroups(proj)) {
String url = remoteUrl + proj.name; String url = remoteUrl + proj.name;
command.addSubmodule(url, proj.path); 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 { private static class ManifestErrorException extends GitAPIException {
ManifestErrorException(Throwable cause) { ManifestErrorException(Throwable cause) {
super(RepoText.get().invalidManifest, cause); super(RepoText.get().invalidManifest, cause);
@ -204,6 +250,17 @@ public class RepoCommand extends GitCommand<Void> {
return this; 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, * The progress monitor associated with the clone operation. By default,
* this is set to <code>NullProgressMonitor</code> * this is set to <code>NullProgressMonitor</code>
@ -225,7 +282,7 @@ public class RepoCommand extends GitCommand<Void> {
if (uri == null || uri.length() == 0) if (uri == null || uri.length() == 0)
throw new IllegalArgumentException(JGitText.get().uriNotConfigured); throw new IllegalArgumentException(JGitText.get().uriNotConfigured);
XmlManifest manifest = new XmlManifest(this, path, uri); XmlManifest manifest = new XmlManifest(this, path, uri, groups);
try { try {
manifest.read(); manifest.read();
} catch (IOException e) { } catch (IOException e) {
@ -236,11 +293,13 @@ public class RepoCommand extends GitCommand<Void> {
} }
private void addSubmodule(String url, String name) throws SAXException { 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) if (monitor != null)
add.setProgressMonitor(monitor); add.setProgressMonitor(monitor);
try { try {
add.setPath(name).setURI(url).call(); add.call();
} catch (GitAPIException e) { } catch (GitAPIException e) {
throw new SAXException(e); throw new SAXException(e);
} }

Loading…
Cancel
Save