From 5dce8614ab45e48a93ca3083105f0ac891229d8a Mon Sep 17 00:00:00 2001 From: Ivan Frade Date: Mon, 20 May 2019 17:14:22 -0700 Subject: [PATCH 01/51] RevWalk: new method createReachabilityChecker() Every caller would need to check if bitmaps are available in the repo to instantiate a reachability checker. Offer a method to create the reachability checker in the walk: the caller has already a walk over the repo, and the walk has all the information required. This allows us to make the implementation classes package-private. Change-Id: I355e47486fcd9d55baa7cb5700ec08dcc230eea5 Signed-off-by: Ivan Frade --- .../revwalk/BitmappedReachabilityChecker.java | 4 +--- .../revwalk/PedestrianReachabilityChecker.java | 4 +--- .../src/org/eclipse/jgit/revwalk/RevWalk.java | 17 +++++++++++++++++ .../org/eclipse/jgit/transport/UploadPack.java | 7 ++----- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java index ab453433d..6e510f677 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java @@ -55,10 +55,8 @@ import org.eclipse.jgit.lib.NullProgressMonitor; /** * Checks the reachability using bitmaps. - * - * @since 5.4 */ -public class BitmappedReachabilityChecker implements ReachabilityChecker { +class BitmappedReachabilityChecker implements ReachabilityChecker { private final RevWalk walk; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java index 4012a45d3..bba3c5cff 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java @@ -52,10 +52,8 @@ import org.eclipse.jgit.errors.MissingObjectException; /** * Checks the reachability walking the graph from the starters towards the * target. - * - * @since 5.4 */ -public class PedestrianReachabilityChecker implements ReachabilityChecker { +class PedestrianReachabilityChecker implements ReachabilityChecker { private final boolean topoSort; 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 f12eb2ff8..80fc81073 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java @@ -249,6 +249,23 @@ public class RevWalk implements Iterable, AutoCloseable { return reader; } + /** + * Get a reachability checker for commits over this revwalk. + * + * @return the most efficient reachability checker for this repository. + * @throws IOException + * if it cannot open any of the underlying indices. + * + * @since 5.4 + */ + public ReachabilityChecker createReachabilityChecker() throws IOException { + if (reader.getBitmapIndex() != null) { + return new BitmappedReachabilityChecker(this); + } + + return new PedestrianReachabilityChecker(true, this); + } + /** * {@inheritDoc} *

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 3ed9886c4..6217d2a0e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -106,10 +106,8 @@ import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.AsyncRevObjectQueue; import org.eclipse.jgit.revwalk.BitmapWalker; -import org.eclipse.jgit.revwalk.BitmappedReachabilityChecker; import org.eclipse.jgit.revwalk.DepthWalk; import org.eclipse.jgit.revwalk.ObjectWalk; -import org.eclipse.jgit.revwalk.PedestrianReachabilityChecker; import org.eclipse.jgit.revwalk.ReachabilityChecker; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevFlag; @@ -1909,9 +1907,8 @@ public class UploadPack { } // All wants are commits, we can use ReachabilityChecker - ReachabilityChecker reachabilityChecker = repoHasBitmaps - ? new BitmappedReachabilityChecker(walk) - : new PedestrianReachabilityChecker(true, walk); + ReachabilityChecker reachabilityChecker = walk + .createReachabilityChecker(); List starters = objectIdsToRevCommits(walk, reachableFrom); From 73ba6658cf1435b7655eed47c172a246af6b4698 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 23 May 2019 02:12:16 +0200 Subject: [PATCH 02/51] BitmapCalculator and its test: add missing license header Change-Id: I3c4a8b1e9159b0553aa95213bb82628370b6c036 Signed-off-by: Matthias Sohn --- .../jgit/revwalk/BitmapCalculatorTest.java | 42 +++++++++++++++++++ .../jgit/revwalk/BitmapCalculator.java | 42 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java index 3a78e1e62..c5d4d4238 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java @@ -1,3 +1,45 @@ +/* + * 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.revwalk; import static org.junit.Assert.assertEquals; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java index e1d5d4ada..a46383160 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java @@ -1,3 +1,45 @@ +/* + * 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.revwalk; import static java.util.Objects.requireNonNull; From 22360a4bee09688acc54961062a6e7e5950d207d Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Mon, 13 May 2019 11:23:31 +0200 Subject: [PATCH 03/51] Upgrade jacoco-maven-plugin to 0.8.4 Change-Id: Ibab24e1f5eefdc14bcf9ab6d72eab7e0a0cfaad9 Signed-off-by: David Pursehouse --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5377b9e40..e2ae7a283 100644 --- a/pom.xml +++ b/pom.xml @@ -366,7 +366,7 @@ org.jacoco jacoco-maven-plugin - 0.8.3 + 0.8.4 org.apache.maven.plugins From d510929a253fe4bc6673928d1a0119ae1943fd7c Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Mon, 13 May 2019 11:24:29 +0200 Subject: [PATCH 04/51] Upgrade maven-jar-plugin to 3.1.2 Change-Id: I9a291390205ee8c44b02c4081f2d8f17635d90ec Signed-off-by: David Pursehouse --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e2ae7a283..92e67ba47 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.1.1 + 3.1.2 From 87c7bda9145296625a9dbd6c7c75c59033dd8f02 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Tue, 21 May 2019 08:25:38 +0900 Subject: [PATCH 05/51] Upgrade maven-source-plugin to 3.1.0 Change-Id: I8253e75f5038b6c0e2205d74683e0ebd9839dd33 Signed-off-by: David Pursehouse --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 92e67ba47..780cbdc2b 100644 --- a/pom.xml +++ b/pom.xml @@ -282,7 +282,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.1.0 From e57a37e76782356eb5a93a71c6288e64fe03e5f1 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Sat, 25 May 2019 09:53:47 +0200 Subject: [PATCH 06/51] RevWalkUtils: add progress callback to findBranchesReachableFrom Offer a version of findBranchesReachableFrom method with progress monitor callback. This is required to allow UI clients to cancel long running operations and show progress. Bug: 547642 Change-Id: I31d1de54dbaa6ffb11e03da4c447963e8defa1d0 Signed-off-by: Andrey Loskutov --- .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/internal/JGitText.java | 1 + .../eclipse/jgit/revwalk/RevWalkUtils.java | 42 ++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index fc2a26f0d..6da6fee38 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -625,6 +625,7 @@ rewinding=Rewinding to commit {0} s3ActionDeletion=Deletion s3ActionReading=Reading s3ActionWriting=Writing +searchForReachableBranches=Finding reachable branches searchForReuse=Finding sources searchForSizes=Getting sizes secondsAgo={0} seconds ago 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 ca0024d1c..7a5ef4b7e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -686,6 +686,7 @@ public class JGitText extends TranslationBundle { /***/ public String s3ActionDeletion; /***/ public String s3ActionReading; /***/ public String s3ActionWriting; + /***/ public String searchForReachableBranches; /***/ public String searchForReuse; /***/ public String searchForSizes; /***/ public String secondsAgo; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java index fabf7075d..2b721b887 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java @@ -50,6 +50,9 @@ import java.util.List; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; /** @@ -153,15 +156,51 @@ public final class RevWalkUtils { RevWalk revWalk, Collection refs) throws MissingObjectException, IncorrectObjectTypeException, IOException { + return findBranchesReachableFrom(commit, revWalk, refs, + NullProgressMonitor.INSTANCE); + } + + /** + * Find the list of branches a given commit is reachable from when following + * parents. + *

+ * Note that this method calls + * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. + *

+ * In order to improve performance this method assumes clock skew among + * committers is never larger than 24 hours. + * + * @param commit + * the commit we are looking at + * @param revWalk + * The RevWalk to be used. + * @param refs + * the set of branches we want to see reachability from + * @param monitor + * the callback for progress and cancellation + * @return the list of branches a given commit is reachable from + * @throws org.eclipse.jgit.errors.MissingObjectException + * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException + * @throws java.io.IOException + * @since 5.4 + */ + public static List findBranchesReachableFrom(RevCommit commit, + RevWalk revWalk, Collection refs, ProgressMonitor monitor) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { // Make sure commit is from the same RevWalk commit = revWalk.parseCommit(commit.getId()); revWalk.reset(); List result = new ArrayList<>(); - + monitor.beginTask(JGitText.get().searchForReachableBranches, + refs.size()); final int SKEW = 24*3600; // one day clock skew for (Ref ref : refs) { + if (monitor.isCancelled()) + return result; + monitor.update(1); RevObject maybehead = revWalk.parseAny(ref.getObjectId()); if (!(maybehead instanceof RevCommit)) continue; @@ -176,6 +215,7 @@ public final class RevWalkUtils { if (revWalk.isMergedInto(commit, headCommit)) result.add(ref); } + monitor.endTask(); return result; } From 82316fc23a31787e80feaf5530e440d311d60b0b Mon Sep 17 00:00:00 2001 From: Ivan Frade Date: Thu, 23 May 2019 10:39:31 -0700 Subject: [PATCH 07/51] BitmapCalculator: javadoc fixes Fill out the description of when IOException is thrown. Also fix a typo in the description for IncorrectObjectTypeException. Change-Id: I9fafd19d68ddc4fe4e95e8516c2c38484b941a3a Signed-off-by: Ivan Frade Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/revwalk/BitmapCalculator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java index a46383160..14e95670a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java @@ -94,8 +94,9 @@ class BitmapCalculator { * @throws MissingObjectException * the supplied id doesn't exist * @throws IncorrectObjectTypeException - * the supplied id doens't refer to a commit or a tag + * the supplied id doesn't refer to a commit or a tag * @throws IOException + * if the walk cannot open a packfile or loose object */ BitmapBuilder getBitmap(RevCommit start, ProgressMonitor pm) throws MissingObjectException, From cd1d2d6fe36725301087cf00b4a0a6453b1d3ccc Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Thu, 30 May 2019 20:17:24 +0900 Subject: [PATCH 08/51] UploadPackTest: Add missing <> operator on instantiation of ArrayList Change-Id: I348cbcd75252d7857ada843dc496d445ee1d62fb Signed-off-by: David Pursehouse --- .../tst/org/eclipse/jgit/transport/UploadPackTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 9ffcbccc8..85be4348a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -1557,7 +1557,7 @@ public class UploadPackTest { long depth, ObjectId... wants) throws Exception { server.getConfig().setBoolean("uploadpack", null, "allowfilter", true); - List input = new ArrayList(); + List input = new ArrayList<>(); input.add("command=fetch\n"); input.add(PacketLineIn.DELIM); for (ObjectId want : wants) { From 9f5d271b12e93f927b18e76a1a8c1f650cd40cdf Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Thu, 30 May 2019 20:18:28 +0900 Subject: [PATCH 09/51] UploadPackTest: Rename variable to avoid hiding class member Change-Id: I9e02642b2f56a735681e58b8c8d6e3545ef9093b Signed-off-by: David Pursehouse --- .../tst/org/eclipse/jgit/transport/UploadPackTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 85be4348a..3ead31dbd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -1088,8 +1088,8 @@ public class UploadPackTest { PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); - ReceivedPackStatistics stats = parsePack(recvStream); - assertTrue(stats.getNumOfsDelta() == 0); + ReceivedPackStatistics receivedStats = parsePack(recvStream); + assertTrue(receivedStats.getNumOfsDelta() == 0); // With ofs-delta. recvStream = uploadPackV2( @@ -1101,8 +1101,8 @@ public class UploadPackTest { PacketLineIn.END); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); - stats = parsePack(recvStream); - assertTrue(stats.getNumOfsDelta() != 0); + receivedStats = parsePack(recvStream); + assertTrue(receivedStats.getNumOfsDelta() != 0); } @Test From d2425e16f465303905ba23309d876127faa93af1 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Thu, 30 May 2019 20:31:39 +0900 Subject: [PATCH 10/51] PacketLineIn: Add helper methods to check for END and DELIM These methods will allow clients to check for END and DELIM without doing a reference comparison on the String objects, which raises warnings from Error Prone. Change-Id: I9e7e59843553ed4488ee8e864033198bbb60d67c Signed-off-by: David Pursehouse --- .../jgit/transport/PacketLineInTest.java | 13 +++++----- .../eclipse/jgit/transport/PacketLineIn.java | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java index 8b1d86005..1e5a03256 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java @@ -44,7 +44,8 @@ package org.eclipse.jgit.transport; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; @@ -142,21 +143,21 @@ public class PacketLineInTest { init("0004"); final String act = in.readString(); assertEquals("", act); - assertNotSame(PacketLineIn.END, act); + assertFalse(PacketLineIn.isEnd(act)); assertEOF(); } @Test public void testReadString_End() throws IOException { init("0000"); - assertSame(PacketLineIn.END, in.readString()); + assertTrue(PacketLineIn.isEnd(in.readString())); assertEOF(); } @Test public void testReadString_Delim() throws IOException { init("0001"); - assertSame(PacketLineIn.DELIM, in.readString()); + assertTrue(PacketLineIn.isDelim(in.readString())); assertEOF(); } @@ -183,14 +184,14 @@ public class PacketLineInTest { init("0004"); final String act = in.readStringRaw(); assertEquals("", act); - assertNotSame(PacketLineIn.END, act); + assertFalse(PacketLineIn.isEnd(act)); assertEOF(); } @Test public void testReadStringRaw_End() throws IOException { init("0000"); - assertSame(PacketLineIn.END, in.readStringRaw()); + assertTrue(PacketLineIn.isEnd(in.readString())); assertEOF(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index c6e19d576..15d3481f4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -224,6 +224,30 @@ public class PacketLineIn { return s; } + /** + * Check if a string is the delimiter marker. + * + * @param s + * the string to check + * @return true if the given string is {@link #DELIM}, otherwise false. + * @since 5.4 + */ + public static boolean isDelim(String s) { + return s == DELIM; + } + + /** + * Check if a string is the packet end marker. + * + * @param s + * the string to check + * @return true if the given string is {@link #END}, otherwise false. + * @since 5.4 + */ + public static boolean isEnd(String s) { + return s == END; + } + void discardUntilEnd() throws IOException { for (;;) { int n = readLength(); From 22352e47516546c1484bf912b8499e88a119b1e7 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 30 May 2019 23:51:05 +0200 Subject: [PATCH 11/51] Remove excess blank line in FileUtilsTest Change-Id: I0d617feb7baacf9917b1da605fcb75f7d4ccd184 Signed-off-by: Matthias Sohn --- .../tst/org/eclipse/jgit/util/FileUtilsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java index c0f496566..9ee9613f7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java @@ -137,7 +137,6 @@ public class FileUtilsTest { } @Test - public void testDeleteRecursiveEmpty() throws IOException { File f1 = new File(trash, "test/test/a"); File f2 = new File(trash, "test/a"); From afcb3a8c9e9a245baceb671868923bb2500f77f6 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Fri, 31 May 2019 17:08:39 +0200 Subject: [PATCH 12/51] DescribeCommand: Consistenly omit the default value Omit the default value of "false" for "useTags" like already done for "longDesc". Change-Id: I25aaacae028fc8cf27f4040ba45fe79609318aa1 Signed-off-by: Sebastian Schuberth --- org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index 9ebcf9fd0..659812450 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -109,7 +109,7 @@ public class DescribeCommand extends GitCommand { /** * Whether to use all tags (incl. lightweight) or not. */ - private boolean useTags = false; + private boolean useTags; /** * Constructor for DescribeCommand. From 0cac83466842a26a4901151b9db11a9a7428dc5a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 18 Mar 2019 22:00:15 +0100 Subject: [PATCH 13/51] cli: Add the --tags option to describe Change-Id: I78924e61e2050eeaff991ee56715f36514100492 Signed-off-by: Sebastian Schuberth --- .../org/eclipse/jgit/pgm/internal/CLIText.properties | 1 + org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index b9982fe6a..47716149b 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -289,6 +289,7 @@ usage_Status=Show the working tree status usage_StopTrackingAFile=Stop tracking a file usage_TextHashFunctions=Scan repository to compute maximum number of collisions for hash functions usage_UpdateRemoteRepositoryFromLocalRefs=Update remote repository from local refs +usage_UseTags=Use any tag including lightweight tags usage_WriteDirCache=Write the DirCache usage_abbrevCommits=abbreviate commits to N + 1 digits usage_abortConnectionIfNoActivity=abort connection if no activity diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java index d89fee623..6d7df9767 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java @@ -65,6 +65,9 @@ class Describe extends TextBuiltin { @Option(name = "--long", usage = "usage_LongFormat") private boolean longDesc; + @Option(name = "--tags", usage = "usage_UseTags") + private boolean useTags; + @Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern") private List patterns = new ArrayList<>(); @@ -77,6 +80,7 @@ class Describe extends TextBuiltin { cmd.setTarget(tree); } cmd.setLong(longDesc); + cmd.setTags(useTags); cmd.setMatch(patterns.toArray(new String[0])); String result = null; try { From 237c76fddfbca59062c495ce4b3e05ea61b1cd7e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Fri, 15 Mar 2019 15:27:18 +0100 Subject: [PATCH 14/51] DescribeCommand: Support the "always" option See: https://git-scm.com/docs/git-describe#Documentation/git-describe.txt---always Extend the tests accordingly. Change-Id: Ibfcda338a246c8cba0df6b6e7b9bad76c9f8b593 Signed-off-by: Sebastian Schuberth --- .../eclipse/jgit/api/DescribeCommandTest.java | 31 ++++++++++++++----- .../org/eclipse/jgit/api/DescribeCommand.java | 25 +++++++++++++-- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index bc3ac7a72..fd3aa2884 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java @@ -109,7 +109,7 @@ public class DescribeCommandTest extends RepositoryTestCase { assertNameStartsWith(c4, "3e563c5"); assertNull(describe(c1)); - assertNull(describe(c1, true)); + assertNull(describe(c1, true, false)); assertNull(describe(c1, "a*", "b*", "c*")); assertNull(describe(c2, "bob*")); assertNull(describe(c2, "?ob*")); @@ -120,7 +120,7 @@ public class DescribeCommandTest extends RepositoryTestCase { assertEquals("alice-t1", describe(c2, "a*", "b*", "c*")); assertEquals("bob-t2", describe(c3)); - assertEquals("bob-t2-0-g44579eb", describe(c3, true)); + assertEquals("bob-t2-0-g44579eb", describe(c3, true, false)); assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*")); assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*")); assertEquals("bob-t2", describe(c3, "bob*")); @@ -129,7 +129,7 @@ public class DescribeCommandTest extends RepositoryTestCase { // the value verified with git-describe(1) assertEquals("bob-t2-1-g3e563c5", describe(c4)); - assertEquals("bob-t2-1-g3e563c5", describe(c4, true)); + assertEquals("bob-t2-1-g3e563c5", describe(c4, true, false)); assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*")); assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*")); assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*")); @@ -137,6 +137,10 @@ public class DescribeCommandTest extends RepositoryTestCase { assertEquals(null, describe(c2)); assertEquals(null, describe(c3)); assertEquals(null, describe(c4)); + + assertEquals("3747db3", describe(c2, false, true)); + assertEquals("44579eb", describe(c3, false, true)); + assertEquals("3e563c5", describe(c4, false, true)); } // test default target @@ -169,6 +173,10 @@ public class DescribeCommandTest extends RepositoryTestCase { if (!useAnnotatedTags && !describeUseAllTags) { assertEquals(null, describe(c1)); assertEquals(null, describe(c2)); + + assertEquals("fd70040", describe(c1, false, true)); + assertEquals("b89dead", describe(c2, false, true)); + return; } @@ -235,9 +243,11 @@ public class DescribeCommandTest extends RepositoryTestCase { assertEquals("2 commits: c4 and c3", "t-2-g119892b", describe(c4)); } else { assertEquals(null, describe(c4)); + + assertEquals("119892b", describe(c4, false, true)); } assertNull(describe(c3)); - assertNull(describe(c3, true)); + assertNull(describe(c3, true, false)); } private void branch(String name, ObjectId base) throws GitAPIException { @@ -279,6 +289,9 @@ public class DescribeCommandTest extends RepositoryTestCase { } else { assertEquals(null, describe(c4)); assertEquals(null, describe(c3)); + + assertEquals("119892b", describe(c4, false, true)); + assertEquals("0244e7f", describe(c3, false, true)); } } @@ -368,6 +381,8 @@ public class DescribeCommandTest extends RepositoryTestCase { assertEquals("t1-3-gbb389a4", describe(c4)); } else { assertEquals(null, describe(c4)); + + assertEquals("bb389a4", describe(c4, false, true)); } } @@ -401,6 +416,8 @@ public class DescribeCommandTest extends RepositoryTestCase { assertEquals("t2-4-gbb389a4", describe(c4)); } else { assertEquals(null, describe(c4)); + + assertEquals("bb389a4", describe(c4, false, true)); } } @@ -433,14 +450,14 @@ public class DescribeCommandTest extends RepositoryTestCase { } } - private String describe(ObjectId c1, boolean longDesc) + private String describe(ObjectId c1, boolean longDesc, boolean always) throws GitAPIException, IOException { return git.describe().setTarget(c1).setTags(describeUseAllTags) - .setLong(longDesc).call(); + .setLong(longDesc).setAlways(always).call(); } private String describe(ObjectId c1) throws GitAPIException, IOException { - return describe(c1, false); + return describe(c1, false, false); } private String describe(ObjectId c1, String... patterns) throws Exception { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index 659812450..db3a3d947 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -111,6 +111,11 @@ public class DescribeCommand extends GitCommand { */ private boolean useTags; + /** + * Whether to show a uniquely abbreviated commit hash as a fallback or not. + */ + private boolean always; + /** * Constructor for DescribeCommand. * @@ -197,6 +202,21 @@ public class DescribeCommand extends GitCommand { return this; } + /** + * Always describe the commit by eventually falling back to a uniquely + * abbreviated commit hash if no other name matches. + * + * @param always + * true enables falling back to a uniquely + * abbreviated commit hash + * @return {@code this} + * @since 5.4 + */ + public DescribeCommand setAlways(boolean always) { + this.always = always; + return this; + } + private String longDescription(Ref tag, int depth, ObjectId tip) throws IOException { return String.format( @@ -399,8 +419,9 @@ public class DescribeCommand extends GitCommand { } // if all the nodes are dominated by all the tags, the walk stops - if (candidates.isEmpty()) - return null; + if (candidates.isEmpty()) { + return always ? w.getObjectReader().abbreviate(target).name() : null; + } Candidate best = Collections.min(candidates, (Candidate o1, Candidate o2) -> o1.depth - o2.depth); From 9ea1ed158b1af805479561a9b1d92b8341ffc1c5 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 18 Mar 2019 22:04:05 +0100 Subject: [PATCH 15/51] cli: Add the --always option to describe Change-Id: I0342d589e4deabe9d80ea3c9c6b48d7b265d8fe6 Signed-off-by: Sebastian Schuberth --- .../org/eclipse/jgit/pgm/internal/CLIText.properties | 1 + org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index 47716149b..2a5a31eba 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -222,6 +222,7 @@ unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: updating=Updating {0}..{1} usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time +usage_AlwaysFallback=Show uniquely abbreviated commit object as fallback usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR. usage_Blame=Show what revision and author last modified each line usage_Clean=Remove untracked files from the working tree diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java index 6d7df9767..8a572f44b 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java @@ -68,6 +68,9 @@ class Describe extends TextBuiltin { @Option(name = "--tags", usage = "usage_UseTags") private boolean useTags; + @Option(name = "--always", usage = "usage_AlwaysFallback") + private boolean always; + @Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern") private List patterns = new ArrayList<>(); @@ -81,6 +84,7 @@ class Describe extends TextBuiltin { } cmd.setLong(longDesc); cmd.setTags(useTags); + cmd.setAlways(always); cmd.setMatch(patterns.toArray(new String[0])); String result = null; try { From fc40a173d63a1b7603153aef591e2592776ca288 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Fri, 31 May 2019 14:57:06 +0200 Subject: [PATCH 16/51] Update to Orbit R20190531194818 and rollback update to Ant 1.10.6 An issue has been reported with Java 1.8 and new Ant version 1.10.6 hence this was rolled back to 1.10.5 in Orbit. See: https://bz.apache.org/bugzilla/show_bug.cgi?id=63457 Bug: 547607 Change-Id: I9c04c988ec89bb1e2cbb528a2d3add30a0b7b3b9 Signed-off-by: Matthias Sohn --- .../org.eclipse.jgit.target/jgit-4.10.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.10.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.11.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.11.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.12-staging.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.12-staging.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.6.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.6.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.7.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.7.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.8.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.8.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.9.target | 8 ++++---- .../org.eclipse.jgit.target/jgit-4.9.tpd | 2 +- .../{S20190521195709.tpd => R20190531194818-2019-06.tpd} | 8 ++++---- 15 files changed, 39 insertions(+), 39 deletions(-) rename org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/{S20190521195709.tpd => R20190531194818-2019-06.tpd} (93%) diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target index 440092a17..b187ecee0 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd index 5bfd81411..e949a9f3c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd @@ -1,7 +1,7 @@ target "jgit-4.10" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/2018-12/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target index a3ad331a4..ea0b20ef2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd index 8b3b509fd..b8ebf43d9 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd @@ -1,7 +1,7 @@ target "jgit-4.11" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/2019-03/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target index 2ea7b79f9..d8ebcfde2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd index f0cd3049f..e18789559 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd @@ -1,7 +1,7 @@ target "jgit-4.12-staging" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/staging/2019-06/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index 64cf3e7d2..21cdb0c19 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd index 8ae721fed..e1fbb7fdc 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd @@ -1,7 +1,7 @@ target "jgit-4.6" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/neon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index eb8c8e91d..e5bd111de 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd index 430506aee..42ffcfe2e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd @@ -1,7 +1,7 @@ target "jgit-4.7" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/oxygen/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index 9764a6158..5bbc23ed5 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd index e18fc7255..b5bcf0dde 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd @@ -1,7 +1,7 @@ target "jgit-4.8" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/photon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target index 331d141b6..a0fc30bcd 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target @@ -1,7 +1,7 @@ - + @@ -23,8 +23,8 @@ - - + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd index 6b71dff4a..4e4ab770d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd @@ -1,7 +1,7 @@ target "jgit-4.9" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/S20190521195709.tpd" +include "orbit/R20190531194818-2019-06.tpd" location "http://download.eclipse.org/releases/2018-09/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20190521195709.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd similarity index 93% rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20190521195709.tpd rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd index d526ab432..1ab52cefa 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20190521195709.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd @@ -1,9 +1,9 @@ -target "S20190521195709" with source configurePhase +target "R20190531194818-2019-06" with source configurePhase // see http://download.eclipse.org/tools/orbit/downloads/ -location "http://download.eclipse.org/tools/orbit/downloads/drops/S20190521195709/repository" { - org.apache.ant [1.10.6.v20190516-0412,1.10.6.v20190516-0412] - org.apache.ant.source [1.10.6.v20190516-0412,1.10.6.v20190516-0412] +location "https://download.eclipse.org/tools/orbit/downloads/drops/R20190531194818/repository" { + org.apache.ant [1.10.5.v20190526-1402,1.10.5.v20190526-1402] + org.apache.ant.source [1.10.5.v20190526-1402,1.10.5.v20190526-1402] org.apache.commons.codec [1.10.0.v20180409-1845,1.10.0.v20180409-1845] org.apache.commons.codec.source [1.10.0.v20180409-1845,1.10.0.v20180409-1845] org.apache.commons.compress [1.18.0.v20181121-2221,1.18.0.v20181121-2221] From f4443ef3f9e31d43f0f8690e3026635f5c7be9da Mon Sep 17 00:00:00 2001 From: Brandon Weeks Date: Wed, 17 Apr 2019 00:15:46 +0200 Subject: [PATCH 17/51] Upgrade Bouncy Castle to 1.61 Also now use JcaKeyBoxBuilder constructor in BouncyCastleGpgKeyLocator.readKeyBoxFile(Path). CQ: 19868 CQ: 19869 CQ: 19870 Change-Id: I45bd80e158aecd90448b0c7e59615db27aaef892 Signed-off-by: Brandon Weeks Signed-off-by: Matthias Sohn --- WORKSPACE | 14 +++++----- .../org.eclipse.jgit.target/jgit-4.10.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.11.target | 16 +++++------ .../jgit-4.12-staging.target | 27 +++++++++---------- .../org.eclipse.jgit.target/jgit-4.6.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.7.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.8.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.9.target | 16 +++++------ .../orbit/R20190531194818-2019-06.tpd | 12 ++++----- org.eclipse.jgit.test/META-INF/MANIFEST.MF | 2 +- org.eclipse.jgit/META-INF/MANIFEST.MF | 21 ++++++++------- .../internal/BouncyCastleGpgKeyLocator.java | 24 ++++++++++------- .../lib/internal/BouncyCastleGpgSigner.java | 11 +++++--- pom.xml | 2 +- 14 files changed, 109 insertions(+), 100 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 7ddd55463..b11de7a68 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -212,25 +212,25 @@ maven_jar( src_sha1 = "94e89a8c9f82e38555e95b9f7f58344a247e862c", ) -BOUNCYCASTLE_VER = "1.60" +BOUNCYCASTLE_VER = "1.61" maven_jar( name = "bcpg", artifact = "org.bouncycastle:bcpg-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "13c7a199c484127daad298996e95818478431a2c", - src_sha1 = "edcd9e86d95e39b4da39bb295efd93bc4f56266e", + sha1 = "422656435514ab8a28752b117d5d2646660a0ace", + src_sha1 = "836da34e11114cbce8fa99f54175f8f3278d1cce", ) maven_jar( name = "bcprov", artifact = "org.bouncycastle:bcprov-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "bd47ad3bd14b8e82595c7adaa143501e60842a84", - src_sha1 = "7c57a4d13fe53d9abb967bba600dd0b293dafd6a", + sha1 = "00df4b474e71be02c1349c3292d98886f888d1f7", + src_sha1 = "3bf88046a16098ea6cc41576dd50d512854d39e1", ) maven_jar( name = "bcpkix", artifact = "org.bouncycastle:bcpkix-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "d0c46320fbc07be3a24eb13a56cee4e3d38e0c75", - src_sha1 = "a25f041293f401af08efba63ff4bbdce98134a03", + sha1 = "89bb3aa5b98b48e584eee2a7401b7682a46779b4", + src_sha1 = "a0498d09200a18737eccc05aa81bbd05c1be0f8c", ) diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target index b187ecee0..988f2c5c6 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target index ea0b20ef2..fac656fa4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target index d8ebcfde2..1069e56cf 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target @@ -1,9 +1,6 @@ - - - - + - + @@ -22,7 +19,7 @@ - + @@ -37,12 +34,12 @@ - - - - - - + + + + + + @@ -82,11 +79,11 @@ - + - + - + \ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index 21cdb0c19..a1776ffcf 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index e5bd111de..4a52ffff4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index 5bbc23ed5..051c898b7 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target index a0fc30bcd..5c8841ebe 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd index 1ab52cefa..b8c815506 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd @@ -16,12 +16,12 @@ location "https://download.eclipse.org/tools/orbit/downloads/drops/R201905311948 org.apache.httpcomponents.httpcore.source [4.4.10.v20190123-2214,4.4.10.v20190123-2214] org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815] org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815] - org.bouncycastle.bcpg [1.60.0.v20181210-2057,1.60.0.v20181210-2057] - org.bouncycastle.bcpg.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057] - org.bouncycastle.bcpkix [1.60.0.v20181210-2057,1.60.0.v20181210-2057] - org.bouncycastle.bcpkix.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057] - org.bouncycastle.bcprov [1.60.0.v20181210-2057,1.60.0.v20181210-2057] - org.bouncycastle.bcprov.source [1.60.0.v20181210-2057,1.60.0.v20181210-2057] + org.bouncycastle.bcpg [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcpg.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcpkix [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcpkix.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcprov [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcprov.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000] diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 73c8de852..7ec5e6175 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -11,7 +11,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.54,0.2.0)", net.bytebuddy.dynamic.loading;version="[1.7.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.60.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.61.0,2.0.0)", org.eclipse.jgit.annotations;version="[5.4.0,5.5.0)", org.eclipse.jgit.api;version="[5.4.0,5.5.0)", org.eclipse.jgit.api.errors;version="[5.4.0,5.5.0)", diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 95594f29e..bd3161b43 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -160,16 +160,17 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.37,0.2.0)", javax.crypto, javax.net.ssl, - org.bouncycastle;version="[1.60.0,2.0.0)", - org.bouncycastle.bcpg;version="[1.60.0,2.0.0)", - org.bouncycastle.gpg;version="[1.60.0,2.0.0)", - org.bouncycastle.gpg.keybox;version="[1.60.0,2.0.0)", - org.bouncycastle.jce.provider;version="[1.60.0,2.0.0)", - org.bouncycastle.openpgp;version="[1.60.0,2.0.0)", - org.bouncycastle.openpgp.jcajce;version="[1.60.0,2.0.0)", - org.bouncycastle.openpgp.operator;version="[1.60.0,2.0.0)", - org.bouncycastle.openpgp.operator.jcajce;version="[1.60.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.60.0,2.0.0)", + org.bouncycastle;version="[1.61.0,2.0.0)", + org.bouncycastle.bcpg;version="[1.61.0,2.0.0)", + org.bouncycastle.gpg;version="[1.61.0,2.0.0)", + org.bouncycastle.gpg.keybox;version="[1.61.0,2.0.0)", + org.bouncycastle.gpg.keybox.jcajce;version="[1.61.0,2.0.0)", + org.bouncycastle.jce.provider;version="[1.61.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.61.0,2.0.0)", + org.bouncycastle.openpgp.jcajce;version="[1.61.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.61.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.61.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.61.0,2.0.0)", org.slf4j;version="[1.7.0,2.0.0)", org.xml.sax, org.xml.sax.helpers 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 df9615fc9..0d4431765 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 @@ -54,6 +54,8 @@ import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.text.MessageFormat; import java.util.Iterator; import java.util.Locale; @@ -67,6 +69,7 @@ import org.bouncycastle.gpg.keybox.KeyBox; import org.bouncycastle.gpg.keybox.KeyInformation; import org.bouncycastle.gpg.keybox.PublicKeyRingBlob; 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.PGPSecretKey; @@ -210,9 +213,12 @@ class BouncyCastleGpgKeyLocator { * @return publicKey the public key (maybe null) * @throws IOException * in case of problems reading the file + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException */ private PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile) - throws IOException { + throws IOException, NoSuchAlgorithmException, + NoSuchProviderException { KeyBox keyBox = readKeyBoxFile(keyboxFile); for (KeyBlob keyBlob : keyBox.getKeyBlobs()) { if (keyBlob.getType() == BlobType.OPEN_PGP_BLOB) { @@ -236,15 +242,17 @@ class BouncyCastleGpgKeyLocator { * @return the secret key * @throws IOException * in case of issues reading key files + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException * @throws PGPException * in case of issues finding a key * @throws CanceledException * @throws URISyntaxException * @throws UnsupportedCredentialItem */ - public BouncyCastleGpgKey findSecretKey() - throws IOException, PGPException, CanceledException, - UnsupportedCredentialItem, URISyntaxException { + public BouncyCastleGpgKey findSecretKey() throws IOException, + NoSuchAlgorithmException, NoSuchProviderException, PGPException, + CanceledException, UnsupportedCredentialItem, URISyntaxException { if (exists(USER_KEYBOX_PATH)) { PGPPublicKey publicKey = // findPublicKeyInKeyBox(USER_KEYBOX_PATH); @@ -376,14 +384,12 @@ class BouncyCastleGpgKeyLocator { .getPublicKey(); } - private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException { + private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException, + NoSuchAlgorithmException, NoSuchProviderException { KeyBox keyBox; try (InputStream in = new BufferedInputStream( newInputStream(keyboxFile))) { - // note: KeyBox constructor reads in the whole InputStream at once - // this code will change in 1.61 to - // either 'new BcKeyBox(in)' or 'new JcaKeyBoxBuilder().build(in)' - keyBox = new KeyBox(in, new JcaKeyFingerprintCalculator()); + keyBox = new JcaKeyBoxBuilder().build(in); } return keyBox; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java index 4d696dd9e..cfe0931b4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java @@ -45,6 +45,8 @@ package org.eclipse.jgit.lib.internal; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URISyntaxException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.Security; import org.bouncycastle.bcpg.ArmoredOutputStream; @@ -100,7 +102,8 @@ public class BouncyCastleGpgSigner extends GpgSigner { BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey, committer, passphrasePrompt); return gpgKey != null; - } catch (PGPException | IOException | URISyntaxException e) { + } catch (PGPException | IOException | NoSuchAlgorithmException + | NoSuchProviderException | URISyntaxException e) { return false; } } @@ -109,7 +112,8 @@ public class BouncyCastleGpgSigner extends GpgSigner { PersonIdent committer, BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt) throws CanceledException, UnsupportedCredentialItem, IOException, - PGPException, URISyntaxException { + NoSuchAlgorithmException, NoSuchProviderException, PGPException, + URISyntaxException { if (gpgSigningKey == null || gpgSigningKey.isEmpty()) { gpgSigningKey = committer.getEmailAddress(); } @@ -153,7 +157,8 @@ public class BouncyCastleGpgSigner extends GpgSigner { signatureGenerator.generate().encode(out); } commit.setGpgSignature(new GpgSignature(buffer.toByteArray())); - } catch (PGPException | IOException | URISyntaxException e) { + } catch (PGPException | IOException | NoSuchAlgorithmException + | NoSuchProviderException | URISyntaxException e) { throw new JGitInternalException(e.getMessage(), e); } } diff --git a/pom.xml b/pom.xml index 780cbdc2b..894458e54 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 3.1.0 1.3.0 2.8.2 - 1.60 + 1.61 3.1.11 2.22.2 3.8.1 From 5862a5e222669d84cd849bbf00ec2250ad9c25ee Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 11:11:28 +0900 Subject: [PATCH 18/51] ProtocolV2ParserTest: Fix typo in comment Change-Id: I22b07179ba6e2517ae3e178c31fde20987cead34 Signed-off-by: David Pursehouse --- .../tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java index 740d92ef4..7d6e300fd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java @@ -136,7 +136,7 @@ public class ProtocolV2ParserTest { } /* - * Succesful fetch with the basic core commands of the protocol. + * Successful fetch with the basic core commands of the protocol. */ @Test public void testFetchBasicArguments() From 07a07a75d6c22458bb94dffc3498a6472222026f Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 11:16:52 +0900 Subject: [PATCH 19/51] PacketLineIn: Rename isDelim to isDelimiter Change-Id: I279808b8ddd8a9230a35582c00867b811633dfe8 Signed-off-by: David Pursehouse --- .../tst/org/eclipse/jgit/transport/PacketLineInTest.java | 2 +- .../src/org/eclipse/jgit/transport/PacketLineIn.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java index 1e5a03256..f512d2849 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java @@ -157,7 +157,7 @@ public class PacketLineInTest { @Test public void testReadString_Delim() throws IOException { init("0001"); - assertTrue(PacketLineIn.isDelim(in.readString())); + assertTrue(PacketLineIn.isDelimiter(in.readString())); assertEOF(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index 15d3481f4..2243175ea 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -232,7 +232,7 @@ public class PacketLineIn { * @return true if the given string is {@link #DELIM}, otherwise false. * @since 5.4 */ - public static boolean isDelim(String s) { + public static boolean isDelimiter(String s) { return s == DELIM; } From 7377b8dd01b56caa85b47e5b2da32a9b784315d3 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 11:04:59 +0900 Subject: [PATCH 20/51] Replace trivial reference comparison of PacketLineIn.{DELIM,END} Replace reference comparisons of PacketLineIn's DELIM and END strings with usage of the helper methods isDelimiter() and isEnd(). Change-Id: I52dcfc4ee9097f1bd6970601c716701847d9eebd Signed-off-by: David Pursehouse --- .../jgit/http/test/HttpClientTests.java | 3 +- .../jgit/http/test/ProtocolErrorTest.java | 4 +- .../jgit/transport/ProtocolV0ParserTest.java | 4 +- .../jgit/transport/ProtocolV2ParserTest.java | 4 +- .../ReceivePackAdvertiseRefsHookTest.java | 24 +++---- .../jgit/transport/RefAdvertiserTest.java | 4 +- .../jgit/transport/UploadPackTest.java | 63 +++++++++---------- .../jgit/transport/BasePackConnection.java | 2 +- .../jgit/transport/BaseReceivePack.java | 2 +- .../jgit/transport/ProtocolV0Parser.java | 2 +- .../jgit/transport/ProtocolV2Parser.java | 10 +-- .../eclipse/jgit/transport/ReceivePack.java | 2 +- .../eclipse/jgit/transport/TransportHttp.java | 2 +- .../eclipse/jgit/transport/UploadPack.java | 4 +- 14 files changed, 64 insertions(+), 66 deletions(-) diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java index 1660f14f3..415804917 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java @@ -44,7 +44,6 @@ package org.eclipse.jgit.http.test; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.theInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -366,7 +365,7 @@ public class HttpClientTests extends HttpTestCase { // Check that we get a v0 response. assertThat(pckIn.readString(), is("# service=git-upload-pack")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.END)); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); assertTrue(pckIn.readString().matches("[0-9a-f]{40} HEAD.*")); } diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java index f0fac5ab5..6a3d8829b 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java @@ -44,7 +44,7 @@ package org.eclipse.jgit.http.test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -157,7 +157,7 @@ public class ProtocolErrorTest extends HttpTestCase { pckin.readString()); assertEquals("ng refs/objects/A n/a (unpacker error)", pckin.readString()); - assertSame(PacketLineIn.END, pckin.readString()); + assertTrue(PacketLineIn.isEnd(pckin.readString())); } } finally { c.disconnect(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java index 28a9c03ec..42553147f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java @@ -64,9 +64,9 @@ public class ProtocolV0ParserTest { ByteArrayOutputStream send = new ByteArrayOutputStream(); PacketLineOut pckOut = new PacketLineOut(send); for (String line : inputLines) { - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { pckOut.end(); - } else if (line == PacketLineIn.DELIM) { + } else if (PacketLineIn.isDelimiter(line)) { pckOut.writeDelim(); } else { pckOut.writeString(line); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java index 7d6e300fd..43da170b6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java @@ -123,9 +123,9 @@ public class ProtocolV2ParserTest { ByteArrayOutputStream send = new ByteArrayOutputStream(); PacketLineOut pckOut = new PacketLineOut(send); for (String line : inputLines) { - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { pckOut.end(); - } else if (line == PacketLineIn.DELIM) { + } else if (PacketLineIn.isDelimiter(line)) { pckOut.writeDelim(); } else { pckOut.writeString(line); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java index 50c8a2954..5d208eea7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java @@ -306,11 +306,11 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); assertEquals("unpack error Missing commit " + P.name(), r.readString()); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } private static void receive(final ReceivePack rp, @@ -366,13 +366,13 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); assertEquals("unpack error Missing blob " + b.name(), r.readString()); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } } @@ -419,13 +419,13 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); assertEquals("unpack error Missing blob " + b.name(), r.readString()); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } } @@ -473,13 +473,13 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); assertEquals("unpack error Missing blob " + n.name(), r.readString()); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } } @@ -504,13 +504,13 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); String errorLine = r.readString(); assertTrue(errorLine.startsWith("unpack error")); assertTrue(errorLine.contains("Invalid submodule URL '-")); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } private TemporaryBuffer.Heap setupSourceRepoInvalidGitmodules() @@ -589,13 +589,13 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas int nul = master.indexOf('\0'); assertTrue("has capability list", nul > 0); assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); assertEquals("unpack error Missing tree " + t.name(), r.readString()); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); - assertSame(PacketLineIn.END, r.readString()); + assertTrue(PacketLineIn.isEnd(r.readString())); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java index ce69adf9c..ccb548d91 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java @@ -45,7 +45,7 @@ package org.eclipse.jgit.transport; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -95,7 +95,7 @@ public class RefAdvertiserTest { assertEquals(id(3).name() + " refs/Iñtërnâtiônàlizætiøn☃💩\n", s); s = pckIn.readStringRaw(); - assertSame(PacketLineIn.END, s); + assertTrue(PacketLineIn.isEnd(s)); } private static ObjectId id(int i) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 3ead31dbd..0ad1e2152 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.theInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -428,9 +427,9 @@ public class UploadPackTest { try (ByteArrayOutputStream send = new ByteArrayOutputStream()) { PacketLineOut pckOut = new PacketLineOut(send); for (String line : inputLines) { - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { pckOut.end(); - } else if (line == PacketLineIn.DELIM) { + } else if (PacketLineIn.isDelimiter(line)) { pckOut.writeDelim(); } else { pckOut.writeString(line); @@ -453,7 +452,7 @@ public class UploadPackTest { PacketLineIn pckIn = new PacketLineIn(recvStream); // drain capabilities - while (pckIn.readString() != PacketLineIn.END) { + while (!PacketLineIn.isEnd(pckIn.readString())) { // do nothing } return recvStream; @@ -504,7 +503,7 @@ public class UploadPackTest { // and additional capabilities to be added to existing // commands without requiring test changes. hasItems("ls-refs", "fetch=shallow", "server-option")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -521,7 +520,7 @@ public class UploadPackTest { // TODO(jonathantanmy) This check overspecifies the // order of the capabilities of "fetch". hasItems("ls-refs", "fetch=filter shallow", "server-option")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -539,7 +538,7 @@ public class UploadPackTest { // order of the capabilities of "fetch". hasItems("ls-refs", "fetch=ref-in-want shallow", "server-option")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -554,7 +553,7 @@ public class UploadPackTest { Arrays.asList(pckIn.readString(), pckIn.readString(), pckIn.readString()), hasItems("ls-refs", "fetch=shallow", "server-option")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -570,7 +569,7 @@ public class UploadPackTest { Arrays.asList(pckIn.readString(), pckIn.readString(), pckIn.readString()), hasItems("ls-refs", "fetch=shallow", "server-option")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -598,7 +597,7 @@ public class UploadPackTest { assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -615,7 +614,7 @@ public class UploadPackTest { assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -635,7 +634,7 @@ public class UploadPackTest { pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag peeled:" + tip.toObjectId().getName())); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -657,11 +656,11 @@ public class UploadPackTest { pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag peeled:" + tip.toObjectId().getName())); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -681,7 +680,7 @@ public class UploadPackTest { assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -700,7 +699,7 @@ public class UploadPackTest { assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/other")); - assertTrue(pckIn.readString() == PacketLineIn.END); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -908,7 +907,7 @@ public class UploadPackTest { assertThat(pckIn.readString(), is("acknowledgments")); assertThat(pckIn.readString(), is("ACK " + fooParent.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.END)); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -937,7 +936,7 @@ public class UploadPackTest { "ACK " + fooParent.toObjectId().getName(), "ACK " + barParent.toObjectId().getName())); assertThat(pckIn.readString(), is("ready")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); assertFalse(client.getObjectDatabase().has(fooParent.toObjectId())); @@ -1160,7 +1159,7 @@ public class UploadPackTest { PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); assertTrue(client.getObjectDatabase().has(child.toObjectId())); @@ -1198,7 +1197,7 @@ public class UploadPackTest { // sent only if a packfile is sent. assertThat(pckIn.readString(), is("acknowledgments")); assertThat(pckIn.readString(), is("NAK")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.END)); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @Test @@ -1237,7 +1236,7 @@ public class UploadPackTest { // later than the given deepen-since time. assertThat(pckIn.readString(), is("unshallow " + boundary.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1286,7 +1285,7 @@ public class UploadPackTest { "shallow " + child1.toObjectId().getName(), "shallow " + child2.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1353,7 +1352,7 @@ public class UploadPackTest { // "three" is unshallow because its parent "two" is now available. assertThat(pckIn.readString(), is("unshallow " + three.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1413,7 +1412,7 @@ public class UploadPackTest { PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); assertThat(pckIn.readString(), is("shallow " + three.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); assertFalse(client.getObjectDatabase().has(one.toObjectId())); @@ -1455,7 +1454,7 @@ public class UploadPackTest { "shallow " + child1.toObjectId().getName(), "shallow " + child2.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1899,7 +1898,7 @@ public class UploadPackTest { hasItems( one.toObjectId().getName() + " refs/heads/one", two.toObjectId().getName() + " refs/heads/two")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1955,7 +1954,7 @@ public class UploadPackTest { assertThat( pckIn.readString(), is(one.toObjectId().getName() + " refs/heads/one")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1987,7 +1986,7 @@ public class UploadPackTest { assertThat( pckIn.readString(), is(one.toObjectId().getName() + " refs/heads/one")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); // ... but the client does not need the object itself. assertThat(pckIn.readString(), is("packfile")); @@ -2015,10 +2014,10 @@ public class UploadPackTest { // shallow-info appears first, then wanted-refs. assertThat(pckIn.readString(), is("shallow-info")); assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("wanted-refs")); assertThat(pckIn.readString(), is(child.toObjectId().getName() + " refs/heads/branch1")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); assertTrue(client.getObjectDatabase().has(child.toObjectId())); @@ -2050,11 +2049,11 @@ public class UploadPackTest { is("shallow " + one.toObjectId().getName())); assertThat(pckIn.readString(), is("unshallow " + two.toObjectId().getName())); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("wanted-refs")); assertThat(pckIn.readString(), is(three.toObjectId().getName() + " refs/heads/three")); - assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java index 20a5d9da7..e8724b72d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java @@ -201,7 +201,7 @@ abstract class BasePackConnection extends BaseConnection { throw noRepository(); throw eof; } - if (line == PacketLineIn.END) + if (PacketLineIn.isEnd(line)) break; if (line.startsWith("ERR ")) { //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java index 1741db97f..e402de015 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java @@ -1282,7 +1282,7 @@ public abstract class BaseReceivePack { return; throw eof; } - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { break; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java index 396327aab..428a45c09 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java @@ -99,7 +99,7 @@ final class ProtocolV0Parser { throw eof; } - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { break; } 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 cb04ff69a..2c7beedc6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java @@ -92,7 +92,7 @@ final class ProtocolV2Parser { String agentPrefix = OPTION_AGENT + '='; String line = pckIn.readString(); - while (line != PacketLineIn.DELIM && line != PacketLineIn.END) { + while (!PacketLineIn.isDelimiter(line) && !PacketLineIn.isEnd(line)) { if (line.startsWith(serverOptionPrefix)) { serverOptionConsumer .accept(line.substring(serverOptionPrefix.length())); @@ -133,11 +133,11 @@ final class ProtocolV2Parser { serverOption -> reqBuilder.addServerOption(serverOption), agent -> reqBuilder.setAgent(agent)); - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { return reqBuilder.build(); } - if (line != PacketLineIn.DELIM) { + if (!PacketLineIn.isDelimiter(line)) { throw new PackProtocolException( MessageFormat.format(JGitText.get().unexpectedPacketLine, line)); @@ -244,11 +244,11 @@ final class ProtocolV2Parser { serverOption -> builder.addServerOption(serverOption), agent -> builder.setAgent(agent)); - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { return builder.build(); } - if (line != PacketLineIn.DELIM) { + if (!PacketLineIn.isDelimiter(line)) { throw new PackProtocolException(MessageFormat .format(JGitText.get().unexpectedPacketLine, line)); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index 4652c3fda..d6adf1e0d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -348,7 +348,7 @@ public class ReceivePack extends BaseReceivePack { pushOptions = new ArrayList<>(4); for (;;) { String option = in.readString(); - if (option == PacketLineIn.END) { + if (PacketLineIn.isEnd(option)) { break; } pushOptions.add(option); 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 b752a6527..42aa80ea4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -902,7 +902,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, JGitText.get().expectedGot, exp, act)); } - while (pckIn.readString() != PacketLineIn.END) { + while (!PacketLineIn.isEnd(pckIn.readString())) { // for now, ignore the remaining header lines } } 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 6217d2a0e..9278f42ad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -1229,7 +1229,7 @@ public class UploadPack { /* EOF when awaiting command is fine */ return true; } - if (command == PacketLineIn.END) { + if (PacketLineIn.isEnd(command)) { // A blank request is valid according // to the protocol; do nothing in this // case. @@ -1600,7 +1600,7 @@ public class UploadPack { throw eof; } - if (line == PacketLineIn.END) { + if (PacketLineIn.isEnd(line)) { last = processHaveLines(peerHas, last, pckOut); if (commonBase.isEmpty() || multiAck != MultiAck.OFF) pckOut.writeString("NAK\n"); //$NON-NLS-1$ From e99aaa5f791c43bcac050a26dcb970ae2584130a Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 11:13:36 +0900 Subject: [PATCH 21/51] PacketLineIn: Deprecate DELIM constant Deprecate DELIM with the intention of making it private in a future release. Callers that want to test if a packet line string is the delimiter should use the isDelimiter(String) method. The only other references to DELIM in the JGit code are in tests. For those, introduce a package visible delimiter() method. Change-Id: I21e8bbac0ffb9ef710c9753e23435416b09a4891 Signed-off-by: David Pursehouse --- .../jgit/transport/ProtocolV2ParserTest.java | 30 ++--- .../jgit/transport/UploadPackTest.java | 104 +++++++++--------- .../eclipse/jgit/transport/PacketLineIn.java | 14 +++ 3 files changed, 81 insertions(+), 67 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java index 43da170b6..c975982a6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java @@ -142,7 +142,7 @@ public class ProtocolV2ParserTest { public void testFetchBasicArguments() throws PackProtocolException, IOException { PacketLineIn pckIn = formatAsPacketLine( - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "thin-pack", "no-progress", "include-tag", "ofs-delta", "want 4624442d68ee402a94364191085b77137618633e", "want f900c8326a43303685c46b279b9f70411bff1a4b", @@ -173,7 +173,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithShallow_deepen() throws IOException { PacketLineIn pckIn = formatAsPacketLine( - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen 15", "deepen-relative", "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", @@ -193,7 +193,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithShallow_deepenNot() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d", "deepen-not a08595f76159b09d57553e37a5123f1091bb13e7", @@ -210,7 +210,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithShallow_deepenSince() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d", "deepen-since 123123123", @@ -226,7 +226,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithNoneFilter() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:none", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( @@ -238,7 +238,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithBlobSizeFilter() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:limit=15", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( @@ -250,7 +250,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithTreeDepthFilter() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter tree:3", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( @@ -262,7 +262,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchMustNotHaveMultipleFilters() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:none", "filter blob:limit=12", PacketLineIn.END); @@ -275,7 +275,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchFilterWithoutAllowFilter() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:limit=12", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); @@ -291,7 +291,7 @@ public class ProtocolV2ParserTest { testRepo.update("branchA", one); testRepo.update("branchB", two); - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "want e4980cdc48cfa1301493ca94eb70523f6788b819", "want-ref refs/heads/branchA", PacketLineIn.END); @@ -309,7 +309,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchWithRefInWantUnknownRef() throws Exception { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "want e4980cdc48cfa1301493ca94eb70523f6788b819", "want-ref refs/heads/branchC", PacketLineIn.END); @@ -328,7 +328,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsMinimalReq() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( @@ -341,7 +341,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsSymrefs() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, "symrefs", + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "symrefs", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( @@ -356,7 +356,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsPeel() throws IOException { PacketLineIn pckIn = formatAsPacketLine( - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "peel", PacketLineIn.END); @@ -370,7 +370,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsRefPrefixes() throws IOException { - PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "ref-prefix refs/for", "ref-prefix refs/heads", PacketLineIn.END); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 0ad1e2152..b0bc51971 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -608,7 +608,7 @@ public class UploadPackTest { RevTag tag = remote.tag("tag", tip); remote.update("refs/tags/tag", tag); - ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "symrefs", PacketLineIn.END); + ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.delimiter(), "symrefs", PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master")); @@ -625,7 +625,7 @@ public class UploadPackTest { RevTag tag = remote.tag("tag", tip); remote.update("refs/tags/tag", tag); - ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "peel", PacketLineIn.END); + ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.delimiter(), "peel", PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD")); @@ -646,8 +646,8 @@ public class UploadPackTest { remote.update("refs/tags/tag", tag); ByteArrayInputStream recvStream = uploadPackV2( - "command=ls-refs\n", PacketLineIn.DELIM, "symrefs", "peel", PacketLineIn.END, - "command=ls-refs\n", PacketLineIn.DELIM, PacketLineIn.END); + "command=ls-refs\n", PacketLineIn.delimiter(), "symrefs", "peel", PacketLineIn.END, + "command=ls-refs\n", PacketLineIn.delimiter(), PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master")); @@ -672,7 +672,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=ls-refs\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "ref-prefix refs/heads/maste", "ref-prefix refs/heads/other", PacketLineIn.END); @@ -691,7 +691,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=ls-refs\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "ref-prefix refs/heads/maste", "ref-prefix r", PacketLineIn.END); @@ -708,7 +708,7 @@ public class UploadPackTest { thrown.expectMessage("unexpected invalid-argument"); uploadPackV2( "command=ls-refs\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "invalid-argument\n", PacketLineIn.END); } @@ -717,7 +717,7 @@ public class UploadPackTest { public void testV2LsRefsServerOptions() throws Exception { String[] lines = { "command=ls-refs\n", "server-option=one\n", "server-option=two\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), PacketLineIn.END }; TestV2Hook testHook = new TestV2Hook(); @@ -762,7 +762,7 @@ public class UploadPackTest { null, null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + advertized.name() + "\n", PacketLineIn.END); @@ -775,7 +775,7 @@ public class UploadPackTest { null, null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + unadvertized.name() + "\n", PacketLineIn.END); } @@ -793,7 +793,7 @@ public class UploadPackTest { null, null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + reachable.name() + "\n", PacketLineIn.END); @@ -806,7 +806,7 @@ public class UploadPackTest { null, null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", PacketLineIn.END); } @@ -823,7 +823,7 @@ public class UploadPackTest { new RejectAllRefFilter(), null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + tip.name() + "\n", PacketLineIn.END); @@ -836,7 +836,7 @@ public class UploadPackTest { new RejectAllRefFilter(), null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n", PacketLineIn.END); } @@ -854,7 +854,7 @@ public class UploadPackTest { new RejectAllRefFilter(), null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n", PacketLineIn.END); @@ -867,7 +867,7 @@ public class UploadPackTest { new RejectAllRefFilter(), null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", PacketLineIn.END); } @@ -882,7 +882,7 @@ public class UploadPackTest { null, null, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", PacketLineIn.END); } @@ -898,7 +898,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + fooChild.toObjectId().getName() + "\n", "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", @@ -921,7 +921,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + fooChild.toObjectId().getName() + "\n", "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", @@ -956,7 +956,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + fooChild.toObjectId().getName() + "\n", "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", @@ -985,7 +985,7 @@ public class UploadPackTest { // Pretend that we have parent to get a thin pack based on it. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "have " + parent.toObjectId().getName() + "\n", "thin-pack\n", @@ -1011,7 +1011,7 @@ public class UploadPackTest { StringWriter sw = new StringWriter(); ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "done\n", PacketLineIn.END); @@ -1024,7 +1024,7 @@ public class UploadPackTest { sw = new StringWriter(); recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "no-progress\n", "done\n", @@ -1045,7 +1045,7 @@ public class UploadPackTest { // Without include-tag. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "done\n", PacketLineIn.END); @@ -1057,7 +1057,7 @@ public class UploadPackTest { // With tag. recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "include-tag\n", "done\n", @@ -1081,7 +1081,7 @@ public class UploadPackTest { // Without ofs-delta. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "done\n", PacketLineIn.END); @@ -1093,7 +1093,7 @@ public class UploadPackTest { // With ofs-delta. recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "ofs-delta\n", "done\n", @@ -1115,7 +1115,7 @@ public class UploadPackTest { // commonParent, so it doesn't send it. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + barChild.toObjectId().getName() + "\n", "have " + fooChild.toObjectId().getName() + "\n", "done\n", @@ -1130,7 +1130,7 @@ public class UploadPackTest { // commonParent, so it sends it. recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + barChild.toObjectId().getName() + "\n", "have " + fooChild.toObjectId().getName() + "\n", "shallow " + fooChild.toObjectId().getName() + "\n", @@ -1151,7 +1151,7 @@ public class UploadPackTest { // "deepen 1" sends only the child. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "deepen 1\n", "done\n", @@ -1168,7 +1168,7 @@ public class UploadPackTest { // Without that, the parent is sent too. recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "done\n", PacketLineIn.END); @@ -1186,7 +1186,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "deepen 1\n", PacketLineIn.END); @@ -1218,7 +1218,7 @@ public class UploadPackTest { // Report that we only have "boundary" as a shallow boundary. ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "shallow " + boundary.toObjectId().getName() + "\n", "deepen-since 1510000\n", "want " + merge.toObjectId().getName() + "\n", @@ -1269,7 +1269,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen-since 1510000\n", "want " + child1.toObjectId().getName() + "\n", "want " + child2.toObjectId().getName() + "\n", @@ -1308,7 +1308,7 @@ public class UploadPackTest { thrown.expectMessage("No commits selected for shallow request"); uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen-since 1510000\n", "want " + tooOld.toObjectId().getName() + "\n", "done\n", @@ -1331,7 +1331,7 @@ public class UploadPackTest { // wants "merge" while excluding "side". ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "shallow " + three.toObjectId().getName() + "\n", "deepen-not side\n", "want " + merge.toObjectId().getName() + "\n", @@ -1384,7 +1384,7 @@ public class UploadPackTest { thrown.expectMessage("No commits selected for shallow request"); uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen-not four\n", "want " + two.toObjectId().getName() + "\n", "done\n", @@ -1404,7 +1404,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen-not twotag\n", "want " + four.toObjectId().getName() + "\n", "done\n", @@ -1438,7 +1438,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "deepen-not base\n", "want " + child1.toObjectId().getName() + "\n", "want " + child2.toObjectId().getName() + "\n", @@ -1470,7 +1470,7 @@ public class UploadPackTest { thrown.expectMessage("unexpected invalid-argument"); uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "invalid-argument\n", PacketLineIn.END); } @@ -1478,7 +1478,7 @@ public class UploadPackTest { @Test public void testV2FetchServerOptions() throws Exception { String[] lines = { "command=fetch\n", "server-option=one\n", - "server-option=two\n", PacketLineIn.DELIM, + "server-option=two\n", PacketLineIn.delimiter(), PacketLineIn.END }; TestV2Hook testHook = new TestV2Hook(); @@ -1503,7 +1503,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "filter blob:limit=5\n", "done\n", @@ -1558,7 +1558,7 @@ public class UploadPackTest { List input = new ArrayList<>(); input.add("command=fetch\n"); - input.add(PacketLineIn.DELIM); + input.add(PacketLineIn.delimiter()); for (ObjectId want : wants) { input.add("want " + want.getName() + "\n"); } @@ -1845,7 +1845,7 @@ public class UploadPackTest { thrown.expectMessage("unexpected filter blob:limit=5"); uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "filter blob:limit=5\n", "done\n", @@ -1860,7 +1860,7 @@ public class UploadPackTest { try { uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "done\n", PacketLineIn.END); @@ -1886,7 +1886,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "want-ref refs/heads/two\n", "done\n", @@ -1917,7 +1917,7 @@ public class UploadPackTest { try { uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "want-ref refs/heads/nonExistentRef\n", "done\n", @@ -1944,7 +1944,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "want " + two.toObjectId().getName() + "\n", "done\n", @@ -1972,7 +1972,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "have " + one.toObjectId().getName(), "done\n", @@ -2004,7 +2004,7 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/branch1\n", "deepen 1\n", "done\n", @@ -2035,7 +2035,7 @@ public class UploadPackTest { true); ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want-ref refs/heads/three\n", "deepen 3", "shallow 0123012301230123012301230123012301230123", @@ -2091,7 +2091,7 @@ public class UploadPackTest { ByteArrayInputStream send = linesAsInputStream( "command=fetch\n", "agent=JGit-test/1.2.4\n", - PacketLineIn.DELIM, "want " + one.getName() + "\n", + PacketLineIn.delimiter(), "want " + one.getName() + "\n", "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n", PacketLineIn.END); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index 2243175ea..62f71e693 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -79,7 +79,10 @@ public class PacketLineIn { * Magic return from {@link #readString()} when a delim packet is found. * * @since 5.0 + * @deprecated Callers should use {@link #isDelimiter(String)} to check if a + * string is the delimiter. */ + @Deprecated public static final String DELIM = new StringBuilder(0).toString(); /* must not string pool */ static enum AckNackResult { @@ -236,6 +239,17 @@ public class PacketLineIn { return s == DELIM; } + /** + * Get the delimiter marker. + *

+ * Intended for use only in tests. + * + * @return The delimiter marker. + */ + static String delimiter() { + return DELIM; + } + /** * Check if a string is the packet end marker. * From e0133b9440cf28cc8495e4af0546d1467edbb028 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 12:50:34 +0900 Subject: [PATCH 22/51] Replace most usages of PacketLineIn.END with PacketLineIn.end() PacketLineIn.END is only referenced in tests. Replace most of those with a new package visible end() method. Remaining usages of PacketLineIn.END are in the form: while ((line = pckIn.readString()) != PacketLineIn.END) { and are not trivial replacements, hence are not touched in this change. Change-Id: Id77c5321ddcad127130b246bde8f08736e60e1ea Signed-off-by: David Pursehouse --- .../jgit/transport/ProtocolV0ParserTest.java | 12 +- .../jgit/transport/ProtocolV2ParserTest.java | 30 ++--- .../jgit/transport/UploadPackTest.java | 123 +++++++++--------- .../eclipse/jgit/transport/PacketLineIn.java | 11 ++ 4 files changed, 95 insertions(+), 81 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java index 42553147f..6e8327c79 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java @@ -90,7 +90,7 @@ public class ProtocolV0ParserTest { "4624442d68ee402a94364191085b77137618633e", "thin-pack", "no-progress", "include-tag", "ofs-delta", "\n"), "want f900c8326a43303685c46b279b9f70411bff1a4b\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities() @@ -114,7 +114,7 @@ public class ProtocolV0ParserTest { "4624442d68ee402a94364191085b77137618633e", "thin-pack", "agent=JGit.test/0.0.1", "\n"), "want f900c8326a43303685c46b279b9f70411bff1a4b\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities() @@ -136,7 +136,7 @@ public class ProtocolV0ParserTest { PacketLineIn pckIn = formatAsPacketLine( "want 4624442d68ee402a94364191085b77137618633e\n", "want f900c8326a43303685c46b279b9f70411bff1a4b\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities().isEmpty()); @@ -151,7 +151,7 @@ public class ProtocolV0ParserTest { PacketLineIn pckIn = formatAsPacketLine( "want 4624442d68ee402a94364191085b77137618633e\n", "want f900c8326a43303685c46b279b9f70411bff1a4b\n", "deepen 3\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities().isEmpty()); @@ -168,7 +168,7 @@ public class ProtocolV0ParserTest { "want 4624442d68ee402a94364191085b77137618633e\n", "want f900c8326a43303685c46b279b9f70411bff1a4b\n", "shallow 4b643d0ef739a1b494e7d6926d8d8ed80d35edf4\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities().isEmpty()); @@ -186,7 +186,7 @@ public class ProtocolV0ParserTest { "want 4624442d68ee402a94364191085b77137618633e\n", "want f900c8326a43303685c46b279b9f70411bff1a4b\n", "filter blob:limit=13000\n", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); FetchV0Request request = parser.recvWants(pckIn); assertTrue(request.getClientCapabilities().isEmpty()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java index c975982a6..0d70cd612 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java @@ -148,7 +148,7 @@ public class ProtocolV2ParserTest { "want f900c8326a43303685c46b279b9f70411bff1a4b", "have 554f6e41067b9e3e565b6988a8294fac1cb78f4b", "have abc760ab9ad72f08209943251b36cb886a578f87", "done", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -178,7 +178,7 @@ public class ProtocolV2ParserTest { "deepen-relative", "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -197,7 +197,7 @@ public class ProtocolV2ParserTest { "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d", "deepen-not a08595f76159b09d57553e37a5123f1091bb13e7", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -214,7 +214,7 @@ public class ProtocolV2ParserTest { "shallow 28274d02c489f4c7e68153056e9061a46f62d7a0", "shallow 145e683b229dcab9d0e2ccb01b386f9ecc17d29d", "deepen-since 123123123", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -228,7 +228,7 @@ public class ProtocolV2ParserTest { public void testFetchWithNoneFilter() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:none", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowFilter().done()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -240,7 +240,7 @@ public class ProtocolV2ParserTest { public void testFetchWithBlobSizeFilter() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:limit=15", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowFilter().done()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -252,7 +252,7 @@ public class ProtocolV2ParserTest { public void testFetchWithTreeDepthFilter() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter tree:3", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowFilter().done()); FetchV2Request request = parser.parseFetchRequest(pckIn); @@ -265,7 +265,7 @@ public class ProtocolV2ParserTest { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "filter blob:none", "filter blob:limit=12", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowFilter().done()); @@ -276,7 +276,7 @@ public class ProtocolV2ParserTest { @Test public void testFetchFilterWithoutAllowFilter() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), - "filter blob:limit=12", PacketLineIn.END); + "filter blob:limit=12", PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); @@ -294,7 +294,7 @@ public class ProtocolV2ParserTest { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "want e4980cdc48cfa1301493ca94eb70523f6788b819", "want-ref refs/heads/branchA", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowRefInWant().done()); @@ -312,7 +312,7 @@ public class ProtocolV2ParserTest { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "want e4980cdc48cfa1301493ca94eb70523f6788b819", "want-ref refs/heads/branchC", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowRefInWant().done()); @@ -329,7 +329,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsMinimalReq() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); @@ -342,7 +342,7 @@ public class ProtocolV2ParserTest { @Test public void testLsRefsSymrefs() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "symrefs", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); @@ -358,7 +358,7 @@ public class ProtocolV2ParserTest { PacketLineIn pckIn = formatAsPacketLine( PacketLineIn.delimiter(), "peel", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); @@ -372,7 +372,7 @@ public class ProtocolV2ParserTest { public void testLsRefsRefPrefixes() throws IOException { PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.delimiter(), "ref-prefix refs/for", "ref-prefix refs/heads", - PacketLineIn.END); + PacketLineIn.end()); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index b0bc51971..260130b2b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -489,7 +489,7 @@ public class UploadPackTest { public void testV2Capabilities() throws Exception { TestV2Hook hook = new TestV2Hook(); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, hook, PacketLineIn.END); + uploadPackV2Setup(null, null, hook, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(hook.capabilitiesRequest, notNullValue()); assertThat(pckIn.readString(), is("version 2")); @@ -510,7 +510,7 @@ public class UploadPackTest { public void testV2CapabilitiesAllowFilter() throws Exception { server.getConfig().setBoolean("uploadpack", null, "allowfilter", true); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, null, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("version 2")); @@ -527,7 +527,7 @@ public class UploadPackTest { public void testV2CapabilitiesRefInWant() throws Exception { server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, null, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("version 2")); @@ -545,7 +545,7 @@ public class UploadPackTest { public void testV2CapabilitiesRefInWantNotAdvertisedIfUnallowed() throws Exception { server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", false); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, null, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("version 2")); @@ -561,7 +561,7 @@ public class UploadPackTest { server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true); server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false); ByteArrayInputStream recvStream = - uploadPackV2Setup(null, null, null, PacketLineIn.END); + uploadPackV2Setup(null, null, null, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("version 2")); @@ -574,7 +574,7 @@ public class UploadPackTest { @Test public void testV2EmptyRequest() throws Exception { - ByteArrayInputStream recvStream = uploadPackV2(PacketLineIn.END); + ByteArrayInputStream recvStream = uploadPackV2(PacketLineIn.end()); // Verify that there is nothing more after the capability // advertisement. assertEquals(0, recvStream.available()); @@ -590,7 +590,7 @@ public class UploadPackTest { TestV2Hook hook = new TestV2Hook(); ByteArrayInputStream recvStream = uploadPackV2(null, null, hook, - "command=ls-refs\n", PacketLineIn.END); + "command=ls-refs\n", PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(hook.lsRefsRequest, notNullValue()); @@ -608,7 +608,8 @@ public class UploadPackTest { RevTag tag = remote.tag("tag", tip); remote.update("refs/tags/tag", tag); - ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.delimiter(), "symrefs", PacketLineIn.END); + ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", + PacketLineIn.delimiter(), "symrefs", PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master")); @@ -625,7 +626,8 @@ public class UploadPackTest { RevTag tag = remote.tag("tag", tip); remote.update("refs/tags/tag", tag); - ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.delimiter(), "peel", PacketLineIn.END); + ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", + PacketLineIn.delimiter(), "peel", PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD")); @@ -646,8 +648,9 @@ public class UploadPackTest { remote.update("refs/tags/tag", tag); ByteArrayInputStream recvStream = uploadPackV2( - "command=ls-refs\n", PacketLineIn.delimiter(), "symrefs", "peel", PacketLineIn.END, - "command=ls-refs\n", PacketLineIn.delimiter(), PacketLineIn.END); + "command=ls-refs\n", PacketLineIn.delimiter(), "symrefs", + "peel", PacketLineIn.end(), "command=ls-refs\n", + PacketLineIn.delimiter(), PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master")); @@ -675,7 +678,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "ref-prefix refs/heads/maste", "ref-prefix refs/heads/other", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); @@ -694,7 +697,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "ref-prefix refs/heads/maste", "ref-prefix r", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master")); @@ -710,7 +713,7 @@ public class UploadPackTest { "command=ls-refs\n", PacketLineIn.delimiter(), "invalid-argument\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -718,7 +721,7 @@ public class UploadPackTest { String[] lines = { "command=ls-refs\n", "server-option=one\n", "server-option=two\n", PacketLineIn.delimiter(), - PacketLineIn.END }; + PacketLineIn.end() }; TestV2Hook testHook = new TestV2Hook(); uploadPackV2Setup(null, null, testHook, lines); @@ -764,7 +767,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + advertized.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); // This doesn't thrown.expect(TransportException.class); @@ -777,7 +780,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + unadvertized.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -795,7 +798,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + reachable.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); // This doesn't thrown.expect(TransportException.class); @@ -808,7 +811,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -825,7 +828,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + tip.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); // This doesn't thrown.expect(TransportException.class); @@ -838,7 +841,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -856,7 +859,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + parentOfTip.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); // This doesn't thrown.expect(TransportException.class); @@ -869,7 +872,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -884,7 +887,7 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "want " + unreachable.name() + "\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -902,7 +905,7 @@ public class UploadPackTest { "want " + fooChild.toObjectId().getName() + "\n", "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("acknowledgments")); @@ -926,7 +929,7 @@ public class UploadPackTest { "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", "have " + barParent.toObjectId().getName() + "\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("acknowledgments")); @@ -961,7 +964,7 @@ public class UploadPackTest { "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); @@ -990,7 +993,7 @@ public class UploadPackTest { "have " + parent.toObjectId().getName() + "\n", "thin-pack\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); @@ -1014,7 +1017,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream, new TextProgressMonitor(sw)); @@ -1028,7 +1031,7 @@ public class UploadPackTest { "want " + commit.toObjectId().getName() + "\n", "no-progress\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream, new TextProgressMonitor(sw)); @@ -1048,7 +1051,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want " + commit.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1061,7 +1064,7 @@ public class UploadPackTest { "want " + commit.toObjectId().getName() + "\n", "include-tag\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1084,7 +1087,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); ReceivedPackStatistics receivedStats = parsePack(recvStream); @@ -1097,7 +1100,7 @@ public class UploadPackTest { "want " + child.toObjectId().getName() + "\n", "ofs-delta\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); receivedStats = parsePack(recvStream); @@ -1119,7 +1122,7 @@ public class UploadPackTest { "want " + barChild.toObjectId().getName() + "\n", "have " + fooChild.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1135,7 +1138,7 @@ public class UploadPackTest { "have " + fooChild.toObjectId().getName() + "\n", "shallow " + fooChild.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1155,7 +1158,7 @@ public class UploadPackTest { "want " + child.toObjectId().getName() + "\n", "deepen 1\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); assertThat(pckIn.readString(), is("shallow " + child.toObjectId().getName())); @@ -1171,7 +1174,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1189,7 +1192,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want " + child.toObjectId().getName() + "\n", "deepen 1\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); // Verify that only the correct section is sent. "shallow-info" @@ -1224,7 +1227,7 @@ public class UploadPackTest { "want " + merge.toObjectId().getName() + "\n", "have " + boundary.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); @@ -1274,7 +1277,7 @@ public class UploadPackTest { "want " + child1.toObjectId().getName() + "\n", "want " + child2.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); @@ -1312,7 +1315,7 @@ public class UploadPackTest { "deepen-since 1510000\n", "want " + tooOld.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -1337,7 +1340,7 @@ public class UploadPackTest { "want " + merge.toObjectId().getName() + "\n", "have " + three.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); @@ -1388,7 +1391,7 @@ public class UploadPackTest { "deepen-not four\n", "want " + two.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -1408,7 +1411,7 @@ public class UploadPackTest { "deepen-not twotag\n", "want " + four.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); assertThat(pckIn.readString(), is("shallow " + three.toObjectId().getName())); @@ -1443,7 +1446,7 @@ public class UploadPackTest { "want " + child1.toObjectId().getName() + "\n", "want " + child2.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); @@ -1472,14 +1475,14 @@ public class UploadPackTest { "command=fetch\n", PacketLineIn.delimiter(), "invalid-argument\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test public void testV2FetchServerOptions() throws Exception { String[] lines = { "command=fetch\n", "server-option=one\n", "server-option=two\n", PacketLineIn.delimiter(), - PacketLineIn.END }; + PacketLineIn.end() }; TestV2Hook testHook = new TestV2Hook(); uploadPackV2Setup(null, null, testHook, lines); @@ -1507,7 +1510,7 @@ public class UploadPackTest { "want " + commit.toObjectId().getName() + "\n", "filter blob:limit=5\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("packfile")); parsePack(recvStream); @@ -1564,7 +1567,7 @@ public class UploadPackTest { } input.add("filter tree:" + depth + "\n"); input.add("done\n"); - input.add(PacketLineIn.END); + input.add(PacketLineIn.end()); ByteArrayInputStream recvStream = uploadPackV2(RequestPolicy.ANY, /*refFilter=*/null, /*hook=*/null, input.toArray(new String[0])); @@ -1849,7 +1852,7 @@ public class UploadPackTest { "want " + commit.toObjectId().getName() + "\n", "filter blob:limit=5\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); } @Test @@ -1863,7 +1866,7 @@ public class UploadPackTest { PacketLineIn.delimiter(), "want-ref refs/heads/one\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); } catch (PackProtocolException e) { assertThat( e.getMessage(), @@ -1890,7 +1893,7 @@ public class UploadPackTest { "want-ref refs/heads/one\n", "want-ref refs/heads/two\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("wanted-refs")); assertThat( @@ -1921,7 +1924,7 @@ public class UploadPackTest { "want-ref refs/heads/one\n", "want-ref refs/heads/nonExistentRef\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); } catch (PackProtocolException e) { assertThat( e.getMessage(), @@ -1948,7 +1951,7 @@ public class UploadPackTest { "want-ref refs/heads/one\n", "want " + two.toObjectId().getName() + "\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("wanted-refs")); assertThat( @@ -1976,7 +1979,7 @@ public class UploadPackTest { "want-ref refs/heads/one\n", "have " + one.toObjectId().getName(), "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); // The client still needs to know the hash of the object that @@ -2008,7 +2011,7 @@ public class UploadPackTest { "want-ref refs/heads/branch1\n", "deepen 1\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); // shallow-info appears first, then wanted-refs. @@ -2041,7 +2044,7 @@ public class UploadPackTest { "shallow 0123012301230123012301230123012301230123", "shallow " + two.getName() + '\n', "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("shallow-info")); @@ -2070,7 +2073,7 @@ public class UploadPackTest { UploadPack up = new UploadPack(server); ByteArrayInputStream send = linesAsInputStream( "want " + one.getName() + " agent=JGit-test/1.2.3\n", - PacketLineIn.END, + PacketLineIn.end(), "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n"); ByteArrayOutputStream recv = new ByteArrayOutputStream(); @@ -2093,7 +2096,7 @@ public class UploadPackTest { "command=fetch\n", "agent=JGit-test/1.2.4\n", PacketLineIn.delimiter(), "want " + one.getName() + "\n", "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); ByteArrayOutputStream recv = new ByteArrayOutputStream(); up.upload(send, recv, null); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index 62f71e693..fff4f08c5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -250,6 +250,17 @@ public class PacketLineIn { return DELIM; } + /** + * Get the end marker. + *

+ * Intended for use only in tests. + * + * @return The end marker. + */ + static String end() { + return END; + } + /** * Check if a string is the packet end marker. * From ee747827b0d26cf770f44a33b201de31e81ca8ea Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 17:02:51 +0900 Subject: [PATCH 23/51] PacketLineIn: Add an iterator over strings in the input stream Allows callers to read all lines in the input stream until the END marker is reached, without having to explicitly check for the END marker. Replace all remaining usage of the END marker with the new method. Change-Id: I51f419c7f569ab7ed01e1aaaf6b40ed8cdc2116b Signed-off-by: David Pursehouse --- .../jgit/http/test/HttpClientTests.java | 6 +- .../transport/BasePackPushConnection.java | 3 +- .../eclipse/jgit/transport/PacketLineIn.java | 58 +++++++++++++++++ .../jgit/transport/ProtocolV2Parser.java | 63 ++++++++++--------- 4 files changed, 93 insertions(+), 37 deletions(-) diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java index 415804917..8ec2f51cf 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java @@ -387,8 +387,7 @@ public class HttpClientTests extends HttpTestCase { // What remains are capabilities - ensure that all of them are // non-empty strings, and that we see END at the end. - String s; - while ((s = pckIn.readString()) != PacketLineIn.END) { + for (String s : pckIn.readStrings()) { assertTrue(!s.isEmpty()); } } @@ -421,8 +420,7 @@ public class HttpClientTests extends HttpTestCase { PacketLineIn pckIn = new PacketLineIn(c.getInputStream()); // Just check that we get what looks like a ref advertisement. - String s; - while ((s = pckIn.readString()) != PacketLineIn.END) { + for (String s : pckIn.readStrings()) { assertTrue(s.matches("[0-9a-f]{40} [A-Za-z/]*")); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index 847e90198..35ea35ecb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -383,8 +383,7 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen JGitText.get().errorOccurredDuringUnpackingOnTheRemoteEnd, unpackStatus)); } - String refLine; - while ((refLine = pckIn.readString()) != PacketLineIn.END) { + for (String refLine : pckIn.readStrings()) { boolean ok = false; int refNameEnd = -1; if (refLine.startsWith("ok ")) { //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index fff4f08c5..e218c1e60 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -49,7 +49,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.text.MessageFormat; +import java.util.Iterator; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.internal.JGitText; @@ -195,6 +197,20 @@ public class PacketLineIn { return s; } + /** + * Get an iterator to read strings from the input stream. + * + * @return an iterator that calls {@link #readString()} until {@link #END} + * is encountered. + * + * @throws IOException + * on failure to read the initial packet line. + * @since 5.4 + */ + public PacketLineInIterator readStrings() throws IOException { + return new PacketLineInIterator(this); + } + /** * Read a single UTF-8 encoded string packet from the input stream. *

@@ -331,4 +347,46 @@ public class PacketLineIn { public static class InputOverLimitIOException extends IOException { private static final long serialVersionUID = 1L; } + + /** + * Iterator over packet lines. + *

+ * Calls {@link #readString()} on the {@link PacketLineIn} until + * {@link #END} is encountered. + * + * @since 5.4 + * + */ + public static class PacketLineInIterator implements Iterable { + private PacketLineIn in; + + private String current; + + PacketLineInIterator(PacketLineIn in) throws IOException { + this.in = in; + current = in.readString(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return !PacketLineIn.isEnd(current); + } + + @Override + public String next() { + String next = current; + try { + current = in.readString(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + return next; + } + }; + } + + } } 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 2c7beedc6..caba15fc5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java @@ -144,29 +144,30 @@ final class ProtocolV2Parser { } boolean filterReceived = false; - while ((line = pckIn.readString()) != PacketLineIn.END) { - if (line.startsWith("want ")) { //$NON-NLS-1$ - reqBuilder.addWantId(ObjectId.fromString(line.substring(5))); + for (String line2 : pckIn.readStrings()) { + if (line2.startsWith("want ")) { //$NON-NLS-1$ + reqBuilder.addWantId(ObjectId.fromString(line2.substring(5))); } else if (transferConfig.isAllowRefInWant() - && line.startsWith(OPTION_WANT_REF + " ")) { //$NON-NLS-1$ - reqBuilder.addWantedRef(line.substring(OPTION_WANT_REF.length() + 1)); - } else if (line.startsWith("have ")) { //$NON-NLS-1$ - reqBuilder.addPeerHas(ObjectId.fromString(line.substring(5))); - } else if (line.equals("done")) { //$NON-NLS-1$ + && line2.startsWith(OPTION_WANT_REF + " ")) { //$NON-NLS-1$ + reqBuilder.addWantedRef( + line2.substring(OPTION_WANT_REF.length() + 1)); + } else if (line2.startsWith("have ")) { //$NON-NLS-1$ + reqBuilder.addPeerHas(ObjectId.fromString(line2.substring(5))); + } else if (line2.equals("done")) { //$NON-NLS-1$ reqBuilder.setDoneReceived(); - } else if (line.equals(OPTION_THIN_PACK)) { + } else if (line2.equals(OPTION_THIN_PACK)) { reqBuilder.addClientCapability(OPTION_THIN_PACK); - } else if (line.equals(OPTION_NO_PROGRESS)) { + } else if (line2.equals(OPTION_NO_PROGRESS)) { reqBuilder.addClientCapability(OPTION_NO_PROGRESS); - } else if (line.equals(OPTION_INCLUDE_TAG)) { + } else if (line2.equals(OPTION_INCLUDE_TAG)) { reqBuilder.addClientCapability(OPTION_INCLUDE_TAG); - } else if (line.equals(OPTION_OFS_DELTA)) { + } else if (line2.equals(OPTION_OFS_DELTA)) { reqBuilder.addClientCapability(OPTION_OFS_DELTA); - } else if (line.startsWith("shallow ")) { //$NON-NLS-1$ + } else if (line2.startsWith("shallow ")) { //$NON-NLS-1$ reqBuilder.addClientShallowCommit( - ObjectId.fromString(line.substring(8))); - } else if (line.startsWith("deepen ")) { //$NON-NLS-1$ - int parsedDepth = Integer.parseInt(line.substring(7)); + ObjectId.fromString(line2.substring(8))); + } else if (line2.startsWith("deepen ")) { //$NON-NLS-1$ + int parsedDepth = Integer.parseInt(line2.substring(7)); if (parsedDepth <= 0) { throw new PackProtocolException( MessageFormat.format(JGitText.get().invalidDepth, @@ -181,19 +182,19 @@ final class ProtocolV2Parser { JGitText.get().deepenNotWithDeepen); } reqBuilder.setDepth(parsedDepth); - } else if (line.startsWith("deepen-not ")) { //$NON-NLS-1$ - reqBuilder.addDeepenNotRef(line.substring(11)); + } else if (line2.startsWith("deepen-not ")) { //$NON-NLS-1$ + reqBuilder.addDeepenNotRef(line2.substring(11)); if (reqBuilder.getDepth() != 0) { throw new PackProtocolException( JGitText.get().deepenNotWithDeepen); } - } else if (line.equals(OPTION_DEEPEN_RELATIVE)) { + } else if (line2.equals(OPTION_DEEPEN_RELATIVE)) { reqBuilder.addClientCapability(OPTION_DEEPEN_RELATIVE); - } else if (line.startsWith("deepen-since ")) { //$NON-NLS-1$ - int ts = Integer.parseInt(line.substring(13)); + } else if (line2.startsWith("deepen-since ")) { //$NON-NLS-1$ + int ts = Integer.parseInt(line2.substring(13)); if (ts <= 0) { throw new PackProtocolException(MessageFormat - .format(JGitText.get().invalidTimestamp, line)); + .format(JGitText.get().invalidTimestamp, line2)); } if (reqBuilder.getDepth() != 0) { throw new PackProtocolException( @@ -201,17 +202,17 @@ final class ProtocolV2Parser { } reqBuilder.setDeepenSince(ts); } else if (transferConfig.isAllowFilter() - && line.startsWith(OPTION_FILTER + ' ')) { + && line2.startsWith(OPTION_FILTER + ' ')) { if (filterReceived) { throw new PackProtocolException( JGitText.get().tooManyFilters); } filterReceived = true; reqBuilder.setFilterSpec(FilterSpec.fromFilterLine( - line.substring(OPTION_FILTER.length() + 1))); + line2.substring(OPTION_FILTER.length() + 1))); } else { throw new PackProtocolException(MessageFormat - .format(JGitText.get().unexpectedPacketLine, line)); + .format(JGitText.get().unexpectedPacketLine, line2)); } } @@ -253,16 +254,16 @@ final class ProtocolV2Parser { .format(JGitText.get().unexpectedPacketLine, line)); } - while ((line = pckIn.readString()) != PacketLineIn.END) { - if (line.equals("peel")) { //$NON-NLS-1$ + for (String line2 : pckIn.readStrings()) { + if (line2.equals("peel")) { //$NON-NLS-1$ builder.setPeel(true); - } else if (line.equals("symrefs")) { //$NON-NLS-1$ + } else if (line2.equals("symrefs")) { //$NON-NLS-1$ builder.setSymrefs(true); - } else if (line.startsWith("ref-prefix ")) { //$NON-NLS-1$ - prefixes.add(line.substring("ref-prefix ".length())); //$NON-NLS-1$ + } else if (line2.startsWith("ref-prefix ")) { //$NON-NLS-1$ + prefixes.add(line2.substring("ref-prefix ".length())); //$NON-NLS-1$ } else { throw new PackProtocolException(MessageFormat - .format(JGitText.get().unexpectedPacketLine, line)); + .format(JGitText.get().unexpectedPacketLine, line2)); } } From e8ed59a2acee4c1819246b5afab6c575a84b3ce7 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sun, 2 Jun 2019 17:27:17 +0900 Subject: [PATCH 24/51] PacketLineIn: Deprecate the END constant Deprecate the constant with the intention of making it private in a future release. All existing usage of the constant within JGit code has already been replaced with the recommended alternatives in preceding commits. Change-Id: I10eb95f3f92cb74f93a26bf1a6edd24615b75c6f Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/transport/PacketLineIn.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java index e218c1e60..90f1b373b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java @@ -74,7 +74,15 @@ import org.slf4j.LoggerFactory; public class PacketLineIn { private static final Logger log = LoggerFactory.getLogger(PacketLineIn.class); - /** Magic return from {@link #readString()} when a flush packet is found. */ + /** + * Magic return from {@link #readString()} when a flush packet is found. + * + * @deprecated Callers should use {@link #isEnd(String)} to check if a + * string is the end marker, or + * {@link PacketLineIn#readStrings()} to iterate over all + * strings in the input stream until the marker is reached. + */ + @Deprecated public static final String END = new StringBuilder(0).toString(); /* must not string pool */ /** From 692524d2bd7bccccecbebe624e427d7a3587cb5f Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 3 Jun 2019 09:55:20 +0200 Subject: [PATCH 25/51] Update to Orbit R20190602212107 This version fixed wrong Require-Capability: osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=9))" in bouncycastle 1.61. Bug: 547570 Change-Id: I715bcc4b39c3d4ad036dcc5bbdf48d321759f55f Signed-off-by: Matthias Sohn --- .../org.eclipse.jgit.target/jgit-4.10.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.10.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.11.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.11.tpd | 2 +- .../jgit-4.12-staging.target | 27 ++++++++++--------- .../jgit-4.12-staging.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.6.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.6.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.7.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.7.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.8.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.8.tpd | 2 +- .../org.eclipse.jgit.target/jgit-4.9.target | 16 +++++------ .../org.eclipse.jgit.target/jgit-4.9.tpd | 2 +- ...019-06.tpd => R20190602212107-2019-06.tpd} | 16 +++++------ 15 files changed, 78 insertions(+), 75 deletions(-) rename org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/{R20190531194818-2019-06.tpd => R20190602212107-2019-06.tpd} (87%) diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target index 988f2c5c6..191574720 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd index e949a9f3c..6beb42e33 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd @@ -1,7 +1,7 @@ target "jgit-4.10" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/2018-12/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target index fac656fa4..e5ea33101 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd index b8ebf43d9..e09e8c387 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd @@ -1,7 +1,7 @@ target "jgit-4.11" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/2019-03/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target index 1069e56cf..5daa8e8ad 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target @@ -1,6 +1,9 @@ - + + + + - + @@ -19,7 +22,7 @@ - + @@ -34,12 +37,12 @@ - - - - - - + + + + + + @@ -79,11 +82,11 @@ - + - + - \ No newline at end of file + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd index e18789559..43b64a030 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.tpd @@ -1,7 +1,7 @@ target "jgit-4.12-staging" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/staging/2019-06/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index a1776ffcf..0638b46a3 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd index e1fbb7fdc..1a2c9a3a1 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd @@ -1,7 +1,7 @@ target "jgit-4.6" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/neon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index 4a52ffff4..1044299df 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd index 42ffcfe2e..fc1b046ed 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd @@ -1,7 +1,7 @@ target "jgit-4.7" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/oxygen/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index 051c898b7..a5f948fde 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd index b5bcf0dde..a8f837e9c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd @@ -1,7 +1,7 @@ target "jgit-4.8" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/photon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target index 5c8841ebe..e0afda3a6 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target @@ -1,7 +1,7 @@ - + @@ -37,12 +37,12 @@ - - - - - - + + + + + + @@ -82,7 +82,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd index 4e4ab770d..f91f53eb8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd @@ -1,7 +1,7 @@ target "jgit-4.9" with source configurePhase include "projects/jetty-9.4.14.tpd" -include "orbit/R20190531194818-2019-06.tpd" +include "orbit/R20190602212107-2019-06.tpd" location "http://download.eclipse.org/releases/2018-09/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd similarity index 87% rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd index b8c815506..df9a810e0 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190531194818-2019-06.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd @@ -1,7 +1,7 @@ -target "R20190531194818-2019-06" with source configurePhase +target "R20190602212107-2019-06" with source configurePhase // see http://download.eclipse.org/tools/orbit/downloads/ -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20190531194818/repository" { +location "https://download.eclipse.org/tools/orbit/downloads/drops/R20190602212107/repository" { org.apache.ant [1.10.5.v20190526-1402,1.10.5.v20190526-1402] org.apache.ant.source [1.10.5.v20190526-1402,1.10.5.v20190526-1402] org.apache.commons.codec [1.10.0.v20180409-1845,1.10.0.v20180409-1845] @@ -16,12 +16,12 @@ location "https://download.eclipse.org/tools/orbit/downloads/drops/R201905311948 org.apache.httpcomponents.httpcore.source [4.4.10.v20190123-2214,4.4.10.v20190123-2214] org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815] org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815] - org.bouncycastle.bcpg [1.61.0.v20190530-2038,1.61.0.v20190530-2038] - org.bouncycastle.bcpg.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] - org.bouncycastle.bcpkix [1.61.0.v20190530-2038,1.61.0.v20190530-2038] - org.bouncycastle.bcpkix.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] - org.bouncycastle.bcprov [1.61.0.v20190530-2038,1.61.0.v20190530-2038] - org.bouncycastle.bcprov.source [1.61.0.v20190530-2038,1.61.0.v20190530-2038] + org.bouncycastle.bcpg [1.61.0.v20190602-1335,1.61.0.v20190602-1335] + org.bouncycastle.bcpg.source [1.61.0.v20190602-1335,1.61.0.v20190602-1335] + org.bouncycastle.bcpkix [1.61.0.v20190602-1335,1.61.0.v20190602-1335] + org.bouncycastle.bcpkix.source [1.61.0.v20190602-1335,1.61.0.v20190602-1335] + org.bouncycastle.bcprov [1.61.0.v20190602-1335,1.61.0.v20190602-1335] + org.bouncycastle.bcprov.source [1.61.0.v20190602-1335,1.61.0.v20190602-1335] org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000] From 8cd07cb8157eec75099cb93c25d6daa9d5e6e0bc Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Thu, 16 May 2019 17:06:57 +0200 Subject: [PATCH 26/51] Repository: Add getIdentifier() method to avoid instanceof operator This change is needed to implement permission aware ref database in Gerrit: [1], that is a pre-requisite to re-enable Git v2 protocol in Gerrit: [2]. Background: Last year Git v2 protocol was enabled in Gerrit. The fact, that JGit layer was not calling ref advertise filter for Git v2 protocol, introduced security vulnerability. The lesson learned from this security incident: Gerrit should not rely on ref advertise filter being called by JGit to implement crictical security checks. Instead, the idea is to use the same approach as currently used by Google's internal code on googlesource.com that didn't suffer from this vulnerability: provide a custom repository to JGit. The repository provides a RefDatabase that is permission-aware and will only ever return refs that the user has access to. However, due to hard coded instanceof operator usages in JGit code base, some tests in Gerrit are failing with: [1] in place. This change addresses this problem. [1] https://gerrit-review.googlesource.com/c/gerrit/+/212874 [2] https://gerrit-review.googlesource.com/c/gerrit/+/226754 Change-Id: I67c0f53ca33b149442e7ee3e51910d19e3f348d5 Signed-off-by: David Ostrovsky Signed-off-by: Matthias Sohn --- .../eclipse/jgit/http/server/ServletUtils.java | 10 ++++------ org.eclipse.jgit/.settings/.api_filters | 8 ++++++++ .../jgit/internal/storage/dfs/DfsRepository.java | 6 ++++++ .../internal/storage/file/FileRepository.java | 11 +++++++++++ .../src/org/eclipse/jgit/lib/Repository.java | 9 +++++++++ .../jgit/transport/HMACSHA1NonceGenerator.java | 16 +--------------- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java index b6d73b559..256279bfe 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java @@ -64,7 +64,6 @@ import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jgit.internal.storage.dfs.DfsRepository; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; @@ -276,12 +275,11 @@ public final class ServletUtils { } static String identify(Repository git) { - if (git instanceof DfsRepository) { - return ((DfsRepository) git).getDescription().getRepositoryName(); - } else if (git.getDirectory() != null) { - return git.getDirectory().getPath(); + String identifier = git.getIdentifier(); + if (identifier == null) { + return "unknown"; } - return "unknown"; + return identifier; } private ServletUtils() { diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index dc1df5963..7f93191ca 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -22,6 +22,14 @@ + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java index 5169e929e..8e5c5a7f7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java @@ -124,6 +124,12 @@ public abstract class DfsRepository extends Repository { return config; } + /** {@inheritDoc} */ + @Override + public String getIdentifier() { + return getDescription().getRepositoryName(); + } + /** {@inheritDoc} */ @Override public void scanForRepoChanges() throws IOException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index d82d29e4c..90772970a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -388,6 +388,17 @@ public class FileRepository extends Repository { return refs; } + /** {@inheritDoc} */ + @Override + public String getIdentifier() { + File directory = getDirectory(); + if (directory != null) { + return directory.getPath(); + } else { + throw new IllegalStateException(); + } + } + /** {@inheritDoc} */ @Override public FileBasedConfig getConfig() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index aac63e9d2..d53b0c926 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -239,6 +239,15 @@ public abstract class Repository implements AutoCloseable { return gitDir; } + /** + * Get repository identifier. + * + * @return repository identifier. The returned identifier has to be unique + * within a given Git server. + * @since 5.4 + */ + public abstract String getIdentifier(); + /** * Get the object database which stores this repository's data. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java index 53eaa6a7f..01f6fec7e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java @@ -45,14 +45,12 @@ package org.eclipse.jgit.transport; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; -import java.io.File; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import org.eclipse.jgit.internal.storage.dfs.DfsRepository; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.PushCertificate.NonceStatus; @@ -87,19 +85,7 @@ public class HMACSHA1NonceGenerator implements NonceGenerator { @Override public synchronized String createNonce(Repository repo, long timestamp) throws IllegalStateException { - String path; - if (repo instanceof DfsRepository) { - path = ((DfsRepository) repo).getDescription().getRepositoryName(); - } else { - File directory = repo.getDirectory(); - if (directory != null) { - path = directory.getPath(); - } else { - throw new IllegalStateException(); - } - } - - String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$ + String input = repo.getIdentifier() + ":" + String.valueOf(timestamp); //$NON-NLS-1$ byte[] rawHmac = mac.doFinal(input.getBytes(UTF_8)); return Long.toString(timestamp) + "-" + toHex(rawHmac); //$NON-NLS-1$ } From d7bd2e700c7eb1ea4f3b4a65087331c4ee96a9e5 Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Mon, 19 Nov 2018 18:10:07 +0100 Subject: [PATCH 27/51] Support reading and writing cookies. The git config entries "http.cookieFile" and "http.saveCookies" are correctly evaluated. Bug: 488572 Change-Id: Icfeeea95e1a5bac3fa4438849d4ac2306d7d5562 Signed-off-by: Konrad Windszus Signed-off-by: Matthias Sohn --- org.eclipse.jgit.test/META-INF/MANIFEST.MF | 1 + .../transport/http/cookies-invalid.txt | 1 + .../transport/http/cookies-simple1.txt | 2 + .../transport/http/cookies-simple2.txt | 2 + .../cookies-with-empty-and-comment-lines.txt | 8 + .../http/NetscapeCookieFileTest.java | 441 ++++++++++++++++ .../jgit/transport/TransportHttpTest.java | 189 +++++++ .../tst/org/eclipse/jgit/util/LRUMapTest.java | 78 +++ org.eclipse.jgit/.settings/.api_filters | 40 ++ org.eclipse.jgit/META-INF/MANIFEST.MF | 1 + .../eclipse/jgit/internal/JGitText.properties | 4 + .../org/eclipse/jgit/internal/JGitText.java | 4 + .../transport/http/NetscapeCookieFile.java | 471 ++++++++++++++++++ .../http/NetscapeCookieFileCache.java | 106 ++++ .../eclipse/jgit/transport/HttpConfig.java | 75 +++ .../eclipse/jgit/transport/TransportHttp.java | 248 ++++++++- .../org/eclipse/jgit/util/HttpSupport.java | 21 + .../src/org/eclipse/jgit/util/LRUMap.java | 83 +++ 18 files changed, 1774 insertions(+), 1 deletion(-) create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-invalid.txt create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple1.txt create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple2.txt create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-with-empty-and-comment-lines.txt create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/util/LRUMapTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/util/LRUMap.java diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 7ec5e6175..1c6211d53 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -35,6 +35,7 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", org.eclipse.jgit.internal.storage.pack;version="[5.4.0,5.5.0)", org.eclipse.jgit.internal.storage.reftable;version="[5.4.0,5.5.0)", org.eclipse.jgit.internal.storage.reftree;version="[5.4.0,5.5.0)", + org.eclipse.jgit.internal.transport.http;version="[5.4.0,5.5.0)", org.eclipse.jgit.internal.transport.parser;version="[5.4.0,5.5.0)", org.eclipse.jgit.junit;version="[5.4.0,5.5.0)", org.eclipse.jgit.junit.ssh;version="[5.4.0,5.5.0)", diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-invalid.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-invalid.txt new file mode 100644 index 000000000..bbc6a7329 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-invalid.txt @@ -0,0 +1 @@ +some-domain /some/path1 FALSE 0 key1 value1 \ No newline at end of file diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple1.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple1.txt new file mode 100644 index 000000000..e06b38c71 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple1.txt @@ -0,0 +1,2 @@ +some-domain1 TRUE /some/path1 FALSE 1893499200000 key1 valueFromSimple1 +some-domain1 TRUE /some/path1 FALSE 1893499200000 key2 valueFromSimple1 \ No newline at end of file diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple2.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple2.txt new file mode 100644 index 000000000..4bf6723fd --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-simple2.txt @@ -0,0 +1,2 @@ +some-domain1 TRUE /some/path1 FALSE 1893499200000 key1 valueFromSimple2 +some-domain1 TRUE /some/path1 FALSE 1893499200000 key3 valueFromSimple2 \ No newline at end of file diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-with-empty-and-comment-lines.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-with-empty-and-comment-lines.txt new file mode 100644 index 000000000..a9b8a2815 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/internal/transport/http/cookies-with-empty-and-comment-lines.txt @@ -0,0 +1,8 @@ +# first line is a comment +# the next cookie is supposed to be removed, because it has expired already +some-domain1 TRUE /some/path1 FALSE 0 key1 value1 + +# expires date is 01/01/2030 @ 12:00am (UTC) +#HttpOnly_.some-domain2 TRUE /some/path2 TRUE 1893499200000 key2 value2 + +some-domain3 TRUE /some/path3 FALSE 1893499200000 key3 value3 \ No newline at end of file diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java new file mode 100644 index 000000000..8f6cd3aae --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.transport.http; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.net.HttpCookie; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.time.Instant; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +import org.eclipse.jgit.internal.storage.file.LockFile; +import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.hamcrest.collection.IsIterableContainingInOrder; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class NetscapeCookieFileTest { + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + private Path tmpFile; + + private URL baseUrl; + + /** + * This is the expiration date that is used in the test cookie files + */ + private static long JAN_01_2030_NOON = Instant + .parse("2030-01-01T12:00:00.000Z").toEpochMilli(); + + @Before + public void setUp() throws IOException { + // this will not only return a new file name but also create new empty + // file! + tmpFile = folder.newFile().toPath(); + baseUrl = new URL("http://domain.com/my/path"); + } + + @Test + public void testMergeCookies() { + Set cookieSet1 = new LinkedHashSet<>(); + HttpCookie cookie = new HttpCookie("key1", "valueFromSet1"); + cookieSet1.add(cookie); + cookie = new HttpCookie("key2", "valueFromSet1"); + cookieSet1.add(cookie); + + Set cookieSet2 = new LinkedHashSet<>(); + cookie = new HttpCookie("key1", "valueFromSet2"); + cookieSet2.add(cookie); + cookie = new HttpCookie("key3", "valueFromSet2"); + cookieSet2.add(cookie); + + Set cookiesExpectedMergedSet = new LinkedHashSet<>(); + cookie = new HttpCookie("key1", "valueFromSet1"); + cookiesExpectedMergedSet.add(cookie); + cookie = new HttpCookie("key2", "valueFromSet1"); + cookiesExpectedMergedSet.add(cookie); + cookie = new HttpCookie("key3", "valueFromSet2"); + cookiesExpectedMergedSet.add(cookie); + + Assert.assertThat( + NetscapeCookieFile.mergeCookies(cookieSet1, cookieSet2), + HttpCookiesMatcher.containsInOrder(cookiesExpectedMergedSet)); + + Assert.assertThat(NetscapeCookieFile.mergeCookies(cookieSet1, null), + HttpCookiesMatcher.containsInOrder(cookieSet1)); + } + + @Test + public void testWriteToNewFile() throws IOException { + Set cookies = new LinkedHashSet<>(); + cookies.add(new HttpCookie("key1", "value")); + // first cookie is a session cookie (and should be ignored) + + HttpCookie cookie = new HttpCookie("key2", "value"); + cookie.setSecure(true); + cookie.setDomain("mydomain.com"); + cookie.setPath("/"); + cookie.setMaxAge(1000); + cookies.add(cookie); + Date creationDate = new Date(); + try (Writer writer = Files.newBufferedWriter(tmpFile, + StandardCharsets.US_ASCII)) { + NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate); + } + + String expectedExpiration = String + .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000)); + + Assert.assertThat( + Files.readAllLines(tmpFile, StandardCharsets.US_ASCII), + CoreMatchers + .equalTo(Arrays.asList("mydomain.com\tTRUE\t/\tTRUE\t" + + expectedExpiration + "\tkey2\tvalue"))); + } + + @Test + public void testWriteToExistingFile() throws IOException { + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-simple1.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + + Set cookies = new LinkedHashSet<>(); + HttpCookie cookie = new HttpCookie("key2", "value2"); + cookie.setMaxAge(1000); + cookies.add(cookie); + Date creationDate = new Date(); + try (Writer writer = Files.newBufferedWriter(tmpFile, + StandardCharsets.US_ASCII)) { + NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate); + } + String expectedExpiration = String + .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000)); + + Assert.assertThat( + Files.readAllLines(tmpFile, StandardCharsets.US_ASCII), + CoreMatchers.equalTo( + Arrays.asList("domain.com\tTRUE\t/my/path\tFALSE\t" + + expectedExpiration + "\tkey2\tvalue2"))); + } + + @Test(expected = IOException.class) + public void testWriteWhileSomeoneIsHoldingTheLock() + throws IllegalArgumentException, IOException, InterruptedException { + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-simple1.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile); + // now imitate another process/thread holding the lock file + LockFile lockFile = new LockFile(tmpFile.toFile()); + try { + Assert.assertTrue("Could not acquire lock", lockFile.lock()); + cookieFile.write(baseUrl); + } finally { + lockFile.unlock(); + } + } + + @Test + public void testWriteAfterAnotherJgitProcessModifiedTheFile() + throws IOException, InterruptedException { + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-simple1.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + NetscapeCookieFile cookieFile = new NetscapeCookieFile(tmpFile); + cookieFile.getCookies(true); + // now modify file externally + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-simple2.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + // now try to write + cookieFile.write(baseUrl); + + // validate that the external changes are there as well + // due to rounding errors (conversion from ms to sec to ms) + // the expiration date might not be exact + List lines = Files.readAllLines(tmpFile, + StandardCharsets.US_ASCII); + + Assert.assertEquals("Expected 3 lines", 3, lines.size()); + assertStringMatchesPatternWithInexactNumber(lines.get(0), + "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey1\tvalueFromSimple2", + JAN_01_2030_NOON, 1000); + assertStringMatchesPatternWithInexactNumber(lines.get(1), + "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey3\tvalueFromSimple2", + JAN_01_2030_NOON, 1000); + assertStringMatchesPatternWithInexactNumber(lines.get(2), + "some-domain1\tTRUE\t/some/path1\tFALSE\t(\\d*)\tkey2\tvalueFromSimple1", + JAN_01_2030_NOON, 1000); + } + + @SuppressWarnings("boxing") + private static final void assertStringMatchesPatternWithInexactNumber( + String string, String pattern, long expectedNumericValue, + long delta) { + java.util.regex.Matcher matcher = Pattern.compile(pattern) + .matcher(string); + Assert.assertTrue("Given string '" + string + "' does not match '" + + pattern + "'", matcher.matches()); + // extract numeric value + Long actualNumericValue = Long.decode(matcher.group(1)); + + Assert.assertTrue( + "Value is supposed to be close to " + expectedNumericValue + + " but is " + actualNumericValue + ".", + Math.abs(expectedNumericValue - actualNumericValue) <= delta); + } + + @Test + public void testWriteAndReadCycle() throws IOException { + Set cookies = new LinkedHashSet<>(); + + HttpCookie cookie = new HttpCookie("key1", "value1"); + cookie.setPath("/some/path1"); + cookie.setDomain("some-domain1"); + cookie.setMaxAge(1000); + cookies.add(cookie); + cookie = new HttpCookie("key2", "value2"); + cookie.setSecure(true); + cookie.setPath("/some/path2"); + cookie.setDomain("some-domain2"); + cookie.setMaxAge(1000); + cookie.setHttpOnly(true); + cookies.add(cookie); + + Date creationDate = new Date(); + + try (Writer writer = Files.newBufferedWriter(tmpFile, + StandardCharsets.US_ASCII)) { + NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate); + } + Set actualCookies = new NetscapeCookieFile(tmpFile, + creationDate).getCookies(true); + Assert.assertThat(actualCookies, + HttpCookiesMatcher.containsInOrder(cookies)); + } + + @Test + public void testReadAndWriteCycle() throws IOException { + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-simple1.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + // round up to the next second (to prevent rounding errors) + Date creationDate = new Date( + (System.currentTimeMillis() / 1000) * 1000); + Set cookies = new NetscapeCookieFile(tmpFile, creationDate) + .getCookies(true); + Path tmpFile2 = folder.newFile().toPath(); + try (Writer writer = Files.newBufferedWriter(tmpFile2, + StandardCharsets.US_ASCII)) { + NetscapeCookieFile.write(writer, cookies, baseUrl, creationDate); + } + // compare original file with newly written one, they should not differ + Assert.assertEquals(Files.readAllLines(tmpFile), + Files.readAllLines(tmpFile2)); + } + + @Test + public void testReadWithEmptyAndCommentLines() throws IOException { + try (InputStream input = this.getClass().getResourceAsStream( + "cookies-with-empty-and-comment-lines.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + + Date creationDate = new Date(); + Set cookies = new LinkedHashSet<>(); + + HttpCookie cookie = new HttpCookie("key2", "value2"); + cookie.setDomain("some-domain2"); + cookie.setPath("/some/path2"); + cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000); + cookie.setSecure(true); + cookie.setHttpOnly(true); + cookies.add(cookie); + + cookie = new HttpCookie("key3", "value3"); + cookie.setDomain("some-domain3"); + cookie.setPath("/some/path3"); + cookie.setMaxAge((JAN_01_2030_NOON - creationDate.getTime()) / 1000); + cookies.add(cookie); + + Set actualCookies = new NetscapeCookieFile(tmpFile, creationDate) + .getCookies(true); + Assert.assertThat(actualCookies, + HttpCookiesMatcher.containsInOrder(cookies)); + } + + @Test + public void testReadInvalidFile() throws IOException { + try (InputStream input = this.getClass() + .getResourceAsStream("cookies-invalid.txt")) { + Files.copy(input, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + + new NetscapeCookieFile(tmpFile) + .getCookies(true); + } + + public final static class HttpCookiesMatcher { + public static Matcher> containsInOrder( + Iterable expectedCookies) { + return containsInOrder(expectedCookies, 0); + } + + public static Matcher> containsInOrder( + Iterable expectedCookies, int allowedMaxAgeDelta) { + final List> cookieMatchers = new LinkedList<>(); + for (HttpCookie cookie : expectedCookies) { + cookieMatchers + .add(new HttpCookieMatcher(cookie, allowedMaxAgeDelta)); + } + return new IsIterableContainingInOrder<>(cookieMatchers); + } + } + + /** + * The default {@link HttpCookie#equals(Object)} is not good enough for + * testing purposes. Also the {@link HttpCookie#toString()} only emits some + * of the cookie attributes. For testing a dedicated matcher is needed which + * takes into account all attributes. + */ + private final static class HttpCookieMatcher + extends TypeSafeMatcher { + + private final HttpCookie cookie; + + private final int allowedMaxAgeDelta; + + public HttpCookieMatcher(HttpCookie cookie, int allowedMaxAgeDelta) { + this.cookie = cookie; + this.allowedMaxAgeDelta = allowedMaxAgeDelta; + } + + @Override + public void describeTo(Description description) { + describeCookie(description, cookie); + } + + @Override + protected void describeMismatchSafely(HttpCookie item, + Description mismatchDescription) { + mismatchDescription.appendText("was "); + describeCookie(mismatchDescription, item); + } + + @Override + protected boolean matchesSafely(HttpCookie otherCookie) { + // the equals method in HttpCookie is not specific enough, we want + // to consider all attributes! + return (equals(cookie.getName(), otherCookie.getName()) + && equals(cookie.getValue(), otherCookie.getValue()) + && equals(cookie.getDomain(), otherCookie.getDomain()) + && equals(cookie.getPath(), otherCookie.getPath()) + && (cookie.getMaxAge() >= otherCookie.getMaxAge() + - allowedMaxAgeDelta) + && (cookie.getMaxAge() <= otherCookie.getMaxAge() + + allowedMaxAgeDelta) + && cookie.isHttpOnly() == otherCookie.isHttpOnly() + && cookie.getSecure() == otherCookie.getSecure() + && cookie.getVersion() == otherCookie.getVersion()); + } + + private static boolean equals(String value1, String value2) { + if (value1 == null && value2 == null) { + return true; + } + if (value1 == null || value2 == null) { + return false; + } + return value1.equals(value2); + } + + @SuppressWarnings("boxing") + protected static void describeCookie(Description description, + HttpCookie cookie) { + description.appendText("HttpCookie["); + description.appendText("name: ").appendValue(cookie.getName()) + .appendText(", "); + description.appendText("value: ").appendValue(cookie.getValue()) + .appendText(", "); + description.appendText("domain: ").appendValue(cookie.getDomain()) + .appendText(", "); + description.appendText("path: ").appendValue(cookie.getPath()) + .appendText(", "); + description.appendText("maxAge: ").appendValue(cookie.getMaxAge()) + .appendText(", "); + description.appendText("httpOnly: ") + .appendValue(cookie.isHttpOnly()).appendText(", "); + description.appendText("secure: ").appendValue(cookie.getSecure()) + .appendText(", "); + description.appendText("version: ").appendValue(cookie.getVersion()) + .appendText(", "); + description.appendText("]"); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java new file mode 100644 index 000000000..111c92523 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.io.File; +import java.io.IOException; +import java.net.HttpCookie; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile; +import org.eclipse.jgit.internal.transport.http.NetscapeCookieFileTest.HttpCookiesMatcher; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; +import org.eclipse.jgit.transport.http.HttpConnection; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; + +public class TransportHttpTest extends SampleDataRepositoryTestCase { + private URIish uri; + private File cookieFile; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + uri = new URIish("https://everyones.loves.git/u/2"); + + final Config config = db.getConfig(); + config.setBoolean("http", null, "saveCookies", true); + cookieFile = createTempFile(); + config.setString("http", null, "cookieFile", + cookieFile.getAbsolutePath()); + } + + @Test + public void testMatchesCookieDomain() { + Assert.assertTrue(TransportHttp.matchesCookieDomain("example.com", + "example.com")); + Assert.assertTrue(TransportHttp.matchesCookieDomain("Example.Com", + "example.cOM")); + Assert.assertTrue(TransportHttp.matchesCookieDomain( + "some.subdomain.example.com", "example.com")); + Assert.assertFalse(TransportHttp + .matchesCookieDomain("someotherexample.com", "example.com")); + Assert.assertFalse(TransportHttp.matchesCookieDomain("example.com", + "example1.com")); + Assert.assertFalse(TransportHttp + .matchesCookieDomain("sub.sub.example.com", ".example.com")); + Assert.assertTrue(TransportHttp.matchesCookieDomain("host.example.com", + "example.com")); + Assert.assertTrue(TransportHttp.matchesCookieDomain( + "something.example.com", "something.example.com")); + Assert.assertTrue(TransportHttp.matchesCookieDomain( + "host.something.example.com", "something.example.com")); + } + + @Test + public void testMatchesCookiePath() { + Assert.assertTrue( + TransportHttp.matchesCookiePath("/some/path", "/some/path")); + Assert.assertTrue(TransportHttp.matchesCookiePath("/some/path/child", + "/some/path")); + Assert.assertTrue(TransportHttp.matchesCookiePath("/some/path/child", + "/some/path/")); + Assert.assertFalse(TransportHttp.matchesCookiePath("/some/pathother", + "/some/path")); + Assert.assertFalse( + TransportHttp.matchesCookiePath("otherpath", "/some/path")); + } + + @Test + public void testProcessResponseCookies() throws IOException { + HttpConnection connection = Mockito.mock(HttpConnection.class); + Mockito.when( + connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie"))) + .thenReturn(Arrays.asList( + "id=a3fWa; Expires=Fri, 01 Jan 2100 11:00:00 GMT; Secure; HttpOnly", + "sessionid=38afes7a8; HttpOnly; Path=/")); + Mockito.when( + connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie2"))) + .thenReturn(Collections + .singletonList("cookie2=some value; Max-Age=1234; Path=/")); + + try (TransportHttp transportHttp = new TransportHttp(db, uri)) { + Date creationDate = new Date(); + transportHttp.processResponseCookies(connection); + + // evaluate written cookie file + Set expectedCookies = new LinkedHashSet<>(); + + HttpCookie cookie = new HttpCookie("id", "a3fWa"); + cookie.setDomain("everyones.loves.git"); + cookie.setPath("/u/2/"); + + cookie.setMaxAge( + (Instant.parse("2100-01-01T11:00:00.000Z").toEpochMilli() + - creationDate.getTime()) / 1000); + cookie.setSecure(true); + cookie.setHttpOnly(true); + expectedCookies.add(cookie); + + cookie = new HttpCookie("cookie2", "some value"); + cookie.setDomain("everyones.loves.git"); + cookie.setPath("/"); + cookie.setMaxAge(1234); + expectedCookies.add(cookie); + + Assert.assertThat( + new NetscapeCookieFile(cookieFile.toPath()) + .getCookies(true), + HttpCookiesMatcher.containsInOrder(expectedCookies, 5)); + } + } + + @Test + public void testProcessResponseCookiesNotPersistingWithSaveCookiesFalse() + throws IOException { + HttpConnection connection = Mockito.mock(HttpConnection.class); + Mockito.when( + connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie"))) + .thenReturn(Arrays.asList( + "id=a3fWa; Expires=Thu, 21 Oct 2100 11:00:00 GMT; Secure; HttpOnly", + "sessionid=38afes7a8; HttpOnly; Path=/")); + Mockito.when( + connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie2"))) + .thenReturn(Collections.singletonList( + "cookie2=some value; Max-Age=1234; Path=/")); + + // tweak config + final Config config = db.getConfig(); + config.setBoolean("http", null, "saveCookies", false); + + try (TransportHttp transportHttp = new TransportHttp(db, uri)) { + transportHttp.processResponseCookies(connection); + + // evaluate written cookie file + Assert.assertFalse("Cookie file was not supposed to be written!", + cookieFile.exists()); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/LRUMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/LRUMapTest.java new file mode 100644 index 000000000..da59533ae --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/LRUMapTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.hamcrest.collection.IsIterableContainingInOrder; +import org.junit.Assert; +import org.junit.Test; + +public class LRUMapTest { + + @SuppressWarnings("boxing") + @Test + public void testLRUEntriesAreEvicted() { + Map map = new LRUMap<>(3, 3); + for (int i = 0; i < 3; i++) { + map.put(i, i); + } + // access the last ones + map.get(2); + map.get(0); + + // put another one which exceeds the limit (entry with key "1" is + // evicted) + map.put(3, 3); + + Map expectedMap = new LinkedHashMap<>(); + expectedMap.put(2, 2); + expectedMap.put(0, 0); + expectedMap.put(3, 3); + + Assert.assertThat(map.entrySet(), + IsIterableContainingInOrder + .contains(expectedMap.entrySet().toArray())); + } +} diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 7f93191ca..ed36dde8b 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -68,4 +68,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index bd3161b43..893f0d430 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -86,6 +86,7 @@ Export-Package: org.eclipse.jgit.annotations;version="5.4.0", org.eclipse.jgit.pgm", org.eclipse.jgit.internal.storage.reftree;version="5.4.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", org.eclipse.jgit.internal.submodule;version="5.4.0";x-internal:=true, + org.eclipse.jgit.internal.transport.http;version="5.4.0";x-friends:="org.eclipse.jgit.test", org.eclipse.jgit.internal.transport.parser;version="5.4.0";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test", org.eclipse.jgit.internal.transport.ssh;version="5.4.0";x-friends:="org.eclipse.jgit.ssh.apache", org.eclipse.jgit.lib;version="5.4.0"; diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 6da6fee38..88fdc3d81 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -208,6 +208,10 @@ couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index couldNotGetAdvertisedRef=Remote {0} did not advertise Ref for branch {1}. This Ref may not exist in the remote or may be hidden by permission settings. couldNotGetRepoStatistics=Could not get repository statistics couldNotLockHEAD=Could not lock HEAD +couldNotFindTabInLine=Could not find tab in line {0}. Tab is the mandatory separator for the Netscape Cookie File Format. +couldNotFindSixTabsInLine=Could not find 6 tabs but only {0} in line '{1}'. 7 tab separated columns per line are mandatory for the Netscape Cookie File Format. +couldNotPersistCookies=Could not persist received cookies in file ''{0}'' +couldNotReadCookieFile=Could not read cookie file ''{0}'' couldNotReadIndexInOneGo=Could not read index in one go, only {0} out of {1} read couldNotReadObjectWhileParsingCommit=Could not read an object while parsing commit {0} couldNotRenameDeleteOldIndex=Could not rename delete old index 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 7a5ef4b7e..88b3fc850 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -267,9 +267,13 @@ public class JGitText extends TranslationBundle { /***/ public String couldNotCheckOutBecauseOfConflicts; /***/ public String couldNotDeleteLockFileShouldNotHappen; /***/ public String couldNotDeleteTemporaryIndexFileShouldNotHappen; + /***/ public String couldNotFindTabInLine; + /***/ public String couldNotFindSixTabsInLine; /***/ public String couldNotGetAdvertisedRef; /***/ public String couldNotGetRepoStatistics; /***/ public String couldNotLockHEAD; + /***/ public String couldNotPersistCookies; + /***/ public String couldNotReadCookieFile; /***/ public String couldNotReadIndexInOneGo; /***/ public String couldNotReadObjectWhileParsingCommit; /***/ public String couldNotRenameDeleteOldIndex; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java new file mode 100644 index 000000000..93be5c69e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.transport.http; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.StringReader; +import java.io.Writer; +import java.net.HttpCookie; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.FileSnapshot; +import org.eclipse.jgit.internal.storage.file.LockFile; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.RawParseUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Wraps all cookies persisted in a Netscape Cookie File Format + * being referenced via the git config http.cookieFile. + * + * It will only load the cookies lazily, i.e. before calling + * {@link #getCookies(boolean)} the file is not evaluated. This class also + * allows persisting cookies in that file format. + *

+ * In general this class is not thread-safe. So any consumer needs to take care + * of synchronization! + * + * @see Netscape Cookie File + * Format + * @see Cookie + * format for wget + * @see libcurl + * Cookie file parsing + * @see libcurl + * Cookie file writing + * @see NetscapeCookieFileCache + */ +public final class NetscapeCookieFile { + + private static final String HTTP_ONLY_PREAMBLE = "#HttpOnly_"; //$NON-NLS-1$ + + private static final String COLUMN_SEPARATOR = "\t"; //$NON-NLS-1$ + + private static final String LINE_SEPARATOR = "\n"; //$NON-NLS-1$ + + /** + * Maximum number of retries to acquire the lock for writing to the + * underlying file. + */ + private static final int LOCK_ACQUIRE_MAX_RETRY_COUNT = 4; + + /** + * Sleep time in milliseconds between retries to acquire the lock for + * writing to the underlying file. + */ + private static final int LOCK_ACQUIRE_RETRY_SLEEP = 500; + + private final Path path; + + private FileSnapshot snapshot; + + private byte[] hash; + + final Date creationDate; + + private Set cookies = null; + + private static final Logger LOG = LoggerFactory + .getLogger(NetscapeCookieFile.class); + + /** + * @param path + */ + public NetscapeCookieFile(Path path) { + this(path, new Date()); + } + + NetscapeCookieFile(Path path, Date creationDate) { + this.path = path; + this.snapshot = FileSnapshot.DIRTY; + this.creationDate = creationDate; + } + + /** + * @return the path to the underlying cookie file + */ + public Path getPath() { + return path; + } + + /** + * @param refresh + * if {@code true} updates the list from the underlying cookie + * file if it has been modified since the last read otherwise + * returns the current transient state. In case the cookie file + * has never been read before will always read from the + * underlying file disregarding the value of this parameter. + * @return all cookies (may contain session cookies as well). This does not + * return a copy of the list but rather the original one. Every + * addition to the returned list can afterwards be persisted via + * {@link #write(URL)}. Errors in the underlying file will not lead + * to exceptions but rather to an empty set being returned and the + * underlying error being logged. + */ + public Set getCookies(boolean refresh) { + if (cookies == null || refresh) { + try { + byte[] in = getFileContentIfModified(); + Set newCookies = parseCookieFile(in, creationDate); + if (cookies != null) { + cookies = mergeCookies(newCookies, cookies); + } else { + cookies = newCookies; + } + return cookies; + } catch (IOException | IllegalArgumentException e) { + LOG.warn( + MessageFormat.format( + JGitText.get().couldNotReadCookieFile, path), + e); + if (cookies == null) { + cookies = new LinkedHashSet<>(); + } + } + } + return cookies; + + } + + /** + * Parses the given file and extracts all cookie information from it. + * + * @param input + * the file content to parse + * @param creationDate + * the date for the creation of the cookies (used to calculate + * the maxAge based on the expiration date given within the file) + * @return the set of parsed cookies from the given file (even expired + * ones). If there is more than one cookie with the same name in + * this file the last one overwrites the first one! + * @throws IOException + * if the given file could not be read for some reason + * @throws IllegalArgumentException + * if the given file does not have a proper format. + */ + private static Set parseCookieFile(@NonNull byte[] input, + @NonNull Date creationDate) + throws IOException, IllegalArgumentException { + + String decoded = RawParseUtils.decode(StandardCharsets.US_ASCII, input); + + Set cookies = new LinkedHashSet<>(); + try (BufferedReader reader = new BufferedReader( + new StringReader(decoded))) { + String line; + while ((line = reader.readLine()) != null) { + HttpCookie cookie = parseLine(line, creationDate); + if (cookie != null) { + cookies.add(cookie); + } + } + } + return cookies; + } + + private static HttpCookie parseLine(@NonNull String line, + @NonNull Date creationDate) { + if (line.isEmpty() || (line.startsWith("#") //$NON-NLS-1$ + && !line.startsWith(HTTP_ONLY_PREAMBLE))) { + return null; + } + String[] cookieLineParts = line.split(COLUMN_SEPARATOR, 7); + if (cookieLineParts == null) { + throw new IllegalArgumentException(MessageFormat + .format(JGitText.get().couldNotFindTabInLine, line)); + } + if (cookieLineParts.length < 7) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().couldNotFindSixTabsInLine, + Integer.valueOf(cookieLineParts.length), line)); + } + String name = cookieLineParts[5]; + String value = cookieLineParts[6]; + HttpCookie cookie = new HttpCookie(name, value); + + String domain = cookieLineParts[0]; + if (domain.startsWith(HTTP_ONLY_PREAMBLE)) { + cookie.setHttpOnly(true); + domain = domain.substring(HTTP_ONLY_PREAMBLE.length()); + } + // strip off leading "." + // (https://tools.ietf.org/html/rfc6265#section-5.2.3) + if (domain.startsWith(".")) { //$NON-NLS-1$ + domain = domain.substring(1); + } + cookie.setDomain(domain); + // domain evaluation as boolean flag not considered (i.e. always assumed + // to be true) + cookie.setPath(cookieLineParts[2]); + cookie.setSecure(Boolean.parseBoolean(cookieLineParts[3])); + + long expires = Long.parseLong(cookieLineParts[4]); + long maxAge = (expires - creationDate.getTime()) / 1000; + if (maxAge <= 0) { + return null; // skip expired cookies + } + cookie.setMaxAge(maxAge); + return cookie; + } + + /** + * Writes all the cookies being maintained in the set being returned by + * {@link #getCookies(boolean)} to the underlying file. + * + * Session-cookies will not be persisted. + * + * @param url + * url for which to write the cookies (important to derive + * default values for non-explicitly set attributes) + * @throws IOException + * @throws IllegalArgumentException + * @throws InterruptedException + */ + public void write(URL url) + throws IllegalArgumentException, IOException, InterruptedException { + try { + byte[] cookieFileContent = getFileContentIfModified(); + if (cookieFileContent != null) { + LOG.debug( + "Reading the underlying cookie file '{}' as it has been modified since the last access", //$NON-NLS-1$ + path); + // reread new changes if necessary + Set cookiesFromFile = NetscapeCookieFile + .parseCookieFile(cookieFileContent, creationDate); + this.cookies = mergeCookies(cookiesFromFile, cookies); + } + } catch (FileNotFoundException e) { + // ignore if file previously did not exist yet! + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (Writer writer = new OutputStreamWriter(output, + StandardCharsets.US_ASCII)) { + write(writer, cookies, url, creationDate); + } + LockFile lockFile = new LockFile(path.toFile()); + for (int retryCount = 0; retryCount < LOCK_ACQUIRE_MAX_RETRY_COUNT; retryCount++) { + if (lockFile.lock()) { + try { + lockFile.setNeedSnapshot(true); + lockFile.write(output.toByteArray()); + if (!lockFile.commit()) { + throw new IOException(MessageFormat.format( + JGitText.get().cannotCommitWriteTo, path)); + } + } finally { + lockFile.unlock(); + } + return; + } + Thread.sleep(LOCK_ACQUIRE_RETRY_SLEEP); + } + throw new IOException( + MessageFormat.format(JGitText.get().cannotLock, lockFile)); + + } + + /** + * Read the underying file and return its content but only in case it has + * been modified since the last access. Internally calculates the hash and + * maintains {@link FileSnapshot}s to prevent issues described as "Racy + * Git problem". Inspired by {@link FileBasedConfig#load()}. + * + * @return the file contents in case the file has been modified since the + * last access, otherwise {@code null} + * @throws IOException + */ + private byte[] getFileContentIfModified() throws IOException { + final int maxStaleRetries = 5; + int retries = 0; + File file = getPath().toFile(); + while (true) { + final FileSnapshot oldSnapshot = snapshot; + final FileSnapshot newSnapshot = FileSnapshot.save(file); + try { + final byte[] in = IO.readFully(file); + byte[] newHash = hash(in); + if (Arrays.equals(hash, newHash)) { + if (oldSnapshot.equals(newSnapshot)) { + oldSnapshot.setClean(newSnapshot); + } else { + snapshot = newSnapshot; + } + } else { + snapshot = newSnapshot; + hash = newHash; + } + return in; + } catch (FileNotFoundException e) { + throw e; + } catch (IOException e) { + if (FileUtils.isStaleFileHandle(e) + && retries < maxStaleRetries) { + if (LOG.isDebugEnabled()) { + LOG.debug(MessageFormat.format( + JGitText.get().configHandleIsStale, + Integer.valueOf(retries)), e); + } + retries++; + continue; + } + throw new IOException(MessageFormat + .format(JGitText.get().cannotReadFile, getPath()), e); + } + } + + } + + private byte[] hash(final byte[] in) { + return Constants.newMessageDigest().digest(in); + } + + /** + * Writes the given cookies to the file in the Netscape Cookie File Format + * (also used by curl) + * + * @param writer + * the writer to use to persist the cookies. + * @param cookies + * the cookies to write into the file + * @param url + * the url for which to write the cookie (to derive the default + * values for certain cookie attributes) + * @param creationDate + * the date when the cookie has been created. Important for + * calculation the cookie expiration time (calculated from + * cookie's maxAge and this creation time). + * @throws IOException + */ + static void write(@NonNull Writer writer, + @NonNull Collection cookies, @NonNull URL url, + @NonNull Date creationDate) throws IOException { + for (HttpCookie cookie : cookies) { + writeCookie(writer, cookie, url, creationDate); + } + } + + private static void writeCookie(@NonNull Writer writer, + @NonNull HttpCookie cookie, @NonNull URL url, + @NonNull Date creationDate) throws IOException { + if (cookie.getMaxAge() <= 0) { + return; // skip expired cookies + } + String domain = ""; //$NON-NLS-1$ + if (cookie.isHttpOnly()) { + domain = HTTP_ONLY_PREAMBLE; + } + if (cookie.getDomain() != null) { + domain += cookie.getDomain(); + } else { + domain += url.getHost(); + } + writer.write(domain); + writer.write(COLUMN_SEPARATOR); + writer.write("TRUE"); //$NON-NLS-1$ + writer.write(COLUMN_SEPARATOR); + String path = cookie.getPath(); + if (path == null) { + path = url.getPath(); + } + writer.write(path); + writer.write(COLUMN_SEPARATOR); + writer.write(Boolean.toString(cookie.getSecure()).toUpperCase()); + writer.write(COLUMN_SEPARATOR); + final String expirationDate; + // whenCreated field is not accessible in HttpCookie + expirationDate = String + .valueOf(creationDate.getTime() + (cookie.getMaxAge() * 1000)); + writer.write(expirationDate); + writer.write(COLUMN_SEPARATOR); + writer.write(cookie.getName()); + writer.write(COLUMN_SEPARATOR); + writer.write(cookie.getValue()); + writer.write(LINE_SEPARATOR); + } + + /** + * Merge the given sets in the following way. All cookies from + * {@code cookies1} and {@code cookies2} are contained in the resulting set + * which have unique names. If there is a duplicate entry for one name only + * the entry from set {@code cookies1} ends up in the resulting set. + * + * @param cookies1 + * @param cookies2 + * + * @return the merged cookies + */ + static Set mergeCookies(Set cookies1, + @Nullable Set cookies2) { + Set mergedCookies = new LinkedHashSet<>(cookies1); + if (cookies2 != null) { + mergedCookies.addAll(cookies2); + } + return mergedCookies; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java new file mode 100644 index 000000000..882b2d055 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.transport.http; + +import java.nio.file.Path; + +import org.eclipse.jgit.transport.HttpConfig; +import org.eclipse.jgit.util.LRUMap; + +/** + * A cache of all known cookie files ({@link NetscapeCookieFile}). May contain + * at most {@code n} entries, where the least-recently used one is evicted as + * soon as more entries are added. The maximum number of entries (={@code n}) + * can be set via the git config key {@code http.cookieFileCacheLimit}. By + * default it is set to 10. + *

+ * The cache is global, i.e. it is shared among all consumers within the same + * Java process. + * + * @see NetscapeCookieFile + * + */ +public class NetscapeCookieFileCache { + + private final LRUMap cookieFileMap; + + private static NetscapeCookieFileCache instance; + + private NetscapeCookieFileCache(HttpConfig config) { + cookieFileMap = new LRUMap<>(config.getCookieFileCacheLimit(), + config.getCookieFileCacheLimit()); + } + + /** + * @param config + * the config which defines the limit for this cache + * @return the singleton instance of the cookie file cache. If the cache has + * already been created the given config is ignored (even if it + * differs from the config, with which the cache has originally been + * created) + */ + public static NetscapeCookieFileCache getInstance(HttpConfig config) { + if (instance == null) { + return new NetscapeCookieFileCache(config); + } else { + return instance; + } + } + + /** + * @param path + * the path of the cookie file to retrieve + * @return the cache entry belonging to the requested file + */ + public NetscapeCookieFile getEntry(Path path) { + if (!cookieFileMap.containsKey(path)) { + synchronized (NetscapeCookieFileCache.class) { + if (!cookieFileMap.containsKey(path)) { + cookieFileMap.put(path, new NetscapeCookieFile(path)); + } + } + } + return cookieFileMap.get(path); + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java index 101ce3568..54c21cbc8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java @@ -89,6 +89,30 @@ public class HttpConfig { /** git config key for the "sslVerify" setting. */ public static final String SSL_VERIFY_KEY = "sslVerify"; //$NON-NLS-1$ + /** + * git config key for the "cookieFile" setting. + * + * @since 5.4 + */ + public static final String COOKIE_FILE_KEY = "cookieFile"; //$NON-NLS-1$ + + /** + * git config key for the "saveCookies" setting. + * + * @since 5.4 + */ + public static final String SAVE_COOKIES_KEY = "saveCookies"; //$NON-NLS-1$ + + /** + * Custom JGit config key which holds the maximum number of cookie files to + * keep in the cache. + * + * @since 5.4 + */ + public static final String COOKIE_FILE_CACHE_LIMIT_KEY = "cookieFileCacheLimit"; //$NON-NLS-1$ + + private static final int DEFAULT_COOKIE_FILE_CACHE_LIMIT = 10; + private static final String MAX_REDIRECT_SYSTEM_PROPERTY = "http.maxRedirects"; //$NON-NLS-1$ private static final int DEFAULT_MAX_REDIRECTS = 5; @@ -153,6 +177,12 @@ public class HttpConfig { private int maxRedirects; + private String cookieFile; + + private boolean saveCookies; + + private int cookieFileCacheLimit; + /** * Get the "http.postBuffer" setting * @@ -189,6 +219,40 @@ public class HttpConfig { return maxRedirects; } + /** + * Get the "http.cookieFile" setting + * + * @return the value of the "http.cookieFile" setting + * + * @since 5.4 + */ + public String getCookieFile() { + return cookieFile; + } + + /** + * Get the "http.saveCookies" setting + * + * @return the value of the "http.saveCookies" setting + * + * @since 5.4 + */ + public boolean getSaveCookies() { + return saveCookies; + } + + /** + * Get the "http.cookieFileCacheLimit" setting (gives the maximum number of + * cookie files to keep in the LRU cache) + * + * @return the value of the "http.cookieFileCacheLimit" setting + * + * @since 5.4 + */ + public int getCookieFileCacheLimit() { + return cookieFileCacheLimit; + } + /** * Creates a new {@link org.eclipse.jgit.transport.HttpConfig} tailored to * the given {@link org.eclipse.jgit.transport.URIish}. @@ -237,6 +301,10 @@ public class HttpConfig { if (redirectLimit < 0) { redirectLimit = MAX_REDIRECTS; } + cookieFile = config.getString(HTTP, null, COOKIE_FILE_KEY); + saveCookies = config.getBoolean(HTTP, SAVE_COOKIES_KEY, false); + cookieFileCacheLimit = config.getInt(HTTP, COOKIE_FILE_CACHE_LIMIT_KEY, + DEFAULT_COOKIE_FILE_CACHE_LIMIT); String match = findMatch(config.getSubsections(HTTP), uri); if (match != null) { // Override with more specific items @@ -251,6 +319,13 @@ public class HttpConfig { if (newMaxRedirects >= 0) { redirectLimit = newMaxRedirects; } + String urlSpecificCookieFile = config.getString(HTTP, match, + COOKIE_FILE_KEY); + if (urlSpecificCookieFile != null) { + cookieFile = urlSpecificCookieFile; + } + saveCookies = config.getBoolean(HTTP, match, SAVE_COOKIES_KEY, + saveCookies); } postBuffer = postBufferSize; sslVerify = sslVerifyFlag; 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 42aa80ea4..f44a99b8b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -54,8 +54,11 @@ import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT; import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING; import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING; import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE; +import static org.eclipse.jgit.util.HttpSupport.HDR_COOKIE; import static org.eclipse.jgit.util.HttpSupport.HDR_LOCATION; import static org.eclipse.jgit.util.HttpSupport.HDR_PRAGMA; +import static org.eclipse.jgit.util.HttpSupport.HDR_SET_COOKIE; +import static org.eclipse.jgit.util.HttpSupport.HDR_SET_COOKIE2; import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT; import static org.eclipse.jgit.util.HttpSupport.HDR_WWW_AUTHENTICATE; import static org.eclipse.jgit.util.HttpSupport.METHOD_GET; @@ -68,11 +71,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.net.HttpCookie; import java.net.MalformedURLException; import java.net.Proxy; import java.net.ProxySelector; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateException; @@ -84,6 +91,8 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -100,6 +109,8 @@ import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.RefDirectory; +import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile; +import org.eclipse.jgit.internal.transport.http.NetscapeCookieFileCache; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; @@ -116,6 +127,7 @@ import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.HttpSupport; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.TemporaryBuffer; import org.eclipse.jgit.util.io.DisabledOutputStream; @@ -274,6 +286,19 @@ public class TransportHttp extends HttpTransport implements WalkTransport, private boolean sslFailure = false; + /** + * All stored cookies bound to this repo (independent of the baseUrl) + */ + private final NetscapeCookieFile cookieFile; + + /** + * The cookies to be sent with each request to the given {@link #baseUrl}. + * Filtered view on top of {@link #cookieFile} where only cookies which + * apply to the current url are left. This set needs to be filtered for + * expired entries each time prior to sending them. + */ + private final Set relevantCookies; + TransportHttp(Repository local, URIish uri) throws NotSupportedException { super(local, uri); @@ -281,6 +306,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport, http = new HttpConfig(local.getConfig(), uri); proxySelector = ProxySelector.getDefault(); sslVerify = http.isSslVerify(); + cookieFile = getCookieFileFromConfig(http); + relevantCookies = filterCookies(cookieFile, baseUrl); } private URL toURL(URIish urish) throws MalformedURLException { @@ -321,6 +348,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport, http = new HttpConfig(uri); proxySelector = ProxySelector.getDefault(); sslVerify = http.isSslVerify(); + cookieFile = getCookieFileFromConfig(http); + relevantCookies = filterCookies(cookieFile, baseUrl); } /** @@ -508,6 +537,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, conn.setRequestProperty(HDR_ACCEPT, "*/*"); //$NON-NLS-1$ } final int status = HttpSupport.response(conn); + processResponseCookies(conn); switch (status) { case HttpConnection.HTTP_OK: // Check if HttpConnection did some authentication in the @@ -596,6 +626,57 @@ public class TransportHttp extends HttpTransport implements WalkTransport, } } + void processResponseCookies(HttpConnection conn) { + if (cookieFile != null && http.getSaveCookies()) { + List foundCookies = new LinkedList<>(); + + List cookieHeaderValues = conn + .getHeaderFields(HDR_SET_COOKIE); + if (!cookieHeaderValues.isEmpty()) { + foundCookies.addAll( + extractCookies(HDR_SET_COOKIE, cookieHeaderValues)); + } + cookieHeaderValues = conn.getHeaderFields(HDR_SET_COOKIE2); + if (!cookieHeaderValues.isEmpty()) { + foundCookies.addAll( + extractCookies(HDR_SET_COOKIE2, cookieHeaderValues)); + } + if (foundCookies.size() > 0) { + try { + // update cookie lists with the newly received cookies! + Set cookies = cookieFile.getCookies(false); + cookies.addAll(foundCookies); + cookieFile.write(baseUrl); + relevantCookies.addAll(foundCookies); + } catch (IOException | IllegalArgumentException + | InterruptedException e) { + LOG.warn(MessageFormat.format( + JGitText.get().couldNotPersistCookies, + cookieFile.getPath()), e); + } + } + } + } + + private List extractCookies(String headerKey, + List headerValues) { + List foundCookies = new LinkedList<>(); + for (String headerValue : headerValues) { + foundCookies + .addAll(HttpCookie.parse(headerKey + ':' + headerValue)); + } + // HttpCookies.parse(...) is only compliant with RFC 2965. Make it RFC + // 6265 compliant by applying the logic from + // https://tools.ietf.org/html/rfc6265#section-5.2.3 + for (HttpCookie foundCookie : foundCookies) { + String domain = foundCookie.getDomain(); + if (domain != null && domain.startsWith(".")) { //$NON-NLS-1$ + foundCookie.setDomain(domain.substring(1)); + } + } + return foundCookies; + } + private static class CredentialItems { CredentialItem.InformationalMessage message; @@ -847,14 +928,35 @@ public class TransportHttp extends HttpTransport implements WalkTransport, conn.setConnectTimeout(effTimeOut); conn.setReadTimeout(effTimeOut); } + // set cookie header if necessary + if (relevantCookies.size() > 0) { + setCookieHeader(conn); + } + if (this.headers != null && !this.headers.isEmpty()) { - for (Map.Entry entry : this.headers.entrySet()) + for (Map.Entry entry : this.headers.entrySet()) { conn.setRequestProperty(entry.getKey(), entry.getValue()); + } } authMethod.configureRequest(conn); return conn; } + private void setCookieHeader(HttpConnection conn) { + StringBuilder cookieHeaderValue = new StringBuilder(); + for (HttpCookie cookie : relevantCookies) { + if (!cookie.hasExpired()) { + if (cookieHeaderValue.length() > 0) { + cookieHeaderValue.append(';'); + } + cookieHeaderValue.append(cookie.toString()); + } + } + if (cookieHeaderValue.length() >= 0) { + conn.setRequestProperty(HDR_COOKIE, cookieHeaderValue.toString()); + } + } + final InputStream openInputStream(HttpConnection conn) throws IOException { InputStream input = conn.getInputStream(); @@ -868,6 +970,150 @@ public class TransportHttp extends HttpTransport implements WalkTransport, return new TransportException(uri, why); } + private static NetscapeCookieFile getCookieFileFromConfig( + HttpConfig config) { + if (!StringUtils.isEmptyOrNull(config.getCookieFile())) { + try { + Path cookieFilePath = Paths.get(config.getCookieFile()); + return NetscapeCookieFileCache.getInstance(config) + .getEntry(cookieFilePath); + } catch (InvalidPathException e) { + LOG.warn(MessageFormat.format( + JGitText.get().couldNotReadCookieFile, + config.getCookieFile()), e); + } + } + return null; + } + + private static Set filterCookies(NetscapeCookieFile cookieFile, + URL url) { + if (cookieFile != null) { + return filterCookies(cookieFile.getCookies(true), url); + } + return Collections.emptySet(); + } + + /** + * + * @param allCookies + * a list of cookies. + * @param url + * the url for which to filter the list of cookies. + * @return only the cookies from {@code allCookies} which are relevant (i.e. + * are not expired, have a matching domain, have a matching path and + * have a matching secure attribute) + */ + private static Set filterCookies(Set allCookies, + URL url) { + Set filteredCookies = new HashSet<>(); + for (HttpCookie cookie : allCookies) { + if (cookie.hasExpired()) { + continue; + } + if (!matchesCookieDomain(url.getHost(), cookie.getDomain())) { + continue; + } + if (!matchesCookiePath(url.getPath(), cookie.getPath())) { + continue; + } + if (cookie.getSecure() && !"https".equals(url.getProtocol())) { //$NON-NLS-1$ + continue; + } + filteredCookies.add(cookie); + } + return filteredCookies; + } + + /** + * + * The utility method to check whether a host name is in a cookie's domain + * or not. Similar to {@link HttpCookie#domainMatches(String, String)} but + * implements domain matching rules according to + * RFC 6265, + * section 5.1.3 instead of the rules from + * RFC 2965, + * section 3.3.1. + *

+ * The former rules are also used by libcurl internally. + *

+ * The rules are as follows + * + * A string matches another domain string if at least one of the following + * conditions holds: + *

    + *
  • The domain string and the string are identical. (Note that both the + * domain string and the string will have been canonicalized to lower case + * at this point.)
  • + *
  • All of the following conditions hold + *
      + *
    • The domain string is a suffix of the string.
    • + *
    • The last character of the string that is not included in the domain + * string is a %x2E (".") character.
    • + *
    • The string is a host name (i.e., not an IP address).
    • + *
    + *
  • + *
+ * + * @param host + * the host to compare against the cookieDomain + * @param cookieDomain + * the domain to compare against + * @return {@code true} if they domain-match; {@code false} if not + * + * @see RFC + * 6265, section 5.1.3 (Domain Matching) + * @see JDK-8206092 + * : HttpCookie.domainMatches() does not match to sub-sub-domain + */ + static boolean matchesCookieDomain(String host, String cookieDomain) { + cookieDomain = cookieDomain.toLowerCase(Locale.ROOT); + host = host.toLowerCase(Locale.ROOT); + if (host.equals(cookieDomain)) { + return true; + } else { + if (!host.endsWith(cookieDomain)) { + return false; + } + return host + .charAt(host.length() - cookieDomain.length() - 1) == '.'; + } + } + + /** + * The utility method to check whether a path is matching a cookie path + * domain or not. The rules are defined by + * RFC 6265, + * section 5.1.4: + * + * A request-path path-matches a given cookie-path if at least one of the + * following conditions holds: + *
    + *
  • The cookie-path and the request-path are identical.
  • + *
  • The cookie-path is a prefix of the request-path, and the last + * character of the cookie-path is %x2F ("/").
  • + *
  • The cookie-path is a prefix of the request-path, and the first + * character of the request-path that is not included in the cookie- path is + * a %x2F ("/") character.
  • + *
+ * @param path + * the path to check + * @param cookiePath + * the cookie's path + * + * @return {@code true} if they path-match; {@code false} if not + */ + static boolean matchesCookiePath(String path, String cookiePath) { + if (cookiePath.equals(path)) { + return true; + } + if (!cookiePath.endsWith("/")) { //$NON-NLS-1$ + cookiePath += "/"; //$NON-NLS-1$ + } + return path.startsWith(cookiePath); + } + private boolean isSmartHttp(HttpConnection c, String service) { final String expType = "application/x-" + service + "-advertisement"; //$NON-NLS-1$ //$NON-NLS-2$ final String actType = c.getContentType(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java index 54e4ee01f..640670deb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java @@ -169,6 +169,27 @@ public class HttpSupport { /** The {@code WWW-Authenticate} header. */ public static final String HDR_WWW_AUTHENTICATE = "WWW-Authenticate"; //$NON-NLS-1$ + /** + * The {@code Cookie} header. + * + * @since 5.4 + */ + public static final String HDR_COOKIE = "Cookie"; //$NON-NLS-1$ + + /** + * The {@code Set-Cookie} header. + * + * @since 5.4 + */ + public static final String HDR_SET_COOKIE = "Set-Cookie"; //$NON-NLS-1$ + + /** + * The {@code Set-Cookie2} header. + * + * @since 5.4 + */ + public static final String HDR_SET_COOKIE2 = "Set-Cookie2"; //$NON-NLS-1$ + /** * URL encode a value string into an output buffer. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LRUMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LRUMap.java new file mode 100644 index 000000000..41c15363f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LRUMap.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.util; + +import java.util.LinkedHashMap; + +/** + * Map with only up to n entries. If a new entry is added so that the map + * contains more than those n entries the least-recently used entry is removed + * from the map. + * + * @param + * the type of keys maintained by this map + * @param + * the type of mapped values + * + * @since 5.4 + */ +public class LRUMap extends LinkedHashMap { + + private static final long serialVersionUID = 4329609127403759486L; + + private final int limit; + + /** + * Constructs an empty map which may contain at most the given amount of + * entries. + * + * @param initialCapacity + * the initial capacity + * @param limit + * the number of entries the map should have at most + */ + public LRUMap(int initialCapacity, int limit) { + super(initialCapacity, 0.75f, true); + this.limit = limit; + } + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + return size() > limit; + } +} From 1609ce75931b2caa4051b51a3e3e4d6fe242c2f9 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Sat, 18 May 2019 23:48:54 +0200 Subject: [PATCH 28/51] Determine hard-linking and nlink support per FileStore It's quite possible that JGit can use the hard-linking mechanism for atomic file creation on some volumes but not on others. Ultimately it depends on the file systems on the mounted volumes. Cache the information per FileStore instead of using a single global flag. Also catch FileSystemException, it may be thrown if the operating system reports a failure. The previously caught AccessDeniedException is a sub-class of FileSystemException. Bug: 547332 Change-Id: I1ef672b3468b0be79e71674344f16f28f9d11ba1 Signed-off-by: Thomas Wolf --- .../src/org/eclipse/jgit/util/FS_POSIX.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java index 716711e06..588855b1f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java @@ -48,7 +48,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.charset.Charset; -import java.nio.file.AccessDeniedException; +import java.nio.file.FileStore; +import java.nio.file.FileSystemException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -57,9 +58,11 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -84,7 +87,7 @@ public class FS_POSIX extends FS { private static final int DEFAULT_UMASK = 0022; private volatile int umask = -1; - private volatile boolean supportsUnixNLink = true; + private static final Map CAN_HARD_LINK = new ConcurrentHashMap<>(); private volatile AtomicFileCreation supportsAtomicCreateNewFile = AtomicFileCreation.UNDEFINED; @@ -388,12 +391,18 @@ public class FS_POSIX extends FS { if (!lock.createNewFile()) { return false; } - if (supportsAtomicCreateNewFile() || !supportsUnixNLink) { + if (supportsAtomicCreateNewFile()) { return true; } Path lockPath = lock.toPath(); Path link = null; + FileStore store = Files.getFileStore(lockPath); try { + Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store, + s -> Boolean.TRUE); + if (canLink == Boolean.FALSE) { + return true; + } link = Files.createLink( Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$ lockPath); @@ -405,11 +414,11 @@ public class FS_POSIX extends FS { nlink)); return false; } else if (nlink < 2) { - supportsUnixNLink = false; + CAN_HARD_LINK.put(store, Boolean.FALSE); } return true; } catch (UnsupportedOperationException | IllegalArgumentException e) { - supportsUnixNLink = false; + CAN_HARD_LINK.put(store, Boolean.FALSE); return true; } finally { if (link != null) { @@ -448,12 +457,18 @@ public class FS_POSIX extends FS { if (!file.createNewFile()) { return token(false, null); } - if (supportsAtomicCreateNewFile() || !supportsUnixNLink) { + if (supportsAtomicCreateNewFile()) { return token(true, null); } Path link = null; Path path = file.toPath(); + FileStore store = Files.getFileStore(path); try { + Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store, + s -> Boolean.TRUE); + if (canLink == Boolean.FALSE) { + return token(true, null); + } link = Files.createLink(Paths.get(uniqueLinkPath(file)), path); Integer nlink = (Integer) (Files.getAttribute(path, "unix:nlink")); //$NON-NLS-1$ @@ -462,12 +477,12 @@ public class FS_POSIX extends FS { JGitText.get().failedAtomicFileCreation, path, nlink)); return token(false, link); } else if (nlink.intValue() < 2) { - supportsUnixNLink = false; + CAN_HARD_LINK.put(store, Boolean.FALSE); } return token(true, link); } catch (UnsupportedOperationException | IllegalArgumentException - | AccessDeniedException | SecurityException e) { - supportsUnixNLink = false; + | FileSystemException | SecurityException e) { + CAN_HARD_LINK.put(store, Boolean.FALSE); return token(true, link); } } From 9f6965674828526ce4ee1cfa9ca68309e85b7353 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 7 Jun 2019 10:22:13 +0900 Subject: [PATCH 29/51] Bazel: Add missing dependency on mockito for TransportHttpTest Change-Id: I54eff21c7aa8ee4b3b4a2fea60c5bca359256808 Signed-off-by: David Pursehouse --- org.eclipse.jgit.test/tests.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl index 6b5c7a1df..3665c2499 100644 --- a/org.eclipse.jgit.test/tests.bzl +++ b/org.eclipse.jgit.test/tests.bzl @@ -53,6 +53,10 @@ def tests(tests): additional_deps = [ "//lib:mockito", ] + if src.endswith("TransportHttpTest.java"): + additional_deps = [ + "//lib:mockito", + ] heap_size = "-Xmx256m" if src.endswith("HugeCommitMessageTest.java"): heap_size = "-Xmx512m" From 6518d63317a8fda856a801cef71db9de1b1052fb Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 7 Jun 2019 10:51:21 +0900 Subject: [PATCH 30/51] NetscapeCookieFileTest: Split HttpCookiesMatcher to own class The bazel build fails due to NetscapeCookieFileTest's internal class not being visible to TransportHttpTest. Split the file out to its own class in the util package, so it's visible to both. Change-Id: I69236026eecb9d08a9a66e51752a80ea522b0c6a Signed-off-by: David Pursehouse --- org.eclipse.jgit.test/BUILD | 1 + .../http/NetscapeCookieFileTest.java | 104 +----------- .../jgit/transport/TransportHttpTest.java | 2 +- .../jgit/util/http/HttpCookiesMatcher.java | 150 ++++++++++++++++++ 4 files changed, 153 insertions(+), 104 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/util/http/HttpCookiesMatcher.java diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index be4fdbdea..5c0540fb9 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD @@ -28,6 +28,7 @@ HELPERS = glob( "treewalk/filter/AlwaysCloneTreeFilter.java", "test/resources/SampleDataRepositoryTestCase.java", "util/CPUTimeStopWatch.java", + "util/http/HttpCookiesMatcher.java", "util/io/Strings.java", ]] diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java index 8f6cd3aae..0a3f89e23 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileTest.java @@ -55,18 +55,14 @@ import java.time.Instant; import java.util.Arrays; import java.util.Date; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import org.eclipse.jgit.internal.storage.file.LockFile; import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile; +import org.eclipse.jgit.util.http.HttpCookiesMatcher; import org.hamcrest.CoreMatchers; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.hamcrest.collection.IsIterableContainingInOrder; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -340,102 +336,4 @@ public class NetscapeCookieFileTest { new NetscapeCookieFile(tmpFile) .getCookies(true); } - - public final static class HttpCookiesMatcher { - public static Matcher> containsInOrder( - Iterable expectedCookies) { - return containsInOrder(expectedCookies, 0); - } - - public static Matcher> containsInOrder( - Iterable expectedCookies, int allowedMaxAgeDelta) { - final List> cookieMatchers = new LinkedList<>(); - for (HttpCookie cookie : expectedCookies) { - cookieMatchers - .add(new HttpCookieMatcher(cookie, allowedMaxAgeDelta)); - } - return new IsIterableContainingInOrder<>(cookieMatchers); - } - } - - /** - * The default {@link HttpCookie#equals(Object)} is not good enough for - * testing purposes. Also the {@link HttpCookie#toString()} only emits some - * of the cookie attributes. For testing a dedicated matcher is needed which - * takes into account all attributes. - */ - private final static class HttpCookieMatcher - extends TypeSafeMatcher { - - private final HttpCookie cookie; - - private final int allowedMaxAgeDelta; - - public HttpCookieMatcher(HttpCookie cookie, int allowedMaxAgeDelta) { - this.cookie = cookie; - this.allowedMaxAgeDelta = allowedMaxAgeDelta; - } - - @Override - public void describeTo(Description description) { - describeCookie(description, cookie); - } - - @Override - protected void describeMismatchSafely(HttpCookie item, - Description mismatchDescription) { - mismatchDescription.appendText("was "); - describeCookie(mismatchDescription, item); - } - - @Override - protected boolean matchesSafely(HttpCookie otherCookie) { - // the equals method in HttpCookie is not specific enough, we want - // to consider all attributes! - return (equals(cookie.getName(), otherCookie.getName()) - && equals(cookie.getValue(), otherCookie.getValue()) - && equals(cookie.getDomain(), otherCookie.getDomain()) - && equals(cookie.getPath(), otherCookie.getPath()) - && (cookie.getMaxAge() >= otherCookie.getMaxAge() - - allowedMaxAgeDelta) - && (cookie.getMaxAge() <= otherCookie.getMaxAge() - + allowedMaxAgeDelta) - && cookie.isHttpOnly() == otherCookie.isHttpOnly() - && cookie.getSecure() == otherCookie.getSecure() - && cookie.getVersion() == otherCookie.getVersion()); - } - - private static boolean equals(String value1, String value2) { - if (value1 == null && value2 == null) { - return true; - } - if (value1 == null || value2 == null) { - return false; - } - return value1.equals(value2); - } - - @SuppressWarnings("boxing") - protected static void describeCookie(Description description, - HttpCookie cookie) { - description.appendText("HttpCookie["); - description.appendText("name: ").appendValue(cookie.getName()) - .appendText(", "); - description.appendText("value: ").appendValue(cookie.getValue()) - .appendText(", "); - description.appendText("domain: ").appendValue(cookie.getDomain()) - .appendText(", "); - description.appendText("path: ").appendValue(cookie.getPath()) - .appendText(", "); - description.appendText("maxAge: ").appendValue(cookie.getMaxAge()) - .appendText(", "); - description.appendText("httpOnly: ") - .appendValue(cookie.isHttpOnly()).appendText(", "); - description.appendText("secure: ").appendValue(cookie.getSecure()) - .appendText(", "); - description.appendText("version: ").appendValue(cookie.getVersion()) - .appendText(", "); - description.appendText("]"); - } - } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java index 111c92523..ee0e0af8c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java @@ -53,10 +53,10 @@ import java.util.LinkedHashSet; import java.util.Set; import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile; -import org.eclipse.jgit.internal.transport.http.NetscapeCookieFileTest.HttpCookiesMatcher; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.eclipse.jgit.transport.http.HttpConnection; +import org.eclipse.jgit.util.http.HttpCookiesMatcher; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/http/HttpCookiesMatcher.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/http/HttpCookiesMatcher.java new file mode 100644 index 000000000..8c5b127de --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/http/HttpCookiesMatcher.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018, Konrad Windszus + * 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.util.http; + +import java.net.HttpCookie; +import java.util.LinkedList; +import java.util.List; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.hamcrest.collection.IsIterableContainingInOrder; + +public final class HttpCookiesMatcher { + public static Matcher> containsInOrder( + Iterable expectedCookies) { + return containsInOrder(expectedCookies, 0); + } + + public static Matcher> containsInOrder( + Iterable expectedCookies, int allowedMaxAgeDelta) { + final List> cookieMatchers = new LinkedList<>(); + for (HttpCookie cookie : expectedCookies) { + cookieMatchers + .add(new HttpCookieMatcher(cookie, allowedMaxAgeDelta)); + } + return new IsIterableContainingInOrder<>(cookieMatchers); + } + + /** + * The default {@link HttpCookie#equals(Object)} is not good enough for + * testing purposes. Also the {@link HttpCookie#toString()} only emits some + * of the cookie attributes. For testing a dedicated matcher is needed which + * takes into account all attributes. + */ + private static final class HttpCookieMatcher + extends TypeSafeMatcher { + + private final HttpCookie cookie; + + private final int allowedMaxAgeDelta; + + public HttpCookieMatcher(HttpCookie cookie, int allowedMaxAgeDelta) { + this.cookie = cookie; + this.allowedMaxAgeDelta = allowedMaxAgeDelta; + } + + @Override + public void describeTo(Description description) { + describeCookie(description, cookie); + } + + @Override + protected void describeMismatchSafely(HttpCookie item, + Description mismatchDescription) { + mismatchDescription.appendText("was "); + describeCookie(mismatchDescription, item); + } + + @Override + protected boolean matchesSafely(HttpCookie otherCookie) { + // the equals method in HttpCookie is not specific enough, we want + // to consider all attributes! + return (equals(cookie.getName(), otherCookie.getName()) + && equals(cookie.getValue(), otherCookie.getValue()) + && equals(cookie.getDomain(), otherCookie.getDomain()) + && equals(cookie.getPath(), otherCookie.getPath()) + && (cookie.getMaxAge() >= otherCookie.getMaxAge() + - allowedMaxAgeDelta) + && (cookie.getMaxAge() <= otherCookie.getMaxAge() + + allowedMaxAgeDelta) + && cookie.isHttpOnly() == otherCookie.isHttpOnly() + && cookie.getSecure() == otherCookie.getSecure() + && cookie.getVersion() == otherCookie.getVersion()); + } + + private static boolean equals(String value1, String value2) { + if (value1 == null && value2 == null) { + return true; + } + if (value1 == null || value2 == null) { + return false; + } + return value1.equals(value2); + } + + @SuppressWarnings("boxing") + protected static void describeCookie(Description description, + HttpCookie cookie) { + description.appendText("HttpCookie["); + description.appendText("name: ").appendValue(cookie.getName()) + .appendText(", "); + description.appendText("value: ").appendValue(cookie.getValue()) + .appendText(", "); + description.appendText("domain: ").appendValue(cookie.getDomain()) + .appendText(", "); + description.appendText("path: ").appendValue(cookie.getPath()) + .appendText(", "); + description.appendText("maxAge: ").appendValue(cookie.getMaxAge()) + .appendText(", "); + description.appendText("httpOnly: ") + .appendValue(cookie.isHttpOnly()).appendText(", "); + description.appendText("secure: ").appendValue(cookie.getSecure()) + .appendText(", "); + description.appendText("version: ").appendValue(cookie.getVersion()) + .appendText(", "); + description.appendText("]"); + } + } +} \ No newline at end of file From 9dc1ddf324c0f5ff37cd3ff47c8b16595012004b Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 7 Jun 2019 10:57:15 +0900 Subject: [PATCH 31/51] TransportHttp: Fix comparison of size with ">= 0" Error Prone reports: [SizeGreaterThanOrEqualsZero] Comparison of a size >= 0 is always true, did you intend to check for non-emptiness? see https://errorprone.info/bugpattern/SizeGreaterThanOrEqualsZero Change-Id: Ie964771cacca4b15569eb45f6e273ad2a7e2e49c Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/transport/TransportHttp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f44a99b8b..88349a7ee 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -952,7 +952,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, cookieHeaderValue.append(cookie.toString()); } } - if (cookieHeaderValue.length() >= 0) { + if (cookieHeaderValue.length() > 0) { conn.setRequestProperty(HDR_COOKIE, cookieHeaderValue.toString()); } } From b5a1b770a05848983688b81b5318f6ce15ead68d Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 7 Jun 2019 10:59:46 +0900 Subject: [PATCH 32/51] TransportHttp: Check for non-empty list with "!isEmpty()" rather than "size() > 0" Change-Id: Iabb627c8f584346eb8ace3c24afb63b4d1ad3d47 Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/transport/TransportHttp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 88349a7ee..27ab87951 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -641,7 +641,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, foundCookies.addAll( extractCookies(HDR_SET_COOKIE2, cookieHeaderValues)); } - if (foundCookies.size() > 0) { + if (!foundCookies.isEmpty()) { try { // update cookie lists with the newly received cookies! Set cookies = cookieFile.getCookies(false); @@ -929,7 +929,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, conn.setReadTimeout(effTimeOut); } // set cookie header if necessary - if (relevantCookies.size() > 0) { + if (!relevantCookies.isEmpty()) { setCookieHeader(conn); } From 00f840dcd1fc53b3face0d824af0eb9de9d19f08 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 7 Jun 2019 12:12:44 +0900 Subject: [PATCH 33/51] Consistently use "!isEmpty()" to detect non-empty list Replace "size() > 0" with "!isEmpty()" where appropriate. In the Status implementation we can drop the check; the subsequent loop will only execute when the list is non-empty anyway. Change-Id: I355aff551a603373e702a9d44304f087b476263c Signed-off-by: David Pursehouse --- .../org/eclipse/jgit/lfs/server/TransferHandler.java | 4 ++-- .../src/org/eclipse/jgit/pgm/Checkout.java | 2 +- .../src/org/eclipse/jgit/pgm/LsFiles.java | 2 +- .../src/org/eclipse/jgit/pgm/LsTree.java | 2 +- .../src/org/eclipse/jgit/pgm/Reset.java | 2 +- .../src/org/eclipse/jgit/pgm/Status.java | 2 +- .../tst/org/eclipse/jgit/api/CleanCommandTest.java | 10 +++++----- .../src/org/eclipse/jgit/api/LogCommand.java | 2 +- .../src/org/eclipse/jgit/api/RebaseCommand.java | 4 ++-- .../src/org/eclipse/jgit/merge/ResolveMerger.java | 2 +- .../src/org/eclipse/jgit/transport/BundleWriter.java | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java index 4fea92e11..6c36661c3 100644 --- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java @@ -84,7 +84,7 @@ abstract class TransferHandler { @Override Body process() throws IOException { Response.Body body = new Response.Body(); - if (objects.size() > 0) { + if (!objects.isEmpty()) { body.objects = new ArrayList<>(); for (LfsObject o : objects) { addObjectInfo(body, o); @@ -122,7 +122,7 @@ abstract class TransferHandler { @Override Body process() throws IOException { Response.Body body = new Response.Body(); - if (objects.size() > 0) { + if (!objects.isEmpty()) { body.objects = new ArrayList<>(); for (LfsObject o : objects) { addObjectInfo(body, o); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java index 7e1737f87..3df37e51c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java @@ -96,7 +96,7 @@ class Checkout extends TextBuiltin { try (Git git = new Git(db)) { CheckoutCommand command = git.checkout() .setProgressMonitor(new TextProgressMonitor(errw)); - if (paths.size() > 0) { + if (!paths.isEmpty()) { command.setStartPoint(name); if (paths.size() == 1 && paths.get(0).equals(".")) { //$NON-NLS-1$ command.setAllPaths(true); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java index ef2584497..e3ed30dc4 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java @@ -85,7 +85,7 @@ class LsFiles extends TextBuiltin { CanonicalTreeParser p = new CanonicalTreeParser(); p.reset(rw.getObjectReader(), c.getTree()); tw.reset(); // drop the first empty tree, which we do not need here - if (paths.size() > 0) { + if (!paths.isEmpty()) { tw.setFilter(PathFilterGroup.createFromStrings(paths)); } tw.addTree(p); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java index 2a2bb7cc9..19f2d7ae4 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java @@ -76,7 +76,7 @@ class LsTree extends TextBuiltin { protected void run() { try (TreeWalk walk = new TreeWalk(db)) { walk.reset(); // drop the first empty tree, which we do not need here - if (paths.size() > 0) { + if (!paths.isEmpty()) { walk.setFilter(PathFilterGroup.createFromStrings(paths)); } walk.setRecursive(recursive); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java index b3e81c6d6..e1a290731 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java @@ -80,7 +80,7 @@ class Reset extends TextBuiltin { try (Git git = new Git(db)) { ResetCommand command = git.reset(); command.setRef(commit); - if (paths.size() > 0) { + if (!paths.isEmpty()) { for (String path : paths) { command.addPath(path); } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java index 8b187587b..c3887fe9c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java @@ -93,7 +93,7 @@ class Status extends TextBuiltin { protected void run() { try (Git git = new Git(db)) { StatusCommand statusCommand = git.status(); - if (filterPaths != null && filterPaths.size() > 0) { + if (filterPaths != null) { for (String path : filterPaths) { statusCommand.addPath(path); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java index 4eeaf4d6e..c9852e8b8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java @@ -98,7 +98,7 @@ public class CleanCommandTest extends RepositoryTestCase { StatusCommand command = git.status(); Status status = command.call(); Set files = status.getUntracked(); - assertTrue(files.size() > 0); + assertFalse(files.isEmpty()); // run clean Set cleanedFiles = git.clean().call(); @@ -120,7 +120,7 @@ public class CleanCommandTest extends RepositoryTestCase { StatusCommand command = git.status(); Status status = command.call(); Set files = status.getUntracked(); - assertTrue(files.size() > 0); + assertFalse(files.isEmpty()); // run clean Set cleanedFiles = git.clean().setCleanDirectories(true).call(); @@ -143,7 +143,7 @@ public class CleanCommandTest extends RepositoryTestCase { StatusCommand command = git.status(); Status status = command.call(); Set files = status.getUntracked(); - assertTrue(files.size() > 0); + assertFalse(files.isEmpty()); // run clean with setPaths Set paths = new TreeSet<>(); @@ -164,7 +164,7 @@ public class CleanCommandTest extends RepositoryTestCase { StatusCommand command = git.status(); Status status = command.call(); Set files = status.getUntracked(); - assertTrue(files.size() > 0); + assertFalse(files.isEmpty()); // run clean Set cleanedFiles = git.clean().setDryRun(true).call(); @@ -186,7 +186,7 @@ public class CleanCommandTest extends RepositoryTestCase { StatusCommand command = git.status(); Status status = command.call(); Set files = status.getUntracked(); - assertTrue(files.size() > 0); + assertFalse(files.isEmpty()); // run clean Set cleanedFiles = git.clean().setDryRun(true) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java index 9b8016ce2..66de8ae13 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java @@ -133,7 +133,7 @@ public class LogCommand extends GitCommand> { @Override public Iterable call() throws GitAPIException, NoHeadException { checkCallable(); - if (pathFilters.size() > 0) + if (!pathFilters.isEmpty()) walk.setTreeFilter(AndTreeFilter.create( PathFilterGroup.create(pathFilters), TreeFilter.ANY_DIFF)); if (skip > -1 && maxCount > -1) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index cdd1b80bb..593874c12 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -490,7 +490,7 @@ public class RebaseCommand extends GitCommand { resetSoftToParent(); List steps = repo.readRebaseTodo( rebaseState.getPath(GIT_REBASE_TODO), false); - RebaseTodoLine nextStep = steps.size() > 0 ? steps.get(0) : null; + RebaseTodoLine nextStep = steps.isEmpty() ? null : steps.get(0); File messageFixupFile = rebaseState.getFile(MESSAGE_FIXUP); File messageSquashFile = rebaseState.getFile(MESSAGE_SQUASH); if (isSquash && messageFixupFile.exists()) @@ -1083,7 +1083,7 @@ public class RebaseCommand extends GitCommand { repo.writeRebaseTodoFile(rebaseState.getPath(GIT_REBASE_TODO), todoLines, false); - if (poppedLines.size() > 0) { + if (!poppedLines.isEmpty()) { repo.writeRebaseTodoFile(rebaseState.getPath(DONE), poppedLines, true); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index b69327a9b..0c3d3fec2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -1190,7 +1190,7 @@ public class ResolveMerger extends ThreeWayMerger { * otherwise */ public boolean failed() { - return failingPaths.size() > 0; + return !failingPaths.isEmpty(); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java index a09b1ff1d..d1db51eca 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java @@ -227,7 +227,7 @@ public class BundleWriter { exc.add(r.getId()); packWriter.setIndexDisabled(true); packWriter.setDeltaBaseAsOffset(true); - packWriter.setThin(exc.size() > 0); + packWriter.setThin(!exc.isEmpty()); packWriter.setReuseValidatingObjects(false); if (exc.isEmpty()) { packWriter.setTagTargets(tagTargets); From d2600693bd5fb8bda20bae41467132668caa1e14 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Sun, 21 Apr 2019 21:23:30 +0200 Subject: [PATCH 34/51] Fix off-by-one error in RebaseTodoFile when reading a todo file Commit messages of length 1 were not read. 'lineEnd' is the offset of the last character in the line before the terminating LF or CR-LF, and 'nextSpace' is actually the offset of the character _after_ the next space. With a one-character commit message, nextSpace == lineEnd. The code also assumes the commit message to be optional, but actually failed in that case because it read beyond the line ending. Fix that, too. Add a test case for reading a todo file. Bug: 546245 Change-Id: I368d63615930ea2398a6230e756442fd88870654 Signed-off-by: Thomas Wolf --- .../eclipse/jgit/lib/RebaseTodoFileTest.java | 142 ++++++++++++++++++ .../org/eclipse/jgit/lib/RebaseTodoFile.java | 12 +- 2 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java new file mode 100644 index 000000000..5cfc75ca9 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RebaseTodoFileTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2019, Thomas Wolf + * 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.lib; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.junit.Test; + +public class RebaseTodoFileTest extends RepositoryTestCase { + + private static final String TEST_TODO = "test.todo"; + + private void createTodoList(String... lines) throws IOException { + Path p = Paths.get(db.getDirectory().getAbsolutePath(), TEST_TODO); + Files.write(p, Arrays.asList(lines)); + } + + @Test + public void testReadTodoFile() throws Exception { + String[] expected = { "reword " + ObjectId.zeroId().name() + " Foo", + "# A comment in the the todo list", + "pick " + ObjectId.zeroId().name() + " Foo fie", + "squash " + ObjectId.zeroId().name() + " F", + "fixup " + ObjectId.zeroId().name(), + "edit " + ObjectId.zeroId().name() + " f", + "edit " + ObjectId.zeroId().name() + ' ' }; + createTodoList(expected); + RebaseTodoFile todo = new RebaseTodoFile(db); + List lines = todo.readRebaseTodo(TEST_TODO, true); + assertEquals("Expected 7 lines", 7, lines.size()); + int i = 0; + for (RebaseTodoLine line : lines) { + switch (i) { + case 0: + assertEquals("Expected REWORD", RebaseTodoLine.Action.REWORD, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "Foo", + line.getShortMessage()); + break; + case 1: + assertEquals("Expected COMMENT", RebaseTodoLine.Action.COMMENT, + line.getAction()); + assertEquals("Unexpected Message", + "# A comment in the the todo list", + line.getComment()); + break; + case 2: + assertEquals("Expected PICK", RebaseTodoLine.Action.PICK, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "Foo fie", + line.getShortMessage()); + break; + case 3: + assertEquals("Expected SQUASH", RebaseTodoLine.Action.SQUASH, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "F", line.getShortMessage()); + break; + case 4: + assertEquals("Expected FIXUP", RebaseTodoLine.Action.FIXUP, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "", line.getShortMessage()); + break; + case 5: + assertEquals("Expected EDIT", RebaseTodoLine.Action.EDIT, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "f", line.getShortMessage()); + break; + case 6: + assertEquals("Expected EDIT", RebaseTodoLine.Action.EDIT, + line.getAction()); + assertEquals("Unexpected ID", ObjectId.zeroId().abbreviate(40), + line.getCommit()); + assertEquals("Unexpected Message", "", line.getShortMessage()); + break; + default: + fail("Too many lines"); + return; + } + i++; + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java index 06b4b227c..c0fcd4161 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java @@ -179,7 +179,7 @@ public class RebaseTodoFile { int nextSpace = RawParseUtils.next(buf, tokenBegin, ' '); int tokenCount = 0; - while (tokenCount < 3 && nextSpace < lineEnd) { + while (tokenCount < 3 && nextSpace <= lineEnd) { switch (tokenCount) { case 0: String actionToken = new String(buf, tokenBegin, @@ -191,8 +191,14 @@ public class RebaseTodoFile { break; case 1: nextSpace = RawParseUtils.next(buf, tokenBegin, ' '); - String commitToken = new String(buf, tokenBegin, - nextSpace - tokenBegin - 1, UTF_8); + String commitToken; + if (nextSpace > lineEnd + 1) { + commitToken = new String(buf, tokenBegin, + lineEnd - tokenBegin + 1, UTF_8); + } else { + commitToken = new String(buf, tokenBegin, + nextSpace - tokenBegin - 1, UTF_8); + } tokenBegin = nextSpace; commit = AbbreviatedObjectId.fromString(commitToken); break; From 10ab407fa6414a1c4ae08696c78e078cce078519 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Tue, 30 Apr 2019 19:11:16 +0200 Subject: [PATCH 35/51] DescribeCommand: use glob match instead of path match Otherwise tags may fail to match if their name contains slashes. Canonical git also uses its wildcard matcher in glob mode.[1] [1] https://github.com/git/git/blob/v2.21.0/builtin/describe.c#L182 Bug: 546703 Change-Id: I122c7959974fa1fc6a53dfc65837e4314a8badd4 Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/DescribeCommandTest.java | 17 +++++++++++++++++ .../org/eclipse/jgit/api/DescribeCommand.java | 17 +++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index fd3aa2884..df9ae6a0f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java @@ -421,6 +421,23 @@ public class DescribeCommandTest extends RepositoryTestCase { } } + @Test + public void globMatchWithSlashes() throws Exception { + ObjectId c1 = modify("aaa"); + tag("a/b/version"); + ObjectId c2 = modify("bbb"); + tag("a/b/version2"); + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("a/b/version", describe(c1, "*/version*")); + assertEquals("a/b/version2", describe(c2, "*/version*")); + } else { + assertNull(describe(c1)); + assertNull(describe(c1, "*/version*")); + assertNull(describe(c2)); + assertNull(describe(c2, "*/version*")); + } + } + private ObjectId merge(ObjectId c2) throws GitAPIException { return git.merge().include(c2).call().getNewHead(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index db3a3d947..9ad77e65f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -63,8 +63,7 @@ import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.InvalidPatternException; import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.ignore.internal.IMatcher; -import org.eclipse.jgit.ignore.internal.PathMatcher; +import org.eclipse.jgit.fnmatch.FileNameMatcher; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -104,7 +103,7 @@ public class DescribeCommand extends GitCommand { /** * Pattern matchers to be applied to tags under consideration. */ - private List matchers = new ArrayList<>(); + private List matchers = new ArrayList<>(); /** * Whether to use all tags (incl. lightweight) or not. @@ -242,7 +241,7 @@ public class DescribeCommand extends GitCommand { */ public DescribeCommand setMatch(String... patterns) throws InvalidPatternException { for (String p : patterns) { - matchers.add(PathMatcher.createPathMatcher(p, null, false)); + matchers.add(new FileNameMatcher(p, null)); } return this; } @@ -275,9 +274,15 @@ public class DescribeCommand extends GitCommand { // Find the first tag that matches in the stream of all tags // filtered by matchers ordered by tie break order Stream matchingTags = Stream.empty(); - for (IMatcher matcher : matchers) { + for (FileNameMatcher matcher : matchers) { Stream m = tags.stream().filter( - tag -> matcher.matches(tag.getName(), false, false)); + tag -> { + matcher.append( + tag.getName().substring(R_TAGS.length())); + boolean result = matcher.isMatch(); + matcher.reset(); + return result; + }); matchingTags = Stream.of(matchingTags, m).flatMap(i -> i); } return matchingTags.sorted(TAG_TIE_BREAKER).findFirst(); From f24ad3da66a0ea86f5674fac9442d3b4e4c78aa2 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Fri, 5 Apr 2019 21:33:14 +0200 Subject: [PATCH 36/51] Handle escaped CR-LF in git config files Canonical git treats CR-LF in config files as LF.[1][2] JGit does so, too, except when escaped as a line continuation. Correct this and treat the sequence \-CR-LF as a line continuation. [1] https://github.com/git/git/commit/db2c075d9 [2] https://github.com/git/git/blob/v2.21.0/config.c#L485 Bug: 545850 Change-Id: I51e7378a22c21b3baa3701163c423d04c900af5a Signed-off-by: Thomas Wolf Signed-off-by: Matthias Sohn --- .../tst/org/eclipse/jgit/lib/ConfigTest.java | 35 +++++++++++++++++++ .../src/org/eclipse/jgit/lib/Config.java | 23 ++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java index 5a4bd886a..e3985cc97 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java @@ -1457,6 +1457,41 @@ public class ConfigTest { parse("[foo \"bar\" ]\nfoo=bar\n"); } + @Test + public void testCrLf() throws ConfigInvalidException { + assertEquals("true", parseEscapedValue("true\r\n")); + } + + @Test + public void testLfContinuation() throws ConfigInvalidException { + assertEquals("true", parseEscapedValue("tr\\\nue")); + } + + @Test + public void testCrCharContinuation() throws ConfigInvalidException { + expectedEx.expect(ConfigInvalidException.class); + expectedEx.expectMessage("Bad escape: \\u000d"); + parseEscapedValue("tr\\\rue"); + } + + @Test + public void testCrEOFContinuation() throws ConfigInvalidException { + expectedEx.expect(ConfigInvalidException.class); + expectedEx.expectMessage("Bad escape: \\u000d"); + parseEscapedValue("tr\\\r"); + } + + @Test + public void testCrLfContinuation() throws ConfigInvalidException { + assertEquals("true", parseEscapedValue("tr\\\r\nue")); + } + + @Test + public void testWhitespaceContinuation() throws ConfigInvalidException { + assertEquals("tr ue", parseEscapedValue("tr \\\n ue")); + assertEquals("tr ue", parseEscapedValue("tr \\\r\n ue")); + } + private static void assertValueRoundTrip(String value) throws ConfigInvalidException { assertValueRoundTrip(value, value); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 4726975d0..2c01d6038 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -1413,11 +1413,23 @@ public class Config { case '"': value.append('"'); continue; + case '\r': { + int next = in.read(); + if (next == '\n') { + continue; // CR-LF + } else if (next >= 0) { + in.reset(); + } + break; + } default: - throw new ConfigInvalidException(MessageFormat.format( - JGitText.get().badEscape, - Character.valueOf(((char) c)))); + break; } + throw new ConfigInvalidException( + MessageFormat.format(JGitText.get().badEscape, + Character.isAlphabetic(c) + ? Character.valueOf(((char) c)) + : toUnicodeLiteral(c))); } if ('"' == c) { @@ -1430,6 +1442,11 @@ public class Config { return value.length() > 0 ? value.toString() : null; } + private static String toUnicodeLiteral(int c) { + return String.format("\\u%04x", //$NON-NLS-1$ + Integer.valueOf(c)); + } + /** * Parses a section of the configuration into an application model object. *

From 786380bd5e06719ce86990824760d4408e1ae565 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 9 Jun 2019 09:49:07 +0200 Subject: [PATCH 37/51] Warn if configured cookie file is missing We logged a stack trace if the configured http.cookieFile was missing. Instead only log a warning. Bug: 548081 Change-Id: I42e39f5ad8ffce7b43162e5068f60af073b8a126 Signed-off-by: Matthias Sohn --- .../resources/org/eclipse/jgit/internal/JGitText.properties | 1 + org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java | 1 + .../jgit/internal/transport/http/NetscapeCookieFile.java | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 88fdc3d81..afa876174 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -459,6 +459,7 @@ mismatchOffset=mismatch offset for object {0} mismatchCRC=mismatch CRC for object {0} missingAccesskey=Missing accesskey. missingConfigurationForKey=No value for key {0} found in configuration +missingCookieFile=Configured http.cookieFile ''{0}'' is missing missingCRC=missing CRC for object {0} missingDeltaBase=delta base missingForwardImageInGITBinaryPatch=Missing forward-image in GIT binary patch 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 88b3fc850..4d0d05156 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -520,6 +520,7 @@ public class JGitText extends TranslationBundle { /***/ public String mismatchCRC; /***/ public String missingAccesskey; /***/ public String missingConfigurationForKey; + /***/ public String missingCookieFile; /***/ public String missingCRC; /***/ public String missingDeltaBase; /***/ public String missingForwardImageInGITBinaryPatch; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java index 93be5c69e..075f55c73 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFile.java @@ -344,6 +344,11 @@ public final class NetscapeCookieFile { final int maxStaleRetries = 5; int retries = 0; File file = getPath().toFile(); + if (!file.exists()) { + LOG.warn(MessageFormat.format(JGitText.get().missingCookieFile, + file.getAbsolutePath())); + return new byte[0]; + } while (true) { final FileSnapshot oldSnapshot = snapshot; final FileSnapshot newSnapshot = FileSnapshot.save(file); From 8a2e221096f38ef0ab3d2e75d8ac81ad189695b0 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Mon, 4 Mar 2019 00:07:40 +0100 Subject: [PATCH 38/51] Make pull --rebase on an unborn branch do a checkout A merging pull on an unborn branch was already supported. But a rebasing pull failed. If the user has pull.rebase = true in his user config, the pull would try to rebase. Rebasing needs a parent commit, though. Native git handles this case: git init git remote add origin git pull --rebase origin master Check up front in PullCommand for the unborn head and just do a checkout in this case. MergeCommand already has similar code. Bug: 544965 Change-Id: I1277e1ac0b0364b4623fd791f3d6b07bd5f58fca Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/CloneCommandTest.java | 28 ++++++++++++ .../src/org/eclipse/jgit/api/PullCommand.java | 45 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 1523b49ec..74d13883e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -718,6 +718,34 @@ public class CloneCommandTest extends RepositoryTestCase { } + @Test + public void testCloneWithPullMerge() throws Exception { + File directory = createTempDirectory("testCloneRepository1"); + try (Git g = Git.init().setDirectory(directory).setBare(false).call()) { + g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME) + .setUri(new URIish(fileUri())).call(); + PullResult result = g.pull().setRebase(false).call(); + assertTrue(result.isSuccessful()); + assertEquals("refs/heads/master", + g.getRepository().getFullBranch()); + checkFile(new File(directory, "Test.txt"), "Hello world"); + } + } + + @Test + public void testCloneWithPullRebase() throws Exception { + File directory = createTempDirectory("testCloneRepository1"); + try (Git g = Git.init().setDirectory(directory).setBare(false).call()) { + g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME) + .setUri(new URIish(fileUri())).call(); + PullResult result = g.pull().setRebase(true).call(); + assertTrue(result.isSuccessful()); + assertEquals("refs/heads/master", + g.getRepository().getFullBranch()); + checkFile(new File(directory, "Test.txt"), "Hello world"); + } + } + private String fileUri() { return "file://" + git.getRepository().getWorkTree().getAbsolutePath(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java index f0ad29db4..bdb2d1bbc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java @@ -60,6 +60,7 @@ import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.RefNotAdvertisedException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; +import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode; @@ -67,12 +68,17 @@ import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode; import org.eclipse.jgit.merge.MergeStrategy; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.TagOpt; @@ -339,6 +345,45 @@ public class PullCommand extends TransportCommand { PullResult result; if (pullRebaseMode != BranchRebaseMode.NONE) { + try { + Ref head = repo.exactRef(Constants.HEAD); + if (head == null) { + throw new NoHeadException(JGitText + .get().commitOnRepoWithoutHEADCurrentlyNotSupported); + } + ObjectId headId = head.getObjectId(); + if (headId == null) { + // Pull on an unborn branch: checkout + try (RevWalk revWalk = new RevWalk(repo)) { + RevCommit srcCommit = revWalk + .parseCommit(commitToMerge); + DirCacheCheckout dco = new DirCacheCheckout(repo, + repo.lockDirCache(), srcCommit.getTree()); + dco.setFailOnConflict(true); + dco.setProgressMonitor(monitor); + dco.checkout(); + RefUpdate refUpdate = repo + .updateRef(head.getTarget().getName()); + refUpdate.setNewObjectId(commitToMerge); + refUpdate.setExpectedOldObjectId(null); + refUpdate.setRefLogMessage("initial pull", false); //$NON-NLS-1$ + if (refUpdate.update() != Result.NEW) { + throw new NoHeadException(JGitText + .get().commitOnRepoWithoutHEADCurrentlyNotSupported); + } + monitor.endTask(); + return new PullResult(fetchRes, remote, + RebaseResult.result( + RebaseResult.Status.FAST_FORWARD, + srcCommit)); + } + } + } catch (NoHeadException e) { + throw e; + } catch (IOException e) { + throw new JGitInternalException(JGitText + .get().exceptionCaughtDuringExecutionOfPullCommand, e); + } RebaseCommand rebase = new RebaseCommand(repo); RebaseResult rebaseRes = rebase.setUpstream(commitToMerge) .setUpstreamName(upstreamName).setProgressMonitor(monitor) From e9abe09809097b431cf2acc50066435ea2cc0a53 Mon Sep 17 00:00:00 2001 From: Michael Keppler Date: Sun, 29 Jul 2018 07:53:11 +0200 Subject: [PATCH 39/51] Retry loading config when locked by another process When loading the config, a FileNotFoundException may occur if the file exists but cannot be read (see [1]). This is the case on Windows with a virus scanner checking the file. Therefore if the file exists and that exception is thrown, retry multiple times, similar to how this was already implemented for IOException. [1] https://docs.oracle.com/javase/8/docs/api/java/io/FileNotFoundException.html Bug: 529522 Change-Id: Ic5dc3b7b24bb0005d6256ed00513bc7c0b91e613 Signed-off-by: Michael Keppler Signed-off-by: Matthias Sohn --- .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/internal/JGitText.java | 1 + .../jgit/storage/file/FileBasedConfig.java | 21 +++++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index afa876174..df42dc757 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -139,6 +139,7 @@ configSubsectionContainsNewline=config subsection name contains newline configSubsectionContainsNullByte=config subsection name contains byte 0x00 configValueContainsNullByte=config value contains byte 0x00 configHandleIsStale=config file handle is stale, {0}. retry +configHandleMayBeLocked=config file handle may be locked by other process, {0}. retry connectionFailed=connection failed connectionTimeOut=Connection time out: {0} contextMustBeNonNegative=context must be >= 0 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 4d0d05156..bdaef5a36 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -200,6 +200,7 @@ public class JGitText extends TranslationBundle { /***/ public String configSubsectionContainsNullByte; /***/ public String configValueContainsNullByte; /***/ public String configHandleIsStale; + /***/ public String configHandleMayBeLocked; /***/ public String connectionFailed; /***/ public String connectionTimeOut; /***/ public String contextMustBeNonNegative; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java index 2b31ebd8e..fc6f4a39c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java @@ -148,7 +148,8 @@ public class FileBasedConfig extends StoredConfig { */ @Override public void load() throws IOException, ConfigInvalidException { - final int maxStaleRetries = 5; + final int maxRetries = 5; + int retryDelayMillis = 20; int retries = 0; while (true) { final FileSnapshot oldSnapshot = snapshot; @@ -177,6 +178,22 @@ public class FileBasedConfig extends StoredConfig { } return; } catch (FileNotFoundException noFile) { + // might be locked by another process (see exception Javadoc) + if (retries < maxRetries && configFile.exists()) { + if (LOG.isDebugEnabled()) { + LOG.debug(MessageFormat.format( + JGitText.get().configHandleMayBeLocked, + Integer.valueOf(retries)), noFile); + } + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + retries++; + retryDelayMillis *= 2; // max wait 1260 ms + continue; + } if (configFile.exists()) { throw noFile; } @@ -185,7 +202,7 @@ public class FileBasedConfig extends StoredConfig { return; } catch (IOException e) { if (FileUtils.isStaleFileHandle(e) - && retries < maxStaleRetries) { + && retries < maxRetries) { if (LOG.isDebugEnabled()) { LOG.debug(MessageFormat.format( JGitText.get().configHandleIsStale, From df616520d77acf0a0722a75e6b7b3653d78b0b0d Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Sat, 8 Jun 2019 17:31:33 +0200 Subject: [PATCH 40/51] Bazel: Bump skylib library version to 0.8.0 Change-Id: I2089899c9f197b2c93b93390fdd55f6fe11e5ce4 Signed-off-by: David Ostrovsky --- WORKSPACE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index b11de7a68..322e74846 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -4,9 +4,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "bazel_skylib", - sha256 = "bbccf674aa441c266df9894182d80de104cabd19be98be002f6d478aaa31574d", - strip_prefix = "bazel-skylib-2169ae1c374aab4a09aa90e65efe1a3aad4e279b", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/2169ae1c374aab4a09aa90e65efe1a3aad4e279b.tar.gz"], + sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a", + strip_prefix = "bazel-skylib-0.8.0", + urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"], ) load("@bazel_skylib//lib:versions.bzl", "versions") From 95de60594ed6fdbc2ac6eaebe114be71c171c038 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Sat, 8 Jun 2019 17:32:35 +0200 Subject: [PATCH 41/51] Bump minimum Bazel version to 0.26.1 Change-Id: I8d6f9eac5af54e5b270e7db4e52d1b4063c1aa56 Signed-off-by: David Ostrovsky --- WORKSPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WORKSPACE b/WORKSPACE index 322e74846..d33c116e2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -11,7 +11,7 @@ http_archive( load("@bazel_skylib//lib:versions.bzl", "versions") -versions.check(minimum_bazel_version = "0.19.0") +versions.check(minimum_bazel_version = "0.26.1") load("//tools:bazlets.bzl", "load_bazlets") From 03f7618fab26409e1a510fd118cf6a6ea7a9e677 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Sat, 8 Jun 2019 17:33:28 +0200 Subject: [PATCH 42/51] Use bazelisk to switch between used bazel version Bazelisk is utility to switch to the right Bazel version, that we used to have with Buck build tool: [1]. Bazelisk will download the right Bazel version only once and will use it in subsequent calls: $ bazelisk build :release 2019/06/06 16:22:15 Downloading \ https://releases.bazel.build/0.26.1/release/bazel-0.26.1-linux-x86_64... Bazelisk is storing the binaries in user's cache directory: [2], e.g. on Linux OS: $ ls -1 ~/.cache/bazelisk/bin bazel-0.26.1-linux-x86_64 * [1] https://github.com/bazelbuild/bazelisk * [2] https://golang.org/pkg/os/#UserCacheDir Change-Id: Ia9180fb75f8cc17a0a0232622cf33a13bfad6b60 Signed-off-by: David Ostrovsky --- .bazelversion | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bazelversion diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..30f6cf8d9 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +0.26.1 From d8429d27f7867ad400112584b5581ed741e1c3ec Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 10 Jun 2019 23:35:20 +0200 Subject: [PATCH 43/51] Increase bazel timeout for long running tests EolRepositoryTest and GcCommitSelectionTest timed out frequently when running unit tests using bazel with the default timeout "moderate" (300s). Increase timeout of these tests to "long" (900s). Change-Id: I43588cf950f55b50f868d9fe9c66d22bd428a54c Signed-off-by: Matthias Sohn --- org.eclipse.jgit.test/tests.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl index 3665c2499..d639a5bea 100644 --- a/org.eclipse.jgit.test/tests.bzl +++ b/org.eclipse.jgit.test/tests.bzl @@ -7,6 +7,7 @@ def tests(tests): for src in tests: name = src[len("tst/"):len(src) - len(".java")].replace("/", "_") labels = [] + timeout = "moderate" if name.startswith("org_eclipse_jgit_"): l = name[len("org.eclipse.jgit_"):] if l.startswith("internal_storage_"): @@ -60,6 +61,8 @@ def tests(tests): heap_size = "-Xmx256m" if src.endswith("HugeCommitMessageTest.java"): heap_size = "-Xmx512m" + if src.endswith("EolRepositoryTest.java") or src.endswith("GcCommitSelectionTest.java"): + timeout = "long" junit_tests( name = name, @@ -77,4 +80,5 @@ def tests(tests): ], flaky = flaky, jvm_flags = [heap_size, "-Dfile.encoding=UTF-8"], + timeout = timeout, ) From e5217400de0e07266616775491d26ec16f747a64 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 14:54:19 +0900 Subject: [PATCH 44/51] FS_POSIX: Fix reference comparison of Boolean.FALSE Change-Id: Ic205d017b365ea85983d0b0d9d033fcf7e6bf6ab Signed-off-by: David Pursehouse --- org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java index 588855b1f..faef9fd0f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java @@ -400,7 +400,7 @@ public class FS_POSIX extends FS { try { Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store, s -> Boolean.TRUE); - if (canLink == Boolean.FALSE) { + if (Boolean.FALSE.equals(canLink)) { return true; } link = Files.createLink( @@ -466,7 +466,7 @@ public class FS_POSIX extends FS { try { Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store, s -> Boolean.TRUE); - if (canLink == Boolean.FALSE) { + if (Boolean.FALSE.equals(canLink)) { return token(true, null); } link = Files.createLink(Paths.get(uniqueLinkPath(file)), path); From 9c97a586bfb4b8c189809db73e04471c729da383 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 15:48:57 +0900 Subject: [PATCH 45/51] GC: Update TODO comments The TODO comments say "in 5.0", but 5.0 was already released without resolving them. Remove "in 5.0" on the assumption that the mentioned improvements still need to be done at some point. Change-Id: I3eb429803e2266de3fc490e1f3912991c08aa1ad Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/internal/storage/file/GC.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index a791ac78e..70a3d5ea5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -243,7 +243,7 @@ public class GC { * If the configuration parameter "gc.pruneexpire" couldn't be * parsed */ - // TODO(ms): in 5.0 change signature and return Future> + // TODO(ms): change signature and return Future> @SuppressWarnings("FutureReturnValueIgnored") public Collection gc() throws IOException, ParseException { if (!background) { @@ -280,7 +280,7 @@ public class GC { } return Collections.emptyList(); }; - // TODO(ms): in 5.0 change signature and return the Future + // TODO(ms): change signature and return the Future executor().submit(gcTask); return Collections.emptyList(); } From 4e8a3df68f5271e56ff4ce76fb77ad2816d49068 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 16:25:32 +0900 Subject: [PATCH 46/51] Abbreviated{Long}ObjectId: Make operator precedence explicit Change-Id: Iafd616d3fdc81ac3072f776061548be195270d85 Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java | 2 +- .../src/org/eclipse/jgit/lib/AbbreviatedObjectId.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java index bdd1b39c0..5109d9bbb 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AbbreviatedLongObjectId.java @@ -170,7 +170,7 @@ public final class AbbreviatedLongObjectId implements Serializable { r |= RawParseUtils.parseHexInt4(bs[p++]); n++; } - return r << (16 - n) * 4; + return r << ((16 - n) * 4); } static long mask(int nibbles, long word, long v) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java index d105d0d20..b0339c677 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java @@ -162,7 +162,7 @@ public final class AbbreviatedObjectId implements Serializable { r |= RawParseUtils.parseHexInt4(bs[p++]); n++; } - return r << (8 - n) * 4; + return r << ((8 - n) * 4); } static int mask(int nibbles, int word, int v) { From 4481beae6399de618c5cbbef9a844a03cfbf22eb Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Tue, 11 Jun 2019 09:24:26 +0900 Subject: [PATCH 47/51] Upgrade spotbugs to 3.1.12 Change-Id: I8093ce8342ab98f12ffabaf2862e6f1b161c4c87 Signed-off-by: David Pursehouse --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 894458e54..48d31c4db 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 1.3.0 2.8.2 1.61 - 3.1.11 + 3.1.12 2.22.2 3.8.1 3.0.0 From 518dc8638073a8371b4d5d77c265d70f96d62ff1 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 15:06:22 +0900 Subject: [PATCH 48/51] FS_Win32: Add missing parentheses on if-blocks Change-Id: I70504484f20aee103e51c852d71cd41b54093793 Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/util/FS_Win32.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java index 98797dc64..3ccbd7280 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java @@ -205,18 +205,21 @@ public class FS_Win32 extends FS { @Override protected File userHomeImpl() { String home = SystemReader.getInstance().getenv("HOME"); //$NON-NLS-1$ - if (home != null) + if (home != null) { return resolve(null, home); + } String homeDrive = SystemReader.getInstance().getenv("HOMEDRIVE"); //$NON-NLS-1$ if (homeDrive != null) { String homePath = SystemReader.getInstance().getenv("HOMEPATH"); //$NON-NLS-1$ - if (homePath != null) + if (homePath != null) { return new File(homeDrive, homePath); + } } String homeShare = SystemReader.getInstance().getenv("HOMESHARE"); //$NON-NLS-1$ - if (homeShare != null) + if (homeShare != null) { return new File(homeShare); + } return super.userHomeImpl(); } @@ -237,8 +240,9 @@ public class FS_Win32 extends FS { /** {@inheritDoc} */ @Override public boolean supportsSymlinks() { - if (supportSymlinks == null) + if (supportSymlinks == null) { detectSymlinkSupport(); + } return Boolean.TRUE.equals(supportSymlinks); } @@ -254,12 +258,13 @@ public class FS_Win32 extends FS { | InternalError e) { supportSymlinks = Boolean.FALSE; } finally { - if (tempFile != null) + if (tempFile != null) { try { FileUtils.delete(tempFile); } catch (IOException e) { throw new RuntimeException(e); // panic } + } } } From 8bd0ba0f150feb485295f8c3890648eddf05fa41 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 15:47:42 +0900 Subject: [PATCH 49/51] ErrorProne: Increase severity of FutureReturnValueIgnored to ERROR The only remaining code where the return value is ignored is in tests. Update them to store the value and perform a basic assertion. Change-Id: I29ef5bd5dd0648aac3490f9e47ecc74544109652 Signed-off-by: David Pursehouse --- .../tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java | 5 ++++- .../eclipse/jgit/internal/storage/file/GcPackRefsTest.java | 3 ++- tools/BUILD | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java index c6f953556..2334ec37a 100644 --- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java +++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.lfs.server.fs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -56,6 +57,7 @@ import java.util.List; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; @@ -122,11 +124,12 @@ public class UploadTest extends LfsServerTest { ExecutorService e = Executors.newFixedThreadPool(count); try { for (Path p : paths) { - e.submit(() -> { + Future result = e.submit(() -> { barrier.await(); putContent(p); return null; }); + assertNotNull(result); } } finally { e.shutdown(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java index 1fa5aa09a..54708da03 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java @@ -176,12 +176,13 @@ public class GcPackRefsTest extends GcTestCase { return update.update(); }); - pool.submit(() -> { + Future result2 = pool.submit(() -> { refUpdateLockedRef.await(); gc.packRefs(); packRefsDone.await(); return null; }); + assertNull(result2.get()); assertSame(result.get(), Result.FORCED); diff --git a/tools/BUILD b/tools/BUILD index 9025e0a6d..abf6c9dc0 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -42,7 +42,7 @@ java_package_configuration( "-Xep:FragmentInjection:WARN", "-Xep:FragmentNotInstantiable:WARN", "-Xep:FunctionalInterfaceClash:WARN", - "-Xep:FutureReturnValueIgnored:WARN", + "-Xep:FutureReturnValueIgnored:ERROR", "-Xep:GetClassOnEnum:WARN", "-Xep:ImmutableAnnotationChecker:WARN", "-Xep:ImmutableEnumChecker:WARN", From fd8d779b5eec614d2cb5a611f2e36f522b34a439 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Sat, 8 Jun 2019 15:01:44 +0900 Subject: [PATCH 50/51] Config: Add helper method to check for empty value Rename MAGIC_EMPTY_VALUE to MISSING_ENTRY, make it private, and add a helper method to check if a given string is that value. This avoids that callers trigger the "reference equality" warning from Error Prone. Change-Id: Idc76f78c0cf1828aa48d02ee33911a4b5df50355 Signed-off-by: David Pursehouse --- .../src/org/eclipse/jgit/lib/Config.java | 19 +++++++++++++++---- .../jgit/lib/DefaultTypedConfigGetter.java | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 2c01d6038..1032fd0df 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -107,7 +107,7 @@ public class Config { * must ensure it is a special copy of the empty string. It also must * be treated like the empty string. */ - static final String MAGIC_EMPTY_VALUE = new String(); + private static final String MISSING_ENTRY = new String(); /** * Create a configuration with no default fallback. @@ -128,6 +128,17 @@ public class Config { state = new AtomicReference<>(newState()); } + /** + * Check if a given string is the "missing" value. + * + * @param value + * @return true if the given string is the "missing" value. + * @since 5.4 + */ + public static boolean isMissing(String value) { + return value == MISSING_ENTRY; + } + /** * Globally sets a {@link org.eclipse.jgit.lib.TypedConfigGetter} that is * subsequently used to read typed values from all git configs. @@ -1041,7 +1052,7 @@ public class Config { if (e.prefix == null || "".equals(e.prefix)) //$NON-NLS-1$ out.append('\t'); out.append(e.name); - if (MAGIC_EMPTY_VALUE != e.value) { + if (MISSING_ENTRY != e.value) { out.append(" ="); //$NON-NLS-1$ if (e.value != null) { out.append(' '); @@ -1132,7 +1143,7 @@ public class Config { e.name = readKeyName(in); if (e.name.endsWith("\n")) { //$NON-NLS-1$ e.name = e.name.substring(0, e.name.length() - 1); - e.value = MAGIC_EMPTY_VALUE; + e.value = MISSING_ENTRY; } else e.value = readValue(in); @@ -1165,7 +1176,7 @@ public class Config { private void addIncludedConfig(final List newEntries, ConfigLine line, int depth) throws ConfigInvalidException { if (!line.name.equalsIgnoreCase("path") || //$NON-NLS-1$ - line.value == null || line.value.equals(MAGIC_EMPTY_VALUE)) { + line.value == null || line.value.equals(MISSING_ENTRY)) { throw new ConfigInvalidException(MessageFormat.format( JGitText.get().invalidLineInConfigFileWithParam, line)); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java index 6a66cf682..4c70d20d6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java @@ -72,7 +72,7 @@ public class DefaultTypedConfigGetter implements TypedConfigGetter { if (n == null) { return defaultValue; } - if (Config.MAGIC_EMPTY_VALUE == n) { + if (Config.isMissing(n)) { return true; } try { From 1cfcde48534dcc9510e6e58d422a78fcd156c85f Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Tue, 11 Jun 2019 13:16:18 +0200 Subject: [PATCH 51/51] Handle missing "ours" stage in WorkingTreeIterator.hasCrLfInIndex() In a delete-modify conflict with the deletion as "ours" there may be no stage 2 in the index. Add appropriate null checks. Add a new test for this case, and verify that the file gets added with a single LF after conflict resolution with core.autocrlf=true. This matches the behavior of canonical git for this case. Bug: 547724 Change-Id: I1bafdb83d9b78bf85294c78325e818e72fae53bc Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/CommitCommandTest.java | 48 +++++++++++++++++++ .../jgit/treewalk/WorkingTreeIterator.java | 25 ++++++---- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 4bfac1505..18fed4bff 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -661,6 +661,54 @@ public class CommitCommandTest extends RepositoryTestCase { } } + @Test + public void testDeletionConflictWithAutoCrlf() throws Exception { + try (Git git = new Git(db)) { + // Commit a file with CR/LF into the index + FileBasedConfig config = db.getConfig(); + config.setString("core", null, "autocrlf", "false"); + config.save(); + File file = writeTrashFile("file.txt", "foo\r\n"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("Initial").call(); + // Switch to side branch + git.checkout().setCreateBranch(true).setName("side").call(); + assertTrue(file.delete()); + git.rm().addFilepattern("file.txt").call(); + git.commit().setMessage("Side").call(); + // Switch on autocrlf=true + config.setString("core", null, "autocrlf", "true"); + config.save(); + // Switch back to master and commit a conflict + git.checkout().setName("master").call(); + writeTrashFile("file.txt", "foob\r\n"); + git.add().addFilepattern("file.txt").call(); + assertEquals("[file.txt, mode:100644, content:foob\r\n]", + indexState(CONTENT)); + writeTrashFile("g", "file2.txt", "anything"); + git.add().addFilepattern("g/file2.txt"); + RevCommit master = git.commit().setMessage("Second").call(); + // Switch to side branch again so that the deletion is "ours" + git.checkout().setName("side").call(); + // Cherry pick master: produces a delete-modify conflict. + CherryPickResult pick = git.cherryPick().include(master).call(); + assertEquals("Expected a cherry-pick conflict", + CherryPickStatus.CONFLICTING, pick.getStatus()); + // XXX: g/file2.txt should actually be staged already, but isn't. + git.add().addFilepattern("g/file2.txt").call(); + // Resolve the conflict by taking the master version + writeTrashFile("file.txt", "foob\r\n"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("Cherry").call(); + // We expect this to be committed with a single LF since there is no + // "ours" stage. + assertEquals( + "[file.txt, mode:100644, content:foob\n]" + + "[g/file2.txt, mode:100644, content:anything]", + indexState(CONTENT)); + } + } + private void testConflictWithAutoCrlf(String baseLf, String lf) throws Exception { try (Git git = new Git(db)) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java index c0c24872b..3efa66459 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -1516,6 +1516,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { ObjectId blobId = entry.getObjectId(); if (entry.getStage() > 0 && entry.getStage() != DirCacheEntry.STAGE_2) { + blobId = null; // Merge conflict: check ours (stage 2) byte[] name = entry.getRawPath(); int i = 0; @@ -1523,7 +1524,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { dirCache.next(1); i++; entry = dirCache.getDirCacheEntry(); - if (!Arrays.equals(name, entry.getRawPath())) { + if (entry == null + || !Arrays.equals(name, entry.getRawPath())) { break; } if (entry.getStage() == DirCacheEntry.STAGE_2) { @@ -1533,17 +1535,20 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { } dirCache.back(i); } - try (ObjectReader reader = repository.newObjectReader()) { - ObjectLoader loader = reader.open(blobId, Constants.OBJ_BLOB); - try { - return RawText.isCrLfText(loader.getCachedBytes()); - } catch (LargeObjectException e) { - try (InputStream in = loader.openStream()) { - return RawText.isCrLfText(in); + if (blobId != null) { + try (ObjectReader reader = repository.newObjectReader()) { + ObjectLoader loader = reader.open(blobId, + Constants.OBJ_BLOB); + try { + return RawText.isCrLfText(loader.getCachedBytes()); + } catch (LargeObjectException e) { + try (InputStream in = loader.openStream()) { + return RawText.isCrLfText(in); + } } + } catch (IOException e) { + // Ignore and return false below } - } catch (IOException e) { - // Ignore and return false below } } return false;