aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java103
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java93
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java36
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java28
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java200
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java19
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/EndGenerator.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java56
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java41
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java44
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java34
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PreUploadHookChain.java47
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java110
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java290
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java10
49 files changed, 1143 insertions, 259 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
index c6f3c671a9..38e5444523 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
@@ -279,9 +279,13 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
}
private boolean isNoNewlineAtEndOfFile(FileHeader fh) {
- HunkHeader lastHunk = fh.getHunks().get(fh.getHunks().size() - 1);
+ List<? extends HunkHeader> hunks = fh.getHunks();
+ if (hunks == null || hunks.isEmpty()) {
+ return false;
+ }
+ HunkHeader lastHunk = hunks.get(hunks.size() - 1);
RawText lhrt = new RawText(lastHunk.getBuffer());
- return lhrt.getString(lhrt.size() - 1).equals(
- "\\ No newline at end of file"); //$NON-NLS-1$
+ return lhrt.getString(lhrt.size() - 1)
+ .equals("\\ No newline at end of file"); //$NON-NLS-1$
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index b8fa74de79..f9a9baf919 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -459,8 +459,8 @@ public class MergeCommand extends GitCommand<MergeResult> {
}
/**
- * Use values from the configuation if they have not been explicitly defined
- * via the setters
+ * Use values from the configuration if they have not been explicitly
+ * defined via the setters
*/
private void fallBackToConfiguration() {
MergeConfig config = MergeConfig.getConfigForCurrentBranch(repo);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 22090f5b60..6bc2946078 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -1301,14 +1301,6 @@ public class DirCacheCheckout {
JGitText.get().cannotDeleteFile, c));
removeEmptyParents(conflict);
}
- for (String r : removed) {
- File file = new File(repo.getWorkTree(), r);
- if (!file.delete())
- throw new CheckoutConflictException(
- MessageFormat.format(JGitText.get().cannotDeleteFile,
- file.getAbsolutePath()));
- removeEmptyParents(file);
- }
}
/**
@@ -1473,6 +1465,9 @@ public class DirCacheCheckout {
ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile();
+ if (parentDir.isFile()) {
+ FileUtils.delete(parentDir);
+ }
FileUtils.mkdirs(parentDir, true);
FS fs = repo.getFS();
WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index cd50e347ab..649f77724e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -139,6 +139,7 @@ public class JGitText extends TranslationBundle {
/***/ public String cannotEnterObjectsPath;
/***/ public String cannotEnterPathFromParent;
/***/ public String cannotExecute;
+ /***/ public String cannotFindMergeBaseUsingFirstParent;
/***/ public String cannotGet;
/***/ public String cannotGetObjectsPath;
/***/ public String cannotListObjectsPath;
@@ -197,6 +198,7 @@ public class JGitText extends TranslationBundle {
/***/ public String commitMessageNotSpecified;
/***/ public String commitOnRepoWithoutHEADCurrentlyNotSupported;
/***/ public String commitAmendOnInitialNotPossible;
+ /***/ public String commitsHaveAlreadyBeenMarkedAsStart;
/***/ public String compressingObjects;
/***/ public String configSubsectionContainsNewline;
/***/ public String configSubsectionContainsNullByte;
@@ -661,6 +663,7 @@ public class JGitText extends TranslationBundle {
/***/ public String refAlreadyExists1;
/***/ public String reflogEntryNotFound;
/***/ public String refNotResolved;
+ /***/ public String refTableRecordsMustIncrease;
/***/ public String refUpdateReturnCodeWas;
/***/ public String remoteConfigHasNoURIAssociated;
/***/ public String remoteDoesNotHaveSpec;
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 258cceebee..968ade6700 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 @@ public class ObjectDirectory extends FileObjectDatabase {
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/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 72699b0438..43bd9d4f58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -313,6 +313,14 @@ public abstract class PackIndex
int matchLimit) throws IOException;
/**
+ * @return the checksum of the pack; caller must not modify it
+ * @since 5.5
+ */
+ public byte[] getChecksum() {
+ return packChecksum;
+ }
+
+ /**
* Represent mutable entry of pack index consisting of object id and offset
* in pack (both mutable).
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java
new file mode 100644
index 0000000000..5cbc2baeb2
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java
@@ -0,0 +1,103 @@
+/*
+ * 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.internal.storage.pack;
+
+import java.io.IOException;
+import java.util.Collection;
+import org.eclipse.jgit.annotations.Nullable;
+
+/**
+ * Provider of URIs corresponding to cached packs. For use with the
+ * "packfile-uris" feature.
+ * @since 5.5
+ */
+public interface CachedPackUriProvider {
+
+ /**
+ * @param pack the cached pack for which to check if a corresponding URI
+ * exists
+ * @param protocolsSupported the protocols that the client has declared
+ * support for; if a URI is returned, it must be of one of these
+ * protocols
+ * @throws IOException implementations may throw this
+ * @return if a URI corresponds to the cached pack, an object
+ * containing the URI and some other information; null otherwise
+ * @since 5.5
+ */
+ @Nullable
+ PackInfo getInfo(CachedPack pack, Collection<String> protocolsSupported)
+ throws IOException;
+
+ /**
+ * Information about a packfile.
+ * @since 5.5
+ */
+ public static class PackInfo {
+ private final String hash;
+ private final String uri;
+
+ /**
+ * Constructs an object containing information about a packfile.
+ * @param hash the hash of the packfile as a hexadecimal string
+ * @param uri the URI corresponding to the packfile
+ */
+ public PackInfo(String hash, String uri) {
+ this.hash = hash;
+ this.uri = uri;
+ }
+
+ /**
+ * @return the hash of the packfile as a hexadecimal string
+ */
+ public String getHash() {
+ return hash;
+ }
+
+ /**
+ * @return the URI corresponding to the packfile
+ */
+ public String getUri() {
+ return uri;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 6506789218..02cfe90497 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -122,6 +122,7 @@ import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.FilterSpec;
import org.eclipse.jgit.transport.ObjectCountCallback;
+import org.eclipse.jgit.transport.PacketLineOut;
import org.eclipse.jgit.transport.WriteAbortedException;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.TemporaryBuffer;
@@ -307,6 +308,8 @@ public class PackWriter implements AutoCloseable {
private FilterSpec filterSpec = FilterSpec.NO_FILTER;
+ private PackfileUriConfig packfileUriConfig;
+
/**
* Create writer for specified repository.
* <p>
@@ -651,6 +654,14 @@ public class PackWriter implements AutoCloseable {
}
/**
+ * @param config configuration related to packfile URIs
+ * @since 5.5
+ */
+ public void setPackfileUriConfig(PackfileUriConfig config) {
+ packfileUriConfig = config;
+ }
+
+ /**
* Returns objects number in a pack file that was created by this writer.
*
* @return number of objects in pack.
@@ -673,6 +684,26 @@ public class PackWriter implements AutoCloseable {
return stats.totalObjects;
}
+ private long getUnoffloadedObjectCount() throws IOException {
+ long objCnt = 0;
+
+ objCnt += objectsLists[OBJ_COMMIT].size();
+ objCnt += objectsLists[OBJ_TREE].size();
+ objCnt += objectsLists[OBJ_BLOB].size();
+ objCnt += objectsLists[OBJ_TAG].size();
+
+ for (CachedPack pack : cachedPacks) {
+ CachedPackUriProvider.PackInfo packInfo =
+ packfileUriConfig.cachedPackUriProvider.getInfo(
+ pack, packfileUriConfig.protocolsSupported);
+ if (packInfo == null) {
+ objCnt += pack.getObjectCount();
+ }
+ }
+
+ return objCnt;
+ }
+
/**
* Returns the object ids in the pack file that was created by this writer.
* <p>
@@ -1177,13 +1208,38 @@ public class PackWriter implements AutoCloseable {
: new CheckedOutputStream(packStream, crc32),
this);
- long objCnt = getObjectCount();
+ long objCnt = packfileUriConfig == null ? getObjectCount() :
+ getUnoffloadedObjectCount();
stats.totalObjects = objCnt;
if (callback != null)
callback.setObjectCount(objCnt);
beginPhase(PackingPhase.WRITING, writeMonitor, objCnt);
long writeStart = System.currentTimeMillis();
try {
+ List<CachedPack> unwrittenCachedPacks;
+
+ if (packfileUriConfig != null) {
+ unwrittenCachedPacks = new ArrayList<>();
+ CachedPackUriProvider p = packfileUriConfig.cachedPackUriProvider;
+ PacketLineOut o = packfileUriConfig.pckOut;
+
+ o.writeString("packfile-uris\n");
+ for (CachedPack pack : cachedPacks) {
+ CachedPackUriProvider.PackInfo packInfo = p.getInfo(
+ pack, packfileUriConfig.protocolsSupported);
+ if (packInfo != null) {
+ o.writeString(packInfo.getHash() + ' ' +
+ packInfo.getUri() + '\n');
+ } else {
+ unwrittenCachedPacks.add(pack);
+ }
+ }
+ packfileUriConfig.pckOut.writeDelim();
+ packfileUriConfig.pckOut.writeString("packfile\n");
+ } else {
+ unwrittenCachedPacks = cachedPacks;
+ }
+
out.writeFileHeader(PACK_VERSION_GENERATED, objCnt);
out.flush();
@@ -1197,7 +1253,7 @@ public class PackWriter implements AutoCloseable {
}
stats.reusedPacks = Collections.unmodifiableList(cachedPacks);
- for (CachedPack pack : cachedPacks) {
+ for (CachedPack pack : unwrittenCachedPacks) {
long deltaCnt = pack.getDeltaCount();
stats.reusedObjects += pack.getObjectCount();
stats.reusedDeltas += deltaCnt;
@@ -2426,4 +2482,37 @@ public class PackWriter implements AutoCloseable {
return "PackWriter.State[" + phase + ", memory=" + bytesUsed + "]";
}
}
+
+ /**
+ * Configuration related to the packfile URI feature.
+ *
+ * @since 5.5
+ */
+ public static class PackfileUriConfig {
+ @NonNull
+ private final PacketLineOut pckOut;
+
+ @NonNull
+ private final Collection<String> protocolsSupported;
+
+ @NonNull
+ private final CachedPackUriProvider cachedPackUriProvider;
+
+ /**
+ * @param pckOut where to write "packfile-uri" lines to (should
+ * output to the same stream as the one passed to
+ * PackWriter#writePack)
+ * @param protocolsSupported list of protocols supported (e.g. "https")
+ * @param cachedPackUriProvider provider of URIs corresponding
+ * to cached packs
+ * @since 5.5
+ */
+ public PackfileUriConfig(@NonNull PacketLineOut pckOut,
+ @NonNull Collection<String> protocolsSupported,
+ @NonNull CachedPackUriProvider cachedPackUriProvider) {
+ this.pckOut = pckOut;
+ this.protocolsSupported = protocolsSupported;
+ this.cachedPackUriProvider = cachedPackUriProvider;
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
index 44529bfff2..b66751b94c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
@@ -84,7 +84,11 @@ import org.eclipse.jgit.util.LongList;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.RawParseUtils;
-/** Reads a single block for {@link ReftableReader}. */
+/**
+ * Reads a single block for {@link ReftableReader}. Instances are tied to a
+ * specific block in the file so are not reused for other blocks. Instances hold
+ * an offset into the block.
+ */
class BlockReader {
private byte blockType;
private long endPosition;
@@ -141,6 +145,8 @@ class BlockReader {
return RawParseUtils.decode(UTF_8, nameBuf, 0, len);
}
+ // Matches the key against a name or a prefix. For reflogs, only the
+ // refname is matched, and the updateIndex suffix is ignored.
boolean match(byte[] match, boolean matchIsPrefix) {
int len = nameLen;
if (blockType == LOG_BLOCK_TYPE) {
@@ -551,7 +557,9 @@ class BlockReader {
}
private short readInt16() {
- return (short) NB.decodeUInt16(buf, ptr += 2);
+ short result =(short) NB.decodeUInt16(buf, ptr);
+ ptr += 2;
+ return result;
}
private int readVarint32() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
index bf3a9aeca0..4f0ff2d1d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java
@@ -255,6 +255,32 @@ public class ReftableReader extends Reftable {
block.seekKey(key);
return block;
}
+ if (blockType == LOG_BLOCK_TYPE) {
+ // No index. Log blocks are irregularly sized, so we can't do binary
+ // search between blocks. Scan over blocks instead.
+ BlockReader block = readBlock(startPos, endPos);
+
+ for (;;) {
+ if (block == null || block.type() != LOG_BLOCK_TYPE) {
+ return null;
+ }
+
+ int result = block.seekKey(key);
+ if (result <= 0) {
+ // == 0 : we found the key.
+ // < 0 : the key is before this block. Either the ref name is there
+ // but only at a newer updateIndex, or it is absent. We leave it to
+ // logcursor to distinguish between both cases.
+ return block;
+ }
+
+ long pos = block.endPosition();
+ if (pos >= endPos) {
+ return null;
+ }
+ block = readBlock(pos, endPos);
+ }
+ }
return binarySearch(blockType, key, startPos, endPos);
}
@@ -529,12 +555,20 @@ public class ReftableReader extends Reftable {
private class LogCursorImpl extends LogCursor {
private final long scanEnd;
private final byte[] match;
-
+
private String refName;
private long updateIndex;
private ReflogEntry entry;
BlockReader block;
+ /**
+ * Scans logs from this table until scanEnd position.
+ *
+ * @param scanEnd
+ * end of the log data in the reftable.
+ * @param match
+ * if non-null, limits the scan to precisely that refname.
+ */
LogCursorImpl(long scanEnd, byte[] match) {
this.scanEnd = scanEnd;
this.match = match;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
index f8b9ffd176..6459c2763d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.reftable;
import static java.lang.Math.log;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.internal.storage.reftable.BlockWriter.padBetweenBlocks;
import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_FOOTER_LEN;
import static org.eclipse.jgit.internal.storage.reftable.ReftableConstants.FILE_HEADER_LEN;
@@ -59,6 +60,7 @@ import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
import java.io.IOException;
import java.io.OutputStream;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -69,6 +71,7 @@ import java.util.Set;
import java.util.zip.CRC32;
import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.reftable.BlockWriter.DeleteLogEntry;
import org.eclipse.jgit.internal.storage.reftable.BlockWriter.Entry;
import org.eclipse.jgit.internal.storage.reftable.BlockWriter.IndexEntry;
@@ -108,6 +111,8 @@ public class ReftableWriter {
private ReftableOutputStream out;
private ObjectIdSubclassMap<RefList> obj2ref;
+ private BlockWriter.Entry lastRef;
+ private BlockWriter.Entry lastLog;
private BlockWriter cur;
private Section refs;
private Section objs;
@@ -120,6 +125,8 @@ public class ReftableWriter {
*/
public ReftableWriter() {
this(new ReftableConfig());
+ lastRef = null;
+ lastLog = null;
}
/**
@@ -269,10 +276,22 @@ public class ReftableWriter {
throw new IllegalArgumentException();
}
long d = updateIndex - minUpdateIndex;
- long blockPos = refs.write(new RefEntry(ref, d));
+ RefEntry entry = new RefEntry(ref, d);
+ if (lastRef != null && Entry.compare(lastRef, entry) >= 0) {
+ throwIllegalEntry(lastRef, entry);
+ }
+ lastRef = entry;
+
+ long blockPos = refs.write(entry);
indexRef(ref, blockPos);
}
+ private void throwIllegalEntry(Entry last, Entry now) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().refTableRecordsMustIncrease,
+ new String(last.key, UTF_8), new String(now.key, UTF_8)));
+ }
+
private void indexRef(Ref ref, long blockPos) {
if (indexObjects && !ref.isSymbolic()) {
indexId(ref.getObjectId(), blockPos);
@@ -322,7 +341,12 @@ public class ReftableWriter {
throws IOException {
String msg = message != null ? message : ""; //$NON-NLS-1$
beginLog();
- logs.write(new LogEntry(ref, updateIndex, who, oldId, newId, msg));
+ LogEntry entry = new LogEntry(ref, updateIndex, who, oldId, newId, msg);
+ if (lastLog != null && Entry.compare(lastLog, entry) >= 0) {
+ throwIllegalEntry(lastLog, entry);
+ }
+ lastLog = entry;
+ logs.write(entry);
}
/**
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 d1cf1cd9ae..96e50667b3 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 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
*/
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 8f4468eef2..a084c82871 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 @@ public final class Constants {
/** 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 27befba5a4..fa113bfc6b 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 @@ public class RepositoryCache {
* 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/lib/internal/BouncyCastleGpgKeyLocator.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java
index 0d44317658..11db7c5998 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java
@@ -50,6 +50,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
+import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
@@ -72,6 +73,8 @@ import org.bouncycastle.gpg.keybox.UserID;
import org.bouncycastle.gpg.keybox.jcajce.JcaKeyBoxBuilder;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
@@ -97,6 +100,13 @@ import org.slf4j.LoggerFactory;
*/
class BouncyCastleGpgKeyLocator {
+ /** Thrown if a keybox file exists but doesn't contain an OpenPGP key. */
+ private static class NoOpenPgpKeyException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ }
+
private static final Logger log = LoggerFactory
.getLogger(BouncyCastleGpgKeyLocator.class);
@@ -108,6 +118,9 @@ class BouncyCastleGpgKeyLocator {
private static final Path USER_SECRET_KEY_DIR = GPG_DIRECTORY
.resolve("private-keys-v1.d"); //$NON-NLS-1$
+ private static final Path USER_PGP_PUBRING_FILE = GPG_DIRECTORY
+ .resolve("pubring.gpg"); //$NON-NLS-1$
+
private static final Path USER_PGP_LEGACY_SECRING_FILE = GPG_DIRECTORY
.resolve("secring.gpg"); //$NON-NLS-1$
@@ -215,13 +228,17 @@ class BouncyCastleGpgKeyLocator {
* in case of problems reading the file
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
+ * @throws NoOpenPgpKeyException
+ * if the file does not contain any OpenPGP key
*/
private PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile)
throws IOException, NoSuchAlgorithmException,
- NoSuchProviderException {
+ NoSuchProviderException, NoOpenPgpKeyException {
KeyBox keyBox = readKeyBoxFile(keyboxFile);
+ boolean hasOpenPgpKey = false;
for (KeyBlob keyBlob : keyBox.getKeyBlobs()) {
if (keyBlob.getType() == BlobType.OPEN_PGP_BLOB) {
+ hasOpenPgpKey = true;
PGPPublicKey key = findPublicKeyByKeyId(keyBlob);
if (key != null) {
return key;
@@ -232,12 +249,20 @@ class BouncyCastleGpgKeyLocator {
}
}
}
+ if (!hasOpenPgpKey) {
+ throw new NoOpenPgpKeyException();
+ }
return null;
}
/**
- * Use pubring.kbx when available, if not fallback to secring.gpg or secret
- * key path provided to parse and return secret key
+ * If there is a private key directory containing keys, use pubring.kbx or
+ * pubring.gpg to find the public key; then try to find the secret key in
+ * the directory.
+ * <p>
+ * If there is no private key directory (or it doesn't contain any keys),
+ * try to find the key in secring.gpg directly.
+ * </p>
*
* @return the secret key
* @throws IOException
@@ -245,42 +270,112 @@ class BouncyCastleGpgKeyLocator {
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws PGPException
- * in case of issues finding a key
+ * in case of issues finding a key, including no key found
* @throws CanceledException
* @throws URISyntaxException
* @throws UnsupportedCredentialItem
*/
+ @NonNull
public BouncyCastleGpgKey findSecretKey() throws IOException,
NoSuchAlgorithmException, NoSuchProviderException, PGPException,
CanceledException, UnsupportedCredentialItem, URISyntaxException {
- if (exists(USER_KEYBOX_PATH)) {
- PGPPublicKey publicKey = //
- findPublicKeyInKeyBox(USER_KEYBOX_PATH);
-
- if (publicKey != null) {
- return findSecretKeyForKeyBoxPublicKey(publicKey,
- USER_KEYBOX_PATH);
- }
-
- throw new PGPException(MessageFormat
- .format(JGitText.get().gpgNoPublicKeyFound, signingKey));
- } else if (exists(USER_PGP_LEGACY_SECRING_FILE)) {
- PGPSecretKey secretKey = findSecretKeyInLegacySecring(signingKey,
- USER_PGP_LEGACY_SECRING_FILE);
-
- if (secretKey != null) {
- if (!secretKey.isSigningKey()) {
+ BouncyCastleGpgKey key;
+ PGPPublicKey publicKey = null;
+ if (hasKeyFiles(USER_SECRET_KEY_DIR)) {
+ // Use pubring.kbx or pubring.gpg to find the public key, then try
+ // the key files in the directory. If the public key was found in
+ // pubring.gpg also try secring.gpg to find the secret key.
+ if (exists(USER_KEYBOX_PATH)) {
+ try {
+ publicKey = findPublicKeyInKeyBox(USER_KEYBOX_PATH);
+ if (publicKey != null) {
+ key = findSecretKeyForKeyBoxPublicKey(publicKey,
+ USER_KEYBOX_PATH);
+ if (key != null) {
+ return key;
+ }
+ throw new PGPException(MessageFormat.format(
+ JGitText.get().gpgNoSecretKeyForPublicKey,
+ Long.toHexString(publicKey.getKeyID())));
+ }
throw new PGPException(MessageFormat.format(
- JGitText.get().gpgNotASigningKey, signingKey));
+ JGitText.get().gpgNoPublicKeyFound, signingKey));
+ } catch (NoOpenPgpKeyException e) {
+ // There are no OpenPGP keys in the keybox at all: try the
+ // pubring.gpg, if it exists.
+ if (log.isDebugEnabled()) {
+ log.debug("{} does not contain any OpenPGP keys", //$NON-NLS-1$
+ USER_KEYBOX_PATH);
+ }
}
- return new BouncyCastleGpgKey(secretKey, USER_PGP_LEGACY_SECRING_FILE);
}
-
+ if (exists(USER_PGP_PUBRING_FILE)) {
+ publicKey = findPublicKeyInPubring(USER_PGP_PUBRING_FILE);
+ if (publicKey != null) {
+ // GPG < 2.1 may have both; the agent using the directory
+ // and gpg using secring.gpg. GPG >= 2.1 delegates all
+ // secret key handling to the agent and doesn't use
+ // secring.gpg at all, even if it exists. Which means for us
+ // we have to try both since we don't know which GPG version
+ // the user has.
+ key = findSecretKeyForKeyBoxPublicKey(publicKey,
+ USER_PGP_PUBRING_FILE);
+ if (key != null) {
+ return key;
+ }
+ }
+ }
+ if (publicKey == null) {
+ throw new PGPException(MessageFormat.format(
+ JGitText.get().gpgNoPublicKeyFound, signingKey));
+ }
+ // We found a public key, but didn't find the secret key in the
+ // private key directory. Go try the secring.gpg.
+ }
+ boolean hasSecring = false;
+ if (exists(USER_PGP_LEGACY_SECRING_FILE)) {
+ hasSecring = true;
+ key = loadKeyFromSecring(USER_PGP_LEGACY_SECRING_FILE);
+ if (key != null) {
+ return key;
+ }
+ }
+ if (publicKey != null) {
+ throw new PGPException(MessageFormat.format(
+ JGitText.get().gpgNoSecretKeyForPublicKey,
+ Long.toHexString(publicKey.getKeyID())));
+ } else if (hasSecring) {
+ // publicKey == null: user has _only_ pubring.gpg/secring.gpg.
throw new PGPException(MessageFormat.format(
JGitText.get().gpgNoKeyInLegacySecring, signingKey));
+ } else {
+ throw new PGPException(JGitText.get().gpgNoKeyring);
}
+ }
- throw new PGPException(JGitText.get().gpgNoKeyring);
+ private boolean hasKeyFiles(Path dir) {
+ try (DirectoryStream<Path> contents = Files.newDirectoryStream(dir,
+ "*.key")) { //$NON-NLS-1$
+ return contents.iterator().hasNext();
+ } catch (IOException e) {
+ // Not a directory, or something else
+ return false;
+ }
+ }
+
+ private BouncyCastleGpgKey loadKeyFromSecring(Path secring)
+ throws IOException, PGPException {
+ PGPSecretKey secretKey = findSecretKeyInLegacySecring(signingKey,
+ secring);
+
+ if (secretKey != null) {
+ if (!secretKey.isSigningKey()) {
+ throw new PGPException(MessageFormat
+ .format(JGitText.get().gpgNotASigningKey, signingKey));
+ }
+ return new BouncyCastleGpgKey(secretKey, secring);
+ }
+ return null;
}
private BouncyCastleGpgKey findSecretKeyForKeyBoxPublicKey(
@@ -315,9 +410,7 @@ class BouncyCastleGpgKeyLocator {
}
passphrasePrompt.clear();
- throw new PGPException(MessageFormat.format(
- JGitText.get().gpgNoSecretKeyForPublicKey,
- Long.toHexString(publicKey.getKeyID())));
+ return null;
} catch (RuntimeException e) {
passphrasePrompt.clear();
throw e;
@@ -379,13 +472,62 @@ class BouncyCastleGpgKeyLocator {
return null;
}
+ /**
+ * Return the first public key matching the key id ({@link #signingKey}.
+ *
+ * @param pubringFile
+ *
+ * @return the PGP public key, or {@code null} if none found
+ * @throws IOException
+ * on I/O related errors
+ * @throws PGPException
+ * on BouncyCastle errors
+ */
+ private PGPPublicKey findPublicKeyInPubring(Path pubringFile)
+ throws IOException, PGPException {
+ try (InputStream in = newInputStream(pubringFile)) {
+ PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
+ new BufferedInputStream(in),
+ new JcaKeyFingerprintCalculator());
+
+ String keyId = signingKey.toLowerCase(Locale.ROOT);
+ Iterator<PGPPublicKeyRing> keyrings = pgpPub.getKeyRings();
+ while (keyrings.hasNext()) {
+ PGPPublicKeyRing keyRing = keyrings.next();
+ Iterator<PGPPublicKey> keys = keyRing.getPublicKeys();
+ while (keys.hasNext()) {
+ PGPPublicKey key = keys.next();
+ // try key id
+ String fingerprint = Hex.toHexString(key.getFingerprint())
+ .toLowerCase(Locale.ROOT);
+ if (fingerprint.endsWith(keyId)) {
+ return key;
+ }
+ // try user id
+ Iterator<String> userIDs = key.getUserIDs();
+ while (userIDs.hasNext()) {
+ String userId = userIDs.next();
+ if (containsSigningKey(userId)) {
+ return key;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
private PGPPublicKey getFirstPublicKey(KeyBlob keyBlob) throws IOException {
return ((PublicKeyRingBlob) keyBlob).getPGPPublicKeyRing()
.getPublicKey();
}
private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException,
- NoSuchAlgorithmException, NoSuchProviderException {
+ NoSuchAlgorithmException, NoSuchProviderException,
+ NoOpenPgpKeyException {
+ if (keyboxFile.toFile().length() == 0) {
+ throw new NoOpenPgpKeyException();
+ }
KeyBox keyBox;
try (InputStream in = new BufferedInputStream(
newInputStream(keyboxFile))) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
index 247a3bdb28..7b5e6fa310 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
@@ -49,6 +49,10 @@ abstract class AbstractRevQueue extends Generator {
/** Current output flags set for this generator instance. */
int outputType;
+ AbstractRevQueue(boolean firstParent) {
+ super(firstParent);
+ }
+
/**
* Add a commit to the queue.
* <p>
@@ -96,10 +100,15 @@ abstract class AbstractRevQueue extends Generator {
*/
public final void addParents(RevCommit c, RevFlag queueControl) {
final RevCommit[] pList = c.parents;
- if (pList == null)
+ if (pList == null) {
return;
- for (RevCommit p : pList)
- add(p, queueControl);
+ }
+ for (int i = 0; i < pList.length; i++) {
+ if (firstParent && i > 0) {
+ break;
+ }
+ add(pList[i], queueControl);
+ }
}
/**
@@ -138,6 +147,10 @@ abstract class AbstractRevQueue extends Generator {
}
private static class AlwaysEmptyQueue extends AbstractRevQueue {
+ private AlwaysEmptyQueue() {
+ super(false);
+ }
+
@Override
public void add(RevCommit c) {
throw new UnsupportedOperationException();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
index 79307b5b7c..64e9e03229 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BlockRevQueue.java
@@ -53,13 +53,19 @@ abstract class BlockRevQueue extends AbstractRevQueue {
/**
* Create an empty revision queue.
+ *
+ * @param firstParent
+ * whether only first-parent links should be followed when
+ * walking
*/
- protected BlockRevQueue() {
+ protected BlockRevQueue(boolean firstParent) {
+ super(firstParent);
free = new BlockFreeList();
}
BlockRevQueue(Generator s) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
+ super(s.firstParent);
free = new BlockFreeList();
outputType = s.outputType();
s.shareFreeList(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
index 0fd6621e62..98c99e845d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
@@ -55,6 +55,7 @@ class BoundaryGenerator extends Generator {
Generator g;
BoundaryGenerator(RevWalk w, Generator s) {
+ super(s.firstParent);
g = new InitialGenerator(w, s);
}
@@ -86,8 +87,9 @@ class BoundaryGenerator extends Generator {
private final Generator source;
InitialGenerator(RevWalk w, Generator s) {
+ super(s.firstParent);
walk = w;
- held = new FIFORevQueue();
+ held = new FIFORevQueue(firstParent);
source = s;
source.shareFreeList(held);
}
@@ -107,13 +109,19 @@ class BoundaryGenerator extends Generator {
IncorrectObjectTypeException, IOException {
RevCommit c = source.next();
if (c != null) {
- for (RevCommit p : c.parents)
- if ((p.flags & UNINTERESTING) != 0)
+ for (int i = 0; i < c.parents.length; i++) {
+ if (firstParent && i > 0) {
+ break;
+ }
+ RevCommit p = c.parents[i];
+ if ((p.flags & UNINTERESTING) != 0) {
held.add(p);
+ }
+ }
return c;
}
- final FIFORevQueue boundary = new FIFORevQueue();
+ final FIFORevQueue boundary = new FIFORevQueue(firstParent);
boundary.shareFreeList(held);
for (;;) {
c = held.next();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
index b86e876201..d77b055534 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
@@ -69,15 +69,18 @@ public class DateRevQueue extends AbstractRevQueue {
private int last = -1;
- /**
- * Create an empty date queue.
- */
+ /** Create an empty date queue. */
public DateRevQueue() {
- super();
+ super(false);
+ }
+
+ DateRevQueue(boolean firstParent) {
+ super(firstParent);
}
DateRevQueue(Generator s) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
+ super(s.firstParent);
for (;;) {
final RevCommit c = s.next();
if (c == null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
index c397a01317..9134e08b28 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DelayRevQueue.java
@@ -70,6 +70,7 @@ final class DelayRevQueue extends Generator {
private int size;
DelayRevQueue(Generator g) {
+ super(g.firstParent);
pending = g;
delay = new FIFORevQueue();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
index 5199a2927d..0b04d5d174 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
@@ -95,7 +95,8 @@ class DepthGenerator extends Generator {
*/
DepthGenerator(DepthWalk w, Generator s) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
- pending = new FIFORevQueue();
+ super(s.firstParent);
+ pending = new FIFORevQueue(firstParent);
walk = (RevWalk)w;
this.depth = w.getDepth();
@@ -196,7 +197,11 @@ class DepthGenerator extends Generator {
int newDepth = c.depth + 1;
- for (RevCommit p : c.parents) {
+ for (int i = 0; i < c.parents.length; i++) {
+ if (firstParent && i > 0) {
+ break;
+ }
+ RevCommit p = c.parents[i];
DepthWalk.Commit dp = (DepthWalk.Commit) p;
// If no depth has been assigned to this commit, assign
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/EndGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/EndGenerator.java
index 627e1c7a51..03916c8152 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/EndGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/EndGenerator.java
@@ -47,7 +47,7 @@ class EndGenerator extends Generator {
static final EndGenerator INSTANCE = new EndGenerator();
private EndGenerator() {
- // We have nothing to initialize.
+ super(false);
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
index cdb084c15e..40ee55c730 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FIFORevQueue.java
@@ -56,11 +56,13 @@ public class FIFORevQueue extends BlockRevQueue {
private Block tail;
- /**
- * Create an empty FIFO queue.
- */
+ /** Create an empty FIFO queue. */
public FIFORevQueue() {
- super();
+ super(false);
+ }
+
+ FIFORevQueue(boolean firstParent) {
+ super(firstParent);
}
FIFORevQueue(Generator s) throws MissingObjectException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
index 4e6d7e681d..289842a909 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FixUninterestingGenerator.java
@@ -62,6 +62,7 @@ final class FixUninterestingGenerator extends Generator {
private final Generator pending;
FixUninterestingGenerator(Generator g) {
+ super(g.firstParent);
pending = g;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
index b2c92ea249..59c5cce828 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/Generator.java
@@ -75,6 +75,12 @@ abstract class Generator {
/** Output may have {@link RevWalk#UNINTERESTING} marked on it. */
static final int HAS_UNINTERESTING = 1 << 4;
+ protected final boolean firstParent;
+
+ protected Generator(boolean firstParent) {
+ this.firstParent = firstParent;
+ }
+
/**
* Connect the supplied queue to this generator's own free list (if any).
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
index 846b8d92fa..5628d359bf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/LIFORevQueue.java
@@ -59,7 +59,7 @@ public class LIFORevQueue extends BlockRevQueue {
* Create an empty LIFO queue.
*/
public LIFORevQueue() {
- super();
+ super(false);
}
LIFORevQueue(Generator s) throws MissingObjectException,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
index 2fe95318b2..4ea57cb51b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
@@ -85,8 +85,9 @@ class MergeBaseGenerator extends Generator {
private CarryStack stack;
MergeBaseGenerator(RevWalk w) {
+ super(w.isFirstParent());
walker = w;
- pending = new DateRevQueue();
+ pending = new DateRevQueue(firstParent);
}
void init(AbstractRevQueue p) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
index e607b7daa0..52dd56d129 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
@@ -109,6 +109,7 @@ class PendingGenerator extends Generator {
PendingGenerator(final RevWalk w, final DateRevQueue p,
final RevFilter f, final int out) {
+ super(w.isFirstParent());
walker = w;
pending = p;
filter = f;
@@ -140,7 +141,11 @@ class PendingGenerator extends Generator {
produce = filter.include(walker, c);
}
- for (RevCommit p : c.parents) {
+ for (int i = 0; i < c.parents.length; i++) {
+ RevCommit p = c.parents[i];
+ if (firstParent && i > 0) {
+ continue;
+ }
if ((p.flags & SEEN) != 0)
continue;
if ((p.flags & PARSED) == 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index f50d189ce5..4aa83252b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -201,6 +201,8 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
private boolean rewriteParents = true;
+ private boolean firstParent;
+
boolean shallowCommitsInitialized;
/**
@@ -233,7 +235,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
idBuffer = new MutableObjectId();
objects = new ObjectIdOwnerMap<>();
roots = new ArrayList<>();
- queue = new DateRevQueue();
+ queue = new DateRevQueue(false);
pending = new StartGenerator(this);
sorting = EnumSet.of(RevSort.NONE);
filter = RevFilter.ALL;
@@ -664,6 +666,35 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
}
/**
+ * @return whether only first-parent links should be followed when walking.
+ *
+ * @since 5.5
+ */
+ public boolean isFirstParent() {
+ return firstParent;
+ }
+
+ /**
+ * Set whether or not only first parent links should be followed.
+ * <p>
+ * If set, second- and higher-parent links are not traversed at all.
+ * <p>
+ * This must be called prior to {@link #markStart(RevCommit)}.
+ *
+ * @param enable
+ * true to walk only first-parent links.
+ *
+ * @since 5.5
+ */
+ public void setFirstParent(boolean enable) {
+ assertNotStarted();
+ assertNoCommitsMarkedStart();
+ firstParent = enable;
+ queue = new DateRevQueue(firstParent);
+ pending = new StartGenerator(this);
+ }
+
+ /**
* Locate a reference to a blob without loading it.
* <p>
* The blob may or may not exist in the repository. It is impossible to tell
@@ -1295,7 +1326,8 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
* <p>
* Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
* instances are not invalidated. RevFlag instances are not invalidated, but
- * are removed from all RevObjects.
+ * are removed from all RevObjects. The value of {@code firstParent} is
+ * retained.
*
* @param retainFlags
* application flags that should <b>not</b> be cleared from
@@ -1331,7 +1363,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
}
roots.clear();
- queue = new DateRevQueue();
+ queue = new DateRevQueue(firstParent);
pending = new StartGenerator(this);
}
@@ -1349,9 +1381,10 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
delayFreeFlags = 0;
retainOnReset = 0;
carryFlags = UNINTERESTING;
+ firstParent = false;
objects.clear();
roots.clear();
- queue = new DateRevQueue();
+ queue = new DateRevQueue(firstParent);
pending = new StartGenerator(this);
shallowCommitsInitialized = false;
}
@@ -1423,6 +1456,21 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
throw new IllegalStateException(JGitText.get().outputHasAlreadyBeenStarted);
}
+ /**
+ * Throws an exception if any commits have been marked as start.
+ * <p>
+ * If {@link #markStart(RevCommit)} has already been called,
+ * {@link #reset()} can be called to satisfy this condition.
+ *
+ * @since 5.5
+ */
+ protected void assertNoCommitsMarkedStart() {
+ if (roots.isEmpty())
+ return;
+ throw new IllegalStateException(
+ JGitText.get().commitsHaveAlreadyBeenMarkedAsStart);
+ }
+
private boolean isNotStarted() {
return pending instanceof StartGenerator;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
index 1c868ffe08..2e26641ebc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
@@ -77,6 +77,7 @@ class RewriteGenerator extends Generator {
private final Generator source;
RewriteGenerator(Generator s) {
+ super(s.firstParent);
source = s;
}
@@ -102,6 +103,10 @@ class RewriteGenerator extends Generator {
final int nParents = pList.length;
for (int i = 0; i < nParents; i++) {
final RevCommit oldp = pList[i];
+ if (firstParent && i > 0) {
+ c.parents = new RevCommit[] { rewrite(oldp) };
+ return c;
+ }
final RevCommit newp = rewrite(oldp);
if (oldp != newp) {
pList[i] = newp;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
index eb129a2631..b309d6fee2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
@@ -67,6 +67,7 @@ class StartGenerator extends Generator {
private final RevWalk walker;
StartGenerator(RevWalk w) {
+ super(w.isFirstParent());
walker = w;
}
@@ -89,9 +90,14 @@ class StartGenerator extends Generator {
// Computing for merge bases is a special case and does not
// use the bulk of the generator pipeline.
//
- if (tf != TreeFilter.ALL)
+ if (tf != TreeFilter.ALL) {
throw new IllegalStateException(MessageFormat.format(
JGitText.get().cannotCombineTreeFilterWithRevFilter, tf, rf));
+ }
+ if (w.isFirstParent()) {
+ throw new IllegalStateException(
+ JGitText.get().cannotFindMergeBaseUsingFirstParent);
+ }
final MergeBaseGenerator mbg = new MergeBaseGenerator(w);
walker.pending = mbg;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
index 645034351f..a2c9ef6da4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
@@ -71,15 +71,21 @@ class TopoSortGenerator extends Generator {
*/
TopoSortGenerator(Generator s) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
- pending = new FIFORevQueue();
+ super(s.firstParent);
+ pending = new FIFORevQueue(firstParent);
outputType = s.outputType() | SORT_TOPO;
s.shareFreeList(pending);
for (;;) {
final RevCommit c = s.next();
- if (c == null)
+ if (c == null) {
break;
- for (RevCommit p : c.parents)
- p.inDegree++;
+ }
+ for (int i = 0; i < c.parents.length; i++) {
+ if (firstParent && i > 0) {
+ break;
+ }
+ c.parents[i].inDegree++;
+ }
pending.add(c);
}
}
@@ -113,7 +119,11 @@ class TopoSortGenerator extends Generator {
// All of our children have already produced,
// so it is OK for us to produce now as well.
//
- for (RevCommit p : c.parents) {
+ for (int i = 0; i < c.parents.length; i++) {
+ if (firstParent && i > 0) {
+ break;
+ }
+ RevCommit p = c.parents[i];
if (--p.inDegree == 0 && (p.flags & TOPO_DELAY) != 0) {
// This parent tried to come before us, but we are
// his last child. unpop the parent so it goes right
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
index 11301538e6..f7c3218850 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
@@ -116,8 +116,7 @@ public class TreeRevFilter extends RevFilter {
* @param rewriteFlag
* flag to color commits to be removed from the simplified DAT.
*/
- TreeRevFilter(final RevWalk walker, final TreeFilter t,
- final int rewriteFlag) {
+ TreeRevFilter(RevWalk walker, TreeFilter t, int rewriteFlag) {
pathFilter = new TreeWalk(walker.reader);
pathFilter.setFilter(t);
pathFilter.setRecursive(t.shouldBeRecursive());
@@ -137,14 +136,15 @@ public class TreeRevFilter extends RevFilter {
IncorrectObjectTypeException, IOException {
// Reset the tree filter to scan this commit and parents.
//
- final RevCommit[] pList = c.parents;
- final int nParents = pList.length;
- final TreeWalk tw = pathFilter;
- final ObjectId[] trees = new ObjectId[nParents + 1];
+ RevCommit[] pList = c.parents;
+ int nParents = pList.length;
+ TreeWalk tw = pathFilter;
+ ObjectId[] trees = new ObjectId[nParents + 1];
for (int i = 0; i < nParents; i++) {
- final RevCommit p = c.parents[i];
- if ((p.flags & PARSED) == 0)
+ RevCommit p = c.parents[i];
+ if ((p.flags & PARSED) == 0) {
p.parseHeaders(walker);
+ }
trees[i] = p.getTree();
}
trees[nParents] = c.getTree();
@@ -156,10 +156,11 @@ public class TreeRevFilter extends RevFilter {
int chgs = 0, adds = 0;
while (tw.next()) {
chgs++;
- if (tw.getRawMode(0) == 0 && tw.getRawMode(1) != 0)
+ if (tw.getRawMode(0) == 0 && tw.getRawMode(1) != 0) {
adds++;
- else
+ } else {
break; // no point in looking at this further.
+ }
}
if (chgs == 0) {
@@ -185,8 +186,9 @@ public class TreeRevFilter extends RevFilter {
// We have no parents to compare against. Consider us to be
// REWRITE only if we have no paths matching our filter.
//
- if (tw.next())
+ if (tw.next()) {
return true;
+ }
c.flags |= rewriteFlag;
return false;
}
@@ -196,18 +198,19 @@ public class TreeRevFilter extends RevFilter {
// it does not contribute changes to us. Such a parent may be an
// uninteresting side branch.
//
- final int[] chgs = new int[nParents];
- final int[] adds = new int[nParents];
+ int[] chgs = new int[nParents];
+ int[] adds = new int[nParents];
while (tw.next()) {
- final int myMode = tw.getRawMode(nParents);
+ int myMode = tw.getRawMode(nParents);
for (int i = 0; i < nParents; i++) {
- final int pMode = tw.getRawMode(i);
- if (myMode == pMode && tw.idEqual(i, nParents))
+ int pMode = tw.getRawMode(i);
+ if (myMode == pMode && tw.idEqual(i, nParents)) {
continue;
-
+ }
chgs[i]++;
- if (pMode == 0 && myMode != 0)
+ if (pMode == 0 && myMode != 0) {
adds[i]++;
+ }
}
}
@@ -220,7 +223,7 @@ public class TreeRevFilter extends RevFilter {
// parent commit.
//
- final RevCommit p = pList[i];
+ RevCommit p = pList[i];
if ((p.flags & UNINTERESTING) != 0) {
// This parent was marked as not interesting by the
// application. We should look for another parent
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index 57d6bc2466..27cc205262 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -129,13 +129,13 @@ public abstract class BasePackFetchConnection extends BasePackConnection
public static final String OPTION_INCLUDE_TAG = GitProtocolConstants.OPTION_INCLUDE_TAG;
/**
- * Mutli-ACK support for improved negotiation.
+ * Multi-ACK support for improved negotiation.
* @since 2.0
*/
public static final String OPTION_MULTI_ACK = GitProtocolConstants.OPTION_MULTI_ACK;
/**
- * Mutli-ACK detailed support for improved negotiation.
+ * Multi-ACK detailed support for improved negotiation.
* @since 2.0
*/
public static final String OPTION_MULTI_ACK_DETAILED = GitProtocolConstants.OPTION_MULTI_ACK_DETAILED;
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 6c24269095..fe1b697612 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,11 @@ public final class FetchV2Request extends FetchRequest {
@NonNull
private final List<String> serverOptions;
+ private final boolean sidebandAll;
+
+ @NonNull
+ private final List<String> packfileUriProtocols;
+
FetchV2Request(@NonNull List<ObjectId> peerHas,
@NonNull List<String> wantedRefs,
@NonNull Set<ObjectId> wantIds,
@@ -79,7 +84,8 @@ public final class FetchV2Request extends FetchRequest {
@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, @NonNull List<String> packfileUriProtocols) {
super(wantIds, depth, clientShallowCommits, filterSpec,
clientCapabilities, deepenSince,
deepenNotRefs, agent);
@@ -87,6 +93,8 @@ public final class FetchV2Request extends FetchRequest {
this.wantedRefs = requireNonNull(wantedRefs);
this.doneReceived = doneReceived;
this.serverOptions = requireNonNull(serverOptions);
+ this.sidebandAll = sidebandAll;
+ this.packfileUriProtocols = packfileUriProtocols;
}
/**
@@ -127,6 +135,18 @@ public final class FetchV2Request extends FetchRequest {
return serverOptions;
}
+ /**
+ * @return true if "sideband-all" was received
+ */
+ boolean getSidebandAll() {
+ return sidebandAll;
+ }
+
+ @NonNull
+ List<String> getPackfileUriProtocols() {
+ return packfileUriProtocols;
+ }
+
/** @return A builder of {@link FetchV2Request}. */
static Builder builder() {
return new Builder();
@@ -159,6 +179,10 @@ public final class FetchV2Request extends FetchRequest {
final List<String> serverOptions = new ArrayList<>();
+ boolean sidebandAll;
+
+ final List<String> packfileUriProtocols = new ArrayList<>();
+
private Builder() {
}
@@ -318,13 +342,29 @@ public final class FetchV2Request extends FetchRequest {
}
/**
+ * @param value true if client sent "sideband-all"
+ * @return this builder
+ */
+ Builder setSidebandAll(boolean value) {
+ sidebandAll = value;
+ return this;
+ }
+
+ Builder addPackfileUriProtocol(@NonNull String value) {
+ packfileUriProtocols.add(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,
+ Collections.unmodifiableList(packfileUriProtocols));
}
}
}
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 1561c93b95..e3c0bc629a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -59,14 +59,14 @@ public final class GitProtocolConstants {
public static final String OPTION_INCLUDE_TAG = "include-tag"; //$NON-NLS-1$
/**
- * Mutli-ACK support for improved negotiation.
+ * Multi-ACK support for improved negotiation.
*
* @since 3.2
*/
public static final String OPTION_MULTI_ACK = "multi_ack"; //$NON-NLS-1$
/**
- * Mutli-ACK detailed support for improved negotiation.
+ * Multi-ACK detailed support for improved negotiation.
*
* @since 3.2
*/
@@ -174,6 +174,14 @@ public final class GitProtocolConstants {
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 0bdd6ba812..79af1ebc60 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 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
* @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 e9400919a8..7f837bb841 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 @@ public class PacketLineOut {
private boolean flushOnEnd;
+ private boolean usingSideband;
+
/**
* Create a new packet line writer.
*
@@ -98,6 +100,28 @@ public class PacketLineOut {
}
/**
+ * @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 @@ public class PacketLineOut {
* @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 542abe7563..4334888a9a 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 @@ import org.eclipse.jgit.storage.pack.PackStatistics;
* @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 @@ public class PostUploadHookChain implements PostUploadHook {
* 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 bfd52af74a..2192654b85 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 @@ import org.eclipse.jgit.lib.ObjectId;
* 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 @@ public class PreUploadHookChain implements PreUploadHook {
* 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 class PreUploadHookChain implements PreUploadHook {
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 @@ public class PreUploadHookChain implements PreUploadHook {
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 @@ public class PreUploadHookChain implements PreUploadHook {
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 0000000000..cc36473757
--- /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 caba15fc54..14ccddfb61 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_INCLUDE_TAG
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,13 @@ final class ProtocolV2Parser {
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 if (line2.startsWith("packfile-uris ")) { //$NON-NLS-1$
+ for (String s : line2.substring(14).split(",")) {
+ reqBuilder.addPackfileUriProtocol(s);
+ }
} 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 a3e655cd92..758d74c3fa 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 @@ public class TransferConfig {
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 @@ public class TransferConfig {
"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 @@ public class TransferConfig {
}
/**
+ * @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 6118cb8770..c0a70bcd2c 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 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport {
@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 a591dbae2a..3029327c52 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 @@ package org.eclipse.jgit.transport;
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;
@@ -75,6 +77,7 @@ import java.net.HttpCookie;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.ProxySelector;
+import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.InvalidPathException;
@@ -589,7 +592,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
JGitText.get().redirectsOff,
Integer.valueOf(status)));
}
- URIish newUri = redirect(conn.getHeaderField(HDR_LOCATION),
+ URIish newUri = redirect(u,
+ conn.getHeaderField(HDR_LOCATION),
Constants.INFO_REFS, redirects++);
setURI(newUri);
u = getServiceURL(service);
@@ -798,7 +802,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
}
}
- private URIish redirect(String location, String checkFor, int redirects)
+ private URIish redirect(URL currentUrl, String location, String checkFor,
+ int redirects)
throws TransportException {
if (location == null || location.isEmpty()) {
throw new TransportException(uri,
@@ -812,13 +817,16 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
location));
}
try {
- if (!isValidRedirect(baseUrl, location, checkFor)) {
+ URI redirectTo = new URI(location);
+ redirectTo = currentUrl.toURI().resolve(redirectTo);
+ String redirected = redirectTo.toASCIIString();
+ if (!isValidRedirect(baseUrl, redirected, checkFor)) {
throw new TransportException(uri,
MessageFormat.format(JGitText.get().redirectBlocked,
- baseUrl, location));
+ baseUrl, redirected));
}
- location = location.substring(0, location.indexOf(checkFor));
- URIish result = new URIish(location);
+ redirected = redirected.substring(0, redirected.indexOf(checkFor));
+ URIish result = new URIish(redirected);
if (LOG.isInfoEnabled()) {
LOG.info(MessageFormat.format(JGitText.get().redirectHttp,
uri.setPass(null),
@@ -1448,7 +1456,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
// Let openResponse() issue an error
return;
}
- currentUri = redirect(conn.getHeaderField(HDR_LOCATION),
+ currentUri = redirect(conn.getURL(),
+ conn.getHeaderField(HDR_LOCATION),
'/' + serviceName, redirects++);
try {
baseUrl = toURL(currentUri);
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 5c68308f90..8d91c6098a 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 @@ public class TransportSftp extends SshTransport implements WalkTransport {
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 9278f42adf..1e49c7b01f 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_DONE;
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;
@@ -92,6 +93,7 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.CachedPackUriProvider;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
import org.eclipse.jgit.internal.transport.parser.FirstWant;
import org.eclipse.jgit.lib.BitmapIndex;
@@ -113,6 +115,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevFlagSet;
import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
@@ -277,8 +280,6 @@ public class UploadPack {
private PacketLineIn pckIn;
- private PacketLineOut pckOut;
-
private OutputStream msgOut = NullOutputStream.INSTANCE;
/**
@@ -359,6 +360,8 @@ public class UploadPack {
*/
private FetchRequest currentRequest;
+ private CachedPackUriProvider cachedPackUriProvider;
+
/**
* Create a new pack upload for an open repository.
*
@@ -602,6 +605,18 @@ public class UploadPack {
}
/**
+ * 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
@@ -724,6 +739,15 @@ public class UploadPack {
this.clientRequestedV2 = params.contains("version=2"); //$NON-NLS-1$
}
+ /**
+ * @param p provider of URIs corresponding to cached packs (to support
+ * the packfile URIs feature)
+ * @since 5.5
+ */
+ public void setCachedPackUriProvider(@Nullable CachedPackUriProvider p) {
+ cachedPackUriProvider = p;
+ }
+
private boolean useProtocolV2() {
return ProtocolVersion.V2.equals(transferConfig.protocolVersion)
&& clientRequestedV2;
@@ -750,8 +774,9 @@ public class UploadPack {
* other network connections this should be null.
* @throws java.io.IOException
*/
- public void upload(final InputStream input, OutputStream output,
- final OutputStream messages) throws IOException {
+ public void upload(InputStream input, OutputStream output,
+ @Nullable OutputStream messages) throws IOException {
+ PacketLineOut pckOut = null;
try {
rawIn = input;
if (messages != null)
@@ -777,10 +802,40 @@ public class UploadPack {
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
+ // that indicates an error is already written to the client. Do
+ // nothing.
+ throw err;
+ } catch (ServiceMayNotContinueException err) {
+ if (!err.isOutput() && err.getMessage() != null && pckOut != null) {
+ try {
+ pckOut.writeString("ERR " + err.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ err.addSuppressed(e);
+ throw err;
+ }
+ err.setOutput();
+ }
+ throw err;
+ } catch (IOException | RuntimeException | Error err) {
+ if (pckOut != null) {
+ String msg = err instanceof PackProtocolException
+ ? err.getMessage()
+ : JGitText.get().internalServerError;
+ try {
+ pckOut.writeString("ERR " + msg + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ err.addSuppressed(e);
+ throw err;
+ }
+ throw new UploadPackInternalServerErrorException(err);
+ }
+ throw err;
} finally {
msgOut = NullOutputStream.INSTANCE;
walk.close();
@@ -941,7 +996,7 @@ public class UploadPack {
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.
@@ -997,7 +1052,7 @@ public class UploadPack {
if (!req.getClientShallowCommits().isEmpty())
walk.assumeShallow(req.getClientShallowCommits());
- sendPack = negotiate(req, accumulator);
+ sendPack = negotiate(req, accumulator, pckOut);
accumulator.timeNegotiating += System.currentTimeMillis()
- negotiateStart;
@@ -1012,31 +1067,6 @@ public class UploadPack {
"\\x" + Integer.toHexString(eof))); //$NON-NLS-1$
}
}
- } catch (ServiceMayNotContinueException err) {
- if (!err.isOutput() && err.getMessage() != null) {
- try {
- pckOut.writeString("ERR " + err.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
- err.setOutput();
- } catch (Throwable err2) {
- // Ignore this secondary failure (and not mark output).
- }
- }
- throw err;
- } catch (IOException | RuntimeException | Error err) {
- boolean output = false;
- try {
- String msg = err instanceof PackProtocolException
- ? err.getMessage()
- : JGitText.get().internalServerError;
- pckOut.writeString("ERR " + msg + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
- output = true;
- } catch (Throwable err2) {
- // Ignore this secondary failure, leave output false.
- }
- if (output) {
- throw new UploadPackInternalServerErrorException(err);
- }
- throw err;
} finally {
if (!sendPack && !biDirectionalPipe) {
while (0 < rawIn.skip(2048) || 0 <= rawIn.read()) {
@@ -1048,11 +1078,11 @@ public class UploadPack {
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);
@@ -1097,7 +1127,7 @@ public class UploadPack {
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
@@ -1117,6 +1147,10 @@ public class UploadPack {
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<>();
@@ -1202,13 +1236,17 @@ public class UploadPack {
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 {
@@ -1221,7 +1259,7 @@ public class UploadPack {
* 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();
@@ -1236,11 +1274,11 @@ public class UploadPack {
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
@@ -1258,12 +1296,14 @@ public class UploadPack {
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$
+ (cachedPackUriProvider != null ? "packfile-uris " : "") + // $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
@@ -1276,14 +1316,14 @@ public class UploadPack {
}
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.
@@ -1579,7 +1619,8 @@ public class UploadPack {
}
private boolean negotiate(FetchRequest req,
- PackStatistics.Accumulator accumulator)
+ PackStatistics.Accumulator accumulator,
+ PacketLineOut pckOut)
throws IOException {
okToGiveUp = Boolean.FALSE;
@@ -1868,6 +1909,36 @@ public class UploadPack {
}
}
+ private static void checkReachabilityByWalkingObjects(ObjectWalk walk,
+ List<RevObject> wants, Set<ObjectId> reachableFrom) throws IOException {
+
+ walk.sort(RevSort.TOPO);
+ for (RevObject want : wants) {
+ walk.markStart(want);
+ }
+ for (ObjectId have : reachableFrom) {
+ RevObject o = walk.parseAny(have);
+ walk.markUninteresting(o);
+
+ RevObject peeled = walk.peel(o);
+ if (peeled instanceof RevCommit) {
+ // By default, for performance reasons, ObjectWalk does not mark a
+ // tree as uninteresting when we mark a commit. Mark it ourselves so
+ // that we can determine reachability exactly.
+ walk.markUninteresting(((RevCommit) peeled).getTree());
+ }
+ }
+
+ RevCommit commit = walk.next();
+ if (commit != null) {
+ throw new WantNotValidException(commit);
+ }
+ RevObject object = walk.nextObject();
+ if (object != null) {
+ throw new WantNotValidException(object);
+ }
+ }
+
private static void checkNotAdvertisedWants(UploadPack up,
List<ObjectId> notAdvertisedWants, Set<ObjectId> reachableFrom)
throws IOException {
@@ -1888,6 +1959,17 @@ public class UploadPack {
if (!allWantsAreCommits) {
if (!repoHasBitmaps) {
+ if (up.transferConfig.isAllowFilter()) {
+ // Use allowFilter as an indication that the server
+ // operator is willing to pay the cost of these
+ // reachability checks.
+ try (ObjectWalk objWalk = walk.toObjectWalkWithSameObjects()) {
+ checkReachabilityByWalkingObjects(objWalk,
+ wantsAsObjs, reachableFrom);
+ }
+ return;
+ }
+
// If unadvertized non-commits are requested, use
// bitmaps. If there are no bitmaps, instead of
// incurring the expense of a manual walk, reject
@@ -2016,6 +2098,8 @@ public class UploadPack {
* 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.
*/
@@ -2023,43 +2107,51 @@ public class UploadPack {
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);
- } catch (ServiceMayNotContinueException noPack) {
- // This was already reported on (below).
- throw noPack;
+ deepenNots, pckOut);
+ } catch (ServiceMayNotContinueException err) {
+ String message = err.getMessage();
+ if (message == null) {
+ message = JGitText.get().internalServerError;
+ }
+ try {
+ reportInternalServerErrorOverSideband(message);
+ } catch (IOException e) {
+ err.addSuppressed(e);
+ throw err;
+ }
+ throw new UploadPackInternalServerErrorException(err);
} catch (IOException | RuntimeException | Error err) {
- if (reportInternalServerErrorOverSideband()) {
- throw new UploadPackInternalServerErrorException(err);
- } else {
+ try {
+ reportInternalServerErrorOverSideband(
+ JGitText.get().internalServerError);
+ } catch (IOException e) {
+ err.addSuppressed(e);
throw err;
}
+ throw new UploadPackInternalServerErrorException(err);
}
} else {
- sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots);
+ sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots,
+ pckOut);
}
}
- private boolean reportInternalServerErrorOverSideband() {
- try {
- @SuppressWarnings("resource" /* java 7 */)
- SideBandOutputStream err = new SideBandOutputStream(
- SideBandOutputStream.CH_ERROR,
- SideBandOutputStream.SMALL_BUF,
- rawOut);
- err.write(Constants.encode(JGitText.get().internalServerError));
- err.flush();
- return true;
- } catch (Throwable cannotReport) {
- // Ignore the reason. This is a secondary failure.
- return false;
- }
+ private void reportInternalServerErrorOverSideband(String message)
+ throws IOException {
+ @SuppressWarnings("resource" /* java 7 */)
+ SideBandOutputStream err = new SideBandOutputStream(
+ SideBandOutputStream.CH_ERROR, SideBandOutputStream.SMALL_BUF,
+ rawOut);
+ err.write(Constants.encode(message));
+ err.flush();
}
/**
@@ -2079,6 +2171,8 @@ public class UploadPack {
* 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.
*/
@@ -2087,7 +2181,8 @@ public class UploadPack {
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;
@@ -2105,25 +2200,12 @@ public class UploadPack {
}
}
- try {
- if (wantAll.isEmpty()) {
- preUploadHook.onSendPack(this, wantIds, commonBase);
- } else {
- preUploadHook.onSendPack(this, wantAll, commonBase);
- }
- msgOut.flush();
- } catch (ServiceMayNotContinueException noPack) {
- if (sideband && noPack.getMessage() != null) {
- noPack.setOutput();
- @SuppressWarnings("resource" /* java 7 */)
- SideBandOutputStream err = new SideBandOutputStream(
- SideBandOutputStream.CH_ERROR,
- SideBandOutputStream.SMALL_BUF, rawOut);
- err.write(Constants.encode(noPack.getMessage()));
- err.flush();
- }
- throw noPack;
+ if (wantAll.isEmpty()) {
+ preUploadHook.onSendPack(this, wantIds, commonBase);
+ } else {
+ preUploadHook.onSendPack(this, wantAll, commonBase);
}
+ msgOut.flush();
PackConfig cfg = packConfig;
if (cfg == null)
@@ -2219,12 +2301,32 @@ public class UploadPack {
if (peeledId == null || objectId == null)
continue;
+ objectId = ref.getObjectId();
if (pw.willInclude(peeledId) && !pw.willInclude(objectId)) {
- pw.addObject(rw.parseAny(objectId));
+ RevObject o = rw.parseAny(objectId);
+ addTagChain(o, pw);
+ pw.addObject(o);
}
}
}
+ if (pckOut.isUsingSideband()) {
+ if (req instanceof FetchV2Request &&
+ cachedPackUriProvider != null &&
+ !((FetchV2Request) req).getPackfileUriProtocols().isEmpty()) {
+ FetchV2Request reqV2 = (FetchV2Request) req;
+ pw.setPackfileUriConfig(new PackWriter.PackfileUriConfig(
+ pckOut,
+ reqV2.getPackfileUriProtocols(),
+ cachedPackUriProvider));
+ } else {
+ // PackWriter will write "packfile-uris\n" and "packfile\n"
+ // for us if provided a PackfileUriConfig. In this case, we
+ // are not providing a PackfileUriConfig, so we have to
+ // write this line ourselves.
+ pckOut.writeString("packfile\n"); //$NON-NLS-1$
+ }
+ }
pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut);
if (msgOut != NullOutputStream.INSTANCE) {
@@ -2253,6 +2355,18 @@ public class UploadPack {
}
}
+ private void addTagChain(
+ RevObject o, PackWriter pw) throws IOException {
+ while (Constants.OBJ_TAG == o.getType()) {
+ RevTag t = (RevTag) o;
+ o = t.getObject();
+ if (o.getType() == Constants.OBJ_TAG && !pw.willInclude(o.getId())) {
+ walk.parseBody(o);
+ pw.addObject(o);
+ }
+ }
+ }
+
private static class ResponseBufferedOutputStream extends OutputStream {
private final OutputStream rawOut;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index b4248ee3fc..7a973aff34 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
@@ -66,8 +66,8 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import javax.xml.bind.DatatypeConverter;
+import org.bouncycastle.util.encoders.Hex;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.util.Base64;
@@ -301,7 +301,7 @@ abstract class WalkEncryption {
String DEFAULT_KEY_ALGO = JetS3tV2.ALGORITHM;
String DEFAULT_KEY_SIZE = Integer.toString(JetS3tV2.KEY_SIZE);
String DEFAULT_KEY_ITER = Integer.toString(JetS3tV2.ITERATIONS);
- String DEFAULT_KEY_SALT = DatatypeConverter.printHexBinary(JetS3tV2.SALT);
+ String DEFAULT_KEY_SALT = Hex.toHexString(JetS3tV2.SALT);
String EMPTY = ""; //$NON-NLS-1$
@@ -377,8 +377,7 @@ abstract class WalkEncryption {
final byte[] salt;
try {
- salt = DatatypeConverter
- .parseHexBinary(keySalt.replaceAll(REGEX_WS, EMPTY));
+ salt = Hex.decode(keySalt.replaceAll(REGEX_WS, EMPTY));
} catch (Exception e) {
throw securityError(X_KEY_SALT + EMPTY + keySalt);
}
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 5c67253cfc..4862d676e1 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 @@ abstract class WalkRemoteObjectDatabase {
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 @@ abstract class WalkRemoteObjectDatabase {
/**
* 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>