Browse Source

Merge branch 'master' into stable-4.0

* master:
  Add more reports to maven site
  Update project meta-data in pom.xml used for site generation
  Update dependencies to the versions used in target platform
  Update 4.5 target platform to use final Mars Orbit repository
  Compare API changes in clirr report against 3.7.0
  Fix CommitCommand.setOnly()
  Add "src" folder to source folders of org.eclipse.jgit.test
  Improve exception thrown when pull can't find advertised ref
  Silence unchecked conversion warning in TransportSftp
  Silence deprecation warning in WindowCacheConfig
  Silence deprecation warning in DirCacheCheckout
  Fix unchecked conversion warning in MergeFormatter
  Fix hidden field warnings in bundle org.eclipse.jgit
  Close WindowCursor using try-with-resources in UnpackedObject
  Fix WindowCursor memory leak.
  archive: Drop unnecessary empty comments and 'final' qualifiers on locals
  Close 'out' consistently in ArchiveCommand.call
  Fix that exceptions in ReceivePack cause Invalid Channel 101 exceptions
  Better report too large pack-files from PushCommand
  FS: Extract GobblerThread into a private static class
  Add bitmap index misses to PackWriter.Statistics
  Enable public access to SimilarityIndex scoring function
  Add getters to RepoProject.
  Silence unused object warning in MyersDiff
  Silence resource leak warnings where caller is responsible to close
  Silence false potential null pointer access warnings
  Fix potential null pointer access in IndexDiffFilter
  Add tests for ObjectFilter
  Expose Sets helper to tests outside org.eclipse.jgit.api

Change-Id: I34b2bb45f51ed6f52a6bb1215de654ebb2ffde10
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.0
Matthias Sohn 10 years ago
parent
commit
f9c7253b15
  1. 2
      org.eclipse.jgit.http.server/pom.xml
  2. 295
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
  3. 4
      org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
  4. 2
      org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
  5. 4
      org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20150519210750-Mars.tpd
  6. 150
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
  7. 1
      org.eclipse.jgit.test/.classpath
  8. 1
      org.eclipse.jgit.test/pom.xml
  9. 6
      org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java
  10. 11
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
  11. 1
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
  12. 1
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
  13. 12
      org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
  14. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
  15. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
  16. 186
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java
  17. 3
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  18. 19
      org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
  19. 2
      org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
  20. 14
      org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
  21. 4
      org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
  22. 54
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java
  23. 65
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java
  24. 1
      org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java
  25. 52
      org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
  26. 1
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
  27. 17
      org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargePackException.java
  28. 10
      org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
  29. 22
      org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
  30. 97
      org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
  31. 1
      org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
  32. 2
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
  33. 11
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
  34. 2
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
  35. 5
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
  36. 3
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
  37. 13
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
  38. 22
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
  39. 6
      org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
  40. 4
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
  41. 1
      org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
  42. 2
      org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
  43. 1
      org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java
  44. 4
      org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
  45. 4
      org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
  46. 10
      org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
  47. 1
      org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
  48. 8
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
  49. 3
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
  50. 90
      org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
  51. 75
      pom.xml

2
org.eclipse.jgit.http.server/pom.xml

@ -75,7 +75,7 @@
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

295
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java

@ -0,0 +1,295 @@
/*
* Copyright (C) 2015, christian.Halstrick <christian.halstrick@sap.com>
* 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.http.test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.errors.TooLargePackException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.http.HttpTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.PostReceiveHook;
import org.eclipse.jgit.transport.PreReceiveHook;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.resolver.RepositoryResolver;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.junit.Before;
import org.junit.Test;
/**
* Tests for correct responses of {@link GitServlet}. Especially error
* situations where the {@link GitServlet} faces exceptions during request
* processing are tested
*/
public class GitServletResponseTests extends HttpTestCase {
private Repository srvRepo;
private URIish srvURI;
private GitServlet gs;
private long maxPackSize = 0; // the maximum pack file size used by
// the server
private PostReceiveHook postHook = null;
private PreReceiveHook preHook = null;
private ObjectChecker oc = null;
/**
* Setup a http server using {@link GitServlet}. Tests should be able to
* configure the maximum pack file size, the object checker and custom hooks
* just before they talk to the server.
*/
@Before
public void setUp() throws Exception {
super.setUp();
final TestRepository<Repository> srv = createTestRepository();
final String repoName = srv.getRepository().getDirectory().getName();
ServletContextHandler app = server.addContext("/git");
gs = new GitServlet();
gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
public Repository open(HttpServletRequest req, String name)
throws RepositoryNotFoundException,
ServiceNotEnabledException {
if (!name.equals(repoName))
throw new RepositoryNotFoundException(name);
final Repository db = srv.getRepository();
db.incrementOpen();
return db;
}
});
gs.setReceivePackFactory(new DefaultReceivePackFactory() {
public ReceivePack create(HttpServletRequest req, Repository db)
throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
ReceivePack recv = super.create(req, db);
if (maxPackSize > 0)
recv.setMaxPackSizeLimit(maxPackSize);
if (postHook != null)
recv.setPostReceiveHook(postHook);
if (preHook != null)
recv.setPreReceiveHook(preHook);
if (oc != null)
recv.setObjectChecker(oc);
return recv;
}
});
app.addServlet(new ServletHolder(gs), "/*");
server.setUp();
srvRepo = srv.getRepository();
srvURI = toURIish(app, repoName);
StoredConfig cfg = srvRepo.getConfig();
cfg.setBoolean("http", null, "receivepack", true);
cfg.save();
}
/**
* Configure a {@link GitServlet} that faces a {@link IllegalStateException}
* during executing preReceiveHooks. This used to lead to exceptions with a
* description of "invalid channel 101" on the client side. Make sure
* clients receive the correct response on the correct sideband.
*
* @throws Exception
*/
@Test
public void testRuntimeExceptionInPreReceiveHook() throws Exception {
final TestRepository client = createTestRepository();
final RevBlob Q_txt = client
.blob("some blob content to measure pack size");
final RevCommit Q = client.commit().add("Q", Q_txt).create();
final Repository clientRepo = client.getRepository();
final String srvBranchName = Constants.R_HEADS + "new.branch";
Transport t;
maxPackSize = 0;
postHook = null;
preHook = new PreReceiveHook() {
@Override
public void onPreReceive(ReceivePack rp,
Collection<ReceiveCommand> commands) {
throw new IllegalStateException();
}
};
t = Transport.open(clientRepo, srvURI);
try {
RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
srvBranchName, false, null, null);
try {
t.push(NullProgressMonitor.INSTANCE,
Collections.singleton(update));
fail("should not reach this line");
} catch (Exception e) {
assertTrue(e instanceof TransportException);
}
} finally {
t.close();
}
}
/**
* Configure a {@link GitServlet} that faces a {@link IllegalStateException}
* during executing objectChecking.
*
* @throws Exception
*/
@Test
public void testObjectCheckerException() throws Exception {
final TestRepository client = createTestRepository();
final RevBlob Q_txt = client
.blob("some blob content to measure pack size");
final RevCommit Q = client.commit().add("Q", Q_txt).create();
final Repository clientRepo = client.getRepository();
final String srvBranchName = Constants.R_HEADS + "new.branch";
Transport t;
maxPackSize = 0;
postHook = null;
preHook = null;
oc = new ObjectChecker() {
@Override
public void checkCommit(byte[] raw) throws CorruptObjectException {
throw new IllegalStateException();
}
};
t = Transport.open(clientRepo, srvURI);
try {
RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
srvBranchName, false, null, null);
try {
t.push(NullProgressMonitor.INSTANCE,
Collections.singleton(update));
fail("should not reach this line");
} catch (Exception e) {
assertTrue(e instanceof TransportException);
}
} finally {
t.close();
}
}
/**
* Configure a {@link GitServlet} that faces a {@link TooLargePackException}
* during persisting the pack and a {@link IllegalStateException} during
* executing postReceiveHooks. This used to lead to exceptions with a
* description of "invalid channel 101" on the client side. Make sure
* clients receive the correct response about the too large pack on the
* correct sideband.
*
* @throws Exception
*/
@Test
public void testUnpackErrorWithSubsequentExceptionInPostReceiveHook()
throws Exception {
final TestRepository client = createTestRepository();
final RevBlob Q_txt = client
.blob("some blob content to measure pack size");
final RevCommit Q = client.commit().add("Q", Q_txt).create();
final Repository clientRepo = client.getRepository();
final String srvBranchName = Constants.R_HEADS + "new.branch";
Transport t;
// this maxPackSize leads to an unPackError
maxPackSize = 400;
// this PostReceiveHook when called after an unsuccesfull unpack will
// lead to an IllegalStateException
postHook = new PostReceiveHook() {
public void onPostReceive(ReceivePack rp,
Collection<ReceiveCommand> commands) {
// the maxPackSize setting caused that the packfile couldn't be
// saved to disk. Calling getPackSize() now will lead to a
// IllegalStateException.
rp.getPackSize();
}
};
t = Transport.open(clientRepo, srvURI);
try {
RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
srvBranchName, false, null, null);
try {
t.push(NullProgressMonitor.INSTANCE,
Collections.singleton(update));
fail("should not reach this line");
} catch (Exception e) {
assertTrue(e instanceof TooLargePackException);
}
} finally {
t.close();
}
}
}

4
org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?> <?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform --> <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
<target name="jgit-4.5" sequenceNumber="1432590632"> <target name="jgit-4.5" sequenceNumber="1433163825">
<locations> <locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/> <unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/>
@ -57,7 +57,7 @@
<unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/> <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
<unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/> <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
<unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20150519210750/repository/"/> <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20150519210750/repository/"/>
</location> </location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="0.0.0"/> <unit id="org.eclipse.osgi" version="0.0.0"/>

2
org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd

