Merge branch 'master' into stable-4.0
Change-Id: I962461630384b76e7f387f4e1c1248833fbc4673
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
index d1c2580..a8e312d 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
@@ -76,6 +76,7 @@
import org.eclipse.jgit.errors.UnpackException;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.InternalHttpServerGlue;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
@@ -100,6 +101,9 @@ protected void begin(HttpServletRequest req, Repository db)
throws IOException, ServiceNotEnabledException,
ServiceNotAuthorizedException {
ReceivePack rp = receivePackFactory.create(req, db);
+ InternalHttpServerGlue.setPeerUserAgent(
+ rp,
+ req.getHeader(HDR_USER_AGENT));
req.setAttribute(ATTRIBUTE_HANDLER, rp);
}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
index 4810753..5133219 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
@@ -101,7 +101,7 @@ public void doFilter(ServletRequest request, ServletResponse response,
res.sendError(SC_UNAUTHORIZED);
return;
} catch (ServiceNotEnabledException e) {
- sendError(req, res, SC_FORBIDDEN);
+ sendError(req, res, SC_FORBIDDEN, e.getMessage());
return;
}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
index c5272b5..7aefcbd 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
@@ -74,6 +74,7 @@
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.InternalHttpServerGlue;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.UploadPackInternalServerErrorException;
@@ -100,6 +101,9 @@ protected void begin(HttpServletRequest req, Repository db)
throws IOException, ServiceNotEnabledException,
ServiceNotAuthorizedException {
UploadPack up = uploadPackFactory.create(req, db);
+ InternalHttpServerGlue.setPeerUserAgent(
+ up,
+ req.getHeader(HDR_USER_AGENT));
req.setAttribute(ATTRIBUTE_HANDLER, up);
}
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index b20464e..327a697 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@
org.eclipse.jgit.internal.storage.file;version="[4.0.0,4.1.0)",
org.eclipse.jgit.internal.storage.pack;version="[4.0.0,4.1.0)",
org.eclipse.jgit.lib;version="[4.0.0,4.1.0)",
+ org.eclipse.jgit.merge;version="[4.0.0,4.1.0)",
org.eclipse.jgit.revwalk;version="[4.0.0,4.1.0)",
org.eclipse.jgit.storage.file;version="[4.0.0,4.1.0)",
org.eclipse.jgit.treewalk;version="[4.0.0,4.1.0)",
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index ce33ec7..925a6b0 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -52,11 +52,13 @@
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.TimeZone;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache;
@@ -88,6 +90,8 @@
import org.eclipse.jgit.lib.RefWriter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TagBuilder;
+import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.merge.ThreeWayMerger;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -187,6 +191,11 @@ public Date getClock() {
return new Date(now);
}
+ /** @return timezone used for default identities. */
+ public TimeZone getTimeZone() {
+ return defaultCommitter.getTimeZone();
+ }
+
/**
* Adjust the current time that will used by the next commit.
*
@@ -616,6 +625,59 @@ public void reset(String name) throws Exception {
}
/**
+ * Cherry-pick a commit onto HEAD.
+ * <p>
+ * This differs from {@code git cherry-pick} in that it works in a bare
+ * repository. As a result, any merge failure results in an exception, as
+ * there is no way to recover.
+ *
+ * @param id
+ * commit-ish to cherry-pick.
+ * @return newly created commit, or null if no work was done due to the
+ * resulting tree being identical.
+ * @throws Exception
+ */
+ public RevCommit cherryPick(AnyObjectId id) throws Exception {
+ RevCommit commit = pool.parseCommit(id);
+ pool.parseBody(commit);
+ if (commit.getParentCount() != 1)
+ throw new IOException(String.format(
+ "Expected 1 parent for %s, found: %s",
+ id.name(), Arrays.asList(commit.getParents())));
+ RevCommit parent = commit.getParent(0);
+ pool.parseHeaders(parent);
+
+ Ref headRef = db.getRef(Constants.HEAD);
+ if (headRef == null)
+ throw new IOException("Missing HEAD");
+ RevCommit head = pool.parseCommit(headRef.getObjectId());
+
+ ThreeWayMerger merger = MergeStrategy.RECURSIVE.newMerger(db, true);
+ merger.setBase(parent.getTree());
+ if (merger.merge(head, commit)) {
+ if (AnyObjectId.equals(head.getTree(), merger.getResultTreeId()))
+ return null;
+ tick(1);
+ org.eclipse.jgit.lib.CommitBuilder b =
+ new org.eclipse.jgit.lib.CommitBuilder();
+ b.setParentId(head);
+ b.setTreeId(merger.getResultTreeId());
+ b.setAuthor(commit.getAuthorIdent());
+ b.setCommitter(new PersonIdent(defaultCommitter, new Date(now)));
+ b.setMessage(commit.getFullMessage());
+ ObjectId result;
+ try (ObjectInserter ins = inserter) {
+ result = ins.insert(b);
+ ins.flush();
+ }
+ update(Constants.HEAD, result);
+ return pool.parseCommit(result);
+ } else {
+ throw new IOException("Merge conflict");
+ }
+ }
+
+ /**
* Update the dumb client server info files.
*
* @throws Exception
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 3f552b6..5c6d51a 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -68,6 +68,10 @@
<id>repo.eclipse.org.cbi-releases</id>
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
</pluginRepository>
+ <pluginRepository>
+ <id>repo.eclipse.org.cbi-snapshots</id>
+ <url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
+ </pluginRepository>
</pluginRepositories>
<modules>
@@ -210,7 +214,7 @@
<plugin>
<groupId>org.eclipse.cbi.maven.plugins</groupId>
<artifactId>eclipse-jarsigner-plugin</artifactId>
- <version>1.1.1</version>
+ <version>1.1.2-SNAPSHOT</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index 38c3a2f..7151de7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -47,14 +47,15 @@
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
-import org.eclipse.jgit.console.ConsoleAuthenticator;
-import org.eclipse.jgit.console.ConsoleCredentialsProvider;
+import org.eclipse.jgit.awtui.AwtAuthenticator;
+import org.eclipse.jgit.awtui.AwtCredentialsProvider;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
@@ -115,8 +116,10 @@ public static void main(final String[] argv) {
*/
protected void run(final String[] argv) {
try {
- ConsoleAuthenticator.install();
- ConsoleCredentialsProvider.install();
+ if (!installConsole()) {
+ AwtAuthenticator.install();
+ AwtCredentialsProvider.install();
+ }
configureHttpProxy();
execute(argv);
} catch (Die err) {
@@ -246,6 +249,45 @@ protected Repository openGitDir(String aGitdir) throws IOException {
return rb.build();
}
+ private static boolean installConsole() {
+ try {
+ install("org.eclipse.jgit.console.ConsoleAuthenticator"); //$NON-NLS-1$
+ install("org.eclipse.jgit.console.ConsoleCredentialsProvider"); //$NON-NLS-1$
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ } catch (NoClassDefFoundError e) {
+ return false;
+ } catch (UnsupportedClassVersionError e) {
+ return false;
+
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
+ }
+ }
+
+ private static void install(final String name)
+ throws IllegalAccessException, InvocationTargetException,
+ NoSuchMethodException, ClassNotFoundException {
+ try {
+ Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException)
+ throw (RuntimeException) e.getCause();
+ if (e.getCause() instanceof Error)
+ throw (Error) e.getCause();
+ throw e;
+ }
+ }
+
/**
* Configure the JRE's standard HTTP based on <code>http_proxy</code>.
* <p>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
index 25534fd..9ad845b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
@@ -180,7 +180,7 @@ public void testPullConflict() throws Exception {
+ remoteUri
+ "\nSource change\n=======\nTarget change\n>>>>>>> 42453fd Target change in local\n";
assertFileContentsEqual(targetFile, result);
- assertEquals(RepositoryState.REBASING_INTERACTIVE, target
+ assertEquals(RepositoryState.REBASING_MERGE, target
.getRepository().getRepositoryState());
}
@@ -225,7 +225,7 @@ public void testPullLocalConflict() throws Exception {
String result = "<<<<<<< Upstream, based on branch 'master' of local repository\n"
+ "Master change\n=======\nSlave change\n>>>>>>> 4049c9e Source change in based on master\n";
assertFileContentsEqual(targetFile, result);
- assertEquals(RepositoryState.REBASING_INTERACTIVE, target
+ assertEquals(RepositoryState.REBASING_MERGE, target
.getRepository().getRepositoryState());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index 8e64776..6b641c4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -824,7 +824,7 @@ public void testStopOnConflict() throws Exception {
"<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
- assertEquals(RepositoryState.REBASING_INTERACTIVE, db
+ assertEquals(RepositoryState.REBASING_MERGE, db
.getRepositoryState());
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
// the first one should be included, so we should have left two picks in
@@ -887,7 +887,7 @@ public void testStopOnConflictAndAbortWithDetachedHEAD() throws Exception {
"<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
- assertEquals(RepositoryState.REBASING_INTERACTIVE,
+ assertEquals(RepositoryState.REBASING_MERGE,
db.getRepositoryState());
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
// the first one should be included, so we should have left two picks in
@@ -1009,7 +1009,7 @@ public void testStopOnConflictAndContinueWithNoDeltaToMaster()
res = git.rebase().setOperation(Operation.CONTINUE).call();
assertNotNull(res);
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
- assertEquals(RepositoryState.REBASING_INTERACTIVE,
+ assertEquals(RepositoryState.REBASING_MERGE,
db.getRepositoryState());
git.rebase().setOperation(Operation.SKIP).call();
@@ -1300,7 +1300,7 @@ public void testStopOnConflictCommitAndContinue() throws Exception {
// user can decide what to do. if he accidentally committed, reset soft,
// and continue, if he really has nothing to commit, skip.
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
- assertEquals(RepositoryState.REBASING_INTERACTIVE,
+ assertEquals(RepositoryState.REBASING_MERGE,
db.getRepositoryState());
git.rebase().setOperation(Operation.SKIP).call();
@@ -1401,7 +1401,7 @@ public void testStopOnConflictFileCreationAndDeletion() throws Exception {
assertEquals(Status.STOPPED, res.getStatus());
assertEquals(conflicting, res.getCurrentCommit());
- assertEquals(RepositoryState.REBASING_INTERACTIVE, db
+ assertEquals(RepositoryState.REBASING_MERGE, db
.getRepositoryState());
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
// the first one should be included, so we should have left two picks in
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
index cefc779..fbb9eec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
@@ -46,6 +46,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -55,9 +56,9 @@
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
-import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
@@ -296,6 +297,83 @@ public void commitToUnbornHead() throws Exception {
assertEquals("refs/heads/master", ref.getTarget().getName());
}
+ @Test
+ public void cherryPick() throws Exception {
+ repo.updateRef("HEAD").link("refs/heads/master");
+ RevCommit head = tr.branch("master").commit()
+ .add("foo", "foo contents\n")
+ .create();
+ rw.parseBody(head);
+ RevCommit toPick = tr.commit()
+ .parent(tr.commit().create()) // Can't cherry-pick root.
+ .author(new PersonIdent("Cherrypick Author", "cpa@example.com",
+ tr.getClock(), tr.getTimeZone()))
+ .author(new PersonIdent("Cherrypick Committer", "cpc@example.com",
+ tr.getClock(), tr.getTimeZone()))
+ .message("message to cherry-pick")
+ .add("bar", "bar contents\n")
+ .create();
+ RevCommit result = tr.cherryPick(toPick);
+ rw.parseBody(result);
+
+ Ref headRef = tr.getRepository().getRef("HEAD");
+ assertEquals(result, headRef.getObjectId());
+ assertTrue(headRef.isSymbolic());
+ assertEquals("refs/heads/master", headRef.getLeaf().getName());
+
+ assertEquals(1, result.getParentCount());
+ assertEquals(head, result.getParent(0));
+ assertEquals(toPick.getAuthorIdent(), result.getAuthorIdent());
+
+ // Committer name/email matches default, and time was incremented.
+ assertEquals(new PersonIdent(head.getCommitterIdent(), new Date(0)),
+ new PersonIdent(result.getCommitterIdent(), new Date(0)));
+ assertTrue(toPick.getCommitTime() < result.getCommitTime());
+
+ assertEquals("message to cherry-pick", result.getFullMessage());
+ assertEquals("foo contents\n", blobAsString(result, "foo"));
+ assertEquals("bar contents\n", blobAsString(result, "bar"));
+ }
+
+ @Test
+ public void cherryPickWithContentMerge() throws Exception {
+ RevCommit base = tr.branch("HEAD").commit()
+ .add("foo", "foo contents\n\n")
+ .create();
+ tr.branch("HEAD").commit()
+ .add("foo", "foo contents\n\nlast line\n")
+ .create();
+ RevCommit toPick = tr.commit()
+ .message("message to cherry-pick")
+ .parent(base)
+ .add("foo", "changed foo contents\n\n")
+ .create();
+ RevCommit result = tr.cherryPick(toPick);
+ rw.parseBody(result);
+
+ assertEquals("message to cherry-pick", result.getFullMessage());
+ assertEquals("changed foo contents\n\nlast line\n",
+ blobAsString(result, "foo"));
+ }
+
+ @Test
+ public void cherryPickWithIdenticalContents() throws Exception {
+ RevCommit base = tr.branch("HEAD").commit().add("foo", "foo contents\n")
+ .create();
+ RevCommit head = tr.branch("HEAD").commit()
+ .parent(base)
+ .add("bar", "bar contents\n")
+ .create();
+ RevCommit toPick = tr.commit()
+ .parent(base)
+ .message("message to cherry-pick")
+ .add("bar", "bar contents\n")
+ .create();
+ assertNotEquals(head, toPick);
+ assertNull(tr.cherryPick(toPick));
+ assertEquals(head, repo.getRef("HEAD").getObjectId());
+ }
+
private String blobAsString(AnyObjectId treeish, String path)
throws Exception {
RevObject obj = tr.get(rw.parseTree(treeish), path);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index c6578cc..274757d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -121,6 +121,42 @@ public void testValidCommitBlankAuthor() throws CorruptObjectException {
}
@Test
+ public void testCommitCorruptAuthor() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
+ b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
+ b.append("author b <b@c> <b@c> 0 +0000\n");
+ b.append("committer <> 0 +0000\n");
+
+ byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid author", e.getMessage());
+ }
+ checker.setAllowInvalidPersonIdent(true);
+ checker.checkCommit(data);
+ }
+
+ @Test
+ public void testCommitCorruptCommitter() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
+ b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
+ b.append("author <> 0 +0000\n");
+ b.append("committer b <b@c> <b@c> 0 +0000\n");
+
+ byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid committer", e.getMessage());
+ }
+ checker.setAllowInvalidPersonIdent(true);
+ checker.checkCommit(data);
+ }
+
+ @Test
public void testValidCommit1Parent() throws CorruptObjectException {
final StringBuilder b = new StringBuilder();
@@ -940,7 +976,8 @@ public void testValidTagHasNoTaggerHeader() throws CorruptObjectException {
}
@Test
- public void testInvalidTagInvalidTaggerHeader1() {
+ public void testInvalidTagInvalidTaggerHeader1()
+ throws CorruptObjectException {
final StringBuilder b = new StringBuilder();
b.append("object ");
@@ -958,6 +995,8 @@ public void testInvalidTagInvalidTaggerHeader1() {
} catch (CorruptObjectException e) {
assertEquals("invalid tagger", e.getMessage());
}
+ checker.setAllowInvalidPersonIdent(true);
+ checker.checkTag(data);
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
index 8a33425..d4a3d62 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
@@ -51,11 +51,25 @@
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.Constants;
+import org.junit.Assume;
import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.runner.RunWith;
+@RunWith(Theories.class)
public class MergeAlgorithmTest {
MergeFormatter fmt=new MergeFormatter();
+ private final boolean newlineAtEnd;
+
+ @DataPoints
+ public static boolean[] newlineAtEndDataPoints = { false, true };
+
+ public MergeAlgorithmTest(boolean newlineAtEnd) {
+ this.newlineAtEnd = newlineAtEnd;
+ }
+
/**
* Check for a conflict where the second text was changed similar to the
* first one, but the second texts modification covers one more line.
@@ -174,28 +188,55 @@ public void testAdjacentModifications() throws IOException {
}
@Test
- public void testSeperateModifications() throws IOException {
+ public void testSeparateModifications() throws IOException {
assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe"));
}
+ @Test
+ public void testBlankLines() throws IOException {
+ assertEquals(t("aZc\nYe"), merge("abc\nde", "aZc\nde", "abc\nYe"));
+ }
+
/**
* Test merging two contents which do one similar modification and one
- * insertion is only done by one side. Between modification and insertion is
- * a block which is common between the two contents and the common base
+ * insertion is only done by one side, in the middle. Between modification
+ * and insertion is a block which is common between the two contents and the
+ * common base
*
* @throws IOException
*/
@Test
public void testTwoSimilarModsAndOneInsert() throws IOException {
- assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ"));
assertEquals(t("aBcDde"), merge("abcde", "aBcde", "aBcDde"));
- assertEquals(t("IAJ"), merge("iA", "IA", "IAJ"));
- assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAAJ"));
assertEquals(t("IAAAJCAB"), merge("iACAB", "IACAB", "IAAAJCAB"));
assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB"));
assertEquals(t("AGADEFHIAAAJCAB"),
merge("AGADEFHiACAB", "AGADEFHIACAB", "AGADEFHIAAAJCAB"));
+ }
+ /**
+ * Test merging two contents which do one similar modification and one
+ * insertion is only done by one side, at the end. Between modification and
+ * insertion is a block which is common between the two contents and the
+ * common base
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testTwoSimilarModsAndOneInsertAtEnd() throws IOException {
+ Assume.assumeTrue(newlineAtEnd);
+ assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ"));
+ assertEquals(t("IAJ"), merge("iA", "IA", "IAJ"));
+ assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAAJ"));
+ }
+
+ @Test
+ public void testTwoSimilarModsAndOneInsertAtEndNoNewlineAtEnd()
+ throws IOException {
+ Assume.assumeFalse(newlineAtEnd);
+ assertEquals(t("I<A=AAJ>"), merge("iA", "IA", "IAAJ"));
+ assertEquals(t("I<A=AJ>"), merge("iA", "IA", "IAJ"));
+ assertEquals(t("I<A=AAAJ>"), merge("iA", "IA", "IAAAJ"));
}
/**
@@ -225,7 +266,7 @@ private String merge(String commonBase, String ours, String theirs) throws IOExc
return new String(bo.toByteArray(), Constants.CHARACTER_ENCODING);
}
- public static String t(String text) {
+ public String t(String text) {
StringBuilder r = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
@@ -241,13 +282,14 @@ public static String t(String text) {
break;
default:
r.append(c);
- r.append('\n');
+ if (newlineAtEnd || i < text.length() - 1)
+ r.append('\n');
}
}
return r.toString();
}
- public static RawText T(String text) {
+ public RawText T(String text) {
return new RawText(Constants.encode(t(text)));
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
index 37cc88b..19e495b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
@@ -177,6 +177,69 @@ public void crissCrossMerge(MergeStrategy strategy, IndexState indexState,
@Theory
/**
+ * Merging m2,s2 from the following topology. m1 and s1 are the two root
+ * commits of the repo. In master and side different files are touched.
+ * No need to do a real content merge.
+ *
+ * <pre>
+ * m1--m2
+ * \/
+ * /\
+ * s1--s2
+ * </pre>
+ */
+ public void crissCrossMerge_twoRoots(MergeStrategy strategy,
+ IndexState indexState, WorktreeState worktreeState)
+ throws Exception {
+ if (!validateStates(indexState, worktreeState))
+ return;
+ // fill the repo
+ BranchBuilder master = db_t.branch("master");
+ BranchBuilder side = db_t.branch("side");
+ RevCommit m1 = master.commit().add("m", "m1").message("m1").create();
+ db_t.getRevWalk().parseCommit(m1);
+
+ RevCommit s1 = side.commit().add("s", "s1").message("s1").create();
+ RevCommit s2 = side.commit().parent(m1).add("m", "m1")
+ .message("s2(merge)").create();
+ RevCommit m2 = master.commit().parent(s1).add("s", "s1")
+ .message("m2(merge)").create();
+
+ Git git = Git.wrap(db);
+ git.checkout().setName("master").call();
+ modifyWorktree(worktreeState, "m", "side");
+ modifyWorktree(worktreeState, "s", "side");
+ modifyIndex(indexState, "m", "side");
+ modifyIndex(indexState, "s", "side");
+
+ ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
+ worktreeState == WorktreeState.Bare);
+ if (worktreeState != WorktreeState.Bare)
+ merger.setWorkingTreeIterator(new FileTreeIterator(db));
+ try {
+ boolean expectSuccess = true;
+ if (!(indexState == IndexState.Bare
+ || indexState == IndexState.Missing
+ || indexState == IndexState.SameAsHead || indexState == IndexState.SameAsOther))
+ // index is dirty
+ expectSuccess = false;
+
+ assertEquals(Boolean.valueOf(expectSuccess),
+ Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
+ assertEquals(MergeStrategy.RECURSIVE, strategy);
+ assertEquals("m1",
+ contentAsString(db, merger.getResultTreeId(), "m"));
+ assertEquals("s1",
+ contentAsString(db, merger.getResultTreeId(), "s"));
+ } catch (NoMergeBaseException e) {
+ assertEquals(MergeStrategy.RESOLVE, strategy);
+ assertEquals(e.getReason(),
+ MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
+ }
+ }
+
+ @Theory
+ /**
* Merging m2,s2 from the following topology. The same file is modified
* in both branches. The modifications should be mergeable. m2 and s2
* contain branch specific conflict resolutions. Therefore m2 and s2 don't contain the same content.
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
index dd06168..478a93b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
@@ -184,7 +184,7 @@ public void checkMergeMergeableTreesWithoutIndex(MergeStrategy strategy)
MergeResult mergeRes = git.merge().setStrategy(strategy)
.include(masterCommit).call();
assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
- assertEquals("[d/1, mode:100644, content:1master\n2\n3side\n]",
+ assertEquals("[d/1, mode:100644, content:1master\n2\n3side]",
indexState(CONTENT));
}
@@ -561,7 +561,7 @@ public void checkMergeCrissCross(MergeStrategy strategy) throws Exception {
assertEquals(MergeStrategy.RECURSIVE, strategy);
assertEquals(MergeResult.MergeStatus.MERGED,
mergeResult.getMergeStatus());
- assertEquals("1master2\n2\n3side2\n", read("1"));
+ assertEquals("1master2\n2\n3side2", read("1"));
} catch (JGitInternalException e) {
assertEquals(MergeStrategy.RESOLVE, strategy);
assertTrue(e.getCause() instanceof NoMergeBaseException);
@@ -697,7 +697,7 @@ public void checkForCorrectIndex(MergeStrategy strategy) throws Exception {
assertEquals(
"[0, mode:100644, content:master]" //
+ "[1, mode:100644, content:side]" //
- + "[2, mode:100644, content:1master\n2\n3side\n]" //
+ + "[2, mode:100644, content:1master\n2\n3side]" //
+ "[3, mode:100644, stage:1, content:orig][3, mode:100644, stage:2, content:side][3, mode:100644, stage:3, content:master]" //
+ "[4, mode:100644, content:orig]", //
indexState(CONTENT));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
index 9cbb1c8..dfde7fc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
@@ -215,21 +215,6 @@ public void testCull() throws Exception {
}
@Test
- public void testMarkUninterestingPropagation() throws Exception {
- final RevBlob f = blob("1");
- final RevTree t = tree(file("f", f));
- final RevCommit c1 = commit(t);
- final RevCommit c2 = commit(t);
-
- markUninteresting(c1);
- markStart(c2);
-
- assertSame(c2, objw.next());
- assertNull(objw.next());
- assertNull(objw.nextObject());
- }
-
- @Test
public void testEmptyTreeCorruption() throws Exception {
ObjectId bId = ObjectId
.fromString("abbbfafe3129f85747aba7bfac992af77134c607");
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
new file mode 100644
index 0000000..fd26bfa
--- /dev/null
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * 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.awtui;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/** Interacts with the user during authentication by using AWT/Swing dialogs. */
+public class AwtCredentialsProvider extends CredentialsProvider {
+ /** Install this implementation as the default. */
+ public static void install() {
+ CredentialsProvider.setDefault(new AwtCredentialsProvider());
+ }
+
+ @Override
+ public boolean isInteractive() {
+ return true;
+ }
+
+ @Override
+ public boolean supports(CredentialItem... items) {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.StringType)
+ continue;
+
+ else if (i instanceof CredentialItem.CharArrayType)
+ continue;
+
+ else if (i instanceof CredentialItem.YesNoType)
+ continue;
+
+ else if (i instanceof CredentialItem.InformationalMessage)
+ continue;
+
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem {
+ if (items.length == 0) {
+ return true;
+
+ } else if (items.length == 1) {
+ final CredentialItem item = items[0];
+
+ if (item instanceof CredentialItem.InformationalMessage) {
+ JOptionPane.showMessageDialog(null, item.getPromptText(),
+ UIText.get().warning, JOptionPane.INFORMATION_MESSAGE);
+ return true;
+
+ } else if (item instanceof CredentialItem.YesNoType) {
+ CredentialItem.YesNoType v = (CredentialItem.YesNoType) item;
+ int r = JOptionPane.showConfirmDialog(null, v.getPromptText(),
+ UIText.get().warning, JOptionPane.YES_NO_OPTION);
+ switch (r) {
+ case JOptionPane.YES_OPTION:
+ v.setValue(true);
+ return true;
+
+ case JOptionPane.NO_OPTION:
+ v.setValue(false);
+ return true;
+
+ case JOptionPane.CANCEL_OPTION:
+ case JOptionPane.CLOSED_OPTION:
+ default:
+ return false;
+ }
+
+ } else {
+ return interactive(uri, items);
+ }
+
+ } else {
+ return interactive(uri, items);
+ }
+ }
+
+ private static boolean interactive(URIish uri, CredentialItem[] items) {
+ final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1,
+ GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+ new Insets(0, 0, 0, 0), 0, 0);
+ final JPanel panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+
+ final JTextField[] texts = new JTextField[items.length];
+ for (int i = 0; i < items.length; i++) {
+ CredentialItem item = items[i];
+
+ if (item instanceof CredentialItem.StringType
+ || item instanceof CredentialItem.CharArrayType) {
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.gridwidth = GridBagConstraints.RELATIVE;
+ gbc.gridx = 0;
+ panel.add(new JLabel(item.getPromptText()), gbc);
+
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.gridwidth = GridBagConstraints.RELATIVE;
+ gbc.gridx = 1;
+ if (item.isValueSecure())
+ texts[i] = new JPasswordField(20);
+ else
+ texts[i] = new JTextField(20);
+ panel.add(texts[i], gbc);
+ gbc.gridy++;
+
+ } else if (item instanceof CredentialItem.InformationalMessage) {
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.gridx = 0;
+ panel.add(new JLabel(item.getPromptText()), gbc);
+ gbc.gridy++;
+
+ } else {
+ throw new UnsupportedCredentialItem(uri, item.getPromptText());
+ }
+ }
+
+ if (JOptionPane.showConfirmDialog(null, panel,
+ UIText.get().authenticationRequired,
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) != JOptionPane.OK_OPTION)
+ return false; // cancel
+
+ for (int i = 0; i < items.length; i++) {
+ CredentialItem item = items[i];
+ JTextField f = texts[i];
+
+ if (item instanceof CredentialItem.StringType) {
+ CredentialItem.StringType v = (CredentialItem.StringType) item;
+ if (f instanceof JPasswordField)
+ v.setValue(new String(((JPasswordField) f).getPassword()));
+ else
+ v.setValue(f.getText());
+
+ } else if (item instanceof CredentialItem.CharArrayType) {
+ CredentialItem.CharArrayType v = (CredentialItem.CharArrayType) item;
+ if (f instanceof JPasswordField)
+ v.setValueNoCopy(((JPasswordField) f).getPassword());
+ else
+ v.setValueNoCopy(f.getText().toCharArray());
+ }
+ }
+ return true;
+ }
+}
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 3dfa7b4..124435a 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,50 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2">
- <resource path="META-INF/MANIFEST.MF">
- <filter comment="minor addition" id="924844039">
- <message_arguments>
- <message_argument value="3.4.0"/>
- <message_argument value="3.4.0"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/lib/ObjectInserter.java" type="org.eclipse.jgit.lib.ObjectInserter">
- <filter id="336695337">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.lib.ObjectInserter"/>
- <message_argument value="newReader()"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
- <filter comment="Doesn't break consumers. Breaking providers is allowed also in minor versions." id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
- <message_argument value="mergeTreeWalk(TreeWalk)"/>
- </message_arguments>
- </filter>
- <filter comment="Doesn't break consumers. Breaking providers is allowed also in minor versions." id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
- <message_argument value="mergeTrees(AbstractTreeIterator, RevTree, RevTree)"/>
- </message_arguments>
- </filter>
- <filter comment="Doesn't break consumers. Breaking providers is allowed also in minor versions." id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
- <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator)"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/transport/GitProtocolConstants.java" type="org.eclipse.jgit.transport.GitProtocolConstants">
- <filter id="388194388">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.transport.GitProtocolConstants"/>
- <message_argument value="CAPABILITY_ATOMIC"/>
- <message_argument value="atomic-push"/>
- </message_arguments>
- </filter>
- </resource>
<resource path="src/org/eclipse/jgit/util/FileUtil.java" type="org.eclipse.jgit.util.FileUtil">
<filter comment="moved into another bundle keeping original package" id="1110441988">
<message_arguments>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index a003b02..6028618 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -44,6 +44,7 @@
cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included.
cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}.
cannotChangeToComment=Cannot change a non-comment line to a comment line.
+cannotCheckoutOursSwitchBranch=Checking out ours/theirs is only possible when checking out index, not when switching branches.
cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff.
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}.
cannotCommitOnARepoWithState=Cannot commit on a repo with state: {0}
@@ -231,6 +232,7 @@
fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes).
fileIsTooLarge=File is too large: {0}
fileModeNotSetForPath=FileMode not set for path {0}
+findingGarbage=Finding garbage
flagIsDisposed={0} is disposed.
flagNotFromThis={0} not from this.
flagsAlreadyCreated={0} flags already created.
@@ -258,6 +260,7 @@
initFailedBareRepoDifferentDirs=When initializing a bare repo with directory {0} and separate git-dir {1} specified both folders must point to the same location
initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory {0} and separate git-dir {1} specified both folders should not point to the same location
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
+inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing.
inputStreamMustSupportMark=InputStream must support mark()
integerValueOutOfRange=Integer value {0}.{1} out of range
internalRevisionError=internal revision error
@@ -391,6 +394,7 @@
packFileInvalid=Pack file invalid: {0}
packfileIsTruncated=Packfile {0} is truncated.
packfileIsTruncatedNoParam=Packfile is truncated.
+packHandleIsStale=Pack file {0} handle is stale, removing it from pack list
packHasUnresolvedDeltas=pack has unresolved deltas
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
@@ -502,6 +506,7 @@
submoduleExists=Submodule ''{0}'' already exists in the index
submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}''
submodulesNotSupported=Submodules are not supported
+supportOnlyPackIndexVersion2=Only support index version 2
symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java.
systemConfigFileInvalid=Systen wide config file {0} is invalid {1}
tagAlreadyExists=tag ''{0}'' already exists
@@ -536,6 +541,7 @@
truncatedHunkOldLinesMissing=Truncated hunk, at least {0} old lines is missing
tSizeMustBeGreaterOrEqual1=tSize must be >= 1
unableToCheckConnectivity=Unable to check connectivity.
+unableToCreateNewObject=Unable to create new object: {0}
unableToStore=Unable to store {0}.
unableToWrite=Unable to write {0}
unencodeableFile=Unencodable file: {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index c23256c..de6c32a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -137,13 +137,12 @@ public DirCache call() throws GitAPIException, NoFilepatternException {
if (filepatterns.contains(".")) //$NON-NLS-1$
addAll = true;
- ObjectInserter inserter = repo.newObjectInserter();
- try {
+ try (ObjectInserter inserter = repo.newObjectInserter();
+ final TreeWalk tw = new TreeWalk(repo)) {
dc = repo.lockDirCache();
DirCacheIterator c;
DirCacheBuilder builder = dc.builder();
- final TreeWalk tw = new TreeWalk(repo);
tw.addTree(new DirCacheBuildIterator(builder));
if (workingTreeIterator == null)
workingTreeIterator = new FileTreeIterator(repo);
@@ -212,7 +211,6 @@ else if (!(path.equals(lastAddedFile))) {
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e);
} finally {
- inserter.release();
if (dc != null)
dc.unlock();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
index 3af8695..9cf8881 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
@@ -83,11 +83,10 @@ protected AddNoteCommand(Repository repo) {
public Note call() throws GitAPIException {
checkCallable();
- RevWalk walk = new RevWalk(repo);
- ObjectInserter inserter = repo.newObjectInserter();
NoteMap map = NoteMap.newEmptyMap();
RevCommit notesCommit = null;
- try {
+ try (RevWalk walk = new RevWalk(repo);
+ ObjectInserter inserter = repo.newObjectInserter()) {
Ref ref = repo.getRef(notesRef);
// if we have a notes ref, use it
if (ref != null) {
@@ -96,13 +95,10 @@ public Note call() throws GitAPIException {
}
map.set(id, message, inserter);
commitNoteMap(walk, map, notesCommit, inserter,
- "Notes added by 'git notes add'");
+ "Notes added by 'git notes add'"); //$NON-NLS-1$
return map.getNote(id);
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
- } finally {
- inserter.release();
- walk.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
index 9014aaf..713866d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
@@ -365,13 +365,11 @@ public ArchiveCommand(Repository repo) {
private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
final String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$
- final TreeWalk walk = new TreeWalk(repo);
- try {
+ try (final TreeWalk walk = new TreeWalk(repo)) {
final T outa = fmt.createArchiveOutputStream(out, formatOptions);
- try {
+ try (final RevWalk rw = new RevWalk(walk.getObjectReader())) {
final MutableObjectId idBuf = new MutableObjectId();
final ObjectReader reader = walk.getObjectReader();
- final RevWalk rw = new RevWalk(walk.getObjectReader());
walk.reset(rw.parseTree(tree));
if (!paths.isEmpty())
@@ -405,8 +403,6 @@ private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
// TODO(jrn): Throw finer-grained errors.
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e);
- } finally {
- walk.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
index f7ce835..a83814e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java
@@ -200,8 +200,7 @@ public BlameCommand reverse(AnyObjectId start, Collection<ObjectId> end)
*/
public BlameResult call() throws GitAPIException {
checkCallable();
- BlameGenerator gen = new BlameGenerator(repo, path);
- try {
+ try (BlameGenerator gen = new BlameGenerator(repo, path)) {
if (diffAlgorithm != null)
gen.setDiffAlgorithm(diffAlgorithm);
if (textComparator != null)
@@ -231,8 +230,6 @@ else if (startCommit != null)
return gen.computeBlameResult();
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
- } finally {
- gen.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 3787ac5..8d8aada 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -208,16 +208,17 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
}
if (createBranch) {
- Git git = new Git(repo);
- CreateBranchCommand command = git.branchCreate();
- command.setName(name);
- if (startCommit != null)
- command.setStartPoint(startCommit);
- else
- command.setStartPoint(startPoint);
- if (upstreamMode != null)
- command.setUpstreamMode(upstreamMode);
- command.call();
+ try (Git git = new Git(repo)) {
+ CreateBranchCommand command = git.branchCreate();
+ command.setName(name);
+ if (startCommit != null)
+ command.setStartPoint(startCommit);
+ else
+ command.setStartPoint(startPoint);
+ if (upstreamMode != null)
+ command.setUpstreamMode(upstreamMode);
+ command.call();
+ }
}
Ref headRef = repo.getRef(Constants.HEAD);
@@ -243,11 +244,14 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
JGitText.get().refNotResolved, name));
}
- RevWalk revWalk = new RevWalk(repo);
- AnyObjectId headId = headRef.getObjectId();
- RevCommit headCommit = headId == null ? null : revWalk
- .parseCommit(headId);
- RevCommit newCommit = revWalk.parseCommit(branch);
+ RevCommit headCommit = null;
+ RevCommit newCommit = null;
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ AnyObjectId headId = headRef.getObjectId();
+ headCommit = headId == null ? null
+ : revWalk.parseCommit(headId);
+ newCommit = revWalk.parseCommit(branch);
+ }
RevTree headTree = headCommit == null ? null : headCommit.getTree();
DirCacheCheckout dco;
DirCache dc = repo.lockDirCache();
@@ -376,26 +380,20 @@ public CheckoutCommand setAllPaths(boolean all) {
*/
protected CheckoutCommand checkoutPaths() throws IOException,
RefNotFoundException {
- RevWalk revWalk = new RevWalk(repo);
DirCache dc = repo.lockDirCache();
- try {
- TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader());
+ try (RevWalk revWalk = new RevWalk(repo);
+ TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader())) {
treeWalk.setRecursive(true);
if (!checkoutAllPaths)
treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
- try {
- if (isCheckoutIndex())
- checkoutPathsFromIndex(treeWalk, dc);
- else {
- RevCommit commit = revWalk.parseCommit(getStartPointObjectId());
- checkoutPathsFromCommit(treeWalk, dc, commit);
- }
- } finally {
- treeWalk.release();
+ if (isCheckoutIndex())
+ checkoutPathsFromIndex(treeWalk, dc);
+ else {
+ RevCommit commit = revWalk.parseCommit(getStartPointObjectId());
+ checkoutPathsFromCommit(treeWalk, dc, commit);
}
} finally {
dc.unlock();
- revWalk.release();
}
return this;
}
@@ -675,7 +673,6 @@ public CheckoutResult getResult() {
private void checkOptions() {
if (checkoutStage != null && !isCheckoutIndex())
throw new IllegalStateException(
- "Checking out ours/theirs is only possible when checking out index, "
- + "not when switching branches.");
+ JGitText.get().cannotCheckoutOursSwitchBranch);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index d4eb0b3..d6e930a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -123,8 +123,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
List<Ref> cherryPickedRefs = new LinkedList<Ref>();
checkCallable();
- RevWalk revWalk = new RevWalk(repo);
- try {
+ try (RevWalk revWalk = new RevWalk(repo)) {
// get the head commit
Ref headRef = repo.getRef(Constants.HEAD);
@@ -153,7 +152,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
merger.setBase(srcParent.getTree());
- merger.setCommitNames(new String[] { "BASE", ourName,
+ merger.setCommitNames(new String[] { "BASE", ourName, //$NON-NLS-1$
cherryPickName });
if (merger.merge(newHead, srcCommit)) {
if (AnyObjectId.equals(newHead.getTree().getId(), merger
@@ -194,8 +193,6 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
MessageFormat.format(
JGitText.get().exceptionCaughtDuringExecutionOfCherryPickCommand,
e), e);
- } finally {
- revWalk.release();
}
return new CherryPickResult(newHead, cherryPickedRefs);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
index 5b3c5d4..b121291 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickResult.java
@@ -63,21 +63,21 @@ public enum CherryPickStatus {
OK {
@Override
public String toString() {
- return "Ok";
+ return "Ok"; //$NON-NLS-1$
}
},
/** */
FAILED {
@Override
public String toString() {
- return "Failed";
+ return "Failed"; //$NON-NLS-1$
}
},
/** */
CONFLICTING {
@Override
public String toString() {
- return "Conflicting";
+ return "Conflicting"; //$NON-NLS-1$
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index f058f79..53901f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -322,12 +322,9 @@ private void addMergeConfig(Repository clonedRepo, Ref head)
private RevCommit parseCommit(final Repository clonedRepo, final Ref ref)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
- final RevWalk rw = new RevWalk(clonedRepo);
final RevCommit commit;
- try {
+ try (final RevWalk rw = new RevWalk(clonedRepo)) {
commit = rw.parseCommit(ref.getObjectId());
- } finally {
- rw.release();
}
return commit;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index b57cff7..87efd79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -165,9 +165,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
checkCallable();
Collections.sort(only);
- RevWalk rw = new RevWalk(repo);
-
- try {
+ try (RevWalk rw = new RevWalk(repo)) {
RepositoryState state = repo.getRepositoryState();
if (!state.canCommit())
throw new WrongRepositoryStateException(MessageFormat.format(
@@ -181,8 +179,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
processOptions(state, rw);
if (all && !repo.isBare() && repo.getWorkTree() != null) {
- Git git = new Git(repo);
- try {
+ try (Git git = new Git(repo)) {
git.add()
.addFilepattern(".") //$NON-NLS-1$
.setUpdate(true).call();
@@ -221,80 +218,74 @@ public RevCommit call() throws GitAPIException, NoHeadException,
// lock the index
DirCache index = repo.lockDirCache();
- try {
+ try (ObjectInserter odi = repo.newObjectInserter()) {
if (!only.isEmpty())
index = createTemporaryIndex(headId, index, rw);
- ObjectInserter odi = repo.newObjectInserter();
- try {
- // Write the index as tree to the object database. This may
- // fail for example when the index contains unmerged paths
- // (unresolved conflicts)
- ObjectId indexTreeId = index.writeTree(odi);
+ // Write the index as tree to the object database. This may
+ // fail for example when the index contains unmerged paths
+ // (unresolved conflicts)
+ ObjectId indexTreeId = index.writeTree(odi);
- if (insertChangeId)
- insertChangeId(indexTreeId);
+ if (insertChangeId)
+ insertChangeId(indexTreeId);
- // Create a Commit object, populate it and write it
- CommitBuilder commit = new CommitBuilder();
- commit.setCommitter(committer);
- commit.setAuthor(author);
- commit.setMessage(message);
+ // Create a Commit object, populate it and write it
+ CommitBuilder commit = new CommitBuilder();
+ commit.setCommitter(committer);
+ commit.setAuthor(author);
+ commit.setMessage(message);
- commit.setParentIds(parents);
- commit.setTreeId(indexTreeId);
- ObjectId commitId = odi.insert(commit);
- odi.flush();
+ commit.setParentIds(parents);
+ commit.setTreeId(indexTreeId);
+ ObjectId commitId = odi.insert(commit);
+ odi.flush();
- RevCommit revCommit = rw.parseCommit(commitId);
- RefUpdate ru = repo.updateRef(Constants.HEAD);
- ru.setNewObjectId(commitId);
- if (reflogComment != null) {
- ru.setRefLogMessage(reflogComment, false);
- } else {
- String prefix = amend ? "commit (amend): " //$NON-NLS-1$
- : parents.size() == 0 ? "commit (initial): " //$NON-NLS-1$
- : "commit: "; //$NON-NLS-1$
- ru.setRefLogMessage(
- prefix + revCommit.getShortMessage(), false);
+ RevCommit revCommit = rw.parseCommit(commitId);
+ RefUpdate ru = repo.updateRef(Constants.HEAD);
+ ru.setNewObjectId(commitId);
+ if (reflogComment != null) {
+ ru.setRefLogMessage(reflogComment, false);
+ } else {
+ String prefix = amend ? "commit (amend): " //$NON-NLS-1$
+ : parents.size() == 0 ? "commit (initial): " //$NON-NLS-1$
+ : "commit: "; //$NON-NLS-1$
+ ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
+ false);
+ }
+ if (headId != null)
+ ru.setExpectedOldObjectId(headId);
+ else
+ ru.setExpectedOldObjectId(ObjectId.zeroId());
+ Result rc = ru.forceUpdate();
+ switch (rc) {
+ case NEW:
+ case FORCED:
+ case FAST_FORWARD: {
+ setCallable(false);
+ if (state == RepositoryState.MERGING_RESOLVED
+ || isMergeDuringRebase(state)) {
+ // Commit was successful. Now delete the files
+ // used for merge commits
+ repo.writeMergeCommitMsg(null);
+ repo.writeMergeHeads(null);
+ } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
+ repo.writeMergeCommitMsg(null);
+ repo.writeCherryPickHead(null);
+ } else if (state == RepositoryState.REVERTING_RESOLVED) {
+ repo.writeMergeCommitMsg(null);
+ repo.writeRevertHead(null);
}
- if (headId != null)
- ru.setExpectedOldObjectId(headId);
- else
- ru.setExpectedOldObjectId(ObjectId.zeroId());
- Result rc = ru.forceUpdate();
- switch (rc) {
- case NEW:
- case FORCED:
- case FAST_FORWARD: {
- setCallable(false);
- if (state == RepositoryState.MERGING_RESOLVED
- || isMergeDuringRebase(state)) {
- // Commit was successful. Now delete the files
- // used for merge commits
- repo.writeMergeCommitMsg(null);
- repo.writeMergeHeads(null);
- } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
- repo.writeMergeCommitMsg(null);
- repo.writeCherryPickHead(null);
- } else if (state == RepositoryState.REVERTING_RESOLVED) {
- repo.writeMergeCommitMsg(null);
- repo.writeRevertHead(null);
- }
- return revCommit;
- }
- case REJECTED:
- case LOCK_FAILURE:
- throw new ConcurrentRefUpdateException(
- JGitText.get().couldNotLockHEAD, ru.getRef(),
- rc);
- default:
- throw new JGitInternalException(MessageFormat.format(
- JGitText.get().updatingRefFailed,
- Constants.HEAD, commitId.toString(), rc));
- }
- } finally {
- odi.release();
+ return revCommit;
+ }
+ case REJECTED:
+ case LOCK_FAILURE:
+ throw new ConcurrentRefUpdateException(
+ JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
+ default:
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().updatingRefFailed, Constants.HEAD,
+ commitId.toString(), rc));
}
} finally {
index.unlock();
@@ -304,8 +295,6 @@ public RevCommit call() throws GitAPIException, NoHeadException,
} catch (IOException e) {
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
- } finally {
- rw.dispose();
}
}
@@ -338,114 +327,120 @@ private DirCache createTemporaryIndex(ObjectId headId, DirCache index,
onlyProcessed = new boolean[only.size()];
boolean emptyCommit = true;
- TreeWalk treeWalk = new TreeWalk(repo);
- int dcIdx = treeWalk.addTree(new DirCacheBuildIterator(existingBuilder));
- int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
- int hIdx = -1;
- if (headId != null)
- hIdx = treeWalk.addTree(rw.parseTree(headId));
- treeWalk.setRecursive(true);
+ try (TreeWalk treeWalk = new TreeWalk(repo)) {
+ int dcIdx = treeWalk
+ .addTree(new DirCacheBuildIterator(existingBuilder));
+ int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
+ int hIdx = -1;
+ if (headId != null)
+ hIdx = treeWalk.addTree(rw.parseTree(headId));
+ treeWalk.setRecursive(true);
- String lastAddedFile = null;
- while (treeWalk.next()) {
- String path = treeWalk.getPathString();
- // check if current entry's path matches a specified path
- int pos = lookupOnly(path);
+ String lastAddedFile = null;
+ while (treeWalk.next()) {
+ String path = treeWalk.getPathString();
+ // check if current entry's path matches a specified path
+ int pos = lookupOnly(path);
- CanonicalTreeParser hTree = null;
- if (hIdx != -1)
- hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
+ CanonicalTreeParser hTree = null;
+ if (hIdx != -1)
+ hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
- DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
- DirCacheIterator.class);
+ DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
+ DirCacheIterator.class);
- if (pos >= 0) {
- // include entry in commit
+ if (pos >= 0) {
+ // include entry in commit
- FileTreeIterator fTree = treeWalk.getTree(fIdx,
- FileTreeIterator.class);
+ FileTreeIterator fTree = treeWalk.getTree(fIdx,
+ FileTreeIterator.class);
- // check if entry refers to a tracked file
- boolean tracked = dcTree != null || hTree != null;
- if (!tracked)
- break;
+ // check if entry refers to a tracked file
+ boolean tracked = dcTree != null || hTree != null;
+ if (!tracked)
+ break;
- // for an unmerged path, DirCacheBuildIterator will yield 3
- // entries, we only want to add one
- if (path.equals(lastAddedFile))
- continue;
+ // for an unmerged path, DirCacheBuildIterator will yield 3
+ // entries, we only want to add one
+ if (path.equals(lastAddedFile))
+ continue;
- lastAddedFile = path;
+ lastAddedFile = path;
- if (fTree != null) {
- // create a new DirCacheEntry with data retrieved from disk
- final DirCacheEntry dcEntry = new DirCacheEntry(path);
- long entryLength = fTree.getEntryLength();
- dcEntry.setLength(entryLength);
- dcEntry.setLastModified(fTree.getEntryLastModified());
- dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
+ if (fTree != null) {
+ // create a new DirCacheEntry with data retrieved from
+ // disk
+ final DirCacheEntry dcEntry = new DirCacheEntry(path);
+ long entryLength = fTree.getEntryLength();
+ dcEntry.setLength(entryLength);
+ dcEntry.setLastModified(fTree.getEntryLastModified());
+ dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
- boolean objectExists = (dcTree != null && fTree
- .idEqual(dcTree))
- || (hTree != null && fTree.idEqual(hTree));
- if (objectExists) {
- dcEntry.setObjectId(fTree.getEntryObjectId());
- } else {
- if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
+ boolean objectExists = (dcTree != null
+ && fTree.idEqual(dcTree))
+ || (hTree != null && fTree.idEqual(hTree));
+ if (objectExists) {
dcEntry.setObjectId(fTree.getEntryObjectId());
- else {
- // insert object
- if (inserter == null)
- inserter = repo.newObjectInserter();
- long contentLength = fTree.getEntryContentLength();
- InputStream inputStream = fTree.openEntryStream();
- try {
- dcEntry.setObjectId(inserter.insert(
- Constants.OBJ_BLOB, contentLength,
- inputStream));
- } finally {
- inputStream.close();
+ } else {
+ if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
+ dcEntry.setObjectId(fTree.getEntryObjectId());
+ else {
+ // insert object
+ if (inserter == null)
+ inserter = repo.newObjectInserter();
+ long contentLength = fTree
+ .getEntryContentLength();
+ InputStream inputStream = fTree
+ .openEntryStream();
+ try {
+ dcEntry.setObjectId(inserter.insert(
+ Constants.OBJ_BLOB, contentLength,
+ inputStream));
+ } finally {
+ inputStream.close();
+ }
}
}
+
+ // add to existing index
+ existingBuilder.add(dcEntry);
+ // add to temporary in-core index
+ tempBuilder.add(dcEntry);
+
+ if (emptyCommit
+ && (hTree == null || !hTree.idEqual(fTree)
+ || hTree.getEntryRawMode() != fTree
+ .getEntryRawMode()))
+ // this is a change
+ emptyCommit = false;
+ } else {
+ // if no file exists on disk, neither add it to
+ // index nor to temporary in-core index
+
+ if (emptyCommit && hTree != null)
+ // this is a change
+ emptyCommit = false;
}
- // add to existing index
- existingBuilder.add(dcEntry);
- // add to temporary in-core index
- tempBuilder.add(dcEntry);
-
- if (emptyCommit
- && (hTree == null || !hTree.idEqual(fTree) || hTree
- .getEntryRawMode() != fTree
- .getEntryRawMode()))
- // this is a change
- emptyCommit = false;
+ // keep track of processed path
+ onlyProcessed[pos] = true;
} else {
- // if no file exists on disk, neither add it to
- // index nor to temporary in-core index
+ // add entries from HEAD for all other paths
+ if (hTree != null) {
+ // create a new DirCacheEntry with data retrieved from
+ // HEAD
+ final DirCacheEntry dcEntry = new DirCacheEntry(path);
+ dcEntry.setObjectId(hTree.getEntryObjectId());
+ dcEntry.setFileMode(hTree.getEntryFileMode());
- if (emptyCommit && hTree != null)
- // this is a change
- emptyCommit = false;
+ // add to temporary in-core index
+ tempBuilder.add(dcEntry);
+ }
+
+ // preserve existing entry in index
+ if (dcTree != null)
+ existingBuilder.add(dcTree.getDirCacheEntry());
}
-
- // keep track of processed path
- onlyProcessed[pos] = true;
- } else {
- // add entries from HEAD for all other paths
- if (hTree != null) {
- // create a new DirCacheEntry with data retrieved from HEAD
- final DirCacheEntry dcEntry = new DirCacheEntry(path);
- dcEntry.setObjectId(hTree.getEntryObjectId());
- dcEntry.setFileMode(hTree.getEntryFileMode());
-
- // add to temporary in-core index
- tempBuilder.add(dcEntry);
- }
-
- // preserve existing entry in index
- if (dcTree != null)
- existingBuilder.add(dcTree.getDirCacheEntry());
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index bf6da45..be45666 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -315,7 +315,7 @@ public int compare(Candidate o1, Candidate o2) {
throw new JGitInternalException(e.getMessage(), e);
} finally {
setCallable(false);
- w.release();
+ w.close();
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
index f31198f..527daef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
@@ -124,11 +124,8 @@ public List<DiffEntry> call() throws GitAPIException {
if (head == null)
throw new NoHeadException(JGitText.get().cannotReadTree);
CanonicalTreeParser p = new CanonicalTreeParser();
- ObjectReader reader = repo.newObjectReader();
- try {
+ try (ObjectReader reader = repo.newObjectReader()) {
p.reset(reader, head);
- } finally {
- reader.release();
}
oldTree = p;
}
@@ -159,7 +156,7 @@ public List<DiffEntry> call() throws GitAPIException {
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} finally {
- diffFmt.release();
+ diffFmt.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
index cce42fc..fd28d0e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java
@@ -185,11 +185,11 @@ public Map<ObjectId, String> call() throws GitAPIException {
}
setCallable(false);
- walk.release();
return result;
} catch (IOException e) {
- walk.reset();
throw new JGitInternalException(e.getMessage(), e);
+ } finally {
+ walk.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 7d3e823..62001d0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -1088,7 +1088,9 @@ else if (!isInteractive() && walk.isMergedInto(headCommit, upstream)) {
rebaseState.createFile(HEAD_NAME, headName);
rebaseState.createFile(ONTO, upstreamCommit.name());
rebaseState.createFile(ONTO_NAME, upstreamCommitName);
- rebaseState.createFile(INTERACTIVE, ""); //$NON-NLS-1$
+ if (isInteractive()) {
+ rebaseState.createFile(INTERACTIVE, ""); //$NON-NLS-1$
+ }
rebaseState.createFile(QUIET, ""); //$NON-NLS-1$
ArrayList<RebaseTodoLine> toDoSteps = new ArrayList<RebaseTodoLine>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 17b1242..ac67037 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -227,9 +227,9 @@ else if (repo.readSquashCommitMsg() != null)
setCallable(false);
return result;
} catch (IOException e) {
- throw new JGitInternalException(
+ throw new JGitInternalException(MessageFormat.format(
JGitText.get().exceptionCaughtDuringExecutionOfResetCommand,
- e);
+ e.getMessage()), e);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
index 735eef7..e34db38 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
@@ -85,7 +85,7 @@ public static BlameResult create(BlameGenerator gen) throws IOException {
String path = gen.getResultPath();
RawText contents = gen.getResultContents();
if (contents == null) {
- gen.release();
+ gen.close();
return null;
}
return new BlameResult(gen, path, contents);
@@ -239,7 +239,7 @@ public void computeAll() throws IOException {
while (gen.next())
loadFrom(gen);
} finally {
- gen.release();
+ gen.close();
generator = null;
}
}
@@ -265,7 +265,7 @@ public int computeNext() throws IOException {
lastLength = gen.getRegionLength();
return gen.getResultStart();
} else {
- gen.release();
+ gen.close();
generator = null;
return -1;
}
@@ -300,7 +300,7 @@ public void computeRange(int start, int end) throws IOException {
return;
if (!gen.next()) {
- gen.release();
+ gen.close();
generator = null;
return;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index 1aab51e..b71e990 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -173,7 +173,7 @@ protected OutputStream getOutputStream() {
*/
public void setRepository(Repository repository) {
if (reader != null)
- reader.release();
+ reader.close();
db = repository;
reader = db.newObjectReader();
@@ -422,10 +422,11 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
throws IOException {
assertHaveRepository();
- RevWalk rw = new RevWalk(reader);
- RevTree aTree = a != null ? rw.parseTree(a) : null;
- RevTree bTree = b != null ? rw.parseTree(b) : null;
- return scan(aTree, bTree);
+ try (RevWalk rw = new RevWalk(reader)) {
+ RevTree aTree = a != null ? rw.parseTree(a) : null;
+ RevTree bTree = b != null ? rw.parseTree(b) : null;
+ return scan(aTree, bTree);
+ }
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 98a1c8c..6d9a32d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -961,9 +961,8 @@ private void registerIndexChangedListener(IndexChangedListener listener) {
* @throws IOException
*/
private void updateSmudgedEntries() throws IOException {
- TreeWalk walk = new TreeWalk(repository);
List<String> paths = new ArrayList<String>(128);
- try {
+ try (TreeWalk walk = new TreeWalk(repository)) {
for (int i = 0; i < entryCnt; i++)
if (sortedEntries[i].isSmudged())
paths.add(sortedEntries[i].getPathString());
@@ -989,8 +988,6 @@ private void updateSmudgedEntries() throws IOException {
entry.setLastModified(fIter.getEntryLastModified());
}
}
- } finally {
- walk.release();
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 015d9d6..99e022b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -1284,10 +1284,8 @@ private static void checkValidPath(CanonicalTreeParser t)
* @throws InvalidPathException
* if the path is invalid
* @since 3.3
- * @deprecated Use {@link SystemReader#checkPath(String)}.
*/
- @Deprecated
- public static void checkValidPath(String path) throws InvalidPathException {
+ static void checkValidPath(String path) throws InvalidPathException {
try {
SystemReader.getInstance().checkPath(path);
} catch (CorruptObjectException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 63b788f..3077e18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -103,6 +103,7 @@ public static JGitText get() {
/***/ public String cannotBeRecursiveWhenTreesAreIncluded;
/***/ public String cannotChangeActionOnComment;
/***/ public String cannotChangeToComment;
+ /***/ public String cannotCheckoutOursSwitchBranch;
/***/ public String cannotCombineSquashWithNoff;
/***/ public String cannotCombineTreeFilterWithRevFilter;
/***/ public String cannotCommitOnARepoWithState;
@@ -290,6 +291,7 @@ public static JGitText get() {
/***/ public String fileIsTooBigForThisConvenienceMethod;
/***/ public String fileIsTooLarge;
/***/ public String fileModeNotSetForPath;
+ /***/ public String findingGarbage;
/***/ public String flagIsDisposed;
/***/ public String flagNotFromThis;
/***/ public String flagsAlreadyCreated;
@@ -317,6 +319,7 @@ public static JGitText get() {
/***/ public String initFailedBareRepoDifferentDirs;
/***/ public String initFailedNonBareRepoSameDirs;
/***/ public String inMemoryBufferLimitExceeded;
+ /***/ public String inputDidntMatchLength;
/***/ public String inputStreamMustSupportMark;
/***/ public String integerValueOutOfRange;
/***/ public String internalRevisionError;
@@ -450,6 +453,7 @@ public static JGitText get() {
/***/ public String packFileInvalid;
/***/ public String packfileIsTruncated;
/***/ public String packfileIsTruncatedNoParam;
+ /***/ public String packHandleIsStale;
/***/ public String packHasUnresolvedDeltas;
/***/ public String packingCancelledDuringObjectsWriting;
/***/ public String packObjectCountMismatch;
@@ -561,6 +565,7 @@ public static JGitText get() {
/***/ public String submoduleExists;
/***/ public String submodulesNotSupported;
/***/ public String submoduleParentRemoteUrlInvalid;
+ /***/ public String supportOnlyPackIndexVersion2;
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
/***/ public String systemConfigFileInvalid;
/***/ public String tagAlreadyExists;
@@ -595,6 +600,7 @@ public static JGitText get() {
/***/ public String truncatedHunkOldLinesMissing;
/***/ public String tSizeMustBeGreaterOrEqual1;
/***/ public String unableToCheckConnectivity;
+ /***/ public String unableToCreateNewObject;
/***/ public String unableToStore;
/***/ public String unableToWrite;
/***/ public String unencodeableFile;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
index c185332..7926536 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
@@ -46,7 +46,6 @@
package org.eclipse.jgit.internal.storage.dfs;
import java.io.IOException;
-import java.security.MessageDigest;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -101,12 +100,9 @@ void crc32(CRC32 out, long pos, int cnt) {
out.update(block, ptr, cnt);
}
- void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
+ void write(PackOutputStream out, long pos, int cnt)
throws IOException {
- int ptr = (int) (pos - start);
- out.write(block, ptr, cnt);
- if (digest != null)
- digest.update(block, ptr, cnt);
+ out.write(block, (int) (pos - start), cnt);
}
void check(Inflater inf, byte[] tmp, long pos, int cnt)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
index 748a4a3..2e170a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
@@ -135,6 +135,9 @@ public static DfsBlockCache getInstance() {
/** Maximum number of bytes the cache should hold. */
private final long maxBytes;
+ /** Pack files smaller than this size can be copied through the cache. */
+ private final long maxStreamThroughCache;
+
/**
* Suggested block size to read from pack files in.
* <p>
@@ -191,6 +194,7 @@ else if (eb < 4)
eb = tableSize;
maxBytes = cfg.getBlockLimit();
+ maxStreamThroughCache = (long) (maxBytes * cfg.getStreamRatio());
blockSize = cfg.getBlockSize();
blockSizeShift = Integer.numberOfTrailingZeros(blockSize);
@@ -206,6 +210,10 @@ else if (eb < 4)
statMiss = new AtomicLong();
}
+ boolean shouldCopyThroughCache(long length) {
+ return length <= maxStreamThroughCache;
+ }
+
/** @return total number of bytes in the cache. */
public long getCurrentSize() {
return liveBytes;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
index ca1451a..a7d13de 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
@@ -47,7 +47,11 @@
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Config;
/** Configuration parameters for {@link DfsBlockCache}. */
@@ -59,13 +63,14 @@ public class DfsBlockCacheConfig {
public static final int MB = 1024 * KB;
private long blockLimit;
-
private int blockSize;
+ private double streamRatio;
/** Create a default configuration. */
public DfsBlockCacheConfig() {
setBlockLimit(32 * MB);
setBlockSize(64 * KB);
+ setStreamRatio(0.30);
}
/**
@@ -106,6 +111,27 @@ public DfsBlockCacheConfig setBlockSize(final int newSize) {
}
/**
+ * @return highest percentage of {@link #getBlockLimit()} a single pack can
+ * occupy while being copied by the pack reuse strategy. <b>Default
+ * is 0.30, or 30%</b>.
+ * @since 4.0
+ */
+ public double getStreamRatio() {
+ return streamRatio;
+ }
+
+ /**
+ * @param ratio
+ * percentage of cache to occupy with a copied pack.
+ * @return {@code this}
+ * @since 4.0
+ */
+ public DfsBlockCacheConfig setStreamRatio(double ratio) {
+ streamRatio = Math.max(0, Math.min(ratio, 1.0));
+ return this;
+ }
+
+ /**
* Update properties by setting fields from the configuration.
* <p>
* If a property is not defined in the configuration, then it is left
@@ -127,6 +153,22 @@ public DfsBlockCacheConfig fromConfig(final Config rc) {
CONFIG_DFS_SECTION,
CONFIG_KEY_BLOCK_SIZE,
getBlockSize()));
+
+ String v = rc.getString(
+ CONFIG_CORE_SECTION,
+ CONFIG_DFS_SECTION,
+ CONFIG_KEY_STREAM_RATIO);
+ if (v != null) {
+ try {
+ setStreamRatio(Double.parseDouble(v));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().enumValueNotSupported3,
+ CONFIG_CORE_SECTION,
+ CONFIG_DFS_SECTION,
+ CONFIG_KEY_STREAM_RATIO, v));
+ }
+ }
return this;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
index 3da5184..a5308f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java
@@ -78,8 +78,7 @@ public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
return ((DfsObjectRepresentation) rep).pack == pack;
}
- void copyAsIs(PackOutputStream out, boolean validate, DfsReader ctx)
- throws IOException {
- pack.copyPackAsIs(out, validate, ctx);
+ void copyAsIs(PackOutputStream out, DfsReader ctx) throws IOException {
+ pack.copyPackAsIs(out, ctx);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
index deb6b7f..fed5338 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -58,6 +58,7 @@
import java.util.Map;
import java.util.Set;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.file.PackIndex;
import org.eclipse.jgit.internal.storage.pack.PackExt;
@@ -188,7 +189,8 @@ public boolean pack(ProgressMonitor pm) throws IOException {
if (pm == null)
pm = NullProgressMonitor.INSTANCE;
if (packConfig.getIndexVersion() != 2)
- throw new IllegalStateException("Only index version 2");
+ throw new IllegalStateException(
+ JGitText.get().supportOnlyPackIndexVersion2);
ctx = (DfsReader) objdb.newReader();
try {
@@ -272,14 +274,11 @@ private void packHeads(ProgressMonitor pm) throws IOException {
if (allHeads.isEmpty())
return;
- PackWriter pw = newPackWriter();
- try {
+ try (PackWriter pw = newPackWriter()) {
pw.setTagTargets(tagTargets);
pw.preparePack(pm, allHeads, Collections.<ObjectId> emptySet());
if (0 < pw.getObjectCount())
writePack(GC, pw, pm);
- } finally {
- pw.release();
}
}
@@ -287,15 +286,12 @@ private void packRest(ProgressMonitor pm) throws IOException {
if (nonHeads.isEmpty())
return;
- PackWriter pw = newPackWriter();
- try {
+ try (PackWriter pw = newPackWriter()) {
for (PackWriter.ObjectIdSet packedObjs : newPackObj)
pw.excludeObjects(packedObjs);
pw.preparePack(pm, nonHeads, allHeads);
if (0 < pw.getObjectCount())
writePack(GC, pw, pm);
- } finally {
- pw.release();
}
}
@@ -307,12 +303,11 @@ private void packGarbage(ProgressMonitor pm) throws IOException {
cfg.setDeltaCompress(false);
cfg.setBuildBitmaps(false);
- PackWriter pw = new PackWriter(cfg, ctx);
- pw.setDeltaBaseAsOffset(true);
- pw.setReuseDeltaCommits(true);
- try {
- RevWalk pool = new RevWalk(ctx);
- pm.beginTask("Finding garbage", objectsBefore());
+ try (PackWriter pw = new PackWriter(cfg, ctx);
+ RevWalk pool = new RevWalk(ctx)) {
+ pw.setDeltaBaseAsOffset(true);
+ pw.setReuseDeltaCommits(true);
+ pm.beginTask(JGitText.get().findingGarbage, objectsBefore());
for (DfsPackFile oldPack : packsBefore) {
PackIndex oldIdx = oldPack.getPackIndex(ctx);
for (PackIndex.MutableEntry ent : oldIdx) {
@@ -328,8 +323,6 @@ private void packGarbage(ProgressMonitor pm) throws IOException {
pm.endTask();
if (0 < pw.getObjectCount())
writePack(UNREACHABLE_GARBAGE, pw, pm);
- } finally {
- pw.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index 58df895..e03488b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -54,6 +54,7 @@
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.text.MessageFormat;
import java.util.Set;
@@ -80,7 +81,6 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.LongList;
/**
@@ -464,11 +464,73 @@ long getObjectCount(DfsReader ctx) throws IOException {
return dstbuf;
}
- void copyPackAsIs(PackOutputStream out, boolean validate, DfsReader ctx)
+ void copyPackAsIs(PackOutputStream out, DfsReader ctx)
throws IOException {
- // Pin the first window, this ensures the length is accurate.
- ctx.pin(this, 0);
- ctx.copyPackAsIs(this, length, validate, out);
+ // If the length hasn't been determined yet, pin to set it.
+ if (length == -1) {
+ ctx.pin(this, 0);
+ ctx.unpin();
+ }
+ if (cache.shouldCopyThroughCache(length))
+ copyPackThroughCache(out, ctx);
+ else
+ copyPackBypassCache(out, ctx);
+ }
+
+ private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
+ throws IOException {
+ long position = 12;
+ long remaining = length - (12 + 20);
+ while (0 < remaining) {
+ DfsBlock b = cache.getOrLoad(this, position, ctx);
+ int ptr = (int) (position - b.start);
+ int n = (int) Math.min(b.size() - ptr, remaining);
+ b.write(out, position, n);
+ position += n;
+ remaining -= n;
+ }
+ }
+
+ private long copyPackBypassCache(PackOutputStream out, DfsReader ctx)
+ throws IOException {
+ try (ReadableChannel rc = ctx.db.openFile(packDesc, PACK)) {
+ ByteBuffer buf = newCopyBuffer(out, rc);
+ if (ctx.getOptions().getStreamPackBufferSize() > 0)
+ rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize());
+ long position = 12;
+ long remaining = length - (12 + 20);
+ while (0 < remaining) {
+ DfsBlock b = cache.get(key, alignToBlock(position));
+ if (b != null) {
+ int ptr = (int) (position - b.start);
+ int n = (int) Math.min(b.size() - ptr, remaining);
+ b.write(out, position, n);
+ position += n;
+ remaining -= n;
+ rc.position(position);
+ continue;
+ }
+
+ buf.position(0);
+ int n = read(rc, buf);
+ if (n <= 0)
+ throw packfileIsTruncated();
+ else if (n > remaining)
+ n = (int) remaining;
+ out.write(buf.array(), 0, n);
+ position += n;
+ remaining -= n;
+ }
+ return position;
+ }
+ }
+
+ private ByteBuffer newCopyBuffer(PackOutputStream out, ReadableChannel rc) {
+ int bs = blockSize(rc);
+ byte[] copyBuf = out.getCopyBuffer();
+ if (bs > copyBuf.length)
+ copyBuf = new byte[bs];
+ return ByteBuffer.wrap(copyBuf, 0, bs);
}
void copyAsIs(PackOutputStream out, DfsObjectToPack src,
@@ -617,7 +679,7 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
// and we have it pinned. Write this out without copying.
//
out.writeHeader(src, inflatedLength);
- quickCopy.write(out, dataOffset, (int) dataLength, null);
+ quickCopy.write(out, dataOffset, (int) dataLength);
} else if (dataLength <= buf.length) {
// Tiny optimization: Lots of objects are very small deltas or
@@ -668,6 +730,12 @@ void setInvalid() {
invalid = true;
}
+ private IOException packfileIsTruncated() {
+ invalid = true;
+ return new IOException(MessageFormat.format(
+ JGitText.get().packfileIsTruncated, getPackName()));
+ }
+
private void readFully(long position, byte[] dstbuf, int dstoff, int cnt,
DfsReader ctx) throws IOException {
if (ctx.copy(this, position, dstbuf, dstoff, cnt) != cnt)
@@ -692,18 +760,8 @@ DfsBlock readOneBlock(long pos, DfsReader ctx)
ReadableChannel rc = ctx.db.openFile(packDesc, PACK);
try {
- // If the block alignment is not yet known, discover it. Prefer the
- // larger size from either the cache or the file itself.
- int size = blockSize;
- if (size == 0) {
- size = rc.blockSize();
- if (size <= 0)
- size = cache.getBlockSize();
- else if (size < cache.getBlockSize())
- size = (cache.getBlockSize() / size) * size;
- blockSize = size;
- pos = (pos / size) * size;
- }
+ int size = blockSize(rc);
+ pos = (pos / size) * size;
// If the size of the file is not yet known, try to discover it.
// Channels may choose to return -1 to indicate they don't
@@ -725,7 +783,7 @@ else if (size < cache.getBlockSize())
byte[] buf = new byte[size];
rc.position(pos);
- int cnt = IO.read(rc, buf, 0, size);
+ int cnt = read(rc, ByteBuffer.wrap(buf, 0, size));
if (cnt != size) {
if (0 <= len) {
throw new EOFException(MessageFormat.format(
@@ -754,6 +812,30 @@ else if (size < cache.getBlockSize())
}
}
+ private int blockSize(ReadableChannel rc) {
+ // If the block alignment is not yet known, discover it. Prefer the
+ // larger size from either the cache or the file itself.
+ int size = blockSize;
+ if (size == 0) {
+ size = rc.blockSize();
+ if (size <= 0)
+ size = cache.getBlockSize();
+ else if (size < cache.getBlockSize())
+ size = (cache.getBlockSize() / size) * size;
+ blockSize = size;
+ }
+ return size;
+ }
+
+ private static int read(ReadableChannel rc, ByteBuffer buf)
+ throws IOException {
+ int n;
+ do {
+ n = rc.read(buf);
+ } while (0 < n && buf.hasRemaining());
+ return buf.position();
+ }
+
ObjectLoader load(DfsReader ctx, long pos)
throws IOException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
index 4cf7cbe..f5f3375 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -44,14 +44,10 @@
package org.eclipse.jgit.internal.storage.dfs;
-import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
import java.io.IOException;
-import java.security.MessageDigest;
-import java.text.MessageFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -65,7 +61,6 @@
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
-import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
import org.eclipse.jgit.internal.storage.file.PackIndex;
@@ -81,7 +76,6 @@
import org.eclipse.jgit.lib.AsyncObjectSizeQueue;
import org.eclipse.jgit.lib.BitmapIndex;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.InflaterCache;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -498,9 +492,9 @@ public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
out.writeObject(otp);
}
- public void copyPackAsIs(PackOutputStream out, CachedPack pack,
- boolean validate) throws IOException {
- ((DfsCachedPack) pack).copyAsIs(out, validate, this);
+ public void copyPackAsIs(PackOutputStream out, CachedPack pack)
+ throws IOException {
+ ((DfsCachedPack) pack).copyAsIs(out, this);
}
/**
@@ -547,52 +541,6 @@ int copy(DfsPackFile pack, long position, byte[] dstbuf, int dstoff, int cnt)
return cnt - need;
}
- void copyPackAsIs(DfsPackFile pack, long length, boolean validate,
- PackOutputStream out) throws IOException {
- MessageDigest md = null;
- if (validate) {
- md = Constants.newMessageDigest();
- byte[] buf = out.getCopyBuffer();
- pin(pack, 0);
- if (block.copy(0, buf, 0, 12) != 12) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileIsTruncated, pack.getPackName()));
- }
- md.update(buf, 0, 12);
- }
-
- long position = 12;
- long remaining = length - (12 + 20);
- while (0 < remaining) {
- pin(pack, position);
-
- int ptr = (int) (position - block.start);
- int n = (int) Math.min(block.size() - ptr, remaining);
- block.write(out, position, n, md);
- position += n;
- remaining -= n;
- }
-
- if (md != null) {
- byte[] buf = new byte[20];
- byte[] actHash = md.digest();
-
- pin(pack, position);
- if (block.copy(position, buf, 0, 20) != 20) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileIsTruncated, pack.getPackName()));
- }
- if (!Arrays.equals(actHash, buf)) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileCorruptionDetected,
- pack.getPackDescription().getFileName(PACK)));
- }
- }
- }
-
/**
* Inflate a region of the pack starting at {@code position}.
*
@@ -664,6 +612,10 @@ void pin(DfsPackFile pack, long position) throws IOException {
}
}
+ void unpin() {
+ block = null;
+ }
+
/** Release the current window cursor. */
@Override
public void release() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
index 2a62547..8419807 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
@@ -46,6 +46,7 @@
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DELTA_BASE_CACHE_LIMIT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_BUFFER;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_FILE_TRESHOLD;
import org.eclipse.jgit.lib.Config;
@@ -60,9 +61,10 @@ public class DfsReaderOptions {
public static final int MiB = 1024 * KiB;
private int deltaBaseCacheLimit;
-
private int streamFileThreshold;
+ private int streamPackBufferSize;
+
/** Create a default reader configuration. */
public DfsReaderOptions() {
setDeltaBaseCacheLimit(10 * MiB);
@@ -105,6 +107,27 @@ public DfsReaderOptions setStreamFileThreshold(final int newLimit) {
}
/**
+ * @return number of bytes to use for buffering when streaming a pack file
+ * during copying. If 0 the block size of the pack is used.
+ * @since 4.0
+ */
+ public int getStreamPackBufferSize() {
+ return streamPackBufferSize;
+ }
+
+ /**
+ * @param bufsz
+ * new buffer size in bytes for buffers used when streaming pack
+ * files during copying.
+ * @return {@code this}
+ * @since 4.0
+ */
+ public DfsReaderOptions setStreamPackBufferSize(int bufsz) {
+ streamPackBufferSize = Math.max(0, bufsz);
+ return this;
+ }
+
+ /**
* Update properties by setting fields from the configuration.
* <p>
* If a property is not defined in the configuration, then it is left
@@ -130,6 +153,12 @@ public DfsReaderOptions fromConfig(Config rc) {
sft = Math.min(sft, maxMem / 4); // don't use more than 1/4 of the heap
sft = Math.min(sft, Integer.MAX_VALUE); // cannot exceed array length
setStreamFileThreshold((int) sft);
+
+ setStreamPackBufferSize(rc.getInt(
+ CONFIG_CORE_SECTION,
+ CONFIG_DFS_SECTION,
+ CONFIG_KEY_STREAM_BUFFER,
+ getStreamPackBufferSize()));
return this;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index ae05536..8e7af0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -227,6 +227,10 @@ public long size() {
public int blockSize() {
return 0;
}
+
+ public void setReadAheadBytes(int b) {
+ // Unnecessary on a byte array.
+ }
}
private class MemRefDatabase extends DfsRefDatabase {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
index 5ec7079..240d552 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java
@@ -100,4 +100,33 @@ public interface ReadableChannel extends ReadableByteChannel {
* not need to be a power of 2.
*/
public int blockSize();
+
+ /**
+ * Recommend the channel maintain a read-ahead buffer.
+ * <p>
+ * A read-ahead buffer of approximately {@code bufferSize} in bytes may be
+ * allocated and used by the channel to smooth out latency for read.
+ * <p>
+ * Callers can continue to read in smaller than {@code bufferSize} chunks.
+ * With read-ahead buffering enabled read latency may fluctuate in a pattern
+ * of one slower read followed by {@code (bufferSize / readSize) - 1} fast
+ * reads satisfied by the read-ahead buffer. When summed up overall time to
+ * read the same contiguous range should be lower than if read-ahead was not
+ * enabled, as the implementation can combine reads to increase throughput.
+ * <p>
+ * To avoid unnecessary IO callers should only enable read-ahead if the
+ * majority of the channel will be accessed in order.
+ * <p>
+ * Implementations may chose to read-ahead using asynchronous APIs or
+ * background threads, or may simply aggregate reads using a buffer.
+ * <p>
+ * This read ahead stays in effect until the channel is closed or the buffer
+ * size is set to 0.
+ *
+ * @param bufferSize
+ * requested size of the read ahead buffer, in bytes.
+ * @throws IOException
+ * if the read ahead cannot be adjusted.
+ */
+ public void setReadAheadBytes(int bufferSize) throws IOException;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
index 863c553..dc720bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteArrayWindow.java
@@ -46,7 +46,6 @@
package org.eclipse.jgit.internal.storage.file;
import java.io.IOException;
-import java.security.MessageDigest;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -84,12 +83,10 @@ void crc32(CRC32 out, long pos, int cnt) {
}
@Override
- void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
+ void write(PackOutputStream out, long pos, int cnt)
throws IOException {
int ptr = (int) (pos - start);
out.write(array, ptr, cnt);
- if (digest != null)
- digest.update(array, ptr, cnt);
}
void check(Inflater inf, byte[] tmp, long pos, int cnt)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
index 31925d2..05ddd69 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteBufferWindow.java
@@ -47,7 +47,6 @@
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.security.MessageDigest;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -76,7 +75,7 @@ protected int copy(final int p, final byte[] b, final int o, int n) {
}
@Override
- void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
+ void write(PackOutputStream out, long pos, int cnt)
throws IOException {
final ByteBuffer s = buffer.slice();
s.position((int) (pos - start));
@@ -86,8 +85,6 @@ void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
int n = Math.min(cnt, buf.length);
s.get(buf, 0, n);
out.write(buf, 0, n);
- if (digest != null)
- digest.update(buf, 0, n);
cnt -= n;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
index ab5eb7c..e774a14 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ByteWindow.java
@@ -45,7 +45,6 @@
package org.eclipse.jgit.internal.storage.file;
import java.io.IOException;
-import java.security.MessageDigest;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -121,8 +120,8 @@ final int copy(long pos, byte[] dstbuf, int dstoff, int cnt) {
*/
protected abstract int copy(int pos, byte[] dstbuf, int dstoff, int cnt);
- abstract void write(PackOutputStream out, long pos, int cnt,
- MessageDigest md) throws IOException;
+ abstract void write(PackOutputStream out, long pos, int cnt)
+ throws IOException;
final int setInput(long pos, Inflater inf) throws DataFormatException {
return setInput((int) (pos - start), inf);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 48335e4..338106f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -618,22 +618,19 @@ private Map<String, Ref> getAllRefs() throws IOException {
*/
private Set<ObjectId> listNonHEADIndexObjects()
throws CorruptObjectException, IOException {
- RevWalk revWalk = null;
try {
if (repo.getIndexFile() == null)
return Collections.emptySet();
} catch (NoWorkTreeException e) {
return Collections.emptySet();
}
- TreeWalk treeWalk = new TreeWalk(repo);
- try {
+ try (TreeWalk treeWalk = new TreeWalk(repo)) {
treeWalk.addTree(new DirCacheIterator(repo.readDirCache()));
ObjectId headID = repo.resolve(Constants.HEAD);
if (headID != null) {
- revWalk = new RevWalk(repo);
- treeWalk.addTree(revWalk.parseTree(headID));
- revWalk.dispose();
- revWalk = null;
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ treeWalk.addTree(revWalk.parseTree(headID));
+ }
}
treeWalk.setFilter(TreeFilter.ANY_DIFF);
@@ -662,10 +659,6 @@ private Set<ObjectId> listNonHEADIndexObjects()
}
}
return ret;
- } finally {
- if (revWalk != null)
- revWalk.dispose();
- treeWalk.release();
}
}
@@ -689,8 +682,9 @@ public int compare(PackExt o1, PackExt o2) {
}
});
- PackWriter pw = new PackWriter((pconfig == null) ? new PackConfig(repo) : pconfig, repo.newObjectReader());
- try {
+ try (PackWriter pw = new PackWriter(
+ (pconfig == null) ? new PackConfig(repo) : pconfig,
+ repo.newObjectReader())) {
// prepare the PackWriter
pw.setDeltaBaseAsOffset(true);
pw.setReuseDeltaCommits(false);
@@ -810,7 +804,6 @@ public int compare(PackExt o1, PackExt o2) {
}
return repo.getObjectDatabase().openPack(realPack);
} finally {
- pw.release();
if (tmpPack != null && tmpPack.exists())
tmpPack.delete();
for (File tmpExt : tmpExts.values()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
index b70ebcf..fd9dcda 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalCachedPack.java
@@ -79,10 +79,10 @@ public long getObjectCount() throws IOException {
return cnt;
}
- void copyAsIs(PackOutputStream out, boolean validate, WindowCursor wc)
+ void copyAsIs(PackOutputStream out, WindowCursor wc)
throws IOException {
for (PackFile pack : getPacks())
- pack.copyPackAsIs(out, validate, wc);
+ pack.copyPackAsIs(out, wc);
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 687408e..796109a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -114,6 +114,8 @@ public class ObjectDirectory extends FileObjectDatabase {
/** Maximum number of candidates offered as resolutions of abbreviation. */
private static final int RESOLVE_ABBREV_LIMIT = 256;
+ private static final String STALE_FILE_HANDLE_MSG = "stale file handle"; //$NON-NLS-1$
+
private final Config config;
private final File objects;
@@ -554,22 +556,35 @@ void selectObjectRepresentation(PackWriter packer, ObjectToPack otp,
}
private void handlePackError(IOException e, PackFile p) {
- String tmpl;
+ String warnTmpl = null;
if ((e instanceof CorruptObjectException)
|| (e instanceof PackInvalidException)) {
- tmpl = JGitText.get().corruptPack;
+ warnTmpl = JGitText.get().corruptPack;
// Assume the pack is corrupted, and remove it from the list.
removePack(p);
} else if (e instanceof FileNotFoundException) {
- tmpl = JGitText.get().packWasDeleted;
+ warnTmpl = JGitText.get().packWasDeleted;
removePack(p);
+ } else if (e.getMessage() != null
+ && e.getMessage().toLowerCase().contains(STALE_FILE_HANDLE_MSG)) {
+ warnTmpl = JGitText.get().packHandleIsStale;
+ removePack(p);
+ }
+ if (warnTmpl != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(MessageFormat.format(warnTmpl,
+ p.getPackFile().getAbsolutePath()), e);
+ } else {
+ LOG.warn(MessageFormat.format(warnTmpl,
+ p.getPackFile().getAbsolutePath()));
+ }
} else {
- tmpl = JGitText.get().exceptionWhileReadingPack;
// Don't remove the pack from the list, as the error may be
// transient.
+ LOG.error(MessageFormat.format(
+ JGitText.get().exceptionWhileReadingPack, p.getPackFile()
+ .getAbsolutePath()), e);
}
- LOG.error(MessageFormat.format(tmpl,
- p.getPackFile().getAbsolutePath()), e);
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
index 812c899..eb87460 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
@@ -55,10 +55,12 @@
import java.nio.channels.Channels;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
+import java.text.MessageFormat;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import org.eclipse.jgit.errors.ObjectWritingException;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -123,7 +125,8 @@ private ObjectId insertOneObject(final File tmp, final ObjectId id)
}
final File dst = db.fileFor(id);
- throw new ObjectWritingException("Unable to create new object: " + dst);
+ throw new ObjectWritingException(MessageFormat
+ .format(JGitText.get().unableToCreateNewObject, dst));
}
@Override
@@ -242,7 +245,7 @@ DeflaterOutputStream compress(final OutputStream out) {
}
private static EOFException shortInput(long missing) {
- return new EOFException("Input did not match supplied length. "
- + missing + " bytes are missing.");
+ return new EOFException(MessageFormat.format(
+ JGitText.get().inputDidntMatchLength, Long.valueOf(missing)));
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index eb22938..75c361e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -344,11 +344,11 @@ ObjectId findObjectForOffset(final long offset) throws IOException {
return dstbuf;
}
- void copyPackAsIs(PackOutputStream out, boolean validate, WindowCursor curs)
+ void copyPackAsIs(PackOutputStream out, WindowCursor curs)
throws IOException {
// Pin the first window, this ensures the length is accurate.
curs.pin(this, 0);
- curs.copyPackAsIs(this, length, validate, out);
+ curs.copyPackAsIs(this, length, out);
}
final void copyAsIs(PackOutputStream out, LocalObjectToPack src,
@@ -362,6 +362,7 @@ final void copyAsIs(PackOutputStream out, LocalObjectToPack src,
}
}
+ @SuppressWarnings("null")
private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
boolean validate, WindowCursor curs) throws IOException,
StoredObjectRepresentationNotAvailableException {
@@ -501,7 +502,7 @@ private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
// and we have it pinned. Write this out without copying.
//
out.writeHeader(src, inflatedLength);
- quickCopy.write(out, dataOffset, (int) dataLength, null);
+ quickCopy.write(out, dataOffset, (int) dataLength);
} else if (dataLength <= buf.length) {
// Tiny optimization: Lots of objects are very small deltas or
@@ -703,6 +704,7 @@ private void onOpenPack() throws IOException {
, getPackFile()));
}
+ @SuppressWarnings("null")
ObjectLoader load(final WindowCursor curs, long pos)
throws IOException, LargeObjectException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
index 70cf20f..cb8c91a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
@@ -232,7 +232,7 @@ public long findCRC32(AnyObjectId objId) throws MissingObjectException {
final int levelOne = objId.getFirstByte();
final int levelTwo = binarySearchLevelTwo(objId, levelOne);
if (levelTwo == -1)
- throw new MissingObjectException(objId.copy(), "unknown");
+ throw new MissingObjectException(objId.copy(), "unknown"); //$NON-NLS-1$
return NB.decodeUInt32(crc32[levelOne], levelTwo << 2);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 85c3c74..21d6cd2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -45,9 +45,6 @@
package org.eclipse.jgit.internal.storage.file;
import java.io.IOException;
-import java.security.MessageDigest;
-import java.text.MessageFormat;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -59,7 +56,6 @@
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
-import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.pack.CachedPack;
import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
@@ -232,27 +228,13 @@ int copy(final PackFile pack, long position, final byte[] dstbuf,
return cnt - need;
}
- public void copyPackAsIs(PackOutputStream out, CachedPack pack,
- boolean validate) throws IOException {
- ((LocalCachedPack) pack).copyAsIs(out, validate, this);
+ public void copyPackAsIs(PackOutputStream out, CachedPack pack)
+ throws IOException {
+ ((LocalCachedPack) pack).copyAsIs(out, this);
}
- void copyPackAsIs(final PackFile pack, final long length, boolean validate,
+ void copyPackAsIs(final PackFile pack, final long length,
final PackOutputStream out) throws IOException {
- MessageDigest md = null;
- if (validate) {
- md = Constants.newMessageDigest();
- byte[] buf = out.getCopyBuffer();
- pin(pack, 0);
- if (window.copy(0, buf, 0, 12) != 12) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileIsTruncated, pack.getPackFile()
- .getPath()));
- }
- md.update(buf, 0, 12);
- }
-
long position = 12;
long remaining = length - (12 + 20);
while (0 < remaining) {
@@ -260,29 +242,10 @@ void copyPackAsIs(final PackFile pack, final long length, boolean validate,
int ptr = (int) (position - window.start);
int n = (int) Math.min(window.size() - ptr, remaining);
- window.write(out, position, n, md);
+ window.write(out, position, n);
position += n;
remaining -= n;
}
-
- if (md != null) {
- byte[] buf = new byte[20];
- byte[] actHash = md.digest();
-
- pin(pack, position);
- if (window.copy(position, buf, 0, 20) != 20) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileIsTruncated, pack.getPackFile()
- .getPath()));
- }
- if (!Arrays.equals(actHash, buf)) {
- pack.setInvalid();
- throw new IOException(MessageFormat.format(
- JGitText.get().packfileCorruptionDetected, pack
- .getPackFile().getPath()));
- }
- }
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
index 00b6b65..2e5d599 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/ObjectReuseAsIs.java
@@ -209,16 +209,11 @@ public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
* stream to append the pack onto.
* @param pack
* the cached pack to send.
- * @param validate
- * if true the representation must be validated and not be
- * corrupt before being reused. If false, validation may be
- * skipped as it will be performed elsewhere in the processing
- * pipeline.
* @throws IOException
* the pack cannot be read, or stream did not accept a write.
*/
- public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack,
- boolean validate) throws IOException;
+ public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack)
+ throws IOException;
/**
* Obtain the available cached packs that match the bitmap and update
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 510538d..6d0c8e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -1048,7 +1048,7 @@ public void writePack(ProgressMonitor compressMonitor,
stats.reusedObjects += pack.getObjectCount();
stats.reusedDeltas += deltaCnt;
stats.totalDeltas += deltaCnt;
- reuseSupport.copyPackAsIs(out, pack, reuseValidate);
+ reuseSupport.copyPackAsIs(out, pack);
}
writeChecksum(out);
out.flush();
@@ -1866,7 +1866,7 @@ private void findObjectsToPackUsingBitmaps(
false);
BitmapBuilder needBitmap = wantBitmap.andNot(haveBitmap);
- if (useCachedPacks && reuseSupport != null
+ if (useCachedPacks && reuseSupport != null && !reuseValidate
&& (excludeInPacks == null || excludeInPacks.length == 0))
cachedPacks.addAll(
reuseSupport.getCachedPacksAndUpdate(needBitmap));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
index a0197d0..cbb2f5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
@@ -104,11 +104,8 @@ public BlobBasedConfig(Config base, Repository db, AnyObjectId objectId)
private static byte[] read(Repository db, AnyObjectId blobId)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
- ObjectReader or = db.newObjectReader();
- try {
+ try (ObjectReader or = db.newObjectReader()) {
return read(or, blobId);
- } finally {
- or.release();
}
}
@@ -146,15 +143,12 @@ public BlobBasedConfig(Config base, Repository db, AnyObjectId treeish,
private static byte[] read(Repository db, AnyObjectId treeish, String path)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
- ObjectReader or = db.newObjectReader();
- try {
+ try (ObjectReader or = db.newObjectReader()) {
TreeWalk tree = TreeWalk.forPath(or, path, asTree(or, treeish));
if (tree == null)
throw new FileNotFoundException(MessageFormat.format(JGitText
.get().entryNotFoundByPath, path));
return read(or, tree.getObjectId(0));
- } finally {
- or.release();
}
}
@@ -168,6 +162,8 @@ private static AnyObjectId asTree(ObjectReader or, AnyObjectId treeish)
&& ((RevCommit) treeish).getTree() != null)
return ((RevCommit) treeish).getTree();
- return new RevWalk(or).parseTree(treeish).getId();
+ try (RevWalk rw = new RevWalk(or)) {
+ return rw.parseTree(treeish).getId();
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 8a2080b..a89bcee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -299,4 +299,16 @@ public class ConfigConstants {
* @since 3.3
*/
public static final String CONFIG_KEY_PRUNE = "prune";
+
+ /**
+ * The "streamBuffer" key
+ * @since 4.0
+ */
+ public static final String CONFIG_KEY_STREAM_BUFFER = "streamBuffer";
+
+ /**
+ * The "streamRatio" key
+ * @since 4.0
+ */
+ public static final String CONFIG_KEY_STREAM_RATIO = "streamRatio";
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 8435c9a..359b592 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -104,6 +104,8 @@ public class ObjectChecker {
private final MutableInteger ptrout = new MutableInteger();
private boolean allowZeroMode;
+
+ private boolean allowInvalidPersonIdent;
private boolean windows;
private boolean macosx;
@@ -125,6 +127,22 @@ public ObjectChecker setAllowLeadingZeroFileMode(boolean allow) {
}
/**
+ * Enable accepting invalid author, committer and tagger identities.
+ * <p>
+ * Some broken Git versions/libraries allowed users to create commits and
+ * tags with invalid formatting between the name, email and timestamp.
+ *
+ * @param allow
+ * if true accept invalid person identity strings.
+ * @return {@code this}.
+ * @since 4.0
+ */
+ public ObjectChecker setAllowInvalidPersonIdent(boolean allow) {
+ allowInvalidPersonIdent = allow;
+ return this;
+ }
+
+ /**
* Restrict trees to only names legal on Windows platforms.
* <p>
* Also rejects any mixed case forms of reserved names ({@code .git}).
@@ -198,6 +216,9 @@ private int id(final byte[] raw, final int ptr) {
}
private int personIdent(final byte[] raw, int ptr) {
+ if (allowInvalidPersonIdent)
+ return nextLF(raw, ptr) - 1;
+
final int emailB = nextLF(raw, ptr, '<');
if (emailB == ptr || raw[emailB - 1] != '<')
return -1;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
index 0cc51d1..2abd6da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
@@ -120,11 +120,8 @@ public void create() throws IOException {
* the object store cannot be accessed.
*/
public boolean has(final AnyObjectId objectId) throws IOException {
- final ObjectReader or = newReader();
- try {
+ try (final ObjectReader or = newReader()) {
return or.has(objectId);
- } finally {
- or.release();
}
}
@@ -172,11 +169,8 @@ public ObjectLoader open(final AnyObjectId objectId)
public ObjectLoader open(AnyObjectId objectId, int typeHint)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
- final ObjectReader or = newReader();
- try {
+ try (final ObjectReader or = newReader()) {
return or.open(objectId, typeHint);
- } finally {
- or.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java
new file mode 100644
index 0000000..1ddac18
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/EolAwareOutputStream.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014, André de Oliveira <andre.oliveira@liferay.com>
+ *
+ * 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.merge;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An output stream which is aware of newlines and can be asked to begin a new
+ * line if not already in one.
+ */
+class EolAwareOutputStream extends OutputStream {
+ private final OutputStream out;
+
+ private boolean bol = true;
+
+ /**
+ * Initialize a new EOL aware stream.
+ *
+ * @param out
+ * stream to output all writes to.
+ */
+ EolAwareOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Begin a new line if not already in one.
+ *
+ * @exception IOException
+ * if an I/O error occurs.
+ */
+ void beginln() throws IOException {
+ if (!bol)
+ write('\n');
+ }
+
+ /** @return true if a new line has just begun. */
+ boolean isBeginln() {
+ return bol;
+ }
+
+ @Override
+ public void write(int val) throws IOException {
+ out.write(val);
+ bol = (val == '\n');
+ }
+
+ @Override
+ public void write(byte[] buf, int pos, int cnt) throws IOException {
+ if (cnt > 0) {
+ out.write(buf, pos, cnt);
+ bol = (buf[pos + (cnt - 1)] == '\n');
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
index eed1dcf..977f953 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
@@ -49,7 +49,6 @@
import java.util.List;
import org.eclipse.jgit.diff.RawText;
-import org.eclipse.jgit.merge.MergeChunk.ConflictState;
/**
* A class to convert merge results into a Git conformant textual presentation
@@ -78,47 +77,7 @@ public class MergeFormatter {
*/
public void formatMerge(OutputStream out, MergeResult<RawText> res,
List<String> seqName, String charsetName) throws IOException {
- String lastConflictingName = null; // is set to non-null whenever we are
- // in a conflict
- boolean threeWayMerge = (res.getSequences().size() == 3);
- for (MergeChunk chunk : res) {
- RawText seq = res.getSequences().get(chunk.getSequenceIndex());
- if (lastConflictingName != null
- && chunk.getConflictState() != ConflictState.NEXT_CONFLICTING_RANGE) {
- // found the end of an conflict
- out.write((">>>>>>> " + lastConflictingName + "\n").getBytes(charsetName)); //$NON-NLS-1$ //$NON-NLS-2$
- lastConflictingName = null;
- }
- if (chunk.getConflictState() == ConflictState.FIRST_CONFLICTING_RANGE) {
- // found the start of an conflict
- out.write(("<<<<<<< " + seqName.get(chunk.getSequenceIndex()) + //$NON-NLS-1$
- "\n").getBytes(charsetName)); //$NON-NLS-1$
- lastConflictingName = seqName.get(chunk.getSequenceIndex());
- } else if (chunk.getConflictState() == ConflictState.NEXT_CONFLICTING_RANGE) {
- // found another conflicting chunk
-
- /*
- * In case of a non-three-way merge I'll add the name of the
- * conflicting chunk behind the equal signs. I also append the
- * name of the last conflicting chunk after the ending
- * greater-than signs. If somebody knows a better notation to
- * present non-three-way merges - feel free to correct here.
- */
- lastConflictingName = seqName.get(chunk.getSequenceIndex());
- out.write((threeWayMerge ? "=======\n" : "======= " //$NON-NLS-1$ //$NON-NLS-2$
- + lastConflictingName + "\n").getBytes(charsetName)); //$NON-NLS-1$
- }
- // the lines with conflict-metadata are written. Now write the chunk
- for (int i = chunk.getBegin(); i < chunk.getEnd(); i++) {
- seq.writeLine(out, i);
- out.write('\n');
- }
- }
- // one possible leftover: if the merge result ended with a conflict we
- // have to close the last conflict here
- if (lastConflictingName != null) {
- out.write((">>>>>>> " + lastConflictingName + "\n").getBytes(charsetName)); //$NON-NLS-1$ //$NON-NLS-2$
- }
+ new MergeFormatterPass(out, res, seqName, charsetName).formatMerge();
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java
new file mode 100644
index 0000000..0345921
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com>
+ * Copyright (C) 2014, André de Oliveira <andre.oliveira@liferay.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.merge;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.eclipse.jgit.diff.RawText;
+import org.eclipse.jgit.merge.MergeChunk.ConflictState;
+
+class MergeFormatterPass {
+
+ private final EolAwareOutputStream out;
+
+ private final MergeResult<RawText> res;
+
+ private final List<String> seqName;
+
+ private final String charsetName;
+
+ private final boolean threeWayMerge;
+
+ private String lastConflictingName; // is set to non-null whenever we are in
+ // a conflict
+
+ MergeFormatterPass(OutputStream out, MergeResult<RawText> res, List<String> seqName,
+ String charsetName) {
+ this.out = new EolAwareOutputStream(out);
+ this.res = res;
+ this.seqName = seqName;
+ this.charsetName = charsetName;
+ this.threeWayMerge = (res.getSequences().size() == 3);
+ }
+
+ void formatMerge() throws IOException {
+ boolean missingNewlineAtEnd = false;
+ for (MergeChunk chunk : res) {
+ RawText seq = res.getSequences().get(chunk.getSequenceIndex());
+ writeConflictMetadata(chunk);
+ // the lines with conflict-metadata are written. Now write the chunk
+ for (int i = chunk.getBegin(); i < chunk.getEnd(); i++)
+ writeLine(seq, i);
+ missingNewlineAtEnd = seq.isMissingNewlineAtEnd();
+ }
+ // one possible leftover: if the merge result ended with a conflict we
+ // have to close the last conflict here
+ if (lastConflictingName != null)
+ writeConflictEnd();
+ if (!missingNewlineAtEnd)
+ out.beginln();
+ }
+
+ private void writeConflictMetadata(MergeChunk chunk) throws IOException {
+ if (lastConflictingName != null
+ && chunk.getConflictState() != ConflictState.NEXT_CONFLICTING_RANGE) {
+ // found the end of an conflict
+ writeConflictEnd();
+ }
+ if (chunk.getConflictState() == ConflictState.FIRST_CONFLICTING_RANGE) {
+ // found the start of an conflict
+ writeConflictStart(chunk);
+ } else if (chunk.getConflictState() == ConflictState.NEXT_CONFLICTING_RANGE) {
+ // found another conflicting chunk
+ writeConflictChange(chunk);
+ }
+ }
+
+ private void writeConflictEnd() throws IOException {
+ writeln(">>>>>>> " + lastConflictingName); //$NON-NLS-1$
+ lastConflictingName = null;
+ }
+
+ private void writeConflictStart(MergeChunk chunk) throws IOException {
+ lastConflictingName = seqName.get(chunk.getSequenceIndex());
+ writeln("<<<<<<< " + lastConflictingName); //$NON-NLS-1$
+ }
+
+ private void writeConflictChange(MergeChunk chunk) throws IOException {
+ /*
+ * In case of a non-three-way merge I'll add the name of the conflicting
+ * chunk behind the equal signs. I also append the name of the last
+ * conflicting chunk after the ending greater-than signs. If somebody
+ * knows a better notation to present non-three-way merges - feel free
+ * to correct here.
+ */
+ lastConflictingName = seqName.get(chunk.getSequenceIndex());
+ writeln(threeWayMerge ? "=======" : "======= " //$NON-NLS-1$ //$NON-NLS-2$
+ + lastConflictingName);
+ }
+
+ private void writeln(String s) throws IOException {
+ out.beginln();
+ out.write((s + "\n").getBytes(charsetName)); //$NON-NLS-1$
+ }
+
+ private void writeLine(RawText seq, int i) throws IOException {
+ out.beginln();
+ seq.writeLine(out, i);
+ // still BOL? It was a blank line. But writeLine won't lf, so we do.
+ if (out.isBeginln())
+ out.write('\n');
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
index d786a18..a76dd35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
@@ -125,9 +125,9 @@ public ObjectInserter getObjectInserter() {
* repository instance returned by {@link #getRepository()}.
*/
public void setObjectInserter(ObjectInserter oi) {
- walk.release();
- reader.release();
- inserter.release();
+ walk.close();
+ reader.close();
+ inserter.close();
inserter = oi;
reader = oi.newReader();
walk = new RevWalk(reader);
@@ -206,8 +206,8 @@ public boolean merge(final boolean flush, final AnyObjectId... tips)
return ok;
} finally {
if (flush)
- inserter.release();
- reader.release();
+ inserter.close();
+ reader.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
index 85cdb76..36ffe7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -68,6 +68,8 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
@@ -194,10 +196,12 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b, int callDepth)
Integer.valueOf(MAX_BASES), a.name(), b.name(),
Integer.valueOf(baseCommits.size())));
parents.add(nextBase);
- if (mergeTrees(
- openTree(getBaseCommit(currentBase, nextBase,
- callDepth + 1).getTree()),
- currentBase.getTree(), nextBase.getTree(), true))
+ RevCommit bc = getBaseCommit(currentBase, nextBase,
+ callDepth + 1);
+ AbstractTreeIterator bcTree = (bc == null) ? new EmptyTreeIterator()
+ : openTree(bc.getTree());
+ if (mergeTrees(bcTree, currentBase.getTree(),
+ nextBase.getTree(), true))
currentBase = createCommitForTree(resultTree, parents);
else
throw new NoMergeBaseException(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 8e70f57..953d3a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -47,12 +47,14 @@
import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -791,25 +793,25 @@ private File writeMergedFile(MergeResult<RawText> result)
File parentFolder = of.getParentFile();
if (!fs.exists(parentFolder))
parentFolder.mkdirs();
- FileOutputStream fos = new FileOutputStream(of);
- try {
- new MergeFormatter().formatMerge(fos, result,
+ try (OutputStream os = new BufferedOutputStream(
+ new FileOutputStream(of))) {
+ new MergeFormatter().formatMerge(os, result,
Arrays.asList(commitNames), CHARACTER_ENCODING);
- } finally {
- fos.close();
}
return of;
}
private ObjectId insertMergeResult(MergeResult<RawText> result)
throws IOException {
- TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(10 << 20);
+ TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
+ db.getDirectory(), 10 << 20);
try {
new MergeFormatter().formatMerge(buf, result,
Arrays.asList(commitNames), CHARACTER_ENCODING);
buf.close();
- return getObjectInserter().insert(OBJ_BLOB, buf.length(),
- buf.openInputStream());
+ try (InputStream in = buf.openInputStream()) {
+ return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
+ }
} finally {
buf.destroy();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
index 0614476..19ec1a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
@@ -135,8 +135,8 @@ public NoteMap merge(NoteMap base, NoteMap ours, NoteMap theirs)
inserter.flush();
return NoteMap.newMap(mergedBucket, reader);
} finally {
- reader.release();
- inserter.release();
+ reader.close();
+ inserter.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
index b73ccb1..a0af067 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -232,7 +232,7 @@ public void markUninteresting(RevObject o) throws MissingObjectException,
}
if (o instanceof RevCommit)
- markUninteresting((RevCommit) o);
+ super.markUninteresting((RevCommit) o);
else if (o instanceof RevTree)
markTreeUninteresting((RevTree) o);
else
@@ -242,18 +242,6 @@ else if (o instanceof RevTree)
addObject(o);
}
- @Override
- public void markUninteresting(RevCommit c) throws MissingObjectException,
- IncorrectObjectTypeException, IOException {
- super.markUninteresting(c);
- try {
- markTreeUninteresting(c.getTree());
- } catch (MissingObjectException e) {
- // we don't care if the tree of the commit does not exist locally
- }
- }
-
- @Override
public void sort(RevSort s) {
super.sort(s);
boundary = hasRevSort(RevSort.BOUNDARY);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
index 1072d58..59ff1bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseConnection.java
@@ -65,6 +65,8 @@
public abstract class BaseConnection implements Connection {
private Map<String, Ref> advertisedRefs = Collections.emptyMap();
+ private String peerUserAgent;
+
private boolean startedOperation;
private Writer messageWriter;
@@ -85,6 +87,28 @@ public String getMessages() {
return messageWriter != null ? messageWriter.toString() : ""; //$NON-NLS-1$
}
+ /**
+ * User agent advertised by the remote server.
+ *
+ * @return agent (version of Git) running on the remote server. Null if the
+ * server does not advertise this version.
+ * @since 4.0
+ */
+ public String getPeerUserAgent() {
+ return peerUserAgent;
+ }
+
+ /**
+ * Remember the remote peer's agent.
+ *
+ * @param agent
+ * remote peer agent string.
+ * @since 4.0
+ */
+ protected void setPeerUserAgent(String agent) {
+ peerUserAgent = agent;
+ }
+
public abstract void close();
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
index 8f825ea..7f9cec7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
@@ -46,6 +46,8 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
+
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -275,6 +277,18 @@ protected boolean wantCapability(final StringBuilder b, final String option) {
return true;
}
+ protected void addUserAgentCapability(StringBuilder b) {
+ String a = UserAgent.get();
+ if (a != null && UserAgent.hasAgent(remoteCapablities)) {
+ b.append(' ').append(OPTION_AGENT).append('=').append(a);
+ }
+ }
+
+ @Override
+ public String getPeerUserAgent() {
+ return UserAgent.getAgent(remoteCapablities, super.getPeerUserAgent());
+ }
+
private PackProtocolException duplicateAdvertisement(final String name) {
return new PackProtocolException(uri, MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, name));
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index f907891..a6fc633 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -377,7 +377,7 @@ protected void doFetch(final ProgressMonitor monitor,
@Override
public void close() {
if (walk != null)
- walk.release();
+ walk.close();
super.close();
}
@@ -521,6 +521,7 @@ else if (wantCapability(line, OPTION_SIDE_BAND))
OPTION_MULTI_ACK_DETAILED));
}
+ addUserAgentCapability(line);
return line.toString();
}
@@ -753,16 +754,13 @@ private void receivePack(final ProgressMonitor monitor,
input = new SideBandInputStream(input, monitor, getMessageWriter(),
outputStream);
- ObjectInserter ins = local.newObjectInserter();
- try {
+ try (ObjectInserter ins = local.newObjectInserter()) {
PackParser parser = ins.newPackParser(input);
parser.setAllowThin(thinPack);
parser.setObjectChecker(transport.getObjectChecker());
parser.setLockMessage(lockMessage);
packLock = parser.parse(monitor);
ins.flush();
- } finally {
- ins.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index e367ab4..1e5b8e8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -268,6 +268,7 @@ private String enableCapabilities(final ProgressMonitor monitor,
outputStream);
pckIn = new PacketLineIn(in);
}
+ addUserAgentCapability(line);
if (line.length() > 0)
line.setCharAt(0, '\0');
@@ -279,9 +280,8 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
Set<ObjectId> remoteObjects = new HashSet<ObjectId>();
Set<ObjectId> newObjects = new HashSet<ObjectId>();
- final PackWriter writer = new PackWriter(transport.getPackConfig(),
- local.newObjectReader());
- try {
+ try (final PackWriter writer = new PackWriter(transport.getPackConfig(),
+ local.newObjectReader())) {
for (final Ref r : getRefs()) {
// only add objects that we actually have
@@ -303,10 +303,9 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
writer.setDeltaBaseAsOffset(capableOfsDelta);
writer.preparePack(monitor, newObjects, remoteObjects);
writer.writePack(monitor, monitor, out);
- } finally {
- writer.release();
+
+ packTransferTime = writer.getStatistics().getTimeWriting();
}
- packTransferTime = writer.getStatistics().getTimeWriting();
}
private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index dfb8ca9..cf6b2fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -48,6 +48,7 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
@@ -224,6 +225,7 @@ public Set<String> getCapabilities() {
/** Capabilities requested by the client. */
private Set<String> enabledCapabilities;
+ String userAgent;
private Set<ObjectId> clientShallowCommits;
private List<ReceiveCommand> commands;
@@ -289,6 +291,7 @@ public ReceiveConfig parse(final Config cfg) {
final boolean checkReceivedObjects;
final boolean allowLeadingZeroFileMode;
+ final boolean allowInvalidPersonIdent;
final boolean safeForWindows;
final boolean safeForMacOS;
@@ -306,6 +309,8 @@ public ReceiveConfig parse(final Config cfg) {
config.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
allowLeadingZeroFileMode = checkReceivedObjects
&& config.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
+ allowInvalidPersonIdent = checkReceivedObjects
+ && config.getBoolean("fsck", "allowInvalidPersonIdent", false); //$NON-NLS-1$ //$NON-NLS-2$
safeForWindows = checkReceivedObjects
&& config.getBoolean("fsck", "safeForWindows", false); //$NON-NLS-1$ //$NON-NLS-2$
safeForMacOS = checkReceivedObjects
@@ -317,7 +322,7 @@ public ReceiveConfig parse(final Config cfg) {
"denynonfastforwards", false); //$NON-NLS-1$
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
true);
- certNonceSeed = config.getString("receive", null, "certnonceseed"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ certNonceSeed = config.getString("receive", null, "certnonceseed"); //$NON-NLS-1$ //$NON-NLS-2$
certNonceSlopLimit = config.getInt("receive", "certnonceslop", 0); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -326,6 +331,7 @@ ObjectChecker newObjectChecker() {
return null;
return new ObjectChecker()
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
+ .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
.setSafeForWindows(safeForWindows)
.setSafeForMacOS(safeForMacOS);
}
@@ -734,6 +740,25 @@ public boolean isSideBand() throws RequestNotYetReadException {
return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K);
}
+ /**
+ * Get the user agent of the client.
+ * <p>
+ * If the client is new enough to use {@code agent=} capability that value
+ * will be returned. Older HTTP clients may also supply their version using
+ * the HTTP {@code User-Agent} header. The capability overrides the HTTP
+ * header if both are available.
+ * <p>
+ * When an HTTP request has been received this method returns the HTTP
+ * {@code User-Agent} header value until capabilities have been parsed.
+ *
+ * @return user agent supplied by the client. Available only if the client
+ * is new enough to advertise its user agent.
+ * @since 4.0
+ */
+ public String getPeerUserAgent() {
+ return UserAgent.getAgent(enabledCapabilities, userAgent);
+ }
+
/** @return all of the command received by the current request. */
public List<ReceiveCommand> getAllCommands() {
return Collections.unmodifiableList(commands);
@@ -951,6 +976,7 @@ public void sendAdvertisedRefs(final RefAdvertiser adv)
adv.advertiseCapability(CAPABILITY_ATOMIC);
if (allowOfsDelta)
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
+ adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
adv.send(getAdvertisedOrDefaultRefs());
for (ObjectId obj : advertisedHaves)
adv.advertiseHave(obj);
@@ -1070,8 +1096,7 @@ private void receivePack() throws IOException {
if (sideBand)
resolving = new SideBandProgressMonitor(msgOut);
- ObjectInserter ins = db.newObjectInserter();
- try {
+ try (ObjectInserter ins = db.newObjectInserter()) {
String lockMsg = "jgit receive-pack"; //$NON-NLS-1$
if (getRefLogIdent() != null)
lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$
@@ -1089,8 +1114,6 @@ private void receivePack() throws IOException {
packLock = parser.parse(receiving, resolving);
packSize = Long.valueOf(parser.getPackSize());
ins.flush();
- } finally {
- ins.release();
}
if (timeoutIn != null)
@@ -1119,67 +1142,69 @@ private void checkConnectivity() throws IOException {
}
parser = null;
- final ObjectWalk ow = new ObjectWalk(db);
- ow.setRetainBody(false);
- if (baseObjects != null) {
- ow.sort(RevSort.TOPO);
- if (!baseObjects.isEmpty())
- ow.sort(RevSort.BOUNDARY, true);
- }
-
- for (final ReceiveCommand cmd : commands) {
- if (cmd.getResult() != Result.NOT_ATTEMPTED)
- continue;
- if (cmd.getType() == ReceiveCommand.Type.DELETE)
- continue;
- ow.markStart(ow.parseAny(cmd.getNewId()));
- }
- for (final ObjectId have : advertisedHaves) {
- RevObject o = ow.parseAny(have);
- ow.markUninteresting(o);
-
- if (baseObjects != null && !baseObjects.isEmpty()) {
- o = ow.peel(o);
- if (o instanceof RevCommit)
- o = ((RevCommit) o).getTree();
- if (o instanceof RevTree)
- ow.markUninteresting(o);
+ try (final ObjectWalk ow = new ObjectWalk(db)) {
+ ow.setRetainBody(false);
+ if (baseObjects != null) {
+ ow.sort(RevSort.TOPO);
+ if (!baseObjects.isEmpty())
+ ow.sort(RevSort.BOUNDARY, true);
}
- }
- checking.beginTask(JGitText.get().countingObjects, ProgressMonitor.UNKNOWN);
- RevCommit c;
- while ((c = ow.next()) != null) {
- checking.update(1);
- if (providedObjects != null //
- && !c.has(RevFlag.UNINTERESTING) //
- && !providedObjects.contains(c))
- throw new MissingObjectException(c, Constants.TYPE_COMMIT);
- }
-
- RevObject o;
- while ((o = ow.nextObject()) != null) {
- checking.update(1);
- if (o.has(RevFlag.UNINTERESTING))
- continue;
-
- if (providedObjects != null) {
- if (providedObjects.contains(o))
+ for (final ReceiveCommand cmd : commands) {
+ if (cmd.getResult() != Result.NOT_ATTEMPTED)
continue;
- else
- throw new MissingObjectException(o, o.getType());
+ if (cmd.getType() == ReceiveCommand.Type.DELETE)
+ continue;
+ ow.markStart(ow.parseAny(cmd.getNewId()));
+ }
+ for (final ObjectId have : advertisedHaves) {
+ RevObject o = ow.parseAny(have);
+ ow.markUninteresting(o);
+
+ if (baseObjects != null && !baseObjects.isEmpty()) {
+ o = ow.peel(o);
+ if (o instanceof RevCommit)
+ o = ((RevCommit) o).getTree();
+ if (o instanceof RevTree)
+ ow.markUninteresting(o);
+ }
}
- if (o instanceof RevBlob && !db.hasObject(o))
- throw new MissingObjectException(o, Constants.TYPE_BLOB);
- }
- checking.endTask();
+ checking.beginTask(JGitText.get().countingObjects,
+ ProgressMonitor.UNKNOWN);
+ RevCommit c;
+ while ((c = ow.next()) != null) {
+ checking.update(1);
+ if (providedObjects != null //
+ && !c.has(RevFlag.UNINTERESTING) //
+ && !providedObjects.contains(c))
+ throw new MissingObjectException(c, Constants.TYPE_COMMIT);
+ }
- if (baseObjects != null) {
- for (ObjectId id : baseObjects) {
- o = ow.parseAny(id);
- if (!o.has(RevFlag.UNINTERESTING))
- throw new MissingObjectException(o, o.getType());
+ RevObject o;
+ while ((o = ow.nextObject()) != null) {
+ checking.update(1);
+ if (o.has(RevFlag.UNINTERESTING))
+ continue;
+
+ if (providedObjects != null) {
+ if (providedObjects.contains(o))
+ continue;
+ else
+ throw new MissingObjectException(o, o.getType());
+ }
+
+ if (o instanceof RevBlob && !db.hasObject(o))
+ throw new MissingObjectException(o, Constants.TYPE_BLOB);
+ }
+ checking.endTask();
+
+ if (baseObjects != null) {
+ for (ObjectId id : baseObjects) {
+ o = ow.parseAny(id);
+ if (!o.has(RevFlag.UNINTERESTING))
+ throw new MissingObjectException(o, o.getType());
+ }
}
}
}
@@ -1502,7 +1527,7 @@ protected void close() throws IOException {
* the pack could not be unlocked.
*/
protected void release() throws IOException {
- walk.release();
+ walk.close();
unlockPack();
timeoutIn = null;
rawIn = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
index e3cfd22..e53c04b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
@@ -183,16 +183,13 @@ protected void doFetch(final ProgressMonitor monitor,
throws TransportException {
verifyPrerequisites();
try {
- ObjectInserter ins = transport.local.newObjectInserter();
- try {
+ try (ObjectInserter ins = transport.local.newObjectInserter()) {
PackParser parser = ins.newPackParser(bin);
parser.setAllowThin(true);
parser.setObjectChecker(transport.getObjectChecker());
parser.setLockMessage(lockMessage);
packLock = parser.parse(NullProgressMonitor.INSTANCE);
ins.flush();
- } finally {
- ins.release();
}
} catch (IOException err) {
close();
@@ -217,8 +214,7 @@ private void verifyPrerequisites() throws TransportException {
if (prereqs.isEmpty())
return;
- final RevWalk rw = new RevWalk(transport.local);
- try {
+ try (final RevWalk rw = new RevWalk(transport.local)) {
final RevFlag PREREQ = rw.newFlag("PREREQ"); //$NON-NLS-1$
final RevFlag SEEN = rw.newFlag("SEEN"); //$NON-NLS-1$
@@ -281,8 +277,6 @@ private void verifyPrerequisites() throws TransportException {
throw new MissingBundlePrerequisiteException(transport.uri,
missing);
}
- } finally {
- rw.release();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index d0f005c..81ad981 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -194,8 +194,7 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
PackConfig pc = packConfig;
if (pc == null)
pc = new PackConfig(db);
- PackWriter packWriter = new PackWriter(pc, db.newObjectReader());
- try {
+ try (PackWriter packWriter = new PackWriter(pc, db.newObjectReader())) {
final HashSet<ObjectId> inc = new HashSet<ObjectId>();
final HashSet<ObjectId> exc = new HashSet<ObjectId>();
inc.addAll(include.values());
@@ -233,8 +232,6 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
w.write('\n');
w.flush();
packWriter.writePack(monitor, monitor, os);
- } finally {
- packWriter.release();
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
index e386c26..0ff9fce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
@@ -127,4 +127,13 @@ public interface Connection {
* remote produced no additional messages.
*/
public String getMessages();
+
+ /**
+ * User agent advertised by the remote server.
+ *
+ * @return agent (version of Git) running on the remote server. Null if the
+ * server does not advertise this version.
+ * @since 4.0
+ */
+ public String getPeerUserAgent();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 52a9bab..9aae1c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -136,6 +136,7 @@ private void executeImp(final ProgressMonitor monitor,
conn = transport.openFetch();
try {
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
+ result.peerUserAgent = conn.getPeerUserAgent();
final Set<Ref> matched = new HashSet<Ref>();
for (final RefSpec spec : toFetch) {
if (spec.getSource() == null)
@@ -196,8 +197,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
.newBatchUpdate()
.setAllowNonFastForwards(true)
.setRefLogMessage("fetch", true); //$NON-NLS-1$
- final RevWalk walk = new RevWalk(transport.local);
- try {
+ try (final RevWalk walk = new RevWalk(transport.local)) {
if (monitor instanceof BatchingProgressMonitor) {
((BatchingProgressMonitor) monitor).setDelayStart(
250, TimeUnit.MILLISECONDS);
@@ -226,8 +226,6 @@ else if (tagopt == TagOpt.FETCH_TAGS)
throw new TransportException(MessageFormat.format(
JGitText.get().failureUpdatingTrackingRef,
getFirstFailedRefName(batch), err.getMessage()), err);
- } finally {
- walk.release();
}
if (!fetchHeadUpdates.isEmpty()) {
@@ -338,15 +336,12 @@ private void updateFETCH_HEAD(final FetchResult result) throws IOException {
private boolean askForIsComplete() throws TransportException {
try {
- final ObjectWalk ow = new ObjectWalk(transport.local);
- try {
+ try (final ObjectWalk ow = new ObjectWalk(transport.local)) {
for (final ObjectId want : askFor.keySet())
ow.markStart(ow.parseAny(want));
for (final Ref ref : localRefs().values())
ow.markUninteresting(ow.parseAny(ref.getObjectId()));
ow.checkConnectivity();
- } finally {
- ow.release();
}
return true;
} catch (MissingObjectException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index 27052db..8d9d2b7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -186,6 +186,13 @@ public class GitProtocolConstants {
*/
public static final String CAPABILITY_PUSH_CERT = "push-cert"; //$NON-NLS-1$
+ /**
+ * Implementation name and version of the client or server.
+ *
+ * @since 4.0
+ */
+ public static final String OPTION_AGENT = "agent"; //$NON-NLS-1$
+
static enum MultiAck {
OFF, CONTINUE, DETAILED;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
new file mode 100644
index 0000000..fe7aaf7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalHttpServerGlue.java
@@ -0,0 +1,80 @@
+/*
+ * 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.transport;
+
+/**
+ * Internal API to to assist {@code org.eclipse.jgit.http.server}.
+ * <p>
+ * <b>Do not call.</b>
+ *
+ * @since 4.0
+ */
+public class InternalHttpServerGlue {
+ /**
+ * Apply a default user agent for a request.
+ *
+ * @param up
+ * current UploadPack instance.
+ * @param agent
+ * user agent string from the HTTP headers.
+ */
+ public static void setPeerUserAgent(UploadPack up, String agent) {
+ up.userAgent = agent;
+ }
+
+ /**
+ * Apply a default user agent for a request.
+ *
+ * @param rp
+ * current ReceivePack instance.
+ * @param agent
+ * user agent string from the HTTP headers.
+ */
+ public static void setPeerUserAgent(ReceivePack rp, String agent) {
+ rp.userAgent = agent;
+ }
+
+ private InternalHttpServerGlue() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
index b4a48b0..ad51f3e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OperationResult.java
@@ -68,6 +68,8 @@ public abstract class OperationResult {
StringBuilder messageBuffer;
+ String peerUserAgent;
+
/**
* Get the URI this result came from.
* <p>
@@ -165,4 +167,15 @@ void addMessages(final String msg) {
messageBuffer.append('\n');
}
}
+
+ /**
+ * Get the user agent advertised by the peer server, if available.
+ *
+ * @return advertised user agent, e.g. {@code "JGit/4.0"}. Null if the peer
+ * did not advertise version information.
+ * @since 4.0
+ */
+ public String getPeerUserAgent() {
+ return peerUserAgent;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 5b54891..04abe22 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -529,7 +529,7 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
} finally {
try {
if (readCurs != null)
- readCurs.release();
+ readCurs.close();
} finally {
readCurs = null;
}
@@ -812,7 +812,7 @@ private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
for (final DeltaChain base : missing) {
if (base.head != null)
- throw new MissingObjectException(base, "delta base");
+ throw new MissingObjectException(base, "delta base"); //$NON-NLS-1$
}
onEndThinPack();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index 53fba55..00f84f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -155,6 +155,7 @@ PushResult execute(final ProgressMonitor monitor)
try {
res.setAdvertisedRefs(transport.getURI(), connection
.getRefsMap());
+ res.peerUserAgent = connection.getPeerUserAgent();
res.setRemoteUpdates(toPush);
monitor.endTask();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
index 76547a6..f72a4b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
@@ -148,6 +148,21 @@ public void advertiseCapability(String name) {
}
/**
+ * Add one protocol capability with a value ({@code "name=value"}).
+ *
+ * @param name
+ * name of the capability.
+ * @param value
+ * value. If null the capability will not be added.
+ * @since 4.0
+ */
+ public void advertiseCapability(String name, String value) {
+ if (value != null) {
+ capablities.add(name + '=' + value);
+ }
+ }
+
+ /**
* Add a symbolic ref to capabilities.
* <p>
* This method must be invoked prior to any of the following:
@@ -164,8 +179,7 @@ public void advertiseCapability(String name) {
* @since 3.6
*/
public void addSymref(String from, String to) {
- String symref = String.format("%s=%s:%s", OPTION_SYMREF, from, to); //$NON-NLS-1$
- advertiseCapability(symref);
+ advertiseCapability(OPTION_SYMREF, from + ':' + to);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 1de91a5..60043ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -67,6 +67,7 @@ public TransferConfig parse(final Config cfg) {
private final boolean checkReceivedObjects;
private final boolean allowLeadingZeroFileMode;
+ private final boolean allowInvalidPersonIdent;
private final boolean safeForWindows;
private final boolean safeForMacOS;
private final boolean allowTipSha1InWant;
@@ -82,6 +83,8 @@ private TransferConfig(final Config rc) {
rc.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
allowLeadingZeroFileMode = checkReceivedObjects
&& rc.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
+ allowInvalidPersonIdent = checkReceivedObjects
+ && rc.getBoolean("fsck", "allowInvalidPersonIdent", false); //$NON-NLS-1$ //$NON-NLS-2$
safeForWindows = checkReceivedObjects
&& rc.getBoolean("fsck", "safeForWindows", //$NON-NLS-1$ //$NON-NLS-2$
SystemReader.getInstance().isWindows());
@@ -113,6 +116,7 @@ public ObjectChecker newObjectChecker() {
return null;
return new ObjectChecker()
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
+ .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
.setSafeForWindows(safeForWindows)
.setSafeForMacOS(safeForMacOS);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 82d1737..b23771e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -134,8 +134,6 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
private static final String SVC_RECEIVE_PACK = "git-receive-pack"; //$NON-NLS-1$
- private static final String userAgent = computeUserAgent();
-
static final TransportProtocol PROTO_HTTP = new TransportProtocol() {
private final String[] schemeNames = { "http", "https" }; //$NON-NLS-1$ //$NON-NLS-2$
@@ -204,17 +202,6 @@ public Transport open(URIish uri, Repository local, String remoteName)
}
};
- private static String computeUserAgent() {
- String version;
- final Package pkg = TransportHttp.class.getPackage();
- if (pkg != null && pkg.getImplementationVersion() != null) {
- version = pkg.getImplementationVersion();
- } else {
- version = "unknown"; //$NON-NLS-1$
- }
- return "JGit/" + version; //$NON-NLS-1$
- }
-
private static final Config.SectionParser<HttpConfig> HTTP_KEY = new SectionParser<HttpConfig>() {
public HttpConfig parse(final Config cfg) {
return new HttpConfig(cfg);
@@ -309,16 +296,17 @@ public FetchConnection openFetch() throws TransportException,
final HttpConnection c = connect(service);
final InputStream in = openInputStream(c);
try {
+ BaseConnection f;
if (isSmartHttp(c, service)) {
readSmartHeaders(in, service);
- return new SmartHttpFetchConnection(in);
-
+ f = new SmartHttpFetchConnection(in);
} else {
// Assume this server doesn't support smart HTTP fetch
// and fall back on dumb object walking.
- //
- return newDumbConnection(in);
+ f = newDumbConnection(in);
}
+ f.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
+ return (FetchConnection) f;
} finally {
in.close();
}
@@ -331,7 +319,7 @@ public FetchConnection openFetch() throws TransportException,
}
}
- private FetchConnection newDumbConnection(InputStream in)
+ private WalkFetchConnection newDumbConnection(InputStream in)
throws IOException, PackProtocolException {
HttpObjectDB d = new HttpObjectDB(objectsUrl);
BufferedReader br = toBufferedReader(in);
@@ -400,9 +388,7 @@ public PushConnection openPush() throws NotSupportedException,
final InputStream in = openInputStream(c);
try {
if (isSmartHttp(c, service)) {
- readSmartHeaders(in, service);
- return new SmartHttpPushConnection(in);
-
+ return smartPush(service, c, in);
} else if (!useSmartHttp) {
final String msg = JGitText.get().smartHTTPPushDisabled;
throw new NotSupportedException(msg);
@@ -423,6 +409,14 @@ public PushConnection openPush() throws NotSupportedException,
}
}
+ private PushConnection smartPush(String service, HttpConnection c,
+ InputStream in) throws IOException, TransportException {
+ readSmartHeaders(in, service);
+ SmartHttpPushConnection p = new SmartHttpPushConnection(in);
+ p.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
+ return p;
+ }
+
@Override
public void close() {
// No explicit connections are maintained.
@@ -551,7 +545,9 @@ protected HttpConnection httpOpen(String method, URL u)
conn.setUseCaches(false);
conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
conn.setRequestProperty(HDR_PRAGMA, "no-cache"); //$NON-NLS-1$
- conn.setRequestProperty(HDR_USER_AGENT, userAgent);
+ if (UserAgent.get() != null) {
+ conn.setRequestProperty(HDR_USER_AGENT, UserAgent.get());
+ }
int timeOut = getTimeout();
if (timeOut != -1) {
int effTimeOut = timeOut * 1000;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 1a653bd..3afdb61 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.transport;
import static org.eclipse.jgit.lib.RefDatabase.ALL;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK;
@@ -253,6 +254,7 @@ public Set<String> getOptions() {
/** Capabilities requested by the client. */
private Set<String> options;
+ String userAgent;
/** Raw ObjectIds the client has asked for, before validating them. */
private final Set<ObjectId> wantIds = new HashSet<ObjectId>();
@@ -806,6 +808,7 @@ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
|| policy == RequestPolicy.REACHABLE_COMMIT_TIP
|| policy == null)
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
+ adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
adv.setDerefTags(true);
Map<String, Ref> refs = getAdvertisedOrDefaultRefs();
findSymrefs(adv, refs);
@@ -884,6 +887,37 @@ private void recvWants() throws IOException {
}
}
+ /**
+ * Returns the clone/fetch depth. Valid only after calling recvWants().
+ *
+ * @return the depth requested by the client, or 0 if unbounded.
+ * @since 4.0
+ */
+ public int getDepth() {
+ if (options == null)
+ throw new RequestNotYetReadException();
+ return depth;
+ }
+
+ /**
+ * Get the user agent of the client.
+ * <p>
+ * If the client is new enough to use {@code agent=} capability that value
+ * will be returned. Older HTTP clients may also supply their version using
+ * the HTTP {@code User-Agent} header. The capability overrides the HTTP
+ * header if both are available.
+ * <p>
+ * When an HTTP request has been received this method returns the HTTP
+ * {@code User-Agent} header value until capabilities have been parsed.
+ *
+ * @return user agent supplied by the client. Available only if the client
+ * is new enough to advertise its user agent.
+ * @since 4.0
+ */
+ public String getPeerUserAgent() {
+ return UserAgent.getAgent(options, userAgent);
+ }
+
private boolean negotiate() throws IOException {
okToGiveUp = Boolean.FALSE;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
new file mode 100644
index 0000000..eadb92d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
@@ -0,0 +1,147 @@
+/*
+ * 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.transport;
+
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
+
+import java.util.Set;
+
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * User agent to be reported by this JGit client and server on the network.
+ * <p>
+ * On HTTP transports this user agent string is always supplied by the JGit
+ * client in the {@code User-Agent} HTTP header.
+ * <p>
+ * On native transports this user agent string is always sent when JGit is a
+ * server. When JGit is a client the user agent string will be supplied to the
+ * remote server only if the remote server advertises its own agent identity.
+ *
+ * @since 4.0
+ */
+public class UserAgent {
+ private static volatile String userAgent = computeUserAgent();
+
+ private static String computeUserAgent() {
+ return clean("JGit/" + computeVersion()); //$NON-NLS-1$
+ }
+
+ private static String computeVersion() {
+ Package pkg = UserAgent.class.getPackage();
+ if (pkg != null) {
+ String ver = pkg.getImplementationVersion();
+ if (!StringUtils.isEmptyOrNull(ver)) {
+ return ver;
+ }
+ }
+ return "unknown"; //$NON-NLS-1$
+ }
+
+ private static String clean(String s) {
+ s = s.trim();
+ StringBuilder b = new StringBuilder(s.length());
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c <= 32 || c >= 127) {
+ if (b.length() > 0 && b.charAt(b.length() - 1) == '.')
+ continue;
+ c = '.';
+ }
+ b.append(c);
+ }
+ return b.length() > 0 ? b.toString() : null;
+ }
+
+ /**
+ * Get the user agent string advertised by JGit.
+ *
+ * @return a string similar to {@code "JGit/4.0"}; null if the agent has
+ * been cleared and should not be shared with a peer.
+ */
+ public static String get() {
+ return userAgent;
+ }
+
+ /**
+ * Change the user agent string advertised by JGit.
+ * <p>
+ * The new string should start with {@code "JGit/"} (for example
+ * {@code "JGit/4.0"}) to advertise the implementation as JGit based.
+ * <p>
+ * Spaces and other whitespace should be avoided as these will be
+ * automatically converted to {@code "."}.
+ * <p>
+ * User agent strings are restricted to printable ASCII.
+ *
+ * @param agent
+ * new user agent string for this running JGit library. Setting
+ * to null or empty string will avoid sending any identification
+ * to the peer.
+ */
+ public static void set(String agent) {
+ userAgent = StringUtils.isEmptyOrNull(agent) ? null : clean(agent);
+ }
+
+ static String getAgent(Set<String> options, String transportAgent) {
+ if (options == null || options.isEmpty()) {
+ return transportAgent;
+ }
+ for (String o : options) {
+ if (o.startsWith(OPTION_AGENT)
+ && o.length() > OPTION_AGENT.length()
+ && o.charAt(OPTION_AGENT.length()) == '=') {
+ return o.substring(OPTION_AGENT.length() + 1);
+ }
+ }
+ return transportAgent;
+ }
+
+ static boolean hasAgent(Set<String> options) {
+ return getAgent(options, null) != null;
+ }
+
+ private UserAgent() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index 35850dc..35fc99e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -115,8 +115,10 @@ public static ObjectId computeChangeId(final ObjectId treeId,
b.append(committer.toExternalString());
b.append("\n\n"); //$NON-NLS-1$
b.append(cleanMessage);
- return new ObjectInserter.Formatter().idFor(Constants.OBJ_COMMIT, //
- b.toString().getBytes(Constants.CHARACTER_ENCODING));
+ try (ObjectInserter f = new ObjectInserter.Formatter()) {
+ return f.idFor(Constants.OBJ_COMMIT, //
+ b.toString().getBytes(Constants.CHARACTER_ENCODING));
+ }
}
private static final Pattern issuePattern = Pattern
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 706b54e..d11b03e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -481,7 +481,7 @@ public void run() {
}
}
} catch (IOException e) {
- LOG.error("Caught exception in FS.readPipe()", e); //$NON-NLS-1$
+ LOG.debug("Caught exception in FS.readPipe()", e); //$NON-NLS-1$
}
if (debug) {
LOG.debug("readpipe returns null"); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index 37c9f7b..8b4ad0a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -74,6 +74,12 @@ public class HttpSupport {
/** The {@code User-Agent} header. */
public static final String HDR_USER_AGENT = "User-Agent"; //$NON-NLS-1$
+ /**
+ * The {@code Server} header.
+ * @since 4.0
+ */
+ public static final String HDR_SERVER = "Server"; //$NON-NLS-1$
+
/** The {@code Date} header. */
public static final String HDR_DATE = "Date"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index 006c3c0..3719bf7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.util;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -435,7 +436,7 @@ public LocalFile(final File directory, final int inCoreLimit) {
protected OutputStream overflow() throws IOException {
onDiskFile = File.createTempFile("jgit_", ".buf", directory); //$NON-NLS-1$ //$NON-NLS-2$
- return new FileOutputStream(onDiskFile);
+ return new BufferedOutputStream(new FileOutputStream(onDiskFile));
}
public long length() {
diff --git a/pom.xml b/pom.xml
index 4b8ac43..1e00f24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -210,6 +210,10 @@
<id>repo.eclipse.org.cbi-releases</id>
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
</pluginRepository>
+ <pluginRepository>
+ <id>repo.eclipse.org.cbi-snapshots</id>
+ <url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
+ </pluginRepository>
</pluginRepositories>
<build>
@@ -346,7 +350,7 @@
<plugin>
<groupId>org.eclipse.cbi.maven.plugins</groupId>
<artifactId>eclipse-jarsigner-plugin</artifactId>
- <version>1.1.1</version>
+ <version>1.1.2-SNAPSHOT</version>
</plugin>
<plugin>
<groupId>org.eclipse.tycho.extras</groupId>