From 6ae4ed0f7da996bde2ba5cdc26daff979c9f6866 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 31 May 2016 15:19:52 -0700 Subject: [PATCH] RepoCommand: record manifest shallow recommendation in .gitmodules Git core learned about the submodule..shallow option in .gitmodules files, which is a recommendation to clone a submodule shallow. A repo manifest may record a clone depth recommendation as an optional field, which contains more information than a binary shallow/nonshallow recommendation, so any attempted conversion may be lossy. In practice the clone depth recommendation is either '1' or doesn't exist, which is the binary behavior we have in Git core. Change-Id: I51aa9cb6d1d9660dae6ab6d21ad7bae9bc5325e6 Signed-off-by: Stefan Beller --- .../eclipse/jgit/gitrepo/RepoCommandTest.java | 48 +++++++++++++++++++ .../eclipse/jgit/gitrepo/ManifestParser.java | 2 + .../org/eclipse/jgit/gitrepo/RepoCommand.java | 33 +++++++++++-- .../org/eclipse/jgit/gitrepo/RepoProject.java | 26 +++++++++- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index d12e5fc0e..80a0250de 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -44,6 +44,7 @@ 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.BufferedReader; @@ -800,6 +801,53 @@ public void testRecordSubmoduleLabels() throws Exception { } } + @Test + public void testRecordShallowRecommendation() throws Exception { + try ( + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository()) { + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("\n") + .append("") + .append("") + .append("") + .append("") + .append("") + .append(""); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri) + .setRecommendShallow(true) + .call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = Git.cloneRepository() + .setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository();) { + // The .gitmodules file should exist + File gitmodules = new File(localDb.getWorkTree(), + ".gitmodules"); + assertTrue("The .gitmodules file should exist", + gitmodules.exists()); + FileBasedConfig c = new FileBasedConfig(gitmodules, + FS.DETECTED); + c.load(); + assertEquals("Recording shallow configuration should work", "true", + c.getString("submodule", "shallow-please", "shallow")); + assertNull("Recording non shallow configuration should work", + c.getString("submodule", "non-shallow", "shallow")); + } + } + } + @Test public void testRemoteRevision() throws Exception { StringBuilder xmlContent = new StringBuilder(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java index 796b422bb..2370ae14c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java @@ -192,6 +192,8 @@ public void startElement( attributes.getValue("revision"), //$NON-NLS-1$ attributes.getValue("remote"), //$NON-NLS-1$ attributes.getValue("groups")); //$NON-NLS-1$ + currentProject.setRecommendShallow( + attributes.getValue("clone-depth")); //$NON-NLS-1$ } else if ("remote".equals(qName)) { //$NON-NLS-1$ String alias = attributes.getValue("alias"); //$NON-NLS-1$ String fetch = attributes.getValue("fetch"); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index 6f682ee98..ef634f3d6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -113,6 +113,7 @@ public class RepoCommand extends GitCommand { private String targetBranch = Constants.HEAD; private boolean recordRemoteBranch = false; private boolean recordSubmoduleLabels = false; + private boolean recordShallowSubmodules = false; private PersonIdent author; private RemoteReader callback; private InputStream inputStream; @@ -362,6 +363,21 @@ public RepoCommand setRecordSubmoduleLabels(boolean enable) { return this; } + /** + * Set whether the clone-depth field should be recorded as a shallow + * recommendation in .gitmodules. + *

+ * Not implemented for non-bare repositories. + * + * @param enable Whether to record the shallow recommendation. + * @return this command + * @since 4.4 + */ + public RepoCommand setRecommendShallow(boolean enable) { + this.recordShallowSubmodules = enable; + return this; + } + /** * The progress monitor associated with the clone operation. By default, * this is set to NullProgressMonitor @@ -471,7 +487,8 @@ public RevCommit call() throws GitAPIException { proj.getPath(), proj.getRevision(), proj.getCopyFiles(), - proj.getGroups()); + proj.getGroups(), + proj.getRecommendShallow()); } } catch (GitAPIException | IOException e) { throw new ManifestErrorException(e); @@ -512,6 +529,16 @@ public RevCommit call() throws GitAPIException { cfg.setString("submodule", name, "branch", //$NON-NLS-1$ //$NON-NLS-2$ proj.getRevision()); } + + if (recordShallowSubmodules && proj.getRecommendShallow() != null) { + // The shallow recommendation is losing information. + // As the repo manifests stores the recommended + // depth in the 'clone-depth' field, while + // git core only uses a binary 'shallow = true/false' + // hint, we'll map any depth to 'shallow = true' + cfg.setBoolean("submodule", name, "shallow", //$NON-NLS-1$ //$NON-NLS-2$ + true); + } } if (recordSubmoduleLabels) { StringBuilder rec = new StringBuilder(); @@ -616,10 +643,10 @@ public RevCommit call() throws GitAPIException { } private void addSubmodule(String url, String name, String revision, - List copyfiles, Set groups) + List copyfiles, Set groups, String recommendShallow) throws GitAPIException, IOException { if (repo.isBare()) { - RepoProject proj = new RepoProject(url, name, revision, null, groups); + RepoProject proj = new RepoProject(url, name, revision, null, groups, recommendShallow); proj.addCopyFiles(copyfiles); bareProjects.add(proj); } else { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java index 1b251368d..bcc7ffc21 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java @@ -70,6 +70,7 @@ public class RepoProject implements Comparable { private final String remote; private final Set groups; private final List copyfiles; + private String recommendShallow; private String url; private String defaultRevision; @@ -138,7 +139,8 @@ public void copy() throws IOException { * @since 4.4 */ public RepoProject(String name, String path, String revision, - String remote, Set groups) { + String remote, Set groups, + String recommendShallow) { if (name == null) { throw new NullPointerException(); } @@ -150,6 +152,7 @@ public RepoProject(String name, String path, String revision, this.revision = revision; this.remote = remote; this.groups = groups; + this.recommendShallow = recommendShallow; copyfiles = new ArrayList(); } @@ -167,7 +170,7 @@ public RepoProject(String name, String path, String revision, */ public RepoProject(String name, String path, String revision, String remote, String groups) { - this(name, path, revision, remote, new HashSet()); + this(name, path, revision, remote, new HashSet(), null); if (groups != null && groups.length() > 0) this.setGroups(groups); } @@ -281,6 +284,25 @@ public Set getGroups() { return groups; } + /** + * Return the recommendation for shallowness. + * + * @return the String of "clone-depth" + * @since 4.4 + */ + public String getRecommendShallow() { + return recommendShallow; + } + + /** + * Sets the recommendation for shallowness. + * + * @since 4.4 + */ + public void setRecommendShallow(String recommendShallow) { + this.recommendShallow = recommendShallow; + } + /** * Add a copy file configuration. *