@ -1,7 +1,7 @@
target "jgit-4.5" with source configurePhase target "jgit-4.5" with source configurePhase
include "projects/jetty-9.2.10.tpd" include "projects/jetty-9.2.10.tpd"
include "orbit/S20150519210750-Mars-RC2.tpd" include "orbit/R20150519210750-Mars.tpd"
location "http://download.eclipse.org/releases/mars/" { location "http://download.eclipse.org/releases/mars/" {
org.eclipse.osgi lazy org.eclipse.osgi lazy

4
org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150519210750-Mars-RC2.tpd → org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20150519210750-Mars.tpd

@ -1,7 +1,7 @@
target "S20141023165154-Mars-M3" with source configurePhase target "R20150519210750-Mars" with source configurePhase
// see http://download.eclipse.org/tools/orbit/downloads/ // see http://download.eclipse.org/tools/orbit/downloads/
location "http://download.eclipse.org/tools/orbit/downloads/drops/S20150519210750/repository/" { location "http://download.eclipse.org/tools/orbit/downloads/drops/R20150519210750/repository/" {
org.apache.ant [1.9.4.v201504302020,1.9.4.v201504302020] org.apache.ant [1.9.4.v201504302020,1.9.4.v201504302020]
org.apache.ant.source [1.9.4.v201504302020,1.9.4.v201504302020] org.apache.ant.source [1.9.4.v201504302020,1.9.4.v201504302020]
org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400] org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]

150
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java

@ -92,22 +92,22 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Ignore("Some versions of java.util.zip refuse to write an empty ZIP") @Ignore("Some versions of java.util.zip refuse to write an empty ZIP")
@Test @Test
public void testEmptyArchive() throws Exception { public void testEmptyArchive() throws Exception {
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip " + emptyTree, db); "git archive --format=zip " + emptyTree, db);
assertArrayEquals(new String[0], listZipEntries(result)); assertArrayEquals(new String[0], listZipEntries(result));
} }
@Test @Test
public void testEmptyTar() throws Exception { public void testEmptyTar() throws Exception {
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar " + emptyTree, db); "git archive --format=tar " + emptyTree, db);
assertArrayEquals(new String[0], listTarEntries(result)); assertArrayEquals(new String[0], listTarEntries(result));
} }
@Test @Test
public void testUnrecognizedFormat() throws Exception { public void testUnrecognizedFormat() throws Exception {
final String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" }; String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" };
final String[] actual = execute("git archive --format=nonsense " + emptyTree); String[] actual = execute("git archive --format=nonsense " + emptyTree);
assertArrayEquals(expect, actual); assertArrayEquals(expect, actual);
} }
@ -120,9 +120,9 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("c").call(); git.add().addFilepattern("c").call();
git.commit().setMessage("populate toplevel").call(); git.commit().setMessage("populate toplevel").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db);
assertArrayEquals(new String[] { "a", "c" }, // assertArrayEquals(new String[] { "a", "c" },
listZipEntries(result)); listZipEntries(result));
} }
@ -135,9 +135,9 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testDefaultFormatIsTar() throws Exception { public void testDefaultFormatIsTar() throws Exception {
commitGreeting(); commitGreeting();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive HEAD", db); "git archive HEAD", db);
assertArrayEquals(new String[] { "greeting" }, // assertArrayEquals(new String[] { "greeting" },
listTarEntries(result)); listTarEntries(result));
} }
@ -147,8 +147,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testFormatOverridesFilename() throws Exception { public void testFormatOverridesFilename() throws Exception {
final File archive = new File(db.getWorkTree(), "format-overrides-name.tar"); File archive = new File(db.getWorkTree(), "format-overrides-name.tar");
final String path = archive.getAbsolutePath(); String path = archive.getAbsolutePath();
commitGreeting(); commitGreeting();
assertArrayEquals(new String[] { "" }, assertArrayEquals(new String[] { "" },
@ -162,8 +162,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testUnrecognizedExtensionMeansTar() throws Exception { public void testUnrecognizedExtensionMeansTar() throws Exception {
final File archive = new File(db.getWorkTree(), "example.txt"); File archive = new File(db.getWorkTree(), "example.txt");
final String path = archive.getAbsolutePath(); String path = archive.getAbsolutePath();
commitGreeting(); commitGreeting();
assertArrayEquals(new String[] { "" }, assertArrayEquals(new String[] { "" },
@ -176,8 +176,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testNoExtensionMeansTar() throws Exception { public void testNoExtensionMeansTar() throws Exception {
final File archive = new File(db.getWorkTree(), "example"); File archive = new File(db.getWorkTree(), "example");
final String path = archive.getAbsolutePath(); String path = archive.getAbsolutePath();
commitGreeting(); commitGreeting();
assertArrayEquals(new String[] { "" }, assertArrayEquals(new String[] { "" },
@ -189,8 +189,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testExtensionMatchIsAnchored() throws Exception { public void testExtensionMatchIsAnchored() throws Exception {
final File archive = new File(db.getWorkTree(), "two-extensions.zip.bak"); File archive = new File(db.getWorkTree(), "two-extensions.zip.bak");
final String path = archive.getAbsolutePath(); String path = archive.getAbsolutePath();
commitGreeting(); commitGreeting();
assertArrayEquals(new String[] { "" }, assertArrayEquals(new String[] { "" },
@ -202,8 +202,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testZipExtension() throws Exception { public void testZipExtension() throws Exception {
final File archiveWithDot = new File(db.getWorkTree(), "greeting.zip"); File archiveWithDot = new File(db.getWorkTree(), "greeting.zip");
final File archiveNoDot = new File(db.getWorkTree(), "greetingzip"); File archiveNoDot = new File(db.getWorkTree(), "greetingzip");
commitGreeting(); commitGreeting();
execute("git archive " + execute("git archive " +
@ -218,8 +218,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testTarExtension() throws Exception { public void testTarExtension() throws Exception {
final File archive = new File(db.getWorkTree(), "tarball.tar"); File archive = new File(db.getWorkTree(), "tarball.tar");
final String path = archive.getAbsolutePath(); String path = archive.getAbsolutePath();
commitGreeting(); commitGreeting();
assertArrayEquals(new String[] { "" }, assertArrayEquals(new String[] { "" },
@ -234,8 +234,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
commitGreeting(); commitGreeting();
for (String ext : Arrays.asList("tar.gz", "tgz")) { for (String ext : Arrays.asList("tar.gz", "tgz")) {
final File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext); File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
final File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext); File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
execute("git archive " + execute("git archive " +
shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " + shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
@ -253,8 +253,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
commitGreeting(); commitGreeting();
for (String ext : Arrays.asList("tar.bz2", "tbz", "tbz2")) { for (String ext : Arrays.asList("tar.bz2", "tbz", "tbz2")) {
final File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext); File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
final File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext); File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
execute("git archive " + execute("git archive " +
shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " + shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
@ -272,8 +272,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
commitGreeting(); commitGreeting();
for (String ext : Arrays.asList("tar.xz", "txz")) { for (String ext : Arrays.asList("tar.xz", "txz")) {
final File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext); File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
final File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext); File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
execute("git archive " + execute("git archive " +
shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " + shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
@ -302,7 +302,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call(); git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call(); git.commit().setMessage("add subdir").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip master", db); "git archive --format=zip master", db);
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -328,7 +328,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call(); git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call(); git.commit().setMessage("add subdir").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar master", db); "git archive --format=tar master", db);
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -390,7 +390,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception { public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception {
commitFoo(); commitFoo();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=x// --format=tar master", db); "git archive --prefix=x// --format=tar master", db);
String[] expect = { "x//foo" }; String[] expect = { "x//foo" };
assertArrayEquals(expect, listTarEntries(result)); assertArrayEquals(expect, listTarEntries(result));
@ -421,7 +421,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testTarPrefixWithoutTrailingSlash() throws Exception { public void testTarPrefixWithoutTrailingSlash() throws Exception {
commitBazAndFooSlashBar(); commitBazAndFooSlashBar();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=my- --format=tar master", db); "git archive --prefix=my- --format=tar master", db);
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -441,7 +441,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call(); git.commit().setMessage("add submodule").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip master", db); "git archive --format=zip master", db);
String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -461,7 +461,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call(); git.commit().setMessage("add submodule").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar master", db); "git archive --format=tar master", db);
String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -491,7 +491,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.commit().setMessage("three files with different modes").call(); git.commit().setMessage("three files with different modes").call();
final byte[] zipData = CLIGitCommand.rawExecute( // byte[] zipData = CLIGitCommand.rawExecute(
"git archive --format=zip master", db); "git archive --format=zip master", db);
writeRaw("zip-with-modes.zip", zipData); writeRaw("zip-with-modes.zip", zipData);
assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain"); assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain");
@ -520,7 +520,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.commit().setMessage("three files with different modes").call(); git.commit().setMessage("three files with different modes").call();
final byte[] archive = CLIGitCommand.rawExecute( // byte[] archive = CLIGitCommand.rawExecute(
"git archive --format=tar master", db); "git archive --format=tar master", db);
writeRaw("with-modes.tar", archive); writeRaw("with-modes.tar", archive);
assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain"); assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain");
@ -532,7 +532,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testArchiveWithLongFilename() throws Exception { public void testArchiveWithLongFilename() throws Exception {
String filename = ""; String filename = "";
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
filename = filename + "1234567890/"; filename = filename + "1234567890/";
l.add(filename); l.add(filename);
@ -543,7 +543,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call(); git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call(); git.commit().setMessage("file with long name").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db);
assertArrayEquals(l.toArray(new String[l.size()]), assertArrayEquals(l.toArray(new String[l.size()]),
listZipEntries(result)); listZipEntries(result));
@ -552,7 +552,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testTarWithLongFilename() throws Exception { public void testTarWithLongFilename() throws Exception {
String filename = ""; String filename = "";
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
filename = filename + "1234567890/"; filename = filename + "1234567890/";
l.add(filename); l.add(filename);
@ -563,7 +563,7 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call(); git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call(); git.commit().setMessage("file with long name").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar HEAD", db); "git archive --format=tar HEAD", db);
assertArrayEquals(l.toArray(new String[l.size()]), assertArrayEquals(l.toArray(new String[l.size()]),
listTarEntries(result)); listTarEntries(result));
@ -571,34 +571,34 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testArchivePreservesContent() throws Exception { public void testArchivePreservesContent() throws Exception {
final String payload = "“The quick brown fox jumps over the lazy dog!”"; String payload = "“The quick brown fox jumps over the lazy dog!”";
writeTrashFile("xyzzy", payload); writeTrashFile("xyzzy", payload);
git.add().addFilepattern("xyzzy").call(); git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call(); git.commit().setMessage("add file with content").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db);
assertArrayEquals(new String[] { payload }, // assertArrayEquals(new String[] { payload },
zipEntryContent(result, "xyzzy")); zipEntryContent(result, "xyzzy"));
} }
@Test @Test
public void testTarPreservesContent() throws Exception { public void testTarPreservesContent() throws Exception {
final String payload = "“The quick brown fox jumps over the lazy dog!”"; String payload = "“The quick brown fox jumps over the lazy dog!”";
writeTrashFile("xyzzy", payload); writeTrashFile("xyzzy", payload);
git.add().addFilepattern("xyzzy").call(); git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call(); git.commit().setMessage("add file with content").call();
final byte[] result = CLIGitCommand.rawExecute( // byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar HEAD", db); "git archive --format=tar HEAD", db);
assertArrayEquals(new String[] { payload }, // assertArrayEquals(new String[] { payload },
tarEntryContent(result, "xyzzy")); tarEntryContent(result, "xyzzy"));
} }
private Process spawnAssumingCommandPresent(String... cmdline) { private Process spawnAssumingCommandPresent(String... cmdline) {
final File cwd = db.getWorkTree(); File cwd = db.getWorkTree();
final ProcessBuilder procBuilder = new ProcessBuilder(cmdline) // ProcessBuilder procBuilder = new ProcessBuilder(cmdline)
.directory(cwd) // .directory(cwd)
.redirectErrorStream(true); .redirectErrorStream(true);
Process proc = null; Process proc = null;
try { try {
@ -612,15 +612,15 @@ public class ArchiveTest extends CLIRepositoryTestCase {
} }
private BufferedReader readFromProcess(Process proc) throws Exception { private BufferedReader readFromProcess(Process proc) throws Exception {
return new BufferedReader( // return new BufferedReader(
new InputStreamReader(proc.getInputStream(), "UTF-8")); new InputStreamReader(proc.getInputStream(), "UTF-8"));
} }
private void grepForEntry(String name, String mode, String... cmdline) // private void grepForEntry(String name, String mode, String... cmdline)
throws Exception { throws Exception {
final Process proc = spawnAssumingCommandPresent(cmdline); Process proc = spawnAssumingCommandPresent(cmdline);
proc.getOutputStream().close(); proc.getOutputStream().close();
final BufferedReader reader = readFromProcess(proc); BufferedReader reader = readFromProcess(proc);
try { try {
String line; String line;
while ((line = reader.readLine()) != null) while ((line = reader.readLine()) != null)
@ -672,20 +672,20 @@ public class ArchiveTest extends CLIRepositoryTestCase {
assertMagic(new byte[] { (byte) 0xfd, '7', 'z', 'X', 'Z', 0 }, file); assertMagic(new byte[] { (byte) 0xfd, '7', 'z', 'X', 'Z', 0 }, file);
} }
private void assertContainsEntryWithMode(String zipFilename, String mode, String name) // private void assertContainsEntryWithMode(String zipFilename, String mode, String name)
throws Exception { throws Exception {
grepForEntry(name, mode, "zipinfo", zipFilename); grepForEntry(name, mode, "zipinfo", zipFilename);
} }
private void assertTarContainsEntry(String tarfile, String mode, String name) // private void assertTarContainsEntry(String tarfile, String mode, String name)
throws Exception { throws Exception {
grepForEntry(name, mode, "tar", "tvf", tarfile); grepForEntry(name, mode, "tar", "tvf", tarfile);
} }
private void writeRaw(String filename, byte[] data) // private void writeRaw(String filename, byte[] data)
throws IOException { throws IOException {
final File path = new File(db.getWorkTree(), filename); File path = new File(db.getWorkTree(), filename);
final OutputStream out = new FileOutputStream(path); OutputStream out = new FileOutputStream(path);
try { try {
out.write(data); out.write(data);
} finally { } finally {
@ -694,8 +694,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
} }
private static String[] listZipEntries(byte[] zipData) throws IOException { private static String[] listZipEntries(byte[] zipData) throws IOException {
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
final ZipInputStream in = new ZipInputStream( // ZipInputStream in = new ZipInputStream(
new ByteArrayInputStream(zipData)); new ByteArrayInputStream(zipData));
ZipEntry e; ZipEntry e;
@ -706,9 +706,9 @@ public class ArchiveTest extends CLIRepositoryTestCase {
} }
private static Future<Object> writeAsync(final OutputStream stream, final byte[] data) { private static Future<Object> writeAsync(final OutputStream stream, final byte[] data) {
final ExecutorService executor = Executors.newSingleThreadExecutor(); ExecutorService executor = Executors.newSingleThreadExecutor();
return executor.submit(new Callable<Object>() { // return executor.submit(new Callable<Object>() {
public Object call() throws IOException { public Object call() throws IOException {
try { try {
stream.write(data); stream.write(data);
@ -721,13 +721,13 @@ public class ArchiveTest extends CLIRepositoryTestCase {
} }
private String[] listTarEntries(byte[] tarData) throws Exception { private String[] listTarEntries(byte[] tarData) throws Exception {
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
final Process proc = spawnAssumingCommandPresent("tar", "tf", "-"); Process proc = spawnAssumingCommandPresent("tar", "tf", "-");
final BufferedReader reader = readFromProcess(proc); BufferedReader reader = readFromProcess(proc);
final OutputStream out = proc.getOutputStream(); OutputStream out = proc.getOutputStream();
// Dump tarball to tar stdin in background // Dump tarball to tar stdin in background
final Future<?> writing = writeAsync(out, tarData); Future<?> writing = writeAsync(out, tarData);
try { try {
String line; String line;
@ -742,9 +742,9 @@ public class ArchiveTest extends CLIRepositoryTestCase {
} }
} }
private static String[] zipEntryContent(byte[] zipData, String path) // private static String[] zipEntryContent(byte[] zipData, String path)
throws IOException { throws IOException {
final ZipInputStream in = new ZipInputStream( // ZipInputStream in = new ZipInputStream(
new ByteArrayInputStream(zipData)); new ByteArrayInputStream(zipData));
ZipEntry e; ZipEntry e;
while ((e = in.getNextEntry()) != null) { while ((e = in.getNextEntry()) != null) {
@ -752,8 +752,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
continue; continue;
// found! // found!
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
final BufferedReader reader = new BufferedReader( // BufferedReader reader = new BufferedReader(
new InputStreamReader(in, "UTF-8")); new InputStreamReader(in, "UTF-8"));
String line; String line;
while ((line = reader.readLine()) != null) while ((line = reader.readLine()) != null)
@ -765,13 +765,13 @@ public class ArchiveTest extends CLIRepositoryTestCase {
return null; return null;
} }
private String[] tarEntryContent(byte[] tarData, String path) // private String[] tarEntryContent(byte[] tarData, String path)
throws Exception { throws Exception {
final List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
final Process proc = spawnAssumingCommandPresent("tar", "Oxf", "-", path); Process proc = spawnAssumingCommandPresent("tar", "Oxf", "-", path);
final BufferedReader reader = readFromProcess(proc); BufferedReader reader = readFromProcess(proc);
final OutputStream out = proc.getOutputStream(); OutputStream out = proc.getOutputStream();
final Future<?> writing = writeAsync(out, tarData); Future<?> writing = writeAsync(out, tarData);
try { try {
String line; String line;

1
org.eclipse.jgit.test/.classpath

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry excluding="**/*.idx|**/*.pack" kind="src" path="tst"/> <classpathentry excluding="**/*.idx|**/*.pack" kind="src" path="tst"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="tst-rsrc"/> <classpathentry kind="src" path="tst-rsrc"/>
<classpathentry kind="src" path="exttst"/> <classpathentry kind="src" path="exttst"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>

1
org.eclipse.jgit.test/pom.xml

@ -102,6 +102,7 @@
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>src/</sourceDirectory>
<testSourceDirectory>tst/</testSourceDirectory> <testSourceDirectory>tst/</testSourceDirectory>
<testResources> <testResources>

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/Sets.java → org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java

@ -41,13 +41,13 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.lib;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
class Sets { public class Sets {
static <T> Set<T> of(T... elements) { public static <T> Set<T> of(T... elements) {
Set<T> ret = new HashSet<T>(); Set<T> ret = new HashSet<T>();
for (T element : elements) for (T element : elements)
ret.add(element); ret.add(element);

11
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java

@ -514,6 +514,17 @@ public class CommitCommandTest extends RepositoryTestCase {
} }
} }
@Test
public void commitOnlyShouldHandleIgnored() throws Exception {
try (Git git = new Git(db)) {
writeTrashFile("subdir/foo", "Hello World");
writeTrashFile("subdir/bar", "Hello World");
writeTrashFile(".gitignore", "bar");
git.add().addFilepattern("subdir").call();
git.commit().setOnly("subdir").setMessage("first commit").call();
}
}
private static void addUnmergedEntry(String file, DirCacheBuilder builder) { private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1); DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1);
DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2); DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2);

1
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java

@ -62,6 +62,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;

1
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java

@ -53,6 +53,7 @@ import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException; import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Sets;
import org.junit.Test; import org.junit.Test;
public class StatusCommandTest extends RepositoryTestCase { public class StatusCommandTest extends RepositoryTestCase {

12
org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java

@ -87,9 +87,9 @@ public class ManifestParserTest {
for (RepoProject proj : parser.getProjects()) { for (RepoProject proj : parser.getProjects()) {
String msg = String.format( String msg = String.format(
"project \"%s\" should be included in unfiltered projects", "project \"%s\" should be included in unfiltered projects",
proj.path); proj.getPath());
assertTrue(msg, results.contains(proj.path)); assertTrue(msg, results.contains(proj.getPath()));
results.remove(proj.path); results.remove(proj.getPath());
} }
assertTrue( assertTrue(
"Unfiltered projects shouldn't contain any unexpected results", "Unfiltered projects shouldn't contain any unexpected results",
@ -101,9 +101,9 @@ public class ManifestParserTest {
for (RepoProject proj : parser.getFilteredProjects()) { for (RepoProject proj : parser.getFilteredProjects()) {
String msg = String.format( String msg = String.format(
"project \"%s\" should be included in filtered projects", "project \"%s\" should be included in filtered projects",
proj.path); proj.getPath());
assertTrue(msg, results.contains(proj.path)); assertTrue(msg, results.contains(proj.getPath()));
results.remove(proj.path); results.remove(proj.getPath());
} }
assertTrue( assertTrue(
"Filtered projects shouldn't contain any unexpected results", "Filtered projects shouldn't contain any unexpected results",

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java

@ -123,7 +123,7 @@ public class PackFileTest extends LocalDiskRepositoryTestCase {
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
if (wc != null) if (wc != null)
wc.release(); wc.close();
new WindowCacheConfig().install(); new WindowCacheConfig().install();
super.tearDown(); super.tearDown();
} }

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java

@ -108,7 +108,7 @@ public class UnpackedObjectTest extends LocalDiskRepositoryTestCase {
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
if (wc != null) if (wc != null)
wc.release(); wc.close();
new WindowCacheConfig().install(); new WindowCacheConfig().install();
super.tearDown(); super.tearDown();
} }

186
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkFilterTest.java

@ -0,0 +1,186 @@
/*
* Copyright (C) 2015, Google Inc.
* 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;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.filter.MessageRevFilter;
import org.eclipse.jgit.revwalk.filter.NotRevFilter;
import org.eclipse.jgit.revwalk.filter.ObjectFilter;
import java.io.IOException;
import java.util.Set;
public class ObjectWalkFilterTest {
private TestRepository<InMemoryRepository> tr;
private ObjectWalk rw;
// 3 commits, 2 top-level trees, 4 subtrees, 3 blobs
private static final int OBJECT_COUNT = 12;
@Before
public void setUp() throws Exception {
tr = new TestRepository<>(new InMemoryRepository(
new DfsRepositoryDescription("test")));
rw = new ObjectWalk(tr.getRepository());
rw.markStart(tr.branch("master").commit()
.add("a/a", "1")
.add("b/b", "2")
.add("c/c", "3")
.message("initial commit")
.child()
.rm("a/a")
.add("a/A", "1")
.message("capitalize a/a")
.child()
.rm("a/A")
.add("a/a", "1")
.message("make a/A lowercase again")
.create());
}
@After
public void tearDown() {
rw.close();
tr.getRepository().close();
}
private static class BlacklistObjectFilter extends ObjectFilter {
final Set<AnyObjectId> badObjects;
BlacklistObjectFilter(Set<AnyObjectId> badObjects) {
this.badObjects = badObjects;
}
@Override
public boolean include(ObjectWalk walker, AnyObjectId o) {
return !badObjects.contains(o);
}
}
private AnyObjectId resolve(String revstr) throws Exception {
return tr.getRepository().resolve(revstr);
}
private int countObjects() throws IOException {
int n = 0;
while (rw.next() != null) {
n++;
}
while (rw.nextObject() != null) {
n++;
}
return n;
}
@Test
public void testDefaultFilter() throws Exception {
assertTrue("filter is ALL",
rw.getObjectFilter() == ObjectFilter.ALL);
assertEquals(OBJECT_COUNT, countObjects());
}
@Test
public void testObjectFilterCanFilterOutBlob() throws Exception {
AnyObjectId one = rw.parseAny(resolve("master:a/a"));
AnyObjectId two = rw.parseAny(resolve("master:b/b"));
rw.setObjectFilter(new BlacklistObjectFilter(Sets.of(one, two)));
// 2 blobs filtered out
assertEquals(OBJECT_COUNT - 2, countObjects());
}
@Test
public void testFilteringCommitsHasNoEffect() throws Exception {
AnyObjectId initial = rw.parseCommit(resolve("master^^"));
rw.setObjectFilter(new BlacklistObjectFilter(Sets.of(initial)));
assertEquals(OBJECT_COUNT, countObjects());
}
@Test
public void testRevFilterAndObjectFilterCanCombine() throws Exception {
AnyObjectId one = rw.parseAny(resolve("master:a/a"));
AnyObjectId two = rw.parseAny(resolve("master:b/b"));
rw.setObjectFilter(new BlacklistObjectFilter(Sets.of(one, two)));
rw.setRevFilter(NotRevFilter.create(
MessageRevFilter.create("capitalize")));
// 2 blobs, one commit, two trees filtered out
assertEquals(OBJECT_COUNT - 5, countObjects());
}
@Test
public void testFilteringTreeFiltersSubtrees() throws Exception {
AnyObjectId capitalizeTree = rw.parseAny(resolve("master^:"));
rw.setObjectFilter(new BlacklistObjectFilter(
Sets.of(capitalizeTree)));
// trees "master^:" and "master^:a" filtered out
assertEquals(OBJECT_COUNT - 2, countObjects());
}
@Test
public void testFilteringTreeFiltersReferencedBlobs() throws Exception {
AnyObjectId a1 = rw.parseAny(resolve("master:a"));
AnyObjectId a2 = rw.parseAny(resolve("master^:a"));
rw.setObjectFilter(new BlacklistObjectFilter(Sets.of(a1, a2)));
// 2 trees, one blob filtered out
assertEquals(OBJECT_COUNT - 3, countObjects());
}
}

3
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties

@ -181,7 +181,7 @@ corruptObjectTruncatedInObjectId=truncated in object id
couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts
couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen
couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen
couldNotGetAdvertisedRef=Could not get advertised Ref for branch {0} 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 couldNotGetRepoStatistics=Could not get repository statistics
couldNotLockHEAD=Could not lock HEAD couldNotLockHEAD=Could not lock HEAD
couldNotReadIndexInOneGo=Could not read index in one go, only {0} out of {1} read couldNotReadIndexInOneGo=Could not read index in one go, only {0} out of {1} read
@ -257,6 +257,7 @@ exceptionCaughtDuringExecutionOfResetCommand=Exception caught during execution o
exceptionCaughtDuringExecutionOfRevertCommand=Exception caught during execution of revert command. {0} exceptionCaughtDuringExecutionOfRevertCommand=Exception caught during execution of revert command. {0}
exceptionCaughtDuringExecutionOfRmCommand=Exception caught during execution of rm command exceptionCaughtDuringExecutionOfRmCommand=Exception caught during execution of rm command
exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of tag command exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of tag command
exceptionCaughtDuringExcecutionOfCommand=Exception caught during execution of command {0} in {1}
exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted. exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted.
exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command
exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1} exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1}

19
org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java

@ -364,19 +364,20 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
} }
private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) { private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
final String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$ try {
try (final TreeWalk walk = new TreeWalk(repo)) { try (TreeWalk walk = new TreeWalk(repo);
final T outa = fmt.createArchiveOutputStream(out, formatOptions); RevWalk rw = new RevWalk(walk.getObjectReader())) {
try (final RevWalk rw = new RevWalk(walk.getObjectReader())) { String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$
final MutableObjectId idBuf = new MutableObjectId(); T outa = fmt.createArchiveOutputStream(out, formatOptions);
final ObjectReader reader = walk.getObjectReader(); MutableObjectId idBuf = new MutableObjectId();
ObjectReader reader = walk.getObjectReader();
walk.reset(rw.parseTree(tree)); walk.reset(rw.parseTree(tree));
if (!paths.isEmpty()) if (!paths.isEmpty())
walk.setFilter(PathFilterGroup.createFromStrings(paths)); walk.setFilter(PathFilterGroup.createFromStrings(paths));
while (walk.next()) { while (walk.next()) {
final String name = pfx + walk.getPathString(); String name = pfx + walk.getPathString();
FileMode mode = walk.getFileMode(0); FileMode mode = walk.getFileMode(0);
if (walk.isSubtree()) if (walk.isSubtree())
@ -395,10 +396,10 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
fmt.putEntry(outa, name, mode, reader.open(idBuf)); fmt.putEntry(outa, name, mode, reader.open(idBuf));
} }
outa.close(); outa.close();
return out;
} finally { } finally {
out.close(); out.close();
} }
return out;
} catch (IOException e) { } catch (IOException e) {
// TODO(jrn): Throw finer-grained errors. // TODO(jrn): Throw finer-grained errors.
throw new JGitInternalException( throw new JGitInternalException(
@ -413,7 +414,7 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
public OutputStream call() throws GitAPIException { public OutputStream call() throws GitAPIException {
checkCallable(); checkCallable();
final Format<?> fmt; Format<?> fmt;
if (format == null) if (format == null)
fmt = formatBySuffix(suffix); fmt = formatBySuffix(suffix);
else else

2
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java

@ -358,7 +358,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
// check if entry refers to a tracked file // check if entry refers to a tracked file
boolean tracked = dcTree != null || hTree != null; boolean tracked = dcTree != null || hTree != null;
if (!tracked) if (!tracked)
break; continue;
// for an unmerged path, DirCacheBuildIterator will yield 3 // for an unmerged path, DirCacheBuildIterator will yield 3
// entries, we only want to add one // entries, we only want to add one

14
org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java

@ -54,6 +54,7 @@ import org.eclipse.jgit.api.errors.InvalidConfigurationException;
import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoHeadException; 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.RefNotFoundException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
@ -171,6 +172,7 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
* @throws InvalidRemoteException * @throws InvalidRemoteException
* @throws CanceledException * @throws CanceledException
* @throws RefNotFoundException * @throws RefNotFoundException
* @throws RefNotAdvertisedException
* @throws NoHeadException * @throws NoHeadException
* @throws org.eclipse.jgit.api.errors.TransportException * @throws org.eclipse.jgit.api.errors.TransportException
* @throws GitAPIException * @throws GitAPIException
@ -178,7 +180,7 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
public PullResult call() throws GitAPIException, public PullResult call() throws GitAPIException,
WrongRepositoryStateException, InvalidConfigurationException, WrongRepositoryStateException, InvalidConfigurationException,
DetachedHeadException, InvalidRemoteException, CanceledException, DetachedHeadException, InvalidRemoteException, CanceledException,
RefNotFoundException, NoHeadException, RefNotFoundException, RefNotAdvertisedException, NoHeadException,
org.eclipse.jgit.api.errors.TransportException { org.eclipse.jgit.api.errors.TransportException {
checkCallable(); checkCallable();
@ -284,11 +286,13 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> {
r = fetchRes.getAdvertisedRef(Constants.R_HEADS r = fetchRes.getAdvertisedRef(Constants.R_HEADS
+ remoteBranchName); + remoteBranchName);
} }
if (r == null) if (r == null) {
throw new JGitInternalException(MessageFormat.format(JGitText throw new RefNotAdvertisedException(MessageFormat.format(
.get().couldNotGetAdvertisedRef, remoteBranchName)); JGitText.get().couldNotGetAdvertisedRef, remote,
else remoteBranchName));
} else {
commitToMerge = r.getObjectId(); commitToMerge = r.getObjectId();
}
} else { } else {
try { try {
commitToMerge = repo.resolve(remoteBranchName); commitToMerge = repo.resolve(remoteBranchName);

4
org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java

@ -55,6 +55,7 @@ import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TooLargePackException;
import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -156,6 +157,9 @@ public class PushCommand extends
PushResult result = transport.push(monitor, toPush, out); PushResult result = transport.push(monitor, toPush, out);
pushResults.add(result); pushResults.add(result);
} catch (TooLargePackException e) {
throw new org.eclipse.jgit.api.errors.TooLargePackException(
e.getMessage(), e);
} catch (TransportException e) { } catch (TransportException e) {
throw new org.eclipse.jgit.api.errors.TransportException( throw new org.eclipse.jgit.api.errors.TransportException(
e.getMessage(), e); e.getMessage(), e);

54
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotAdvertisedException.java

@ -0,0 +1,54 @@
/*
* Copyright (C) 2015,Matthias Sohn <matthias.sohn@sap.com> 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.api.errors;
/**
* Thrown when a ref is not found in advertised refs
*
* @since 4.0
*/
public class RefNotAdvertisedException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param message
*/
public RefNotAdvertisedException(String message) {
super(message);
}
}

65
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargePackException.java

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com> 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.api.errors;
/**
* Exception thrown when the server rejected a too large pack
*
* @since 4.0
*/
public class TooLargePackException extends TransportException {
private static final long serialVersionUID = 1L;
/**
* @param msg
* message describing the transport failure.
*/
public TooLargePackException(String msg) {
super(msg);
}
/**
* @param msg
* message describing the transport exception.
* @param cause
* why the transport failed.
*/
public TooLargePackException(String msg, Throwable cause) {
super(msg, cause);
}
}

1
org.eclipse.jgit/src/org/eclipse/jgit/diff/MyersDiff.java

@ -114,6 +114,7 @@ import org.eclipse.jgit.util.LongList;
public class MyersDiff<S extends Sequence> { public class MyersDiff<S extends Sequence> {
/** Singleton instance of MyersDiff. */ /** Singleton instance of MyersDiff. */
public static final DiffAlgorithm INSTANCE = new LowLevelDiffAlgorithm() { public static final DiffAlgorithm INSTANCE = new LowLevelDiffAlgorithm() {
@SuppressWarnings("unused")
@Override @Override
public <S extends Sequence> void diffNonCommon(EditList edits, public <S extends Sequence> void diffNonCommon(EditList edits,
HashedSequenceComparator<S> cmp, HashedSequence<S> a, HashedSequenceComparator<S> cmp, HashedSequence<S> a,

52
org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java

@ -63,10 +63,13 @@ import org.eclipse.jgit.lib.ObjectStream;
* will not exceed 1 MiB per instance. The index starts out at a smaller size * will not exceed 1 MiB per instance. The index starts out at a smaller size
* (closer to 2 KiB), but may grow as more distinct blocks within the scanned * (closer to 2 KiB), but may grow as more distinct blocks within the scanned
* file are discovered. * file are discovered.
*
* @since 4.0
*/ */
class SimilarityIndex { public class SimilarityIndex {
/** A special {@link TableFullException} used in place of OutOfMemoryError. */ /** A special {@link TableFullException} used in place of OutOfMemoryError. */
private static final TableFullException TABLE_FULL_OUT_OF_MEMORY = new TableFullException(); public static final TableFullException
TABLE_FULL_OUT_OF_MEMORY = new TableFullException();
/** /**
* Shift to apply before storing a key. * Shift to apply before storing a key.
@ -105,6 +108,26 @@ class SimilarityIndex {
/** {@code idHash.length == 1 << idHashBits}. */ /** {@code idHash.length == 1 << idHashBits}. */
private int idHashBits; private int idHashBits;
/**
* Create a new similarity index for the given object
*
* @param obj
* the object to hash
* @return similarity index for this object
* @throws IOException
* file contents cannot be read from the repository.
* @throws TableFullException
* object hashing overflowed the storage capacity of the
* SimilarityIndex.
*/
public static SimilarityIndex create(ObjectLoader obj) throws IOException,
TableFullException {
SimilarityIndex idx = new SimilarityIndex();
idx.hash(obj);
idx.sort();
return idx;
}
SimilarityIndex() { SimilarityIndex() {
idHashBits = 8; idHashBits = 8;
idHash = new long[1 << idHashBits]; idHash = new long[1 << idHashBits];
@ -212,7 +235,27 @@ class SimilarityIndex {
Arrays.sort(idHash); Arrays.sort(idHash);
} }
int score(SimilarityIndex dst, int maxScore) { /**
* Compute the similarity score between this index and another.
* <p>
* A region of a file is defined as a line in a text file or a fixed-size
* block in a binary file. To prepare an index, each region in the file is
* hashed; the values and counts of hashes are retained in a sorted table.
* Define the similarity fraction F as the the count of matching regions
* between the two files divided between the maximum count of regions in
* either file. The similarity score is F multiplied by the maxScore
* constant, yielding a range [0, maxScore]. It is defined as maxScore for
* the degenerate case of two empty files.
* <p>
* The similarity score is symmetrical; i.e. a.score(b) == b.score(a).
*
* @param dst
* the other index
* @param maxScore
* the score representing a 100% match
* @return the similarity score
*/
public int score(SimilarityIndex dst, int maxScore) {
long max = Math.max(hashedCnt, dst.hashedCnt); long max = Math.max(hashedCnt, dst.hashedCnt);
if (max == 0) if (max == 0)
return maxScore; return maxScore;
@ -381,7 +424,8 @@ class SimilarityIndex {
return v & MAX_COUNT; return v & MAX_COUNT;
} }
static class TableFullException extends Exception { /** Thrown by {@code create()} when file is too large. */
public static class TableFullException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }
} }

1
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java vendored

@ -1192,6 +1192,7 @@ public class DirCacheCheckout {
entry.setLastModified(f.lastModified()); entry.setLastModified(f.lastModified());
} }
@SuppressWarnings("deprecation")
private static void checkValidPath(CanonicalTreeParser t) private static void checkValidPath(CanonicalTreeParser t)
throws InvalidPathException { throws InvalidPathException {
ObjectChecker chk = new ObjectChecker() ObjectChecker chk = new ObjectChecker()

17
org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargePackException.java

@ -43,17 +43,17 @@
package org.eclipse.jgit.errors; package org.eclipse.jgit.errors;
import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.transport.URIish;
/** /**
* Thrown when a pack exceeds a given size limit * Thrown when a pack exceeds a given size limit
* *
* @since 3.3 * @since 3.3
*/ */
public class TooLargePackException extends IOException { public class TooLargePackException extends TransportException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -66,4 +66,17 @@ public class TooLargePackException extends IOException {
super(MessageFormat.format(JGitText.get().receivePackTooLarge, super(MessageFormat.format(JGitText.get().receivePackTooLarge,
Long.valueOf(packSizeLimit))); Long.valueOf(packSizeLimit)));
} }
/**
* Construct a too large pack exception.
*
* @param uri
* URI used for transport
* @param s
* message
* @since 4.0
*/
public TooLargePackException(URIish uri, String s) {
super(uri.setPass(null) + ": " + s); //$NON-NLS-1$
}
} }

10
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java

@ -205,7 +205,7 @@ public class ManifestParser extends DefaultHandler {
throw new SAXException(RepoText.get().invalidManifest); throw new SAXException(RepoText.get().invalidManifest);
currentProject.addCopyFile(new CopyFile( currentProject.addCopyFile(new CopyFile(
rootRepo, rootRepo,
currentProject.path, currentProject.getPath(),
attributes.getValue("src"), //$NON-NLS-1$ attributes.getValue("src"), //$NON-NLS-1$
attributes.getValue("dest"))); //$NON-NLS-1$ attributes.getValue("dest"))); //$NON-NLS-1$
} else if ("include".equals(qName)) { //$NON-NLS-1$ } else if ("include".equals(qName)) { //$NON-NLS-1$
@ -266,7 +266,7 @@ public class ManifestParser extends DefaultHandler {
throw new SAXException(e); throw new SAXException(e);
} }
for (RepoProject proj : projects) { for (RepoProject proj : projects) {
String remote = proj.remote; String remote = proj.getRemote();
if (remote == null) { if (remote == null) {
if (defaultRemote == null) { if (defaultRemote == null) {
if (filename != null) if (filename != null)
@ -286,7 +286,7 @@ public class ManifestParser extends DefaultHandler {
remoteUrl = remoteUrl + "/"; //$NON-NLS-1$ remoteUrl = remoteUrl + "/"; //$NON-NLS-1$
remoteUrls.put(remote, remoteUrl); remoteUrls.put(remote, remoteUrl);
} }
proj.setUrl(remoteUrl + proj.name) proj.setUrl(remoteUrl + proj.getName())
.setDefaultRevision(defaultRevision); .setDefaultRevision(defaultRevision);
} }
@ -339,7 +339,7 @@ public class ManifestParser extends DefaultHandler {
boolean inGroups(RepoProject proj) { boolean inGroups(RepoProject proj) {
for (String group : minusGroups) { for (String group : minusGroups) {
if (proj.groups.contains(group)) { if (proj.inGroup(group)) {
// minus groups have highest priority. // minus groups have highest priority.
return false; return false;
} }
@ -349,7 +349,7 @@ public class ManifestParser extends DefaultHandler {
return true; return true;
} }
for (String group : plusGroups) { for (String group : plusGroups) {
if (proj.groups.contains(group)) if (proj.inGroup(group))
return true; return true;
} }
return false; return false;

22
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java

@ -379,10 +379,10 @@ public class RepoCommand extends GitCommand<RevCommit> {
try { try {
parser.read(inputStream); parser.read(inputStream);
for (RepoProject proj : parser.getFilteredProjects()) { for (RepoProject proj : parser.getFilteredProjects()) {
addSubmodule(proj.url, addSubmodule(proj.getUrl(),
proj.path, proj.getPath(),
proj.getRevision(), proj.getRevision(),
proj.copyfiles); proj.getCopyFiles());
} }
} catch (GitAPIException | IOException e) { } catch (GitAPIException | IOException e) {
throw new ManifestErrorException(e); throw new ManifestErrorException(e);
@ -403,17 +403,17 @@ public class RepoCommand extends GitCommand<RevCommit> {
try (RevWalk rw = new RevWalk(repo)) { try (RevWalk rw = new RevWalk(repo)) {
Config cfg = new Config(); Config cfg = new Config();
for (RepoProject proj : bareProjects) { for (RepoProject proj : bareProjects) {
String name = proj.path; String name = proj.getPath();
String nameUri = proj.name; String nameUri = proj.getName();
cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$ cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$
cfg.setString("submodule", name, "url", nameUri); //$NON-NLS-1$ //$NON-NLS-2$ cfg.setString("submodule", name, "url", nameUri); //$NON-NLS-1$ //$NON-NLS-2$
// create gitlink // create gitlink
DirCacheEntry dcEntry = new DirCacheEntry(name); DirCacheEntry dcEntry = new DirCacheEntry(name);
ObjectId objectId; ObjectId objectId;
if (ObjectId.isId(proj.revision)) if (ObjectId.isId(proj.getRevision()))
objectId = ObjectId.fromString(proj.revision); objectId = ObjectId.fromString(proj.getRevision());
else { else {
objectId = callback.sha1(nameUri, proj.revision); objectId = callback.sha1(nameUri, proj.getRevision());
} }
if (objectId == null) if (objectId == null)
throw new RemoteUnavailableException(nameUri); throw new RemoteUnavailableException(nameUri);
@ -421,9 +421,9 @@ public class RepoCommand extends GitCommand<RevCommit> {
dcEntry.setFileMode(FileMode.GITLINK); dcEntry.setFileMode(FileMode.GITLINK);
builder.add(dcEntry); builder.add(dcEntry);
for (CopyFile copyfile : proj.copyfiles) { for (CopyFile copyfile : proj.getCopyFiles()) {
byte[] src = callback.readFile( byte[] src = callback.readFile(
nameUri, proj.revision, copyfile.src); nameUri, proj.getRevision(), copyfile.src);
objectId = inserter.insert(Constants.OBJ_BLOB, src); objectId = inserter.insert(Constants.OBJ_BLOB, src);
dcEntry = new DirCacheEntry(copyfile.dest); dcEntry = new DirCacheEntry(copyfile.dest);
dcEntry.setObjectId(objectId); dcEntry.setObjectId(objectId);
@ -495,7 +495,7 @@ public class RepoCommand extends GitCommand<RevCommit> {
List<CopyFile> copyfiles) throws GitAPIException, IOException { List<CopyFile> copyfiles) throws GitAPIException, IOException {
if (repo.isBare()) { if (repo.isBare()) {
RepoProject proj = new RepoProject(url, name, revision, null, null); RepoProject proj = new RepoProject(url, name, revision, null, null);
proj.copyfiles.addAll(copyfiles); proj.addCopyFiles(copyfiles);
bareProjects.add(proj); bareProjects.add(proj);
} else { } else {
SubmoduleAddCommand add = git SubmoduleAddCommand add = git

97
org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java

@ -49,6 +49,8 @@ import java.io.IOException;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -62,14 +64,14 @@ import org.eclipse.jgit.lib.Repository;
* @since 4.0 * @since 4.0
*/ */
public class RepoProject implements Comparable<RepoProject> { public class RepoProject implements Comparable<RepoProject> {
final String name; private final String name;
final String path; private final String path;
final String revision; private final String revision;
final String remote; private final String remote;
final Set<String> groups; private final Set<String> groups;
final List<CopyFile> copyfiles; private final List<CopyFile> copyfiles;
String url; private String url;
String defaultRevision; private String defaultRevision;
/** /**
* The representation of a copy file configuration. * The representation of a copy file configuration.
@ -82,10 +84,13 @@ public class RepoProject implements Comparable<RepoProject> {
/** /**
* @param repo * @param repo
* the super project.
* @param path * @param path
* the path of the project containing this copyfile config. * the path of the project containing this copyfile config.
* @param src * @param src
* the source path relative to the sub repo.
* @param dest * @param dest
* the destination path relative to the super project.
*/ */
public CopyFile(Repository repo, String path, String src, String dest) { public CopyFile(Repository repo, String path, String src, String dest) {
this.repo = repo; this.repo = repo;
@ -108,7 +113,8 @@ public class RepoProject implements Comparable<RepoProject> {
FileOutputStream output = new FileOutputStream(destFile); FileOutputStream output = new FileOutputStream(destFile);
try { try {
FileChannel channel = input.getChannel(); FileChannel channel = input.getChannel();
output.getChannel().transferFrom(channel, 0, channel.size()); output.getChannel().transferFrom(
channel, 0, channel.size());
} finally { } finally {
output.close(); output.close();
} }
@ -120,10 +126,15 @@ public class RepoProject implements Comparable<RepoProject> {
/** /**
* @param name * @param name
* the relative path to the {@code remote}
* @param path * @param path
* the relative path to the super project
* @param revision * @param revision
* a SHA-1 or branch name or tag name
* @param remote * @param remote
* name of the remote definition
* @param groups * @param groups
* comma separated group list
*/ */
public RepoProject(String name, String path, String revision, public RepoProject(String name, String path, String revision,
String remote, String groups) { String remote, String groups) {
@ -162,15 +173,70 @@ public class RepoProject implements Comparable<RepoProject> {
return this; return this;
} }
/**
* Get the name (relative path to the {@code remote}) of this sub repo.
*
* @return {@code name}
*/
public String getName() {
return name;
}
/**
* Get the path (relative path to the super project) of this sub repo.
*
* @return {@code path}
*/
public String getPath() {
return path;
}
/** /**
* Get the revision of the sub repo. * Get the revision of the sub repo.
* *
* @return revision if set, or default revision. * @return {@code revision} if set, or {@code defaultRevision}.
*/ */
public String getRevision() { public String getRevision() {
return revision == null ? defaultRevision : revision; return revision == null ? defaultRevision : revision;
} }
/**
* Getter for the copyfile configurations.
*
* @return Immutable copy of {@code copyfiles}
*/
public List<CopyFile> getCopyFiles() {
return Collections.unmodifiableList(copyfiles);
}
/**
* Get the url of the sub repo.
*
* @return {@code url}
*/
public String getUrl() {
return url;
}
/**
* Get the name of the remote definition of the sub repo.
*
* @return {@remote}
*/
public String getRemote() {
return remote;
}
/**
* Test whether this sub repo belongs to a specified group.
*
* @param group
* @return true if {@code group} is present.
*/
public boolean inGroup(String group) {
return groups.contains(group);
}
/** /**
* Add a copy file configuration. * Add a copy file configuration.
* *
@ -180,7 +246,16 @@ public class RepoProject implements Comparable<RepoProject> {
copyfiles.add(copyfile); copyfiles.add(copyfile);
} }
String getPathWithSlash() { /**
* Add a bunch of copyfile configurations.
*
* @param copyfiles
*/
public void addCopyFiles(Collection<CopyFile> copyfiles) {
this.copyfiles.addAll(copyfiles);
}
private String getPathWithSlash() {
if (path.endsWith("/")) //$NON-NLS-1$ if (path.endsWith("/")) //$NON-NLS-1$
return path; return path;
else else

1
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java

@ -316,6 +316,7 @@ public class JGitText extends TranslationBundle {
/***/ public String exceptionCaughtDuringExecutionOfRevertCommand; /***/ public String exceptionCaughtDuringExecutionOfRevertCommand;
/***/ public String exceptionCaughtDuringExecutionOfRmCommand; /***/ public String exceptionCaughtDuringExecutionOfRmCommand;
/***/ public String exceptionCaughtDuringExecutionOfTagCommand; /***/ public String exceptionCaughtDuringExecutionOfTagCommand;
/***/ public String exceptionCaughtDuringExcecutionOfCommand;
/***/ public String exceptionHookExecutionInterrupted; /***/ public String exceptionHookExecutionInterrupted;
/***/ public String exceptionOccurredDuringAddingOfOptionToALogCommand; /***/ public String exceptionOccurredDuringAddingOfOptionToALogCommand;
/***/ public String exceptionOccurredDuringReadingOfGIT_DIR; /***/ public String exceptionOccurredDuringReadingOfGIT_DIR;

2
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java

@ -533,6 +533,7 @@ public final class DfsPackFile {
return ByteBuffer.wrap(copyBuf, 0, bs); return ByteBuffer.wrap(copyBuf, 0, bs);
} }
@SuppressWarnings("null")
void copyAsIs(PackOutputStream out, DfsObjectToPack src, void copyAsIs(PackOutputStream out, DfsObjectToPack src,
boolean validate, DfsReader ctx) throws IOException, boolean validate, DfsReader ctx) throws IOException,
StoredObjectRepresentationNotAvailableException { StoredObjectRepresentationNotAvailableException {
@ -836,6 +837,7 @@ public final class DfsPackFile {
return buf.position(); return buf.position();
} }
@SuppressWarnings("null")
ObjectLoader load(DfsReader ctx, long pos) ObjectLoader load(DfsReader ctx, long pos)
throws IOException { throws IOException {
try { try {

11
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java

@ -366,11 +366,10 @@ public class ObjectDirectoryPackParser extends PackParser {
@Override @Override
protected void onEndThinPack() throws IOException { protected void onEndThinPack() throws IOException {
final byte[] tailHash = this.tailDigest.digest();
final byte[] buf = buffer(); final byte[] buf = buffer();
final MessageDigest origDigest = Constants.newMessageDigest(); final MessageDigest origDigest = Constants.newMessageDigest();
final MessageDigest tailDigest = Constants.newMessageDigest(); final MessageDigest tailDigest2 = Constants.newMessageDigest();
final MessageDigest packDigest = Constants.newMessageDigest(); final MessageDigest packDigest = Constants.newMessageDigest();
long origRemaining = origEnd; long origRemaining = origEnd;
@ -393,15 +392,15 @@ public class ObjectDirectoryPackParser extends PackParser {
origDigest.update(buf, 0, origCnt); origDigest.update(buf, 0, origCnt);
origRemaining -= origCnt; origRemaining -= origCnt;
if (origRemaining == 0) if (origRemaining == 0)
tailDigest.update(buf, origCnt, n - origCnt); tailDigest2.update(buf, origCnt, n - origCnt);
} else } else
tailDigest.update(buf, 0, n); tailDigest2.update(buf, 0, n);
packDigest.update(buf, 0, n); packDigest.update(buf, 0, n);
} }
if (!Arrays.equals(origDigest.digest(), origHash) if (!Arrays.equals(origDigest.digest(), origHash) || !Arrays
|| !Arrays.equals(tailDigest.digest(), tailHash)) .equals(tailDigest2.digest(), this.tailDigest.digest()))
throw new IOException( throw new IOException(
JGitText.get().packCorruptedWhileWritingToFilesystem); JGitText.get().packCorruptedWhileWritingToFilesystem);

2
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java

@ -80,6 +80,6 @@ class PackInputStream extends InputStream {
@Override @Override
public void close() { public void close() {
wc.release(); wc.close();
} }
} }

5
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java

@ -91,11 +91,8 @@ public class UnpackedObject {
*/ */
public static ObjectLoader parse(byte[] raw, AnyObjectId id) public static ObjectLoader parse(byte[] raw, AnyObjectId id)
throws IOException { throws IOException {
WindowCursor wc = new WindowCursor(null); try (WindowCursor wc = new WindowCursor(null)) {
try {
return open(new ByteArrayInputStream(raw), null, id, wc); return open(new ByteArrayInputStream(raw), null, id, wc);
} finally {
wc.release();
} }
} }

3
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java

@ -330,7 +330,8 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
} }
/** Release the current window cursor. */ /** Release the current window cursor. */
public void release() { @Override
public void close() {
window = null; window = null;
baseCache = null; baseCache = null;
try { try {

13
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java

@ -1591,6 +1591,7 @@ public class PackWriter implements AutoCloseable {
findObjectsToPackUsingBitmaps(bitmapWalker, want, have); findObjectsToPackUsingBitmaps(bitmapWalker, want, have);
endPhase(countingMonitor); endPhase(countingMonitor);
stats.timeCounting = System.currentTimeMillis() - countingStart; stats.timeCounting = System.currentTimeMillis() - countingStart;
stats.bitmapIndexMisses = bitmapWalker.getCountOfBitmapIndexMisses();
return; return;
} }
} }
@ -2084,6 +2085,8 @@ public class PackWriter implements AutoCloseable {
long totalObjects; long totalObjects;
long bitmapIndexMisses;
long totalDeltas; long totalDeltas;
long reusedObjects; long reusedObjects;
@ -2165,6 +2168,16 @@ public class PackWriter implements AutoCloseable {
return totalObjects; return totalObjects;
} }
/**
* @return the count of objects that needed to be discovered through an
* object walk because they were not found in bitmap indices.
*
* @since 4.0
*/
public long getBitmapIndexMisses() {
return bitmapIndexMisses;
}
/** /**
* @return total number of deltas output. This may be lower than the * @return total number of deltas output. This may be lower than the
* actual number of deltas if a cached pack was reused. * actual number of deltas if a cached pack was reused.

22
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java

@ -71,6 +71,8 @@ final class PackWriterBitmapWalker {
private final ProgressMonitor pm; private final ProgressMonitor pm;
private long countOfBitmapIndexMisses;
PackWriterBitmapWalker( PackWriterBitmapWalker(
ObjectWalk walker, BitmapIndex bitmapIndex, ProgressMonitor pm) { ObjectWalk walker, BitmapIndex bitmapIndex, ProgressMonitor pm) {
this.walker = walker; this.walker = walker;
@ -78,6 +80,10 @@ final class PackWriterBitmapWalker {
this.pm = (pm == null) ? NullProgressMonitor.INSTANCE : pm; this.pm = (pm == null) ? NullProgressMonitor.INSTANCE : pm;
} }
long getCountOfBitmapIndexMisses() {
return countOfBitmapIndexMisses;
}
BitmapBuilder findObjects(Set<? extends ObjectId> start, BitmapBuilder seen, boolean ignoreMissingStart) BitmapBuilder findObjects(Set<? extends ObjectId> start, BitmapBuilder seen, boolean ignoreMissingStart)
throws MissingObjectException, IncorrectObjectTypeException, throws MissingObjectException, IncorrectObjectTypeException,
IOException { IOException {
@ -104,7 +110,8 @@ final class PackWriterBitmapWalker {
} }
if (marked) { if (marked) {
walker.setRevFilter(newRevFilter(seen, bitmapResult)); BitmapRevFilter filter = newRevFilter(seen, bitmapResult);
walker.setRevFilter(filter);
while (walker.next() != null) { while (walker.next() != null) {
// Iterate through all of the commits. The BitmapRevFilter does // Iterate through all of the commits. The BitmapRevFilter does
@ -117,6 +124,7 @@ final class PackWriterBitmapWalker {
bitmapResult.add(ro, ro.getType()); bitmapResult.add(ro, ro.getType());
pm.update(1); pm.update(1);
} }
countOfBitmapIndexMisses += filter.getCountOfLoadedCommits();
} }
return bitmapResult; return bitmapResult;
@ -126,7 +134,7 @@ final class PackWriterBitmapWalker {
walker.reset(); walker.reset();
} }
static RevFilter newRevFilter( static BitmapRevFilter newRevFilter(
final BitmapBuilder seen, final BitmapBuilder bitmapResult) { final BitmapBuilder seen, final BitmapBuilder bitmapResult) {
if (seen != null) { if (seen != null) {
return new BitmapRevFilter() { return new BitmapRevFilter() {
@ -146,12 +154,16 @@ final class PackWriterBitmapWalker {
} }
static abstract class BitmapRevFilter extends RevFilter { static abstract class BitmapRevFilter extends RevFilter {
private long countOfLoadedCommits;
protected abstract boolean load(RevCommit cmit); protected abstract boolean load(RevCommit cmit);
@Override @Override
public final boolean include(RevWalk walker, RevCommit cmit) { public final boolean include(RevWalk walker, RevCommit cmit) {
if (load(cmit)) if (load(cmit)) {
countOfLoadedCommits++;
return true; return true;
}
for (RevCommit p : cmit.getParents()) for (RevCommit p : cmit.getParents())
p.add(RevFlag.SEEN); p.add(RevFlag.SEEN);
return false; return false;
@ -166,5 +178,9 @@ final class PackWriterBitmapWalker {
public final boolean requiresCommitBody() { public final boolean requiresCommitBody() {
return false; return false;
} }
long getCountOfLoadedCommits() {
return countOfLoadedCommits;
}
} }
} }

6
org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java

@ -565,14 +565,16 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
* based on other options. If insufficient information is available, an * based on other options. If insufficient information is available, an
* exception is thrown to the caller. * exception is thrown to the caller.
* *
* @return a repository matching this configuration. * @return a repository matching this configuration. The caller is
* responsible to close the repository instance when it is no longer
* needed.
* @throws IllegalArgumentException * @throws IllegalArgumentException
* insufficient parameters were set. * insufficient parameters were set.
* @throws IOException * @throws IOException
* the repository could not be accessed to configure the rest of * the repository could not be accessed to configure the rest of
* the builder's parameters. * the builder's parameters.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({ "unchecked", "resource" })
public R build() throws IOException { public R build() throws IOException {
R repo = (R) new FileRepository(setup()); R repo = (R) new FileRepository(setup());
if (isMustExist() && !repo.getObjectDatabase().exists()) if (isMustExist() && !repo.getObjectDatabase().exists())

4
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java

@ -430,7 +430,5 @@ public abstract class ObjectReader implements AutoCloseable {
* @since 4.0 * @since 4.0
*/ */
@Override @Override
public void close() { public abstract void close();
// Do nothing.
}
} }

1
org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java

@ -159,6 +159,7 @@ public class RepositoryCache {
openLocks[i] = new Lock(); openLocks[i] = new Lock();
} }
@SuppressWarnings("resource")
private Repository openRepository(final Key location, private Repository openRepository(final Key location,
final boolean mustExist) throws IOException { final boolean mustExist) throws IOException {
Reference<Repository> ref = cacheMap.get(location); Reference<Repository> ref = cacheMap.get(location);

2
org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java

@ -102,7 +102,7 @@ public class MergeFormatter {
* metadata * metadata
* @throws IOException * @throws IOException
*/ */
public void formatMerge(OutputStream out, MergeResult res, String baseName, public void formatMerge(OutputStream out, MergeResult<RawText> res, String baseName,
String oursName, String theirsName, String charsetName) throws IOException { String oursName, String theirsName, String charsetName) throws IOException {
List<String> names = new ArrayList<String>(3); List<String> names = new ArrayList<String>(3);
names.add(baseName); names.add(baseName);

1
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheConfig.java

@ -221,6 +221,7 @@ public class WindowCacheConfig {
* *
* @since 3.0 * @since 3.0
*/ */
@SuppressWarnings("deprecation")
public void install() { public void install() {
WindowCache.reconfigure(this); WindowCache.reconfigure(this);
} }

4
org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java

@ -55,6 +55,7 @@ import java.util.Set;
import org.eclipse.jgit.errors.NoRemoteRepositoryException; import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.errors.TooLargePackException;
import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.pack.PackWriter; import org.eclipse.jgit.internal.storage.pack.PackWriter;
@ -314,6 +315,9 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$ if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$
throw new PackProtocolException(uri, MessageFormat.format(JGitText.get().unexpectedReportLine, unpackLine)); throw new PackProtocolException(uri, MessageFormat.format(JGitText.get().unexpectedReportLine, unpackLine));
final String unpackStatus = unpackLine.substring("unpack ".length()); //$NON-NLS-1$ final String unpackStatus = unpackLine.substring("unpack ".length()); //$NON-NLS-1$
if (unpackStatus.startsWith("error Pack exceeds the limit of")) //$NON-NLS-1$
throw new TooLargePackException(uri,
unpackStatus.substring("error ".length())); //$NON-NLS-1$
if (!unpackStatus.equals("ok")) //$NON-NLS-1$ if (!unpackStatus.equals("ok")) //$NON-NLS-1$
throw new TransportException(uri, MessageFormat.format( throw new TransportException(uri, MessageFormat.format(
JGitText.get().errorOccurredDuringUnpackingOnTheRemoteEnd, unpackStatus)); JGitText.get().errorOccurredDuringUnpackingOnTheRemoteEnd, unpackStatus));

4
org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java

@ -1583,7 +1583,9 @@ public abstract class BaseReceivePack {
pckIn = null; pckIn = null;
pckOut = null; pckOut = null;
refs = null; refs = null;
enabledCapabilities = null; // Keep the capabilities. If responses are sent after this release
// we need to remember at least whether sideband communication has to be
// used
commands = null; commands = null;
if (timer != null) { if (timer != null) {
try { try {

10
org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

@ -240,11 +240,17 @@ public class ReceivePack extends BaseReceivePack {
}); });
} }
if (unpackError != null) {
// we already know which exception to throw. Ignore
// potential additional exceptions raised in postReceiveHooks
try {
postReceive.onPostReceive(this, filterCommands(Result.OK)); postReceive.onPostReceive(this, filterCommands(Result.OK));
} catch (Throwable e) {
if (unpackError != null) }
throw new UnpackException(unpackError); throw new UnpackException(unpackError);
} }
postReceive.onPostReceive(this, filterCommands(Result.OK));
}
} }
@Override @Override

1
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java

@ -227,6 +227,7 @@ public class TransportSftp extends SshTransport implements WalkTransport {
Collection<String> getPackNames() throws IOException { Collection<String> getPackNames() throws IOException {
final List<String> packs = new ArrayList<String>(); final List<String> packs = new ArrayList<String>();
try { try {
@SuppressWarnings("unchecked")
final Collection<ChannelSftp.LsEntry> list = ftp.ls("pack"); //$NON-NLS-1$ final Collection<ChannelSftp.LsEntry> list = ftp.ls("pack"); //$NON-NLS-1$
final HashMap<String, ChannelSftp.LsEntry> files; final HashMap<String, ChannelSftp.LsEntry> files;
final HashMap<String, Integer> mtimes; final HashMap<String, Integer> mtimes;

8
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

@ -810,9 +810,9 @@ public class UploadPack {
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT); adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
adv.advertiseCapability(OPTION_AGENT, UserAgent.get()); adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
adv.setDerefTags(true); adv.setDerefTags(true);
Map<String, Ref> refs = getAdvertisedOrDefaultRefs(); Map<String, Ref> advertisedOrDefaultRefs = getAdvertisedOrDefaultRefs();
findSymrefs(adv, refs); findSymrefs(adv, advertisedOrDefaultRefs);
advertised = adv.send(refs); advertised = adv.send(advertisedOrDefaultRefs);
if (adv.isEmpty()) if (adv.isEmpty())
adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); //$NON-NLS-1$ adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); //$NON-NLS-1$
adv.end(); adv.end();
@ -1467,7 +1467,7 @@ public class UploadPack {
pckOut.end(); pckOut.end();
} }
private void findSymrefs( private static void findSymrefs(
final RefAdvertiser adv, final Map<String, Ref> refs) { final RefAdvertiser adv, final Map<String, Ref> refs) {
Ref head = refs.get(Constants.HEAD); Ref head = refs.get(Constants.HEAD);
if (head != null && head.isSymbolic()) { if (head != null && head.isSymbolic()) {

3
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java

@ -224,7 +224,8 @@ public class IndexDiffFilter extends TreeFilter {
// Only one chance left to detect a diff: between index and working // Only one chance left to detect a diff: between index and working
// tree. Make use of the WorkingTreeIterator#isModified() method to // tree. Make use of the WorkingTreeIterator#isModified() method to
// avoid computing SHA1 on filesystem content if not really needed. // avoid computing SHA1 on filesystem content if not really needed.
return wi.isModified(di.getDirCacheEntry(), true, tw.getObjectReader()); return wi.isModified(di == null ? null : di.getDirCacheEntry(), true,
tw.getObjectReader());
} }
/** /**

90
org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java

@ -440,40 +440,11 @@ public abstract class FS {
if (env != null) { if (env != null) {
pb.environment().putAll(env); pb.environment().putAll(env);
} }
final Process p = pb.start(); Process p = pb.start();
final BufferedReader lineRead = new BufferedReader( BufferedReader lineRead = new BufferedReader(
new InputStreamReader(p.getInputStream(), encoding)); new InputStreamReader(p.getInputStream(), encoding));
p.getOutputStream().close(); p.getOutputStream().close();
final AtomicBoolean gooblerFail = new AtomicBoolean(false); GobblerThread gobbler = new GobblerThread(p, command, dir);
Thread gobbler = new Thread() {
public void run() {
InputStream is = p.getErrorStream();
try {
int ch;
if (debug)
while ((ch = is.read()) != -1)
System.err.print((char) ch);
else
while (is.read() != -1) {
// ignore
}
} catch (IOException e) {
// Just print on stderr for debugging
if (debug)
e.printStackTrace(System.err);
gooblerFail.set(true);
}
try {
is.close();
} catch (IOException e) {
// Just print on stderr for debugging
if (debug) {
LOG.debug("Caught exception in gobbler thread", e); //$NON-NLS-1$
}
gooblerFail.set(true);
}
}
};
gobbler.start(); gobbler.start();
String r = null; String r = null;
try { try {
@ -498,7 +469,7 @@ public abstract class FS {
int rc = p.waitFor(); int rc = p.waitFor();
gobbler.join(); gobbler.join();
if (rc == 0 && r != null && r.length() > 0 if (rc == 0 && r != null && r.length() > 0
&& !gooblerFail.get()) && !gobbler.fail.get())
return r; return r;
if (debug) { if (debug) {
LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$ LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$
@ -517,6 +488,59 @@ public abstract class FS {
return null; return null;
} }
private static class GobblerThread extends Thread {
private final Process p;
private final String desc;
private final String dir;
private final boolean debug = LOG.isDebugEnabled();
private final AtomicBoolean fail = new AtomicBoolean();
private GobblerThread(Process p, String[] command, File dir) {
this.p = p;
if (debug) {
this.desc = Arrays.asList(command).toString();
this.dir = dir.toString();
} else {
this.desc = null;
this.dir = null;
}
}
public void run() {
InputStream is = p.getErrorStream();
try {
int ch;
if (debug) {
while ((ch = is.read()) != -1) {
System.err.print((char) ch);
}
} else {
while (is.read() != -1) {
// ignore
}
}
} catch (IOException e) {
logError(e);
fail.set(true);
}
try {
is.close();
} catch (IOException e) {
logError(e);
fail.set(true);
}
}
private void logError(Throwable t) {
if (!debug) {
return;
}
String msg = MessageFormat.format(
JGitText.get().exceptionCaughtDuringExcecutionOfCommand, desc, dir);
LOG.debug(msg, t);
}
}
/** /**
* @return the path to the Git executable or {@code null} if it cannot be * @return the path to the Git executable or {@code null} if it cannot be
* determined. * determined.

75
pom.xml

@ -56,15 +56,25 @@
<name>JGit - Parent</name> <name>JGit - Parent</name>
<url>${jgit-url}</url> <url>${jgit-url}</url>
<organization>
<name>Eclipse JGit Project</name>
<url>http://www.eclipse.org/jgit</url>
</organization>
<description> <description>
Pure Java implementation of Git Pure Java implementation of Git
</description> </description>
<scm> <scm>
<url>http://egit.eclipse.org/w/?p=jgit.git</url> <url>http://git.eclipse.org/c/jgit/jgit.git/</url>
<connection>scm:git:git://egit.eclipse.org/jgit.git</connection> <connection>scm:git:https://git.eclipse.org/r/jgit/jgit</connection>
</scm> </scm>
<ciManagement>
<system>hudson</system>
<url>https://hudson.eclipse.org/jgit/</url>
</ciManagement>
<developers> <developers>
<developer> <developer>
<name>Chris Aniszczyk</name> <name>Chris Aniszczyk</name>
@ -81,6 +91,9 @@
<developer> <developer>
<name>Gunnar Wagenknecht</name> <name>Gunnar Wagenknecht</name>
</developer> </developer>
<developer>
<name>Jonathan Nieder</name>
</developer>
<developer> <developer>
<name>Kevin Sawicki</name> <name>Kevin Sawicki</name>
</developer> </developer>
@ -93,6 +106,9 @@
<developer> <developer>
<name>Robin Rosenberg</name> <name>Robin Rosenberg</name>
</developer> </developer>
<developer>
<name>Robin Stocker</name>
</developer>
<developer> <developer>
<name>Sasa Zivkov</name> <name>Sasa Zivkov</name>
</developer> </developer>
@ -176,21 +192,22 @@
<maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format> <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest> <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
<jgit-last-release-version>3.6.0.201412230720-r</jgit-last-release-version> <jgit-last-release-version>3.7.0.201502260915-r</jgit-last-release-version>
<jsch-version>0.1.50</jsch-version> <jsch-version>0.1.51</jsch-version>
<javaewah-version>0.7.9</javaewah-version> <javaewah-version>0.7.9</javaewah-version>
<junit-version>4.11</junit-version> <junit-version>4.11</junit-version>
<test-fork-count>1C</test-fork-count> <test-fork-count>1C</test-fork-count>
<args4j-version>2.0.15</args4j-version> <args4j-version>2.0.15</args4j-version>
<commons-compress-version>1.6</commons-compress-version> <commons-compress-version>1.6</commons-compress-version>
<osgi-core-version>4.3.1</osgi-core-version> <osgi-core-version>4.3.1</osgi-core-version>
<servlet-api-version>2.5</servlet-api-version> <servlet-api-version>3.1.0</servlet-api-version>
<jetty-version>9.2.10.v20150310</jetty-version> <jetty-version>9.2.10.v20150310</jetty-version>
<clirr-version>2.6.1</clirr-version> <clirr-version>2.6.1</clirr-version>
<httpclient-version>4.1.3</httpclient-version> <httpclient-version>4.1.3</httpclient-version>
<slf4j-version>1.7.2</slf4j-version> <slf4j-version>1.7.2</slf4j-version>
<log4j-version>1.2.15</log4j-version> <log4j-version>1.2.15</log4j-version>
<maven-javadoc-plugin-version>2.10.1</maven-javadoc-plugin-version> <maven-javadoc-plugin-version>2.10.1</maven-javadoc-plugin-version>
<tycho-extras-version>0.22.0</tycho-extras-version>
<!-- Properties to enable jacoco code coverage analysis --> <!-- Properties to enable jacoco code coverage analysis -->
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@ -355,12 +372,12 @@
<plugin> <plugin>
<groupId>org.eclipse.tycho.extras</groupId> <groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-pack200a-plugin</artifactId> <artifactId>tycho-pack200a-plugin</artifactId>
<version>0.22.0</version> <version>${tycho-extras-version}</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.eclipse.tycho.extras</groupId> <groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-pack200b-plugin</artifactId> <artifactId>tycho-pack200b-plugin</artifactId>
<version>0.22.0</version> <version>${tycho-extras-version}</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
@ -379,6 +396,21 @@
</dependency> </dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.8</version>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
@ -478,6 +510,10 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>
@ -490,6 +526,29 @@
<configuration> <configuration>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<configuration>
<aggregate>true</aggregate>
<alwaysGenerateSurefireReport>false</alwaysGenerateSurefireReport>
<reportsDirectories>
<reportsDirectories>${project.build.directory}/surefire-reports</reportsDirectories>
</reportsDirectories>
</configuration>
</plugin>
</plugins> </plugins>
</reporting> </reporting>
@ -521,7 +580,7 @@
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
<version>${servlet-api-version}</version> <version>${servlet-api-version}</version>
</dependency> </dependency>

Loading…
Cancel
Save