Merge changes from topic 'sshd'
* changes:
sshd: add missing javadoc in SshTestGitServer
sshd: shared reference in JGitClientSession must be volatile
sshd: correct the protocol version exchange
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
index 51de8ab..1c5e7ec 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java
@@ -248,13 +248,13 @@
.through(enabled)//
.with(new TextFileServlet(Constants.HEAD));
- final String info_alternates = "objects/info/alternates";
+ final String info_alternates = Constants.OBJECTS + "/" + Constants.INFO_ALTERNATES;
serve("*/" + info_alternates)//
.through(mustBeLocal)//
.through(enabled)//
.with(new TextFileServlet(info_alternates));
- final String http_alternates = "objects/info/http-alternates";
+ final String http_alternates = Constants.OBJECTS + "/" + Constants.INFO_HTTP_ALTERNATES;
serve("*/" + http_alternates)//
.through(mustBeLocal)//
.through(enabled)//
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
index 4c46bbd..8dba09c 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/Lfs.java
@@ -42,6 +42,8 @@
*/
package org.eclipse.jgit.lfs;
+import static org.eclipse.jgit.lib.Constants.OBJECTS;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -104,7 +106,7 @@
*/
public Path getLfsObjDir() {
if (objDir == null) {
- objDir = root.resolve("objects"); //$NON-NLS-1$
+ objDir = root.resolve(OBJECTS);
}
return objDir;
}
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
index a830ff2..befb7f6 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
@@ -211,6 +211,14 @@
.replaceAll("\t", "\\\\t");
}
+ protected String shellQuote(String s) {
+ return "'" + s.replace("'", "'\\''") + "'";
+ }
+
+ protected String shellQuote(File f) {
+ return "'" + f.getPath().replace("'", "'\\''") + "'";
+ }
+
protected void assertStringArrayEquals(String expected, String[] actual) {
// if there is more than one line, ignore last one if empty
assertEquals(1,
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index e07fdd5..03aa469 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -139,10 +139,6 @@
listTarEntries(result));
}
- private static String shellQuote(String s) {
- return "'" + s.replace("'", "'\\''") + "'";
- }
-
@Test
public void testFormatOverridesFilename() throws Exception {
File archive = new File(db.getWorkTree(), "format-overrides-name.tar");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
index 2c0abd7..c31f28c 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -78,9 +78,9 @@
File gitDir = db.getDirectory();
String sourceURI = gitDir.toURI().toString();
File target = createTempDirectory("target");
- StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
- + " " + target.getPath());
- String[] result = execute(cmd.toString());
+ String cmd = "git clone " + sourceURI + " "
+ + shellQuote(target.getPath());
+ String[] result = execute(cmd);
assertArrayEquals(new String[] {
"Cloning into '" + target.getPath() + "'...",
"", "" }, result);
@@ -101,9 +101,9 @@
File gitDir = db.getDirectory();
String sourceURI = gitDir.toURI().toString();
File target = createTempDirectory("target");
- StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
- + " " + target.getPath());
- String[] result = execute(cmd.toString());
+ String cmd = "git clone " + sourceURI + " "
+ + shellQuote(target.getPath());
+ String[] result = execute(cmd);
assertArrayEquals(new String[] {
"Cloning into '" + target.getPath() + "'...",
"warning: You appear to have cloned an empty repository.", "",
@@ -125,8 +125,8 @@
File gitDir = db.getDirectory();
String sourceURI = gitDir.toURI().toString();
String name = new URIish(sourceURI).getHumanishName();
- StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI);
- String[] result = execute(cmd.toString());
+ String cmd = "git clone " + sourceURI;
+ String[] result = execute(cmd);
assertArrayEquals(new String[] {
"Cloning into '" + new File(target, name).getName() + "'...",
"", "" }, result);
@@ -143,10 +143,10 @@
String sourcePath = gitDir.getAbsolutePath();
String targetPath = (new File(sourcePath)).getParentFile()
.getParentFile().getAbsolutePath()
- + "/target.git";
- StringBuilder cmd = new StringBuilder("git clone --bare ")
- .append(sourcePath + " " + targetPath);
- String[] result = execute(cmd.toString());
+ + File.separator + "target.git";
+ String cmd = "git clone --bare " + shellQuote(sourcePath) + " "
+ + shellQuote(targetPath);
+ String[] result = execute(cmd);
assertArrayEquals(new String[] {
"Cloning into '" + targetPath + "'...", "", "" }, result);
Git git2 = Git.open(new File(targetPath));
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
index ba6b771..fd3c383 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
@@ -80,7 +80,7 @@
@Test
public void testLsRemote() throws Exception {
final List<String> result = CLIGitCommand.execute(
- "git ls-remote " + db.getDirectory(), db);
+ "git ls-remote " + shellQuote(db.getDirectory()), db);
assertArrayEquals(new String[] {
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c HEAD",
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/master",
@@ -98,7 +98,8 @@
public void testLsRemoteHeads() throws Exception {
final List<String> result = CLIGitCommand.execute(
"git ls-remote --heads "
- + db.getDirectory(), db);
+ + shellQuote(db.getDirectory()),
+ db);
assertArrayEquals(new String[] {
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/master",
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/test",
@@ -108,7 +109,7 @@
@Test
public void testLsRemoteTags() throws Exception {
final List<String> result = CLIGitCommand.execute(
- "git ls-remote --tags " + db.getDirectory(), db);
+ "git ls-remote --tags " + shellQuote(db.getDirectory()), db);
assertArrayEquals(new String[] {
"efc02078d83a5226986ae917323acec7e1e8b7cb refs/tags/tag1",
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/tags/tag1^{}",
@@ -122,7 +123,8 @@
@Test
public void testLsRemoteHeadsTags() throws Exception {
final List<String> result = CLIGitCommand.execute(
- "git ls-remote --heads --tags " + db.getDirectory(), db);
+ "git ls-remote --heads --tags " + shellQuote(db.getDirectory()),
+ db);
assertArrayEquals(new String[] {
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/master",
"d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/test",
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
index b09db03..2306e0b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AlternatesTest.java
@@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.internal.storage.file;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
import static org.junit.Assert.assertTrue;
import java.io.File;
@@ -76,7 +77,7 @@
private void setAlternate(FileRepository from, FileRepository to)
throws IOException {
File alt = new File(from.getObjectDatabase().getDirectory(),
- "info/alternates");
+ INFO_ALTERNATES);
alt.getParentFile().mkdirs();
File fromDir = from.getObjectDatabase().getDirectory();
File toDir = to.getObjectDatabase().getDirectory();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 5d0a7e2..1e2341b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.file;
import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -138,7 +139,7 @@
config = new PackConfig(db);
dst = createBareRepository();
- File alt = new File(dst.getObjectDatabase().getDirectory(), "info/alternates");
+ File alt = new File(dst.getObjectDatabase().getDirectory(), INFO_ALTERNATES);
alt.getParentFile().mkdirs();
write(alt, db.getObjectDatabase().getDirectory().getAbsolutePath() + "\n");
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index c613849..825d15b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -96,7 +96,7 @@
public void test001_Initalize() {
final File gitdir = new File(trash, Constants.DOT_GIT);
final File hooks = new File(gitdir, "hooks");
- final File objects = new File(gitdir, "objects");
+ final File objects = new File(gitdir, Constants.OBJECTS);
final File objects_pack = new File(objects, "pack");
final File objects_info = new File(objects, "info");
final File refs = new File(gitdir, "refs");
@@ -148,7 +148,7 @@
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -174,7 +174,7 @@
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent.getParentFile(), r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -198,7 +198,7 @@
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -227,7 +227,7 @@
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -256,7 +256,7 @@
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkTree());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
- assertEqualsPath(new File(theDir, "objects"), r.getObjectDatabase()
+ assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase()
.getDirectory());
}
@@ -312,7 +312,7 @@
}
final File o = new File(new File(new File(newdb.getDirectory(),
- "objects"), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
+ Constants.OBJECTS), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
assertTrue("Exists " + o, o.isFile());
assertTrue("Read-only " + o, !o.canWrite());
}
@@ -324,7 +324,7 @@
final ObjectId treeId = insertTree(new TreeFormatter());
assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", treeId.name());
final File o = new File(new File(
- new File(db.getDirectory(), "objects"), "4b"),
+ new File(db.getDirectory(), Constants.OBJECTS), "4b"),
"825dc642cb6eb9a060e54bf8d69288fbee4904");
assertFalse("Exists " + o, o.isFile());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java
new file mode 100644
index 0000000..ea7e8ed
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PostUploadHookChainTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * 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.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.storage.pack.PackStatistics;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PostUploadHookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ PostUploadHook[] noHooks = {};
+ PostUploadHook newChain = PostUploadHookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, PostUploadHook.NULL);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakePostUploadHook hook1 = new FakePostUploadHook();
+ PostUploadHook newChain = PostUploadHookChain
+ .newChain(Arrays.asList(PostUploadHook.NULL, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() {
+ FakePostUploadHook hook1 = new FakePostUploadHook();
+ FakePostUploadHook hook2 = new FakePostUploadHook();
+
+ PostUploadHook chained = PostUploadHookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onPostUpload(null);
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakePostUploadHook implements PostUploadHook {
+ boolean invoked;
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+
+ @Override
+ public void onPostUpload(PackStatistics stats) {
+ invoked = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java
new file mode 100644
index 0000000..2a36d8a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PreUploadHookChainTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * 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.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PreUploadHookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ PreUploadHook[] noHooks = {};
+ PreUploadHook newChain = PreUploadHookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, PreUploadHook.NULL);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakePreUploadHook hook1 = new FakePreUploadHook();
+ PreUploadHook newChain = PreUploadHookChain
+ .newChain(Arrays.asList(PreUploadHook.NULL, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() throws ServiceMayNotContinueException {
+ FakePreUploadHook hook1 = new FakePreUploadHook();
+ FakePreUploadHook hook2 = new FakePreUploadHook();
+
+ PreUploadHook chained = PreUploadHookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onBeginNegotiateRound(null, null, 0);
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakePreUploadHook implements PreUploadHook {
+ boolean invoked;
+
+ @Override
+ public void onBeginNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntOffered)
+ throws ServiceMayNotContinueException {
+ invoked = true;
+ }
+
+ @Override
+ public void onEndNegotiateRound(UploadPack up,
+ Collection<? extends ObjectId> wants, int cntCommon,
+ int cntNotFound, boolean ready)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onSendPack(UploadPack up,
+ Collection<? extends ObjectId> wants,
+ Collection<? extends ObjectId> haves)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java
new file mode 100644
index 0000000..8fb1ca8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2HookChainTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * 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.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ProtocolV2HookChainTest {
+
+ @Test
+ public void testDefaultIfEmpty() {
+ ProtocolV2Hook[] noHooks = {};
+ ProtocolV2Hook newChain = ProtocolV2HookChain
+ .newChain(Arrays.asList(noHooks));
+ assertEquals(newChain, ProtocolV2Hook.DEFAULT);
+ }
+
+ @Test
+ public void testFlattenChainIfOnlyOne() {
+ FakeProtocolV2Hook hook1 = new FakeProtocolV2Hook();
+ ProtocolV2Hook newChain = ProtocolV2HookChain
+ .newChain(Arrays.asList(ProtocolV2Hook.DEFAULT, hook1));
+ assertEquals(newChain, hook1);
+ }
+
+ @Test
+ public void testMultipleHooks() throws ServiceMayNotContinueException {
+ FakeProtocolV2Hook hook1 = new FakeProtocolV2Hook();
+ FakeProtocolV2Hook hook2 = new FakeProtocolV2Hook();
+
+ ProtocolV2Hook chained = ProtocolV2HookChain
+ .newChain(Arrays.asList(hook1, hook2));
+ chained.onLsRefs(LsRefsV2Request.builder().build());
+
+ assertTrue(hook1.wasInvoked());
+ assertTrue(hook2.wasInvoked());
+ }
+
+ private static final class FakeProtocolV2Hook implements ProtocolV2Hook {
+ boolean invoked;
+
+ @Override
+ public void onLsRefs(LsRefsV2Request req)
+ throws ServiceMayNotContinueException {
+ invoked = true;
+ }
+
+ @Override
+ public void onCapabilities(CapabilitiesV2Request req)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onFetch(FetchV2Request req)
+ throws ServiceMayNotContinueException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean wasInvoked() {
+ return invoked;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 0ef29d4..22c67c1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -1,6 +1,7 @@
package org.eclipse.jgit.transport;
import static org.eclipse.jgit.lib.MoreAsserts.assertThrows;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
@@ -23,6 +24,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
@@ -423,22 +426,18 @@
* Invokes UploadPack with protocol v2 and sends it the given lines,
* and returns UploadPack's output stream.
*/
- private ByteArrayInputStream uploadPackV2Setup(RequestPolicy requestPolicy,
- RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
+ private ByteArrayInputStream uploadPackV2Setup(
+ Consumer<UploadPack> postConstructionSetup, String... inputLines)
throws Exception {
ByteArrayInputStream send = linesAsInputStream(inputLines);
server.getConfig().setString("protocol", null, "version", "2");
UploadPack up = new UploadPack(server);
- if (requestPolicy != null)
- up.setRequestPolicy(requestPolicy);
- if (refFilter != null)
- up.setRefFilter(refFilter);
- up.setExtraParameters(Sets.of("version=2"));
- if (hook != null) {
- up.setProtocolV2Hook(hook);
+ if (postConstructionSetup != null) {
+ postConstructionSetup.accept(up);
}
+ up.setExtraParameters(Sets.of("version=2"));
ByteArrayOutputStream recv = new ByteArrayOutputStream();
up.upload(send, recv, null);
@@ -452,6 +451,7 @@
try (ByteArrayOutputStream send = new ByteArrayOutputStream()) {
PacketLineOut pckOut = new PacketLineOut(send);
for (String line : inputLines) {
+ Objects.requireNonNull(line);
if (PacketLineIn.isEnd(line)) {
pckOut.end();
} else if (PacketLineIn.isDelimiter(line)) {
@@ -469,11 +469,12 @@
* Returns UploadPack's output stream, not including the capability
* advertisement by the server.
*/
- private ByteArrayInputStream uploadPackV2(RequestPolicy requestPolicy,
- RefFilter refFilter, ProtocolV2Hook hook, String... inputLines)
+ private ByteArrayInputStream uploadPackV2(
+ Consumer<UploadPack> postConstructionSetup,
+ String... inputLines)
throws Exception {
ByteArrayInputStream recvStream =
- uploadPackV2Setup(requestPolicy, refFilter, hook, inputLines);
+ uploadPackV2Setup(postConstructionSetup, inputLines);
PacketLineIn pckIn = new PacketLineIn(recvStream);
// drain capabilities
@@ -484,7 +485,7 @@
}
private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception {
- return uploadPackV2(null, null, null, inputLines);
+ return uploadPackV2(null, inputLines);
}
private static class TestV2Hook implements ProtocolV2Hook {
@@ -513,8 +514,9 @@
@Test
public void testV2Capabilities() throws Exception {
TestV2Hook hook = new TestV2Hook();
- ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, hook, PacketLineIn.end());
+ ByteArrayInputStream recvStream = uploadPackV2Setup(
+ (UploadPack up) -> {up.setProtocolV2Hook(hook);},
+ PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(hook.capabilitiesRequest, notNullValue());
assertThat(pckIn.readString(), is("version 2"));
@@ -531,54 +533,72 @@
assertTrue(PacketLineIn.isEnd(pckIn.readString()));
}
- @Test
- public void testV2CapabilitiesAllowFilter() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowfilter", true);
+ private void checkAdvertisedIfAllowed(String configSection, String configName,
+ String fetchCapability) throws Exception {
+ server.getConfig().setBoolean(configSection, null, configName, true);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
+ uploadPackV2Setup(null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- // TODO(jonathantanmy) This check overspecifies the
- // order of the capabilities of "fetch".
- hasItems("ls-refs", "fetch=filter shallow", "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+
+ ArrayList<String> lines = new ArrayList<>();
+ String line;
+ while (!PacketLineIn.isEnd((line = pckIn.readString()))) {
+ if (line.startsWith("fetch=")) {
+ assertThat(
+ Arrays.asList(line.substring(6).split(" ")),
+ containsInAnyOrder(fetchCapability, "shallow"));
+ lines.add("fetch");
+ } else {
+ lines.add(line);
+ }
+ }
+ assertThat(lines, containsInAnyOrder("ls-refs", "fetch", "server-option"));
+ }
+
+ private void checkUnadvertisedIfUnallowed(String fetchCapability) throws Exception {
+ ByteArrayInputStream recvStream =
+ uploadPackV2Setup(null, PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ assertThat(pckIn.readString(), is("version 2"));
+
+ ArrayList<String> lines = new ArrayList<>();
+ String line;
+ while (!PacketLineIn.isEnd((line = pckIn.readString()))) {
+ if (line.startsWith("fetch=")) {
+ assertThat(
+ Arrays.asList(line.substring(6).split(" ")),
+ hasItems("shallow"));
+ lines.add("fetch");
+ } else {
+ lines.add(line);
+ }
+ }
+ assertThat(lines, hasItems("ls-refs", "fetch", "server-option"));
+ }
+
+ @Test
+ public void testV2CapabilitiesAllowFilter() throws Exception {
+ checkAdvertisedIfAllowed("uploadpack", "allowfilter", "filter");
+ checkUnadvertisedIfUnallowed("filter");
}
@Test
public void testV2CapabilitiesRefInWant() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
- ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
- PacketLineIn pckIn = new PacketLineIn(recvStream);
-
- assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- // TODO(jonathantanmy) This check overspecifies the
- // order of the capabilities of "fetch".
- hasItems("ls-refs", "fetch=ref-in-want shallow",
- "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ checkAdvertisedIfAllowed("uploadpack", "allowrefinwant", "ref-in-want");
}
@Test
public void testV2CapabilitiesRefInWantNotAdvertisedIfUnallowed() throws Exception {
- server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", false);
- ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
- PacketLineIn pckIn = new PacketLineIn(recvStream);
+ checkUnadvertisedIfUnallowed("ref-in-want");
+ }
- assertThat(pckIn.readString(), is("version 2"));
- assertThat(
- Arrays.asList(pckIn.readString(), pckIn.readString(),
- pckIn.readString()),
- hasItems("ls-refs", "fetch=shallow", "server-option"));
- assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ @Test
+ public void testV2CapabilitiesAllowSidebandAll() throws Exception {
+ checkAdvertisedIfAllowed("uploadpack", "allowsidebandall", "sideband-all");
+ checkUnadvertisedIfUnallowed("sideband-all");
}
@Test
@@ -586,7 +606,7 @@
server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, null, null, PacketLineIn.end());
+ uploadPackV2Setup(null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
@@ -614,7 +634,8 @@
remote.update("refs/tags/tag", tag);
TestV2Hook hook = new TestV2Hook();
- ByteArrayInputStream recvStream = uploadPackV2(null, null, hook,
+ ByteArrayInputStream recvStream = uploadPackV2(
+ (UploadPack up) -> {up.setProtocolV2Hook(hook);},
"command=ls-refs\n", PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
@@ -749,7 +770,7 @@
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup(null, null, testHook, lines);
+ uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
LsRefsV2Request req = testHook.lsRefsRequest;
assertEquals(2, req.getServerOptions().size());
@@ -785,14 +806,18 @@
remote.update("branch1", advertized);
// This works
- uploadPackV2(RequestPolicy.ADVERTISED, null, null, "command=fetch\n",
- PacketLineIn.delimiter(), "want " + advertized.name() + "\n",
- PacketLineIn.end());
+ uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ADVERTISED);},
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + advertized.name() + "\n",
+ PacketLineIn.end());
// This doesn't
UploadPackInternalServerErrorException e = assertThrows(
UploadPackInternalServerErrorException.class,
- () -> uploadPackV2(RequestPolicy.ADVERTISED, null, null,
+ () -> uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ADVERTISED);},
"command=fetch\n", PacketLineIn.delimiter(),
"want " + unadvertized.name() + "\n",
PacketLineIn.end()));
@@ -809,14 +834,18 @@
remote.update("branch1", advertized);
// This works
- uploadPackV2(RequestPolicy.REACHABLE_COMMIT, null, null,
- "command=fetch\n", PacketLineIn.delimiter(),
- "want " + reachable.name() + "\n", PacketLineIn.end());
+ uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + reachable.name() + "\n",
+ PacketLineIn.end());
// This doesn't
UploadPackInternalServerErrorException e = assertThrows(
UploadPackInternalServerErrorException.class,
- () -> uploadPackV2(RequestPolicy.REACHABLE_COMMIT, null, null,
+ () -> uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
"command=fetch\n", PacketLineIn.delimiter(),
"want " + unreachable.name() + "\n",
PacketLineIn.end()));
@@ -832,15 +861,25 @@
remote.update("secret", tip);
// This works
- uploadPackV2(RequestPolicy.TIP, new RejectAllRefFilter(), null,
- "command=fetch\n", PacketLineIn.delimiter(),
- "want " + tip.name() + "\n", PacketLineIn.end());
+ uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + tip.name() + "\n",
+ PacketLineIn.end());
// This doesn't
UploadPackInternalServerErrorException e = assertThrows(
UploadPackInternalServerErrorException.class,
- () -> uploadPackV2(RequestPolicy.TIP, new RejectAllRefFilter(),
- null, "command=fetch\n", PacketLineIn.delimiter(),
+ () -> uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n", PacketLineIn.delimiter(),
"want " + parentOfTip.name() + "\n",
PacketLineIn.end()));
assertThat(e.getCause().getMessage(),
@@ -856,16 +895,24 @@
remote.update("secret", tip);
// This works
- uploadPackV2(RequestPolicy.REACHABLE_COMMIT_TIP,
- new RejectAllRefFilter(), null, "command=fetch\n",
+ uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT_TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n",
PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n",
PacketLineIn.end());
// This doesn't
UploadPackInternalServerErrorException e = assertThrows(
UploadPackInternalServerErrorException.class,
- () -> uploadPackV2(RequestPolicy.REACHABLE_COMMIT_TIP,
- new RejectAllRefFilter(), null, "command=fetch\n",
+ () -> uploadPackV2(
+ (UploadPack up) -> {
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT_TIP);
+ up.setRefFilter(new RejectAllRefFilter());
+ },
+ "command=fetch\n",
PacketLineIn.delimiter(),
"want " + unreachable.name() + "\n",
PacketLineIn.end()));
@@ -879,9 +926,7 @@
// Exercise to make sure that even unreachable commits can be fetched
uploadPackV2(
- RequestPolicy.ANY,
- null,
- null,
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ANY);},
"command=fetch\n",
PacketLineIn.delimiter(),
"want " + unreachable.name() + "\n",
@@ -1481,7 +1526,7 @@
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup(null, null, testHook, lines);
+ uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
FetchV2Request req = testHook.fetchRequest;
assertNotNull(req);
@@ -1565,8 +1610,9 @@
input.add("done\n");
input.add(PacketLineIn.end());
ByteArrayInputStream recvStream =
- uploadPackV2(RequestPolicy.ANY, /*refFilter=*/null,
- /*hook=*/null, input.toArray(new String[0]));
+ uploadPackV2(
+ (UploadPack up) -> {up.setRequestPolicy(RequestPolicy.ANY);},
+ input.toArray(new String[0]));
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("packfile"));
parsePack(recvStream);
@@ -1833,34 +1879,39 @@
.has(preparator.subtree3.toObjectId()));
}
- @Test
- public void testV2FetchFilterWhenNotAllowed() throws Exception {
+ private void checkV2FetchWhenNotAllowed(String fetchLine, String expectedMessage)
+ throws Exception {
RevCommit commit = remote.commit().message("0").create();
remote.update("master", commit);
- server.getConfig().setBoolean("uploadpack", null, "allowfilter", false);
-
UploadPackInternalServerErrorException e = assertThrows(
UploadPackInternalServerErrorException.class,
() -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
"want " + commit.toObjectId().getName() + "\n",
- "filter blob:limit=5\n", "done\n", PacketLineIn.end()));
+ fetchLine, "done\n", PacketLineIn.end()));
assertThat(e.getCause().getMessage(),
- containsString("unexpected filter blob:limit=5"));
+ containsString(expectedMessage));
+ }
+
+ @Test
+ public void testV2FetchFilterWhenNotAllowed() throws Exception {
+ checkV2FetchWhenNotAllowed(
+ "filter blob:limit=5\n",
+ "unexpected filter blob:limit=5");
}
@Test
public void testV2FetchWantRefIfNotAllowed() throws Exception {
- RevCommit one = remote.commit().message("1").create();
- remote.update("one", one);
+ checkV2FetchWhenNotAllowed(
+ "want-ref refs/heads/one\n",
+ "unexpected want-ref refs/heads/one");
+ }
- UploadPackInternalServerErrorException e = assertThrows(
- UploadPackInternalServerErrorException.class,
- () -> uploadPackV2("command=fetch\n", PacketLineIn.delimiter(),
- "want-ref refs/heads/one\n", "done\n",
- PacketLineIn.end()));
- assertThat(e.getCause().getMessage(),
- containsString("unexpected want-ref refs/heads/one"));
+ @Test
+ public void testV2FetchSidebandAllIfNotAllowed() throws Exception {
+ checkV2FetchWhenNotAllowed(
+ "sideband-all\n",
+ "unexpected sideband-all");
}
@Test
@@ -2047,6 +2098,58 @@
}
@Test
+ public void testV2FetchSidebandAllNoPackfile() throws Exception {
+ RevCommit fooParent = remote.commit().message("x").create();
+ RevCommit fooChild = remote.commit().message("x").parent(fooParent).create();
+ RevCommit barParent = remote.commit().message("y").create();
+ RevCommit barChild = remote.commit().message("y").parent(barParent).create();
+ remote.update("branch1", fooChild);
+ remote.update("branch2", barChild);
+
+ server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.DELIM,
+ "sideband-all\n",
+ "want " + fooChild.toObjectId().getName() + "\n",
+ "want " + barChild.toObjectId().getName() + "\n",
+ "have " + fooParent.toObjectId().getName() + "\n",
+ PacketLineIn.END);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ assertThat(pckIn.readString(), is("\001acknowledgments"));
+ assertThat(pckIn.readString(), is("\001ACK " + fooParent.getName()));
+ assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ }
+
+ @Test
+ public void testV2FetchSidebandAllPackfile() throws Exception {
+ RevCommit commit = remote.commit().message("x").create();
+ remote.update("master", commit);
+
+ server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true);
+
+ ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n",
+ PacketLineIn.DELIM,
+ "want " + commit.getName() + "\n",
+ "sideband-all\n",
+ "done\n",
+ PacketLineIn.END);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ String s;
+ // When sideband-all is used, object counting happens before
+ // "packfile" is written, and object counting outputs progress
+ // in sideband 2. Skip all these lines.
+ for (s = pckIn.readString(); s.startsWith("\002"); s = pckIn.readString()) {
+ // do nothing
+ }
+ assertThat(s, is("\001packfile"));
+ parsePack(recvStream);
+ }
+
+ @Test
public void testGetPeerAgentProtocolV0() throws Exception {
RevCommit one = remote.commit().message("1").create();
remote.update("one", one);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 258ccee..968ade6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -171,7 +171,7 @@
infoDirectory = new File(objects, "info"); //$NON-NLS-1$
packDirectory = new File(objects, "pack"); //$NON-NLS-1$
preservedDirectory = new File(packDirectory, "preserved"); //$NON-NLS-1$
- alternatesFile = new File(infoDirectory, "alternates"); //$NON-NLS-1$
+ alternatesFile = new File(objects, Constants.INFO_ALTERNATES);
packList = new AtomicReference<>(NO_PACKS);
unpackedObjectCache = new UnpackedObjectCache();
this.fs = fs;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index d1cf1cd..96e5066 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -681,7 +681,7 @@
*/
protected void setupInternals() throws IOException {
if (getObjectDirectory() == null && getGitDir() != null)
- setObjectDirectory(safeFS().resolve(getGitDir(), "objects")); //$NON-NLS-1$
+ setObjectDirectory(safeFS().resolve(getGitDir(), Constants.OBJECTS));
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 8f4468e..a084c82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -275,9 +275,27 @@
/** Logs folder name */
public static final String LOGS = "logs";
+ /**
+ * Objects folder name
+ * @since 5.5
+ */
+ public static final String OBJECTS = "objects";
+
/** Info refs folder */
public static final String INFO_REFS = "info/refs";
+ /**
+ * Info alternates file (goes under OBJECTS)
+ * @since 5.5
+ */
+ public static final String INFO_ALTERNATES = "info/alternates";
+
+ /**
+ * HTTP alternates file (goes under OBJECTS)
+ * @since 5.5
+ */
+ public static final String INFO_HTTP_ALTERNATES = "info/http-alternates";
+
/** Packed refs file */
public static final String PACKED_REFS = "packed-refs";
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
index 27befba..fa113bf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -474,7 +474,7 @@
* Git directory.
*/
public static boolean isGitRepository(File dir, FS fs) {
- return fs.resolve(dir, "objects").exists() //$NON-NLS-1$
+ return fs.resolve(dir, Constants.OBJECTS).exists()
&& fs.resolve(dir, "refs").exists() //$NON-NLS-1$
&& isValidHead(new File(dir, Constants.HEAD));
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
index 6c24269..86574c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
@@ -72,6 +72,8 @@
@NonNull
private final List<String> serverOptions;
+ private final boolean sidebandAll;
+
FetchV2Request(@NonNull List<ObjectId> peerHas,
@NonNull List<String> wantedRefs,
@NonNull Set<ObjectId> wantIds,
@@ -79,7 +81,8 @@
@NonNull List<String> deepenNotRefs, int depth,
@NonNull FilterSpec filterSpec,
boolean doneReceived, @NonNull Set<String> clientCapabilities,
- @Nullable String agent, @NonNull List<String> serverOptions) {
+ @Nullable String agent, @NonNull List<String> serverOptions,
+ boolean sidebandAll) {
super(wantIds, depth, clientShallowCommits, filterSpec,
clientCapabilities, deepenSince,
deepenNotRefs, agent);
@@ -87,6 +90,7 @@
this.wantedRefs = requireNonNull(wantedRefs);
this.doneReceived = doneReceived;
this.serverOptions = requireNonNull(serverOptions);
+ this.sidebandAll = sidebandAll;
}
/**
@@ -127,6 +131,13 @@
return serverOptions;
}
+ /**
+ * @return true if "sideband-all" was received
+ */
+ boolean getSidebandAll() {
+ return sidebandAll;
+ }
+
/** @return A builder of {@link FetchV2Request}. */
static Builder builder() {
return new Builder();
@@ -159,6 +170,8 @@
final List<String> serverOptions = new ArrayList<>();
+ boolean sidebandAll;
+
private Builder() {
}
@@ -318,13 +331,23 @@
}
/**
+ * @param value true if client sent "sideband-all"
+ * @return this builder
+ */
+ Builder setSidebandAll(boolean value) {
+ sidebandAll = value;
+ return this;
+ }
+
+ /**
* @return Initialized fetch request
*/
FetchV2Request build() {
return new FetchV2Request(peerHas, wantedRefs, wantIds,
clientShallowCommits, deepenSince, deepenNotRefs,
depth, filterSpec, doneReceived, clientCapabilities,
- agent, Collections.unmodifiableList(serverOptions));
+ agent, Collections.unmodifiableList(serverOptions),
+ sidebandAll);
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index 096bb67..e3c0bc6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -174,6 +174,14 @@
public static final String OPTION_WANT_REF = "want-ref"; //$NON-NLS-1$
/**
+ * The client requested that the whole response be multiplexed, with
+ * each non-flush and non-delim pkt prefixed by a sideband designator.
+ *
+ * @since 5.5
+ */
+ public static final String OPTION_SIDEBAND_ALL = "sideband-all"; //$NON-NLS-1$
+
+ /**
* The client supports atomic pushes. If this option is used, the server
* will update all refs within one atomic transaction.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
index 0bdd6ba..79af1eb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
@@ -551,7 +551,7 @@
* @param config
* to use
*/
- void setConfig(OpenSshConfig config) {
+ synchronized void setConfig(OpenSshConfig config) {
this.config = config;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
index e940091..7f837bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
@@ -74,6 +74,8 @@
private boolean flushOnEnd;
+ private boolean usingSideband;
+
/**
* Create a new packet line writer.
*
@@ -98,6 +100,28 @@
}
/**
+ * @return whether to add a sideband designator to each non-flush and
+ * non-delim packet
+ * @see #setUsingSideband
+ * @since 5.5
+ */
+ public boolean isUsingSideband() {
+ return usingSideband;
+ }
+
+ /**
+ * @param value If true, when writing packet lines, add, as the first
+ * byte, a sideband designator to each non-flush and non-delim
+ * packet. See pack-protocol.txt and protocol-v2.txt from the Git
+ * project for more information, specifically the "side-band" and
+ * "sideband-all" sections.
+ * @since 5.5
+ */
+ public void setUsingSideband(boolean value) {
+ this.usingSideband = value;
+ }
+
+ /**
* Write a UTF-8 encoded string as a single length-delimited packet.
*
* @param s
@@ -139,8 +163,14 @@
* @since 4.5
*/
public void writePacket(byte[] buf, int pos, int len) throws IOException {
- formatLength(len + 4);
- out.write(lenbuffer, 0, 4);
+ if (usingSideband) {
+ formatLength(len + 5);
+ out.write(lenbuffer, 0, 4);
+ out.write(1);
+ } else {
+ formatLength(len + 4);
+ out.write(lenbuffer, 0, 4);
+ }
out.write(buf, pos, len);
if (log.isDebugEnabled()) {
String s = RawParseUtils.decode(UTF_8, buf, pos, len);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
index 542abe7..4334888 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
@@ -42,7 +42,9 @@
package org.eclipse.jgit.transport;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.jgit.storage.pack.PackStatistics;
@@ -55,8 +57,7 @@
* @since 4.1
*/
public class PostUploadHookChain implements PostUploadHook {
- private final PostUploadHook[] hooks;
- private final int count;
+ private final List<PostUploadHook> hooks;
/**
* Create a new hook chaining the given hooks together.
@@ -65,29 +66,29 @@
* hooks to execute, in order.
* @return a new chain of the given hooks.
*/
- public static PostUploadHook newChain(List<? extends PostUploadHook> hooks) {
- PostUploadHook[] newHooks = new PostUploadHook[hooks.size()];
- int i = 0;
- for (PostUploadHook hook : hooks)
- if (hook != PostUploadHook.NULL)
- newHooks[i++] = hook;
- if (i == 0)
+ public static PostUploadHook newChain(List<PostUploadHook> hooks) {
+ List<PostUploadHook> newHooks = hooks.stream()
+ .filter(hook -> !hook.equals(PostUploadHook.NULL))
+ .collect(Collectors.toList());
+
+ if (newHooks.isEmpty()) {
return PostUploadHook.NULL;
- else if (i == 1)
- return newHooks[0];
- else
- return new PostUploadHookChain(newHooks, i);
+ } else if (newHooks.size() == 1) {
+ return newHooks.get(0);
+ } else {
+ return new PostUploadHookChain(newHooks);
+ }
}
/** {@inheritDoc} */
@Override
public void onPostUpload(PackStatistics stats) {
- for (int i = 0; i < count; i++)
- hooks[i].onPostUpload(stats);
+ for (PostUploadHook hook : hooks) {
+ hook.onPostUpload(stats);
+ }
}
- private PostUploadHookChain(PostUploadHook[] hooks, int count) {
- this.hooks = hooks;
- this.count = count;
+ private PostUploadHookChain(List<PostUploadHook> hooks) {
+ this.hooks = Collections.unmodifiableList(hooks);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
index bfd52af..2192654 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java
@@ -44,7 +44,9 @@
package org.eclipse.jgit.transport;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.jgit.lib.ObjectId;
@@ -56,8 +58,7 @@
* one hook throws an exception, execution of remaining hook methods is aborted.
*/
public class PreUploadHookChain implements PreUploadHook {
- private final PreUploadHook[] hooks;
- private final int count;
+ private final List<PreUploadHook> hooks;
/**
* Create a new hook chaining the given hooks together.
@@ -66,18 +67,18 @@
* hooks to execute, in order.
* @return a new hook chain of the given hooks.
*/
- public static PreUploadHook newChain(List<? extends PreUploadHook> hooks) {
- PreUploadHook[] newHooks = new PreUploadHook[hooks.size()];
- int i = 0;
- for (PreUploadHook hook : hooks)
- if (hook != PreUploadHook.NULL)
- newHooks[i++] = hook;
- if (i == 0)
+ public static PreUploadHook newChain(List<PreUploadHook> hooks) {
+ List<PreUploadHook> newHooks = hooks.stream()
+ .filter(hook -> !hook.equals(PreUploadHook.NULL))
+ .collect(Collectors.toList());
+
+ if (newHooks.isEmpty()) {
return PreUploadHook.NULL;
- else if (i == 1)
- return newHooks[0];
- else
- return new PreUploadHookChain(newHooks, i);
+ } else if (newHooks.size() == 1) {
+ return newHooks.get(0);
+ } else {
+ return new PreUploadHookChain(newHooks);
+ }
}
/** {@inheritDoc} */
@@ -85,8 +86,9 @@
public void onBeginNegotiateRound(UploadPack up,
Collection<? extends ObjectId> wants, int cntOffered)
throws ServiceMayNotContinueException {
- for (int i = 0; i < count; i++)
- hooks[i].onBeginNegotiateRound(up, wants, cntOffered);
+ for (PreUploadHook hook : hooks) {
+ hook.onBeginNegotiateRound(up, wants, cntOffered);
+ }
}
/** {@inheritDoc} */
@@ -95,8 +97,9 @@
Collection<? extends ObjectId> wants, int cntCommon,
int cntNotFound, boolean ready)
throws ServiceMayNotContinueException {
- for (int i = 0; i < count; i++)
- hooks[i].onEndNegotiateRound(up, wants, cntCommon, cntNotFound, ready);
+ for (PreUploadHook hook : hooks) {
+ hook.onEndNegotiateRound(up, wants, cntCommon, cntNotFound, ready);
+ }
}
/** {@inheritDoc} */
@@ -105,12 +108,12 @@
Collection<? extends ObjectId> wants,
Collection<? extends ObjectId> haves)
throws ServiceMayNotContinueException {
- for (int i = 0; i < count; i++)
- hooks[i].onSendPack(up, wants, haves);
+ for (PreUploadHook hook : hooks) {
+ hook.onSendPack(up, wants, haves);
+ }
}
- private PreUploadHookChain(PreUploadHook[] hooks, int count) {
- this.hooks = hooks;
- this.count = count;
+ private PreUploadHookChain(List<PreUploadHook> hooks) {
+ this.hooks = Collections.unmodifiableList(hooks);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java
new file mode 100644
index 0000000..cc36473
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019, Google LLC.
+ * 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.transport;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * {@link org.eclipse.jgit.transport.ProtocolV2Hook} that delegates to a list of
+ * other hooks.
+ * <p>
+ * Hooks are run in the order passed to the constructor. If running a method on
+ * one hook throws an exception, execution of remaining hook methods is aborted.
+ *
+ * @since 5.5
+ */
+public class ProtocolV2HookChain implements ProtocolV2Hook {
+ private final List<? extends ProtocolV2Hook> hooks;
+
+ /**
+ * Create a new hook chaining the given hooks together.
+ *
+ * @param hooks
+ * hooks to execute, in order.
+ * @return a new hook chain of the given hooks.
+ */
+ public static ProtocolV2Hook newChain(
+ List<? extends ProtocolV2Hook> hooks) {
+ List<? extends ProtocolV2Hook> newHooks = hooks.stream()
+ .filter(hook -> !hook.equals(ProtocolV2Hook.DEFAULT))
+ .collect(Collectors.toList());
+
+ if (newHooks.isEmpty()) {
+ return ProtocolV2Hook.DEFAULT;
+ } else if (newHooks.size() == 1) {
+ return newHooks.get(0);
+ } else {
+ return new ProtocolV2HookChain(newHooks);
+ }
+ }
+
+ @Override
+ public void onCapabilities(CapabilitiesV2Request req)
+ throws ServiceMayNotContinueException {
+ for (ProtocolV2Hook hook : hooks) {
+ hook.onCapabilities(req);
+ }
+ }
+
+ @Override
+ public void onLsRefs(LsRefsV2Request req)
+ throws ServiceMayNotContinueException {
+ for (ProtocolV2Hook hook : hooks) {
+ hook.onLsRefs(req);
+ }
+ }
+
+ @Override
+ public void onFetch(FetchV2Request req)
+ throws ServiceMayNotContinueException {
+ for (ProtocolV2Hook hook : hooks) {
+ hook.onFetch(req);
+ }
+ }
+
+ private ProtocolV2HookChain(List<? extends ProtocolV2Hook> hooks) {
+ this.hooks = Collections.unmodifiableList(hooks);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
index caba15f..453be7f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
@@ -49,6 +49,7 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_NO_PROGRESS;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_OFS_DELTA;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SERVER_OPTION;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_ALL;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_WANT_REF;
@@ -210,6 +211,9 @@
filterReceived = true;
reqBuilder.setFilterSpec(FilterSpec.fromFilterLine(
line2.substring(OPTION_FILTER.length() + 1)));
+ } else if (transferConfig.isAllowSidebandAll()
+ && line2.equals(OPTION_SIDEBAND_ALL)) {
+ reqBuilder.setSidebandAll(true);
} else {
throw new PackProtocolException(MessageFormat
.format(JGitText.get().unexpectedPacketLine, line2));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index a3e655c..758d74c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -131,6 +131,7 @@
private final boolean allowTipSha1InWant;
private final boolean allowReachableSha1InWant;
private final boolean allowFilter;
+ private final boolean allowSidebandAll;
final @Nullable ProtocolVersion protocolVersion;
final String[] hideRefs;
@@ -210,6 +211,8 @@
"uploadpack", "allowfilter", false);
protocolVersion = ProtocolVersion.parse(rc.getString("protocol", null, "version"));
hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
+ allowSidebandAll = rc.getBoolean(
+ "uploadpack", "allowsidebandall", false);
}
/**
@@ -292,6 +295,14 @@
}
/**
+ * @return true if clients are allowed to specify a "sideband-all" line
+ * @since 5.5
+ */
+ public boolean isAllowSidebandAll() {
+ return allowSidebandAll;
+ }
+
+ /**
* Get {@link org.eclipse.jgit.transport.RefFilter} respecting configured
* hidden refs.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
index 6118cb8..c0a70bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
@@ -259,7 +259,7 @@
@Override
Collection<WalkRemoteObjectDatabase> getAlternates() throws IOException {
try {
- return readAlternates(INFO_ALTERNATES);
+ return readAlternates(Constants.INFO_ALTERNATES);
} catch (FileNotFoundException err) {
// Fall through.
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 27ab879..d5b06c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -48,6 +48,8 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
+import static org.eclipse.jgit.lib.Constants.INFO_HTTP_ALTERNATES;
import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP;
import static org.eclipse.jgit.util.HttpSupport.ENCODING_X_GZIP;
import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
index 5c68308..8d91c60 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
@@ -43,7 +43,9 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.lib.Constants.INFO_ALTERNATES;
import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
+import static org.eclipse.jgit.lib.Constants.OBJECTS;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
@@ -172,7 +174,7 @@
try {
ftp = newSftp();
ftp.cd(path);
- ftp.cd("objects"); //$NON-NLS-1$
+ ftp.cd(OBJECTS);
objectsPath = ftp.pwd();
} catch (FtpChannel.FtpException f) {
throw new TransportException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 37ecead..2194f2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -61,6 +61,7 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_NO_PROGRESS;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_OFS_DELTA;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SHALLOW;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_ALL;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
@@ -278,8 +279,6 @@
private PacketLineIn pckIn;
- private PacketLineOut pckOut;
-
private OutputStream msgOut = NullOutputStream.INSTANCE;
/**
@@ -603,6 +602,18 @@
}
/**
+ * Get the currently installed protocol v2 hook.
+ *
+ * @return the hook or a default implementation if none installed.
+ *
+ * @since 5.5
+ */
+ public ProtocolV2Hook getProtocolV2Hook() {
+ return this.protocolV2Hook != null ? this.protocolV2Hook
+ : ProtocolV2Hook.DEFAULT;
+ }
+
+ /**
* Set the filter used while advertising the refs to the client.
* <p>
* Only refs allowed by this filter will be sent to the client. The filter
@@ -753,6 +764,7 @@
*/
public void upload(InputStream input, OutputStream output,
@Nullable OutputStream messages) throws IOException {
+ PacketLineOut pckOut = null;
try {
rawIn = input;
if (messages != null)
@@ -778,9 +790,9 @@
pckIn = new PacketLineIn(rawIn);
pckOut = new PacketLineOut(rawOut);
if (useProtocolV2()) {
- serviceV2();
+ serviceV2(pckOut);
} else {
- service();
+ service(pckOut);
}
} catch (UploadPackInternalServerErrorException err) {
// UploadPackInternalServerErrorException is a special exception
@@ -972,7 +984,7 @@
return RefDatabase.findRef(getAdvertisedOrDefaultRefs(), name);
}
- private void service() throws IOException {
+ private void service(PacketLineOut pckOut) throws IOException {
boolean sendPack = false;
// If it's a non-bidi request, we need to read the entire request before
// writing a response. Buffer the response until then.
@@ -1028,7 +1040,7 @@
if (!req.getClientShallowCommits().isEmpty())
walk.assumeShallow(req.getClientShallowCommits());
- sendPack = negotiate(req, accumulator);
+ sendPack = negotiate(req, accumulator, pckOut);
accumulator.timeNegotiating += System.currentTimeMillis()
- negotiateStart;
@@ -1054,11 +1066,11 @@
if (sendPack) {
sendPack(accumulator, req, refs == null ? null : refs.values(),
- unshallowCommits, Collections.emptyList());
+ unshallowCommits, Collections.emptyList(), pckOut);
}
}
- private void lsRefsV2() throws IOException {
+ private void lsRefsV2(PacketLineOut pckOut) throws IOException {
ProtocolV2Parser parser = new ProtocolV2Parser(transferConfig);
LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
protocolV2Hook.onLsRefs(req);
@@ -1103,7 +1115,7 @@
return result;
}
- private void fetchV2() throws IOException {
+ private void fetchV2(PacketLineOut pckOut) throws IOException {
// Depending on the requestValidator, #processHaveLines may
// require that advertised be set. Set it only in the required
// circumstances (to avoid a full ref lookup in the case that
@@ -1123,6 +1135,10 @@
protocolV2Hook.onFetch(req);
+ if (req.getSidebandAll()) {
+ pckOut.setUsingSideband(true);
+ }
+
// TODO(ifrade): Refactor to pass around the Request object, instead of
// copying data back to class fields
List<ObjectId> deepenNots = new ArrayList<>();
@@ -1208,13 +1224,17 @@
if (sectionSent)
pckOut.writeDelim();
- pckOut.writeString("packfile\n"); //$NON-NLS-1$
+ if (!pckOut.isUsingSideband()) {
+ // sendPack will write "packfile\n" for us if sideband-all is used.
+ // But sideband-all is not used, so we have to write it ourselves.
+ pckOut.writeString("packfile\n"); //$NON-NLS-1$
+ }
sendPack(new PackStatistics.Accumulator(),
req,
req.getClientCapabilities().contains(OPTION_INCLUDE_TAG)
? db.getRefDatabase().getRefsByPrefix(R_TAGS)
: null,
- unshallowCommits, deepenNots);
+ unshallowCommits, deepenNots, pckOut);
// sendPack invokes pckOut.end() for us, so we do not
// need to invoke it here.
} else {
@@ -1227,7 +1247,7 @@
* Returns true if this is the last command and we should tear down the
* connection.
*/
- private boolean serveOneCommandV2() throws IOException {
+ private boolean serveOneCommandV2(PacketLineOut pckOut) throws IOException {
String command;
try {
command = pckIn.readString();
@@ -1242,11 +1262,11 @@
return true;
}
if (command.equals("command=" + COMMAND_LS_REFS)) { //$NON-NLS-1$
- lsRefsV2();
+ lsRefsV2(pckOut);
return false;
}
if (command.equals("command=" + COMMAND_FETCH)) { //$NON-NLS-1$
- fetchV2();
+ fetchV2(pckOut);
return false;
}
throw new PackProtocolException(MessageFormat
@@ -1264,12 +1284,13 @@
COMMAND_FETCH + '=' +
(transferConfig.isAllowFilter() ? OPTION_FILTER + ' ' : "") + //$NON-NLS-1$
(advertiseRefInWant ? CAPABILITY_REF_IN_WANT + ' ' : "") + //$NON-NLS-1$
+ (transferConfig.isAllowSidebandAll() ? OPTION_SIDEBAND_ALL + ' ' : "") + //$NON-NLS-1$
OPTION_SHALLOW);
caps.add(CAPABILITY_SERVER_OPTION);
return caps;
}
- private void serviceV2() throws IOException {
+ private void serviceV2(PacketLineOut pckOut) throws IOException {
if (biDirectionalPipe) {
// Just like in service(), the capability advertisement
// is sent only if this is a bidirectional pipe. (If
@@ -1282,14 +1303,14 @@
}
pckOut.end();
- while (!serveOneCommandV2()) {
+ while (!serveOneCommandV2(pckOut)) {
// Repeat until an empty command or EOF.
}
return;
}
try {
- serveOneCommandV2();
+ serveOneCommandV2(pckOut);
} finally {
while (0 < rawIn.skip(2048) || 0 <= rawIn.read()) {
// Discard until EOF.
@@ -1585,7 +1606,8 @@
}
private boolean negotiate(FetchRequest req,
- PackStatistics.Accumulator accumulator)
+ PackStatistics.Accumulator accumulator,
+ PacketLineOut pckOut)
throws IOException {
okToGiveUp = Boolean.FALSE;
@@ -2063,6 +2085,8 @@
* shallow commits on the client that are now becoming unshallow
* @param deepenNots
* objects that the client specified using --shallow-exclude
+ * @param pckOut
+ * output writer
* @throws IOException
* if an error occurred while generating or writing the pack.
*/
@@ -2070,14 +2094,15 @@
FetchRequest req,
@Nullable Collection<Ref> allTags,
List<ObjectId> unshallowCommits,
- List<ObjectId> deepenNots) throws IOException {
+ List<ObjectId> deepenNots,
+ PacketLineOut pckOut) throws IOException {
Set<String> caps = req.getClientCapabilities();
boolean sideband = caps.contains(OPTION_SIDE_BAND)
|| caps.contains(OPTION_SIDE_BAND_64K);
if (sideband) {
try {
sendPack(true, req, accumulator, allTags, unshallowCommits,
- deepenNots);
+ deepenNots, pckOut);
} catch (ServiceMayNotContinueException err) {
String message = err.getMessage();
if (message == null) {
@@ -2101,7 +2126,8 @@
throw new UploadPackInternalServerErrorException(err);
}
} else {
- sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots);
+ sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots,
+ pckOut);
}
}
@@ -2132,6 +2158,8 @@
* shallow commits on the client that are now becoming unshallow
* @param deepenNots
* objects that the client specified using --shallow-exclude
+ * @param pckOut
+ * output writer
* @throws IOException
* if an error occurred while generating or writing the pack.
*/
@@ -2140,7 +2168,8 @@
PackStatistics.Accumulator accumulator,
@Nullable Collection<Ref> allTags,
List<ObjectId> unshallowCommits,
- List<ObjectId> deepenNots) throws IOException {
+ List<ObjectId> deepenNots,
+ PacketLineOut pckOut) throws IOException {
ProgressMonitor pm = NullProgressMonitor.INSTANCE;
OutputStream packOut = rawOut;
@@ -2268,6 +2297,9 @@
}
}
+ if (pckOut.isUsingSideband()) {
+ pckOut.writeString("packfile\n"); //$NON-NLS-1$
+ }
pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut);
if (msgOut != NullOutputStream.INSTANCE) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
index 5c67253..4862d67 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java
@@ -82,10 +82,6 @@
static final String INFO_PACKS = "info/packs"; //$NON-NLS-1$
- static final String INFO_ALTERNATES = "info/alternates"; //$NON-NLS-1$
-
- static final String INFO_HTTP_ALTERNATES = "info/http-alternates"; //$NON-NLS-1$
-
static final String INFO_REFS = ROOT_DIR + Constants.INFO_REFS;
abstract URIish getURI();
@@ -107,8 +103,10 @@
/**
* Obtain alternate connections to alternate object databases (if any).
* <p>
- * Alternates are typically read from the file {@link #INFO_ALTERNATES} or
- * {@link #INFO_HTTP_ALTERNATES}. The content of each line must be resolved
+ * Alternates are typically read from the file
+ * {@link org.eclipse.jgit.lib.Constants#INFO_ALTERNATES} or
+ * {@link org.eclipse.jgit.lib.Constants#INFO_HTTP_ALTERNATES}.
+ * The content of each line must be resolved
* by the implementation and a new database reference should be returned to
* represent the additional location.
* <p>
diff --git a/pom.xml b/pom.xml
index fd5cb70..a07c3cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -199,7 +199,7 @@
<httpcore-version>4.4.10</httpcore-version>
<slf4j-version>1.7.2</slf4j-version>
<log4j-version>1.2.15</log4j-version>
- <maven-javadoc-plugin-version>3.1.0</maven-javadoc-plugin-version>
+ <maven-javadoc-plugin-version>3.1.1</maven-javadoc-plugin-version>
<tycho-extras-version>1.3.0</tycho-extras-version>
<gson-version>2.8.2</gson-version>
<bouncycastle-version>1.61</bouncycastle-version>
@@ -376,7 +376,7 @@
<dependency><!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
- <version>3.3.2</version>
+ <version>3.3.3</version>
</dependency>
</dependencies>
</plugin>
@@ -906,7 +906,7 @@
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
- <version>3.17.0</version>
+ <version>3.18.0</version>
</dependency>
</dependencies>
</plugin>