Browse Source

Add comand support for git-submodule

Adds the following commands:
    - Add
    - Init
    - Status
    - Sync
    - Update

This also updates AddCommand so that file patterns added that
are submodules can be staged in the index.

Change-Id: Ie5112aa26430e5a2a3acd65a7b0e1d76067dc545
Signed-off-by: Kevin Sawicki <kevin@github.com>
Signed-off-by: Chris Aniszczyk <zx@twitter.com>
stable-1.3
Kevin Sawicki 13 years ago committed by Chris Aniszczyk
parent
commit
92c6f2f97b
  1. 1
      org.eclipse.jgit.test/META-INF/MANIFEST.MF
  2. 172
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
  3. 126
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
  4. 359
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
  5. 140
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
  6. 187
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java
  7. 177
      org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
  8. 1
      org.eclipse.jgit/META-INF/MANIFEST.MF
  9. 3
      org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
  10. 3
      org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
  11. 25
      org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
  12. 211
      org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
  13. 130
      org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
  14. 148
      org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java
  15. 157
      org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
  16. 190
      org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
  17. 9
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
  18. 3
      org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
  19. 115
      org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java
  20. 64
      org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatusType.java
  21. 435
      org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java

1
org.eclipse.jgit.test/META-INF/MANIFEST.MF

@ -33,6 +33,7 @@ Import-Package: org.eclipse.jgit;version="[1.3.0,1.4.0)",
org.eclipse.jgit.revwalk.filter;version="[1.3.0,1.4.0)", org.eclipse.jgit.revwalk.filter;version="[1.3.0,1.4.0)",
org.eclipse.jgit.storage.file;version="[1.3.0,1.4.0)", org.eclipse.jgit.storage.file;version="[1.3.0,1.4.0)",
org.eclipse.jgit.storage.pack;version="[1.3.0,1.4.0)", org.eclipse.jgit.storage.pack;version="[1.3.0,1.4.0)",
org.eclipse.jgit.submodule;version="[1.3.0,1.4.0)",
org.eclipse.jgit.transport;version="[1.3.0,1.4.0)", org.eclipse.jgit.transport;version="[1.3.0,1.4.0)",
org.eclipse.jgit.treewalk;version="[1.3.0,1.4.0)", org.eclipse.jgit.treewalk;version="[1.3.0,1.4.0)",
org.eclipse.jgit.treewalk.filter;version="[1.3.0,1.4.0)", org.eclipse.jgit.treewalk.filter;version="[1.3.0,1.4.0)",

172
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java

@ -0,0 +1,172 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.SubmoduleAddCommand;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
/**
* Unit tests of {@link org.eclipse.jgit.api.SubmoduleAddCommand}
*/
public class SubmoduleAddTest extends RepositoryTestCase {
@Test
public void commandWithNullPath() {
try {
new SubmoduleAddCommand(db).setURI("uri").call();
fail("Exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals(JGitText.get().pathNotConfigured, e.getMessage());
}
}
@Test
public void commandWithEmptyPath() {
try {
new SubmoduleAddCommand(db).setPath("").setURI("uri").call();
fail("Exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals(JGitText.get().pathNotConfigured, e.getMessage());
}
}
@Test
public void commandWithNullUri() {
try {
new SubmoduleAddCommand(db).setPath("sub").call();
fail("Exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals(JGitText.get().uriNotConfigured, e.getMessage());
}
}
@Test
public void commandWithEmptyUri() {
try {
new SubmoduleAddCommand(db).setPath("sub").setURI("").call();
fail("Exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals(JGitText.get().uriNotConfigured, e.getMessage());
}
}
@Test
public void addSubmodule() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
RevCommit commit = git.commit().setMessage("create file").call();
SubmoduleAddCommand command = new SubmoduleAddCommand(db);
String path = "sub";
command.setPath(path);
String uri = db.getDirectory().toURI().toString();
command.setURI(uri);
Repository repo = command.call();
assertNotNull(repo);
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
assertEquals(path, generator.getPath());
assertEquals(commit, generator.getObjectId());
assertEquals(uri, generator.getModulesUrl());
assertEquals(path, generator.getModulesPath());
assertEquals(uri, generator.getConfigUrl());
assertNotNull(generator.getRepository());
assertEquals(commit, repo.resolve(Constants.HEAD));
Status status = Git.wrap(db).status().call();
assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
assertTrue(status.getAdded().contains(path));
}
@Test
public void addExistentSubmodule() throws Exception {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
SubmoduleAddCommand command = new SubmoduleAddCommand(db);
command.setPath(path);
command.setURI("git://server/repo.git");
try {
command.call();
fail("Exception not thrown");
} catch (JGitInternalException e) {
assertEquals(
MessageFormat.format(JGitText.get().submoduleExists, path),
e.getMessage());
}
}
}

126
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java

@ -0,0 +1,126 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.eclipse.jgit.api.SubmoduleInitCommand;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test;
/**
* Unit tests of {@link SubmoduleInitCommand}
*/
public class SubmoduleInitTest extends RepositoryTestCase {
@Test
public void repositoryWithNoSubmodules() {
SubmoduleInitCommand command = new SubmoduleInitCommand(db);
Collection<String> modules = command.call();
assertNotNull(modules);
assertTrue(modules.isEmpty());
}
@Test
public void repositoryWithUninitializedModule() throws IOException,
ConfigInvalidException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
assertNull(generator.getConfigUrl());
assertNull(generator.getConfigUpdate());
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
String url = "git://server/repo.git";
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
String update = "rebase";
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_UPDATE, update);
modulesConfig.save();
SubmoduleInitCommand command = new SubmoduleInitCommand(db);
Collection<String> modules = command.call();
assertNotNull(modules);
assertEquals(1, modules.size());
assertEquals(path, modules.iterator().next());
generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
assertEquals(url, generator.getConfigUrl());
assertEquals(update, generator.getConfigUpdate());
}
}

359
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java

@ -0,0 +1,359 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.SubmoduleStatusCommand;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test;
/**
* Unit tests of {@link SubmoduleStatusCommand}
*/
public class SubmoduleStatusTest extends RepositoryTestCase {
@Test
public void repositoryWithNoSubmodules() {
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertTrue(statuses.isEmpty());
}
@Test
public void repositoryWithMissingSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(SubmoduleStatusType.MISSING, status.getType());
}
@Test
public void repositoryWithUninitializedSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, "git://server/repo.git");
modulesConfig.save();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(SubmoduleStatusType.UNINITIALIZED, status.getType());
}
@Test
public void repositoryWithNoHeadInSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
String url = "git://server/repo.git";
StoredConfig config = db.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
config.save();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
Repository subRepo = Git.init().setBare(false)
.setDirectory(new File(db.getWorkTree(), path)).call()
.getRepository();
assertNotNull(subRepo);
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(SubmoduleStatusType.UNINITIALIZED, status.getType());
}
@Test
public void repositoryWithNoSubmoduleRepository() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
String url = "git://server/repo.git";
StoredConfig config = db.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
config.save();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(SubmoduleStatusType.UNINITIALIZED, status.getType());
}
@Test
public void repositoryWithInitializedSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
String url = "git://server/repo.git";
StoredConfig config = db.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
config.save();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
Repository subRepo = Git.init().setBare(false)
.setDirectory(new File(db.getWorkTree(), path)).call()
.getRepository();
assertNotNull(subRepo);
RefUpdate update = subRepo.updateRef(Constants.HEAD, true);
update.setNewObjectId(id);
update.forceUpdate();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(SubmoduleStatusType.INITIALIZED, status.getType());
}
@Test
public void repositoryWithDifferentRevCheckedOutSubmodule()
throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
String url = "git://server/repo.git";
StoredConfig config = db.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
config.save();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
Repository subRepo = Git.init().setBare(false)
.setDirectory(new File(db.getWorkTree(), path)).call()
.getRepository();
assertNotNull(subRepo);
RefUpdate update = subRepo.updateRef(Constants.HEAD, true);
update.setNewObjectId(ObjectId
.fromString("aaaa0000aaaa0000aaaa0000aaaa0000aaaa0000"));
update.forceUpdate();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
assertEquals(1, statuses.size());
Entry<String, SubmoduleStatus> module = statuses.entrySet().iterator()
.next();
assertNotNull(module);
assertEquals(path, module.getKey());
SubmoduleStatus status = module.getValue();
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
assertEquals(update.getNewObjectId(), status.getHeadId());
assertEquals(SubmoduleStatusType.REV_CHECKED_OUT, status.getType());
}
}

