diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2018-06-14 00:00:30 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2018-06-14 00:00:30 +0200 |
commit | 331f1a8e49dbd619d501f925210df31b0d9db2ea (patch) | |
tree | 186c632429b7688dd67dd1a7f0f4f86ca22adca8 | |
parent | 44137491dc5e0fb428cacd6df1d7a958c7eba070 (diff) | |
parent | 0dbaf9d951e78a6b0aec0c2aac3153570c4b9a9f (diff) | |
download | jgit-331f1a8e49dbd619d501f925210df31b0d9db2ea.tar.gz jgit-331f1a8e49dbd619d501f925210df31b0d9db2ea.zip |
Merge branch 'stable-5.0'
* stable-5.0:
Prepare 5.0.1-SNAPSHOT builds
JGit v5.0.0.201806131550-r
JGit v5.0.0.201806131210-r
Downgrade Apache httpclient to 4.5.2.v20170210-0925
RefUpdateTest: Refactor to not use deprecated Repository#getAllRefs
Propagate failure of ssh command to caller of SshSupport
Make JGit describe behaves same as c-git for lightweight tags
Fix issues with LFS on GitHub (SSH)
Change-Id: I0471440919adfdbfc72996711d9e0bbd1f3cf477
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
10 files changed, 325 insertions, 91 deletions
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java index 5320af0b78..f90a003b4b 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsConfigInvalidException.java @@ -63,4 +63,17 @@ public class LfsConfigInvalidException extends IOException { super(msg); } + /** + * Constructor for LfsConfigInvalidException. + * + * @param msg + * the error description + * @param e + * cause of this exception + * @since 5.0 + */ + public LfsConfigInvalidException(String msg, Exception e) { + super(msg, e); + } + } diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java index 3ac69923f2..955eca0c3f 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java @@ -49,6 +49,7 @@ import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE; import java.io.IOException; import java.net.ProxySelector; +import java.net.URISyntaxException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.LinkedList; @@ -56,6 +57,7 @@ import java.util.Map; import java.util.TreeMap; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.errors.CommandFailedException; import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lfs.Protocol; import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException; @@ -74,7 +76,7 @@ import org.eclipse.jgit.util.SshSupport; */ public class LfsConnectionFactory { - private static final int SSH_AUTH_TIMEOUT_SECONDS = 5; + private static final int SSH_AUTH_TIMEOUT_SECONDS = 30; private static final String SCHEME_HTTPS = "https"; //$NON-NLS-1$ private static final String SCHEME_SSH = "ssh"; //$NON-NLS-1$ private static final Map<String, AuthCache> sshAuthCache = new TreeMap<>(); @@ -128,6 +130,7 @@ public class LfsConnectionFactory { String lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS, null, ConfigConstants.CONFIG_KEY_URL); + Exception ex = null; if (lfsUrl == null) { String remoteUrl = null; for (String remote : db.getRemoteNames()) { @@ -146,38 +149,44 @@ public class LfsConnectionFactory { break; } if (lfsUrl == null && remoteUrl != null) { - lfsUrl = discoverLfsUrl(db, purpose, additionalHeaders, - remoteUrl); + try { + lfsUrl = discoverLfsUrl(db, purpose, additionalHeaders, + remoteUrl); + } catch (URISyntaxException | IOException + | CommandFailedException e) { + ex = e; + } } else { lfsUrl = lfsUrl + Protocol.INFO_LFS_ENDPOINT; } } if (lfsUrl == null) { + if (ex != null) { + throw new LfsConfigInvalidException( + LfsText.get().lfsNoDownloadUrl, ex); + } throw new LfsConfigInvalidException(LfsText.get().lfsNoDownloadUrl); } return lfsUrl; } private static String discoverLfsUrl(Repository db, String purpose, - Map<String, String> additionalHeaders, String remoteUrl) { - try { - URIish u = new URIish(remoteUrl); - if (SCHEME_SSH.equals(u.getScheme())) { - Protocol.ExpiringAction action = getSshAuthentication( - db, purpose, remoteUrl, u); - additionalHeaders.putAll(action.header); - return action.href; - } else { - return remoteUrl + Protocol.INFO_LFS_ENDPOINT; - } - } catch (Exception e) { - return null; // could not discover + Map<String, String> additionalHeaders, String remoteUrl) + throws URISyntaxException, IOException, CommandFailedException { + URIish u = new URIish(remoteUrl); + if (u.getScheme() == null || SCHEME_SSH.equals(u.getScheme())) { + Protocol.ExpiringAction action = getSshAuthentication(db, purpose, + remoteUrl, u); + additionalHeaders.putAll(action.header); + return action.href; + } else { + return remoteUrl + Protocol.INFO_LFS_ENDPOINT; } } private static Protocol.ExpiringAction getSshAuthentication( Repository db, String purpose, String remoteUrl, URIish u) - throws IOException { + throws IOException, CommandFailedException { AuthCache cached = sshAuthCache.get(remoteUrl); Protocol.ExpiringAction action = null; if (cached != null && cached.validUntil > System.currentTimeMillis()) { @@ -226,8 +235,10 @@ public class LfsConnectionFactory { .create(contentUrl, HttpSupport .proxyFor(ProxySelector.getDefault(), contentUrl)); contentServerConn.setRequestMethod(method); - action.header - .forEach((k, v) -> contentServerConn.setRequestProperty(k, v)); + if (action.header != null) { + action.header.forEach( + (k, v) -> contentServerConn.setRequestProperty(k, v)); + } if (contentUrl.getProtocol().equals(SCHEME_HTTPS) && !repo.getConfig().getBoolean(HttpConfig.HTTP, HttpConfig.SSL_VERIFY_KEY, true)) { @@ -241,7 +252,13 @@ public class LfsConnectionFactory { } private static String extractProjectName(URIish u) { - String path = u.getPath().substring(1); + String path = u.getPath(); + + // begins with a slash if the url contains a port (gerrit vs. github). + if (path.startsWith("/")) { //$NON-NLS-1$ + path = path.substring(1); + } + if (path.endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT)) { return path.substring(0, path.length() - 4); } else { 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 564b49326a..6f57c9d6a1 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 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform --> -<target name="jgit-4.8" sequenceNumber="1528373976"> +<target name="jgit-4.8" sequenceNumber="1528872727"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.jetty.client" version="9.4.8.v20171121"/> @@ -33,8 +33,6 @@ <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.6.v20170210-0925"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.6.v20170210-0925"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20180410-1551"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20180410-1551"/> <unit id="org.apache.log4j" version="1.2.15.v201012070815"/> <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/> <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/> @@ -69,6 +67,11 @@ <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180606145124/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.2.v20170210-0925"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.2.v20170210-0925"/> + <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository/"/> + </location> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> <repository location="http://download.eclipse.org/releases/oxygen/"/> </location> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd index 8497c2c871..808b9d6944 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd @@ -12,8 +12,6 @@ location "http://download.eclipse.org/tools/orbit/downloads/drops/R2018060614512 org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721] org.apache.httpcomponents.httpcore [4.4.6.v20170210-0925,4.4.6.v20170210-0925] org.apache.httpcomponents.httpcore.source [4.4.6.v20170210-0925,4.4.6.v20170210-0925] - org.apache.httpcomponents.httpclient [4.5.2.v20180410-1551,4.5.2.v20180410-1551] - org.apache.httpcomponents.httpclient.source [4.5.2.v20180410-1551,4.5.2.v20180410-1551] org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815] org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815] org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] @@ -45,4 +43,10 @@ location "http://download.eclipse.org/tools/orbit/downloads/drops/R2018060614512 org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200] com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] +} + +location "http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository/" { + // platform uses this outdated version of httpclient in Photon + org.apache.httpcomponents.httpclient [4.5.2.v20170210-0925,4.5.2.v20170210-0925] + org.apache.httpcomponents.httpclient.source [4.5.2.v20170210-0925,4.5.2.v20170210-0925] }
\ No newline at end of file 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 79da2da7ea..a422ef91cb 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 @@ -54,7 +54,6 @@ import java.util.Collection; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefNotFoundException; -import org.eclipse.jgit.errors.InvalidPatternException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; @@ -68,13 +67,18 @@ public class DescribeCommandTest extends RepositoryTestCase { private Git git; - @Parameter + @Parameter(0) public boolean useAnnotatedTags; - @Parameters + @Parameter(1) + public boolean describeUseAllTags; + + @Parameters(name = "git tag -a {0}?-a: with git describe {1}?--tags:") public static Collection<Boolean[]> getUseAnnotatedTagsValues() { - return Arrays.asList(new Boolean[][] { { Boolean.TRUE }, - { Boolean.FALSE } }); + return Arrays.asList(new Boolean[][] { { Boolean.TRUE, Boolean.FALSE }, + { Boolean.FALSE, Boolean.FALSE }, + { Boolean.TRUE, Boolean.TRUE }, + { Boolean.FALSE, Boolean.TRUE } }); } @Override @@ -99,35 +103,52 @@ public class DescribeCommandTest extends RepositoryTestCase { tag("bob-t2"); ObjectId c4 = modify("ddd"); + assertNameStartsWith(c4, "3e563c5"); assertNull(describe(c1)); assertNull(describe(c1, true)); assertNull(describe(c1, "a*", "b*", "c*")); - - assertEquals("alice-t1", describe(c2)); - assertEquals("alice-t1", describe(c2, "alice*")); assertNull(describe(c2, "bob*")); assertNull(describe(c2, "?ob*")); - assertEquals("alice-t1", describe(c2, "a*", "b*", "c*")); - assertEquals("bob-t2", describe(c3)); - assertEquals("bob-t2-0-g44579eb", describe(c3, true)); - assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*")); - assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*")); - assertEquals("bob-t2", describe(c3, "bob*")); - assertEquals("bob-t2", describe(c3, "?ob*")); - assertEquals("bob-t2", describe(c3, "a*", "b*", "c*")); - - assertNameStartsWith(c4, "3e563c5"); - // the value verified with git-describe(1) - assertEquals("bob-t2-1-g3e563c5", describe(c4)); - assertEquals("bob-t2-1-g3e563c5", describe(c4, true)); - 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*")); + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("alice-t1", describe(c2)); + assertEquals("alice-t1", describe(c2, "alice*")); + assertEquals("alice-t1", describe(c2, "a*", "b*", "c*")); + + assertEquals("bob-t2", describe(c3)); + assertEquals("bob-t2-0-g44579eb", describe(c3, true)); + assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*")); + assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*")); + assertEquals("bob-t2", describe(c3, "bob*")); + assertEquals("bob-t2", describe(c3, "?ob*")); + assertEquals("bob-t2", describe(c3, "a*", "b*", "c*")); + + // the value verified with git-describe(1) + assertEquals("bob-t2-1-g3e563c5", describe(c4)); + assertEquals("bob-t2-1-g3e563c5", describe(c4, true)); + 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*")); + } else { + assertEquals(null, describe(c2)); + assertEquals(null, describe(c3)); + assertEquals(null, describe(c4)); + } // test default target - assertEquals("bob-t2-1-g3e563c5", git.describe().call()); + if (useAnnotatedTags) { + assertEquals("bob-t2-1-g3e563c5", git.describe().call()); + assertEquals("bob-t2-1-g3e563c5", + git.describe().setTags(false).call()); + assertEquals("bob-t2-1-g3e563c5", + git.describe().setTags(true).call()); + } else { + assertEquals(null, git.describe().call()); + assertEquals(null, git.describe().setTags(false).call()); + assertEquals("bob-t2-1-g3e563c5", + git.describe().setTags(true).call()); + } } @Test @@ -137,7 +158,14 @@ public class DescribeCommandTest extends RepositoryTestCase { tag("v1.1.1"); ObjectId c2 = modify("bbb"); - // Ensure that if we're interested in any tags, we get the first match as per Git behaviour + if (!useAnnotatedTags && !describeUseAllTags) { + assertEquals(null, describe(c1)); + assertEquals(null, describe(c2)); + return; + } + + // Ensure that if we're interested in any tags, we get the first match + // as per Git behaviour assertEquals("v1.0.0", describe(c1)); assertEquals("v1.0.0-1-g3747db3", describe(c2)); @@ -179,7 +207,11 @@ public class DescribeCommandTest extends RepositoryTestCase { ObjectId c4 = merge(c2); assertNameStartsWith(c4, "119892b"); - assertEquals("t-2-g119892b", describe(c4)); // 2 commits: c4 and c3 + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("2 commits: c4 and c3", "t-2-g119892b", describe(c4)); + } else { + assertEquals(null, describe(c4)); + } assertNull(describe(c3)); assertNull(describe(c3, true)); } @@ -211,14 +243,76 @@ public class DescribeCommandTest extends RepositoryTestCase { branch("b", c1); ObjectId c3 = modify("ccc"); + assertNameStartsWith(c3, "0244e7f"); ObjectId c4 = merge(c2); assertNameStartsWith(c4, "119892b"); - assertEquals("t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3 + + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3 + assertEquals("t1-1-g0244e7f", describe(c3)); + } else { + assertEquals(null, describe(c4)); + assertEquals(null, describe(c3)); + } + } + + /** + * When t1 annotated dominates t2 lightweight tag + * + * <pre> + * t1 -+-> t2 - + * | | + * +-> c3 -+-> c4 + * </pre> + * + * @throws Exception + */ + @Test + public void t1AnnotatedDominatesT2lightweight() throws Exception { + ObjectId c1 = modify("aaa"); + tag("t1", useAnnotatedTags); + + ObjectId c2 = modify("bbb"); + tag("t2", false); + + assertNameStartsWith(c2, "3747db3"); + if (useAnnotatedTags && !describeUseAllTags) { + assertEquals( + "only annotated tag t1 expected to be used for describe", + "t1-1-g3747db3", describe(c2)); // 1 commits: t2 overridden + // by t1 + } else if (!useAnnotatedTags && !describeUseAllTags) { + assertEquals("no commits to describe expected", null, describe(c2)); + } else { + assertEquals("lightweight tag t2 expected in describe", "t2", + describe(c2)); + } + + branch("b", c1); + + ObjectId c3 = modify("ccc"); assertNameStartsWith(c3, "0244e7f"); - assertEquals("t1-1-g0244e7f", describe(c3)); + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("t1-1-g0244e7f", describe(c3)); + } + + ObjectId c4 = merge(c2); + + assertNameStartsWith(c4, "119892b"); + if (describeUseAllTags) { + assertEquals( + "2 commits for describe commit increment expected since lightweight tag: c4 and c3", + "t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3 + } else if (!useAnnotatedTags && !describeUseAllTags) { + assertEquals("no matching commits expected", null, describe(c4)); + } else { + assertEquals( + "3 commits for describe commit increment expected since annotated tag: c4 and c3 and c2", + "t1-3-g119892b", describe(c4)); // + } } /** @@ -246,7 +340,11 @@ public class DescribeCommandTest extends RepositoryTestCase { ObjectId c4 = merge(t1); assertNameStartsWith(c4, "bb389a4"); - assertEquals("t1-3-gbb389a4", describe(c4)); + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("t1-3-gbb389a4", describe(c4)); + } else { + assertEquals(null, describe(c4)); + } } /** @@ -275,7 +373,11 @@ public class DescribeCommandTest extends RepositoryTestCase { ObjectId c4 = merge(c2); assertNameStartsWith(c4, "bb389a4"); - assertEquals("t2-4-gbb389a4", describe(c4)); + if (useAnnotatedTags || describeUseAllTags) { + assertEquals("t2-4-gbb389a4", describe(c4)); + } else { + assertEquals(null, describe(c4)); + } } private ObjectId merge(ObjectId c2) throws GitAPIException { @@ -289,10 +391,15 @@ public class DescribeCommandTest extends RepositoryTestCase { } private void tag(String tag) throws GitAPIException { + tag(tag, this.useAnnotatedTags); + } + + private void tag(String tag, boolean annotatedTag) throws GitAPIException { TagCommand tagCommand = git.tag().setName(tag) - .setAnnotated(useAnnotatedTags); - if (useAnnotatedTags) + .setAnnotated(annotatedTag); + if (annotatedTag) { tagCommand.setMessage(tag); + } tagCommand.call(); } @@ -304,15 +411,17 @@ public class DescribeCommandTest extends RepositoryTestCase { private String describe(ObjectId c1, boolean longDesc) throws GitAPIException, IOException { - return git.describe().setTarget(c1).setLong(longDesc).call(); + return git.describe().setTarget(c1).setTags(describeUseAllTags) + .setLong(longDesc).call(); } private String describe(ObjectId c1) throws GitAPIException, IOException { return describe(c1, false); } - private String describe(ObjectId c1, String... patterns) throws GitAPIException, IOException, InvalidPatternException { - return git.describe().setTarget(c1).setMatch(patterns).call(); + private String describe(ObjectId c1, String... patterns) throws Exception { + return git.describe().setTarget(c1).setTags(describeUseAllTags) + .setMatch(patterns).call(); } private static void assertNameStartsWith(ObjectId c4, String prefix) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java index b2fae316c3..e1adeedc54 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java @@ -62,6 +62,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; @@ -110,11 +111,21 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { delete(db, ref, expected, exists, removed); } - private void delete(Repository repo, final RefUpdate ref, final Result expected, - final boolean exists, final boolean removed) throws IOException { - assertEquals(exists, repo.getAllRefs().containsKey(ref.getName())); + private void delete(Repository repo, final RefUpdate ref, + final Result expected, final boolean exists, final boolean removed) + throws IOException { + assertEquals(exists, getRef(repo, ref.getName()).isPresent()); assertEquals(expected, ref.delete()); - assertEquals(!removed, repo.getAllRefs().containsKey(ref.getName())); + assertEquals(!removed, getRef(repo, ref.getName()).isPresent()); + } + + private Optional<Ref> getRef(Repository repo, String name) + throws IOException { + return getRef(repo.getRefDatabase().getRefs(), name); + } + + private Optional<Ref> getRef(List<Ref> refs, String name) { + return refs.stream().filter(r -> r.getName().equals(name)).findAny(); } @Test @@ -125,8 +136,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { ru.setNewObjectId(newid); Result update = ru.update(); assertEquals(Result.NEW, update); - final Ref r = db.getAllRefs().get(newRef); - assertNotNull(r); + final Ref r = getRef(db, newRef).get(); assertEquals(newRef, r.getName()); assertNotNull(r.getObjectId()); assertNotSame(newid, r.getObjectId()); @@ -378,10 +388,10 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { @Test public void testRefKeySameAsName() { + @SuppressWarnings("deprecation") Map<String, Ref> allRefs = db.getAllRefs(); for (Entry<String, Ref> e : allRefs.entrySet()) { assertEquals(e.getKey(), e.getValue().getName()); - } } @@ -520,8 +530,8 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { */ @Test public void testRefsCacheAfterUpdate() throws Exception { - // Do not use the defalt repo for this case. - Map<String, Ref> allRefs = db.getAllRefs(); + // Do not use the default repo for this case. + List<Ref> allRefs = db.getRefDatabase().getRefs(); ObjectId oldValue = db.resolve("HEAD"); ObjectId newValue = db.resolve("HEAD^"); // first make HEAD refer to loose ref @@ -537,9 +547,9 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { update = updateRef.update(); assertEquals(Result.FAST_FORWARD, update); - allRefs = db.getAllRefs(); - Ref master = allRefs.get("refs/heads/master"); - Ref head = allRefs.get("HEAD"); + allRefs = db.getRefDatabase().getRefs(); + Ref master = getRef(allRefs, "refs/heads/master").get(); + Ref head = getRef(allRefs, "HEAD").get(); assertEquals("refs/heads/master", master.getName()); assertEquals("HEAD", head.getName()); assertTrue("is symbolic reference", head.isSymbolic()); @@ -557,8 +567,8 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { */ @Test public void testRefsCacheAfterUpdateLooseOnly() throws Exception { - // Do not use the defalt repo for this case. - Map<String, Ref> allRefs = db.getAllRefs(); + // Do not use the default repo for this case. + List<Ref> allRefs = db.getRefDatabase().getRefs(); ObjectId oldValue = db.resolve("HEAD"); writeSymref(Constants.HEAD, "refs/heads/newref"); RefUpdate updateRef = db.updateRef(Constants.HEAD); @@ -567,9 +577,9 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { Result update = updateRef.update(); assertEquals(Result.NEW, update); - allRefs = db.getAllRefs(); - Ref head = allRefs.get("HEAD"); - Ref newref = allRefs.get("refs/heads/newref"); + allRefs = db.getRefDatabase().getRefs(); + Ref head = getRef(allRefs, "HEAD").get(); + Ref newref = getRef(allRefs, "refs/heads/newref").get(); assertEquals("refs/heads/newref", newref.getName()); assertEquals("HEAD", head.getName()); assertTrue("is symbolic reference", head.isSymbolic()); 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 b608ca8533..809bdf2865 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -629,6 +629,7 @@ sourceIsNotAWildcard=Source is not a wildcard. sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object. sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0} squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD +sshCommandFailed=Execution of ssh command ''{0}'' failed with error ''{1}'' sshUserNameError=Jsch error: failed to set SSH user name correctly to ''{0}''; using ''{1}'' picked up from SSH config file. sslFailureExceptionMessage=Secure connection to {0} could not be stablished because of SSL problems sslFailureInfo=A secure connection to {0}\ncould not be established because the server''s certificate could not be validated. 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 dc605a91e5..4d5e499571 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java @@ -104,6 +104,11 @@ public class DescribeCommand extends GitCommand<String> { private List<IMatcher> matchers = new ArrayList<>(); /** + * Whether to use all tags (incl. lightweight) or not + */ + private boolean useTags = false; + + /** * Constructor for DescribeCommand. * * @param repo @@ -173,6 +178,22 @@ public class DescribeCommand extends GitCommand<String> { return this; } + /** + * Instead of using only the annotated tags, use any tag found in refs/tags + * namespace. This option enables matching lightweight (non-annotated) tags + * or not. + * + * @param tags + * <code>true</code> enables matching lightweight (non-annotated) + * tags like setting option --tags in c git + * @return {@code this} + * @since 5.0 + */ + public DescribeCommand setTags(boolean tags) { + this.useTags = tags; + return this; + } + private String longDescription(Ref tag, int depth, ObjectId tip) throws IOException { return String.format( @@ -246,13 +267,14 @@ public class DescribeCommand extends GitCommand<String> { public String call() throws GitAPIException { try { checkCallable(); - - if (target == null) + if (target == null) { setTarget(Constants.HEAD); + } Collection<Ref> tagList = repo.getRefDatabase() .getRefsByPrefix(R_TAGS); Map<ObjectId, List<Ref>> tags = tagList.stream() + .filter(this::filterLightweightTags) .collect(Collectors.groupingBy(this::getObjectIdFromRef)); // combined flags of all the candidate instances @@ -376,4 +398,22 @@ public class DescribeCommand extends GitCommand<String> { w.close(); } } + + /** + * Whether we use lightweight tags or not for describe Candidates + * + * @param ref + * reference under inspection + * @return true if it should be used for describe or not regarding + * {@link org.eclipse.jgit.api.DescribeCommand#useTags} + */ + @SuppressWarnings("null") + private boolean filterLightweightTags(Ref ref) { + ObjectId id = ref.getObjectId(); + try { + return this.useTags || (id != null && (w.parseTag(id) != null)); + } catch (IOException e) { + return false; + } + } } 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 2ac75e1c2f..f3029bf3a1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -690,6 +690,7 @@ public class JGitText extends TranslationBundle { /***/ public String sourceRefDoesntResolveToAnyObject; /***/ public String sourceRefNotSpecifiedForRefspec; /***/ public String squashCommitNotUpdatingHEAD; + /***/ public String sshCommandFailed; /***/ public String sshUserNameError; /***/ public String sslFailureExceptionMessage; /***/ public String sslFailureInfo; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java index 96123ea670..913aa72867 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java @@ -42,12 +42,12 @@ */ package org.eclipse.jgit.util; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; +import java.text.MessageFormat; import org.eclipse.jgit.annotations.Nullable; -import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.errors.CommandFailedException; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.RemoteSession; import org.eclipse.jgit.transport.SshSessionFactory; @@ -76,27 +76,44 @@ public class SshSupport { * @param command * the remote command to execute. * @param timeout - * a timeout in seconds. - * @return The first line of output read from stdout. Stderr is discarded. + * a timeout in seconds. The timeout may be exceeded in corner + * cases. + * @return The entire output read from stdout. * @throws IOException + * @throws CommandFailedException + * if the ssh command execution failed, error message contains + * the content of stderr. */ public static String runSshCommand(URIish sshUri, @Nullable CredentialsProvider provider, FS fs, String command, - int timeout) throws IOException { + int timeout) throws IOException, CommandFailedException { RemoteSession session = null; Process process = null; StreamCopyThread errorThread = null; - try (MessageWriter stderr = new MessageWriter()) { + StreamCopyThread outThread = null; + CommandFailedException failure = null; + @SuppressWarnings("resource") + MessageWriter stderr = new MessageWriter(); + try (MessageWriter stdout = new MessageWriter()) { session = SshSessionFactory.getInstance().getSession(sshUri, provider, fs, 1000 * timeout); process = session.exec(command, 0); errorThread = new StreamCopyThread(process.getErrorStream(), stderr.getRawStream()); errorThread.start(); - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(process.getInputStream(), - Constants.CHARSET))) { - return reader.readLine(); + outThread = new StreamCopyThread(process.getInputStream(), + stdout.getRawStream()); + outThread.start(); + try { + // waitFor with timeout has a bug - JSch' exitValue() throws the + // wrong exception type :( + if (process.waitFor() == 0) { + return stdout.toString(); + } else { + return null; // still running after timeout + } + } catch (InterruptedException e) { + return null; // error } } finally { if (errorThread != null) { @@ -108,12 +125,31 @@ public class SshSupport { errorThread = null; } } + if (outThread != null) { + try { + outThread.halt(); + } catch (InterruptedException e) { + // Stop waiting and return anyway. + } finally { + outThread = null; + } + } if (process != null) { + if (process.exitValue() != 0) { + failure = new CommandFailedException(process.exitValue(), + MessageFormat.format( + JGitText.get().sshCommandFailed, command, + stderr.toString())); + } process.destroy(); } + stderr.close(); if (session != null) { SshSessionFactory.getInstance().releaseSession(session); } + if (failure != null) { + throw failure; + } } } |