Merge branch 'master' into stable-4.0
Change-Id: I962461630384b76e7f387f4e1c1248833fbc4673 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
commit
f1a1acbd1c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ public int compare(Candidate o1, Candidate o2) {
|
|||
throw new JGitInternalException(e.getMessage(), e);
|
||||
} finally {
|
||||
setCallable(false);
|
||||
w.release();
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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$
|
||||
|
|
|
@ -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$
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -210,6 +210,10 @@
|
|||
<id>repo.eclipse.org.cbi-releases</id>
|
||||
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>repo.eclipse.org.cbi-snapshots</id>
|
||||
<url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
|
@ -346,7 +350,7 @@
|
|||
<plugin>
|
||||
<groupId>org.eclipse.cbi.maven.plugins</groupId>
|
||||
<artifactId>eclipse-jarsigner-plugin</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.1.2-SNAPSHOT</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho.extras</groupId>
|
||||
|
|
Loading…
Reference in New Issue