140
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java

@ -0,0 +1,140 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.SubmoduleSyncCommand;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test;
/**
* Unit tests of {@link SubmoduleSyncCommand}
*/
public class SubmoduleSyncTest extends RepositoryTestCase {
@Test
public void repositoryWithNoSubmodules() {
SubmoduleSyncCommand command = new SubmoduleSyncCommand(db);
Map<String, String> modules = command.call();
assertNotNull(modules);
assertTrue(modules.isEmpty());
}
@Test
public void repositoryWithSubmodule() throws Exception {
writeTrashFile("file.txt", "content");
Git git = Git.wrap(db);
git.add().addFilepattern("file.txt").call();
git.commit().setMessage("create file").call();
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
String url = "git://server/repo.git";
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
Repository subRepo = Git.cloneRepository()
.setURI(db.getDirectory().toURI().toString())
.setDirectory(new File(db.getWorkTree(), path)).call()
.getRepository();
assertNotNull(subRepo);
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
assertNull(generator.getConfigUrl());
assertEquals(url, generator.getModulesUrl());
SubmoduleSyncCommand command = new SubmoduleSyncCommand(db);
Map<String, String> synced = command.call();
assertNotNull(synced);
assertEquals(1, synced.size());
Entry<String, String> module = synced.entrySet().iterator().next();
assertEquals(path, module.getKey());
assertEquals(url, module.getValue());
generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
assertEquals(url, generator.getConfigUrl());
StoredConfig submoduleConfig = generator.getRepository().getConfig();
assertEquals(url, submoduleConfig.getString(
ConfigConstants.CONFIG_REMOTE_SECTION,
Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL));
}
}

187
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java

@ -0,0 +1,187 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.SubmoduleUpdateCommand;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test;
/**
* Unit tests of {@link SubmoduleUpdateCommand}
*/
public class SubmoduleUpdateTest extends RepositoryTestCase {
@Test
public void repositoryWithNoSubmodules() {
SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db);
Collection<String> modules = command.call();
assertNotNull(modules);
assertTrue(modules.isEmpty());
}
@Test
public void repositoryWithSubmodule() throws Exception {
writeTrashFile("file.txt", "content");
Git git = Git.wrap(db);
git.add().addFilepattern("file.txt").call();
final RevCommit commit = git.commit().setMessage("create file").call();
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(commit);
}
});
editor.commit();
StoredConfig config = db.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, db.getDirectory().toURI()
.toString());
config.save();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.save();
SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db);
Collection<String> updated = command.call();
assertNotNull(updated);
assertEquals(1, updated.size());
assertEquals(path, updated.iterator().next());
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
Repository subRepo = generator.getRepository();
assertNotNull(subRepo);
assertEquals(commit, subRepo.resolve(Constants.HEAD));
}
@Test
public void repositoryWithUnconfiguredSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
String url = "git://server/repo.git";
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, url);
String update = "rebase";
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_UPDATE, update);
modulesConfig.save();
SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db);
Collection<String> updated = command.call();
assertNotNull(updated);
assertTrue(updated.isEmpty());
}
@Test
public void repositoryWithInitializedSubmodule() throws IOException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
Repository subRepo = Git.init().setBare(false)
.setDirectory(new File(db.getWorkTree(), path)).call()
.getRepository();
assertNotNull(subRepo);
SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db);
Collection<String> updated = command.call();
assertNotNull(updated);
assertTrue(updated.isEmpty());
}
}

