Merge branch 'master' into stable-4.0

Change-Id: I962461630384b76e7f387f4e1c1248833fbc4673
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Matthias Sohn 2015-05-04 22:02:23 +02:00
commit f1a1acbd1c
95 changed files with 1889 additions and 747 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -14,6 +14,7 @@ Import-Package: org.eclipse.jgit.api;version="[4.0.0,4.1.0)",
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)",

View File

@ -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.
*
@ -615,6 +624,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.
*

View File

@ -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>

View File

@ -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>

View File

@ -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());
}

View File

@ -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

View File

@ -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);

View File

@ -120,6 +120,42 @@ public void testValidCommitBlankAuthor() throws CorruptObjectException {
checker.check(Constants.OBJ_COMMIT, data);
}
@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

View File

@ -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)));
}
}

View File

@ -175,6 +175,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

View File

@ -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));

View File

@ -214,21 +214,6 @@ public void testCull() throws Exception {
assertNull(objw.nextObject());
}
@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

View File

@ -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;
}
}

View File

@ -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>

View File

@ -44,6 +44,7 @@ cannotBeCombined=Cannot be combined.
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 @@ fileCannotBeDeleted=File cannot be deleted: {0}
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 @@ indexWriteException=Modified index could not be written
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 @@ packfileCorruptionDetected=Packfile corruption detected: {0}
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 @@ statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled
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 @@ truncatedHunkNewLinesMissing=Truncated hunk, at least {0} new lines is missing
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}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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$
}
}
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -315,7 +315,7 @@ public int compare(Candidate o1, Candidate o2) {
throw new JGitInternalException(e.getMessage(), e);
} finally {
setCallable(false);
w.release();
w.close();
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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>();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}
/**

View File

@ -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();
}
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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);
}
/**
@ -105,6 +110,27 @@ public DfsBlockCacheConfig setBlockSize(final int newSize) {
return this;
}
/**
* @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>
@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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 @@ private byte[] decompress(long position, int sz, DfsReader ctx)
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 {

View File

@ -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() {

View File

@ -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);
@ -104,6 +106,27 @@ public DfsReaderOptions setStreamFileThreshold(final int newLimit) {
return this;
}
/**
* @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>
@ -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;
}
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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()) {

View File

@ -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

View File

@ -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

View File

@ -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)));
}
}

View File

@ -344,11 +344,11 @@ private final byte[] decompress(final long position, final int sz,
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 {

View File

@ -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);
}

View File

@ -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()));
}
}
}
/**

View File

@ -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

View File

@ -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));

View File

@ -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();
}
}
}

View File

@ -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";
}

View File

@ -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;
@ -124,6 +126,22 @@ public ObjectChecker setAllowLeadingZeroFileMode(boolean allow) {
return this;
}
/**
* 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>
@ -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;

View File

@ -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();
}
}

View File

@ -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');
}
}
}

View File

@ -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();
}
/**

View File

@ -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');
}
}

View File

@ -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();
}
}

View File

@ -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(

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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();
/**

View File

@ -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));
}

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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() {
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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();

View File

@ -147,6 +147,21 @@ public void advertiseCapability(String name) {
capablities.add(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>
@ -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);
}
/**

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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() {
}
}

View File

@ -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

View File

@ -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$

View File

@ -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$

View File

@ -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() {

View File

@ -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>