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.errors.UnpackException;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.transport.InternalHttpServerGlue;
|
||||||
import org.eclipse.jgit.transport.ReceivePack;
|
import org.eclipse.jgit.transport.ReceivePack;
|
||||||
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
|
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
|
||||||
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
|
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
|
||||||
|
@ -100,6 +101,9 @@ protected void begin(HttpServletRequest req, Repository db)
|
||||||
throws IOException, ServiceNotEnabledException,
|
throws IOException, ServiceNotEnabledException,
|
||||||
ServiceNotAuthorizedException {
|
ServiceNotAuthorizedException {
|
||||||
ReceivePack rp = receivePackFactory.create(req, db);
|
ReceivePack rp = receivePackFactory.create(req, db);
|
||||||
|
InternalHttpServerGlue.setPeerUserAgent(
|
||||||
|
rp,
|
||||||
|
req.getHeader(HDR_USER_AGENT));
|
||||||
req.setAttribute(ATTRIBUTE_HANDLER, rp);
|
req.setAttribute(ATTRIBUTE_HANDLER, rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
res.sendError(SC_UNAUTHORIZED);
|
res.sendError(SC_UNAUTHORIZED);
|
||||||
return;
|
return;
|
||||||
} catch (ServiceNotEnabledException e) {
|
} catch (ServiceNotEnabledException e) {
|
||||||
sendError(req, res, SC_FORBIDDEN);
|
sendError(req, res, SC_FORBIDDEN, e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.transport.InternalHttpServerGlue;
|
||||||
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
|
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
|
||||||
import org.eclipse.jgit.transport.UploadPack;
|
import org.eclipse.jgit.transport.UploadPack;
|
||||||
import org.eclipse.jgit.transport.UploadPackInternalServerErrorException;
|
import org.eclipse.jgit.transport.UploadPackInternalServerErrorException;
|
||||||
|
@ -100,6 +101,9 @@ protected void begin(HttpServletRequest req, Repository db)
|
||||||
throws IOException, ServiceNotEnabledException,
|
throws IOException, ServiceNotEnabledException,
|
||||||
ServiceNotAuthorizedException {
|
ServiceNotAuthorizedException {
|
||||||
UploadPack up = uploadPackFactory.create(req, db);
|
UploadPack up = uploadPackFactory.create(req, db);
|
||||||
|
InternalHttpServerGlue.setPeerUserAgent(
|
||||||
|
up,
|
||||||
|
req.getHeader(HDR_USER_AGENT));
|
||||||
req.setAttribute(ATTRIBUTE_HANDLER, up);
|
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.file;version="[4.0.0,4.1.0)",
|
||||||
org.eclipse.jgit.internal.storage.pack;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.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.revwalk;version="[4.0.0,4.1.0)",
|
||||||
org.eclipse.jgit.storage.file;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)",
|
org.eclipse.jgit.treewalk;version="[4.0.0,4.1.0)",
|
||||||
|
|
|
@ -52,11 +52,13 @@
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.dircache.DirCache;
|
import org.eclipse.jgit.dircache.DirCache;
|
||||||
|
@ -88,6 +90,8 @@
|
||||||
import org.eclipse.jgit.lib.RefWriter;
|
import org.eclipse.jgit.lib.RefWriter;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.lib.TagBuilder;
|
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.ObjectWalk;
|
||||||
import org.eclipse.jgit.revwalk.RevBlob;
|
import org.eclipse.jgit.revwalk.RevBlob;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
@ -187,6 +191,11 @@ public Date getClock() {
|
||||||
return new Date(now);
|
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.
|
* 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.
|
* Update the dumb client server info files.
|
||||||
*
|
*
|
||||||
|
|
|
@ -68,6 +68,10 @@
|
||||||
<id>repo.eclipse.org.cbi-releases</id>
|
<id>repo.eclipse.org.cbi-releases</id>
|
||||||
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
|
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
|
||||||
</pluginRepository>
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>repo.eclipse.org.cbi-snapshots</id>
|
||||||
|
<url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
|
||||||
|
</pluginRepository>
|
||||||
</pluginRepositories>
|
</pluginRepositories>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
@ -210,7 +214,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.cbi.maven.plugins</groupId>
|
<groupId>org.eclipse.cbi.maven.plugins</groupId>
|
||||||
<artifactId>eclipse-jarsigner-plugin</artifactId>
|
<artifactId>eclipse-jarsigner-plugin</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>1.1.2-SNAPSHOT</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
|
|
@ -47,14 +47,15 @@
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jgit.console.ConsoleAuthenticator;
|
import org.eclipse.jgit.awtui.AwtAuthenticator;
|
||||||
import org.eclipse.jgit.console.ConsoleCredentialsProvider;
|
import org.eclipse.jgit.awtui.AwtCredentialsProvider;
|
||||||
import org.eclipse.jgit.errors.TransportException;
|
import org.eclipse.jgit.errors.TransportException;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.lib.RepositoryBuilder;
|
import org.eclipse.jgit.lib.RepositoryBuilder;
|
||||||
|
@ -115,8 +116,10 @@ public static void main(final String[] argv) {
|
||||||
*/
|
*/
|
||||||
protected void run(final String[] argv) {
|
protected void run(final String[] argv) {
|
||||||
try {
|
try {
|
||||||
ConsoleAuthenticator.install();
|
if (!installConsole()) {
|
||||||
ConsoleCredentialsProvider.install();
|
AwtAuthenticator.install();
|
||||||
|
AwtCredentialsProvider.install();
|
||||||
|
}
|
||||||
configureHttpProxy();
|
configureHttpProxy();
|
||||||
execute(argv);
|
execute(argv);
|
||||||
} catch (Die err) {
|
} catch (Die err) {
|
||||||
|
@ -246,6 +249,45 @@ protected Repository openGitDir(String aGitdir) throws IOException {
|
||||||
return rb.build();
|
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>.
|
* Configure the JRE's standard HTTP based on <code>http_proxy</code>.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -180,7 +180,7 @@ public void testPullConflict() throws Exception {
|
||||||
+ remoteUri
|
+ remoteUri
|
||||||
+ "\nSource change\n=======\nTarget change\n>>>>>>> 42453fd Target change in local\n";
|
+ "\nSource change\n=======\nTarget change\n>>>>>>> 42453fd Target change in local\n";
|
||||||
assertFileContentsEqual(targetFile, result);
|
assertFileContentsEqual(targetFile, result);
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE, target
|
assertEquals(RepositoryState.REBASING_MERGE, target
|
||||||
.getRepository().getRepositoryState());
|
.getRepository().getRepositoryState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ public void testPullLocalConflict() throws Exception {
|
||||||
String result = "<<<<<<< Upstream, based on branch 'master' of local repository\n"
|
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";
|
+ "Master change\n=======\nSlave change\n>>>>>>> 4049c9e Source change in based on master\n";
|
||||||
assertFileContentsEqual(targetFile, result);
|
assertFileContentsEqual(targetFile, result);
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE, target
|
assertEquals(RepositoryState.REBASING_MERGE, target
|
||||||
.getRepository().getRepositoryState());
|
.getRepository().getRepositoryState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -824,7 +824,7 @@ public void testStopOnConflict() throws Exception {
|
||||||
"<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
|
"<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
|
||||||
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
|
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
|
||||||
|
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE, db
|
assertEquals(RepositoryState.REBASING_MERGE, db
|
||||||
.getRepositoryState());
|
.getRepositoryState());
|
||||||
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
||||||
// the first one should be included, so we should have left two picks in
|
// 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",
|
"<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
|
||||||
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
|
">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
|
||||||
|
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE,
|
assertEquals(RepositoryState.REBASING_MERGE,
|
||||||
db.getRepositoryState());
|
db.getRepositoryState());
|
||||||
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
||||||
// the first one should be included, so we should have left two picks in
|
// 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();
|
res = git.rebase().setOperation(Operation.CONTINUE).call();
|
||||||
assertNotNull(res);
|
assertNotNull(res);
|
||||||
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
|
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE,
|
assertEquals(RepositoryState.REBASING_MERGE,
|
||||||
db.getRepositoryState());
|
db.getRepositoryState());
|
||||||
|
|
||||||
git.rebase().setOperation(Operation.SKIP).call();
|
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,
|
// user can decide what to do. if he accidentally committed, reset soft,
|
||||||
// and continue, if he really has nothing to commit, skip.
|
// and continue, if he really has nothing to commit, skip.
|
||||||
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
|
assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE,
|
assertEquals(RepositoryState.REBASING_MERGE,
|
||||||
db.getRepositoryState());
|
db.getRepositoryState());
|
||||||
|
|
||||||
git.rebase().setOperation(Operation.SKIP).call();
|
git.rebase().setOperation(Operation.SKIP).call();
|
||||||
|
@ -1401,7 +1401,7 @@ public void testStopOnConflictFileCreationAndDeletion() throws Exception {
|
||||||
assertEquals(Status.STOPPED, res.getStatus());
|
assertEquals(Status.STOPPED, res.getStatus());
|
||||||
assertEquals(conflicting, res.getCurrentCommit());
|
assertEquals(conflicting, res.getCurrentCommit());
|
||||||
|
|
||||||
assertEquals(RepositoryState.REBASING_INTERACTIVE, db
|
assertEquals(RepositoryState.REBASING_MERGE, db
|
||||||
.getRepositoryState());
|
.getRepositoryState());
|
||||||
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
|
||||||
// the first one should be included, so we should have left two picks in
|
// 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 java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
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.DfsRepositoryDescription;
|
||||||
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
|
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.AnyObjectId;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectLoader;
|
import org.eclipse.jgit.lib.ObjectLoader;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
@ -296,6 +297,83 @@ public void commitToUnbornHead() throws Exception {
|
||||||
assertEquals("refs/heads/master", ref.getTarget().getName());
|
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)
|
private String blobAsString(AnyObjectId treeish, String path)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
RevObject obj = tr.get(rw.parseTree(treeish), path);
|
RevObject obj = tr.get(rw.parseTree(treeish), path);
|
||||||
|
|
|
@ -120,6 +120,42 @@ public void testValidCommitBlankAuthor() throws CorruptObjectException {
|
||||||
checker.check(Constants.OBJ_COMMIT, data);
|
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
|
@Test
|
||||||
public void testValidCommit1Parent() throws CorruptObjectException {
|
public void testValidCommit1Parent() throws CorruptObjectException {
|
||||||
final StringBuilder b = new StringBuilder();
|
final StringBuilder b = new StringBuilder();
|
||||||
|
@ -940,7 +976,8 @@ public void testValidTagHasNoTaggerHeader() throws CorruptObjectException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidTagInvalidTaggerHeader1() {
|
public void testInvalidTagInvalidTaggerHeader1()
|
||||||
|
throws CorruptObjectException {
|
||||||
final StringBuilder b = new StringBuilder();
|
final StringBuilder b = new StringBuilder();
|
||||||
|
|
||||||
b.append("object ");
|
b.append("object ");
|
||||||
|
@ -958,6 +995,8 @@ public void testInvalidTagInvalidTaggerHeader1() {
|
||||||
} catch (CorruptObjectException e) {
|
} catch (CorruptObjectException e) {
|
||||||
assertEquals("invalid tagger", e.getMessage());
|
assertEquals("invalid tagger", e.getMessage());
|
||||||
}
|
}
|
||||||
|
checker.setAllowInvalidPersonIdent(true);
|
||||||
|
checker.checkTag(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -51,11 +51,25 @@
|
||||||
import org.eclipse.jgit.diff.RawText;
|
import org.eclipse.jgit.diff.RawText;
|
||||||
import org.eclipse.jgit.diff.RawTextComparator;
|
import org.eclipse.jgit.diff.RawTextComparator;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.junit.Assume;
|
||||||
import org.junit.Test;
|
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 {
|
public class MergeAlgorithmTest {
|
||||||
MergeFormatter fmt=new MergeFormatter();
|
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
|
* Check for a conflict where the second text was changed similar to the
|
||||||
* first one, but the second texts modification covers one more line.
|
* first one, but the second texts modification covers one more line.
|
||||||
|
@ -174,28 +188,55 @@ public void testAdjacentModifications() throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSeperateModifications() throws IOException {
|
public void testSeparateModifications() throws IOException {
|
||||||
assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe"));
|
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
|
* Test merging two contents which do one similar modification and one
|
||||||
* insertion is only done by one side. Between modification and insertion is
|
* insertion is only done by one side, in the middle. Between modification
|
||||||
* a block which is common between the two contents and the common base
|
* and insertion is a block which is common between the two contents and the
|
||||||
|
* common base
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTwoSimilarModsAndOneInsert() throws IOException {
|
public void testTwoSimilarModsAndOneInsert() throws IOException {
|
||||||
assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ"));
|
|
||||||
assertEquals(t("aBcDde"), merge("abcde", "aBcde", "aBcDde"));
|
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("IAAAJCAB"), merge("iACAB", "IACAB", "IAAAJCAB"));
|
||||||
assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB"));
|
assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB"));
|
||||||
assertEquals(t("AGADEFHIAAAJCAB"),
|
assertEquals(t("AGADEFHIAAAJCAB"),
|
||||||
merge("AGADEFHiACAB", "AGADEFHIACAB", "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);
|
return new String(bo.toByteArray(), Constants.CHARACTER_ENCODING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String t(String text) {
|
public String t(String text) {
|
||||||
StringBuilder r = new StringBuilder();
|
StringBuilder r = new StringBuilder();
|
||||||
for (int i = 0; i < text.length(); i++) {
|
for (int i = 0; i < text.length(); i++) {
|
||||||
char c = text.charAt(i);
|
char c = text.charAt(i);
|
||||||
|
@ -241,13 +282,14 @@ public static String t(String text) {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
r.append(c);
|
r.append(c);
|
||||||
r.append('\n');
|
if (newlineAtEnd || i < text.length() - 1)
|
||||||
|
r.append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r.toString();
|
return r.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RawText T(String text) {
|
public RawText T(String text) {
|
||||||
return new RawText(Constants.encode(t(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
|
@Theory
|
||||||
/**
|
/**
|
||||||
* Merging m2,s2 from the following topology. The same file is modified
|
* 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)
|
MergeResult mergeRes = git.merge().setStrategy(strategy)
|
||||||
.include(masterCommit).call();
|
.include(masterCommit).call();
|
||||||
assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
|
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));
|
indexState(CONTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,7 +561,7 @@ public void checkMergeCrissCross(MergeStrategy strategy) throws Exception {
|
||||||
assertEquals(MergeStrategy.RECURSIVE, strategy);
|
assertEquals(MergeStrategy.RECURSIVE, strategy);
|
||||||
assertEquals(MergeResult.MergeStatus.MERGED,
|
assertEquals(MergeResult.MergeStatus.MERGED,
|
||||||
mergeResult.getMergeStatus());
|
mergeResult.getMergeStatus());
|
||||||
assertEquals("1master2\n2\n3side2\n", read("1"));
|
assertEquals("1master2\n2\n3side2", read("1"));
|
||||||
} catch (JGitInternalException e) {
|
} catch (JGitInternalException e) {
|
||||||
assertEquals(MergeStrategy.RESOLVE, strategy);
|
assertEquals(MergeStrategy.RESOLVE, strategy);
|
||||||
assertTrue(e.getCause() instanceof NoMergeBaseException);
|
assertTrue(e.getCause() instanceof NoMergeBaseException);
|
||||||
|
@ -697,7 +697,7 @@ public void checkForCorrectIndex(MergeStrategy strategy) throws Exception {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"[0, mode:100644, content:master]" //
|
"[0, mode:100644, content:master]" //
|
||||||
+ "[1, mode:100644, content:side]" //
|
+ "[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]" //
|
+ "[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]", //
|
+ "[4, mode:100644, content:orig]", //
|
||||||
indexState(CONTENT));
|
indexState(CONTENT));
|
||||||
|
|
|
@ -214,21 +214,6 @@ public void testCull() throws Exception {
|
||||||
assertNull(objw.nextObject());
|
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
|
@Test
|
||||||
public void testEmptyTreeCorruption() throws Exception {
|
public void testEmptyTreeCorruption() throws Exception {
|
||||||
ObjectId bId = ObjectId
|
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"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<component id="org.eclipse.jgit" version="2">
|
<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">
|
<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">
|
<filter comment="moved into another bundle keeping original package" id="1110441988">
|
||||||
<message_arguments>
|
<message_arguments>
|
||||||
|
|
|
@ -44,6 +44,7 @@ cannotBeCombined=Cannot be combined.
|
||||||
cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included.
|
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}.
|
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.
|
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.
|
cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff.
|
||||||
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}.
|
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}.
|
||||||
cannotCommitOnARepoWithState=Cannot commit on a repo with state: {0}
|
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).
|
fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes).
|
||||||
fileIsTooLarge=File is too large: {0}
|
fileIsTooLarge=File is too large: {0}
|
||||||
fileModeNotSetForPath=FileMode not set for path {0}
|
fileModeNotSetForPath=FileMode not set for path {0}
|
||||||
|
findingGarbage=Finding garbage
|
||||||
flagIsDisposed={0} is disposed.
|
flagIsDisposed={0} is disposed.
|
||||||
flagNotFromThis={0} not from this.
|
flagNotFromThis={0} not from this.
|
||||||
flagsAlreadyCreated={0} flags already created.
|
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
|
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
|
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
|
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
|
||||||
|
inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing.
|
||||||
inputStreamMustSupportMark=InputStream must support mark()
|
inputStreamMustSupportMark=InputStream must support mark()
|
||||||
integerValueOutOfRange=Integer value {0}.{1} out of range
|
integerValueOutOfRange=Integer value {0}.{1} out of range
|
||||||
internalRevisionError=internal revision error
|
internalRevisionError=internal revision error
|
||||||
|
@ -391,6 +394,7 @@ packfileCorruptionDetected=Packfile corruption detected: {0}
|
||||||
packFileInvalid=Pack file invalid: {0}
|
packFileInvalid=Pack file invalid: {0}
|
||||||
packfileIsTruncated=Packfile {0} is truncated.
|
packfileIsTruncated=Packfile {0} is truncated.
|
||||||
packfileIsTruncatedNoParam=Packfile is truncated.
|
packfileIsTruncatedNoParam=Packfile is truncated.
|
||||||
|
packHandleIsStale=Pack file {0} handle is stale, removing it from pack list
|
||||||
packHasUnresolvedDeltas=pack has unresolved deltas
|
packHasUnresolvedDeltas=pack has unresolved deltas
|
||||||
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
|
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
|
||||||
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
|
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
|
submoduleExists=Submodule ''{0}'' already exists in the index
|
||||||
submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}''
|
submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}''
|
||||||
submodulesNotSupported=Submodules are not supported
|
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.
|
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}
|
systemConfigFileInvalid=Systen wide config file {0} is invalid {1}
|
||||||
tagAlreadyExists=tag ''{0}'' already exists
|
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
|
truncatedHunkOldLinesMissing=Truncated hunk, at least {0} old lines is missing
|
||||||
tSizeMustBeGreaterOrEqual1=tSize must be >= 1
|
tSizeMustBeGreaterOrEqual1=tSize must be >= 1
|
||||||
unableToCheckConnectivity=Unable to check connectivity.
|
unableToCheckConnectivity=Unable to check connectivity.
|
||||||
|
unableToCreateNewObject=Unable to create new object: {0}
|
||||||
unableToStore=Unable to store {0}.
|
unableToStore=Unable to store {0}.
|
||||||
unableToWrite=Unable to write {0}
|
unableToWrite=Unable to write {0}
|
||||||
unencodeableFile=Unencodable file: {0}
|
unencodeableFile=Unencodable file: {0}
|
||||||
|
|
|
@ -137,13 +137,12 @@ public DirCache call() throws GitAPIException, NoFilepatternException {
|
||||||
if (filepatterns.contains(".")) //$NON-NLS-1$
|
if (filepatterns.contains(".")) //$NON-NLS-1$
|
||||||
addAll = true;
|
addAll = true;
|
||||||
|
|
||||||
ObjectInserter inserter = repo.newObjectInserter();
|
try (ObjectInserter inserter = repo.newObjectInserter();
|
||||||
try {
|
final TreeWalk tw = new TreeWalk(repo)) {
|
||||||
dc = repo.lockDirCache();
|
dc = repo.lockDirCache();
|
||||||
DirCacheIterator c;
|
DirCacheIterator c;
|
||||||
|
|
||||||
DirCacheBuilder builder = dc.builder();
|
DirCacheBuilder builder = dc.builder();
|
||||||
final TreeWalk tw = new TreeWalk(repo);
|
|
||||||
tw.addTree(new DirCacheBuildIterator(builder));
|
tw.addTree(new DirCacheBuildIterator(builder));
|
||||||
if (workingTreeIterator == null)
|
if (workingTreeIterator == null)
|
||||||
workingTreeIterator = new FileTreeIterator(repo);
|
workingTreeIterator = new FileTreeIterator(repo);
|
||||||
|
@ -212,7 +211,6 @@ else if (!(path.equals(lastAddedFile))) {
|
||||||
throw new JGitInternalException(
|
throw new JGitInternalException(
|
||||||
JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e);
|
JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e);
|
||||||
} finally {
|
} finally {
|
||||||
inserter.release();
|
|
||||||
if (dc != null)
|
if (dc != null)
|
||||||
dc.unlock();
|
dc.unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,11 +83,10 @@ protected AddNoteCommand(Repository repo) {
|
||||||
|
|
||||||
public Note call() throws GitAPIException {
|
public Note call() throws GitAPIException {
|
||||||
checkCallable();
|
checkCallable();
|
||||||
RevWalk walk = new RevWalk(repo);
|
|
||||||
ObjectInserter inserter = repo.newObjectInserter();
|
|
||||||
NoteMap map = NoteMap.newEmptyMap();
|
NoteMap map = NoteMap.newEmptyMap();
|
||||||
RevCommit notesCommit = null;
|
RevCommit notesCommit = null;
|
||||||
try {
|
try (RevWalk walk = new RevWalk(repo);
|
||||||
|
ObjectInserter inserter = repo.newObjectInserter()) {
|
||||||
Ref ref = repo.getRef(notesRef);
|
Ref ref = repo.getRef(notesRef);
|
||||||
// if we have a notes ref, use it
|
// if we have a notes ref, use it
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
|
@ -96,13 +95,10 @@ public Note call() throws GitAPIException {
|
||||||
}
|
}
|
||||||
map.set(id, message, inserter);
|
map.set(id, message, inserter);
|
||||||
commitNoteMap(walk, map, notesCommit, 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);
|
return map.getNote(id);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(e.getMessage(), 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) {
|
private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
|
||||||
final String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$
|
final String pfx = prefix == null ? "" : prefix; //$NON-NLS-1$
|
||||||
final TreeWalk walk = new TreeWalk(repo);
|
try (final TreeWalk walk = new TreeWalk(repo)) {
|
||||||
try {
|
|
||||||
final T outa = fmt.createArchiveOutputStream(out, formatOptions);
|
final T outa = fmt.createArchiveOutputStream(out, formatOptions);
|
||||||
try {
|
try (final RevWalk rw = new RevWalk(walk.getObjectReader())) {
|
||||||
final MutableObjectId idBuf = new MutableObjectId();
|
final MutableObjectId idBuf = new MutableObjectId();
|
||||||
final ObjectReader reader = walk.getObjectReader();
|
final ObjectReader reader = walk.getObjectReader();
|
||||||
final RevWalk rw = new RevWalk(walk.getObjectReader());
|
|
||||||
|
|
||||||
walk.reset(rw.parseTree(tree));
|
walk.reset(rw.parseTree(tree));
|
||||||
if (!paths.isEmpty())
|
if (!paths.isEmpty())
|
||||||
|
@ -405,8 +403,6 @@ private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
|
||||||
// TODO(jrn): Throw finer-grained errors.
|
// TODO(jrn): Throw finer-grained errors.
|
||||||
throw new JGitInternalException(
|
throw new JGitInternalException(
|
||||||
JGitText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e);
|
JGitText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e);
|
||||||
} finally {
|
|
||||||
walk.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,8 +200,7 @@ public BlameCommand reverse(AnyObjectId start, Collection<ObjectId> end)
|
||||||
*/
|
*/
|
||||||
public BlameResult call() throws GitAPIException {
|
public BlameResult call() throws GitAPIException {
|
||||||
checkCallable();
|
checkCallable();
|
||||||
BlameGenerator gen = new BlameGenerator(repo, path);
|
try (BlameGenerator gen = new BlameGenerator(repo, path)) {
|
||||||
try {
|
|
||||||
if (diffAlgorithm != null)
|
if (diffAlgorithm != null)
|
||||||
gen.setDiffAlgorithm(diffAlgorithm);
|
gen.setDiffAlgorithm(diffAlgorithm);
|
||||||
if (textComparator != null)
|
if (textComparator != null)
|
||||||
|
@ -231,8 +230,6 @@ else if (startCommit != null)
|
||||||
return gen.computeBlameResult();
|
return gen.computeBlameResult();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(e.getMessage(), e);
|
throw new JGitInternalException(e.getMessage(), e);
|
||||||
} finally {
|
|
||||||
gen.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,16 +208,17 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createBranch) {
|
if (createBranch) {
|
||||||
Git git = new Git(repo);
|
try (Git git = new Git(repo)) {
|
||||||
CreateBranchCommand command = git.branchCreate();
|
CreateBranchCommand command = git.branchCreate();
|
||||||
command.setName(name);
|
command.setName(name);
|
||||||
if (startCommit != null)
|
if (startCommit != null)
|
||||||
command.setStartPoint(startCommit);
|
command.setStartPoint(startCommit);
|
||||||
else
|
else
|
||||||
command.setStartPoint(startPoint);
|
command.setStartPoint(startPoint);
|
||||||
if (upstreamMode != null)
|
if (upstreamMode != null)
|
||||||
command.setUpstreamMode(upstreamMode);
|
command.setUpstreamMode(upstreamMode);
|
||||||
command.call();
|
command.call();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref headRef = repo.getRef(Constants.HEAD);
|
Ref headRef = repo.getRef(Constants.HEAD);
|
||||||
|
@ -243,11 +244,14 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
|
||||||
JGitText.get().refNotResolved, name));
|
JGitText.get().refNotResolved, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
RevWalk revWalk = new RevWalk(repo);
|
RevCommit headCommit = null;
|
||||||
AnyObjectId headId = headRef.getObjectId();
|
RevCommit newCommit = null;
|
||||||
RevCommit headCommit = headId == null ? null : revWalk
|
try (RevWalk revWalk = new RevWalk(repo)) {
|
||||||
.parseCommit(headId);
|
AnyObjectId headId = headRef.getObjectId();
|
||||||
RevCommit newCommit = revWalk.parseCommit(branch);
|
headCommit = headId == null ? null
|
||||||
|
: revWalk.parseCommit(headId);
|
||||||
|
newCommit = revWalk.parseCommit(branch);
|
||||||
|
}
|
||||||
RevTree headTree = headCommit == null ? null : headCommit.getTree();
|
RevTree headTree = headCommit == null ? null : headCommit.getTree();
|
||||||
DirCacheCheckout dco;
|
DirCacheCheckout dco;
|
||||||
DirCache dc = repo.lockDirCache();
|
DirCache dc = repo.lockDirCache();
|
||||||
|
@ -376,26 +380,20 @@ public CheckoutCommand setAllPaths(boolean all) {
|
||||||
*/
|
*/
|
||||||
protected CheckoutCommand checkoutPaths() throws IOException,
|
protected CheckoutCommand checkoutPaths() throws IOException,
|
||||||
RefNotFoundException {
|
RefNotFoundException {
|
||||||
RevWalk revWalk = new RevWalk(repo);
|
|
||||||
DirCache dc = repo.lockDirCache();
|
DirCache dc = repo.lockDirCache();
|
||||||
try {
|
try (RevWalk revWalk = new RevWalk(repo);
|
||||||
TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader());
|
TreeWalk treeWalk = new TreeWalk(revWalk.getObjectReader())) {
|
||||||
treeWalk.setRecursive(true);
|
treeWalk.setRecursive(true);
|
||||||
if (!checkoutAllPaths)
|
if (!checkoutAllPaths)
|
||||||
treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
|
treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
|
||||||
try {
|
if (isCheckoutIndex())
|
||||||
if (isCheckoutIndex())
|
checkoutPathsFromIndex(treeWalk, dc);
|
||||||
checkoutPathsFromIndex(treeWalk, dc);
|
else {
|
||||||
else {
|
RevCommit commit = revWalk.parseCommit(getStartPointObjectId());
|
||||||
RevCommit commit = revWalk.parseCommit(getStartPointObjectId());
|
checkoutPathsFromCommit(treeWalk, dc, commit);
|
||||||
checkoutPathsFromCommit(treeWalk, dc, commit);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
treeWalk.release();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
dc.unlock();
|
dc.unlock();
|
||||||
revWalk.release();
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -675,7 +673,6 @@ public CheckoutResult getResult() {
|
||||||
private void checkOptions() {
|
private void checkOptions() {
|
||||||
if (checkoutStage != null && !isCheckoutIndex())
|
if (checkoutStage != null && !isCheckoutIndex())
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Checking out ours/theirs is only possible when checking out index, "
|
JGitText.get().cannotCheckoutOursSwitchBranch);
|
||||||
+ "not when switching branches.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,8 +123,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
|
||||||
List<Ref> cherryPickedRefs = new LinkedList<Ref>();
|
List<Ref> cherryPickedRefs = new LinkedList<Ref>();
|
||||||
checkCallable();
|
checkCallable();
|
||||||
|
|
||||||
RevWalk revWalk = new RevWalk(repo);
|
try (RevWalk revWalk = new RevWalk(repo)) {
|
||||||
try {
|
|
||||||
|
|
||||||
// get the head commit
|
// get the head commit
|
||||||
Ref headRef = repo.getRef(Constants.HEAD);
|
Ref headRef = repo.getRef(Constants.HEAD);
|
||||||
|
@ -153,7 +152,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
|
||||||
ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
|
ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
|
||||||
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
|
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
|
||||||
merger.setBase(srcParent.getTree());
|
merger.setBase(srcParent.getTree());
|
||||||
merger.setCommitNames(new String[] { "BASE", ourName,
|
merger.setCommitNames(new String[] { "BASE", ourName, //$NON-NLS-1$
|
||||||
cherryPickName });
|
cherryPickName });
|
||||||
if (merger.merge(newHead, srcCommit)) {
|
if (merger.merge(newHead, srcCommit)) {
|
||||||
if (AnyObjectId.equals(newHead.getTree().getId(), merger
|
if (AnyObjectId.equals(newHead.getTree().getId(), merger
|
||||||
|
@ -194,8 +193,6 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
|
||||||
MessageFormat.format(
|
MessageFormat.format(
|
||||||
JGitText.get().exceptionCaughtDuringExecutionOfCherryPickCommand,
|
JGitText.get().exceptionCaughtDuringExecutionOfCherryPickCommand,
|
||||||
e), e);
|
e), e);
|
||||||
} finally {
|
|
||||||
revWalk.release();
|
|
||||||
}
|
}
|
||||||
return new CherryPickResult(newHead, cherryPickedRefs);
|
return new CherryPickResult(newHead, cherryPickedRefs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,21 +63,21 @@ public enum CherryPickStatus {
|
||||||
OK {
|
OK {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Ok";
|
return "Ok"; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** */
|
/** */
|
||||||
FAILED {
|
FAILED {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Failed";
|
return "Failed"; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** */
|
/** */
|
||||||
CONFLICTING {
|
CONFLICTING {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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)
|
private RevCommit parseCommit(final Repository clonedRepo, final Ref ref)
|
||||||
throws MissingObjectException, IncorrectObjectTypeException,
|
throws MissingObjectException, IncorrectObjectTypeException,
|
||||||
IOException {
|
IOException {
|
||||||
final RevWalk rw = new RevWalk(clonedRepo);
|
|
||||||
final RevCommit commit;
|
final RevCommit commit;
|
||||||
try {
|
try (final RevWalk rw = new RevWalk(clonedRepo)) {
|
||||||
commit = rw.parseCommit(ref.getObjectId());
|
commit = rw.parseCommit(ref.getObjectId());
|
||||||
} finally {
|
|
||||||
rw.release();
|
|
||||||
}
|
}
|
||||||
return commit;
|
return commit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,9 +165,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
|
||||||
checkCallable();
|
checkCallable();
|
||||||
Collections.sort(only);
|
Collections.sort(only);
|
||||||
|
|
||||||
RevWalk rw = new RevWalk(repo);
|
try (RevWalk rw = new RevWalk(repo)) {
|
||||||
|
|
||||||
try {
|
|
||||||
RepositoryState state = repo.getRepositoryState();
|
RepositoryState state = repo.getRepositoryState();
|
||||||
if (!state.canCommit())
|
if (!state.canCommit())
|
||||||
throw new WrongRepositoryStateException(MessageFormat.format(
|
throw new WrongRepositoryStateException(MessageFormat.format(
|
||||||
|
@ -181,8 +179,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
|
||||||
processOptions(state, rw);
|
processOptions(state, rw);
|
||||||
|
|
||||||
if (all && !repo.isBare() && repo.getWorkTree() != null) {
|
if (all && !repo.isBare() && repo.getWorkTree() != null) {
|
||||||
Git git = new Git(repo);
|
try (Git git = new Git(repo)) {
|
||||||
try {
|
|
||||||
git.add()
|
git.add()
|
||||||
.addFilepattern(".") //$NON-NLS-1$
|
.addFilepattern(".") //$NON-NLS-1$
|
||||||
.setUpdate(true).call();
|
.setUpdate(true).call();
|
||||||
|
@ -221,80 +218,74 @@ public RevCommit call() throws GitAPIException, NoHeadException,
|
||||||
|
|
||||||
// lock the index
|
// lock the index
|
||||||
DirCache index = repo.lockDirCache();
|
DirCache index = repo.lockDirCache();
|
||||||
try {
|
try (ObjectInserter odi = repo.newObjectInserter()) {
|
||||||
if (!only.isEmpty())
|
if (!only.isEmpty())
|
||||||
index = createTemporaryIndex(headId, index, rw);
|
index = createTemporaryIndex(headId, index, rw);
|
||||||
|
|
||||||
ObjectInserter odi = repo.newObjectInserter();
|
// Write the index as tree to the object database. This may
|
||||||
try {
|
// fail for example when the index contains unmerged paths
|
||||||
// Write the index as tree to the object database. This may
|
// (unresolved conflicts)
|
||||||
// fail for example when the index contains unmerged paths
|
ObjectId indexTreeId = index.writeTree(odi);
|
||||||
// (unresolved conflicts)
|
|
||||||
ObjectId indexTreeId = index.writeTree(odi);
|
|
||||||
|
|
||||||
if (insertChangeId)
|
if (insertChangeId)
|
||||||
insertChangeId(indexTreeId);
|
insertChangeId(indexTreeId);
|
||||||
|
|
||||||
// Create a Commit object, populate it and write it
|
// Create a Commit object, populate it and write it
|
||||||
CommitBuilder commit = new CommitBuilder();
|
CommitBuilder commit = new CommitBuilder();
|
||||||
commit.setCommitter(committer);
|
commit.setCommitter(committer);
|
||||||
commit.setAuthor(author);
|
commit.setAuthor(author);
|
||||||
commit.setMessage(message);
|
commit.setMessage(message);
|
||||||
|
|
||||||
commit.setParentIds(parents);
|
commit.setParentIds(parents);
|
||||||
commit.setTreeId(indexTreeId);
|
commit.setTreeId(indexTreeId);
|
||||||
ObjectId commitId = odi.insert(commit);
|
ObjectId commitId = odi.insert(commit);
|
||||||
odi.flush();
|
odi.flush();
|
||||||
|
|
||||||
RevCommit revCommit = rw.parseCommit(commitId);
|
RevCommit revCommit = rw.parseCommit(commitId);
|
||||||
RefUpdate ru = repo.updateRef(Constants.HEAD);
|
RefUpdate ru = repo.updateRef(Constants.HEAD);
|
||||||
ru.setNewObjectId(commitId);
|
ru.setNewObjectId(commitId);
|
||||||
if (reflogComment != null) {
|
if (reflogComment != null) {
|
||||||
ru.setRefLogMessage(reflogComment, false);
|
ru.setRefLogMessage(reflogComment, false);
|
||||||
} else {
|
} else {
|
||||||
String prefix = amend ? "commit (amend): " //$NON-NLS-1$
|
String prefix = amend ? "commit (amend): " //$NON-NLS-1$
|
||||||
: parents.size() == 0 ? "commit (initial): " //$NON-NLS-1$
|
: parents.size() == 0 ? "commit (initial): " //$NON-NLS-1$
|
||||||
: "commit: "; //$NON-NLS-1$
|
: "commit: "; //$NON-NLS-1$
|
||||||
ru.setRefLogMessage(
|
ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
|
||||||
prefix + revCommit.getShortMessage(), false);
|
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)
|
return revCommit;
|
||||||
ru.setExpectedOldObjectId(headId);
|
}
|
||||||
else
|
case REJECTED:
|
||||||
ru.setExpectedOldObjectId(ObjectId.zeroId());
|
case LOCK_FAILURE:
|
||||||
Result rc = ru.forceUpdate();
|
throw new ConcurrentRefUpdateException(
|
||||||
switch (rc) {
|
JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
|
||||||
case NEW:
|
default:
|
||||||
case FORCED:
|
throw new JGitInternalException(MessageFormat.format(
|
||||||
case FAST_FORWARD: {
|
JGitText.get().updatingRefFailed, Constants.HEAD,
|
||||||
setCallable(false);
|
commitId.toString(), rc));
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
index.unlock();
|
index.unlock();
|
||||||
|
@ -304,8 +295,6 @@ public RevCommit call() throws GitAPIException, NoHeadException,
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(
|
throw new JGitInternalException(
|
||||||
JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
|
JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
|
||||||
} finally {
|
|
||||||
rw.dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,114 +327,120 @@ private DirCache createTemporaryIndex(ObjectId headId, DirCache index,
|
||||||
onlyProcessed = new boolean[only.size()];
|
onlyProcessed = new boolean[only.size()];
|
||||||
boolean emptyCommit = true;
|
boolean emptyCommit = true;
|
||||||
|
|
||||||
TreeWalk treeWalk = new TreeWalk(repo);
|
try (TreeWalk treeWalk = new TreeWalk(repo)) {
|
||||||
int dcIdx = treeWalk.addTree(new DirCacheBuildIterator(existingBuilder));
|
int dcIdx = treeWalk
|
||||||
int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
|
.addTree(new DirCacheBuildIterator(existingBuilder));
|
||||||
int hIdx = -1;
|
int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
|
||||||
if (headId != null)
|
int hIdx = -1;
|
||||||
hIdx = treeWalk.addTree(rw.parseTree(headId));
|
if (headId != null)
|
||||||
treeWalk.setRecursive(true);
|
hIdx = treeWalk.addTree(rw.parseTree(headId));
|
||||||
|
treeWalk.setRecursive(true);
|
||||||
|
|
||||||
String lastAddedFile = null;
|
String lastAddedFile = null;
|
||||||
while (treeWalk.next()) {
|
while (treeWalk.next()) {
|
||||||
String path = treeWalk.getPathString();
|
String path = treeWalk.getPathString();
|
||||||
// check if current entry's path matches a specified path
|
// check if current entry's path matches a specified path
|
||||||
int pos = lookupOnly(path);
|
int pos = lookupOnly(path);
|
||||||
|
|
||||||
CanonicalTreeParser hTree = null;
|
CanonicalTreeParser hTree = null;
|
||||||
if (hIdx != -1)
|
if (hIdx != -1)
|
||||||
hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
|
hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
|
||||||
|
|
||||||
DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
|
DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
|
||||||
DirCacheIterator.class);
|
DirCacheIterator.class);
|
||||||
|
|
||||||
if (pos >= 0) {
|
if (pos >= 0) {
|
||||||
// include entry in commit
|
// include entry in commit
|
||||||
|
|
||||||
FileTreeIterator fTree = treeWalk.getTree(fIdx,
|
FileTreeIterator fTree = treeWalk.getTree(fIdx,
|
||||||
FileTreeIterator.class);
|
FileTreeIterator.class);
|
||||||
|
|
||||||
// check if entry refers to a tracked file
|
// check if entry refers to a tracked file
|
||||||
boolean tracked = dcTree != null || hTree != null;
|
boolean tracked = dcTree != null || hTree != null;
|
||||||
if (!tracked)
|
if (!tracked)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// for an unmerged path, DirCacheBuildIterator will yield 3
|
// for an unmerged path, DirCacheBuildIterator will yield 3
|
||||||
// entries, we only want to add one
|
// entries, we only want to add one
|
||||||
if (path.equals(lastAddedFile))
|
if (path.equals(lastAddedFile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lastAddedFile = path;
|
lastAddedFile = path;
|
||||||
|
|
||||||
if (fTree != null) {
|
if (fTree != null) {
|
||||||
// create a new DirCacheEntry with data retrieved from disk
|
// create a new DirCacheEntry with data retrieved from
|
||||||
final DirCacheEntry dcEntry = new DirCacheEntry(path);
|
// disk
|
||||||
long entryLength = fTree.getEntryLength();
|
final DirCacheEntry dcEntry = new DirCacheEntry(path);
|
||||||
dcEntry.setLength(entryLength);
|
long entryLength = fTree.getEntryLength();
|
||||||
dcEntry.setLastModified(fTree.getEntryLastModified());
|
dcEntry.setLength(entryLength);
|
||||||
dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
|
dcEntry.setLastModified(fTree.getEntryLastModified());
|
||||||
|
dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
|
||||||
|
|
||||||
boolean objectExists = (dcTree != null && fTree
|
boolean objectExists = (dcTree != null
|
||||||
.idEqual(dcTree))
|
&& fTree.idEqual(dcTree))
|
||||||
|| (hTree != null && fTree.idEqual(hTree));
|
|| (hTree != null && fTree.idEqual(hTree));
|
||||||
if (objectExists) {
|
if (objectExists) {
|
||||||
dcEntry.setObjectId(fTree.getEntryObjectId());
|
|
||||||
} else {
|
|
||||||
if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
|
|
||||||
dcEntry.setObjectId(fTree.getEntryObjectId());
|
dcEntry.setObjectId(fTree.getEntryObjectId());
|
||||||
else {
|
} else {
|
||||||
// insert object
|
if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
|
||||||
if (inserter == null)
|
dcEntry.setObjectId(fTree.getEntryObjectId());
|
||||||
inserter = repo.newObjectInserter();
|
else {
|
||||||
long contentLength = fTree.getEntryContentLength();
|
// insert object
|
||||||
InputStream inputStream = fTree.openEntryStream();
|
if (inserter == null)
|
||||||
try {
|
inserter = repo.newObjectInserter();
|
||||||
dcEntry.setObjectId(inserter.insert(
|
long contentLength = fTree
|
||||||
Constants.OBJ_BLOB, contentLength,
|
.getEntryContentLength();
|
||||||
inputStream));
|
InputStream inputStream = fTree
|
||||||
} finally {
|
.openEntryStream();
|
||||||
inputStream.close();
|
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
|
// keep track of processed path
|
||||||
existingBuilder.add(dcEntry);
|
onlyProcessed[pos] = true;
|
||||||
// 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 {
|
} else {
|
||||||
// if no file exists on disk, neither add it to
|
// add entries from HEAD for all other paths
|
||||||
// index nor to temporary in-core index
|
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)
|
// add to temporary in-core index
|
||||||
// this is a change
|
tempBuilder.add(dcEntry);
|
||||||
emptyCommit = false;
|
}
|
||||||
|
|
||||||
|
// 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);
|
throw new JGitInternalException(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
setCallable(false);
|
setCallable(false);
|
||||||
w.release();
|
w.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,11 +124,8 @@ public List<DiffEntry> call() throws GitAPIException {
|
||||||
if (head == null)
|
if (head == null)
|
||||||
throw new NoHeadException(JGitText.get().cannotReadTree);
|
throw new NoHeadException(JGitText.get().cannotReadTree);
|
||||||
CanonicalTreeParser p = new CanonicalTreeParser();
|
CanonicalTreeParser p = new CanonicalTreeParser();
|
||||||
ObjectReader reader = repo.newObjectReader();
|
try (ObjectReader reader = repo.newObjectReader()) {
|
||||||
try {
|
|
||||||
p.reset(reader, head);
|
p.reset(reader, head);
|
||||||
} finally {
|
|
||||||
reader.release();
|
|
||||||
}
|
}
|
||||||
oldTree = p;
|
oldTree = p;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +156,7 @@ public List<DiffEntry> call() throws GitAPIException {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(e.getMessage(), e);
|
throw new JGitInternalException(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
diffFmt.release();
|
diffFmt.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,11 +185,11 @@ public Map<ObjectId, String> call() throws GitAPIException {
|
||||||
}
|
}
|
||||||
|
|
||||||
setCallable(false);
|
setCallable(false);
|
||||||
walk.release();
|
|
||||||
return result;
|
return result;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
walk.reset();
|
|
||||||
throw new JGitInternalException(e.getMessage(), e);
|
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(HEAD_NAME, headName);
|
||||||
rebaseState.createFile(ONTO, upstreamCommit.name());
|
rebaseState.createFile(ONTO, upstreamCommit.name());
|
||||||
rebaseState.createFile(ONTO_NAME, upstreamCommitName);
|
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$
|
rebaseState.createFile(QUIET, ""); //$NON-NLS-1$
|
||||||
|
|
||||||
ArrayList<RebaseTodoLine> toDoSteps = new ArrayList<RebaseTodoLine>();
|
ArrayList<RebaseTodoLine> toDoSteps = new ArrayList<RebaseTodoLine>();
|
||||||
|
|
|
@ -227,9 +227,9 @@ else if (repo.readSquashCommitMsg() != null)
|
||||||
setCallable(false);
|
setCallable(false);
|
||||||
return result;
|
return result;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(
|
throw new JGitInternalException(MessageFormat.format(
|
||||||
JGitText.get().exceptionCaughtDuringExecutionOfResetCommand,
|
JGitText.get().exceptionCaughtDuringExecutionOfResetCommand,
|
||||||
e);
|
e.getMessage()), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ public static BlameResult create(BlameGenerator gen) throws IOException {
|
||||||
String path = gen.getResultPath();
|
String path = gen.getResultPath();
|
||||||
RawText contents = gen.getResultContents();
|
RawText contents = gen.getResultContents();
|
||||||
if (contents == null) {
|
if (contents == null) {
|
||||||
gen.release();
|
gen.close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new BlameResult(gen, path, contents);
|
return new BlameResult(gen, path, contents);
|
||||||
|
@ -239,7 +239,7 @@ public void computeAll() throws IOException {
|
||||||
while (gen.next())
|
while (gen.next())
|
||||||
loadFrom(gen);
|
loadFrom(gen);
|
||||||
} finally {
|
} finally {
|
||||||
gen.release();
|
gen.close();
|
||||||
generator = null;
|
generator = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,7 @@ public int computeNext() throws IOException {
|
||||||
lastLength = gen.getRegionLength();
|
lastLength = gen.getRegionLength();
|
||||||
return gen.getResultStart();
|
return gen.getResultStart();
|
||||||
} else {
|
} else {
|
||||||
gen.release();
|
gen.close();
|
||||||
generator = null;
|
generator = null;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ public void computeRange(int start, int end) throws IOException {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!gen.next()) {
|
if (!gen.next()) {
|
||||||
gen.release();
|
gen.close();
|
||||||
generator = null;
|
generator = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ protected OutputStream getOutputStream() {
|
||||||
*/
|
*/
|
||||||
public void setRepository(Repository repository) {
|
public void setRepository(Repository repository) {
|
||||||
if (reader != null)
|
if (reader != null)
|
||||||
reader.release();
|
reader.close();
|
||||||
|
|
||||||
db = repository;
|
db = repository;
|
||||||
reader = db.newObjectReader();
|
reader = db.newObjectReader();
|
||||||
|
@ -422,10 +422,11 @@ public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assertHaveRepository();
|
assertHaveRepository();
|
||||||
|
|
||||||
RevWalk rw = new RevWalk(reader);
|
try (RevWalk rw = new RevWalk(reader)) {
|
||||||
RevTree aTree = a != null ? rw.parseTree(a) : null;
|
RevTree aTree = a != null ? rw.parseTree(a) : null;
|
||||||
RevTree bTree = b != null ? rw.parseTree(b) : null;
|
RevTree bTree = b != null ? rw.parseTree(b) : null;
|
||||||
return scan(aTree, bTree);
|
return scan(aTree, bTree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -961,9 +961,8 @@ private void registerIndexChangedListener(IndexChangedListener listener) {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void updateSmudgedEntries() throws IOException {
|
private void updateSmudgedEntries() throws IOException {
|
||||||
TreeWalk walk = new TreeWalk(repository);
|
|
||||||
List<String> paths = new ArrayList<String>(128);
|
List<String> paths = new ArrayList<String>(128);
|
||||||
try {
|
try (TreeWalk walk = new TreeWalk(repository)) {
|
||||||
for (int i = 0; i < entryCnt; i++)
|
for (int i = 0; i < entryCnt; i++)
|
||||||
if (sortedEntries[i].isSmudged())
|
if (sortedEntries[i].isSmudged())
|
||||||
paths.add(sortedEntries[i].getPathString());
|
paths.add(sortedEntries[i].getPathString());
|
||||||
|
@ -989,8 +988,6 @@ private void updateSmudgedEntries() throws IOException {
|
||||||
entry.setLastModified(fIter.getEntryLastModified());
|
entry.setLastModified(fIter.getEntryLastModified());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
walk.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1284,10 +1284,8 @@ private static void checkValidPath(CanonicalTreeParser t)
|
||||||
* @throws InvalidPathException
|
* @throws InvalidPathException
|
||||||
* if the path is invalid
|
* if the path is invalid
|
||||||
* @since 3.3
|
* @since 3.3
|
||||||
* @deprecated Use {@link SystemReader#checkPath(String)}.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
static void checkValidPath(String path) throws InvalidPathException {
|
||||||
public static void checkValidPath(String path) throws InvalidPathException {
|
|
||||||
try {
|
try {
|
||||||
SystemReader.getInstance().checkPath(path);
|
SystemReader.getInstance().checkPath(path);
|
||||||
} catch (CorruptObjectException e) {
|
} catch (CorruptObjectException e) {
|
||||||
|
|
|
@ -103,6 +103,7 @@ public static JGitText get() {
|
||||||
/***/ public String cannotBeRecursiveWhenTreesAreIncluded;
|
/***/ public String cannotBeRecursiveWhenTreesAreIncluded;
|
||||||
/***/ public String cannotChangeActionOnComment;
|
/***/ public String cannotChangeActionOnComment;
|
||||||
/***/ public String cannotChangeToComment;
|
/***/ public String cannotChangeToComment;
|
||||||
|
/***/ public String cannotCheckoutOursSwitchBranch;
|
||||||
/***/ public String cannotCombineSquashWithNoff;
|
/***/ public String cannotCombineSquashWithNoff;
|
||||||
/***/ public String cannotCombineTreeFilterWithRevFilter;
|
/***/ public String cannotCombineTreeFilterWithRevFilter;
|
||||||
/***/ public String cannotCommitOnARepoWithState;
|
/***/ public String cannotCommitOnARepoWithState;
|
||||||
|
@ -290,6 +291,7 @@ public static JGitText get() {
|
||||||
/***/ public String fileIsTooBigForThisConvenienceMethod;
|
/***/ public String fileIsTooBigForThisConvenienceMethod;
|
||||||
/***/ public String fileIsTooLarge;
|
/***/ public String fileIsTooLarge;
|
||||||
/***/ public String fileModeNotSetForPath;
|
/***/ public String fileModeNotSetForPath;
|
||||||
|
/***/ public String findingGarbage;
|
||||||
/***/ public String flagIsDisposed;
|
/***/ public String flagIsDisposed;
|
||||||
/***/ public String flagNotFromThis;
|
/***/ public String flagNotFromThis;
|
||||||
/***/ public String flagsAlreadyCreated;
|
/***/ public String flagsAlreadyCreated;
|
||||||
|
@ -317,6 +319,7 @@ public static JGitText get() {
|
||||||
/***/ public String initFailedBareRepoDifferentDirs;
|
/***/ public String initFailedBareRepoDifferentDirs;
|
||||||
/***/ public String initFailedNonBareRepoSameDirs;
|
/***/ public String initFailedNonBareRepoSameDirs;
|
||||||
/***/ public String inMemoryBufferLimitExceeded;
|
/***/ public String inMemoryBufferLimitExceeded;
|
||||||
|
/***/ public String inputDidntMatchLength;
|
||||||
/***/ public String inputStreamMustSupportMark;
|
/***/ public String inputStreamMustSupportMark;
|
||||||
/***/ public String integerValueOutOfRange;
|
/***/ public String integerValueOutOfRange;
|
||||||
/***/ public String internalRevisionError;
|
/***/ public String internalRevisionError;
|
||||||
|
@ -450,6 +453,7 @@ public static JGitText get() {
|
||||||
/***/ public String packFileInvalid;
|
/***/ public String packFileInvalid;
|
||||||
/***/ public String packfileIsTruncated;
|
/***/ public String packfileIsTruncated;
|
||||||
/***/ public String packfileIsTruncatedNoParam;
|
/***/ public String packfileIsTruncatedNoParam;
|
||||||
|
/***/ public String packHandleIsStale;
|
||||||
/***/ public String packHasUnresolvedDeltas;
|
/***/ public String packHasUnresolvedDeltas;
|
||||||
/***/ public String packingCancelledDuringObjectsWriting;
|
/***/ public String packingCancelledDuringObjectsWriting;
|
||||||
/***/ public String packObjectCountMismatch;
|
/***/ public String packObjectCountMismatch;
|
||||||
|
@ -561,6 +565,7 @@ public static JGitText get() {
|
||||||
/***/ public String submoduleExists;
|
/***/ public String submoduleExists;
|
||||||
/***/ public String submodulesNotSupported;
|
/***/ public String submodulesNotSupported;
|
||||||
/***/ public String submoduleParentRemoteUrlInvalid;
|
/***/ public String submoduleParentRemoteUrlInvalid;
|
||||||
|
/***/ public String supportOnlyPackIndexVersion2;
|
||||||
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
|
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
|
||||||
/***/ public String systemConfigFileInvalid;
|
/***/ public String systemConfigFileInvalid;
|
||||||
/***/ public String tagAlreadyExists;
|
/***/ public String tagAlreadyExists;
|
||||||
|
@ -595,6 +600,7 @@ public static JGitText get() {
|
||||||
/***/ public String truncatedHunkOldLinesMissing;
|
/***/ public String truncatedHunkOldLinesMissing;
|
||||||
/***/ public String tSizeMustBeGreaterOrEqual1;
|
/***/ public String tSizeMustBeGreaterOrEqual1;
|
||||||
/***/ public String unableToCheckConnectivity;
|
/***/ public String unableToCheckConnectivity;
|
||||||
|
/***/ public String unableToCreateNewObject;
|
||||||
/***/ public String unableToStore;
|
/***/ public String unableToStore;
|
||||||
/***/ public String unableToWrite;
|
/***/ public String unableToWrite;
|
||||||
/***/ public String unencodeableFile;
|
/***/ public String unencodeableFile;
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
package org.eclipse.jgit.internal.storage.dfs;
|
package org.eclipse.jgit.internal.storage.dfs;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
@ -101,12 +100,9 @@ void crc32(CRC32 out, long pos, int cnt) {
|
||||||
out.update(block, ptr, 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 {
|
throws IOException {
|
||||||
int ptr = (int) (pos - start);
|
out.write(block, (int) (pos - start), cnt);
|
||||||
out.write(block, ptr, cnt);
|
|
||||||
if (digest != null)
|
|
||||||
digest.update(block, ptr, cnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(Inflater inf, byte[] tmp, long pos, int 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. */
|
/** Maximum number of bytes the cache should hold. */
|
||||||
private final long maxBytes;
|
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.
|
* Suggested block size to read from pack files in.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -191,6 +194,7 @@ else if (eb < 4)
|
||||||
eb = tableSize;
|
eb = tableSize;
|
||||||
|
|
||||||
maxBytes = cfg.getBlockLimit();
|
maxBytes = cfg.getBlockLimit();
|
||||||
|
maxStreamThroughCache = (long) (maxBytes * cfg.getStreamRatio());
|
||||||
blockSize = cfg.getBlockSize();
|
blockSize = cfg.getBlockSize();
|
||||||
blockSizeShift = Integer.numberOfTrailingZeros(blockSize);
|
blockSizeShift = Integer.numberOfTrailingZeros(blockSize);
|
||||||
|
|
||||||
|
@ -206,6 +210,10 @@ else if (eb < 4)
|
||||||
statMiss = new AtomicLong();
|
statMiss = new AtomicLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean shouldCopyThroughCache(long length) {
|
||||||
|
return length <= maxStreamThroughCache;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return total number of bytes in the cache. */
|
/** @return total number of bytes in the cache. */
|
||||||
public long getCurrentSize() {
|
public long getCurrentSize() {
|
||||||
return liveBytes;
|
return liveBytes;
|
||||||
|
|
|
@ -47,7 +47,11 @@
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION;
|
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_LIMIT;
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE;
|
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;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
|
||||||
/** Configuration parameters for {@link DfsBlockCache}. */
|
/** Configuration parameters for {@link DfsBlockCache}. */
|
||||||
|
@ -59,13 +63,14 @@ public class DfsBlockCacheConfig {
|
||||||
public static final int MB = 1024 * KB;
|
public static final int MB = 1024 * KB;
|
||||||
|
|
||||||
private long blockLimit;
|
private long blockLimit;
|
||||||
|
|
||||||
private int blockSize;
|
private int blockSize;
|
||||||
|
private double streamRatio;
|
||||||
|
|
||||||
/** Create a default configuration. */
|
/** Create a default configuration. */
|
||||||
public DfsBlockCacheConfig() {
|
public DfsBlockCacheConfig() {
|
||||||
setBlockLimit(32 * MB);
|
setBlockLimit(32 * MB);
|
||||||
setBlockSize(64 * KB);
|
setBlockSize(64 * KB);
|
||||||
|
setStreamRatio(0.30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,6 +110,27 @@ public DfsBlockCacheConfig setBlockSize(final int newSize) {
|
||||||
return this;
|
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.
|
* Update properties by setting fields from the configuration.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -127,6 +153,22 @@ public DfsBlockCacheConfig fromConfig(final Config rc) {
|
||||||
CONFIG_DFS_SECTION,
|
CONFIG_DFS_SECTION,
|
||||||
CONFIG_KEY_BLOCK_SIZE,
|
CONFIG_KEY_BLOCK_SIZE,
|
||||||
getBlockSize()));
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,8 +78,7 @@ public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
|
||||||
return ((DfsObjectRepresentation) rep).pack == pack;
|
return ((DfsObjectRepresentation) rep).pack == pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyAsIs(PackOutputStream out, boolean validate, DfsReader ctx)
|
void copyAsIs(PackOutputStream out, DfsReader ctx) throws IOException {
|
||||||
throws IOException {
|
pack.copyPackAsIs(out, ctx);
|
||||||
pack.copyPackAsIs(out, validate, ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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.dfs.DfsObjDatabase.PackSource;
|
||||||
import org.eclipse.jgit.internal.storage.file.PackIndex;
|
import org.eclipse.jgit.internal.storage.file.PackIndex;
|
||||||
import org.eclipse.jgit.internal.storage.pack.PackExt;
|
import org.eclipse.jgit.internal.storage.pack.PackExt;
|
||||||
|
@ -188,7 +189,8 @@ public boolean pack(ProgressMonitor pm) throws IOException {
|
||||||
if (pm == null)
|
if (pm == null)
|
||||||
pm = NullProgressMonitor.INSTANCE;
|
pm = NullProgressMonitor.INSTANCE;
|
||||||
if (packConfig.getIndexVersion() != 2)
|
if (packConfig.getIndexVersion() != 2)
|
||||||
throw new IllegalStateException("Only index version 2");
|
throw new IllegalStateException(
|
||||||
|
JGitText.get().supportOnlyPackIndexVersion2);
|
||||||
|
|
||||||
ctx = (DfsReader) objdb.newReader();
|
ctx = (DfsReader) objdb.newReader();
|
||||||
try {
|
try {
|
||||||
|
@ -272,14 +274,11 @@ private void packHeads(ProgressMonitor pm) throws IOException {
|
||||||
if (allHeads.isEmpty())
|
if (allHeads.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PackWriter pw = newPackWriter();
|
try (PackWriter pw = newPackWriter()) {
|
||||||
try {
|
|
||||||
pw.setTagTargets(tagTargets);
|
pw.setTagTargets(tagTargets);
|
||||||
pw.preparePack(pm, allHeads, Collections.<ObjectId> emptySet());
|
pw.preparePack(pm, allHeads, Collections.<ObjectId> emptySet());
|
||||||
if (0 < pw.getObjectCount())
|
if (0 < pw.getObjectCount())
|
||||||
writePack(GC, pw, pm);
|
writePack(GC, pw, pm);
|
||||||
} finally {
|
|
||||||
pw.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,15 +286,12 @@ private void packRest(ProgressMonitor pm) throws IOException {
|
||||||
if (nonHeads.isEmpty())
|
if (nonHeads.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PackWriter pw = newPackWriter();
|
try (PackWriter pw = newPackWriter()) {
|
||||||
try {
|
|
||||||
for (PackWriter.ObjectIdSet packedObjs : newPackObj)
|
for (PackWriter.ObjectIdSet packedObjs : newPackObj)
|
||||||
pw.excludeObjects(packedObjs);
|
pw.excludeObjects(packedObjs);
|
||||||
pw.preparePack(pm, nonHeads, allHeads);
|
pw.preparePack(pm, nonHeads, allHeads);
|
||||||
if (0 < pw.getObjectCount())
|
if (0 < pw.getObjectCount())
|
||||||
writePack(GC, pw, pm);
|
writePack(GC, pw, pm);
|
||||||
} finally {
|
|
||||||
pw.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,12 +303,11 @@ private void packGarbage(ProgressMonitor pm) throws IOException {
|
||||||
cfg.setDeltaCompress(false);
|
cfg.setDeltaCompress(false);
|
||||||
cfg.setBuildBitmaps(false);
|
cfg.setBuildBitmaps(false);
|
||||||
|
|
||||||
PackWriter pw = new PackWriter(cfg, ctx);
|
try (PackWriter pw = new PackWriter(cfg, ctx);
|
||||||
pw.setDeltaBaseAsOffset(true);
|
RevWalk pool = new RevWalk(ctx)) {
|
||||||
pw.setReuseDeltaCommits(true);
|
pw.setDeltaBaseAsOffset(true);
|
||||||
try {
|
pw.setReuseDeltaCommits(true);
|
||||||
RevWalk pool = new RevWalk(ctx);
|
pm.beginTask(JGitText.get().findingGarbage, objectsBefore());
|
||||||
pm.beginTask("Finding garbage", objectsBefore());
|
|
||||||
for (DfsPackFile oldPack : packsBefore) {
|
for (DfsPackFile oldPack : packsBefore) {
|
||||||
PackIndex oldIdx = oldPack.getPackIndex(ctx);
|
PackIndex oldIdx = oldPack.getPackIndex(ctx);
|
||||||
for (PackIndex.MutableEntry ent : oldIdx) {
|
for (PackIndex.MutableEntry ent : oldIdx) {
|
||||||
|
@ -328,8 +323,6 @@ private void packGarbage(ProgressMonitor pm) throws IOException {
|
||||||
pm.endTask();
|
pm.endTask();
|
||||||
if (0 < pw.getObjectCount())
|
if (0 < pw.getObjectCount())
|
||||||
writePack(UNREACHABLE_GARBAGE, pw, pm);
|
writePack(UNREACHABLE_GARBAGE, pw, pm);
|
||||||
} finally {
|
|
||||||
pw.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -80,7 +81,6 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectLoader;
|
import org.eclipse.jgit.lib.ObjectLoader;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.util.IO;
|
|
||||||
import org.eclipse.jgit.util.LongList;
|
import org.eclipse.jgit.util.LongList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -464,11 +464,73 @@ private byte[] decompress(long position, int sz, DfsReader ctx)
|
||||||
return dstbuf;
|
return dstbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyPackAsIs(PackOutputStream out, boolean validate, DfsReader ctx)
|
void copyPackAsIs(PackOutputStream out, DfsReader ctx)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Pin the first window, this ensures the length is accurate.
|
// If the length hasn't been determined yet, pin to set it.
|
||||||
ctx.pin(this, 0);
|
if (length == -1) {
|
||||||
ctx.copyPackAsIs(this, length, validate, out);
|
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,
|
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.
|
// and we have it pinned. Write this out without copying.
|
||||||
//
|
//
|
||||||
out.writeHeader(src, inflatedLength);
|
out.writeHeader(src, inflatedLength);
|
||||||
quickCopy.write(out, dataOffset, (int) dataLength, null);
|
quickCopy.write(out, dataOffset, (int) dataLength);
|
||||||
|
|
||||||
} else if (dataLength <= buf.length) {
|
} else if (dataLength <= buf.length) {
|
||||||
// Tiny optimization: Lots of objects are very small deltas or
|
// Tiny optimization: Lots of objects are very small deltas or
|
||||||
|
@ -668,6 +730,12 @@ void setInvalid() {
|
||||||
invalid = true;
|
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,
|
private void readFully(long position, byte[] dstbuf, int dstoff, int cnt,
|
||||||
DfsReader ctx) throws IOException {
|
DfsReader ctx) throws IOException {
|
||||||
if (ctx.copy(this, position, dstbuf, dstoff, cnt) != cnt)
|
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);
|
ReadableChannel rc = ctx.db.openFile(packDesc, PACK);
|
||||||
try {
|
try {
|
||||||
// If the block alignment is not yet known, discover it. Prefer the
|
int size = blockSize(rc);
|
||||||
// larger size from either the cache or the file itself.
|
pos = (pos / size) * size;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the size of the file is not yet known, try to discover it.
|
// 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
|
// 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];
|
byte[] buf = new byte[size];
|
||||||
rc.position(pos);
|
rc.position(pos);
|
||||||
int cnt = IO.read(rc, buf, 0, size);
|
int cnt = read(rc, ByteBuffer.wrap(buf, 0, size));
|
||||||
if (cnt != size) {
|
if (cnt != size) {
|
||||||
if (0 <= len) {
|
if (0 <= len) {
|
||||||
throw new EOFException(MessageFormat.format(
|
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)
|
ObjectLoader load(DfsReader ctx, long pos)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -44,14 +44,10 @@
|
||||||
|
|
||||||
package org.eclipse.jgit.internal.storage.dfs;
|
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 static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -65,7 +61,6 @@
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
import org.eclipse.jgit.errors.MissingObjectException;
|
||||||
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
|
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.BitmapIndexImpl;
|
||||||
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
|
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
|
||||||
import org.eclipse.jgit.internal.storage.file.PackIndex;
|
import org.eclipse.jgit.internal.storage.file.PackIndex;
|
||||||
|
@ -81,7 +76,6 @@
|
||||||
import org.eclipse.jgit.lib.AsyncObjectSizeQueue;
|
import org.eclipse.jgit.lib.AsyncObjectSizeQueue;
|
||||||
import org.eclipse.jgit.lib.BitmapIndex;
|
import org.eclipse.jgit.lib.BitmapIndex;
|
||||||
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
|
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
|
||||||
import org.eclipse.jgit.lib.InflaterCache;
|
import org.eclipse.jgit.lib.InflaterCache;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectLoader;
|
import org.eclipse.jgit.lib.ObjectLoader;
|
||||||
|
@ -498,9 +492,9 @@ public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
|
||||||
out.writeObject(otp);
|
out.writeObject(otp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyPackAsIs(PackOutputStream out, CachedPack pack,
|
public void copyPackAsIs(PackOutputStream out, CachedPack pack)
|
||||||
boolean validate) throws IOException {
|
throws IOException {
|
||||||
((DfsCachedPack) pack).copyAsIs(out, validate, this);
|
((DfsCachedPack) pack).copyAsIs(out, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,52 +541,6 @@ int copy(DfsPackFile pack, long position, byte[] dstbuf, int dstoff, int cnt)
|
||||||
return cnt - need;
|
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}.
|
* 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. */
|
/** Release the current window cursor. */
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
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_CORE_SECTION;
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_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_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 static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_FILE_TRESHOLD;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
@ -60,9 +61,10 @@ public class DfsReaderOptions {
|
||||||
public static final int MiB = 1024 * KiB;
|
public static final int MiB = 1024 * KiB;
|
||||||
|
|
||||||
private int deltaBaseCacheLimit;
|
private int deltaBaseCacheLimit;
|
||||||
|
|
||||||
private int streamFileThreshold;
|
private int streamFileThreshold;
|
||||||
|
|
||||||
|
private int streamPackBufferSize;
|
||||||
|
|
||||||
/** Create a default reader configuration. */
|
/** Create a default reader configuration. */
|
||||||
public DfsReaderOptions() {
|
public DfsReaderOptions() {
|
||||||
setDeltaBaseCacheLimit(10 * MiB);
|
setDeltaBaseCacheLimit(10 * MiB);
|
||||||
|
@ -104,6 +106,27 @@ public DfsReaderOptions setStreamFileThreshold(final int newLimit) {
|
||||||
return this;
|
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.
|
* Update properties by setting fields from the configuration.
|
||||||
* <p>
|
* <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, maxMem / 4); // don't use more than 1/4 of the heap
|
||||||
sft = Math.min(sft, Integer.MAX_VALUE); // cannot exceed array length
|
sft = Math.min(sft, Integer.MAX_VALUE); // cannot exceed array length
|
||||||
setStreamFileThreshold((int) sft);
|
setStreamFileThreshold((int) sft);
|
||||||
|
|
||||||
|
setStreamPackBufferSize(rc.getInt(
|
||||||
|
CONFIG_CORE_SECTION,
|
||||||
|
CONFIG_DFS_SECTION,
|
||||||
|
CONFIG_KEY_STREAM_BUFFER,
|
||||||
|
getStreamPackBufferSize()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,6 +227,10 @@ public long size() {
|
||||||
public int blockSize() {
|
public int blockSize() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setReadAheadBytes(int b) {
|
||||||
|
// Unnecessary on a byte array.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MemRefDatabase extends DfsRefDatabase {
|
private class MemRefDatabase extends DfsRefDatabase {
|
||||||
|
|
|
@ -100,4 +100,33 @@ public interface ReadableChannel extends ReadableByteChannel {
|
||||||
* not need to be a power of 2.
|
* not need to be a power of 2.
|
||||||
*/
|
*/
|
||||||
public int blockSize();
|
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;
|
package org.eclipse.jgit.internal.storage.file;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
@ -84,12 +83,10 @@ void crc32(CRC32 out, long pos, int cnt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
|
void write(PackOutputStream out, long pos, int cnt)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int ptr = (int) (pos - start);
|
int ptr = (int) (pos - start);
|
||||||
out.write(array, ptr, cnt);
|
out.write(array, ptr, cnt);
|
||||||
if (digest != null)
|
|
||||||
digest.update(array, ptr, cnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(Inflater inf, byte[] tmp, long pos, int cnt)
|
void check(Inflater inf, byte[] tmp, long pos, int cnt)
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
|
@ -76,7 +75,7 @@ protected int copy(final int p, final byte[] b, final int o, int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void write(PackOutputStream out, long pos, int cnt, MessageDigest digest)
|
void write(PackOutputStream out, long pos, int cnt)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final ByteBuffer s = buffer.slice();
|
final ByteBuffer s = buffer.slice();
|
||||||
s.position((int) (pos - start));
|
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);
|
int n = Math.min(cnt, buf.length);
|
||||||
s.get(buf, 0, n);
|
s.get(buf, 0, n);
|
||||||
out.write(buf, 0, n);
|
out.write(buf, 0, n);
|
||||||
if (digest != null)
|
|
||||||
digest.update(buf, 0, n);
|
|
||||||
cnt -= n;
|
cnt -= n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
package org.eclipse.jgit.internal.storage.file;
|
package org.eclipse.jgit.internal.storage.file;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Inflater;
|
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);
|
protected abstract int copy(int pos, byte[] dstbuf, int dstoff, int cnt);
|
||||||
|
|
||||||
abstract void write(PackOutputStream out, long pos, int cnt,
|
abstract void write(PackOutputStream out, long pos, int cnt)
|
||||||
MessageDigest md) throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
final int setInput(long pos, Inflater inf) throws DataFormatException {
|
final int setInput(long pos, Inflater inf) throws DataFormatException {
|
||||||
return setInput((int) (pos - start), inf);
|
return setInput((int) (pos - start), inf);
|
||||||
|
|
|
@ -618,22 +618,19 @@ private Map<String, Ref> getAllRefs() throws IOException {
|
||||||
*/
|
*/
|
||||||
private Set<ObjectId> listNonHEADIndexObjects()
|
private Set<ObjectId> listNonHEADIndexObjects()
|
||||||
throws CorruptObjectException, IOException {
|
throws CorruptObjectException, IOException {
|
||||||
RevWalk revWalk = null;
|
|
||||||
try {
|
try {
|
||||||
if (repo.getIndexFile() == null)
|
if (repo.getIndexFile() == null)
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
} catch (NoWorkTreeException e) {
|
} catch (NoWorkTreeException e) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
TreeWalk treeWalk = new TreeWalk(repo);
|
try (TreeWalk treeWalk = new TreeWalk(repo)) {
|
||||||
try {
|
|
||||||
treeWalk.addTree(new DirCacheIterator(repo.readDirCache()));
|
treeWalk.addTree(new DirCacheIterator(repo.readDirCache()));
|
||||||
ObjectId headID = repo.resolve(Constants.HEAD);
|
ObjectId headID = repo.resolve(Constants.HEAD);
|
||||||
if (headID != null) {
|
if (headID != null) {
|
||||||
revWalk = new RevWalk(repo);
|
try (RevWalk revWalk = new RevWalk(repo)) {
|
||||||
treeWalk.addTree(revWalk.parseTree(headID));
|
treeWalk.addTree(revWalk.parseTree(headID));
|
||||||
revWalk.dispose();
|
}
|
||||||
revWalk = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
treeWalk.setFilter(TreeFilter.ANY_DIFF);
|
treeWalk.setFilter(TreeFilter.ANY_DIFF);
|
||||||
|
@ -662,10 +659,6 @@ private Set<ObjectId> listNonHEADIndexObjects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
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 (PackWriter pw = new PackWriter(
|
||||||
try {
|
(pconfig == null) ? new PackConfig(repo) : pconfig,
|
||||||
|
repo.newObjectReader())) {
|
||||||
// prepare the PackWriter
|
// prepare the PackWriter
|
||||||
pw.setDeltaBaseAsOffset(true);
|
pw.setDeltaBaseAsOffset(true);
|
||||||
pw.setReuseDeltaCommits(false);
|
pw.setReuseDeltaCommits(false);
|
||||||
|
@ -810,7 +804,6 @@ public int compare(PackExt o1, PackExt o2) {
|
||||||
}
|
}
|
||||||
return repo.getObjectDatabase().openPack(realPack);
|
return repo.getObjectDatabase().openPack(realPack);
|
||||||
} finally {
|
} finally {
|
||||||
pw.release();
|
|
||||||
if (tmpPack != null && tmpPack.exists())
|
if (tmpPack != null && tmpPack.exists())
|
||||||
tmpPack.delete();
|
tmpPack.delete();
|
||||||
for (File tmpExt : tmpExts.values()) {
|
for (File tmpExt : tmpExts.values()) {
|
||||||
|
|
|
@ -79,10 +79,10 @@ public long getObjectCount() throws IOException {
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyAsIs(PackOutputStream out, boolean validate, WindowCursor wc)
|
void copyAsIs(PackOutputStream out, WindowCursor wc)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
for (PackFile pack : getPacks())
|
for (PackFile pack : getPacks())
|
||||||
pack.copyPackAsIs(out, validate, wc);
|
pack.copyPackAsIs(out, wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -114,6 +114,8 @@ public class ObjectDirectory extends FileObjectDatabase {
|
||||||
/** Maximum number of candidates offered as resolutions of abbreviation. */
|
/** Maximum number of candidates offered as resolutions of abbreviation. */
|
||||||
private static final int RESOLVE_ABBREV_LIMIT = 256;
|
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 Config config;
|
||||||
|
|
||||||
private final File objects;
|
private final File objects;
|
||||||
|
@ -554,22 +556,35 @@ void selectObjectRepresentation(PackWriter packer, ObjectToPack otp,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePackError(IOException e, PackFile p) {
|
private void handlePackError(IOException e, PackFile p) {
|
||||||
String tmpl;
|
String warnTmpl = null;
|
||||||
if ((e instanceof CorruptObjectException)
|
if ((e instanceof CorruptObjectException)
|
||||||
|| (e instanceof PackInvalidException)) {
|
|| (e instanceof PackInvalidException)) {
|
||||||
tmpl = JGitText.get().corruptPack;
|
warnTmpl = JGitText.get().corruptPack;
|
||||||
// Assume the pack is corrupted, and remove it from the list.
|
// Assume the pack is corrupted, and remove it from the list.
|
||||||
removePack(p);
|
removePack(p);
|
||||||
} else if (e instanceof FileNotFoundException) {
|
} else if (e instanceof FileNotFoundException) {
|
||||||
tmpl = JGitText.get().packWasDeleted;
|
warnTmpl = JGitText.get().packWasDeleted;
|
||||||
removePack(p);
|
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 {
|
} else {
|
||||||
tmpl = JGitText.get().exceptionWhileReadingPack;
|
|
||||||
// Don't remove the pack from the list, as the error may be
|
// Don't remove the pack from the list, as the error may be
|
||||||
// transient.
|
// transient.
|
||||||
|
LOG.error(MessageFormat.format(
|
||||||
|
JGitText.get().exceptionWhileReadingPack, p.getPackFile()
|
||||||
|
.getAbsolutePath()), e);
|
||||||
}
|
}
|
||||||
LOG.error(MessageFormat.format(tmpl,
|
|
||||||
p.getPackFile().getAbsolutePath()), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -55,10 +55,12 @@
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.security.DigestOutputStream;
|
import java.security.DigestOutputStream;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.text.MessageFormat;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.ObjectWritingException;
|
import org.eclipse.jgit.errors.ObjectWritingException;
|
||||||
|
import org.eclipse.jgit.internal.JGitText;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
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);
|
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
|
@Override
|
||||||
|
@ -242,7 +245,7 @@ DeflaterOutputStream compress(final OutputStream out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EOFException shortInput(long missing) {
|
private static EOFException shortInput(long missing) {
|
||||||
return new EOFException("Input did not match supplied length. "
|
return new EOFException(MessageFormat.format(
|
||||||
+ missing + " bytes are missing.");
|
JGitText.get().inputDidntMatchLength, Long.valueOf(missing)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,11 +344,11 @@ private final byte[] decompress(final long position, final int sz,
|
||||||
return dstbuf;
|
return dstbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyPackAsIs(PackOutputStream out, boolean validate, WindowCursor curs)
|
void copyPackAsIs(PackOutputStream out, WindowCursor curs)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Pin the first window, this ensures the length is accurate.
|
// Pin the first window, this ensures the length is accurate.
|
||||||
curs.pin(this, 0);
|
curs.pin(this, 0);
|
||||||
curs.copyPackAsIs(this, length, validate, out);
|
curs.copyPackAsIs(this, length, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
final void copyAsIs(PackOutputStream out, LocalObjectToPack src,
|
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,
|
private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
|
||||||
boolean validate, WindowCursor curs) throws IOException,
|
boolean validate, WindowCursor curs) throws IOException,
|
||||||
StoredObjectRepresentationNotAvailableException {
|
StoredObjectRepresentationNotAvailableException {
|
||||||
|
@ -501,7 +502,7 @@ private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
|
||||||
// and we have it pinned. Write this out without copying.
|
// and we have it pinned. Write this out without copying.
|
||||||
//
|
//
|
||||||
out.writeHeader(src, inflatedLength);
|
out.writeHeader(src, inflatedLength);
|
||||||
quickCopy.write(out, dataOffset, (int) dataLength, null);
|
quickCopy.write(out, dataOffset, (int) dataLength);
|
||||||
|
|
||||||
} else if (dataLength <= buf.length) {
|
} else if (dataLength <= buf.length) {
|
||||||
// Tiny optimization: Lots of objects are very small deltas or
|
// Tiny optimization: Lots of objects are very small deltas or
|
||||||
|
@ -703,6 +704,7 @@ private void onOpenPack() throws IOException {
|
||||||
, getPackFile()));
|
, getPackFile()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
ObjectLoader load(final WindowCursor curs, long pos)
|
ObjectLoader load(final WindowCursor curs, long pos)
|
||||||
throws IOException, LargeObjectException {
|
throws IOException, LargeObjectException {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -232,7 +232,7 @@ public long findCRC32(AnyObjectId objId) throws MissingObjectException {
|
||||||
final int levelOne = objId.getFirstByte();
|
final int levelOne = objId.getFirstByte();
|
||||||
final int levelTwo = binarySearchLevelTwo(objId, levelOne);
|
final int levelTwo = binarySearchLevelTwo(objId, levelOne);
|
||||||
if (levelTwo == -1)
|
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);
|
return NB.decodeUInt32(crc32[levelOne], levelTwo << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,6 @@
|
||||||
package org.eclipse.jgit.internal.storage.file;
|
package org.eclipse.jgit.internal.storage.file;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -59,7 +56,6 @@
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
import org.eclipse.jgit.errors.MissingObjectException;
|
||||||
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
|
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.CachedPack;
|
||||||
import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
|
import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
|
||||||
import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
|
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;
|
return cnt - need;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyPackAsIs(PackOutputStream out, CachedPack pack,
|
public void copyPackAsIs(PackOutputStream out, CachedPack pack)
|
||||||
boolean validate) throws IOException {
|
throws IOException {
|
||||||
((LocalCachedPack) pack).copyAsIs(out, validate, this);
|
((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 {
|
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 position = 12;
|
||||||
long remaining = length - (12 + 20);
|
long remaining = length - (12 + 20);
|
||||||
while (0 < remaining) {
|
while (0 < remaining) {
|
||||||
|
@ -260,29 +242,10 @@ void copyPackAsIs(final PackFile pack, final long length, boolean validate,
|
||||||
|
|
||||||
int ptr = (int) (position - window.start);
|
int ptr = (int) (position - window.start);
|
||||||
int n = (int) Math.min(window.size() - ptr, remaining);
|
int n = (int) Math.min(window.size() - ptr, remaining);
|
||||||
window.write(out, position, n, md);
|
window.write(out, position, n);
|
||||||
position += n;
|
position += n;
|
||||||
remaining -= 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.
|
* stream to append the pack onto.
|
||||||
* @param pack
|
* @param pack
|
||||||
* the cached pack to send.
|
* 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
|
* @throws IOException
|
||||||
* the pack cannot be read, or stream did not accept a write.
|
* the pack cannot be read, or stream did not accept a write.
|
||||||
*/
|
*/
|
||||||
public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack,
|
public abstract void copyPackAsIs(PackOutputStream out, CachedPack pack)
|
||||||
boolean validate) throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the available cached packs that match the bitmap and update
|
* 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.reusedObjects += pack.getObjectCount();
|
||||||
stats.reusedDeltas += deltaCnt;
|
stats.reusedDeltas += deltaCnt;
|
||||||
stats.totalDeltas += deltaCnt;
|
stats.totalDeltas += deltaCnt;
|
||||||
reuseSupport.copyPackAsIs(out, pack, reuseValidate);
|
reuseSupport.copyPackAsIs(out, pack);
|
||||||
}
|
}
|
||||||
writeChecksum(out);
|
writeChecksum(out);
|
||||||
out.flush();
|
out.flush();
|
||||||
|
@ -1866,7 +1866,7 @@ private void findObjectsToPackUsingBitmaps(
|
||||||
false);
|
false);
|
||||||
BitmapBuilder needBitmap = wantBitmap.andNot(haveBitmap);
|
BitmapBuilder needBitmap = wantBitmap.andNot(haveBitmap);
|
||||||
|
|
||||||
if (useCachedPacks && reuseSupport != null
|
if (useCachedPacks && reuseSupport != null && !reuseValidate
|
||||||
&& (excludeInPacks == null || excludeInPacks.length == 0))
|
&& (excludeInPacks == null || excludeInPacks.length == 0))
|
||||||
cachedPacks.addAll(
|
cachedPacks.addAll(
|
||||||
reuseSupport.getCachedPacksAndUpdate(needBitmap));
|
reuseSupport.getCachedPacksAndUpdate(needBitmap));
|
||||||
|
|
|
@ -104,11 +104,8 @@ public BlobBasedConfig(Config base, Repository db, AnyObjectId objectId)
|
||||||
private static byte[] read(Repository db, AnyObjectId blobId)
|
private static byte[] read(Repository db, AnyObjectId blobId)
|
||||||
throws MissingObjectException, IncorrectObjectTypeException,
|
throws MissingObjectException, IncorrectObjectTypeException,
|
||||||
IOException {
|
IOException {
|
||||||
ObjectReader or = db.newObjectReader();
|
try (ObjectReader or = db.newObjectReader()) {
|
||||||
try {
|
|
||||||
return read(or, blobId);
|
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)
|
private static byte[] read(Repository db, AnyObjectId treeish, String path)
|
||||||
throws MissingObjectException, IncorrectObjectTypeException,
|
throws MissingObjectException, IncorrectObjectTypeException,
|
||||||
IOException {
|
IOException {
|
||||||
ObjectReader or = db.newObjectReader();
|
try (ObjectReader or = db.newObjectReader()) {
|
||||||
try {
|
|
||||||
TreeWalk tree = TreeWalk.forPath(or, path, asTree(or, treeish));
|
TreeWalk tree = TreeWalk.forPath(or, path, asTree(or, treeish));
|
||||||
if (tree == null)
|
if (tree == null)
|
||||||
throw new FileNotFoundException(MessageFormat.format(JGitText
|
throw new FileNotFoundException(MessageFormat.format(JGitText
|
||||||
.get().entryNotFoundByPath, path));
|
.get().entryNotFoundByPath, path));
|
||||||
return read(or, tree.getObjectId(0));
|
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)
|
&& ((RevCommit) treeish).getTree() != null)
|
||||||
return ((RevCommit) treeish).getTree();
|
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
|
* @since 3.3
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_KEY_PRUNE = "prune";
|
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 final MutableInteger ptrout = new MutableInteger();
|
||||||
|
|
||||||
private boolean allowZeroMode;
|
private boolean allowZeroMode;
|
||||||
|
|
||||||
|
private boolean allowInvalidPersonIdent;
|
||||||
private boolean windows;
|
private boolean windows;
|
||||||
private boolean macosx;
|
private boolean macosx;
|
||||||
|
|
||||||
|
@ -124,6 +126,22 @@ public ObjectChecker setAllowLeadingZeroFileMode(boolean allow) {
|
||||||
return this;
|
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.
|
* Restrict trees to only names legal on Windows platforms.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -198,6 +216,9 @@ private int id(final byte[] raw, final int ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int personIdent(final byte[] raw, int ptr) {
|
private int personIdent(final byte[] raw, int ptr) {
|
||||||
|
if (allowInvalidPersonIdent)
|
||||||
|
return nextLF(raw, ptr) - 1;
|
||||||
|
|
||||||
final int emailB = nextLF(raw, ptr, '<');
|
final int emailB = nextLF(raw, ptr, '<');
|
||||||
if (emailB == ptr || raw[emailB - 1] != '<')
|
if (emailB == ptr || raw[emailB - 1] != '<')
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -120,11 +120,8 @@ public void create() throws IOException {
|
||||||
* the object store cannot be accessed.
|
* the object store cannot be accessed.
|
||||||
*/
|
*/
|
||||||
public boolean has(final AnyObjectId objectId) throws IOException {
|
public boolean has(final AnyObjectId objectId) throws IOException {
|
||||||
final ObjectReader or = newReader();
|
try (final ObjectReader or = newReader()) {
|
||||||
try {
|
|
||||||
return or.has(objectId);
|
return or.has(objectId);
|
||||||
} finally {
|
|
||||||
or.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +169,8 @@ public ObjectLoader open(final AnyObjectId objectId)
|
||||||
public ObjectLoader open(AnyObjectId objectId, int typeHint)
|
public ObjectLoader open(AnyObjectId objectId, int typeHint)
|
||||||
throws MissingObjectException, IncorrectObjectTypeException,
|
throws MissingObjectException, IncorrectObjectTypeException,
|
||||||
IOException {
|
IOException {
|
||||||
final ObjectReader or = newReader();
|
try (final ObjectReader or = newReader()) {
|
||||||
try {
|
|
||||||
return or.open(objectId, typeHint);
|
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 java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jgit.diff.RawText;
|
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
|
* 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,
|
public void formatMerge(OutputStream out, MergeResult<RawText> res,
|
||||||
List<String> seqName, String charsetName) throws IOException {
|
List<String> seqName, String charsetName) throws IOException {
|
||||||
String lastConflictingName = null; // is set to non-null whenever we are
|
new MergeFormatterPass(out, res, seqName, charsetName).formatMerge();
|
||||||
// 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$
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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()}.
|
* repository instance returned by {@link #getRepository()}.
|
||||||
*/
|
*/
|
||||||
public void setObjectInserter(ObjectInserter oi) {
|
public void setObjectInserter(ObjectInserter oi) {
|
||||||
walk.release();
|
walk.close();
|
||||||
reader.release();
|
reader.close();
|
||||||
inserter.release();
|
inserter.close();
|
||||||
inserter = oi;
|
inserter = oi;
|
||||||
reader = oi.newReader();
|
reader = oi.newReader();
|
||||||
walk = new RevWalk(reader);
|
walk = new RevWalk(reader);
|
||||||
|
@ -206,8 +206,8 @@ public boolean merge(final boolean flush, final AnyObjectId... tips)
|
||||||
return ok;
|
return ok;
|
||||||
} finally {
|
} finally {
|
||||||
if (flush)
|
if (flush)
|
||||||
inserter.release();
|
inserter.close();
|
||||||
reader.release();
|
reader.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.filter.RevFilter;
|
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.TreeWalk;
|
||||||
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
|
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(MAX_BASES), a.name(), b.name(),
|
||||||
Integer.valueOf(baseCommits.size())));
|
Integer.valueOf(baseCommits.size())));
|
||||||
parents.add(nextBase);
|
parents.add(nextBase);
|
||||||
if (mergeTrees(
|
RevCommit bc = getBaseCommit(currentBase, nextBase,
|
||||||
openTree(getBaseCommit(currentBase, nextBase,
|
callDepth + 1);
|
||||||
callDepth + 1).getTree()),
|
AbstractTreeIterator bcTree = (bc == null) ? new EmptyTreeIterator()
|
||||||
currentBase.getTree(), nextBase.getTree(), true))
|
: openTree(bc.getTree());
|
||||||
|
if (mergeTrees(bcTree, currentBase.getTree(),
|
||||||
|
nextBase.getTree(), true))
|
||||||
currentBase = createCommitForTree(resultTree, parents);
|
currentBase = createCommitForTree(resultTree, parents);
|
||||||
else
|
else
|
||||||
throw new NoMergeBaseException(
|
throw new NoMergeBaseException(
|
||||||
|
|
|
@ -47,12 +47,14 @@
|
||||||
import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
|
import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
|
||||||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -791,25 +793,25 @@ private File writeMergedFile(MergeResult<RawText> result)
|
||||||
File parentFolder = of.getParentFile();
|
File parentFolder = of.getParentFile();
|
||||||
if (!fs.exists(parentFolder))
|
if (!fs.exists(parentFolder))
|
||||||
parentFolder.mkdirs();
|
parentFolder.mkdirs();
|
||||||
FileOutputStream fos = new FileOutputStream(of);
|
try (OutputStream os = new BufferedOutputStream(
|
||||||
try {
|
new FileOutputStream(of))) {
|
||||||
new MergeFormatter().formatMerge(fos, result,
|
new MergeFormatter().formatMerge(os, result,
|
||||||
Arrays.asList(commitNames), CHARACTER_ENCODING);
|
Arrays.asList(commitNames), CHARACTER_ENCODING);
|
||||||
} finally {
|
|
||||||
fos.close();
|
|
||||||
}
|
}
|
||||||
return of;
|
return of;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectId insertMergeResult(MergeResult<RawText> result)
|
private ObjectId insertMergeResult(MergeResult<RawText> result)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(10 << 20);
|
TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
|
||||||
|
db.getDirectory(), 10 << 20);
|
||||||
try {
|
try {
|
||||||
new MergeFormatter().formatMerge(buf, result,
|
new MergeFormatter().formatMerge(buf, result,
|
||||||
Arrays.asList(commitNames), CHARACTER_ENCODING);
|
Arrays.asList(commitNames), CHARACTER_ENCODING);
|
||||||
buf.close();
|
buf.close();
|
||||||
return getObjectInserter().insert(OBJ_BLOB, buf.length(),
|
try (InputStream in = buf.openInputStream()) {
|
||||||
buf.openInputStream());
|
return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
buf.destroy();
|
buf.destroy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,8 +135,8 @@ public NoteMap merge(NoteMap base, NoteMap ours, NoteMap theirs)
|
||||||
inserter.flush();
|
inserter.flush();
|
||||||
return NoteMap.newMap(mergedBucket, reader);
|
return NoteMap.newMap(mergedBucket, reader);
|
||||||
} finally {
|
} finally {
|
||||||
reader.release();
|
reader.close();
|
||||||
inserter.release();
|
inserter.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ public void markUninteresting(RevObject o) throws MissingObjectException,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o instanceof RevCommit)
|
if (o instanceof RevCommit)
|
||||||
markUninteresting((RevCommit) o);
|
super.markUninteresting((RevCommit) o);
|
||||||
else if (o instanceof RevTree)
|
else if (o instanceof RevTree)
|
||||||
markTreeUninteresting((RevTree) o);
|
markTreeUninteresting((RevTree) o);
|
||||||
else
|
else
|
||||||
|
@ -242,18 +242,6 @@ else if (o instanceof RevTree)
|
||||||
addObject(o);
|
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) {
|
public void sort(RevSort s) {
|
||||||
super.sort(s);
|
super.sort(s);
|
||||||
boundary = hasRevSort(RevSort.BOUNDARY);
|
boundary = hasRevSort(RevSort.BOUNDARY);
|
||||||
|
|
|
@ -65,6 +65,8 @@
|
||||||
public abstract class BaseConnection implements Connection {
|
public abstract class BaseConnection implements Connection {
|
||||||
private Map<String, Ref> advertisedRefs = Collections.emptyMap();
|
private Map<String, Ref> advertisedRefs = Collections.emptyMap();
|
||||||
|
|
||||||
|
private String peerUserAgent;
|
||||||
|
|
||||||
private boolean startedOperation;
|
private boolean startedOperation;
|
||||||
|
|
||||||
private Writer messageWriter;
|
private Writer messageWriter;
|
||||||
|
@ -85,6 +87,28 @@ public String getMessages() {
|
||||||
return messageWriter != null ? messageWriter.toString() : ""; //$NON-NLS-1$
|
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();
|
public abstract void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
|
|
||||||
package org.eclipse.jgit.transport;
|
package org.eclipse.jgit.transport;
|
||||||
|
|
||||||
|
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -275,6 +277,18 @@ protected boolean wantCapability(final StringBuilder b, final String option) {
|
||||||
return true;
|
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) {
|
private PackProtocolException duplicateAdvertisement(final String name) {
|
||||||
return new PackProtocolException(uri, MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, name));
|
return new PackProtocolException(uri, MessageFormat.format(JGitText.get().duplicateAdvertisementsOf, name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,7 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (walk != null)
|
if (walk != null)
|
||||||
walk.release();
|
walk.close();
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,6 +521,7 @@ else if (wantCapability(line, OPTION_SIDE_BAND))
|
||||||
OPTION_MULTI_ACK_DETAILED));
|
OPTION_MULTI_ACK_DETAILED));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addUserAgentCapability(line);
|
||||||
return line.toString();
|
return line.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,16 +754,13 @@ private void receivePack(final ProgressMonitor monitor,
|
||||||
input = new SideBandInputStream(input, monitor, getMessageWriter(),
|
input = new SideBandInputStream(input, monitor, getMessageWriter(),
|
||||||
outputStream);
|
outputStream);
|
||||||
|
|
||||||
ObjectInserter ins = local.newObjectInserter();
|
try (ObjectInserter ins = local.newObjectInserter()) {
|
||||||
try {
|
|
||||||
PackParser parser = ins.newPackParser(input);
|
PackParser parser = ins.newPackParser(input);
|
||||||
parser.setAllowThin(thinPack);
|
parser.setAllowThin(thinPack);
|
||||||
parser.setObjectChecker(transport.getObjectChecker());
|
parser.setObjectChecker(transport.getObjectChecker());
|
||||||
parser.setLockMessage(lockMessage);
|
parser.setLockMessage(lockMessage);
|
||||||
packLock = parser.parse(monitor);
|
packLock = parser.parse(monitor);
|
||||||
ins.flush();
|
ins.flush();
|
||||||
} finally {
|
|
||||||
ins.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,7 @@ private String enableCapabilities(final ProgressMonitor monitor,
|
||||||
outputStream);
|
outputStream);
|
||||||
pckIn = new PacketLineIn(in);
|
pckIn = new PacketLineIn(in);
|
||||||
}
|
}
|
||||||
|
addUserAgentCapability(line);
|
||||||
|
|
||||||
if (line.length() > 0)
|
if (line.length() > 0)
|
||||||
line.setCharAt(0, '\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> remoteObjects = new HashSet<ObjectId>();
|
||||||
Set<ObjectId> newObjects = new HashSet<ObjectId>();
|
Set<ObjectId> newObjects = new HashSet<ObjectId>();
|
||||||
|
|
||||||
final PackWriter writer = new PackWriter(transport.getPackConfig(),
|
try (final PackWriter writer = new PackWriter(transport.getPackConfig(),
|
||||||
local.newObjectReader());
|
local.newObjectReader())) {
|
||||||
try {
|
|
||||||
|
|
||||||
for (final Ref r : getRefs()) {
|
for (final Ref r : getRefs()) {
|
||||||
// only add objects that we actually have
|
// only add objects that we actually have
|
||||||
|
@ -303,10 +303,9 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
|
||||||
writer.setDeltaBaseAsOffset(capableOfsDelta);
|
writer.setDeltaBaseAsOffset(capableOfsDelta);
|
||||||
writer.preparePack(monitor, newObjects, remoteObjects);
|
writer.preparePack(monitor, newObjects, remoteObjects);
|
||||||
writer.writePack(monitor, monitor, out);
|
writer.writePack(monitor, monitor, out);
|
||||||
} finally {
|
|
||||||
writer.release();
|
packTransferTime = writer.getStatistics().getTimeWriting();
|
||||||
}
|
}
|
||||||
packTransferTime = writer.getStatistics().getTimeWriting();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
|
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_OFS_DELTA;
|
||||||
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
|
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.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_DATA;
|
||||||
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
|
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
|
||||||
import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
|
import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
|
||||||
|
@ -224,6 +225,7 @@ public Set<String> getCapabilities() {
|
||||||
|
|
||||||
/** Capabilities requested by the client. */
|
/** Capabilities requested by the client. */
|
||||||
private Set<String> enabledCapabilities;
|
private Set<String> enabledCapabilities;
|
||||||
|
String userAgent;
|
||||||
private Set<ObjectId> clientShallowCommits;
|
private Set<ObjectId> clientShallowCommits;
|
||||||
private List<ReceiveCommand> commands;
|
private List<ReceiveCommand> commands;
|
||||||
|
|
||||||
|
@ -289,6 +291,7 @@ public ReceiveConfig parse(final Config cfg) {
|
||||||
|
|
||||||
final boolean checkReceivedObjects;
|
final boolean checkReceivedObjects;
|
||||||
final boolean allowLeadingZeroFileMode;
|
final boolean allowLeadingZeroFileMode;
|
||||||
|
final boolean allowInvalidPersonIdent;
|
||||||
final boolean safeForWindows;
|
final boolean safeForWindows;
|
||||||
final boolean safeForMacOS;
|
final boolean safeForMacOS;
|
||||||
|
|
||||||
|
@ -306,6 +309,8 @@ public ReceiveConfig parse(final Config cfg) {
|
||||||
config.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
config.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
allowLeadingZeroFileMode = checkReceivedObjects
|
allowLeadingZeroFileMode = checkReceivedObjects
|
||||||
&& config.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
|
&& 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
|
safeForWindows = checkReceivedObjects
|
||||||
&& config.getBoolean("fsck", "safeForWindows", false); //$NON-NLS-1$ //$NON-NLS-2$
|
&& config.getBoolean("fsck", "safeForWindows", false); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
safeForMacOS = checkReceivedObjects
|
safeForMacOS = checkReceivedObjects
|
||||||
|
@ -317,7 +322,7 @@ public ReceiveConfig parse(final Config cfg) {
|
||||||
"denynonfastforwards", false); //$NON-NLS-1$
|
"denynonfastforwards", false); //$NON-NLS-1$
|
||||||
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
|
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
true);
|
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$
|
certNonceSlopLimit = config.getInt("receive", "certnonceslop", 0); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +331,7 @@ ObjectChecker newObjectChecker() {
|
||||||
return null;
|
return null;
|
||||||
return new ObjectChecker()
|
return new ObjectChecker()
|
||||||
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
|
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
|
||||||
|
.setAllowInvalidPersonIdent(allowInvalidPersonIdent)
|
||||||
.setSafeForWindows(safeForWindows)
|
.setSafeForWindows(safeForWindows)
|
||||||
.setSafeForMacOS(safeForMacOS);
|
.setSafeForMacOS(safeForMacOS);
|
||||||
}
|
}
|
||||||
|
@ -734,6 +740,25 @@ public boolean isSideBand() throws RequestNotYetReadException {
|
||||||
return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K);
|
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. */
|
/** @return all of the command received by the current request. */
|
||||||
public List<ReceiveCommand> getAllCommands() {
|
public List<ReceiveCommand> getAllCommands() {
|
||||||
return Collections.unmodifiableList(commands);
|
return Collections.unmodifiableList(commands);
|
||||||
|
@ -951,6 +976,7 @@ public void sendAdvertisedRefs(final RefAdvertiser adv)
|
||||||
adv.advertiseCapability(CAPABILITY_ATOMIC);
|
adv.advertiseCapability(CAPABILITY_ATOMIC);
|
||||||
if (allowOfsDelta)
|
if (allowOfsDelta)
|
||||||
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
|
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
|
||||||
|
adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
|
||||||
adv.send(getAdvertisedOrDefaultRefs());
|
adv.send(getAdvertisedOrDefaultRefs());
|
||||||
for (ObjectId obj : advertisedHaves)
|
for (ObjectId obj : advertisedHaves)
|
||||||
adv.advertiseHave(obj);
|
adv.advertiseHave(obj);
|
||||||
|
@ -1070,8 +1096,7 @@ private void receivePack() throws IOException {
|
||||||
if (sideBand)
|
if (sideBand)
|
||||||
resolving = new SideBandProgressMonitor(msgOut);
|
resolving = new SideBandProgressMonitor(msgOut);
|
||||||
|
|
||||||
ObjectInserter ins = db.newObjectInserter();
|
try (ObjectInserter ins = db.newObjectInserter()) {
|
||||||
try {
|
|
||||||
String lockMsg = "jgit receive-pack"; //$NON-NLS-1$
|
String lockMsg = "jgit receive-pack"; //$NON-NLS-1$
|
||||||
if (getRefLogIdent() != null)
|
if (getRefLogIdent() != null)
|
||||||
lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$
|
lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$
|
||||||
|
@ -1089,8 +1114,6 @@ private void receivePack() throws IOException {
|
||||||
packLock = parser.parse(receiving, resolving);
|
packLock = parser.parse(receiving, resolving);
|
||||||
packSize = Long.valueOf(parser.getPackSize());
|
packSize = Long.valueOf(parser.getPackSize());
|
||||||
ins.flush();
|
ins.flush();
|
||||||
} finally {
|
|
||||||
ins.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeoutIn != null)
|
if (timeoutIn != null)
|
||||||
|
@ -1119,67 +1142,69 @@ private void checkConnectivity() throws IOException {
|
||||||
}
|
}
|
||||||
parser = null;
|
parser = null;
|
||||||
|
|
||||||
final ObjectWalk ow = new ObjectWalk(db);
|
try (final ObjectWalk ow = new ObjectWalk(db)) {
|
||||||
ow.setRetainBody(false);
|
ow.setRetainBody(false);
|
||||||
if (baseObjects != null) {
|
if (baseObjects != null) {
|
||||||
ow.sort(RevSort.TOPO);
|
ow.sort(RevSort.TOPO);
|
||||||
if (!baseObjects.isEmpty())
|
if (!baseObjects.isEmpty())
|
||||||
ow.sort(RevSort.BOUNDARY, true);
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
checking.beginTask(JGitText.get().countingObjects, ProgressMonitor.UNKNOWN);
|
for (final ReceiveCommand cmd : commands) {
|
||||||
RevCommit c;
|
if (cmd.getResult() != Result.NOT_ATTEMPTED)
|
||||||
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))
|
|
||||||
continue;
|
continue;
|
||||||
else
|
if (cmd.getType() == ReceiveCommand.Type.DELETE)
|
||||||
throw new MissingObjectException(o, o.getType());
|
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))
|
checking.beginTask(JGitText.get().countingObjects,
|
||||||
throw new MissingObjectException(o, Constants.TYPE_BLOB);
|
ProgressMonitor.UNKNOWN);
|
||||||
}
|
RevCommit c;
|
||||||
checking.endTask();
|
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) {
|
RevObject o;
|
||||||
for (ObjectId id : baseObjects) {
|
while ((o = ow.nextObject()) != null) {
|
||||||
o = ow.parseAny(id);
|
checking.update(1);
|
||||||
if (!o.has(RevFlag.UNINTERESTING))
|
if (o.has(RevFlag.UNINTERESTING))
|
||||||
throw new MissingObjectException(o, o.getType());
|
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.
|
* the pack could not be unlocked.
|
||||||
*/
|
*/
|
||||||
protected void release() throws IOException {
|
protected void release() throws IOException {
|
||||||
walk.release();
|
walk.close();
|
||||||
unlockPack();
|
unlockPack();
|
||||||
timeoutIn = null;
|
timeoutIn = null;
|
||||||
rawIn = null;
|
rawIn = null;
|
||||||
|
|
|
@ -183,16 +183,13 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
verifyPrerequisites();
|
verifyPrerequisites();
|
||||||
try {
|
try {
|
||||||
ObjectInserter ins = transport.local.newObjectInserter();
|
try (ObjectInserter ins = transport.local.newObjectInserter()) {
|
||||||
try {
|
|
||||||
PackParser parser = ins.newPackParser(bin);
|
PackParser parser = ins.newPackParser(bin);
|
||||||
parser.setAllowThin(true);
|
parser.setAllowThin(true);
|
||||||
parser.setObjectChecker(transport.getObjectChecker());
|
parser.setObjectChecker(transport.getObjectChecker());
|
||||||
parser.setLockMessage(lockMessage);
|
parser.setLockMessage(lockMessage);
|
||||||
packLock = parser.parse(NullProgressMonitor.INSTANCE);
|
packLock = parser.parse(NullProgressMonitor.INSTANCE);
|
||||||
ins.flush();
|
ins.flush();
|
||||||
} finally {
|
|
||||||
ins.release();
|
|
||||||
}
|
}
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
close();
|
close();
|
||||||
|
@ -217,8 +214,7 @@ private void verifyPrerequisites() throws TransportException {
|
||||||
if (prereqs.isEmpty())
|
if (prereqs.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
final RevWalk rw = new RevWalk(transport.local);
|
try (final RevWalk rw = new RevWalk(transport.local)) {
|
||||||
try {
|
|
||||||
final RevFlag PREREQ = rw.newFlag("PREREQ"); //$NON-NLS-1$
|
final RevFlag PREREQ = rw.newFlag("PREREQ"); //$NON-NLS-1$
|
||||||
final RevFlag SEEN = rw.newFlag("SEEN"); //$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,
|
throw new MissingBundlePrerequisiteException(transport.uri,
|
||||||
missing);
|
missing);
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
rw.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,8 +194,7 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
|
||||||
PackConfig pc = packConfig;
|
PackConfig pc = packConfig;
|
||||||
if (pc == null)
|
if (pc == null)
|
||||||
pc = new PackConfig(db);
|
pc = new PackConfig(db);
|
||||||
PackWriter packWriter = new PackWriter(pc, db.newObjectReader());
|
try (PackWriter packWriter = new PackWriter(pc, db.newObjectReader())) {
|
||||||
try {
|
|
||||||
final HashSet<ObjectId> inc = new HashSet<ObjectId>();
|
final HashSet<ObjectId> inc = new HashSet<ObjectId>();
|
||||||
final HashSet<ObjectId> exc = new HashSet<ObjectId>();
|
final HashSet<ObjectId> exc = new HashSet<ObjectId>();
|
||||||
inc.addAll(include.values());
|
inc.addAll(include.values());
|
||||||
|
@ -233,8 +232,6 @@ public void writeBundle(ProgressMonitor monitor, OutputStream os)
|
||||||
w.write('\n');
|
w.write('\n');
|
||||||
w.flush();
|
w.flush();
|
||||||
packWriter.writePack(monitor, monitor, os);
|
packWriter.writePack(monitor, monitor, os);
|
||||||
} finally {
|
|
||||||
packWriter.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,4 +127,13 @@ public interface Connection {
|
||||||
* remote produced no additional messages.
|
* remote produced no additional messages.
|
||||||
*/
|
*/
|
||||||
public String getMessages();
|
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();
|
conn = transport.openFetch();
|
||||||
try {
|
try {
|
||||||
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
|
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
|
||||||
|
result.peerUserAgent = conn.getPeerUserAgent();
|
||||||
final Set<Ref> matched = new HashSet<Ref>();
|
final Set<Ref> matched = new HashSet<Ref>();
|
||||||
for (final RefSpec spec : toFetch) {
|
for (final RefSpec spec : toFetch) {
|
||||||
if (spec.getSource() == null)
|
if (spec.getSource() == null)
|
||||||
|
@ -196,8 +197,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
|
||||||
.newBatchUpdate()
|
.newBatchUpdate()
|
||||||
.setAllowNonFastForwards(true)
|
.setAllowNonFastForwards(true)
|
||||||
.setRefLogMessage("fetch", true); //$NON-NLS-1$
|
.setRefLogMessage("fetch", true); //$NON-NLS-1$
|
||||||
final RevWalk walk = new RevWalk(transport.local);
|
try (final RevWalk walk = new RevWalk(transport.local)) {
|
||||||
try {
|
|
||||||
if (monitor instanceof BatchingProgressMonitor) {
|
if (monitor instanceof BatchingProgressMonitor) {
|
||||||
((BatchingProgressMonitor) monitor).setDelayStart(
|
((BatchingProgressMonitor) monitor).setDelayStart(
|
||||||
250, TimeUnit.MILLISECONDS);
|
250, TimeUnit.MILLISECONDS);
|
||||||
|
@ -226,8 +226,6 @@ else if (tagopt == TagOpt.FETCH_TAGS)
|
||||||
throw new TransportException(MessageFormat.format(
|
throw new TransportException(MessageFormat.format(
|
||||||
JGitText.get().failureUpdatingTrackingRef,
|
JGitText.get().failureUpdatingTrackingRef,
|
||||||
getFirstFailedRefName(batch), err.getMessage()), err);
|
getFirstFailedRefName(batch), err.getMessage()), err);
|
||||||
} finally {
|
|
||||||
walk.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fetchHeadUpdates.isEmpty()) {
|
if (!fetchHeadUpdates.isEmpty()) {
|
||||||
|
@ -338,15 +336,12 @@ private void updateFETCH_HEAD(final FetchResult result) throws IOException {
|
||||||
|
|
||||||
private boolean askForIsComplete() throws TransportException {
|
private boolean askForIsComplete() throws TransportException {
|
||||||
try {
|
try {
|
||||||
final ObjectWalk ow = new ObjectWalk(transport.local);
|
try (final ObjectWalk ow = new ObjectWalk(transport.local)) {
|
||||||
try {
|
|
||||||
for (final ObjectId want : askFor.keySet())
|
for (final ObjectId want : askFor.keySet())
|
||||||
ow.markStart(ow.parseAny(want));
|
ow.markStart(ow.parseAny(want));
|
||||||
for (final Ref ref : localRefs().values())
|
for (final Ref ref : localRefs().values())
|
||||||
ow.markUninteresting(ow.parseAny(ref.getObjectId()));
|
ow.markUninteresting(ow.parseAny(ref.getObjectId()));
|
||||||
ow.checkConnectivity();
|
ow.checkConnectivity();
|
||||||
} finally {
|
|
||||||
ow.release();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (MissingObjectException e) {
|
} catch (MissingObjectException e) {
|
||||||
|
|
|
@ -186,6 +186,13 @@ public class GitProtocolConstants {
|
||||||
*/
|
*/
|
||||||
public static final String CAPABILITY_PUSH_CERT = "push-cert"; //$NON-NLS-1$
|
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 {
|
static enum MultiAck {
|
||||||
OFF, CONTINUE, DETAILED;
|
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;
|
StringBuilder messageBuffer;
|
||||||
|
|
||||||
|
String peerUserAgent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the URI this result came from.
|
* Get the URI this result came from.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -165,4 +167,15 @@ void addMessages(final String msg) {
|
||||||
messageBuffer.append('\n');
|
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 {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (readCurs != null)
|
if (readCurs != null)
|
||||||
readCurs.release();
|
readCurs.close();
|
||||||
} finally {
|
} finally {
|
||||||
readCurs = null;
|
readCurs = null;
|
||||||
}
|
}
|
||||||
|
@ -812,7 +812,7 @@ private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
|
||||||
|
|
||||||
for (final DeltaChain base : missing) {
|
for (final DeltaChain base : missing) {
|
||||||
if (base.head != null)
|
if (base.head != null)
|
||||||
throw new MissingObjectException(base, "delta base");
|
throw new MissingObjectException(base, "delta base"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
onEndThinPack();
|
onEndThinPack();
|
||||||
|
|
|
@ -155,6 +155,7 @@ PushResult execute(final ProgressMonitor monitor)
|
||||||
try {
|
try {
|
||||||
res.setAdvertisedRefs(transport.getURI(), connection
|
res.setAdvertisedRefs(transport.getURI(), connection
|
||||||
.getRefsMap());
|
.getRefsMap());
|
||||||
|
res.peerUserAgent = connection.getPeerUserAgent();
|
||||||
res.setRemoteUpdates(toPush);
|
res.setRemoteUpdates(toPush);
|
||||||
monitor.endTask();
|
monitor.endTask();
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,21 @@ public void advertiseCapability(String name) {
|
||||||
capablities.add(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.
|
* Add a symbolic ref to capabilities.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -164,8 +179,7 @@ public void advertiseCapability(String name) {
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
public void addSymref(String from, String to) {
|
public void addSymref(String from, String to) {
|
||||||
String symref = String.format("%s=%s:%s", OPTION_SYMREF, from, to); //$NON-NLS-1$
|
advertiseCapability(OPTION_SYMREF, from + ':' + to);
|
||||||
advertiseCapability(symref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -67,6 +67,7 @@ public TransferConfig parse(final Config cfg) {
|
||||||
|
|
||||||
private final boolean checkReceivedObjects;
|
private final boolean checkReceivedObjects;
|
||||||
private final boolean allowLeadingZeroFileMode;
|
private final boolean allowLeadingZeroFileMode;
|
||||||
|
private final boolean allowInvalidPersonIdent;
|
||||||
private final boolean safeForWindows;
|
private final boolean safeForWindows;
|
||||||
private final boolean safeForMacOS;
|
private final boolean safeForMacOS;
|
||||||
private final boolean allowTipSha1InWant;
|
private final boolean allowTipSha1InWant;
|
||||||
|
@ -82,6 +83,8 @@ private TransferConfig(final Config rc) {
|
||||||
rc.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
rc.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
allowLeadingZeroFileMode = checkReceivedObjects
|
allowLeadingZeroFileMode = checkReceivedObjects
|
||||||
&& rc.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
|
&& 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
|
safeForWindows = checkReceivedObjects
|
||||||
&& rc.getBoolean("fsck", "safeForWindows", //$NON-NLS-1$ //$NON-NLS-2$
|
&& rc.getBoolean("fsck", "safeForWindows", //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
SystemReader.getInstance().isWindows());
|
SystemReader.getInstance().isWindows());
|
||||||
|
@ -113,6 +116,7 @@ public ObjectChecker newObjectChecker() {
|
||||||
return null;
|
return null;
|
||||||
return new ObjectChecker()
|
return new ObjectChecker()
|
||||||
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
|
.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
|
||||||
|
.setAllowInvalidPersonIdent(allowInvalidPersonIdent)
|
||||||
.setSafeForWindows(safeForWindows)
|
.setSafeForWindows(safeForWindows)
|
||||||
.setSafeForMacOS(safeForMacOS);
|
.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 SVC_RECEIVE_PACK = "git-receive-pack"; //$NON-NLS-1$
|
||||||
|
|
||||||
private static final String userAgent = computeUserAgent();
|
|
||||||
|
|
||||||
static final TransportProtocol PROTO_HTTP = new TransportProtocol() {
|
static final TransportProtocol PROTO_HTTP = new TransportProtocol() {
|
||||||
private final String[] schemeNames = { "http", "https" }; //$NON-NLS-1$ //$NON-NLS-2$
|
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>() {
|
private static final Config.SectionParser<HttpConfig> HTTP_KEY = new SectionParser<HttpConfig>() {
|
||||||
public HttpConfig parse(final Config cfg) {
|
public HttpConfig parse(final Config cfg) {
|
||||||
return new HttpConfig(cfg);
|
return new HttpConfig(cfg);
|
||||||
|
@ -309,16 +296,17 @@ public FetchConnection openFetch() throws TransportException,
|
||||||
final HttpConnection c = connect(service);
|
final HttpConnection c = connect(service);
|
||||||
final InputStream in = openInputStream(c);
|
final InputStream in = openInputStream(c);
|
||||||
try {
|
try {
|
||||||
|
BaseConnection f;
|
||||||
if (isSmartHttp(c, service)) {
|
if (isSmartHttp(c, service)) {
|
||||||
readSmartHeaders(in, service);
|
readSmartHeaders(in, service);
|
||||||
return new SmartHttpFetchConnection(in);
|
f = new SmartHttpFetchConnection(in);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Assume this server doesn't support smart HTTP fetch
|
// Assume this server doesn't support smart HTTP fetch
|
||||||
// and fall back on dumb object walking.
|
// and fall back on dumb object walking.
|
||||||
//
|
f = newDumbConnection(in);
|
||||||
return newDumbConnection(in);
|
|
||||||
}
|
}
|
||||||
|
f.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
|
||||||
|
return (FetchConnection) f;
|
||||||
} finally {
|
} finally {
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
|
@ -331,7 +319,7 @@ public FetchConnection openFetch() throws TransportException,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FetchConnection newDumbConnection(InputStream in)
|
private WalkFetchConnection newDumbConnection(InputStream in)
|
||||||
throws IOException, PackProtocolException {
|
throws IOException, PackProtocolException {
|
||||||
HttpObjectDB d = new HttpObjectDB(objectsUrl);
|
HttpObjectDB d = new HttpObjectDB(objectsUrl);
|
||||||
BufferedReader br = toBufferedReader(in);
|
BufferedReader br = toBufferedReader(in);
|
||||||
|
@ -400,9 +388,7 @@ public PushConnection openPush() throws NotSupportedException,
|
||||||
final InputStream in = openInputStream(c);
|
final InputStream in = openInputStream(c);
|
||||||
try {
|
try {
|
||||||
if (isSmartHttp(c, service)) {
|
if (isSmartHttp(c, service)) {
|
||||||
readSmartHeaders(in, service);
|
return smartPush(service, c, in);
|
||||||
return new SmartHttpPushConnection(in);
|
|
||||||
|
|
||||||
} else if (!useSmartHttp) {
|
} else if (!useSmartHttp) {
|
||||||
final String msg = JGitText.get().smartHTTPPushDisabled;
|
final String msg = JGitText.get().smartHTTPPushDisabled;
|
||||||
throw new NotSupportedException(msg);
|
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
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
// No explicit connections are maintained.
|
// No explicit connections are maintained.
|
||||||
|
@ -551,7 +545,9 @@ protected HttpConnection httpOpen(String method, URL u)
|
||||||
conn.setUseCaches(false);
|
conn.setUseCaches(false);
|
||||||
conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
|
conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
|
||||||
conn.setRequestProperty(HDR_PRAGMA, "no-cache"); //$NON-NLS-1$
|
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();
|
int timeOut = getTimeout();
|
||||||
if (timeOut != -1) {
|
if (timeOut != -1) {
|
||||||
int effTimeOut = timeOut * 1000;
|
int effTimeOut = timeOut * 1000;
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
package org.eclipse.jgit.transport;
|
package org.eclipse.jgit.transport;
|
||||||
|
|
||||||
import static org.eclipse.jgit.lib.RefDatabase.ALL;
|
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_ALLOW_TIP_SHA1_IN_WANT;
|
||||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
|
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
|
||||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK;
|
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_MULTI_ACK;
|
||||||
|
@ -253,6 +254,7 @@ public Set<String> getOptions() {
|
||||||
|
|
||||||
/** Capabilities requested by the client. */
|
/** Capabilities requested by the client. */
|
||||||
private Set<String> options;
|
private Set<String> options;
|
||||||
|
String userAgent;
|
||||||
|
|
||||||
/** Raw ObjectIds the client has asked for, before validating them. */
|
/** Raw ObjectIds the client has asked for, before validating them. */
|
||||||
private final Set<ObjectId> wantIds = new HashSet<ObjectId>();
|
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 == RequestPolicy.REACHABLE_COMMIT_TIP
|
||||||
|| policy == null)
|
|| policy == null)
|
||||||
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
|
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
|
||||||
|
adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
|
||||||
adv.setDerefTags(true);
|
adv.setDerefTags(true);
|
||||||
Map<String, Ref> refs = getAdvertisedOrDefaultRefs();
|
Map<String, Ref> refs = getAdvertisedOrDefaultRefs();
|
||||||
findSymrefs(adv, refs);
|
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 {
|
private boolean negotiate() throws IOException {
|
||||||
okToGiveUp = Boolean.FALSE;
|
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(committer.toExternalString());
|
||||||
b.append("\n\n"); //$NON-NLS-1$
|
b.append("\n\n"); //$NON-NLS-1$
|
||||||
b.append(cleanMessage);
|
b.append(cleanMessage);
|
||||||
return new ObjectInserter.Formatter().idFor(Constants.OBJ_COMMIT, //
|
try (ObjectInserter f = new ObjectInserter.Formatter()) {
|
||||||
b.toString().getBytes(Constants.CHARACTER_ENCODING));
|
return f.idFor(Constants.OBJ_COMMIT, //
|
||||||
|
b.toString().getBytes(Constants.CHARACTER_ENCODING));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern issuePattern = Pattern
|
private static final Pattern issuePattern = Pattern
|
||||||
|
|
|
@ -481,7 +481,7 @@ public void run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} 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) {
|
if (debug) {
|
||||||
LOG.debug("readpipe returns null"); //$NON-NLS-1$
|
LOG.debug("readpipe returns null"); //$NON-NLS-1$
|
||||||
|
|
|
@ -74,6 +74,12 @@ public class HttpSupport {
|
||||||
/** The {@code User-Agent} header. */
|
/** The {@code User-Agent} header. */
|
||||||
public static final String HDR_USER_AGENT = "User-Agent"; //$NON-NLS-1$
|
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. */
|
/** The {@code Date} header. */
|
||||||
public static final String HDR_DATE = "Date"; //$NON-NLS-1$
|
public static final String HDR_DATE = "Date"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
package org.eclipse.jgit.util;
|
package org.eclipse.jgit.util;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -435,7 +436,7 @@ public LocalFile(final File directory, final int inCoreLimit) {
|
||||||
|
|
||||||
protected OutputStream overflow() throws IOException {
|
protected OutputStream overflow() throws IOException {
|
||||||
onDiskFile = File.createTempFile("jgit_", ".buf", directory); //$NON-NLS-1$ //$NON-NLS-2$
|
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() {
|
public long length() {
|
||||||
|
|
6
pom.xml
6
pom.xml
|
@ -210,6 +210,10 @@
|
||||||
<id>repo.eclipse.org.cbi-releases</id>
|
<id>repo.eclipse.org.cbi-releases</id>
|
||||||
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
|
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
|
||||||
</pluginRepository>
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>repo.eclipse.org.cbi-snapshots</id>
|
||||||
|
<url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
|
||||||
|
</pluginRepository>
|
||||||
</pluginRepositories>
|
</pluginRepositories>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -346,7 +350,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.cbi.maven.plugins</groupId>
|
<groupId>org.eclipse.cbi.maven.plugins</groupId>
|
||||||
<artifactId>eclipse-jarsigner-plugin</artifactId>
|
<artifactId>eclipse-jarsigner-plugin</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>1.1.2-SNAPSHOT</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.tycho.extras</groupId>
|
<groupId>org.eclipse.tycho.extras</groupId>
|
||||||
|
|
Loading…
Reference in New Issue