177
org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java

@ -0,0 +1,177 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.junit.Test;
/**
* Unit tests of {@link SubmoduleWalk}
*/
public class SubmoduleWalkTest extends RepositoryTestCase {
@Test
public void repositoryWithNoSubmodules() throws IOException {
SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
assertFalse(gen.next());
assertNull(gen.getPath());
assertEquals(ObjectId.zeroId(), gen.getObjectId());
}
@Test
public void repositoryWithRootLevelSubmodule() throws IOException,
ConfigInvalidException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
assertTrue(gen.next());
assertEquals(path, gen.getPath());
assertEquals(id, gen.getObjectId());
assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
assertEquals(new File(db.getWorkTree(), path + File.separatorChar
+ Constants.DOT_GIT), gen.getGitDirectory());
assertNull(gen.getConfigUpdate());
assertNull(gen.getConfigUrl());
assertNull(gen.getModulesPath());
assertNull(gen.getModulesUpdate());
assertNull(gen.getModulesUrl());
assertNull(gen.getRepository());
assertFalse(gen.next());
}
@Test
public void repositoryWithNestedSubmodule() throws IOException,
ConfigInvalidException {
final ObjectId id = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path = "sub/dir/final";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id);
}
});
editor.commit();
SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
assertTrue(gen.next());
assertEquals(path, gen.getPath());
assertEquals(id, gen.getObjectId());
assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
assertEquals(new File(db.getWorkTree(), path + File.separatorChar
+ Constants.DOT_GIT), gen.getGitDirectory());
assertNull(gen.getConfigUpdate());
assertNull(gen.getConfigUrl());
assertNull(gen.getModulesPath());
assertNull(gen.getModulesUpdate());
assertNull(gen.getModulesUrl());
assertNull(gen.getRepository());
assertFalse(gen.next());
}
@Test
public void generatorFilteredToOneOfTwoSubmodules() throws IOException {
final ObjectId id1 = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
final String path1 = "sub1";
final ObjectId id2 = ObjectId
.fromString("abcd1234abcd1234abcd1234abcd1234abcd1235");
final String path2 = "sub2";
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path1) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id1);
}
});
editor.add(new PathEdit(path2) {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.GITLINK);
ent.setObjectId(id2);
}
});
editor.commit();
SubmoduleWalk gen = SubmoduleWalk.forIndex(db);
gen.setFilter(PathFilter.create(path1));
assertTrue(gen.next());
assertEquals(path1, gen.getPath());
assertEquals(id1, gen.getObjectId());
assertFalse(gen.next());
}
}

1
org.eclipse.jgit/META-INF/MANIFEST.MF

@ -26,6 +26,7 @@ Export-Package: org.eclipse.jgit;version="1.3.0",
org.eclipse.jgit.storage.dfs;version="1.3.0", org.eclipse.jgit.storage.dfs;version="1.3.0",
org.eclipse.jgit.storage.file;version="1.3.0", org.eclipse.jgit.storage.file;version="1.3.0",
org.eclipse.jgit.storage.pack;version="1.3.0", org.eclipse.jgit.storage.pack;version="1.3.0",
org.eclipse.jgit.submodule;version="1.3.0",
org.eclipse.jgit.transport;version="1.3.0", org.eclipse.jgit.transport;version="1.3.0",
org.eclipse.jgit.transport.resolver;version="1.3.0", org.eclipse.jgit.transport.resolver;version="1.3.0",
org.eclipse.jgit.treewalk;version="1.3.0", org.eclipse.jgit.treewalk;version="1.3.0",

3
org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties

@ -346,6 +346,7 @@ packfileCorruptionDetected=Packfile corruption detected: {0}
packfileIsTruncated=Packfile is truncated. packfileIsTruncated=Packfile is truncated.
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packWriterStatistics=Total {0,number,#0} (delta {1,number,#0}), reused {2,number,#0} (delta {3,number,#0}) packWriterStatistics=Total {0,number,#0} (delta {1,number,#0}), reused {2,number,#0} (delta {3,number,#0})
pathNotConfigured=Submodule path is not configured
pathIsNotInWorkingDir=Path is not in working dir pathIsNotInWorkingDir=Path is not in working dir
peeledLineBeforeRef=Peeled line before ref. peeledLineBeforeRef=Peeled line before ref.
peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph
@ -421,6 +422,7 @@ sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
staleRevFlagsOn=Stale RevFlags on {0} staleRevFlagsOn=Stale RevFlags on {0}
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled
submoduleExists=Submodule ''{0}'' already exists in the index
submodulesNotSupported=Submodules are not supported submodulesNotSupported=Submodules are not supported
symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java. symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java.
systemConfigFileInvalid=Systen wide config file {0} is invalid {1} systemConfigFileInvalid=Systen wide config file {0} is invalid {1}
@ -480,6 +482,7 @@ unsupportedPackIndexVersion=Unsupported pack index version {0}
unsupportedPackVersion=Unsupported pack version {0}. unsupportedPackVersion=Unsupported pack version {0}.
updatingReferences=Updating references updatingReferences=Updating references
updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2} updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2}
uriNotConfigured=Submodule URI not configured
uriNotFound={0} not found uriNotFound={0} not found
userConfigFileInvalid=User config file {0} invalid {1} userConfigFileInvalid=User config file {0} invalid {1}
walkFailure=Walk failure. walkFailure=Walk failure.

3
org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java

@ -407,6 +407,7 @@ public class JGitText extends TranslationBundle {
/***/ public String packingCancelledDuringObjectsWriting; /***/ public String packingCancelledDuringObjectsWriting;
/***/ public String packWriterStatistics; /***/ public String packWriterStatistics;
/***/ public String pathIsNotInWorkingDir; /***/ public String pathIsNotInWorkingDir;
/***/ public String pathNotConfigured;
/***/ public String peeledLineBeforeRef; /***/ public String peeledLineBeforeRef;
/***/ public String peerDidNotSupplyACompleteObjectGraph; /***/ public String peerDidNotSupplyACompleteObjectGraph;
/***/ public String prefixRemote; /***/ public String prefixRemote;
@ -481,6 +482,7 @@ public class JGitText extends TranslationBundle {
/***/ public String staleRevFlagsOn; /***/ public String staleRevFlagsOn;
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported; /***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
/***/ public String statelessRPCRequiresOptionToBeEnabled; /***/ public String statelessRPCRequiresOptionToBeEnabled;
/***/ public String submoduleExists;
/***/ public String submodulesNotSupported; /***/ public String submodulesNotSupported;
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget; /***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
/***/ public String systemConfigFileInvalid; /***/ public String systemConfigFileInvalid;
@ -540,6 +542,7 @@ public class JGitText extends TranslationBundle {
/***/ public String unsupportedPackVersion; /***/ public String unsupportedPackVersion;
/***/ public String updatingReferences; /***/ public String updatingReferences;
/***/ public String updatingRefFailed; /***/ public String updatingRefFailed;
/***/ public String uriNotConfigured;
/***/ public String uriNotFound; /***/ public String uriNotFound;
/***/ public String userConfigFileInvalid; /***/ public String userConfigFileInvalid;
/***/ public String walkFailure; /***/ public String walkFailure;

25
org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java

@ -43,6 +43,7 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
@ -57,6 +58,8 @@ import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
@ -168,10 +171,13 @@ public class AddCommand extends GitCommand<DirCache> {
DirCacheEntry entry = new DirCacheEntry(path); DirCacheEntry entry = new DirCacheEntry(path);
if (c == null || c.getDirCacheEntry() == null if (c == null || c.getDirCacheEntry() == null
|| !c.getDirCacheEntry().isAssumeValid()) { || !c.getDirCacheEntry().isAssumeValid()) {
entry.setLength(sz); FileMode mode = f.getEntryFileMode();
entry.setLastModified(f.getEntryLastModified()); entry.setFileMode(mode);
entry.setFileMode(f.getEntryFileMode());
if (FileMode.GITLINK != mode) {
entry.setLength(sz);
entry.setLastModified(f
.getEntryLastModified());
InputStream in = f.openEntryStream(); InputStream in = f.openEntryStream();
try { try {
entry.setObjectId(inserter.insert( entry.setObjectId(inserter.insert(
@ -179,9 +185,20 @@ public class AddCommand extends GitCommand<DirCache> {
} finally { } finally {
in.close(); in.close();
} }
builder.add(entry); builder.add(entry);
lastAddedFile = path; lastAddedFile = path;
} else {
Repository subRepo = Git.open(
new File(repo.getWorkTree(), path))
.getRepository();
ObjectId subRepoHead = subRepo
.resolve(Constants.HEAD);
if (subRepoHead != null) {
entry.setObjectId(subRepoHead);
builder.add(entry);
lastAddedFile = path;
}
}
} else { } else {
builder.add(c.getDirCacheEntry()); builder.add(c.getDirCacheEntry());
} }

211
org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java

@ -0,0 +1,211 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
/**
* A class used to execute a submodule add command.
*
* This will clone the configured submodule, register the submodule in the
* .gitmodules file and the repository config file, and also add the submodule
* and .gitmodules file to the index.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
* >Git documentation about submodules</a>
*/
public class SubmoduleAddCommand extends GitCommand<Repository> {
private String path;
private String uri;
private ProgressMonitor monitor;
private CredentialsProvider credentialsProvider;
/**
* @param repo
*/
public SubmoduleAddCommand(final Repository repo) {
super(repo);
}
/**
* Set repository-relative path of submodule
*
* @param path
* @return this command
*/
public SubmoduleAddCommand setPath(final String path) {
this.path = path;
return this;
}
/**
* Set URI to clone submodule from
*
* @param uri
* @return this command
*/
public SubmoduleAddCommand setURI(final String uri) {
this.uri = uri;
return this;
}
/**
* The progress monitor associated with the clone operation. By default,
* this is set to <code>NullProgressMonitor</code>
*
* @see NullProgressMonitor
* @param monitor
* @return this command
*/
public SubmoduleAddCommand setProgressMonitor(final ProgressMonitor monitor) {
this.monitor = monitor;
return this;
}
/**
* @param credentialsProvider
* the {@link CredentialsProvider} to use
* @return this command
*/
public SubmoduleAddCommand setCredentialsProvider(
final CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
/**
* Is the configured already a submodule in the index?
*
* @return true if submodule exists in index, false otherwise
* @throws IOException
*/
protected boolean submoduleExists() throws IOException {
TreeFilter filter = PathFilter.create(path);
return SubmoduleWalk.forIndex(repo).setFilter(filter).next();
}
public Repository call() throws JGitInternalException {
checkCallable();
if (path == null || path.length() == 0)
throw new IllegalArgumentException(JGitText.get().pathNotConfigured);
if (uri == null || uri.length() == 0)
throw new IllegalArgumentException(JGitText.get().uriNotConfigured);
try {
if (submoduleExists())
throw new JGitInternalException(MessageFormat.format(
JGitText.get().submoduleExists, path));
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
// Clone submodule repository
File moduleDirectory = SubmoduleWalk.getSubmoduleDirectory(repo, path);
CloneCommand clone = Git.cloneRepository();
clone.setDirectory(moduleDirectory);
clone.setURI(uri);
if (monitor != null)
clone.setProgressMonitor(monitor);
if (credentialsProvider != null)
clone.setCredentialsProvider(credentialsProvider);
Repository subRepo = clone.call().getRepository();
// Save submodule URL to parent repository's config
StoredConfig config = repo.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, uri);
try {
config.save();
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
// Save path and URL to parent repository's .gitmodules file
FileBasedConfig modulesConfig = new FileBasedConfig(new File(
repo.getWorkTree(), Constants.DOT_GIT_MODULES), repo.getFS());
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH, path);
modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL, uri);
try {
modulesConfig.save();
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
AddCommand add = new AddCommand(repo);
// Add .gitmodules file to parent repository's index
add.addFilepattern(Constants.DOT_GIT_MODULES);
// Add submodule directory to parent repository's index
add.addFilepattern(path);
try {
add.call();
} catch (NoFilepatternException e) {
throw new JGitInternalException(e.getMessage(), e);
}
return subRepo;
}
}

130
org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java

@ -0,0 +1,130 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
/**
* A class used to execute a submodule init command.
*
* This will copy the 'url' and 'update' fields from the working tree
* .gitmodules file to a repository's config file for each submodule not
* currently present in the repository's config file.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
* >Git documentation about submodules</a>
*/
public class SubmoduleInitCommand extends GitCommand<Collection<String>> {
private final Collection<String> paths;
/**
* @param repo
*/
public SubmoduleInitCommand(final Repository repo) {
super(repo);
paths = new ArrayList<String>();
}
/**
* Add repository-relative submodule path to initialize
*
* @param path
* @return this command
*/
public SubmoduleInitCommand addPath(final String path) {
paths.add(path);
return this;
}
public Collection<String> call() throws JGitInternalException {
checkCallable();
try {
SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
if (!paths.isEmpty())
generator.setFilter(PathFilterGroup.createFromStrings(paths));
StoredConfig config = repo.getConfig();
List<String> initialized = new ArrayList<String>();
while (generator.next()) {
// Ignore entry if URL is already present in config file
if (generator.getConfigUrl() != null)
continue;
String path = generator.getPath();
// Copy 'url' and 'update' fields from .gitmodules to config
// file
String url = generator.getModulesUrl();
String update = generator.getModulesUpdate();
if (url != null)
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
path, ConfigConstants.CONFIG_KEY_URL, url);
if (update != null)
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
path, ConfigConstants.CONFIG_KEY_UPDATE, update);
if (url != null || update != null)
initialized.add(path);
}
// Save repository config if any values were updated
if (!initialized.isEmpty())
config.save();
return initialized;
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (ConfigInvalidException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

148
org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java

@ -0,0 +1,148 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.submodule.SubmoduleStatus;
import org.eclipse.jgit.submodule.SubmoduleStatusType;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
/**
* A class used to execute a submodule status command.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
* >Git documentation about submodules</a>
*/
public class SubmoduleStatusCommand extends
GitCommand<Map<String, SubmoduleStatus>> {
private final Collection<String> paths;
/**
* @param repo
*/
public SubmoduleStatusCommand(final Repository repo) {
super(repo);
paths = new ArrayList<String>();
}
/**
* Add repository-relative submodule path to limit status reporting to
*
* @param path
* @return this command
*/
public SubmoduleStatusCommand addPath(final String path) {
paths.add(path);
return this;
}
public Map<String, SubmoduleStatus> call() throws JGitInternalException {
checkCallable();
try {
SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
if (!paths.isEmpty())
generator.setFilter(PathFilterGroup.createFromStrings(paths));
Map<String, SubmoduleStatus> statuses = new HashMap<String, SubmoduleStatus>();
while (generator.next()) {
SubmoduleStatus status = getStatus(generator);
statuses.put(status.getPath(), status);
}
return statuses;
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (ConfigInvalidException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
private SubmoduleStatus getStatus(SubmoduleWalk generator)
throws IOException, ConfigInvalidException {
ObjectId id = generator.getObjectId();
String path = generator.getPath();
// Report missing if no path in .gitmodules file
if (generator.getModulesPath() == null)
return new SubmoduleStatus(SubmoduleStatusType.MISSING, path, id);
// Report uninitialized if no URL in config file
if (generator.getConfigUrl() == null)
return new SubmoduleStatus(SubmoduleStatusType.UNINITIALIZED, path,
id);
// Report uninitialized if no submodule repository
Repository subRepo = generator.getRepository();
if (subRepo == null)
return new SubmoduleStatus(SubmoduleStatusType.UNINITIALIZED, path,
id);
ObjectId headId = subRepo.resolve(Constants.HEAD);
// Report uninitialized if no HEAD commit in submodule repository
if (headId == null)
return new SubmoduleStatus(SubmoduleStatusType.UNINITIALIZED, path,
id, headId);
// Report checked out if HEAD commit is different than index commit
if (!headId.equals(id))
return new SubmoduleStatus(SubmoduleStatusType.REV_CHECKED_OUT,
path, id, headId);
// Report initialized if HEAD commit is the same as the index commit
return new SubmoduleStatus(SubmoduleStatusType.INITIALIZED, path, id,
headId);
}
}

157
org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java

@ -0,0 +1,157 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
/**
* A class used to execute a submodule sync command.
*
* This will set the remote URL in a submodule's repository to the current value
* in the .gitmodules file.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
* >Git documentation about submodules</a>
*/
public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> {
private final Collection<String> paths;
/**
* @param repo
*/
public SubmoduleSyncCommand(final Repository repo) {
super(repo);
paths = new ArrayList<String>();
}
/**
* Add repository-relative submodule path to synchronize
*
* @param path
* @return this command
*/
public SubmoduleSyncCommand addPath(final String path) {
paths.add(path);
return this;
}
/**
* Get branch that HEAD currently points to
*
* @param subRepo
* @return shortened branch name, null on failures
* @throws IOException
*/
protected String getHeadBranch(final Repository subRepo) throws IOException {
Ref head = subRepo.getRef(Constants.HEAD);
if (head != null && head.isSymbolic())
return Repository.shortenRefName(head.getLeaf().getName());
else
return null;
}
public Map<String, String> call() throws JGitInternalException {
checkCallable();
try {
SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
if (!paths.isEmpty())
generator.setFilter(PathFilterGroup.createFromStrings(paths));
Map<String, String> synced = new HashMap<String, String>();
StoredConfig config = repo.getConfig();
while (generator.next()) {
String remoteUrl = generator.getModulesUrl();
if (remoteUrl == null)
continue;
String path = generator.getPath();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
path, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
synced.put(path, remoteUrl);
Repository subRepo = generator.getRepository();
if (subRepo == null)
continue;
StoredConfig subConfig = subRepo.getConfig();
// Get name of remote associated with current branch and
// fall back to default remote name as last resort
String branch = getHeadBranch(subRepo);
String remote = null;
if (branch != null)
remote = subConfig.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branch,
ConfigConstants.CONFIG_KEY_REMOTE);
if (remote == null)
remote = Constants.DEFAULT_REMOTE_NAME;
subConfig.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
remote, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
subConfig.save();
}
if (!synced.isEmpty())
config.save();
return synced;
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (ConfigInvalidException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

190
org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java

@ -0,0 +1,190 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
/**
* A class used to execute a submodule update command.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
* >Git documentation about submodules</a>
*/
public class SubmoduleUpdateCommand extends GitCommand<Collection<String>> {
private ProgressMonitor monitor;
private CredentialsProvider credentialsProvider;
private final Collection<String> paths;
/**
* @param repo
*/
public SubmoduleUpdateCommand(final Repository repo) {
super(repo);
paths = new ArrayList<String>();
}
/**
* The progress monitor associated with the clone operation. By default,
* this is set to <code>NullProgressMonitor</code>
*
* @see NullProgressMonitor
* @param monitor
* @return this command
*/
public SubmoduleUpdateCommand setProgressMonitor(
final ProgressMonitor monitor) {
this.monitor = monitor;
return this;
}
/**
* @param credentialsProvider
* the {@link CredentialsProvider} to use
* @return this command
*/
public SubmoduleUpdateCommand setCredentialsProvider(
final CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
/**
* Add repository-relative submodule path to initialize
*
* @param path
* @return this command
*/
public SubmoduleUpdateCommand addPath(final String path) {
paths.add(path);
return this;
}
public Collection<String> call() throws JGitInternalException {
checkCallable();
try {
SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
if (!paths.isEmpty())
generator.setFilter(PathFilterGroup.createFromStrings(paths));
List<String> updated = new ArrayList<String>();
while (generator.next()) {
// Skip submodules not registered in .gitmodules file
if (generator.getModulesPath() == null)
continue;
// Skip submodules not registered in parent repository's config
String url = generator.getConfigUrl();
if (url == null)
continue;
Repository submoduleRepo = generator.getRepository();
// Clone repository is not present
if (submoduleRepo == null) {
CloneCommand clone = Git.cloneRepository();
clone.setURI(url);
clone.setDirectory(generator.getDirectory());
if (monitor != null)
clone.setProgressMonitor(monitor);
if (credentialsProvider != null)
clone.setCredentialsProvider(credentialsProvider);
submoduleRepo = clone.call().getRepository();
}
RevWalk walk = new RevWalk(submoduleRepo);
RevCommit commit = walk.parseCommit(generator.getObjectId());
String update = generator.getConfigUpdate();
if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) {
MergeCommand merge = new MergeCommand(submoduleRepo);
merge.include(commit);
merge.call();
} else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) {
RebaseCommand rebase = new RebaseCommand(submoduleRepo);
rebase.setUpstream(commit);
rebase.call();
} else {
// Checkout commit referenced in parent repository's index
// as a detached HEAD
DirCacheCheckout co = new DirCacheCheckout(submoduleRepo,
submoduleRepo.lockDirCache(), commit.getTree());
co.setFailOnConflict(true);
co.checkout();
RefUpdate refUpdate = submoduleRepo.updateRef(
Constants.HEAD, true);
refUpdate.setNewObjectId(commit);
refUpdate.forceUpdate();
}
updated.add(generator.getPath());
}
return updated;
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (ConfigInvalidException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (GitAPIException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

9
org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java

@ -72,6 +72,9 @@ public class ConfigConstants {
/** The "workflow" section */ /** The "workflow" section */
public static final String CONFIG_WORKFLOW_SECTION = "workflow"; public static final String CONFIG_WORKFLOW_SECTION = "workflow";
/** The "submodule" section */
public static final String CONFIG_SUBMODULE_SECTION = "submodule";
/** The "algorithm" key */ /** The "algorithm" key */
public static final String CONFIG_KEY_ALGORITHM = "algorithm"; public static final String CONFIG_KEY_ALGORITHM = "algorithm";
@ -160,4 +163,10 @@ public class ConfigConstants {
/** The "defaultsourceref" key */ /** The "defaultsourceref" key */
public static final String CONFIG_KEY_DEFBRANCHSTARTPOINT = "defbranchstartpoint"; public static final String CONFIG_KEY_DEFBRANCHSTARTPOINT = "defbranchstartpoint";
/** The "path" key */
public static final String CONFIG_KEY_PATH = "path";
/** The "update" key */
public static final String CONFIG_KEY_UPDATE = "update";
} }

3
org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java

@ -328,6 +328,9 @@ public final class Constants {
/** Name of the ignore file */ /** Name of the ignore file */
public static final String DOT_GIT_IGNORE = ".gitignore"; public static final String DOT_GIT_IGNORE = ".gitignore";
/** Name of the submodules file */
public static final String DOT_GIT_MODULES = ".gitmodules";
/** /**
* Create a new digest function for objects. * Create a new digest function for objects.
* *

115
org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatus.java

@ -0,0 +1,115 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import org.eclipse.jgit.lib.ObjectId;
/**
* Status class containing the type, path, and commit id of the submodule.
*/
public class SubmoduleStatus {
private final SubmoduleStatusType type;
private final String path;
private final ObjectId indexId;
private final ObjectId headId;
/**
* Create submodule status
*
* @param type
* @param path
* @param indexId
*/
public SubmoduleStatus(final SubmoduleStatusType type, final String path,
final ObjectId indexId) {
this(type, path, indexId, null);
}
/**
* Create submodule status
*
* @param type
* @param path
* @param indexId
* @param headId
*/
public SubmoduleStatus(final SubmoduleStatusType type, final String path,
final ObjectId indexId, final ObjectId headId) {
this.type = type;
this.path = path;
this.indexId = indexId;
this.headId = headId;
}
/**
* @return type
*/
public SubmoduleStatusType getType() {
return type;
}
/**
* @return path
*/
public String getPath() {
return path;
}
/**
* @return index object id
*/
public ObjectId getIndexId() {
return indexId;
}
/**
* @return HEAD object id
*/
public ObjectId getHeadId() {
return headId;
}
}

64
org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleStatusType.java

@ -0,0 +1,64 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
/**
* Enumeration of different statuses that a submodule can be in
*/
public enum SubmoduleStatusType {
/** Submodule's configuration is missing */
MISSING,
/** Submodule's Git repository is not initialized */
UNINITIALIZED,
/** Submodule's Git repository is initialized */
INITIALIZED,
/**
* Submodule commit checked out is different than the commit referenced in
* the index tree
*/
REV_CHECKED_OUT;
}

435
org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java

@ -0,0 +1,435 @@
/*
* Copyright (C) 2011, GitHub Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.submodule;
import java.io.File;
import java.io.IOException;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.FS;
/**
* Walker that visits all submodule entries found in a tree
*/
public class SubmoduleWalk {
/**
* Create a generator to walk over the submodule entries currently in the
* index
*
* @param repository
* @return generator over submodule index entries
* @throws IOException
*/
public static SubmoduleWalk forIndex(Repository repository)
throws IOException {
SubmoduleWalk generator = new SubmoduleWalk(repository);
generator.setTree(new DirCacheIterator(repository.readDirCache()));
return generator;
}
/**
* Create a generator and advance it to the submodule entry at the given
* path
*
* @param repository
* @param treeId
* @param path
* @return generator at given path, null if no submodule at given path
* @throws IOException
*/
public static SubmoduleWalk forPath(Repository repository,
AnyObjectId treeId, String path) throws IOException {
SubmoduleWalk generator = new SubmoduleWalk(repository);
generator.setTree(treeId);
PathFilter filter = PathFilter.create(path);
generator.setFilter(filter);
while (generator.next())
if (filter.isDone(generator.walk))
return generator;
return null;
}
/**
* Create a generator and advance it to the submodule entry at the given
* path
*
* @param repository
* @param iterator
* @param path
* @return generator at given path, null if no submodule at given path
* @throws IOException
*/
public static SubmoduleWalk forPath(Repository repository,
AbstractTreeIterator iterator, String path) throws IOException {
SubmoduleWalk generator = new SubmoduleWalk(repository);
generator.setTree(iterator);
PathFilter filter = PathFilter.create(path);
generator.setFilter(filter);
while (generator.next())
if (filter.isDone(generator.walk))
return generator;
return null;
}
/**
* Get submodule directory
*
* @param parent
* @param path
* @return directory
*/
public static File getSubmoduleDirectory(final Repository parent,
final String path) {
return new File(parent.getWorkTree(), path);
}
/**
* Get submodule repository
*
* @param parent
* @param path
* @return repository or null if repository doesn't exist
* @throws IOException
*/
public static Repository getSubmoduleRepository(final Repository parent,
final String path) throws IOException {
File directory = getSubmoduleGitDirectory(parent, path);
if (!directory.isDirectory())
return null;
try {
return new RepositoryBuilder().setMustExist(true)
.setFS(FS.DETECTED).setGitDir(directory).build();
} catch (RepositoryNotFoundException e) {
return null;
}
}
/**
* Get the .git directory for a repository submodule path
*
* @param parent
* @param path
* @return .git for submodule repository
*/
public static File getSubmoduleGitDirectory(final Repository parent,
final String path) {
return new File(getSubmoduleDirectory(parent, path), Constants.DOT_GIT);
}
private final Repository repository;
private final TreeWalk walk;
private StoredConfig repoConfig;
private FileBasedConfig modulesConfig;
private String path;
/**
* Create submodule generator
*
* @param repository
* @throws IOException
*/
public SubmoduleWalk(final Repository repository) throws IOException {
this.repository = repository;
repoConfig = repository.getConfig();
walk = new TreeWalk(repository);
walk.setRecursive(true);
}
private void loadModulesConfig() throws IOException, ConfigInvalidException {
if (modulesConfig == null) {
File modulesFile = new File(repository.getWorkTree(),
Constants.DOT_GIT_MODULES);
FileBasedConfig config = new FileBasedConfig(modulesFile,
repository.getFS());
config.load();
modulesConfig = config;
}
}
/**
* Set tree filter
*
* @param filter
* @return this generator
*/
public SubmoduleWalk setFilter(TreeFilter filter) {
walk.setFilter(filter);
return this;
}
/**
* Set the tree iterator used for finding submodule entries
*
* @param iterator
* @return this generator
* @throws CorruptObjectException
*/
public SubmoduleWalk setTree(final AbstractTreeIterator iterator)
throws CorruptObjectException {
walk.addTree(iterator);
return this;
}
/**
* Set the tree used for finding submodule entries
*
* @param treeId
* @return this generator
* @throws IOException
* @throws IncorrectObjectTypeException
* @throws MissingObjectException
*/
public SubmoduleWalk setTree(final AnyObjectId treeId) throws IOException {
walk.addTree(treeId);
return this;
}
/**
* Reset generator and start new submodule walk
*
* @return this generator
*/
public SubmoduleWalk reset() {
repoConfig = repository.getConfig();
modulesConfig = null;
walk.reset();
return this;
}
/**
* Get directory that will be the root of the submodule's local repository
*
* @return submodule repository directory
*/
public File getDirectory() {
return getSubmoduleDirectory(repository, path);
}
/**
* Get the .git directory for the current submodule entry
*
* @return .git for submodule repository
*/
public File getGitDirectory() {
return getSubmoduleGitDirectory(repository, path);
}
/**
* Advance to next submodule in the index tree.
*
* The object id and path of the next entry can be obtained by calling
* {@link #getObjectId()} and {@link #getPath()}.
*
* @return true if entry found, false otherwise
* @throws IOException
*/
public boolean next() throws IOException {
while (walk.next()) {
if (FileMode.GITLINK != walk.getFileMode(0))
continue;
path = walk.getPathString();
return true;
}
path = null;
return false;
}
/**
* Get path of current submodule entry
*
* @return path
*/
public String getPath() {
return path;
}
/**
* Get object id of current submodule entry
*
* @return object id
*/
public ObjectId getObjectId() {
return walk.getObjectId(0);
}
/**
* Get the configured path for current entry. This will be the value from
* the .gitmodules file in the current repository's working tree.
*
* @return configured path
* @throws ConfigInvalidException
* @throws IOException
*/
public String getModulesPath() throws IOException, ConfigInvalidException {
loadModulesConfig();
return modulesConfig.getString(
ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_PATH);
}
/**
* Get the configured remote URL for current entry. This will be the value
* from the repository's config.
*
* @return configured URL
* @throws ConfigInvalidException
* @throws IOException
*/
public String getConfigUrl() throws IOException, ConfigInvalidException {
return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
path, ConfigConstants.CONFIG_KEY_URL);
}
/**
* Get the configured remote URL for current entry. This will be the value
* from the .gitmodules file in the current repository's working tree.
*
* @return configured URL
* @throws ConfigInvalidException
* @throws IOException
*/
public String getModulesUrl() throws IOException, ConfigInvalidException {
loadModulesConfig();
return modulesConfig.getString(
ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_URL);
}
/**
* Get the configured update field for current entry. This will be the value
* from the repository's config.
*
* @return update value
* @throws ConfigInvalidException
* @throws IOException
*/
public String getConfigUpdate() throws IOException, ConfigInvalidException {
return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
path, ConfigConstants.CONFIG_KEY_UPDATE);
}
/**
* Get the configured update field for current entry. This will be the value
* from the .gitmodules file in the current repository's working tree.
*
* @return update value
* @throws ConfigInvalidException
* @throws IOException
*/
public String getModulesUpdate() throws IOException, ConfigInvalidException {
loadModulesConfig();
return modulesConfig.getString(
ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
ConfigConstants.CONFIG_KEY_UPDATE);
}
/**
* Does the current submodule entry have a .git directory in the parent
* repository's working tree?
*
* @return true if .git directory exists, false otherwise
*/
public boolean hasGitDirectory() {
return getGitDirectory().isDirectory();
}
/**
* Get repository for current submodule entry
*
* @see #hasGitDirectory()
* @return repository or null if non-existent
* @throws IOException
*/
public Repository getRepository() throws IOException {
return getSubmoduleRepository(repository, path);
}
/**
* Get commit id that HEAD points to in the current submodule's repository
*
* @return object id of HEAD reference
* @throws IOException
*/
public ObjectId getHead() throws IOException {
Repository subRepo = getRepository();
return subRepo != null ? subRepo.resolve(Constants.HEAD) : null;
}
/**
* Get ref that HEAD points to in the current submodule's repository
*
* @return ref name, null on failures
* @throws IOException
*/
public String getHeadRef() throws IOException {
Repository subRepo = getRepository();
if (subRepo == null)
return null;
Ref head = subRepo.getRef(Constants.HEAD);
return head != null ? head.getLeaf().getName() : null;
}
}
Loading…
Cancel
Save