Merge branch 'stable-4.0' into stable-4.1
* stable-4.0:
JGit v4.0.3.201509231615-r
Change-Id: Ie74b0392ef145ffd27dc903c45f7fec2d4492a17
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 84e0927..83051f9 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.ant.tasks;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
org.hamcrest;version="[1.1.0,2.0.0)",
org.junit;version="[4.0.0,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index b213b59..67e6c38 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index adea04e..5ff9fd5 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)"
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.0.3";
+Export-Package: org.eclipse.jgit.ant.tasks;version="4.1.2";
uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 580bead..f40e0f7 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -48,7 +48,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
index c76ae2a..b9a8688 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitAddTask.java
@@ -117,10 +117,10 @@
}
AddCommand gitAdd;
- try {
- Repository repo = new FileRepositoryBuilder().readEnvironment()
- .findGitDir(src).build();
- gitAdd = new Git(repo).add();
+ try (Repository repo = new FileRepositoryBuilder().readEnvironment()
+ .findGitDir(src).build();
+ Git git = new Git(repo);) {
+ gitAdd = git.add();
} catch (IOException e) {
throw new BuildException("Could not access repository " + src, e);
}
diff --git a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
index 14c4bc5..9962472 100644
--- a/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
+++ b/org.eclipse.jgit.ant/src/org/eclipse/jgit/ant/tasks/GitCheckoutTask.java
@@ -105,10 +105,10 @@
@Override
public void execute() throws BuildException {
CheckoutCommand checkout;
- try {
- Repository repo = new FileRepositoryBuilder().readEnvironment()
- .findGitDir(src).build();
- checkout = new Git(repo).checkout();
+ try (Repository repo = new FileRepositoryBuilder().readEnvironment()
+ .findGitDir(src).build();
+ Git git = new Git(repo)) {
+ checkout = git.checkout();
} catch (IOException e) {
throw new BuildException("Could not access repository " + src, e);
}
diff --git a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
index ff39d16..4e28e0b 100644
--- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
@@ -67,11 +67,11 @@
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=ignore
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 7db8615..3787f86 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -12,15 +12,16 @@
org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
org.osgi.framework;version="[1.3.0,2.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="4.0.3";
+Export-Package: org.eclipse.jgit.archive;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.api,
org.apache.commons.compress.archivers,
org.osgi.framework"
+Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index 06084e2..d1f674d 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.archive - Sources
Bundle-SymbolicName: org.eclipse.jgit.archive.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.0.3.201509231615-r
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.0.3.201509231615-r";roots="."
+Bundle-Version: 4.1.2.201602141800-r
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.2.201602141800-r";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 5bb3eda..377d812 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index d30a17b..182262f 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,10 +2,11 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
+Bundle-ActivationPolicy: lazy
Import-Package: org.apache.http;version="[4.1.0,5.0.0)",
org.apache.http.client;version="[4.1.0,5.0.0)",
org.apache.http.client.methods;version="[4.1.0,5.0.0)",
@@ -18,12 +19,13 @@
org.apache.http.impl.client;version="[4.1.0,5.0.0)",
org.apache.http.impl.client.cache;version="[4.1.0,5.0.0)",
org.apache.http.params;version="[4.1.0,5.0.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.http;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.0.3";
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.1.2";
uses:="org.eclipse.jgit.transport.http,
javax.net.ssl,
org.apache.http.client,
org.apache.http.client.methods,
- org.apache.http"
+ org.apache.http",
+ org.eclipse.jgit.transport.http.apache.internal;x-internal:=true
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 37f3462..7510088 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -48,7 +48,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 135525f..b66606c 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -2,13 +2,13 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.0.3",
- org.eclipse.jgit.http.server.glue;version="4.0.3";
+Export-Package: org.eclipse.jgit.http.server;version="4.1.2",
+ org.eclipse.jgit.http.server.glue;version="4.1.2";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.0.3";
+ org.eclipse.jgit.http.server.resolver;version="4.1.2";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -17,12 +17,12 @@
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.resolver;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)"
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 7e1b8ef..ea60b00 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
index b2250e3..d33362b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java
@@ -80,14 +80,16 @@
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
try {
final Repository db = getRepository(request);
- asIs.access((HttpServletRequest) request, db);
+ asIs.access(req, db);
chain.doFilter(request, response);
} catch (ServiceNotAuthorizedException e) {
- ((HttpServletResponse) response).sendError(SC_UNAUTHORIZED);
+ res.sendError(SC_UNAUTHORIZED, e.getMessage());
} catch (ServiceNotEnabledException e) {
- ((HttpServletResponse) response).sendError(SC_FORBIDDEN);
+ res.sendError(SC_FORBIDDEN, e.getMessage());
}
}
}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
index 030287b..c88670e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
@@ -76,6 +76,7 @@
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.errors.UnpackException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.InternalHttpServerGlue;
@@ -137,11 +138,10 @@
try {
rp = receivePackFactory.create(req, getRepository(req));
} catch (ServiceNotAuthorizedException e) {
- rsp.sendError(SC_UNAUTHORIZED);
+ rsp.sendError(SC_UNAUTHORIZED, e.getMessage());
return;
-
} catch (ServiceNotEnabledException e) {
- sendError(req, rsp, SC_FORBIDDEN);
+ sendError(req, rsp, SC_FORBIDDEN, e.getMessage());
return;
}
@@ -201,7 +201,7 @@
consumeRequestBody(req);
out.close();
- } catch (UnpackException e) {
+ } catch (UnpackException | PackProtocolException e) {
// This should be already reported to the client.
log(rp.getRepository(), e.getCause());
consumeRequestBody(req);
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
index 5840402..a021c1f 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java
@@ -137,10 +137,10 @@
sendError(req, res, SC_NOT_FOUND);
return;
} catch (ServiceNotEnabledException e) {
- sendError(req, res, SC_FORBIDDEN);
+ sendError(req, res, SC_FORBIDDEN, e.getMessage());
return;
} catch (ServiceNotAuthorizedException e) {
- res.sendError(SC_UNAUTHORIZED);
+ res.sendError(SC_UNAUTHORIZED, e.getMessage());
return;
} catch (ServiceMayNotContinueException e) {
sendError(req, res, SC_FORBIDDEN, e.getMessage());
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
index 5133219..7d4f21b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
@@ -98,7 +98,7 @@
try {
begin(req, db);
} catch (ServiceNotAuthorizedException e) {
- res.sendError(SC_UNAUTHORIZED);
+ res.sendError(SC_UNAUTHORIZED, e.getMessage());
return;
} catch (ServiceNotEnabledException e) {
sendError(req, res, SC_FORBIDDEN, e.getMessage());
@@ -132,11 +132,9 @@
advertise(req, new PacketLineOutRefAdvertiser(out));
buf.close();
} catch (ServiceNotAuthorizedException e) {
- res.sendError(SC_UNAUTHORIZED);
-
+ res.sendError(SC_UNAUTHORIZED, e.getMessage());
} catch (ServiceNotEnabledException e) {
- sendError(req, res, SC_FORBIDDEN);
-
+ sendError(req, res, SC_FORBIDDEN, e.getMessage());
} catch (ServiceMayNotContinueException e) {
if (e.isOutput())
buf.close();
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
index 44d4b1b..8c27b71 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
@@ -137,11 +137,10 @@
try {
rp = uploadPackFactory.create(req, getRepository(req));
} catch (ServiceNotAuthorizedException e) {
- rsp.sendError(SC_UNAUTHORIZED);
+ rsp.sendError(SC_UNAUTHORIZED, e.getMessage());
return;
-
} catch (ServiceNotEnabledException e) {
- sendError(req, rsp, SC_FORBIDDEN);
+ sendError(req, rsp, SC_FORBIDDEN, e.getMessage());
return;
}
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index ad965a9..a5bf31a 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -22,23 +22,23 @@
org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.http.server;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.http.server.glue;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit.http;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.http;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.resolver;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit.http;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
org.hamcrest.core;version="[1.1.0,2.0.0)",
org.junit;version="[4.0.0,5.0.0)",
org.junit.runner;version="[4.0.0,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 5631230..17128ed 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -51,7 +51,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index c63e16c..8a5ee6c 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
@@ -20,13 +20,23 @@
org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.http.server;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.resolver;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.0.3"
+Export-Package: org.eclipse.jgit.junit.http;version="4.1.2";
+ uses:="org.eclipse.jgit.transport,
+ org.eclipse.jgit.junit,
+ javax.servlet.http,
+ org.eclipse.jgit.lib,
+ org.eclipse.jgit.revwalk,
+ org.eclipse.jetty.server.handler,
+ javax.servlet,
+ org.eclipse.jetty.server,
+ org.eclipse.jetty.util.log,
+ org.eclipse.jetty.servlet"
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index 38e2594..d25ae00 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 2ca7e3a..ea32b1b 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,24 +2,32 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.api.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.dircache;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.merge;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util.io;version="[4.0.3,4.1.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="4.0.3"
+Export-Package: org.eclipse.jgit.junit;version="4.1.2";
+ uses:="org.eclipse.jgit.dircache,
+ org.eclipse.jgit.lib,
+ org.eclipse.jgit.revwalk,
+ org.eclipse.jgit.internal.storage.file,
+ org.eclipse.jgit.treewalk,
+ org.eclipse.jgit.util,
+ org.eclipse.jgit.storage.file,
+ org.eclipse.jgit.api"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index 25f88f8..d3616a7 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index b98db7d..b5348f9 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -50,18 +50,13 @@
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.internal.storage.file.FileRepository;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.eclipse.jgit.util.FS;
@@ -229,6 +224,102 @@
System.err.println(msg);
}
+ public static final int MOD_TIME = 1;
+
+ public static final int SMUDGE = 2;
+
+ public static final int LENGTH = 4;
+
+ public static final int CONTENT_ID = 8;
+
+ public static final int CONTENT = 16;
+
+ public static final int ASSUME_UNCHANGED = 32;
+
+ /**
+ * Represent the state of the index in one String. This representation is
+ * useful when writing tests which do assertions on the state of the index.
+ * By default information about path, mode, stage (if different from 0) is
+ * included. A bitmask controls which additional info about
+ * modificationTimes, smudge state and length is included.
+ * <p>
+ * The format of the returned string is described with this BNF:
+ *
+ * <pre>
+ * result = ( "[" path mode stage? time? smudge? length? sha1? content? "]" )* .
+ * mode = ", mode:" number .
+ * stage = ", stage:" number .
+ * time = ", time:t" timestamp-index .
+ * smudge = "" | ", smudged" .
+ * length = ", length:" number .
+ * sha1 = ", sha1:" hex-sha1 .
+ * content = ", content:" blob-data .
+ * </pre>
+ *
+ * 'stage' is only presented when the stage is different from 0. All
+ * reported time stamps are mapped to strings like "t0", "t1", ... "tn". The
+ * smallest reported time-stamp will be called "t0". This allows to write
+ * assertions against the string although the concrete value of the time
+ * stamps is unknown.
+ *
+ * @param repo
+ * the repository the index state should be determined for
+ *
+ * @param includedOptions
+ * a bitmask constructed out of the constants {@link #MOD_TIME},
+ * {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and
+ * {@link #CONTENT} controlling which info is present in the
+ * resulting string.
+ * @return a string encoding the index state
+ * @throws IllegalStateException
+ * @throws IOException
+ */
+ public static String indexState(Repository repo, int includedOptions)
+ throws IllegalStateException, IOException {
+ DirCache dc = repo.readDirCache();
+ StringBuilder sb = new StringBuilder();
+ TreeSet<Long> timeStamps = null;
+
+ // iterate once over the dircache just to collect all time stamps
+ if (0 != (includedOptions & MOD_TIME)) {
+ timeStamps = new TreeSet<Long>();
+ for (int i=0; i<dc.getEntryCount(); ++i)
+ timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified()));
+ }
+
+ // iterate again, now produce the result string
+ for (int i=0; i<dc.getEntryCount(); ++i) {
+ DirCacheEntry entry = dc.getEntry(i);
+ sb.append("["+entry.getPathString()+", mode:" + entry.getFileMode());
+ int stage = entry.getStage();
+ if (stage != 0)
+ sb.append(", stage:" + stage);
+ if (0 != (includedOptions & MOD_TIME)) {
+ sb.append(", time:t"+
+ timeStamps.headSet(Long.valueOf(entry.getLastModified())).size());
+ }
+ if (0 != (includedOptions & SMUDGE))
+ if (entry.isSmudged())
+ sb.append(", smudged");
+ if (0 != (includedOptions & LENGTH))
+ sb.append(", length:"
+ + Integer.toString(entry.getLength()));
+ if (0 != (includedOptions & CONTENT_ID))
+ sb.append(", sha1:" + ObjectId.toString(entry.getObjectId()));
+ if (0 != (includedOptions & CONTENT)) {
+ sb.append(", content:"
+ + new String(repo.open(entry.getObjectId(),
+ Constants.OBJ_BLOB).getCachedBytes(), "UTF-8"));
+ }
+ if (0 != (includedOptions & ASSUME_UNCHANGED))
+ sb.append(", assume-unchanged:"
+ + Boolean.toString(entry.isAssumeValid()));
+ sb.append("]");
+ }
+ return sb.toString();
+ }
+
+
/**
* Creates a new empty bare repository.
*
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
index 65551d6..d24dd44 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
@@ -47,6 +47,7 @@
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
@@ -170,6 +171,7 @@
* Assign some properties for the currently executing platform
*/
public void setCurrentPlatform() {
+ resetOsNames();
setProperty("os.name", System.getProperty("os.name"));
setProperty("file.separator", System.getProperty("file.separator"));
setProperty("path.separator", System.getProperty("path.separator"));
@@ -180,6 +182,7 @@
* Emulate Windows
*/
public void setWindows() {
+ resetOsNames();
setProperty("os.name", "Windows");
setProperty("file.separator", "\\");
setProperty("path.separator", ";");
@@ -191,10 +194,25 @@
* Emulate Unix
*/
public void setUnix() {
+ resetOsNames();
setProperty("os.name", "*nix"); // Essentially anything but Windows
setProperty("file.separator", "/");
setProperty("path.separator", ":");
setProperty("line.separator", "\n");
setPlatformChecker();
}
+
+ private void resetOsNames() {
+ Field field;
+ try {
+ field = SystemReader.class.getDeclaredField("isWindows");
+ field.setAccessible(true);
+ field.set(null, null);
+ field = SystemReader.class.getDeclaredField("isMacOS");
+ field.setAccessible(true);
+ field.set(null, null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index 83148d0..ac4539a 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -56,11 +56,9 @@
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;
-import java.util.TreeSet;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -154,101 +152,6 @@
trash = db.getWorkTree();
}
- public static final int MOD_TIME = 1;
-
- public static final int SMUDGE = 2;
-
- public static final int LENGTH = 4;
-
- public static final int CONTENT_ID = 8;
-
- public static final int CONTENT = 16;
-
- public static final int ASSUME_UNCHANGED = 32;
-
- /**
- * Represent the state of the index in one String. This representation is
- * useful when writing tests which do assertions on the state of the index.
- * By default information about path, mode, stage (if different from 0) is
- * included. A bitmask controls which additional info about
- * modificationTimes, smudge state and length is included.
- * <p>
- * The format of the returned string is described with this BNF:
- *
- * <pre>
- * result = ( "[" path mode stage? time? smudge? length? sha1? content? "]" )* .
- * mode = ", mode:" number .
- * stage = ", stage:" number .
- * time = ", time:t" timestamp-index .
- * smudge = "" | ", smudged" .
- * length = ", length:" number .
- * sha1 = ", sha1:" hex-sha1 .
- * content = ", content:" blob-data .
- * </pre>
- *
- * 'stage' is only presented when the stage is different from 0. All
- * reported time stamps are mapped to strings like "t0", "t1", ... "tn". The
- * smallest reported time-stamp will be called "t0". This allows to write
- * assertions against the string although the concrete value of the time
- * stamps is unknown.
- *
- * @param repo
- * the repository the index state should be determined for
- *
- * @param includedOptions
- * a bitmask constructed out of the constants {@link #MOD_TIME},
- * {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and
- * {@link #CONTENT} controlling which info is present in the
- * resulting string.
- * @return a string encoding the index state
- * @throws IllegalStateException
- * @throws IOException
- */
- public String indexState(Repository repo, int includedOptions)
- throws IllegalStateException, IOException {
- DirCache dc = repo.readDirCache();
- StringBuilder sb = new StringBuilder();
- TreeSet<Long> timeStamps = null;
-
- // iterate once over the dircache just to collect all time stamps
- if (0 != (includedOptions & MOD_TIME)) {
- timeStamps = new TreeSet<Long>();
- for (int i=0; i<dc.getEntryCount(); ++i)
- timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified()));
- }
-
- // iterate again, now produce the result string
- for (int i=0; i<dc.getEntryCount(); ++i) {
- DirCacheEntry entry = dc.getEntry(i);
- sb.append("["+entry.getPathString()+", mode:" + entry.getFileMode());
- int stage = entry.getStage();
- if (stage != 0)
- sb.append(", stage:" + stage);
- if (0 != (includedOptions & MOD_TIME)) {
- sb.append(", time:t"+
- timeStamps.headSet(Long.valueOf(entry.getLastModified())).size());
- }
- if (0 != (includedOptions & SMUDGE))
- if (entry.isSmudged())
- sb.append(", smudged");
- if (0 != (includedOptions & LENGTH))
- sb.append(", length:"
- + Integer.toString(entry.getLength()));
- if (0 != (includedOptions & CONTENT_ID))
- sb.append(", sha1:" + ObjectId.toString(entry.getObjectId()));
- if (0 != (includedOptions & CONTENT)) {
- sb.append(", content:"
- + new String(db.open(entry.getObjectId(),
- Constants.OBJ_BLOB).getCachedBytes(), "UTF-8"));
- }
- if (0 != (includedOptions & ASSUME_UNCHANGED))
- sb.append(", assume-unchanged:"
- + Boolean.toString(entry.isAssumeValid()));
- sb.append("]");
- }
- return sb.toString();
- }
-
/**
* Represent the state of the index in one String. This representation is
* useful when writing tests which do assertions on the state of the index.
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index 59c6a2e..09b59b0 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index ec7fd40..ce0f9b9 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index 2ec128a..31295cf 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.http.apache"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 313d526..350de3c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 52dc5f5..cb9fbf3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.junit"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index ac6d5ba..cb76911 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index f1b8cea..e1dcfcd 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.pgm"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -27,7 +27,7 @@
version="0.0.0"/>
<requires>
- <import feature="org.eclipse.jgit" version="4.0.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="4.1.0" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 0dedec3..9076053 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
index 381178b..bbd0aa0 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.pgm.source"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index 551835a..0e64da4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 135f9ec..88ad032 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index b10c53f..17030ff 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.source"
label="%featureName"
- version="4.0.3.201509231615-r"
+ version="4.1.2.201602141800-r"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index e6d565d..aa7128e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index 3464b30..38732b5 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
Bundle-ManifestVersion: 2
Bundle-Name: JGit Target Platform Bundle
Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
index decc554..e8670e7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.3" sequenceNumber="1436830977">
+<target name="jgit-4.3" sequenceNumber="1440024094">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.client.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util.source" version="9.2.10.v20150310"/>
- <repository id="jetty-9.2.10" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.10.v20150310/"/>
+ <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
+ <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.2.v201404171502"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd
index f038aa0..062e930 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.tpd
@@ -1,6 +1,6 @@
target "jgit-4.3" with source configurePhase
-include "projects/jetty-9.2.10.tpd"
+include "projects/jetty-9.2.13.tpd"
include "orbit/R20150124073747-Luna-SR2.tpd"
location "http://download.eclipse.org/releases/kepler/" {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
index c7172fe..0b85d75 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.4" sequenceNumber="1436830965">
+<target name="jgit-4.4" sequenceNumber="1440024079">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.client.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util.source" version="9.2.10.v20150310"/>
- <repository id="jetty-9.2.10" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.10.v20150310/"/>
+ <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
+ <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.2.v201404171502"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd
index 0760bcd..9b9558f 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.tpd
@@ -1,6 +1,6 @@
target "jgit-4.4" with source configurePhase
-include "projects/jetty-9.2.10.tpd"
+include "projects/jetty-9.2.13.tpd"
include "orbit/R20150124073747-Luna-SR2.tpd"
location "http://download.eclipse.org/releases/luna/" {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
index 030bbc2..2067482 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.5" sequenceNumber="1441320200">
+<target name="jgit-4.5" sequenceNumber="1440022750">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.client.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.http.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.io.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.security.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.server.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util" version="9.2.10.v20150310"/>
- <unit id="org.eclipse.jetty.util.source" version="9.2.10.v20150310"/>
- <repository id="jetty-9.2.10" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.10.v20150310/"/>
+ <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util" version="9.2.13.v20150730"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.2.13.v20150730"/>
+ <repository id="jetty-9.2.13" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.4.v201504302020"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
index 93ffef3..cdf24b5 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
@@ -1,6 +1,6 @@
target "jgit-4.5" with source configurePhase
-include "projects/jetty-9.2.10.tpd"
+include "projects/jetty-9.2.13.tpd"
include "orbit/R20150821153341-Mars.tpd"
location "http://download.eclipse.org/releases/mars/" {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index 278bca0..9b565ec 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -49,7 +49,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.10.tpd
deleted file mode 100644
index 5a7ee2e..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.10.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.2.10" with source configurePhase
-
-location jetty-9.2.10 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.10.v20150310/" {
- org.eclipse.jetty.client [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.client.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.continuation [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.continuation.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.http [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.http.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.io [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.io.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.security [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.security.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.server [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.server.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.servlet [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.servlet.source [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.util [9.2.10.v20150310,9.2.10.v20150310]
- org.eclipse.jetty.util.source [9.2.10.v20150310,9.2.10.v20150310]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd
new file mode 100644
index 0000000..289a73d
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.2.13.tpd
@@ -0,0 +1,20 @@
+target "jetty-9.2.13" with source configurePhase
+
+location jetty-9.2.13 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.13.v20150730/" {
+ org.eclipse.jetty.client [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.client.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.continuation [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.continuation.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.http [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.http.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.io [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.io.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.security [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.security.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.server [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.server.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.servlet [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.servlet.source [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.util [9.2.13.v20150730,9.2.13.v20150730]
+ org.eclipse.jetty.util.source [9.2.13.v20150730,9.2.13.v20150730]
+}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 2a3fcb2..3b5b7d8 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,7 +53,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 8d61863..1693bee 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.api.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.diff;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.dircache;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.merge;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.pgm;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.pgm.internal;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.pgm.opt;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util.io;version="[4.0.3,4.1.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)"
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index c570b1b..cca2e92 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
index cef9b9e..387eb2b 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
@@ -59,7 +60,6 @@
import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FileUtils;
-import org.junit.Assert;
import org.junit.Test;
public class CheckoutTest extends CLIRepositoryTestCase {
@@ -68,7 +68,8 @@
public void testCheckoutSelf() throws Exception {
new Git(db).commit().setMessage("initial commit").call();
- assertEquals("Already on 'master'", execute("git checkout master"));
+ assertStringArrayEquals("Already on 'master'",
+ execute("git checkout master"));
}
@Test
@@ -76,20 +77,21 @@
new Git(db).commit().setMessage("initial commit").call();
new Git(db).branchCreate().setName("side").call();
- assertEquals("Switched to branch 'side'", execute("git checkout side"));
+ assertStringArrayEquals("Switched to branch 'side'",
+ execute("git checkout side"));
}
@Test
public void testCheckoutNewBranch() throws Exception {
new Git(db).commit().setMessage("initial commit").call();
- assertEquals("Switched to a new branch 'side'",
+ assertStringArrayEquals("Switched to a new branch 'side'",
execute("git checkout -b side"));
}
@Test
public void testCheckoutNonExistingBranch() throws Exception {
- assertEquals(
+ assertStringArrayEquals(
"error: pathspec 'side' did not match any file(s) known to git.",
execute("git checkout side"));
}
@@ -98,19 +100,20 @@
public void testCheckoutNewBranchThatAlreadyExists() throws Exception {
new Git(db).commit().setMessage("initial commit").call();
- assertEquals("fatal: A branch named 'master' already exists.",
+ assertStringArrayEquals(
+ "fatal: A branch named 'master' already exists.",
execute("git checkout -b master"));
}
@Test
public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception {
- assertEquals("fatal: You are on a branch yet to be born",
+ assertStringArrayEquals("fatal: You are on a branch yet to be born",
execute("git checkout -b side"));
}
@Test
public void testCheckoutUnresolvedHead() throws Exception {
- assertEquals(
+ assertStringArrayEquals(
"error: pathspec 'HEAD' did not match any file(s) known to git.",
execute("git checkout HEAD"));
}
@@ -119,7 +122,7 @@
public void testCheckoutHead() throws Exception {
new Git(db).commit().setMessage("initial commit").call();
- assertEquals("", execute("git checkout HEAD"));
+ assertStringArrayEquals("", execute("git checkout HEAD"));
}
@Test
@@ -139,10 +142,10 @@
git.add().addFilepattern(".").call();
String[] execute = execute("git checkout branch_1");
- Assert.assertEquals(
+ assertEquals(
"error: Your local changes to the following files would be overwritten by checkout:",
execute[0]);
- Assert.assertEquals("\ta", execute[1]);
+ assertEquals("\ta", execute[1]);
}
/**
@@ -193,7 +196,7 @@
Git git = new Git(db);
git.commit().setMessage("initial commit").call();
- assertEquals("Switched to a new branch 'new_branch'",
+ assertStringArrayEquals("Switched to a new branch 'new_branch'",
execute("git checkout --orphan new_branch"));
assertEquals("refs/heads/new_branch", db.getRef("HEAD").getTarget().getName());
RevCommit commit = git.commit().setMessage("orphan commit").call();
@@ -553,17 +556,13 @@
// assertEquals("a/c", exception.getConflictingPaths().get(1));
}
- static private void assertEquals(Object expected, Object actual) {
- Assert.assertEquals(expected, actual);
- }
-
- static private void assertEquals(String expected, String[] actual) {
+ static private void assertStringArrayEquals(String expected, String[] actual) {
// if there is more than one line, ignore last one if empty
- Assert.assertEquals(
+ assertEquals(
1,
actual.length > 1 && actual[actual.length - 1].equals("") ? actual.length - 1
: actual.length);
- Assert.assertEquals(expected, actual[0]);
+ assertEquals(expected, actual[0]);
}
@Test
diff --git a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
index ff39d16..4e28e0b 100644
--- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
@@ -67,11 +67,11 @@
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=ignore
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 746fd2b..7d00a96 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,44 +2,46 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Vendor: %provider_name
+Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.apache.commons.compress.archivers.tar;version="[1.3,2.0)",
org.apache.commons.compress.archivers.zip;version="[1.3,2.0)",
- org.eclipse.jgit.api;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.api.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.archive;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.awtui;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.blame;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.diff;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.dircache;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.gitrepo;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.merge;version="4.0.3",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.notes;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revplot;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.pack;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.resolver;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util.io;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.archive;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.blame;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.merge;version="4.1.2",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.notes;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)",
org.kohsuke.args4j.spi;version="[2.0.15,2.1.0)"
-Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.console;version="4.0.3",
- org.eclipse.jgit.pgm;version="4.0.3";
+Export-Package: org.eclipse.jgit.console;version="4.1.2";
+ uses:="org.eclipse.jgit.transport,
+ org.eclipse.jgit.util",
+ org.eclipse.jgit.pgm;version="4.1.2";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.pgm.opt,
@@ -50,12 +52,15 @@
org.eclipse.jgit.treewalk,
javax.swing,
org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.0.3";uses:="org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.0.3";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.0.3";
+ org.eclipse.jgit.pgm.debug;version="4.1.2";
+ uses:="org.eclipse.jgit.util.io,
+ org.eclipse.jgit.pgm",
+ org.eclipse.jgit.pgm.internal;version="4.1.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.kohsuke.args4j.spi,
org.kohsuke.args4j"
Main-Class: org.eclipse.jgit.pgm.Main
Implementation-Title: JGit Command Line Interface
+Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index c68c9f4..215f8e7 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.pgm - Sources
Bundle-SymbolicName: org.eclipse.jgit.pgm.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.0.3.201509231615-r
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.0.3.201509231615-r";roots="."
+Bundle-Version: 4.1.2.201602141800-r
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.2.201602141800-r";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 9d8485f..f84e746 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/log4j.properties b/org.eclipse.jgit.pgm/resources/log4j.properties
index 4a2e480..1496c5a 100644
--- a/org.eclipse.jgit.pgm/resources/log4j.properties
+++ b/org.eclipse.jgit.pgm/resources/log4j.properties
@@ -1,4 +1,4 @@
-log4j.rootLogger=WARNING, stderr
+log4j.rootLogger=WARN, stderr
log4j.appender.stderr=org.apache.log4j.ConsoleAppender
log4j.appender.stderr.Target=System.err
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
index 12aac77..c36c485 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
@@ -62,10 +62,12 @@
@Override
protected void run() throws Exception {
- AddCommand addCmd = new Git(db).add();
- addCmd.setUpdate(update);
- for (String p : filepatterns)
- addCmd.addFilepattern(p);
- addCmd.call();
+ try (Git git = new Git(db)) {
+ AddCommand addCmd = git.add();
+ addCmd.setUpdate(update);
+ for (String p : filepatterns)
+ addCmd.addFilepattern(p);
+ addCmd.call();
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
index 80bb9ec..fe2ba83 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
@@ -87,8 +87,8 @@
else
stream = outs;
- try {
- ArchiveCommand cmd = new Git(db).archive()
+ try (Git git = new Git(db)) {
+ ArchiveCommand cmd = git.archive()
.setTree(tree)
.setFormat(format)
.setPrefix(prefix)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index 72e3715..83a1ca7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -186,29 +186,31 @@
// This can happen if HEAD is stillborn
if (head != null) {
String current = head.getLeaf().getName();
- ListBranchCommand command = new Git(db).branchList();
- if (all)
- command.setListMode(ListMode.ALL);
- else if (remote)
- command.setListMode(ListMode.REMOTE);
+ try (Git git = new Git(db)) {
+ ListBranchCommand command = git.branchList();
+ if (all)
+ command.setListMode(ListMode.ALL);
+ else if (remote)
+ command.setListMode(ListMode.REMOTE);
- if (containsCommitish != null)
- command.setContains(containsCommitish);
+ if (containsCommitish != null)
+ command.setContains(containsCommitish);
- List<Ref> refs = command.call();
- for (Ref ref : refs) {
- if (ref.getName().equals(Constants.HEAD))
- addRef("(no branch)", head); //$NON-NLS-1$
- }
+ List<Ref> refs = command.call();
+ for (Ref ref : refs) {
+ if (ref.getName().equals(Constants.HEAD))
+ addRef("(no branch)", head); //$NON-NLS-1$
+ }
- addRefs(refs, Constants.R_HEADS);
- addRefs(refs, Constants.R_REMOTES);
+ addRefs(refs, Constants.R_HEADS);
+ addRefs(refs, Constants.R_REMOTES);
- try (ObjectReader reader = db.newObjectReader()) {
- for (final Entry<String, Ref> e : printRefs.entrySet()) {
- final Ref ref = e.getValue();
- printHead(reader, e.getKey(),
- current.equals(ref.getName()), ref);
+ try (ObjectReader reader = db.newObjectReader()) {
+ for (final Entry<String, Ref> e : printRefs.entrySet()) {
+ final Ref ref = e.getValue();
+ printHead(reader, e.getKey(),
+ current.equals(ref.getName()), ref);
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 56d4fcf..4579462 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -89,47 +89,49 @@
throw die(CLIText.get().onBranchToBeBorn);
}
- CheckoutCommand command = new Git(db).checkout();
- if (paths.size() > 0) {
- command.setStartPoint(name);
- for (String path : paths)
- command.addPath(path);
- } else {
- command.setCreateBranch(createBranch);
- command.setName(name);
- command.setForce(force);
- command.setOrphan(orphan);
- }
- try {
- String oldBranch = db.getBranch();
- Ref ref = command.call();
- if (ref == null)
- return;
- if (Repository.shortenRefName(ref.getName()).equals(oldBranch)) {
- outw.println(MessageFormat.format(
- CLIText.get().alreadyOnBranch,
- name));
- return;
+ try (Git git = new Git(db)) {
+ CheckoutCommand command = git.checkout();
+ if (paths.size() > 0) {
+ command.setStartPoint(name);
+ for (String path : paths)
+ command.addPath(path);
+ } else {
+ command.setCreateBranch(createBranch);
+ command.setName(name);
+ command.setForce(force);
+ command.setOrphan(orphan);
}
- if (createBranch || orphan)
+ try {
+ String oldBranch = db.getBranch();
+ Ref ref = command.call();
+ if (ref == null)
+ return;
+ if (Repository.shortenRefName(ref.getName()).equals(oldBranch)) {
+ outw.println(MessageFormat.format(
+ CLIText.get().alreadyOnBranch,
+ name));
+ return;
+ }
+ if (createBranch || orphan)
+ outw.println(MessageFormat.format(
+ CLIText.get().switchedToNewBranch, name));
+ else
+ outw.println(MessageFormat.format(
+ CLIText.get().switchedToBranch,
+ Repository.shortenRefName(ref.getName())));
+ } catch (RefNotFoundException e) {
outw.println(MessageFormat.format(
- CLIText.get().switchedToNewBranch, name));
- else
- outw.println(MessageFormat.format(
- CLIText.get().switchedToBranch,
- Repository.shortenRefName(ref.getName())));
- } catch (RefNotFoundException e) {
- outw.println(MessageFormat.format(
- CLIText.get().pathspecDidNotMatch,
- name));
- } catch (RefAlreadyExistsException e) {
- throw die(MessageFormat.format(CLIText.get().branchAlreadyExists,
- name));
- } catch (CheckoutConflictException e) {
- outw.println(CLIText.get().checkoutConflict);
- for (String path : e.getConflictingPaths())
- outw.println(MessageFormat.format(
- CLIText.get().checkoutConflictPathLine, path));
+ CLIText.get().pathspecDidNotMatch,
+ name));
+ } catch (RefAlreadyExistsException e) {
+ throw die(MessageFormat.format(CLIText.get().branchAlreadyExists,
+ name));
+ } catch (CheckoutConflictException e) {
+ outw.println(CLIText.get().checkoutConflict);
+ for (String path : e.getConflictingPaths())
+ outw.println(MessageFormat.format(
+ CLIText.get().checkoutConflictPathLine, path));
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index 14c449a..f18242d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -80,37 +80,39 @@
@Override
protected void run() throws NoHeadException, NoMessageException,
ConcurrentRefUpdateException, JGitInternalException, Exception {
- CommitCommand commitCmd = new Git(db).commit();
- if (author != null)
- commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author));
- if (message != null)
- commitCmd.setMessage(message);
- if (only && paths.isEmpty())
- throw die(CLIText.get().pathsRequired);
- if (only && all)
- throw die(CLIText.get().onlyOneOfIncludeOnlyAllInteractiveCanBeUsed);
- if (!paths.isEmpty())
- for (String p : paths)
- commitCmd.setOnly(p);
- commitCmd.setAmend(amend);
- commitCmd.setAll(all);
- Ref head = db.getRef(Constants.HEAD);
- RevCommit commit;
- try {
- commit = commitCmd.call();
- } catch (JGitInternalException e) {
- throw die(e.getMessage());
- }
+ try (Git git = new Git(db)) {
+ CommitCommand commitCmd = git.commit();
+ if (author != null)
+ commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author));
+ if (message != null)
+ commitCmd.setMessage(message);
+ if (only && paths.isEmpty())
+ throw die(CLIText.get().pathsRequired);
+ if (only && all)
+ throw die(CLIText.get().onlyOneOfIncludeOnlyAllInteractiveCanBeUsed);
+ if (!paths.isEmpty())
+ for (String p : paths)
+ commitCmd.setOnly(p);
+ commitCmd.setAmend(amend);
+ commitCmd.setAll(all);
+ Ref head = db.getRef(Constants.HEAD);
+ RevCommit commit;
+ try {
+ commit = commitCmd.call();
+ } catch (JGitInternalException e) {
+ throw die(e.getMessage());
+ }
- String branchName;
- if (!head.isSymbolic())
- branchName = CLIText.get().branchDetachedHEAD;
- else {
- branchName = head.getTarget().getName();
- if (branchName.startsWith(Constants.R_HEADS))
- branchName = branchName.substring(Constants.R_HEADS.length());
+ String branchName;
+ if (!head.isSymbolic())
+ branchName = CLIText.get().branchDetachedHEAD;
+ else {
+ branchName = head.getTarget().getName();
+ if (branchName.startsWith(Constants.R_HEADS))
+ branchName = branchName.substring(Constants.R_HEADS.length());
+ }
+ outw.println("[" + branchName + " " + commit.name() + "] " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ + commit.getShortMessage());
}
- outw.println("[" + branchName + " " + commit.name() + "] " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- + commit.getShortMessage());
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index 901e560..ec000f3 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -61,20 +61,21 @@
@Override
protected void run() throws Exception {
- DescribeCommand cmd = new Git(db).describe();
- if (tree != null)
- cmd.setTarget(tree);
- cmd.setLong(longDesc);
- String result = null;
- try {
- result = cmd.call();
- } catch (RefNotFoundException e) {
- throw die(CLIText.get().noNamesFound, e);
+ try (Git git = new Git(db)) {
+ DescribeCommand cmd = git.describe();
+ if (tree != null)
+ cmd.setTarget(tree);
+ cmd.setLong(longDesc);
+ String result = null;
+ try {
+ result = cmd.call();
+ } catch (RefNotFoundException e) {
+ throw die(CLIText.get().noNamesFound, e);
+ }
+ if (result == null)
+ throw die(CLIText.get().noNamesFound);
+
+ outw.println(result);
}
- if (result == null)
- throw die(CLIText.get().noNamesFound);
-
- outw.println(result);
}
-
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
index d89053c..32adf6d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java
@@ -74,46 +74,47 @@
@Override
protected void run() throws Exception {
- final TreeWalk walk = new TreeWalk(db);
- walk.setRecursive(recursive);
- for (final AbstractTreeIterator i : trees)
- walk.addTree(i);
- walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
+ try (final TreeWalk walk = new TreeWalk(db)) {
+ walk.setRecursive(recursive);
+ for (final AbstractTreeIterator i : trees)
+ walk.addTree(i);
+ walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
- final int nTree = walk.getTreeCount();
- while (walk.next()) {
- for (int i = 1; i < nTree; i++)
- outw.print(':');
- for (int i = 0; i < nTree; i++) {
- final FileMode m = walk.getFileMode(i);
- final String s = m.toString();
- for (int pad = 6 - s.length(); pad > 0; pad--)
- outw.print('0');
- outw.print(s);
- outw.print(' ');
+ final int nTree = walk.getTreeCount();
+ while (walk.next()) {
+ for (int i = 1; i < nTree; i++)
+ outw.print(':');
+ for (int i = 0; i < nTree; i++) {
+ final FileMode m = walk.getFileMode(i);
+ final String s = m.toString();
+ for (int pad = 6 - s.length(); pad > 0; pad--)
+ outw.print('0');
+ outw.print(s);
+ outw.print(' ');
+ }
+
+ for (int i = 0; i < nTree; i++) {
+ outw.print(walk.getObjectId(i).name());
+ outw.print(' ');
+ }
+
+ char chg = 'M';
+ if (nTree == 2) {
+ final int m0 = walk.getRawMode(0);
+ final int m1 = walk.getRawMode(1);
+ if (m0 == 0 && m1 != 0)
+ chg = 'A';
+ else if (m0 != 0 && m1 == 0)
+ chg = 'D';
+ else if (m0 != m1 && walk.idEqual(0, 1))
+ chg = 'T';
+ }
+ outw.print(chg);
+
+ outw.print('\t');
+ outw.print(walk.getPathString());
+ outw.println();
}
-
- for (int i = 0; i < nTree; i++) {
- outw.print(walk.getObjectId(i).name());
- outw.print(' ');
- }
-
- char chg = 'M';
- if (nTree == 2) {
- final int m0 = walk.getRawMode(0);
- final int m1 = walk.getRawMode(1);
- if (m0 == 0 && m1 != 0)
- chg = 'A';
- else if (m0 != 0 && m1 == 0)
- chg = 'D';
- else if (m0 != m1 && walk.idEqual(0, 1))
- chg = 'T';
- }
- outw.print(chg);
-
- outw.print('\t');
- outw.print(walk.getPathString());
- outw.println();
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
index 186fdd8..ed06733 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
@@ -104,31 +104,32 @@
@Override
protected void run() throws Exception {
- Git git = new Git(db);
- FetchCommand fetch = git.fetch();
- if (fsck != null)
- fetch.setCheckFetchedObjects(fsck.booleanValue());
- if (prune != null)
- fetch.setRemoveDeletedRefs(prune.booleanValue());
- if (toget != null)
- fetch.setRefSpecs(toget);
- if (tags != null) {
- fetch.setTagOpt(tags.booleanValue() ? TagOpt.FETCH_TAGS
- : TagOpt.NO_TAGS);
+ try (Git git = new Git(db)) {
+ FetchCommand fetch = git.fetch();
+ if (fsck != null)
+ fetch.setCheckFetchedObjects(fsck.booleanValue());
+ if (prune != null)
+ fetch.setRemoveDeletedRefs(prune.booleanValue());
+ if (toget != null)
+ fetch.setRefSpecs(toget);
+ if (tags != null) {
+ fetch.setTagOpt(tags.booleanValue() ? TagOpt.FETCH_TAGS
+ : TagOpt.NO_TAGS);
+ }
+ if (0 <= timeout)
+ fetch.setTimeout(timeout);
+ fetch.setDryRun(dryRun);
+ fetch.setRemote(remote);
+ if (thin != null)
+ fetch.setThin(thin.booleanValue());
+ if (quiet == null || !quiet.booleanValue())
+ fetch.setProgressMonitor(new TextProgressMonitor(errw));
+
+ FetchResult result = fetch.call();
+ if (result.getTrackingRefUpdates().isEmpty())
+ return;
+
+ showFetchResult(result);
}
- if (0 <= timeout)
- fetch.setTimeout(timeout);
- fetch.setDryRun(dryRun);
- fetch.setRemote(remote);
- if (thin != null)
- fetch.setThin(thin.booleanValue());
- if (quiet == null || !quiet.booleanValue())
- fetch.setProgressMonitor(new TextProgressMonitor(errw));
-
- FetchResult result = fetch.call();
- if (result.getTrackingRefUpdates().isEmpty())
- return;
-
- showFetchResult(result);
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
index 4b16ed8..872ea67 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java
@@ -72,27 +72,28 @@
@Override
protected void run() throws Exception {
- final TreeWalk walk = new TreeWalk(db);
- walk.reset(); // drop the first empty tree, which we do not need here
- if (paths.size() > 0)
- walk.setFilter(PathFilterGroup.createFromStrings(paths));
- walk.setRecursive(recursive);
- walk.addTree(tree);
+ try (final TreeWalk walk = new TreeWalk(db)) {
+ walk.reset(); // drop the first empty tree, which we do not need here
+ if (paths.size() > 0)
+ walk.setFilter(PathFilterGroup.createFromStrings(paths));
+ walk.setRecursive(recursive);
+ walk.addTree(tree);
- while (walk.next()) {
- final FileMode mode = walk.getFileMode(0);
- if (mode == FileMode.TREE)
- outw.print('0');
- outw.print(mode);
- outw.print(' ');
- outw.print(Constants.typeString(mode.getObjectType()));
+ while (walk.next()) {
+ final FileMode mode = walk.getFileMode(0);
+ if (mode == FileMode.TREE)
+ outw.print('0');
+ outw.print(mode);
+ outw.print(' ');
+ outw.print(Constants.typeString(mode.getObjectType()));
- outw.print(' ');
- outw.print(walk.getObjectId(0).name());
+ outw.print(' ');
+ outw.print(walk.getObjectId(0).name());
- outw.print('\t');
- outw.print(QuotedString.GIT_PATH.quote(walk.getPathString()));
- outw.println();
+ outw.print('\t');
+ outw.print(QuotedString.GIT_PATH.quote(walk.getPathString()));
+ outw.println();
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index 7151de7..ceb0d6b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -181,7 +181,7 @@
if (argv.length == 0 || help) {
final String ex = clp.printExample(ExampleMode.ALL, CLIText.get().resourceBundle());
- writer.println("jgit" + ex + " command [ARG ...]"); //$NON-NLS-1$
+ writer.println("jgit" + ex + " command [ARG ...]"); //$NON-NLS-1$ //$NON-NLS-2$
if (help) {
writer.println();
clp.printUsage(writer, CLIText.get().resourceBundle());
@@ -291,39 +291,45 @@
/**
* Configure the JRE's standard HTTP based on <code>http_proxy</code>.
* <p>
- * The popular libcurl library honors the <code>http_proxy</code>
- * environment variable as a means of specifying an HTTP proxy for requests
- * made behind a firewall. This is not natively recognized by the JRE, so
- * this method can be used by command line utilities to configure the JRE
- * before the first request is sent.
+ * The popular libcurl library honors the <code>http_proxy</code>,
+ * <code>https_proxy</code> environment variables as a means of specifying
+ * an HTTP/S proxy for requests made behind a firewall. This is not natively
+ * recognized by the JRE, so this method can be used by command line
+ * utilities to configure the JRE before the first request is sent.
*
* @throws MalformedURLException
- * the value in <code>http_proxy</code> is unsupportable.
+ * the value in <code>http_proxy</code> or
+ * <code>https_proxy</code> is unsupportable.
*/
private static void configureHttpProxy() throws MalformedURLException {
- final String s = System.getenv("http_proxy"); //$NON-NLS-1$
- if (s == null || s.equals("")) //$NON-NLS-1$
- return;
+ for (String protocol : new String[] { "http", "https" }) { //$NON-NLS-1$ //$NON-NLS-2$
+ final String s = System.getenv(protocol + "_proxy"); //$NON-NLS-1$
+ if (s == null || s.equals("")) //$NON-NLS-1$
+ return;
- final URL u = new URL((s.indexOf("://") == -1) ? "http://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$
- if (!"http".equals(u.getProtocol())) //$NON-NLS-1$
- throw new MalformedURLException(MessageFormat.format(CLIText.get().invalidHttpProxyOnlyHttpSupported, s));
+ final URL u = new URL(
+ (s.indexOf("://") == -1) ? protocol + "://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!u.getProtocol().startsWith("http")) //$NON-NLS-1$
+ throw new MalformedURLException(MessageFormat.format(
+ CLIText.get().invalidHttpProxyOnlyHttpSupported, s));
- final String proxyHost = u.getHost();
- final int proxyPort = u.getPort();
+ final String proxyHost = u.getHost();
+ final int proxyPort = u.getPort();
- System.setProperty("http.proxyHost", proxyHost); //$NON-NLS-1$
- if (proxyPort > 0)
- System.setProperty("http.proxyPort", String.valueOf(proxyPort)); //$NON-NLS-1$
+ System.setProperty(protocol + ".proxyHost", proxyHost); //$NON-NLS-1$
+ if (proxyPort > 0)
+ System.setProperty(protocol + ".proxyPort", //$NON-NLS-1$
+ String.valueOf(proxyPort));
- final String userpass = u.getUserInfo();
- if (userpass != null && userpass.contains(":")) { //$NON-NLS-1$
- final int c = userpass.indexOf(':');
- final String user = userpass.substring(0, c);
- final String pass = userpass.substring(c + 1);
- CachedAuthenticator
- .add(new CachedAuthenticator.CachedAuthentication(
- proxyHost, proxyPort, user, pass));
+ final String userpass = u.getUserInfo();
+ if (userpass != null && userpass.contains(":")) { //$NON-NLS-1$
+ final int c = userpass.indexOf(':');
+ final String user = userpass.substring(0, c);
+ final String pass = userpass.substring(c + 1);
+ CachedAuthenticator.add(
+ new CachedAuthenticator.CachedAuthentication(proxyHost,
+ proxyPort, user, pass));
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index 93c4388..e0ff058 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -121,22 +121,23 @@
CLIText.get().refDoesNotExistOrNoCommit, ref));
Ref oldHead = db.getRef(Constants.HEAD);
- Git git = new Git(db);
- MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
- .setSquash(squash).setFastForward(ff).setCommit(!noCommit);
- if (srcRef != null)
- mergeCmd.include(srcRef);
- else
- mergeCmd.include(src);
-
- if (message != null)
- mergeCmd.setMessage(message);
-
MergeResult result;
- try {
- result = mergeCmd.call();
- } catch (CheckoutConflictException e) {
- result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT
+ try (Git git = new Git(db)) {
+ MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
+ .setSquash(squash).setFastForward(ff).setCommit(!noCommit);
+ if (srcRef != null)
+ mergeCmd.include(srcRef);
+ else
+ mergeCmd.include(src);
+
+ if (message != null)
+ mergeCmd.setMessage(message);
+
+ try {
+ result = mergeCmd.call();
+ } catch (CheckoutConflictException e) {
+ result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT
+ }
}
switch (result.getMergeStatus()) {
@@ -206,12 +207,13 @@
private boolean isMergedInto(Ref oldHead, AnyObjectId src)
throws IOException {
- RevWalk revWalk = new RevWalk(db);
- ObjectId oldHeadObjectId = oldHead.getPeeledObjectId();
- if (oldHeadObjectId == null)
- oldHeadObjectId = oldHead.getObjectId();
- RevCommit oldHeadCommit = revWalk.lookupCommit(oldHeadObjectId);
- RevCommit srcCommit = revWalk.lookupCommit(src);
- return revWalk.isMergedInto(oldHeadCommit, srcCommit);
+ try (RevWalk revWalk = new RevWalk(db)) {
+ ObjectId oldHeadObjectId = oldHead.getPeeledObjectId();
+ if (oldHeadObjectId == null)
+ oldHeadObjectId = oldHead.getObjectId();
+ RevCommit oldHeadCommit = revWalk.lookupCommit(oldHeadObjectId);
+ RevCommit srcCommit = revWalk.lookupCommit(src);
+ return revWalk.isMergedInto(oldHeadCommit, srcCommit);
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
index 4268f21..1879ef5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
@@ -109,24 +109,25 @@
@Override
protected void run() throws Exception {
- Git git = new Git(db);
- PushCommand push = git.push();
- push.setDryRun(dryRun);
- push.setForce(force);
- push.setProgressMonitor(new TextProgressMonitor(errw));
- push.setReceivePack(receivePack);
- push.setRefSpecs(refSpecs);
- if (all)
- push.setPushAll();
- if (tags)
- push.setPushTags();
- push.setRemote(remote);
- push.setThin(thin);
- push.setTimeout(timeout);
- Iterable<PushResult> results = push.call();
- for (PushResult result : results) {
- try (ObjectReader reader = db.newObjectReader()) {
- printPushResult(reader, result.getURI(), result);
+ try (Git git = new Git(db)) {
+ PushCommand push = git.push();
+ push.setDryRun(dryRun);
+ push.setForce(force);
+ push.setProgressMonitor(new TextProgressMonitor(errw));
+ push.setReceivePack(receivePack);
+ push.setRefSpecs(refSpecs);
+ if (all)
+ push.setPushAll();
+ if (tags)
+ push.setPushTags();
+ push.setRemote(remote);
+ push.setThin(thin);
+ push.setTimeout(timeout);
+ Iterable<PushResult> results = push.call();
+ for (PushResult result : results) {
+ try (ObjectReader reader = db.newObjectReader()) {
+ printPushResult(reader, result.getURI(), result);
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
index aa90f8d..86a021d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
@@ -59,13 +59,15 @@
@Override
protected void run() throws Exception {
- ReflogCommand cmd = new Git(db).reflog();
- if (ref != null)
- cmd.setRef(ref);
- Collection<ReflogEntry> entries = cmd.call();
- int i = 0;
- for (ReflogEntry entry : entries) {
- outw.println(toString(entry, i++));
+ try (Git git = new Git(db)) {
+ ReflogCommand cmd = git.reflog();
+ if (ref != null)
+ cmd.setRef(ref);
+ Collection<ReflogEntry> entries = cmd.call();
+ int i = 0;
+ for (ReflogEntry entry : entries) {
+ outw.println(toString(entry, i++));
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
index f4cbcaf..6d1b1c5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
@@ -66,19 +66,21 @@
@Override
protected void run() throws Exception {
- ResetCommand command = new Git(db).reset();
- command.setRef(commit);
- ResetType mode = null;
- if (soft)
- mode = selectMode(mode, ResetType.SOFT);
- if (mixed)
- mode = selectMode(mode, ResetType.MIXED);
- if (hard)
- mode = selectMode(mode, ResetType.HARD);
- if (mode == null)
- throw die("no reset mode set");
- command.setMode(mode);
- command.call();
+ try (Git git = new Git(db)) {
+ ResetCommand command = git.reset();
+ command.setRef(commit);
+ ResetType mode = null;
+ if (soft)
+ mode = selectMode(mode, ResetType.SOFT);
+ if (mixed)
+ mode = selectMode(mode, ResetType.MIXED);
+ if (hard)
+ mode = selectMode(mode, ResetType.HARD);
+ if (mode == null)
+ throw die("no reset mode set");
+ command.setMode(mode);
+ command.call();
+ }
}
private static ResetType selectMode(ResetType mode, ResetType want) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
index 816b310..f4f864b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java
@@ -63,10 +63,11 @@
@Override
protected void run() throws Exception {
- RmCommand command = new Git(db).rm();
- for (String p : paths)
- command.addFilepattern(p);
- command.call();
+ try (Git git = new Git(db)) {
+ RmCommand command = git.rm();
+ for (String p : paths)
+ command.addFilepattern(p);
+ command.call();
+ }
}
-
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
index b668139..c5986b0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
@@ -251,16 +251,17 @@
private void show(RevTree obj) throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
- final TreeWalk walk = new TreeWalk(db);
- walk.reset();
- walk.addTree(obj);
+ try (final TreeWalk walk = new TreeWalk(db)) {
+ walk.reset();
+ walk.addTree(obj);
- while (walk.next()) {
- outw.print(walk.getPathString());
- final FileMode mode = walk.getFileMode(0);
- if (mode == FileMode.TREE)
- outw.print("/"); //$NON-NLS-1$
- outw.println();
+ while (walk.next()) {
+ outw.print(walk.getPathString());
+ final FileMode mode = walk.getFileMode(0);
+ if (mode == FileMode.TREE)
+ outw.print("/"); //$NON-NLS-1$
+ outw.println();
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index 12d4208..be82d07 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -88,12 +88,14 @@
@Override
protected void run() throws Exception {
- StatusCommand statusCommand = new Git(db).status();
- if (filterPaths != null && filterPaths.size() > 0)
- for (String path : filterPaths)
- statusCommand.addPath(path);
- org.eclipse.jgit.api.Status status = statusCommand.call();
- printStatus(status);
+ try (Git git = new Git(db)) {
+ StatusCommand statusCommand = git.status();
+ if (filterPaths != null && filterPaths.size() > 0)
+ for (String path : filterPaths)
+ statusCommand.addPath(path);
+ org.eclipse.jgit.api.Status status = statusCommand.call();
+ printStatus(status);
+ }
}
private void printStatus(org.eclipse.jgit.api.Status status)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index a90d4c4..45fceb5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -79,26 +79,28 @@
@Override
protected void run() throws Exception {
- Git git = new Git(db);
- if (tagName != null) {
- TagCommand command = git.tag().setForceUpdate(force)
- .setMessage(message).setName(tagName);
+ try (Git git = new Git(db)) {
+ if (tagName != null) {
+ TagCommand command = git.tag().setForceUpdate(force)
+ .setMessage(message).setName(tagName);
- if (object != null) {
- RevWalk walk = new RevWalk(db);
- command.setObjectId(walk.parseAny(object));
- }
- try {
- command.call();
- } catch (RefAlreadyExistsException e) {
- throw die(MessageFormat.format(CLIText.get().tagAlreadyExists,
- tagName));
- }
- } else {
- ListTagCommand command = git.tagList();
- List<Ref> list = command.call();
- for (Ref ref : list) {
- outw.println(Repository.shortenRefName(ref.getName()));
+ if (object != null) {
+ try (RevWalk walk = new RevWalk(db)) {
+ command.setObjectId(walk.parseAny(object));
+ }
+ }
+ try {
+ command.call();
+ } catch (RefAlreadyExistsException e) {
+ throw die(MessageFormat.format(CLIText.get().tagAlreadyExists,
+ tagName));
+ }
+ } else {
+ ListTagCommand command = git.tagList();
+ List<Ref> list = command.call();
+ for (Ref ref : list) {
+ outw.println(Repository.shortenRefName(ref.getName()));
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
index 24d717d..df7ebb7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
@@ -173,9 +173,9 @@
int maxN = 0;
AbbreviatedObjectId startId;
- try (ObjectReader or = db.newObjectReader()) {
+ try (ObjectReader or = db.newObjectReader();
+ RevWalk rw = new RevWalk(or)) {
final MutableObjectId id = new MutableObjectId();
- RevWalk rw = new RevWalk(or);
TreeWalk tw = new TreeWalk(or);
tw.setFilter(TreeFilter.ANY_DIFF);
tw.setRecursive(true);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
index 7b5cdbf..d3eb245 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
@@ -75,7 +75,10 @@
@Override
protected void run() throws Exception {
ObjectReader reader = db.newObjectReader();
- RevObject obj = new RevWalk(reader).parseAny(objectId);
+ RevObject obj;
+ try (RevWalk rw = new RevWalk(reader)) {
+ obj = rw.parseAny(objectId);
+ }
byte[] delta = getDelta(reader, obj);
// We're crossing our fingers that this will be a delta. Double
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
index dcfa8cf..dcbc37b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
@@ -300,10 +300,10 @@
long fileCnt = 0;
long lineCnt = 0;
- try (ObjectReader or = db.newObjectReader()) {
- final MutableObjectId id = new MutableObjectId();
+ try (ObjectReader or = db.newObjectReader();
RevWalk rw = new RevWalk(or);
- TreeWalk tw = new TreeWalk(or);
+ TreeWalk tw = new TreeWalk(or)) {
+ final MutableObjectId id = new MutableObjectId();
tw.reset(rw.parseTree(db.resolve(Constants.HEAD)));
tw.setRecursive(true);
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 0c3edef..f059fdb 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,51 +2,51 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
- org.eclipse.jgit.api;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.api.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.attributes;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.awtui;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.blame;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.diff;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.dircache;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.events;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.fnmatch;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.gitrepo;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.hooks;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.ignore;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.ignore.internal;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.junit;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.merge;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.notes;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.patch;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.pgm;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.pgm.internal;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revplot;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.file;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.storage.pack;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.submodule;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.http;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport.resolver;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util.io;version="[4.0.3,4.1.0)",
+ org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.attributes;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.blame;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.events;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.fnmatch;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.hooks;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.ignore;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.notes;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.patch;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.submodule;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
org.hamcrest;version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)",
org.junit.experimental.theories;version="[4.4.0,5.0.0)",
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index ab77aec..be72211 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
index 3b2fa6c..ce11e1b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
@@ -202,6 +202,66 @@
fetchRefSpec(git2.getRepository()));
}
+ @Test
+ public void testCloneRepositoryCustomRemote() throws Exception {
+ File directory = createTempDirectory("testCloneRemoteUpstream");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setRemote("upstream");
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertEquals("+refs/heads/*:refs/remotes/upstream/*",
+ git2.getRepository()
+ .getConfig()
+ .getStringList("remote", "upstream",
+ "fetch")[0]);
+ assertEquals("upstream",
+ git2.getRepository()
+ .getConfig()
+ .getString("branch", "test", "remote"));
+ assertEquals(db.resolve("test"),
+ git2.getRepository().resolve("upstream/test"));
+ }
+
+ @Test
+ public void testBareCloneRepositoryCustomRemote() throws Exception {
+ File directory = createTempDirectory("testCloneRemoteUpstream_bare");
+ CloneCommand command = Git.cloneRepository();
+ command.setBare(true);
+ command.setDirectory(directory);
+ command.setRemote("upstream");
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertEquals("+refs/heads/*:refs/heads/*",
+ git2.getRepository()
+ .getConfig()
+ .getStringList("remote", "upstream",
+ "fetch")[0]);
+ assertEquals("upstream",
+ git2.getRepository()
+ .getConfig()
+ .getString("branch", "test", "remote"));
+ assertNull(git2.getRepository().resolve("upstream/test"));
+ }
+
+ @Test
+ public void testBareCloneRepositoryNullRemote() throws Exception {
+ File directory = createTempDirectory("testCloneRemoteNull_bare");
+ CloneCommand command = Git.cloneRepository();
+ command.setBare(true);
+ command.setDirectory(directory);
+ command.setRemote(null);
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertEquals("+refs/heads/*:refs/heads/*", git2.getRepository()
+ .getConfig().getStringList("remote", "origin", "fetch")[0]);
+ assertEquals("origin", git2.getRepository().getConfig()
+ .getString("branch", "test", "remote"));
+ }
+
public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
RemoteConfig remoteConfig =
new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
@@ -391,6 +451,17 @@
git.add().addFilepattern(path)
.addFilepattern(Constants.DOT_GIT_MODULES).call();
git.commit().setMessage("adding submodule").call();
+ try (SubmoduleWalk walk = SubmoduleWalk.forIndex(git.getRepository())) {
+ assertTrue(walk.next());
+ Repository subRepo = walk.getRepository();
+ addRepoToClose(subRepo);
+ assertNotNull(subRepo);
+ assertEquals(
+ new File(git.getRepository().getWorkTree(), walk.getPath()),
+ subRepo.getWorkTree());
+ assertEquals(new File(new File(git.getRepository().getDirectory(),
+ "modules"), walk.getPath()), subRepo.getDirectory());
+ }
File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
CloneCommand clone = Git.cloneRepository();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java
index 95b1419..ce235a7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java
@@ -609,7 +609,7 @@
} catch (JGitInternalException e) {
assertEquals(MessageFormat.format(
JGitText.get().stashCommitIncorrectNumberOfParents,
- head.name(), 0),
+ head.name(), "0"),
e.getMessage());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index 02e485d..58348d5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -241,8 +241,7 @@
ObjectId bId = blob("b\n");
String diffHeader = makeDiffHeaderModeChange(PATH_A, PATH_A, aId, bId,
- GITLINK, REGULAR_FILE)
- + "-Subproject commit " + aId.name() + "\n";
+ GITLINK, REGULAR_FILE);
DiffEntry ad = DiffEntry.delete(PATH_A, aId);
ad.oldMode = FileMode.GITLINK;
@@ -257,7 +256,69 @@
assertEquals(1, fh.getHunks().size());
HunkHeader hh = fh.getHunks().get(0);
- assertEquals(0, hh.toEditList().size());
+ assertEquals(1, hh.toEditList().size());
+ }
+
+ @Test
+ public void testCreateFileHeader_AddGitLink() throws Exception {
+ ObjectId adId = blob("a\nd\n");
+ DiffEntry ent = DiffEntry.add("FOO", adId);
+ ent.newMode = FileMode.GITLINK;
+ FileHeader fh = df.toFileHeader(ent);
+
+ String diffHeader = "diff --git a/FOO b/FOO\n" //
+ + "new file mode " + GITLINK + "\n"
+ + "index "
+ + ObjectId.zeroId().abbreviate(8).name()
+ + ".."
+ + adId.abbreviate(8).name() + "\n" //
+ + "--- /dev/null\n"//
+ + "+++ b/FOO\n";
+ assertEquals(diffHeader, RawParseUtils.decode(fh.getBuffer()));
+
+ assertEquals(1, fh.getHunks().size());
+ HunkHeader hh = fh.getHunks().get(0);
+
+ EditList el = hh.toEditList();
+ assertEquals(1, el.size());
+
+ Edit e = el.get(0);
+ assertEquals(0, e.getBeginA());
+ assertEquals(0, e.getEndA());
+ assertEquals(0, e.getBeginB());
+ assertEquals(1, e.getEndB());
+ assertEquals(Edit.Type.INSERT, e.getType());
+ }
+
+ @Test
+ public void testCreateFileHeader_DeleteGitLink() throws Exception {
+ ObjectId adId = blob("a\nd\n");
+ DiffEntry ent = DiffEntry.delete("FOO", adId);
+ ent.oldMode = FileMode.GITLINK;
+ FileHeader fh = df.toFileHeader(ent);
+
+ String diffHeader = "diff --git a/FOO b/FOO\n" //
+ + "deleted file mode " + GITLINK + "\n"
+ + "index "
+ + adId.abbreviate(8).name()
+ + ".."
+ + ObjectId.zeroId().abbreviate(8).name() + "\n" //
+ + "--- a/FOO\n"//
+ + "+++ /dev/null\n";
+ assertEquals(diffHeader, RawParseUtils.decode(fh.getBuffer()));
+
+ assertEquals(1, fh.getHunks().size());
+ HunkHeader hh = fh.getHunks().get(0);
+
+ EditList el = hh.toEditList();
+ assertEquals(1, el.size());
+
+ Edit e = el.get(0);
+ assertEquals(0, e.getBeginA());
+ assertEquals(1, e.getEndA());
+ assertEquals(0, e.getBeginB());
+ assertEquals(0, e.getEndB());
+ assertEquals(Edit.Type.DELETE, e.getType());
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 3d86cfd..66e7256 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -241,9 +241,9 @@
@Test
public void testBareRepo() throws Exception {
- Repository remoteDb = createBareRepository();
- Repository tempDb = createWorkRepository();
- try {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
StringBuilder xmlContent = new StringBuilder();
xmlContent
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
@@ -280,9 +280,6 @@
String remote = defaultDb.resolve(Constants.HEAD).name();
assertEquals("The gitlink should be the same as remote head",
remote, gitlink);
- } finally {
- tempDb.close();
- remoteDb.close();
}
}
@@ -366,9 +363,9 @@
@Test
public void testRevisionBare() throws Exception {
- Repository remoteDb = createBareRepository();
- Repository tempDb = createWorkRepository();
- try {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
StringBuilder xmlContent = new StringBuilder();
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
.append("<manifest>")
@@ -393,17 +390,14 @@
localDb.close();
assertEquals("The gitlink is same as remote head",
oldCommitId.name(), gitlink);
- } finally {
- tempDb.close();
- remoteDb.close();
}
}
@Test
public void testCopyFileBare() throws Exception {
- Repository remoteDb = createBareRepository();
- Repository tempDb = createWorkRepository();
- try {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
StringBuilder xmlContent = new StringBuilder();
xmlContent
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
@@ -435,17 +429,14 @@
reader.close();
assertEquals("The Hello file should have expected content",
"branch world", content);
- } finally {
- tempDb.close();
- remoteDb.close();
}
}
@Test
public void testReplaceManifestBare() throws Exception {
- Repository remoteDb = createBareRepository();
- Repository tempDb = createWorkRepository();
- try {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
StringBuilder xmlContent = new StringBuilder();
xmlContent
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
@@ -512,17 +503,14 @@
reader.close();
assertTrue("The bar submodule should exist", bar);
assertFalse("The foo submodule shouldn't exist", foo);
- } finally {
- tempDb.close();
- remoteDb.close();
}
}
@Test
public void testRemoveOverlappingBare() throws Exception {
- Repository remoteDb = createBareRepository();
- Repository tempDb = createWorkRepository();
- try {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
StringBuilder xmlContent = new StringBuilder();
xmlContent
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
@@ -571,9 +559,6 @@
assertTrue("The foo submodule should exist", foo);
assertFalse("The foo/bar submodule shouldn't exist", foobar);
assertTrue("The a submodule should exist", a);
- } finally {
- tempDb.close();
- remoteDb.close();
}
}
@@ -671,6 +656,42 @@
assertTrue("We should have foo", file.exists());
}
+ @Test
+ public void testTargetBranch() throws Exception {
+ try (
+ Repository remoteDb1 = createBareRepository();
+ Repository remoteDb2 = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
+ StringBuilder xmlContent = new StringBuilder();
+ xmlContent
+ .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+ .append("<manifest>")
+ .append("<remote name=\"remote1\" fetch=\".\" />")
+ .append("<default revision=\"master\" remote=\"remote1\" />")
+ .append("<project path=\"foo\" name=\"").append(defaultUri)
+ .append("\" />").append("</manifest>");
+ JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+ xmlContent.toString());
+ RepoCommand command = new RepoCommand(remoteDb1);
+ command
+ .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+ .setURI(rootUri)
+ .setTargetBranch("test")
+ .call();
+ ObjectId branchId = remoteDb1.resolve(
+ Constants.R_HEADS + "test^{tree}");
+ command = new RepoCommand(remoteDb2);
+ command
+ .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+ .setURI(rootUri)
+ .call();
+ ObjectId defaultId = remoteDb2.resolve(Constants.HEAD + "^{tree}");
+ assertEquals(
+ "The tree id of branch db and default db should be the same",
+ branchId, defaultId);
+ }
+ }
+
private void resolveRelativeUris() {
// Find the longest common prefix ends with "/" as rootUri.
defaultUri = defaultDb.getDirectory().toURI().toString();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
index a4b799a..2c04787 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
@@ -55,6 +55,7 @@
@Test
public void testSimpleCharClass() {
assertMatched("[a]", "a");
+ assertMatched("][a]", "]a");
assertMatched("[a]", "a/");
assertMatched("[a]", "a/b");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
index 571f318..9722ac6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
@@ -44,12 +44,15 @@
import static org.eclipse.jgit.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -324,6 +327,15 @@
}
@Test
+ public void testEmptyIgnoreRules() throws IOException {
+ IgnoreNode node = new IgnoreNode();
+ node.parse(writeToString("", "#", "!", "[[=a=]]"));
+ assertEquals(new ArrayList<>(), node.getRules());
+ node.parse(writeToString(" ", " / "));
+ assertEquals(2, node.getRules().size());
+ }
+
+ @Test
public void testSlashOnlyMatchesDirectory() throws IOException {
writeIgnoreFile(".gitignore", "out/");
writeTrashFile("out", "");
@@ -343,6 +355,56 @@
}
@Test
+ public void testSlashMatchesDirectory() throws IOException {
+ writeIgnoreFile(".gitignore", "out2/");
+
+ writeTrashFile("out1/out1", "");
+ writeTrashFile("out1/out2", "");
+ writeTrashFile("out2/out1", "");
+ writeTrashFile("out2/out2", "");
+
+ beginWalk();
+ assertEntry(F, tracked, ".gitignore");
+ assertEntry(D, tracked, "out1");
+ assertEntry(F, tracked, "out1/out1");
+ assertEntry(F, tracked, "out1/out2");
+ assertEntry(D, ignored, "out2");
+ assertEntry(F, ignored, "out2/out1");
+ assertEntry(F, ignored, "out2/out2");
+ endWalk();
+ }
+
+ @Test
+ public void testWildcardWithSlashMatchesDirectory() throws IOException {
+ writeIgnoreFile(".gitignore", "out2*/");
+
+ writeTrashFile("out1/out1.txt", "");
+ writeTrashFile("out1/out2", "");
+ writeTrashFile("out1/out2.txt", "");
+ writeTrashFile("out1/out2x/a", "");
+ writeTrashFile("out2/out1.txt", "");
+ writeTrashFile("out2/out2.txt", "");
+ writeTrashFile("out2x/out1.txt", "");
+ writeTrashFile("out2x/out2.txt", "");
+
+ beginWalk();
+ assertEntry(F, tracked, ".gitignore");
+ assertEntry(D, tracked, "out1");
+ assertEntry(F, tracked, "out1/out1.txt");
+ assertEntry(F, tracked, "out1/out2");
+ assertEntry(F, tracked, "out1/out2.txt");
+ assertEntry(D, ignored, "out1/out2x");
+ assertEntry(F, ignored, "out1/out2x/a");
+ assertEntry(D, ignored, "out2");
+ assertEntry(F, ignored, "out2/out1.txt");
+ assertEntry(F, ignored, "out2/out2.txt");
+ assertEntry(D, ignored, "out2x");
+ assertEntry(F, ignored, "out2x/out1.txt");
+ assertEntry(F, ignored, "out2x/out2.txt");
+ endWalk();
+ }
+
+ @Test
public void testWithSlashDoesNotMatchInSubDirectory() throws IOException {
writeIgnoreFile(".gitignore", "a/b");
writeTrashFile("a/a", "");
@@ -375,6 +437,67 @@
}
@Test
+ public void testLeadingSpaces() throws IOException {
+ writeTrashFile(" a/ a", "");
+ writeTrashFile(" a/ a", "");
+ writeTrashFile(" a/a", "");
+ writeTrashFile(" a/ a", "");
+ writeTrashFile(" a/ a", "");
+ writeTrashFile(" a/a", "");
+ writeIgnoreFile(".gitignore", " a", " a");
+ writeTrashFile("a/ a", "");
+ writeTrashFile("a/ a", "");
+ writeTrashFile("a/a", "");
+
+ beginWalk();
+ assertEntry(D, ignored, " a");
+ assertEntry(F, ignored, " a/ a");
+ assertEntry(F, ignored, " a/ a");
+ assertEntry(F, ignored, " a/a");
+ assertEntry(D, ignored, " a");
+ assertEntry(F, ignored, " a/ a");
+ assertEntry(F, ignored, " a/ a");
+ assertEntry(F, ignored, " a/a");
+ assertEntry(F, tracked, ".gitignore");
+ assertEntry(D, tracked, "a");
+ assertEntry(F, ignored, "a/ a");
+ assertEntry(F, ignored, "a/ a");
+ assertEntry(F, tracked, "a/a");
+ endWalk();
+ }
+
+ @Test
+ public void testTrailingSpaces() throws IOException {
+ writeTrashFile("a /a", "");
+ writeTrashFile("a /a ", "");
+ writeTrashFile("a /a ", "");
+ writeTrashFile("a /a", "");
+ writeTrashFile("a /a ", "");
+ writeTrashFile("a /a ", "");
+ writeTrashFile("a/a", "");
+ writeTrashFile("a/a ", "");
+ writeTrashFile("a/a ", "");
+
+ writeIgnoreFile(".gitignore", "a\\ ", "a \\ ");
+
+ beginWalk();
+ assertEntry(F, tracked, ".gitignore");
+ assertEntry(D, ignored, "a ");
+ assertEntry(F, ignored, "a /a");
+ assertEntry(F, ignored, "a /a ");
+ assertEntry(F, ignored, "a /a ");
+ assertEntry(D, ignored, "a ");
+ assertEntry(F, ignored, "a /a");
+ assertEntry(F, ignored, "a /a ");
+ assertEntry(F, ignored, "a /a ");
+ assertEntry(D, tracked, "a");
+ assertEntry(F, tracked, "a/a");
+ assertEntry(F, ignored, "a/a ");
+ assertEntry(F, ignored, "a/a ");
+ endWalk();
+ }
+
+ @Test
public void testToString() throws Exception {
assertEquals(Arrays.asList("").toString(), new IgnoreNode().toString());
assertEquals(Arrays.asList("hello").toString(),
@@ -411,4 +534,12 @@
data.append(line + "\n");
writeTrashFile(name, data.toString());
}
+
+ private InputStream writeToString(String... rules) throws IOException {
+ StringBuilder data = new StringBuilder();
+ for (String line : rules) {
+ data.append(line + "\n");
+ }
+ return new ByteArrayInputStream(data.toString().getBytes("UTF-8"));
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
index a7a78f8..f8eb126 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
@@ -830,9 +830,45 @@
}
@Test
+ public void testIgnoredBackslash() throws Exception {
+ // In Git CLI a\b\c is equal to abc
+ assertMatch("a\\b\\c", "abc", true);
+ }
+
+ @Test
public void testEscapedBackslash() throws Exception {
// In Git CLI a\\b matches a\b file
assertMatch("a\\\\b", "a\\b", true);
+ assertMatch("a\\\\b\\c", "a\\bc", true);
+
+ }
+
+ @Test
+ public void testEscapedExclamationMark() throws Exception {
+ assertMatch("\\!b!.txt", "!b!.txt", true);
+ assertMatch("a\\!b!.txt", "a!b!.txt", true);
+ }
+
+ @Test
+ public void testEscapedHash() throws Exception {
+ assertMatch("\\#b", "#b", true);
+ assertMatch("a\\#", "a#", true);
+ }
+
+ @Test
+ public void testEscapedTrailingSpaces() throws Exception {
+ assertMatch("\\ ", " ", true);
+ assertMatch("a\\ ", "a ", true);
+ }
+
+ @Test
+ public void testNotEscapingBackslash() throws Exception {
+ assertMatch("\\out", "out", true);
+ assertMatch("\\out", "a/out", true);
+ assertMatch("c:\\/", "c:/", true);
+ assertMatch("c:\\/", "a/c:/", true);
+ assertMatch("c:\\tmp", "c:tmp", true);
+ assertMatch("c:\\tmp", "a/c:tmp", true);
}
@Test
@@ -841,6 +877,100 @@
}
@Test
+ public void testBackslash() throws Exception {
+ assertMatch("a\\", "a", true);
+ assertMatch("\\a", "a", true);
+ assertMatch("a/\\", "a/", true);
+ assertMatch("a/b\\", "a/b", true);
+ assertMatch("\\a/b", "a/b", true);
+ assertMatch("/\\a", "/a", true);
+ assertMatch("\\a\\b\\c\\", "abc", true);
+ assertMatch("/\\a/\\b/\\c\\", "a/b/c", true);
+
+ // empty path segment doesn't match
+ assertMatch("\\/a", "/a", false);
+ assertMatch("\\/a", "a", false);
+ }
+
+ @Test
+ public void testDollar() throws Exception {
+ assertMatch("$", "$", true);
+ assertMatch("$x", "$x", true);
+ assertMatch("$x", "x$", false);
+ assertMatch("$x", "$", false);
+
+ assertMatch("$x.*", "$x.a", true);
+ assertMatch("*$", "x$", true);
+ assertMatch("*.$", "x.$", true);
+
+ assertMatch("$*x", "$ax", true);
+ assertMatch("x*$", "xa$", true);
+ assertMatch("x*$", "xa", false);
+ assertMatch("[a$b]", "$", true);
+ }
+
+ @Test
+ public void testCaret() throws Exception {
+ assertMatch("^", "^", true);
+ assertMatch("^x", "^x", true);
+ assertMatch("^x", "x^", false);
+ assertMatch("^x", "^", false);
+
+ assertMatch("^x.*", "^x.a", true);
+ assertMatch("*^", "x^", true);
+ assertMatch("*.^", "x.^", true);
+
+ assertMatch("x*^", "xa^", true);
+ assertMatch("^*x", "^ax", true);
+ assertMatch("^*x", "ax", false);
+ assertMatch("[a^b]", "^", true);
+ }
+
+ @Test
+ public void testPlus() throws Exception {
+ assertMatch("+", "+", true);
+ assertMatch("+x", "+x", true);
+ assertMatch("+x", "x+", false);
+ assertMatch("+x", "+", false);
+ assertMatch("x+", "xx", false);
+
+ assertMatch("+x.*", "+x.a", true);
+ assertMatch("*+", "x+", true);
+ assertMatch("*.+", "x.+", true);
+
+ assertMatch("x*+", "xa+", true);
+ assertMatch("+*x", "+ax", true);
+ assertMatch("+*x", "ax", false);
+ assertMatch("[a+b]", "+", true);
+ }
+
+ @Test
+ public void testPipe() throws Exception {
+ assertMatch("|", "|", true);
+ assertMatch("|x", "|x", true);
+ assertMatch("|x", "x|", false);
+ assertMatch("|x", "|", false);
+ assertMatch("x|x", "xx", false);
+
+ assertMatch("x|x.*", "x|x.a", true);
+ assertMatch("*|", "x|", true);
+ assertMatch("*.|", "x.|", true);
+
+ assertMatch("x*|a", "xb|a", true);
+ assertMatch("b|*x", "b|ax", true);
+ assertMatch("b|*x", "ax", false);
+ assertMatch("[a|b]", "|", true);
+ }
+
+ @Test
+ public void testBrackets() throws Exception {
+ assertMatch("{}*()", "{}x()", true);
+ assertMatch("[a{}()b][a{}()b]?[a{}()b][a{}()b]", "{}x()", true);
+ assertMatch("x*{x}3", "xa{x}3", true);
+ assertMatch("a*{x}3", "axxx", false);
+ }
+
+ @Test
public void testFilePathSimpleCase() throws Exception {
assertFileNameMatch("a/b", "a/b", true);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index 8dbe644..d66753d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -359,6 +359,33 @@
}
@Test
+ public void testFirstExactRef_IgnoresGarbageRef() throws IOException {
+ writeLooseRef("refs/heads/A", A);
+ write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "FAIL\n");
+
+ Ref a = refdir.firstExactRef("refs/heads/bad", "refs/heads/A");
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals(A, a.getObjectId());
+ }
+
+ @Test
+ public void testExactRef_IgnoresGarbageRef() throws IOException {
+ writeLooseRef("refs/heads/A", A);
+ write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "FAIL\n");
+
+ Map<String, Ref> refs =
+ refdir.exactRef("refs/heads/bad", "refs/heads/A");
+
+ assertNull("no refs/heads/bad", refs.get("refs/heads/bad"));
+
+ Ref a = refs.get("refs/heads/A");
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals(A, a.getObjectId());
+
+ assertEquals(1, refs.size());
+ }
+
+ @Test
public void testGetRefs_InvalidName() throws IOException {
writeLooseRef("refs/heads/A", A);
@@ -464,6 +491,21 @@
}
@Test
+ public void testFirstExactRef_Mixed() throws IOException {
+ writeLooseRef("refs/heads/A", A);
+ writePackedRef("refs/tags/v1.0", v1_0);
+
+ Ref a = refdir.firstExactRef("refs/heads/A", "refs/tags/v1.0");
+ Ref one = refdir.firstExactRef("refs/tags/v1.0", "refs/heads/A");
+
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals("refs/tags/v1.0", one.getName());
+
+ assertEquals(A, a.getObjectId());
+ assertEquals(v1_0, one.getObjectId());
+ }
+
+ @Test
public void testGetRefs_TagsOnly_AllLoose() throws IOException {
Map<String, Ref> tags;
Ref a;
@@ -983,6 +1025,25 @@
}
@Test
+ public void testExactRef_EmptyDatabase() throws IOException {
+ Ref r;
+
+ r = refdir.exactRef(HEAD);
+ assertTrue(r.isSymbolic());
+ assertSame(LOOSE, r.getStorage());
+ assertEquals("refs/heads/master", r.getTarget().getName());
+ assertSame(NEW, r.getTarget().getStorage());
+ assertNull(r.getTarget().getObjectId());
+
+ assertNull(refdir.exactRef("refs/heads/master"));
+ assertNull(refdir.exactRef("refs/tags/v1.0"));
+ assertNull(refdir.exactRef("FETCH_HEAD"));
+ assertNull(refdir.exactRef("NOT.A.REF.NAME"));
+ assertNull(refdir.exactRef("master"));
+ assertNull(refdir.exactRef("v1.0"));
+ }
+
+ @Test
public void testGetRef_FetchHead() throws IOException {
// This is an odd special case where we need to make sure we read
// exactly the first 40 bytes of the file and nothing further on
@@ -1000,6 +1061,23 @@
}
@Test
+ public void testExactRef_FetchHead() throws IOException {
+ // This is an odd special case where we need to make sure we read
+ // exactly the first 40 bytes of the file and nothing further on
+ // that line, or the remainder of the file.
+ write(new File(diskRepo.getDirectory(), "FETCH_HEAD"), A.name()
+ + "\tnot-for-merge"
+ + "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
+
+ Ref r = refdir.exactRef("FETCH_HEAD");
+ assertFalse(r.isSymbolic());
+ assertEquals(A, r.getObjectId());
+ assertEquals("FETCH_HEAD", r.getName());
+ assertFalse(r.isPeeled());
+ assertNull(r.getPeeledObjectId());
+ }
+
+ @Test
public void testGetRef_AnyHeadWithGarbage() throws IOException {
write(new File(diskRepo.getDirectory(), "refs/heads/A"), A.name()
+ "012345 . this is not a standard reference\n"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
index db31fd3..6238a35 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -51,7 +51,6 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -503,27 +502,6 @@
}
@Test
- public void testEmptyString() throws ConfigInvalidException {
- Config c = parse("[my]\n\tempty =\n");
- assertNull(c.getString("my", null, "empty"));
-
- String[] values = c.getStringList("my", null, "empty");
- assertNotNull(values);
- assertEquals(1, values.length);
- assertNull(values[0]);
-
- // always matches the default, because its non-boolean
- assertTrue(c.getBoolean("my", "empty", true));
- assertFalse(c.getBoolean("my", "empty", false));
-
- assertEquals("[my]\n\tempty =\n", c.toText());
-
- c = new Config();
- c.setStringList("my", null, "empty", Arrays.asList(values));
- assertEquals("[my]\n\tempty =\n", c.toText());
- }
-
- @Test
public void testUnsetBranchSection() throws ConfigInvalidException {
Config c = parse("" //
+ "[branch \"keep\"]\n"
@@ -699,6 +677,68 @@
assertEquals("1", c.getString("a", null, "y"));
}
+ @Test
+ public void testExplicitlySetEmptyString() throws Exception {
+ Config c = new Config();
+ c.setString("a", null, "x", "0");
+ c.setString("a", null, "y", "");
+
+ assertEquals("0", c.getString("a", null, "x"));
+ assertEquals(0, c.getInt("a", null, "x", 1));
+
+ assertEquals("", c.getString("a", null, "y"));
+ assertArrayEquals(new String[]{""}, c.getStringList("a", null, "y"));
+ try {
+ c.getInt("a", null, "y", 1);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid integer value: a.y=", e.getMessage());
+ }
+
+ assertNull(c.getString("a", null, "z"));
+ assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
+ }
+
+ @Test
+ public void testParsedEmptyString() throws Exception {
+ Config c = parse("[a]\n"
+ + "x = 0\n"
+ + "y =\n");
+
+ assertEquals("0", c.getString("a", null, "x"));
+ assertEquals(0, c.getInt("a", null, "x", 1));
+
+ assertNull(c.getString("a", null, "y"));
+ assertArrayEquals(new String[]{null}, c.getStringList("a", null, "y"));
+ try {
+ c.getInt("a", null, "y", 1);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid integer value: a.y=", e.getMessage());
+ }
+
+ assertNull(c.getString("a", null, "z"));
+ assertArrayEquals(new String[]{}, c.getStringList("a", null, "z"));
+ }
+
+ @Test
+ public void testSetStringListWithEmptyValue() throws Exception {
+ Config c = new Config();
+ c.setStringList("a", null, "x", Arrays.asList(""));
+ assertArrayEquals(new String[]{""}, c.getStringList("a", null, "x"));
+ }
+
+ @Test
+ public void testEmptyValueAtEof() throws Exception {
+ String text = "[a]\nx =";
+ Config c = parse(text);
+ assertNull(c.getString("a", null, "x"));
+ assertArrayEquals(new String[]{null},
+ c.getStringList("a", null, "x"));
+ c = parse(text + "\n");
+ assertNull(c.getString("a", null, "x"));
+ assertArrayEquals(new String[]{null},
+ c.getStringList("a", null, "x"));
+ }
+
private static void assertReadLong(long exp) throws ConfigInvalidException {
assertReadLong(exp, String.valueOf(exp));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index 274757d..3abe81c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -1810,6 +1810,17 @@
}
@Test
+ public void testBug477090() throws CorruptObjectException {
+ checker.setSafeForMacOS(true);
+ final byte[] bytes = {
+ // U+221E 0xe2889e INFINITY ∞
+ (byte) 0xe2, (byte) 0x88, (byte) 0x9e,
+ // .html
+ 0x2e, 0x68, 0x74, 0x6d, 0x6c };
+ checker.checkPathSegment(bytes, 0, bytes.length);
+ }
+
+ @Test
public void testRejectDotAtEndOnWindows() {
checker.setSafeForWindows(true);
try {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
index abf57d6..2198b87 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
@@ -49,6 +49,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import org.eclipse.jgit.errors.InvalidObjectIdException;
+
import org.junit.Test;
public class ObjectIdTest {
@@ -124,6 +126,21 @@
assertEquals(x.toLowerCase(), oid.name());
}
+ @Test(expected = InvalidObjectIdException.class)
+ public void testFromString_short() {
+ ObjectId.fromString("cafe1234");
+ }
+
+ @Test(expected = InvalidObjectIdException.class)
+ public void testFromString_nonHex() {
+ ObjectId.fromString("0123456789abcdefghij0123456789abcdefghij");
+ }
+
+ @Test(expected = InvalidObjectIdException.class)
+ public void testFromString_shortNonHex() {
+ ObjectId.fromString("6789ghij");
+ }
+
@Test
public void testGetByte() {
byte[] raw = new byte[20];
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
index f2ed684..109f401 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
@@ -84,6 +84,12 @@
}
}
+ private void writeNewRef(String name, ObjectId value) throws IOException {
+ RefUpdate updateRef = db.updateRef(name);
+ updateRef.setNewObjectId(value);
+ assertEquals(RefUpdate.Result.NEW, updateRef.update());
+ }
+
@Test
public void testRemoteNames() throws Exception {
FileBasedConfig config = db.getConfig();
@@ -192,6 +198,50 @@
assertEquals(Storage.LOOSE, ref.getStorage());
}
+ @Test
+ public void testGetShortRef() throws IOException {
+ Ref ref = db.getRef("master");
+ assertEquals("refs/heads/master", ref.getName());
+ assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+ }
+
+ @Test
+ public void testGetShortExactRef() throws IOException {
+ assertNull(db.getRefDatabase().exactRef("master"));
+
+ Ref ref = db.getRefDatabase().exactRef("HEAD");
+ assertEquals("HEAD", ref.getName());
+ assertEquals("refs/heads/master", ref.getTarget().getName());
+ assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+ }
+
+ @Test
+ public void testRefsUnderRefs() throws IOException {
+ ObjectId masterId = db.resolve("refs/heads/master");
+ writeNewRef("refs/heads/refs/foo/bar", masterId);
+
+ assertNull(db.getRefDatabase().exactRef("refs/foo/bar"));
+
+ Ref ref = db.getRef("refs/foo/bar");
+ assertEquals("refs/heads/refs/foo/bar", ref.getName());
+ assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+ }
+
+ @Test
+ public void testAmbiguousRefsUnderRefs() throws IOException {
+ ObjectId masterId = db.resolve("refs/heads/master");
+ writeNewRef("refs/foo/bar", masterId);
+ writeNewRef("refs/heads/refs/foo/bar", masterId);
+
+ Ref exactRef = db.getRefDatabase().exactRef("refs/foo/bar");
+ assertEquals("refs/foo/bar", exactRef.getName());
+ assertEquals(masterId, exactRef.getObjectId());
+
+ Ref ref = db.getRef("refs/foo/bar");
+ assertEquals("refs/foo/bar", ref.getName());
+ assertEquals(masterId, ref.getObjectId());
+ }
+
/**
* Let an "outsider" create a loose ref with the same name as a packed one
*
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
index 0cab987..6c62925 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
@@ -43,11 +43,13 @@
package org.eclipse.jgit.lib;
+import static org.hamcrest.CoreMatchers.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -147,4 +149,28 @@
d2.close();
d2.close();
}
+
+ @Test
+ public void testGetRegisteredWhenEmpty() {
+ assertEquals(0, RepositoryCache.getRegisteredKeys().size());
+ }
+
+ @Test
+ public void testGetRegistered() {
+ RepositoryCache.register(db);
+
+ assertThat(RepositoryCache.getRegisteredKeys(),
+ hasItem(FileKey.exact(db.getDirectory(), db.getFS())));
+ assertEquals(1, RepositoryCache.getRegisteredKeys().size());
+ }
+
+ @Test
+ public void testUnregister() {
+ RepositoryCache.register(db);
+ RepositoryCache
+ .unregister(FileKey.exact(db.getDirectory(), db.getFS()));
+
+ assertEquals(0, RepositoryCache.getRegisteredKeys().size());
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
index 19e495b..7ef6448 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
@@ -60,6 +60,7 @@
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
@@ -308,7 +309,7 @@
if (indexState != IndexState.Bare)
assertEquals(
"[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side\n]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
if (worktreeState != WorktreeState.Bare
&& worktreeState != WorktreeState.Missing)
assertEquals(
@@ -393,7 +394,7 @@
if (indexState != IndexState.Bare)
assertEquals(
"[f, mode:100644, content:1-master-r\n2\n3-side-r\n]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
if (worktreeState != WorktreeState.Bare
&& worktreeState != WorktreeState.Missing)
assertEquals(
@@ -478,7 +479,7 @@
if (indexState != IndexState.Bare)
assertEquals(
"[f, mode:100644, content:1\nx(side)\n2\n3\ny(side-again)\n]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
if (worktreeState != WorktreeState.Bare
&& worktreeState != WorktreeState.Missing)
assertEquals("1\nx(side)\n2\n3\ny(side-again)\n", read("f"));
@@ -561,7 +562,7 @@
if (indexState != IndexState.Bare)
assertEquals(
"[f, mode:100644, content:1-master-r\n2\n3-side-r\n][m.c, mode:100644, content:0][m.m, mode:100644, content:1][s.c, mode:100644, content:0][s.m, mode:100644, content:1]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
if (worktreeState != WorktreeState.Bare
&& worktreeState != WorktreeState.Missing) {
assertEquals(
@@ -638,7 +639,7 @@
"[f, mode:100644, stage:1, content:1-master\n2\n3\n4\n5\n6\n7\n8\n9-side\n]"
+ "[f, mode:100644, stage:2, content:1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n]"
+ "[f, mode:100644, stage:3, content:1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
assertEquals(
"1-master\n2\n3\n4\n5\n6\n<<<<<<< OURS\n7-conflict\n=======\n7-res(side)\n>>>>>>> THEIRS\n8\n9-side\n",
read("f"));
@@ -736,7 +737,7 @@
if (indexState != IndexState.Bare)
assertEquals(
"[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side\n]",
- indexState(RepositoryTestCase.CONTENT));
+ indexState(LocalDiskRepositoryTestCase.CONTENT));
if (worktreeState != WorktreeState.Bare
&& worktreeState != WorktreeState.Missing)
assertEquals(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
index 478a93b..cd6a4be 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
@@ -227,6 +227,80 @@
}
/**
+ * A tracked file is replaced by a folder in THEIRS.
+ *
+ * @param strategy
+ * @throws Exception
+ */
+ @Theory
+ public void checkFileReplacedByFolderInTheirs(MergeStrategy strategy)
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("sub", "file");
+ git.add().addFilepattern("sub").call();
+ RevCommit first = git.commit().setMessage("initial").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(first)
+ .setName("side").call();
+
+ git.rm().addFilepattern("sub").call();
+ writeTrashFile("sub/file", "subfile");
+ git.add().addFilepattern("sub/file").call();
+ RevCommit masterCommit = git.commit().setMessage("file -> folder")
+ .call();
+
+ git.checkout().setName("master").call();
+ writeTrashFile("noop", "other");
+ git.add().addFilepattern("noop").call();
+ git.commit().setAll(true).setMessage("noop").call();
+
+ MergeResult mergeRes = git.merge().setStrategy(strategy)
+ .include(masterCommit).call();
+ assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
+ assertEquals(
+ "[noop, mode:100644, content:other][sub/file, mode:100644, content:subfile]",
+ indexState(CONTENT));
+ }
+
+ /**
+ * A tracked file is replaced by a folder in OURS.
+ *
+ * @param strategy
+ * @throws Exception
+ */
+ @Theory
+ public void checkFileReplacedByFolderInOurs(MergeStrategy strategy)
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("sub", "file");
+ git.add().addFilepattern("sub").call();
+ RevCommit first = git.commit().setMessage("initial").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(first)
+ .setName("side").call();
+ writeTrashFile("noop", "other");
+ git.add().addFilepattern("noop").call();
+ RevCommit sideCommit = git.commit().setAll(true).setMessage("noop")
+ .call();
+
+ git.checkout().setName("master").call();
+ git.rm().addFilepattern("sub").call();
+ writeTrashFile("sub/file", "subfile");
+ git.add().addFilepattern("sub/file").call();
+ git.commit().setMessage("file -> folder")
+ .call();
+
+ MergeResult mergeRes = git.merge().setStrategy(strategy)
+ .include(sideCommit).call();
+ assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
+ assertEquals(
+ "[noop, mode:100644, content:other][sub/file, mode:100644, content:subfile]",
+ indexState(CONTENT));
+ }
+
+ /**
* An existing directory without tracked content should not prevent merging
* a file with that name.
*
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
index 22e55fe..2b46498 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
@@ -246,9 +246,8 @@
if (File.separatorChar == '\\')
base = base.replace('\\', '/');
FileBasedConfig config = db.getConfig();
- config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
- Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
- null);
+ config.unset(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL);
config.save();
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
index f7acaa7..72b4611 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
@@ -65,6 +65,7 @@
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
@@ -101,6 +102,13 @@
}
@Test
+ public void bareRepositoryWithNoSubmodules() throws IOException {
+ FileRepository bareRepo = createBareRepository();
+ boolean result = SubmoduleWalk.containsGitModulesFile(bareRepo);
+ assertFalse(result);
+ }
+
+ @Test
public void repositoryWithRootLevelSubmodule() throws IOException,
ConfigInvalidException, NoWorkTreeException, GitAPIException {
final ObjectId id = ObjectId
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BaseReceivePackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BaseReceivePackTest.java
new file mode 100644
index 0000000..7578c6e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BaseReceivePackTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.eclipse.jgit.errors.PackProtocolException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+
+/** Tests for base receive-pack utilities. */
+public class BaseReceivePackTest {
+ @Test
+ public void parseCommand() throws Exception {
+ String o = "0000000000000000000000000000000000000000";
+ String n = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ String r = "refs/heads/master";
+ ReceiveCommand cmd = BaseReceivePack.parseCommand(o + " " + n + " " + r);
+ assertEquals(ObjectId.zeroId(), cmd.getOldId());
+ assertEquals("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+ cmd.getNewId().name());
+ assertEquals("refs/heads/master", cmd.getRefName());
+
+ assertParseCommandFails(null);
+ assertParseCommandFails("");
+ assertParseCommandFails(o.substring(35) + " " + n.substring(35)
+ + " " + r + "\n");
+ assertParseCommandFails(o + " " + n + " " + r + "\n");
+ assertParseCommandFails(o + " " + n + " " + "refs^foo");
+ assertParseCommandFails(o + " " + n.substring(10) + " " + r);
+ assertParseCommandFails(o.substring(10) + " " + n + " " + r);
+ assertParseCommandFails("X" + o.substring(1) + " " + n + " " + r);
+ assertParseCommandFails(o + " " + "X" + n.substring(1) + " " + r);
+ }
+
+ private void assertParseCommandFails(String input) {
+ try {
+ BaseReceivePack.parseCommand(input);
+ fail();
+ } catch (PackProtocolException e) {
+ // Expected.
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
index 24cee0a..ba89d2d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -147,6 +147,18 @@
}
}
+ @Test
+ public void testAbortWrite() throws Exception {
+ boolean caught = false;
+ try {
+ makeBundleWithCallback(
+ "refs/heads/aa", db.resolve("a").name(), null, false);
+ } catch (WriteAbortedException e) {
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+
private static FetchResult fetchFromBundle(final Repository newRepo,
final byte[] bundle) throws URISyntaxException,
NotSupportedException, TransportException {
@@ -161,9 +173,17 @@
private byte[] makeBundle(final String name,
final String anObjectToInclude, final RevCommit assume)
throws FileNotFoundException, IOException {
+ return makeBundleWithCallback(name, anObjectToInclude, assume, true);
+ }
+
+ private byte[] makeBundleWithCallback(final String name,
+ final String anObjectToInclude, final RevCommit assume,
+ boolean value)
+ throws FileNotFoundException, IOException {
final BundleWriter bw;
bw = new BundleWriter(db);
+ bw.setObjectCountCallback(new NaiveObjectCountCallback(value));
bw.include(name, ObjectId.fromString(anObjectToInclude));
if (assume != null)
bw.assume(assume);
@@ -172,4 +192,19 @@
return out.toByteArray();
}
+ private static class NaiveObjectCountCallback
+ implements ObjectCountCallback {
+ private final boolean value;
+
+ NaiveObjectCountCallback(boolean value) {
+ this.value = value;
+ }
+
+ @Override
+ public void setObjectCount(long unused) throws WriteAbortedException {
+ if (!value)
+ throw new WriteAbortedException();
+ }
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HMACSHA1NonceGeneratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HMACSHA1NonceGeneratorTest.java
new file mode 100644
index 0000000..1e79b7a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HMACSHA1NonceGeneratorTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Test for HMAC SHA-1 certificate verifier. */
+public class HMACSHA1NonceGeneratorTest {
+ private static final long TS = 1433954361;
+
+ private HMACSHA1NonceGenerator gen;
+ private Repository db;
+
+ @Before
+ public void setUp() {
+ gen = new HMACSHA1NonceGenerator("sekret");
+ db = new InMemoryRepository(new DfsRepositoryDescription("db"));
+ }
+
+ @Test
+ public void missing() throws Exception {
+ assertEquals(NonceStatus.MISSING, gen.verify("", "1234", db, false, 0));
+ }
+
+ @Test
+ public void unsolicited() throws Exception {
+ assertEquals(NonceStatus.UNSOLICITED, gen.verify("1234", "", db, false, 0));
+ }
+
+ @Test
+ public void invalidFormat() throws Exception {
+ String sent = gen.createNonce(db, TS);
+ int idx = sent.indexOf('-');
+ String sig = sent.substring(idx, sent.length() - idx);
+ assertEquals(NonceStatus.BAD,
+ gen.verify(Long.toString(TS), sent, db, true, 100));
+ assertEquals(NonceStatus.BAD, gen.verify(sig, sent, db, true, 100));
+ assertEquals(NonceStatus.BAD, gen.verify("xxx-" + sig, sent, db, true, 100));
+ assertEquals(NonceStatus.BAD, gen.verify(sent, "xxx-" + sig, db, true, 100));
+ }
+
+ @Test
+ public void slop() throws Exception {
+ String sent = gen.createNonce(db, TS - 10);
+ String received = gen.createNonce(db, TS);
+ assertEquals(NonceStatus.BAD,
+ gen.verify(received, sent, db, false, 0));
+ assertEquals(NonceStatus.BAD,
+ gen.verify(received, sent, db, false, 11));
+ assertEquals(NonceStatus.SLOP,
+ gen.verify(received, sent, db, true, 0));
+ assertEquals(NonceStatus.SLOP,
+ gen.verify(received, sent, db, true, 9));
+ assertEquals(NonceStatus.OK,
+ gen.verify(received, sent, db, true, 10));
+ assertEquals(NonceStatus.OK,
+ gen.verify(received, sent, db, true, 11));
+ }
+
+ @Test
+ public void ok() throws Exception {
+ String sent = gen.createNonce(db, TS);
+ assertEquals(NonceStatus.OK, gen.verify(sent, sent, db, false, 0));
+ }
+
+ @Test
+ public void signedByDifferentKey() throws Exception {
+ HMACSHA1NonceGenerator other = new HMACSHA1NonceGenerator("other");
+ String sent = gen.createNonce(db, TS);
+ String received = other.createNonce(db, TS);
+ assertNotEquals(received, sent);
+ assertEquals(NonceStatus.BAD,
+ gen.verify(received, sent, db, false, 0));
+ }
+
+ @Test
+ public void signedByDifferentKeyWithSlop() throws Exception {
+ HMACSHA1NonceGenerator other = new HMACSHA1NonceGenerator("other");
+ String sent = gen.createNonce(db, TS - 10);
+ String received = other.createNonce(db, TS);
+ assertEquals(NonceStatus.BAD, gen.verify(received, sent, db, true, 100));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java
new file mode 100644
index 0000000..68aff72
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.PushCertificateIdent.parse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.eclipse.jgit.lib.PersonIdent;
+import org.junit.Test;
+
+public class PushCertificateIdentTest {
+ @Test
+ public void parseValid() throws Exception {
+ String raw = "A U. Thor <a_u_thor@example.com> 1218123387 +0700";
+ PushCertificateIdent ident = parse(raw);
+ assertEquals(raw, ident.getRaw());
+ assertEquals("A U. Thor <a_u_thor@example.com>", ident.getUserId());
+ assertEquals("A U. Thor", ident.getName());
+ assertEquals("a_u_thor@example.com", ident.getEmailAddress());
+ assertEquals(1218123387000L, ident.getWhen().getTime());
+ assertEquals(TimeZone.getTimeZone("GMT+0700"), ident.getTimeZone());
+ assertEquals(7 * 60, ident.getTimeZoneOffset());
+ }
+
+ @Test
+ public void trimName() throws Exception {
+ String name = "A U. Thor";
+ String email = "a_u_thor@example.com";
+ String rest = "<a_u_thor@example.com> 1218123387 +0700";
+
+ checkNameEmail(name, email, name + rest);
+ checkNameEmail(name, email, " " + name + rest);
+ checkNameEmail(name, email, " " + name + rest);
+ checkNameEmail(name, email, name + " " + rest);
+ checkNameEmail(name, email, name + " " + rest);
+ checkNameEmail(name, email, " " + name + " " + rest);
+ }
+
+ @Test
+ public void noEmail() throws Exception {
+ String name = "A U. Thor";
+ String rest = " 1218123387 +0700";
+
+ checkNameEmail(name, null, name + rest);
+ checkNameEmail(name, null, " " + name + rest);
+ checkNameEmail(name, null, " " + name + rest);
+ checkNameEmail(name, null, name + " " + rest);
+ checkNameEmail(name, null, name + " " + rest);
+ checkNameEmail(name, null, " " + name + " " + rest);
+ }
+
+ @Test
+ public void exoticUserId() throws Exception {
+ String rest = " 218123387 +0700";
+ assertEquals("", parse(rest).getUserId());
+
+ String id = "foo\n\0bar\uabcd\n ";
+ assertEquals(id, parse(id + rest).getUserId());
+ }
+
+ @Test
+ public void fuzzyCasesMatchPersonIdent() throws Exception {
+ // See RawParseUtils_ParsePersonIdentTest#testParsePersonIdent_fuzzyCases()
+ Date when = new Date(1234567890000l);
+ TimeZone tz = TimeZone.getTimeZone("GMT-7");
+
+ assertMatchesPersonIdent(
+ "A U Thor <author@example.com>, C O. Miter <comiter@example.com> 1234567890 -0700",
+ new PersonIdent("A U Thor", "author@example.com", when, tz),
+ "A U Thor <author@example.com>, C O. Miter <comiter@example.com>");
+ assertMatchesPersonIdent(
+ "A U Thor <author@example.com> and others 1234567890 -0700",
+ new PersonIdent("A U Thor", "author@example.com", when, tz),
+ "A U Thor <author@example.com> and others");
+ }
+
+ @Test
+ public void incompleteCasesMatchPersonIdent() throws Exception {
+ // See RawParseUtils_ParsePersonIdentTest#testParsePersonIdent_incompleteCases()
+ Date when = new Date(1234567890000l);
+ TimeZone tz = TimeZone.getTimeZone("GMT-7");
+
+ assertMatchesPersonIdent(
+ "Me <> 1234567890 -0700",
+ new PersonIdent("Me", "", when, tz),
+ "Me <>");
+ assertMatchesPersonIdent(
+ " <me@example.com> 1234567890 -0700",
+ new PersonIdent("", "me@example.com", when, tz),
+ " <me@example.com>");
+ assertMatchesPersonIdent(
+ " <> 1234567890 -0700",
+ new PersonIdent("", "", when, tz),
+ " <>");
+ assertMatchesPersonIdent(
+ "<>",
+ new PersonIdent("", "", 0, 0),
+ "<>");
+ assertMatchesPersonIdent(
+ " <>",
+ new PersonIdent("", "", 0, 0),
+ " <>");
+ assertMatchesPersonIdent(
+ "<me@example.com>",
+ new PersonIdent("", "me@example.com", 0, 0),
+ "<me@example.com>");
+ assertMatchesPersonIdent(
+ " <me@example.com>",
+ new PersonIdent("", "me@example.com", 0, 0),
+ " <me@example.com>");
+ assertMatchesPersonIdent(
+ "Me <>",
+ new PersonIdent("Me", "", 0, 0),
+ "Me <>");
+ assertMatchesPersonIdent(
+ "Me <me@example.com>",
+ new PersonIdent("Me", "me@example.com", 0, 0),
+ "Me <me@example.com>");
+ assertMatchesPersonIdent(
+ "Me <me@example.com> 1234567890",
+ new PersonIdent("Me", "me@example.com", 0, 0),
+ "Me <me@example.com>");
+ assertMatchesPersonIdent(
+ "Me <me@example.com> 1234567890 ",
+ new PersonIdent("Me", "me@example.com", 0, 0),
+ "Me <me@example.com>");
+ }
+
+ private static void assertMatchesPersonIdent(String raw,
+ PersonIdent expectedPersonIdent, String expectedUserId) {
+ PushCertificateIdent certIdent = PushCertificateIdent.parse(raw);
+ assertNotNull(raw);
+ assertEquals(raw, certIdent.getRaw());
+ assertEquals(expectedPersonIdent.getName(), certIdent.getName());
+ assertEquals(expectedPersonIdent.getEmailAddress(),
+ certIdent.getEmailAddress());
+ assertEquals(expectedPersonIdent.getWhen(), certIdent.getWhen());
+ assertEquals(expectedPersonIdent.getTimeZoneOffset(),
+ certIdent.getTimeZoneOffset());
+ assertEquals(expectedUserId, certIdent.getUserId());
+ }
+
+ private static void checkNameEmail(String expectedName, String expectedEmail,
+ String raw) {
+ PushCertificateIdent ident = parse(raw);
+ assertNotNull(ident);
+ assertEquals(raw, ident.getRaw());
+ assertEquals(expectedName, ident.getName());
+ assertEquals(expectedEmail, ident.getEmailAddress());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java
new file mode 100644
index 0000000..0647167
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.eclipse.jgit.errors.PackProtocolException;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Test for push certificate parsing. */
+public class PushCertificateParserTest {
+ // Example push certificate generated by C git 2.2.0.
+ private static final String INPUT = "001ccertificate version 0.1\n"
+ + "0041pusher Dave Borowitz <dborowitz@google.com> 1433954361 -0700\n"
+ + "0024pushee git://localhost/repo.git\n"
+ + "002anonce 1433954361-bde756572d665bba81d8\n"
+ + "0005\n"
+ + "00680000000000000000000000000000000000000000"
+ + " 6c2b981a177396fb47345b7df3e4d3f854c6bea7"
+ + " refs/heads/master\n"
+ + "0022-----BEGIN PGP SIGNATURE-----\n"
+ + "0016Version: GnuPG v1\n"
+ + "0005\n"
+ + "0045iQEcBAABAgAGBQJVeGg5AAoJEPfTicJkUdPkUggH/RKAeI9/i/LduuiqrL/SSdIa\n"
+ + "00459tYaSqJKLbXz63M/AW4Sp+4u+dVCQvnAt/a35CVEnpZz6hN4Kn/tiswOWVJf4CO7\n"
+ + "0045htNubGs5ZMwvD6sLYqKAnrM3WxV/2TbbjzjZW6Jkidz3jz/WRT4SmjGYiEO7aA+V\n"
+ + "00454ZdIS9f7sW5VsHHYlNThCA7vH8Uu48bUovFXyQlPTX0pToSgrWV3JnTxDNxfn3iG\n"
+ + "0045IL0zTY/qwVCdXgFownLcs6J050xrrBWIKqfcWr3u4D2aCLyR0v+S/KArr7ulZygY\n"
+ + "0045+SOklImn8TAZiNxhWtA6ens66IiammUkZYFv7SSzoPLFZT4dC84SmGPWgf94NoQ=\n"
+ + "000a=XFeC\n"
+ + "0020-----END PGP SIGNATURE-----\n"
+ + "0012push-cert-end\n";
+
+ // Same push certificate, with all trailing newlines stripped.
+ // (Note that the canonical signed payload is the same, so the same signature
+ // is still valid.)
+ private static final String INPUT_NO_NEWLINES = "001bcertificate version 0.1"
+ + "0040pusher Dave Borowitz <dborowitz@google.com> 1433954361 -0700"
+ + "0023pushee git://localhost/repo.git"
+ + "0029nonce 1433954361-bde756572d665bba81d8"
+ + "0004"
+ + "00670000000000000000000000000000000000000000"
+ + " 6c2b981a177396fb47345b7df3e4d3f854c6bea7"
+ + " refs/heads/master"
+ + "0021-----BEGIN PGP SIGNATURE-----"
+ + "0015Version: GnuPG v1"
+ + "0004"
+ + "0044iQEcBAABAgAGBQJVeGg5AAoJEPfTicJkUdPkUggH/RKAeI9/i/LduuiqrL/SSdIa"
+ + "00449tYaSqJKLbXz63M/AW4Sp+4u+dVCQvnAt/a35CVEnpZz6hN4Kn/tiswOWVJf4CO7"
+ + "0044htNubGs5ZMwvD6sLYqKAnrM3WxV/2TbbjzjZW6Jkidz3jz/WRT4SmjGYiEO7aA+V"
+ + "00444ZdIS9f7sW5VsHHYlNThCA7vH8Uu48bUovFXyQlPTX0pToSgrWV3JnTxDNxfn3iG"
+ + "0044IL0zTY/qwVCdXgFownLcs6J050xrrBWIKqfcWr3u4D2aCLyR0v+S/KArr7ulZygY"
+ + "0044+SOklImn8TAZiNxhWtA6ens66IiammUkZYFv7SSzoPLFZT4dC84SmGPWgf94NoQ="
+ + "0009=XFeC"
+ + "001f-----END PGP SIGNATURE-----"
+ + "0011push-cert-end";
+
+ private Repository db;
+
+ @Before
+ public void setUp() {
+ db = new InMemoryRepository(new DfsRepositoryDescription("repo"));
+ }
+
+ private static SignedPushConfig newEnabledConfig() {
+ Config cfg = new Config();
+ cfg.setString("receive", null, "certnonceseed", "sekret");
+ return SignedPushConfig.KEY.parse(cfg);
+ }
+
+ private static SignedPushConfig newDisabledConfig() {
+ return SignedPushConfig.KEY.parse(new Config());
+ }
+
+ @Test
+ public void noCert() throws Exception {
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newEnabledConfig());
+ assertTrue(parser.enabled());
+ assertNull(parser.build());
+
+ ObjectId oldId = ObjectId.zeroId();
+ ObjectId newId =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ String line = oldId.name() + " " + newId.name() + " refs/heads/master";
+ ReceiveCommand cmd = BaseReceivePack.parseCommand(line);
+
+ parser.addCommand(cmd);
+ parser.addCommand(line);
+ assertNull(parser.build());
+ }
+
+ @Test
+ public void disabled() throws Exception {
+ PacketLineIn pckIn = newPacketLineIn(INPUT);
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newDisabledConfig());
+ assertFalse(parser.enabled());
+ assertNull(parser.build());
+
+ parser.receiveHeader(pckIn, false);
+ parser.addCommand(pckIn.readString());
+ assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString());
+ parser.receiveSignature(pckIn);
+ assertNull(parser.build());
+ }
+
+ @Test
+ public void disabledParserStillRequiresCorrectSyntax() throws Exception {
+ PacketLineIn pckIn = newPacketLineIn("001ccertificate version XYZ\n");
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newDisabledConfig());
+ assertFalse(parser.enabled());
+ try {
+ parser.receiveHeader(pckIn, false);
+ fail("Expected PackProtocolException");
+ } catch (PackProtocolException e) {
+ assertEquals(
+ "Push certificate has missing or invalid value for certificate"
+ + " version: XYZ",
+ e.getMessage());
+ }
+ assertNull(parser.build());
+ }
+
+ @Test
+ public void parseCertFromPktLine() throws Exception {
+ PacketLineIn pckIn = newPacketLineIn(INPUT);
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newEnabledConfig());
+ parser.receiveHeader(pckIn, false);
+ parser.addCommand(pckIn.readString());
+ assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString());
+ parser.receiveSignature(pckIn);
+
+ PushCertificate cert = parser.build();
+ assertEquals("0.1", cert.getVersion());
+ assertEquals("Dave Borowitz", cert.getPusherIdent().getName());
+ assertEquals("dborowitz@google.com",
+ cert.getPusherIdent().getEmailAddress());
+ assertEquals(1433954361000L, cert.getPusherIdent().getWhen().getTime());
+ assertEquals(-7 * 60, cert.getPusherIdent().getTimeZoneOffset());
+ assertEquals("git://localhost/repo.git", cert.getPushee());
+ assertEquals("1433954361-bde756572d665bba81d8", cert.getNonce());
+
+ assertNotEquals(cert.getNonce(), parser.getAdvertiseNonce());
+ assertEquals(PushCertificate.NonceStatus.BAD, cert.getNonceStatus());
+
+ assertEquals(1, cert.getCommands().size());
+ ReceiveCommand cmd = cert.getCommands().get(0);
+ assertEquals("refs/heads/master", cmd.getRefName());
+ assertEquals(ObjectId.zeroId(), cmd.getOldId());
+ assertEquals("6c2b981a177396fb47345b7df3e4d3f854c6bea7",
+ cmd.getNewId().name());
+
+ assertEquals(concatPacketLines(INPUT, 0, 6), cert.toText());
+ assertEquals(concatPacketLines(INPUT, 0, 17), cert.toTextWithSignature());
+
+ String signature = concatPacketLines(INPUT, 6, 17);
+ assertTrue(signature.startsWith(PushCertificateParser.BEGIN_SIGNATURE));
+ assertTrue(signature.endsWith(PushCertificateParser.END_SIGNATURE + "\n"));
+ assertEquals(signature, cert.getSignature());
+ }
+
+ @Test
+ public void parseCertFromPktLineNoNewlines() throws Exception {
+ PacketLineIn pckIn = newPacketLineIn(INPUT_NO_NEWLINES);
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newEnabledConfig());
+ parser.receiveHeader(pckIn, false);
+ parser.addCommand(pckIn.readString());
+ assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString());
+ parser.receiveSignature(pckIn);
+
+ PushCertificate cert = parser.build();
+ assertEquals("0.1", cert.getVersion());
+ assertEquals("Dave Borowitz", cert.getPusherIdent().getName());
+ assertEquals("dborowitz@google.com",
+ cert.getPusherIdent().getEmailAddress());
+ assertEquals(1433954361000L, cert.getPusherIdent().getWhen().getTime());
+ assertEquals(-7 * 60, cert.getPusherIdent().getTimeZoneOffset());
+ assertEquals("git://localhost/repo.git", cert.getPushee());
+ assertEquals("1433954361-bde756572d665bba81d8", cert.getNonce());
+
+ assertNotEquals(cert.getNonce(), parser.getAdvertiseNonce());
+ assertEquals(PushCertificate.NonceStatus.BAD, cert.getNonceStatus());
+
+ assertEquals(1, cert.getCommands().size());
+ ReceiveCommand cmd = cert.getCommands().get(0);
+ assertEquals("refs/heads/master", cmd.getRefName());
+ assertEquals(ObjectId.zeroId(), cmd.getOldId());
+ assertEquals("6c2b981a177396fb47345b7df3e4d3f854c6bea7",
+ cmd.getNewId().name());
+
+ // Canonical signed payload has reinserted newlines.
+ assertEquals(concatPacketLines(INPUT, 0, 6), cert.toText());
+
+ String signature = concatPacketLines(INPUT, 6, 17);
+ assertTrue(signature.startsWith(PushCertificateParser.BEGIN_SIGNATURE));
+ assertTrue(signature.endsWith(PushCertificateParser.END_SIGNATURE + "\n"));
+ assertEquals(signature, cert.getSignature());
+ }
+
+ @Test
+ public void testConcatPacketLines() throws Exception {
+ String input = "000bline 1\n000bline 2\n000bline 3\n";
+ assertEquals("line 1\n", concatPacketLines(input, 0, 1));
+ assertEquals("line 1\nline 2\n", concatPacketLines(input, 0, 2));
+ assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 3));
+ assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 4));
+ }
+
+ @Test
+ public void testConcatPacketLinesInsertsNewlines() throws Exception {
+ String input = "000bline 1\n000aline 2000bline 3\n";
+ assertEquals("line 1\n", concatPacketLines(input, 0, 1));
+ assertEquals("line 1\nline 2\n", concatPacketLines(input, 0, 2));
+ assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 3));
+ assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 4));
+ }
+
+ @Test
+ public void testParseReader() throws Exception {
+ Reader reader = new StringReader(concatPacketLines(INPUT, 0, 18));
+ PushCertificate streamCert = PushCertificateParser.fromReader(reader);
+
+ PacketLineIn pckIn = newPacketLineIn(INPUT);
+ PushCertificateParser pckParser =
+ new PushCertificateParser(db, newEnabledConfig());
+ pckParser.receiveHeader(pckIn, false);
+ pckParser.addCommand(pckIn.readString());
+ assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString());
+ pckParser.receiveSignature(pckIn);
+ PushCertificate pckCert = pckParser.build();
+
+ // Nonce status is unsolicited since this was not parsed in the context of
+ // the wire protocol; as a result, certs are not actually equal.
+ assertEquals(NonceStatus.UNSOLICITED, streamCert.getNonceStatus());
+
+ assertEquals(pckCert.getVersion(), streamCert.getVersion());
+ assertEquals(pckCert.getPusherIdent().getName(),
+ streamCert.getPusherIdent().getName());
+ assertEquals(pckCert.getPusherIdent().getEmailAddress(),
+ streamCert.getPusherIdent().getEmailAddress());
+ assertEquals(pckCert.getPusherIdent().getWhen().getTime(),
+ streamCert.getPusherIdent().getWhen().getTime());
+ assertEquals(pckCert.getPusherIdent().getTimeZoneOffset(),
+ streamCert.getPusherIdent().getTimeZoneOffset());
+ assertEquals(pckCert.getPushee(), streamCert.getPushee());
+ assertEquals(pckCert.getNonce(), streamCert.getNonce());
+ assertEquals(pckCert.getSignature(), streamCert.getSignature());
+ assertEquals(pckCert.toText(), streamCert.toText());
+
+ assertEquals(pckCert.getCommands().size(), streamCert.getCommands().size());
+ ReceiveCommand pckCmd = pckCert.getCommands().get(0);
+ ReceiveCommand streamCmd = streamCert.getCommands().get(0);
+ assertEquals(pckCmd.getRefName(), streamCmd.getRefName());
+ assertEquals(pckCmd.getOldId(), streamCmd.getOldId());
+ assertEquals(pckCmd.getNewId().name(), streamCmd.getNewId().name());
+ }
+
+ @Test
+ public void testParseString() throws Exception {
+ String str = concatPacketLines(INPUT, 0, 18);
+ assertEquals(
+ PushCertificateParser.fromReader(new StringReader(str)),
+ PushCertificateParser.fromString(str));
+ }
+
+ @Test
+ public void testParseMultipleFromStream() throws Exception {
+ String input = concatPacketLines(INPUT, 0, 17);
+ assertFalse(input.contains(PushCertificateParser.END_CERT));
+ input += input;
+ Reader reader = new InputStreamReader(
+ new ByteArrayInputStream(Constants.encode(input)));
+
+ assertNotNull(PushCertificateParser.fromReader(reader));
+ assertNotNull(PushCertificateParser.fromReader(reader));
+ assertEquals(-1, reader.read());
+ assertNull(PushCertificateParser.fromReader(reader));
+ }
+
+ @Test
+ public void testMissingPusheeField() throws Exception {
+ // Omit pushee line from existing cert. (This means the signature would not
+ // match, but we're not verifying it here.)
+ String input = INPUT.replace("0024pushee git://localhost/repo.git\n", "");
+ assertFalse(input.contains(PushCertificateParser.PUSHEE));
+
+ PacketLineIn pckIn = newPacketLineIn(input);
+ PushCertificateParser parser =
+ new PushCertificateParser(db, newEnabledConfig());
+ parser.receiveHeader(pckIn, false);
+ parser.addCommand(pckIn.readString());
+ assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString());
+ parser.receiveSignature(pckIn);
+
+ PushCertificate cert = parser.build();
+ assertEquals("0.1", cert.getVersion());
+ assertNull(cert.getPushee());
+ assertFalse(cert.toText().contains(PushCertificateParser.PUSHEE));
+ }
+
+ private static String concatPacketLines(String input, int begin, int end)
+ throws IOException {
+ StringBuilder result = new StringBuilder();
+ int i = 0;
+ PacketLineIn pckIn = newPacketLineIn(input);
+ while (i < end) {
+ String line;
+ try {
+ line = pckIn.readString();
+ } catch (EOFException e) {
+ break;
+ }
+ if (++i > begin) {
+ result.append(line).append('\n');
+ }
+ }
+ return result.toString();
+ }
+
+ private static PacketLineIn newPacketLineIn(String input) {
+ return new PacketLineIn(new ByteArrayInputStream(Constants.encode(input)));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java
new file mode 100644
index 0000000..68e0129
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java
@@ -0,0 +1,380 @@
+/*
+ * 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.lib.ObjectId.zeroId;
+import static org.eclipse.jgit.lib.RefUpdate.Result.FAST_FORWARD;
+import static org.eclipse.jgit.lib.RefUpdate.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.lib.RefUpdate.Result.NEW;
+import static org.eclipse.jgit.lib.RefUpdate.Result.NO_CHANGE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PushCertificateStoreTest {
+ private static final ObjectId ID1 =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+
+ private static final ObjectId ID2 =
+ ObjectId.fromString("badc0ffebadc0ffebadc0ffebadc0ffebadc0ffe");
+
+ private static PushCertificate newCert(String... updateLines) {
+ StringBuilder cert = new StringBuilder(
+ "certificate version 0.1\n"
+ + "pusher Dave Borowitz <dborowitz@google.com> 1433954361 -0700\n"
+ + "pushee git://localhost/repo.git\n"
+ + "nonce 1433954361-bde756572d665bba81d8\n"
+ + "\n");
+ for (String updateLine : updateLines) {
+ cert.append(updateLine).append('\n');
+ }
+ cert.append(
+ "-----BEGIN PGP SIGNATURE-----\n"
+ + "DUMMY/SIGNATURE\n"
+ + "-----END PGP SIGNATURE-----\n");
+ try {
+ return PushCertificateParser.fromReader(new InputStreamReader(
+ new ByteArrayInputStream(Constants.encode(cert.toString()))));
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private static String command(ObjectId oldId, ObjectId newId, String ref) {
+ return oldId.name() + " " + newId.name() + " " + ref;
+ }
+
+ private AtomicInteger ts = new AtomicInteger(1433954361);
+ private InMemoryRepository repo;
+ private PushCertificateStore store;
+
+ @Before
+ public void setUp() throws Exception {
+ repo = new InMemoryRepository(new DfsRepositoryDescription("repo"));
+ store = newStore();
+ }
+
+ @Test
+ public void missingRef() throws Exception {
+ assertCerts("refs/heads/master");
+ }
+
+ @Test
+ public void saveNoChange() throws Exception {
+ assertEquals(NO_CHANGE, store.save());
+ }
+
+ @Test
+ public void saveOneCertOnOneRef() throws Exception {
+ PersonIdent ident = newIdent();
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, ident);
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads/master", addMaster);
+ assertCerts("refs/heads/branch");
+
+ try (RevWalk rw = new RevWalk(repo)) {
+ RevCommit c = rw.parseCommit(repo.resolve(PushCertificateStore.REF_NAME));
+ rw.parseBody(c);
+ assertEquals("Store push certificate for refs/heads/master\n",
+ c.getFullMessage());
+ assertEquals(ident, c.getAuthorIdent());
+ assertEquals(ident, c.getCommitterIdent());
+ }
+ }
+
+ @Test
+ public void saveTwoCertsOnSameRefInTwoUpdates() throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertEquals(NEW, store.save());
+ PushCertificate updateMaster = newCert(
+ command(ID1, ID2, "refs/heads/master"));
+ store.put(updateMaster, newIdent());
+ assertEquals(FAST_FORWARD, store.save());
+ assertCerts("refs/heads/master", updateMaster, addMaster);
+ }
+
+ @Test
+ public void saveTwoCertsOnSameRefInOneUpdate() throws Exception {
+ PersonIdent ident1 = newIdent();
+ PersonIdent ident2 = newIdent();
+ PushCertificate updateMaster = newCert(
+ command(ID1, ID2, "refs/heads/master"));
+ store.put(updateMaster, ident2);
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, ident1);
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads/master", updateMaster, addMaster);
+ }
+
+ @Test
+ public void saveTwoCertsOnDifferentRefsInOneUpdate() throws Exception {
+ PersonIdent ident1 = newIdent();
+ PersonIdent ident3 = newIdent();
+ PushCertificate addBranch = newCert(
+ command(zeroId(), ID1, "refs/heads/branch"));
+ store.put(addBranch, ident3);
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, ident1);
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads/master", addMaster);
+ assertCerts("refs/heads/branch", addBranch);
+ }
+
+ @Test
+ public void saveTwoCertsOnDifferentRefsInTwoUpdates() throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertEquals(NEW, store.save());
+ PushCertificate addBranch = newCert(
+ command(zeroId(), ID1, "refs/heads/branch"));
+ store.put(addBranch, newIdent());
+ assertEquals(FAST_FORWARD, store.save());
+ assertCerts("refs/heads/master", addMaster);
+ assertCerts("refs/heads/branch", addBranch);
+ }
+
+ @Test
+ public void saveOneCertOnMultipleRefs() throws Exception {
+ PersonIdent ident = newIdent();
+ PushCertificate addMasterAndBranch = newCert(
+ command(zeroId(), ID1, "refs/heads/branch"),
+ command(zeroId(), ID2, "refs/heads/master"));
+ store.put(addMasterAndBranch, ident);
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads/master", addMasterAndBranch);
+ assertCerts("refs/heads/branch", addMasterAndBranch);
+
+ try (RevWalk rw = new RevWalk(repo)) {
+ RevCommit c = rw.parseCommit(repo.resolve(PushCertificateStore.REF_NAME));
+ rw.parseBody(c);
+ assertEquals("Store push certificate for 2 refs\n", c.getFullMessage());
+ assertEquals(ident, c.getAuthorIdent());
+ assertEquals(ident, c.getCommitterIdent());
+ }
+ }
+
+ @Test
+ public void changeRefFileToDirectory() throws Exception {
+ PushCertificate deleteRefsHeads = newCert(
+ command(ID1, zeroId(), "refs/heads"));
+ store.put(deleteRefsHeads, newIdent());
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads", deleteRefsHeads);
+ assertCerts("refs/heads/master", addMaster);
+ }
+
+ @Test
+ public void getBeforeSaveDoesNotIncludePending() throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertEquals(NEW, store.save());
+
+ PushCertificate updateMaster = newCert(
+ command(ID1, ID2, "refs/heads/master"));
+ store.put(updateMaster, newIdent());
+
+ assertCerts("refs/heads/master", addMaster);
+ assertEquals(FAST_FORWARD, store.save());
+ assertCerts("refs/heads/master", updateMaster, addMaster);
+ }
+
+ @Test
+ public void lockFailure() throws Exception {
+ PushCertificateStore store1 = store;
+ PushCertificateStore store2 = newStore();
+ store2.get("refs/heads/master");
+
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store1.put(addMaster, newIdent());
+ assertEquals(NEW, store1.save());
+
+ PushCertificate addBranch = newCert(
+ command(zeroId(), ID2, "refs/heads/branch"));
+ store2.put(addBranch, newIdent());
+
+ assertEquals(LOCK_FAILURE, store2.save());
+ // Reread ref after lock failure.
+ assertCerts(store2, "refs/heads/master", addMaster);
+ assertCerts(store2, "refs/heads/branch");
+
+ assertEquals(FAST_FORWARD, store2.save());
+ assertCerts(store2, "refs/heads/master", addMaster);
+ assertCerts(store2, "refs/heads/branch", addBranch);
+ }
+
+ @Test
+ public void saveInBatch() throws Exception {
+ BatchRefUpdate batch = repo.getRefDatabase().newBatchUpdate();
+ assertFalse(store.save(batch));
+ assertEquals(0, batch.getCommands().size());
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertTrue(store.save(batch));
+
+ List<ReceiveCommand> commands = batch.getCommands();
+ assertEquals(1, commands.size());
+ ReceiveCommand cmd = commands.get(0);
+ assertEquals("refs/meta/push-certs", cmd.getRefName());
+ assertEquals(ReceiveCommand.Result.NOT_ATTEMPTED, cmd.getResult());
+
+ try (RevWalk rw = new RevWalk(repo)) {
+ batch.execute(rw, NullProgressMonitor.INSTANCE);
+ assertEquals(ReceiveCommand.Result.OK, cmd.getResult());
+ }
+ }
+
+ @Test
+ public void putMatchingWithNoMatchingRefs() throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"),
+ command(zeroId(), ID2, "refs/heads/branch"));
+ store.put(addMaster, newIdent(), Collections.<ReceiveCommand> emptyList());
+ assertEquals(NO_CHANGE, store.save());
+ }
+
+ @Test
+ public void putMatchingWithNoMatchingRefsInBatchOnEmptyRef()
+ throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"),
+ command(zeroId(), ID2, "refs/heads/branch"));
+ store.put(addMaster, newIdent(), Collections.<ReceiveCommand> emptyList());
+ BatchRefUpdate batch = repo.getRefDatabase().newBatchUpdate();
+ assertFalse(store.save(batch));
+ assertEquals(0, batch.getCommands().size());
+ }
+
+ @Test
+ public void putMatchingWithNoMatchingRefsInBatchOnNonEmptyRef()
+ throws Exception {
+ PushCertificate addMaster = newCert(
+ command(zeroId(), ID1, "refs/heads/master"));
+ store.put(addMaster, newIdent());
+ assertEquals(NEW, store.save());
+
+ PushCertificate addBranch = newCert(
+ command(zeroId(), ID2, "refs/heads/branch"));
+ store.put(addBranch, newIdent(), Collections.<ReceiveCommand> emptyList());
+ BatchRefUpdate batch = repo.getRefDatabase().newBatchUpdate();
+ assertFalse(store.save(batch));
+ assertEquals(0, batch.getCommands().size());
+ }
+
+ @Test
+ public void putMatchingWithSomeMatchingRefs() throws Exception {
+ PushCertificate addMasterAndBranch = newCert(
+ command(zeroId(), ID1, "refs/heads/master"),
+ command(zeroId(), ID2, "refs/heads/branch"));
+ store.put(addMasterAndBranch, newIdent(),
+ Collections.singleton(addMasterAndBranch.getCommands().get(0)));
+ assertEquals(NEW, store.save());
+ assertCerts("refs/heads/master", addMasterAndBranch);
+ assertCerts("refs/heads/branch");
+ }
+
+ private PersonIdent newIdent() {
+ return new PersonIdent(
+ "A U. Thor", "author@example.com", ts.getAndIncrement(), 0);
+ }
+
+ private PushCertificateStore newStore() {
+ return new PushCertificateStore(repo);
+ }
+
+ private void assertCerts(String refName, PushCertificate... expected)
+ throws Exception {
+ assertCerts(store, refName, expected);
+ assertCerts(newStore(), refName, expected);
+ }
+
+ private static void assertCerts(PushCertificateStore store, String refName,
+ PushCertificate... expected) throws Exception {
+ List<PushCertificate> ex = Arrays.asList(expected);
+ PushCertificate first = !ex.isEmpty() ? ex.get(0) : null;
+ assertEquals(first, store.get(refName));
+ assertEquals(ex, toList(store.getAll(refName)));
+ }
+
+ private static <T> List<T> toList(Iterable<T> it) {
+ List<T> list = new ArrayList<>();
+ for (T t : it) {
+ list.add(t);
+ }
+ return list;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
index 8c7c992..745c322 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -3,6 +3,7 @@
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2013, Robin Stocker <robin@nibor.org>
+ * Copyright (C) 2015, Patrick Steinhardt <ps@pks.im>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -379,6 +380,56 @@
}
@Test
+ public void testSshProtoHostOnly() throws Exception {
+ final String str = "ssh://example.com/";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/", u.getRawPath());
+ assertEquals("/", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals("ssh://example.com/", u.toString());
+ assertEquals("ssh://example.com/", u.toASCIIString());
+ assertEquals("example.com", u.getHumanishName());
+ assertEquals(u, new URIish(str));
+ }
+
+ @Test
+ public void testSshProtoHostWithAuthentication() throws Exception {
+ final String str = "ssh://user:secret@pass@example.com/";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/", u.getRawPath());
+ assertEquals("/", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals("ssh://user@example.com/", u.toString());
+ assertEquals("ssh://user@example.com/", u.toASCIIString());
+ assertEquals("example.com", u.getHumanishName());
+ assertEquals("user", u.getUser());
+ assertEquals("secret@pass", u.getPass());
+ assertEquals(u, new URIish(str));
+ }
+
+ @Test
+ public void testSshProtoHostWithPort() throws Exception {
+ final String str = "ssh://example.com:2222/";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/", u.getRawPath());
+ assertEquals("/", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(2222, u.getPort());
+ assertEquals("ssh://example.com:2222/", u.toString());
+ assertEquals("ssh://example.com:2222/", u.toASCIIString());
+ assertEquals("example.com", u.getHumanishName());
+ assertEquals(u, new URIish(str));
+ }
+
+ @Test
public void testSshProtoWithUserAndPort() throws Exception {
final String str = "ssh://user@example.com:33/some/p ath";
URIish u = new URIish(str);
@@ -623,6 +674,13 @@
}
@Test
+ public void testGetEmptyHumanishNameWithAuthorityOnly() throws IllegalArgumentException,
+ URISyntaxException {
+ String humanishName = new URIish(GIT_SCHEME + "abc").getHumanishName();
+ assertEquals("abc", humanishName);
+ }
+
+ @Test
public void testGetValidSlashHumanishName()
throws IllegalArgumentException, URISyntaxException {
String humanishName = new URIish(GIT_SCHEME + "host/abc/")
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
index 9dc5fac..4625f30 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
@@ -48,6 +48,8 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import org.junit.After;
import org.junit.Before;
@@ -83,4 +85,14 @@
assertTrue(dir.exists());
assertTrue(file.exists());
}
+
+ @Test
+ public void testAtomicMove() throws IOException {
+ File src = new File(trash, "src");
+ Files.createFile(src.toPath());
+ File dst = new File(trash, "dst");
+ FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
+ assertFalse(Files.exists(src.toPath()));
+ assertTrue(Files.exists(dst.toPath()));
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java
new file mode 100644
index 0000000..928fb2e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.jgit.lib.Constants;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IOReadLineTest {
+ @Parameter(0)
+ public boolean buffered;
+
+ @Parameter(1)
+ public int sizeHint;
+
+ @SuppressWarnings("boxing")
+ @Parameters(name="buffered={0}, sizeHint={1}")
+ public static Collection<Object[]> getParameters() {
+ Boolean[] bv = {false, true};
+ Integer[] sv = {-1, 0, 1, 2, 3, 4, 64};
+ Collection<Object[]> params = new ArrayList<>(bv.length * sv.length);
+ for (boolean b : bv) {
+ for (Integer s : sv) {
+ params.add(new Object[]{b, s});
+ }
+ }
+ return params;
+ }
+
+ @Test
+ public void testReadLine() throws Exception {
+ Reader r = newReader("foo\nbar\nbaz\n");
+ assertEquals("foo\n", readLine(r));
+ assertEquals("bar\n", readLine(r));
+ assertEquals("baz\n", readLine(r));
+ assertEquals("", readLine(r));
+ }
+
+ @Test
+ public void testReadLineNoTrailingNewline() throws Exception {
+ Reader r = newReader("foo\nbar\nbaz");
+ assertEquals("foo\n", readLine(r));
+ assertEquals("bar\n", readLine(r));
+ assertEquals("baz", readLine(r));
+ assertEquals("", readLine(r));
+ }
+
+ private String readLine(Reader r) throws Exception {
+ return IO.readLine(r, sizeHint);
+ }
+
+ private Reader newReader(String in) {
+ Reader r = new InputStreamReader(
+ new ByteArrayInputStream(Constants.encode(in)));
+ if (buffered) {
+ r = new BufferedReader(r);
+ }
+ assertEquals(Boolean.valueOf(buffered),
+ Boolean.valueOf(r.markSupported()));
+ return r;
+ }
+}
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 2cd9dc6..3586cbc 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Export-Package: org.eclipse.jgit.awtui;version="4.0.3"
-Import-Package: org.eclipse.jgit.errors;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.lib;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.nls;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revplot;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.revwalk;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.transport;version="[4.0.3,4.1.0)",
- org.eclipse.jgit.util;version="[4.0.3,4.1.0)"
+Export-Package: org.eclipse.jgit.awtui;version="4.1.2"
+Import-Package: org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 3ffda41..776cb8b 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
index 4a11964..7359093 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/SwingCommitList.java
@@ -82,6 +82,7 @@
}
static class SwingLane extends PlotLane {
+ private static final long serialVersionUID = 1L;
Color color;
}
}
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 124435a..a1e79e2 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,9 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2">
- <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">
+ <resource path="src/org/eclipse/jgit/transport/PushCertificate.java" type="org.eclipse.jgit.transport.PushCertificate">
+ <filter comment="PushCertificate wasn't really usable in 4.0" id="338722907">
<message_arguments>
- <message_argument value="org.eclipse.jgit.util.FileUtil"/>
+ <message_argument value="org.eclipse.jgit.transport.PushCertificate"/>
+ <message_argument value="PushCertificate()"/>
+ </message_arguments>
+ </filter>
+ <filter comment="PushCertificate wasn't really usable in 4.0" id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.PushCertificate"/>
+ <message_argument value="getCommandList()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/transport/PushCertificateParser.java" type="org.eclipse.jgit.transport.PushCertificateParser">
+ <filter comment="PushCertificates haven't been really usable in 4.0" id="338849923">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.PushCertificateParser"/>
</message_arguments>
</filter>
</resource>
diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
index ff39d16..4e28e0b 100644
--- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
@@ -67,11 +67,11 @@
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=ignore
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index edf38e4..a51bee8 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,10 +2,11 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.0.3.201509231615-r
+Bundle-Version: 4.1.2.201602141800-r
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.api;version="4.0.3";
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.jgit.api;version="4.1.2";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
@@ -19,56 +20,60 @@
org.eclipse.jgit.submodule,
org.eclipse.jgit.transport,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.0.3";
- uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.0.3",
- org.eclipse.jgit.blame;version="4.0.3";
+ org.eclipse.jgit.api.errors;version="4.1.2";
+ uses:="org.eclipse.jgit.lib,
+ org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="4.1.2",
+ org.eclipse.jgit.blame;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.0.3";
+ org.eclipse.jgit.diff;version="4.1.2";
uses:="org.eclipse.jgit.patch,
org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="4.0.3";
+ org.eclipse.jgit.dircache;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util,
org.eclipse.jgit.events,
org.eclipse.jgit.attributes",
- org.eclipse.jgit.errors;version="4.0.3";
+ org.eclipse.jgit.errors;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.internal.storage.pack,
org.eclipse.jgit.transport,
org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="4.0.3";
+ org.eclipse.jgit.events;version="4.1.2";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.0.3",
- org.eclipse.jgit.gitrepo;version="4.0.3";
+ org.eclipse.jgit.fnmatch;version="4.1.2",
+ org.eclipse.jgit.gitrepo;version="4.1.2";
uses:="org.eclipse.jgit.api,
org.eclipse.jgit.lib,
- org.eclipse.jgit.revwalk",
- org.eclipse.jgit.gitrepo.internal;version="4.0.3";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.0.3",
- org.eclipse.jgit.ignore;version="4.0.3",
- org.eclipse.jgit.ignore.internal;version="4.0.3";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.0.3";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.storage.dfs;version="4.0.3";
+ org.eclipse.jgit.revwalk,
+ org.xml.sax.helpers,
+ org.xml.sax",
+ org.eclipse.jgit.gitrepo.internal;version="4.1.2";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.1.2";
+ uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="4.1.2",
+ org.eclipse.jgit.ignore.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.storage.dfs;version="4.1.2";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server",
- org.eclipse.jgit.internal.storage.file;version="4.0.3";
+ org.eclipse.jgit.internal.storage.file;version="4.1.2";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
org.eclipse.jgit.http.server,
org.eclipse.jgit.java7.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="4.0.3";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.0.3";
+ org.eclipse.jgit.internal.storage.pack;version="4.1.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.1.2";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
@@ -78,41 +83,45 @@
org.eclipse.jgit.treewalk,
org.eclipse.jgit.transport,
org.eclipse.jgit.submodule",
- org.eclipse.jgit.merge;version="4.0.3";
+ org.eclipse.jgit.merge;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.diff,
org.eclipse.jgit.dircache,
org.eclipse.jgit.api",
- org.eclipse.jgit.nls;version="4.0.3",
- org.eclipse.jgit.notes;version="4.0.3";
+ org.eclipse.jgit.nls;version="4.1.2",
+ org.eclipse.jgit.notes;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.0.3";
- uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.0.3";
+ org.eclipse.jgit.patch;version="4.1.2";
+ uses:="org.eclipse.jgit.lib,
+ org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.0.3";
+ org.eclipse.jgit.revwalk;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="4.0.3";
- uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.0.3";
- uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.0.3";
+ org.eclipse.jgit.revwalk.filter;version="4.1.2";
+ uses:="org.eclipse.jgit.revwalk,
+ org.eclipse.jgit.lib,
+ org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="4.1.2";
+ uses:="org.eclipse.jgit.lib,
+ org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="4.1.2";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.0.3";
+ org.eclipse.jgit.submodule;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.0.3";
+ org.eclipse.jgit.transport;version="4.1.2";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.internal.storage.pack,
@@ -124,29 +133,29 @@
org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.0.3";
+ org.eclipse.jgit.transport.http;version="4.1.2";
uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.0.3";
+ org.eclipse.jgit.transport.resolver;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.0.3";
+ org.eclipse.jgit.treewalk;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.attributes,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="4.0.3";
+ org.eclipse.jgit.treewalk.filter;version="4.1.2";
uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.0.3";
+ org.eclipse.jgit.util;version="4.1.2";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport.http,
org.eclipse.jgit.storage.file,
org.ietf.jgss",
- org.eclipse.jgit.util.io;version="4.0.3"
-Bundle-ActivationPolicy: lazy
+ org.eclipse.jgit.util.io;version="4.1.2"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
+Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)",
+ org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
javax.crypto,
javax.net.ssl,
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index b7c2a35..c7d9753 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit - Sources
Bundle-SymbolicName: org.eclipse.jgit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.0.3.201509231615-r
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.0.3.201509231615-r";roots="."
+Bundle-Version: 4.1.2.201602141800-r
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.2.201602141800-r";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 3dc7132..945b135 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -53,7 +53,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.0.3.201509231615-r</version>
+ <version>4.1.2.201602141800-r</version>
</parent>
<artifactId>org.eclipse.jgit</artifactId>
@@ -88,6 +88,12 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jdt</groupId>
+ <artifactId>org.eclipse.jdt.annotation</artifactId>
+ <version>1.1.0</version>
+ </dependency>
</dependencies>
<build>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index db9a684..34bbb41 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -59,23 +59,23 @@
cannotCreateTempDir=Cannot create a temp dir
cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted
cannotDeleteFile=Cannot delete file: {0}
-cannotDeleteObjectsPath="Can't delete {0}/{1}: {2}
+cannotDeleteObjectsPath=Cannot delete {0}/{1}: {2}
cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0}
cannotDeleteStaleTrackingRef2=Cannot delete stale tracking ref {0}: {1}
cannotDetermineProxyFor=Cannot determine proxy for {0}
cannotDownload=Cannot download {0}
-cannotEnterObjectsPath=Can't enter {0}/objects: {1}
-cannotEnterPathFromParent=Can't enter {0} from {1}: {2}
+cannotEnterObjectsPath=Cannot enter {0}/objects: {1}
+cannotEnterPathFromParent=Cannot enter {0} from {1}: {2}
cannotExecute=cannot execute: {0}
cannotGet=Cannot get {0}
-cannotGetObjectsPath=Can't get {0}/{1}: {2}
-cannotListObjectsPath=Can't ls {0}/{1}: {2}
-cannotListPackPath=Can't ls {0}/pack: {1}
+cannotGetObjectsPath=Cannot get {0}/{1}: {2}
+cannotListObjectsPath=Cannot ls {0}/{1}: {2}
+cannotListPackPath=Cannot ls {0}/pack: {1}
cannotListRefs=cannot list refs
cannotLock=Cannot lock {0}
cannotLockPackIn=Cannot lock pack in {0}
cannotMatchOnEmptyString=Cannot match on empty string.
-cannotMkdirObjectPath=Can't mkdir {0}/{1}: {2}
+cannotMkdirObjectPath=Cannot mkdir {0}/{1}: {2}
cannotMoveIndexTo=Cannot move index to {0}
cannotMovePackTo=Cannot move pack to {0}
cannotOpenService=cannot open {0}
@@ -97,7 +97,7 @@
cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID
cannotUnloadAModifiedTree=Cannot unload a modified tree.
cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index.
-cannotWriteObjectsPath="Can't write {0}/{1}: {2}
+cannotWriteObjectsPath=Cannot write {0}/{1}: {2}
canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported.
canOnlyRevertCommitsWithOneParent=Cannot revert commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported
commitDoesNotHaveGivenParent=The commit ''{0}'' does not have a parent number {1}.
@@ -237,12 +237,10 @@
errorEncodingFromFile=Error encoding from file {0}
errorInBase64CodeReadingStream=Error in Base64 code reading stream.
errorInPackedRefs=error in packed-refs
-errorInvalidPushCert=error: invalid protocol: {0}
errorInvalidProtocolWantedOldNewRef=error: invalid protocol: wanted 'old new ref'
errorListing=Error listing {0}
errorOccurredDuringUnpackingOnTheRemoteEnd=error occurred during unpacking on the remote end: {0}
errorReadingInfoRefs=error reading info/refs
-errorSymlinksNotSupported=Symlinks are not supported with this OS/JRE
exceptionCaughtDuringExecutionOfHook=Exception caught during execution of "{0}" hook.
exceptionCaughtDuringExecutionOfAddCommand=Exception caught during execution of add command
exceptionCaughtDuringExecutionOfArchiveCommand=Exception caught during execution of archive command
@@ -288,7 +286,6 @@
gcFailed=Garbage collection failed.
gitmodulesNotFound=.gitmodules not found in tree.
headRequiredToStash=HEAD required to stash local changes
-hiddenFilesStartWithDot=Hiding only allowed for names that start with a period
hoursAgo={0} hours ago
hugeIndexesAreNotSupportedByJgitYet=Huge indexes are not supported by jgit, yet
hunkBelongsToAnotherFile=Hunk belongs to another file
@@ -326,8 +323,10 @@
invalidGitdirRef = Invalid .git reference in file ''{0}''
invalidGitType=invalid git type: {0}
invalidId=Invalid id: {0}
+invalidId0=Invalid id
invalidIdLength=Invalid id length {0}; should be {1}
invalidIgnoreParamSubmodule=Found invalid ignore param for submodule {0}.
+invalidIgnoreRule=Exception caught while parsing ignore rule ''{0}''.
invalidIntegerValue=Invalid integer value: {0}.{1}={2}
invalidKey=Invalid key: {0}
invalidLineInConfigFile=Invalid line in config file
@@ -344,6 +343,7 @@
invalidReflogRevision=Invalid reflog revision: {0}
invalidRefName=Invalid ref name: {0}
invalidRemote=Invalid remote: {0}
+invalidShallowObject=invalid shallow object {0}, expected commit
invalidStageForPath=Invalid stage {0} for path {1}
invalidTagOption=Invalid tag option: {0}
invalidTimeout=Invalid timeout: {0}
@@ -440,6 +440,7 @@
packChecksumMismatch=Pack checksum mismatch detected for pack file {0}
packCorruptedWhileWritingToFilesystem=Pack corrupted while writing to filesystem
packDoesNotMatchIndex=Pack {0} does not match index
+packedRefsHandleIsStale=packed-refs handle is stale, {0}. retry
packetSizeMustBeAtLeast=packet size {0} must be >= {1}
packetSizeMustBeAtMost=packet size {0} must be <= {1}
packfileCorruptionDetected=Packfile corruption detected: {0}
@@ -464,7 +465,7 @@
peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph
personIdentEmailNonNull=E-mail address of PersonIdent must not be null.
personIdentNameNonNull=Name of PersonIdent must not be null.
-prefixRemote=remote:
+prefixRemote=remote:
problemWithResolvingPushRefSpecsLocally=Problem with resolving push ref specs locally: {0}
progressMonUploading=Uploading {0}
propertyIsAlreadyNonNull=Property is already non null
@@ -473,6 +474,10 @@
pullOnRepoWithoutHEADCurrentlyNotSupported=Pull on repository without HEAD currently not supported
pullTaskName=Pull
pushCancelled=push cancelled
+pushCertificateInvalidField=Push certificate has missing or invalid value for {0}
+pushCertificateInvalidFieldValue=Push certificate has missing or invalid value for {0}: {1}
+pushCertificateInvalidHeader=Push certificate has invalid header format
+pushCertificateInvalidSignature=Push certificate has invalid signature format
pushIsNotSupportedForBundleTransport=Push is not supported for bundle transport
pushNotPermitted=push not permitted
rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry
@@ -531,7 +536,6 @@
sequenceTooLargeForDiffAlgorithm=Sequence too large for difference algorithm.
serviceNotEnabledNoName=Service not enabled
serviceNotPermitted={0} not permitted
-serviceNotPermittedNoName=Service not permitted
shallowCommitsAlreadyInitialized=Shallow commits have already been initialized
shortCompressedStreamAt=Short compressed stream at {0}
shortReadOfBlock=Short read of block.
@@ -561,6 +565,9 @@
stashFailed=Stashing local changes did not successfully complete
stashResolveFailed=Reference ''{0}'' does not resolve to stashed commit
statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled
+storePushCertMultipleRefs=Store push certificate for {0} refs
+storePushCertOneRef=Store push certificate for {0}
+storePushCertReflog=Store push certificate
submoduleExists=Submodule ''{0}'' already exists in the index
submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}''
submodulesNotSupported=Submodules are not supported
@@ -602,6 +609,7 @@
unableToCreateNewObject=Unable to create new object: {0}
unableToStore=Unable to store {0}.
unableToWrite=Unable to write {0}
+unauthorized=Unauthorized
unencodeableFile=Unencodable file: {0}
unexpectedCompareResult=Unexpected metadata comparison result: {0}
unexpectedEndOfConfigFile=Unexpected end of config file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index 53901f5..b3bc319 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -127,16 +127,23 @@
*/
public Git call() throws GitAPIException, InvalidRemoteException,
org.eclipse.jgit.api.errors.TransportException {
+ Repository repository = null;
try {
URIish u = new URIish(uri);
- Repository repository = init(u);
+ repository = init(u);
FetchResult result = fetch(repository, u);
if (!noCheckout)
checkout(repository, result);
- return new Git(repository);
+ return new Git(repository, true);
} catch (IOException ioe) {
+ if (repository != null) {
+ repository.close();
+ }
throw new JGitInternalException(ioe.getMessage(), ioe);
} catch (URISyntaxException e) {
+ if (repository != null) {
+ repository.close();
+ }
throw new InvalidRemoteException(MessageFormat.format(
JGitText.get().invalidRemote, remote));
}
@@ -331,7 +338,8 @@
/**
* @param uri
- * the uri to clone from
+ * the URI to clone from, or {@code null} to unset the URI.
+ * The URI must be set before {@link #call} is called.
* @return this instance
*/
public CloneCommand setURI(String uri) {
@@ -346,7 +354,8 @@
* @see URIish#getHumanishName()
*
* @param directory
- * the directory to clone to
+ * the directory to clone to, or {@code null} if the directory
+ * name should be taken from the source uri
* @return this instance
* @throws IllegalStateException
* if the combination of directory, gitDir and bare is illegal.
@@ -362,7 +371,8 @@
/**
* @param gitDir
- * the repository meta directory
+ * the repository meta directory, or {@code null} to choose one
+ * automatically at clone time
* @return this instance
* @throws IllegalStateException
* if the combination of directory, gitDir and bare is illegal.
@@ -400,10 +410,14 @@
*
* @see Constants#DEFAULT_REMOTE_NAME
* @param remote
- * name that keeps track of the upstream repository
+ * name that keeps track of the upstream repository.
+ * {@code null} means to use DEFAULT_REMOTE_NAME.
* @return this instance
*/
public CloneCommand setRemote(String remote) {
+ if (remote == null) {
+ remote = Constants.DEFAULT_REMOTE_NAME;
+ }
this.remote = remote;
return this;
}
@@ -413,9 +427,15 @@
* the initial branch to check out when cloning the repository.
* Can be specified as ref name (<code>refs/heads/master</code>),
* branch name (<code>master</code>) or tag name (<code>v1.2.3</code>).
+ * The default is to use the branch pointed to by the cloned
+ * repository's HEAD and can be requested by passing {@code null}
+ * or <code>HEAD</code>.
* @return this instance
*/
public CloneCommand setBranch(String branch) {
+ if (branch == null) {
+ branch = Constants.HEAD;
+ }
this.branch = branch;
return this;
}
@@ -430,6 +450,9 @@
* @return {@code this}
*/
public CloneCommand setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
index 527daef..3e3a7a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
@@ -268,7 +268,10 @@
* @return this instance
*/
public DiffCommand setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
index 29d475a..9620089 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -244,6 +244,9 @@
*/
public FetchCommand setProgressMonitor(ProgressMonitor monitor) {
checkCallable();
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
index 1e9fe5c..addca4c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -207,7 +207,7 @@
this(repo, false);
}
- private Git(Repository repo, boolean closeRepo) {
+ Git(Repository repo, boolean closeRepo) {
if (repo == null)
throw new NullPointerException();
this.repo = repo;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
index 63de85c..2783edd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -130,6 +130,9 @@
* @return this instance
*/
public PullCommand setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index 0e1ce58..227e322 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -257,6 +257,9 @@
*/
public PushCommand setProgressMonitor(ProgressMonitor monitor) {
checkCallable();
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 7196a2f..ff29008 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -1493,6 +1493,9 @@
* @return this instance
*/
public RebaseCommand setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
this.monitor = monitor;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
index 06c8f41..fbb24c1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -173,6 +173,8 @@
CloneCommand clone = Git.cloneRepository();
configure(clone);
clone.setDirectory(moduleDirectory);
+ clone.setGitDir(new File(new File(repo.getDirectory(),
+ Constants.MODULES), path));
clone.setURI(resolvedUri);
if (monitor != null)
clone.setProgressMonitor(monitor);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
index c8d96a0..b9f2a56 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
@@ -45,6 +45,15 @@
/**
* @param message
+ * @param cause
+ * @since 4.1
+ */
+ public RefNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
*/
public RefNotFoundException(String message) {
super(message);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
index 25d7e4d..1d54f77 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/StashApplyFailureException.java
@@ -10,6 +10,15 @@
private static final long serialVersionUID = 1L;
/**
+ * @param message
+ * @param cause
+ * @since 4.1
+ */
+ public StashApplyFailureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
* Create a StashApplyFailedException
*
* @param message
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
index 0990040..082f94c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnmergedPathsException.java
@@ -61,4 +61,13 @@
public UnmergedPathsException(Throwable cause) {
super(JGitText.get().unmergedPaths, cause);
}
+
+ /**
+ * @param message
+ * @param cause
+ * @since 4.1
+ */
+ public UnmergedPathsException(String message, Throwable cause) {
+ super(message, cause);
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index bcc30c3..fc701f3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -665,16 +665,12 @@
format(res.header, res.a, res.b);
}
- private static void writeGitLinkDiffText(OutputStream o, DiffEntry ent)
- throws IOException {
- if (ent.getOldMode() == GITLINK) {
- o.write(encodeASCII("-Subproject commit " + ent.getOldId().name() //$NON-NLS-1$
- + "\n")); //$NON-NLS-1$
+ private static byte[] writeGitLinkText(AbbreviatedObjectId id) {
+ if (id.toObjectId().equals(ObjectId.zeroId())) {
+ return EMPTY;
}
- if (ent.getNewMode() == GITLINK) {
- o.write(encodeASCII("+Subproject commit " + ent.getNewId().name() //$NON-NLS-1$
- + "\n")); //$NON-NLS-1$
- }
+ return encodeASCII("Subproject commit " + id.name() //$NON-NLS-1$
+ + "\n"); //$NON-NLS-1$
}
private String format(AbbreviatedObjectId id) {
@@ -938,13 +934,7 @@
formatHeader(buf, ent);
- if (ent.getOldMode() == GITLINK || ent.getNewMode() == GITLINK) {
- formatOldNewPaths(buf, ent);
- writeGitLinkDiffText(buf, ent);
- editList = new EditList();
- type = PatchType.UNIFIED;
-
- } else if (ent.getOldId() == null || ent.getNewId() == null) {
+ if (ent.getOldId() == null || ent.getNewId() == null) {
// Content not changed (e.g. only mode, pure rename)
editList = new EditList();
type = PatchType.UNIFIED;
@@ -952,8 +942,15 @@
} else {
assertHaveRepository();
- byte[] aRaw = open(OLD, ent);
- byte[] bRaw = open(NEW, ent);
+ byte[] aRaw, bRaw;
+
+ if (ent.getOldMode() == GITLINK || ent.getNewMode() == GITLINK) {
+ aRaw = writeGitLinkText(ent.getOldId());
+ bRaw = writeGitLinkText(ent.getNewId());
+ } else {
+ aRaw = open(OLD, ent);
+ bRaw = open(NEW, ent);
+ }
if (aRaw == BINARY || bRaw == BINARY //
|| RawText.isBinary(aRaw) || RawText.isBinary(bRaw)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
index 83aa8fa..f139afc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
@@ -478,6 +478,7 @@
// The entry is contained in this subtree.
//
+ assert(st != null);
st.validate(cache, cCnt, cIdx, pathOff + st.nameLength() + 1);
cIdx += st.entrySpan;
entrySpan += st.entrySpan;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
index e6ae685..5f9ce35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DiffInterruptedException.java
@@ -51,4 +51,26 @@
*/
public class DiffInterruptedException extends RuntimeException {
private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * @param cause
+ * @since 4.1
+ */
+ public DiffInterruptedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
+ * @since 4.1
+ */
+ public DiffInterruptedException(String message) {
+ super(message);
+ }
+
+ /** Indicates that the thread computing a diff was interrupted. */
+ public DiffInterruptedException() {
+ super();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
index b545312..390545f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/InvalidObjectIdException.java
@@ -45,7 +45,8 @@
package org.eclipse.jgit.errors;
-import java.io.UnsupportedEncodingException;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
import java.text.MessageFormat;
import org.eclipse.jgit.internal.JGitText;
@@ -64,16 +65,25 @@
* @param length of the sequence of invalid bytes.
*/
public InvalidObjectIdException(byte[] bytes, int offset, int length) {
- super(MessageFormat.format(JGitText.get().invalidId, asAscii(bytes, offset, length)));
+ super(msg(bytes, offset, length));
}
- private static String asAscii(byte[] bytes, int offset, int length) {
+ /**
+ * @param id the invalid id.
+ *
+ * @since 4.1
+ */
+ public InvalidObjectIdException(String id) {
+ super(MessageFormat.format(JGitText.get().invalidId, id));
+ }
+
+ private static String msg(byte[] bytes, int offset, int length) {
try {
- return ": " + new String(bytes, offset, length, "US-ASCII"); //$NON-NLS-1$ //$NON-NLS-2$
- } catch (UnsupportedEncodingException e2) {
- return ""; //$NON-NLS-1$
- } catch (StringIndexOutOfBoundsException e2) {
- return ""; //$NON-NLS-1$
+ return MessageFormat.format(
+ JGitText.get().invalidId,
+ new String(bytes, offset, length, US_ASCII));
+ } catch (StringIndexOutOfBoundsException e) {
+ return JGitText.get().invalidId0;
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
index 18aa9d9..0142e17 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/LockFailedException.java
@@ -57,6 +57,20 @@
private File file;
/**
+ * @param file
+ * file that could not be locked
+ * @param message
+ * exception message
+ * @param cause
+ * cause, for later retrieval by {@link Throwable#getCause()}
+ * @since 4.1
+ */
+ public LockFailedException(File file, String message, Throwable cause) {
+ super(message, cause);
+ this.file = file;
+ }
+
+ /**
* Construct a CannotLockException for the given file and message
*
* @param file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
index 5503bd1..44bc164 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackProtocolException.java
@@ -60,7 +60,7 @@
* @param uri
* URI used for transport
* @param s
- * message
+ * message, which may be shown to an end-user.
*/
public PackProtocolException(final URIish uri, final String s) {
super(uri + ": " + s); //$NON-NLS-1$
@@ -73,7 +73,7 @@
* @param uri
* URI used for transport
* @param s
- * message
+ * message, which may be shown to an end-user.
* @param cause
* root cause exception
*/
@@ -86,7 +86,7 @@
* Constructs an PackProtocolException with the specified detail message.
*
* @param s
- * message
+ * message, which may be shown to an end-user.
*/
public PackProtocolException(final String s) {
super(s);
@@ -96,7 +96,7 @@
* Constructs an PackProtocolException with the specified detail message.
*
* @param s
- * message
+ * message, which may be shown to an end-user.
* @param cause
* root cause exception
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index fa27948..891479d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -183,6 +183,9 @@
String qName,
Attributes attributes) throws SAXException {
if ("project".equals(qName)) { //$NON-NLS-1$
+ if (attributes.getValue("name") == null) { //$NON-NLS-1$
+ throw new SAXException(RepoText.get().invalidManifest);
+ }
currentProject = new RepoProject(
attributes.getValue("name"), //$NON-NLS-1$
attributes.getValue("path"), //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index b39dd8a..790f4db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -105,6 +105,7 @@
private String uri;
private String groups;
private String branch;
+ private String targetBranch = Constants.HEAD;
private PersonIdent author;
private RemoteReader callback;
private InputStream inputStream;
@@ -224,27 +225,27 @@
/**
* @param repo
*/
- public RepoCommand(final Repository repo) {
+ public RepoCommand(Repository repo) {
super(repo);
}
/**
* Set path to the manifest XML file.
- *
+ * <p>
* Calling {@link #setInputStream} will ignore the path set here.
*
* @param path
* (with <code>/</code> as separator)
* @return this command
*/
- public RepoCommand setPath(final String path) {
+ public RepoCommand setPath(String path) {
this.path = path;
return this;
}
/**
* Set the input stream to the manifest XML.
- *
+ * <p>
* Setting inputStream will ignore the path set. It will be closed in
* {@link #call}.
*
@@ -252,7 +253,7 @@
* @return this command
* @since 3.5
*/
- public RepoCommand setInputStream(final InputStream inputStream) {
+ public RepoCommand setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
return this;
}
@@ -263,7 +264,7 @@
* @param uri
* @return this command
*/
- public RepoCommand setURI(final String uri) {
+ public RepoCommand setURI(String uri) {
this.uri = uri;
return this;
}
@@ -274,14 +275,14 @@
* @param groups groups separated by comma, examples: default|all|G1,-G2,-G3
* @return this command
*/
- public RepoCommand setGroups(final String groups) {
+ public RepoCommand setGroups(String groups) {
this.groups = groups;
return this;
}
/**
* Set default branch.
- *
+ * <p>
* This is generally the name of the branch the manifest file was in. If
* there's no default revision (branch) specified in manifest and no
* revision specified in project, this branch will be used.
@@ -289,12 +290,30 @@
* @param branch
* @return this command
*/
- public RepoCommand setBranch(final String branch) {
+ public RepoCommand setBranch(String branch) {
this.branch = branch;
return this;
}
/**
+ * Set target branch.
+ * <p>
+ * This is the target branch of the super project to be updated. If not set,
+ * default is HEAD.
+ * <p>
+ * For non-bare repositories, HEAD will always be used and this will be
+ * ignored.
+ *
+ * @param branch
+ * @return this command
+ * @since 4.1
+ */
+ public RepoCommand setTargetBranch(String branch) {
+ this.targetBranch = Constants.R_HEADS + branch;
+ return this;
+ }
+
+ /**
* The progress monitor associated with the clone operation. By default,
* this is set to <code>NullProgressMonitor</code>
*
@@ -309,7 +328,7 @@
/**
* Set the author/committer for the bare repository commit.
- *
+ * <p>
* For non-bare repositories, the current user will be used and this will be
* ignored.
*
@@ -445,7 +464,7 @@
ObjectId treeId = index.writeTree(inserter);
// Create a Commit object, populate it and write it
- ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}"); //$NON-NLS-1$
+ ObjectId headId = repo.resolve(targetBranch + "^{commit}"); //$NON-NLS-1$
CommitBuilder commit = new CommitBuilder();
commit.setTreeId(treeId);
if (headId != null)
@@ -457,7 +476,7 @@
ObjectId commitId = inserter.insert(commit);
inserter.flush();
- RefUpdate ru = repo.updateRef(Constants.HEAD);
+ RefUpdate ru = repo.updateRef(targetBranch);
ru.setNewObjectId(commitId);
ru.setExpectedOldObjectId(headId != null ? headId : ObjectId.zeroId());
Result rc = ru.update(rw);
@@ -471,12 +490,14 @@
case REJECTED:
case LOCK_FAILURE:
throw new ConcurrentRefUpdateException(
- JGitText.get().couldNotLockHEAD, ru.getRef(),
+ MessageFormat.format(
+ JGitText.get().cannotLock, targetBranch),
+ ru.getRef(),
rc);
default:
throw new JGitInternalException(MessageFormat.format(
JGitText.get().updatingRefFailed,
- Constants.HEAD, commitId.name(), rc));
+ targetBranch, commitId.name(), rc));
}
return rw.parseCommit(commitId);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index 1fff1c3..9a07211 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -138,6 +138,9 @@
*/
public RepoProject(String name, String path, String revision,
String remote, String groups) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
this.name = name;
if (path != null)
this.path = path;
@@ -221,7 +224,7 @@
/**
* Get the name of the remote definition of the sub repo.
*
- * @return {@remote}
+ * @return {@code remote}
*/
public String getRemote() {
return remote;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
index 2303ffd..e376cbb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -47,6 +47,8 @@
import org.eclipse.jgit.errors.InvalidPatternException;
import org.eclipse.jgit.ignore.internal.IMatcher;
import org.eclipse.jgit.ignore.internal.PathMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* "Fast" (compared with IgnoreRule) git ignore rule implementation supporting
@@ -57,6 +59,8 @@
* @since 3.6
*/
public class FastIgnoreRule {
+ private final static Logger LOG = LoggerFactory
+ .getLogger(FastIgnoreRule.class);
/**
* Character used as default path separator for ignore entries
@@ -98,24 +102,32 @@
if (pattern.charAt(0) == '#') {
this.matcher = NO_MATCH;
dirOnly = false;
- } else {
- dirOnly = pattern.charAt(pattern.length() - 1) == PATH_SEPARATOR;
- if (dirOnly) {
- pattern = stripTrailing(pattern, PATH_SEPARATOR);
- if (pattern.length() == 0) {
- this.matcher = NO_MATCH;
- return;
- }
- }
- IMatcher m;
- try {
- m = PathMatcher.createPathMatcher(pattern,
- Character.valueOf(PATH_SEPARATOR), dirOnly);
- } catch (InvalidPatternException e) {
- m = NO_MATCH;
- }
- this.matcher = m;
+ return;
}
+ if (pattern.charAt(0) == '\\' && pattern.length() > 1) {
+ char next = pattern.charAt(1);
+ if (next == '!' || next == '#') {
+ // remove backslash escaping first special characters
+ pattern = pattern.substring(1);
+ }
+ }
+ dirOnly = pattern.charAt(pattern.length() - 1) == PATH_SEPARATOR;
+ if (dirOnly) {
+ pattern = stripTrailing(pattern, PATH_SEPARATOR);
+ if (pattern.length() == 0) {
+ this.matcher = NO_MATCH;
+ return;
+ }
+ }
+ IMatcher m;
+ try {
+ m = PathMatcher.createPathMatcher(pattern,
+ Character.valueOf(PATH_SEPARATOR), dirOnly);
+ } catch (InvalidPatternException e) {
+ m = NO_MATCH;
+ LOG.error(e.getMessage(), e);
+ }
+ this.matcher = m;
}
/**
@@ -176,6 +188,14 @@
return !inverse;
}
+ /**
+ * @return true if the rule never matches (comment line or broken pattern)
+ * @since 4.1
+ */
+ public boolean isEmpty() {
+ return matcher == NO_MATCH;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
index efaeacd..8b1244e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreNode.java
@@ -109,9 +109,12 @@
BufferedReader br = asReader(in);
String txt;
while ((txt = br.readLine()) != null) {
- txt = txt.trim();
- if (txt.length() > 0 && !txt.startsWith("#") && !txt.equals("/")) //$NON-NLS-1$ //$NON-NLS-2$
- rules.add(new FastIgnoreRule(txt));
+ if (txt.length() > 0 && !txt.startsWith("#") && !txt.equals("/")) { //$NON-NLS-1$ //$NON-NLS-2$
+ FastIgnoreRule rule = new FastIgnoreRule(txt);
+ if (!rule.isEmpty()) {
+ rules.add(rule);
+ }
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
index f1153d9..3d0ad09 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java
@@ -50,7 +50,7 @@
public class LeadingAsteriskMatcher extends NameMatcher {
LeadingAsteriskMatcher(String pattern, Character pathSeparator, boolean dirOnly) {
- super(pattern, pathSeparator, dirOnly);
+ super(pattern, pathSeparator, dirOnly, true);
if (subPattern.charAt(0) != '*')
throw new IllegalArgumentException(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
index 6c4c809..8beae83 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java
@@ -58,9 +58,13 @@
final String subPattern;
- NameMatcher(String pattern, Character pathSeparator, boolean dirOnly) {
+ NameMatcher(String pattern, Character pathSeparator, boolean dirOnly,
+ boolean deleteBackslash) {
super(pattern, dirOnly);
slash = getPathSeparator(pathSeparator);
+ if (deleteBackslash) {
+ pattern = Strings.deleteBackslash(pattern);
+ }
beginning = pattern.length() == 0 ? false : pattern.charAt(0) == slash;
if (!beginning)
this.subPattern = pattern;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
index d3e5f6a..c3f6694 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
@@ -85,7 +85,8 @@
}
private boolean isSimplePathWithSegments(String path) {
- return !isWildCard(path) && count(path, slash, true) > 0;
+ return !isWildCard(path) && path.indexOf('\\') < 0
+ && count(path, slash, true) > 0;
}
static private List<IMatcher> createMatchers(List<String> segments,
@@ -118,7 +119,7 @@
public static IMatcher createPathMatcher(String pattern,
Character pathSeparator, boolean dirOnly)
throws InvalidPatternException {
- pattern = pattern.trim();
+ pattern = trim(pattern);
char slash = Strings.getPathSeparator(pathSeparator);
// ignore possible leading and trailing slash
int slashIdx = pattern.indexOf(slash, 1);
@@ -127,6 +128,29 @@
return createNameMatcher0(pattern, pathSeparator, dirOnly);
}
+ /**
+ * Trim trailing spaces, unless they are escaped with backslash, see
+ * https://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+ *
+ * @param pattern
+ * non null
+ * @return trimmed pattern
+ */
+ private static String trim(String pattern) {
+ while (pattern.length() > 0
+ && pattern.charAt(pattern.length() - 1) == ' ') {
+ if (pattern.length() > 1
+ && pattern.charAt(pattern.length() - 2) == '\\') {
+ // last space was escaped by backslash: remove backslash and
+ // keep space
+ pattern = pattern.substring(0, pattern.length() - 2) + " "; //$NON-NLS-1$
+ return pattern;
+ }
+ pattern = pattern.substring(0, pattern.length() - 1);
+ }
+ return pattern;
+ }
+
private static IMatcher createNameMatcher0(String segment,
Character pathSeparator, boolean dirOnly)
throws InvalidPatternException {
@@ -144,7 +168,7 @@
case COMPLEX:
return new WildCardMatcher(segment, pathSeparator, dirOnly);
default:
- return new NameMatcher(segment, pathSeparator, dirOnly);
+ return new NameMatcher(segment, pathSeparator, dirOnly, true);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
index cd4d753..f972828 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
@@ -44,13 +44,16 @@
import static java.lang.Character.isLetter;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
import org.eclipse.jgit.errors.InvalidPatternException;
import org.eclipse.jgit.ignore.FastIgnoreRule;
+import org.eclipse.jgit.internal.JGitText;
/**
* Various {@link String} related utility methods, written mostly to avoid
@@ -138,16 +141,36 @@
private static boolean isComplexWildcard(String pattern) {
int idx1 = pattern.indexOf('[');
if (idx1 != -1) {
- int idx2 = pattern.indexOf(']');
+ int idx2 = pattern.indexOf(']', idx1);
if (idx2 > idx1)
return true;
}
- // required to match escaped backslashes '\\\\'
- if (pattern.indexOf('?') != -1 || pattern.indexOf('\\') != -1)
+ if (pattern.indexOf('?') != -1) {
return true;
+ } else {
+ // check if the backslash escapes one of the glob special characters
+ // if not, backslash is not part of a regex and treated literally
+ int backSlash = pattern.indexOf('\\');
+ if (backSlash >= 0) {
+ int nextIdx = backSlash + 1;
+ if (pattern.length() == nextIdx) {
+ return false;
+ }
+ char nextChar = pattern.charAt(nextIdx);
+ if (escapedByBackslash(nextChar)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
return false;
}
+ private static boolean escapedByBackslash(char nextChar) {
+ return nextChar == '?' || nextChar == '*' || nextChar == '[';
+ }
+
static PatternState checkWildCards(String pattern) {
if (isComplexWildcard(pattern))
return PatternState.COMPLEX;
@@ -226,7 +249,7 @@
char[] charClass = new char[6];
for (int i = 0; i < pattern.length(); i++) {
- char c = pattern.charAt(i);
+ final char c = pattern.charAt(i);
switch (c) {
case '*':
@@ -236,6 +259,20 @@
sb.append('.').append(c);
break;
+ case '(': // fall-through
+ case ')': // fall-through
+ case '{': // fall-through
+ case '}': // fall-through
+ case '+': // fall-through
+ case '$': // fall-through
+ case '^': // fall-through
+ case '|':
+ if (seenEscape || in_brackets > 0)
+ sb.append(c);
+ else
+ sb.append('\\').append(c);
+ break;
+
case '.':
if (seenEscape)
sb.append(c);
@@ -273,6 +310,14 @@
char lookAhead = lookAhead(pattern, i);
if (lookAhead == ']' || lookAhead == '[')
ignoreLastBracket = true;
+ } else {
+ //
+ char lookAhead = lookAhead(pattern, i);
+ if (lookAhead != '\\' && lookAhead != '['
+ && lookAhead != '?' && lookAhead != '*'
+ && lookAhead != ' ' && lookBehind(sb) != '\\') {
+ break;
+ }
}
sb.append(c);
break;
@@ -349,7 +394,16 @@
if (in_brackets > 0)
throw new InvalidPatternException("Not closed bracket?", pattern); //$NON-NLS-1$
- return Pattern.compile(sb.toString());
+ try {
+ return Pattern.compile(sb.toString());
+ } catch (PatternSyntaxException e) {
+ InvalidPatternException patternException = new InvalidPatternException(
+ MessageFormat.format(JGitText.get().invalidIgnoreRule,
+ pattern),
+ pattern);
+ patternException.initCause(e);
+ throw patternException;
+ }
}
/**
@@ -401,4 +455,30 @@
return null;
}
+ static String deleteBackslash(String s) {
+ if (s.indexOf('\\') < 0) {
+ return s;
+ }
+ StringBuilder sb = new StringBuilder(s.length());
+ for (int i = 0; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ if (ch == '\\') {
+ if (i + 1 == s.length()) {
+ continue;
+ }
+ char next = s.charAt(i + 1);
+ if (next == '\\') {
+ sb.append(ch);
+ i++;
+ continue;
+ }
+ if (!escapedByBackslash(next)) {
+ continue;
+ }
+ }
+ sb.append(ch);
+ }
+ return sb.toString();
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
index 4a1c780..b927d27 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java
@@ -50,7 +50,7 @@
public class TrailingAsteriskMatcher extends NameMatcher {
TrailingAsteriskMatcher(String pattern, Character pathSeparator, boolean dirOnly) {
- super(pattern, pathSeparator, dirOnly);
+ super(pattern, pathSeparator, dirOnly, true);
if (subPattern.charAt(subPattern.length() - 1) != '*')
throw new IllegalArgumentException(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
index 7d12b0d..8f98152 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java
@@ -62,7 +62,7 @@
WildCardMatcher(String pattern, Character pathSeparator, boolean dirOnly)
throws InvalidPatternException {
- super(pattern, pathSeparator, dirOnly);
+ super(pattern, pathSeparator, dirOnly, false);
p = convertGlob(subPattern);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 9f6efef..9067e82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -296,12 +296,10 @@
/***/ public String errorEncodingFromFile;
/***/ public String errorInBase64CodeReadingStream;
/***/ public String errorInPackedRefs;
- /***/ public String errorInvalidPushCert;
/***/ public String errorInvalidProtocolWantedOldNewRef;
/***/ public String errorListing;
/***/ public String errorOccurredDuringUnpackingOnTheRemoteEnd;
/***/ public String errorReadingInfoRefs;
- /***/ public String errorSymlinksNotSupported;
/***/ public String exceptionCaughtDuringExecutionOfHook;
/***/ public String exceptionCaughtDuringExecutionOfAddCommand;
/***/ public String exceptionCaughtDuringExecutionOfArchiveCommand;
@@ -347,7 +345,6 @@
/***/ public String gcFailed;
/***/ public String gitmodulesNotFound;
/***/ public String headRequiredToStash;
- /***/ public String hiddenFilesStartWithDot;
/***/ public String hoursAgo;
/***/ public String hugeIndexesAreNotSupportedByJgitYet;
/***/ public String hunkBelongsToAnotherFile;
@@ -385,8 +382,10 @@
/***/ public String invalidGitdirRef;
/***/ public String invalidGitType;
/***/ public String invalidId;
+ /***/ public String invalidId0;
/***/ public String invalidIdLength;
/***/ public String invalidIgnoreParamSubmodule;
+ /***/ public String invalidIgnoreRule;
/***/ public String invalidIntegerValue;
/***/ public String invalidKey;
/***/ public String invalidLineInConfigFile;
@@ -403,6 +402,7 @@
/***/ public String invalidReflogRevision;
/***/ public String invalidRefName;
/***/ public String invalidRemote;
+ /***/ public String invalidShallowObject;
/***/ public String invalidStageForPath;
/***/ public String invalidTagOption;
/***/ public String invalidTimeout;
@@ -499,6 +499,7 @@
/***/ public String packChecksumMismatch;
/***/ public String packCorruptedWhileWritingToFilesystem;
/***/ public String packDoesNotMatchIndex;
+ /***/ public String packedRefsHandleIsStale;
/***/ public String packetSizeMustBeAtLeast;
/***/ public String packetSizeMustBeAtMost;
/***/ public String packfileCorruptionDetected;
@@ -532,6 +533,10 @@
/***/ public String pullOnRepoWithoutHEADCurrentlyNotSupported;
/***/ public String pullTaskName;
/***/ public String pushCancelled;
+ /***/ public String pushCertificateInvalidField;
+ /***/ public String pushCertificateInvalidFieldValue;
+ /***/ public String pushCertificateInvalidHeader;
+ /***/ public String pushCertificateInvalidSignature;
/***/ public String pushIsNotSupportedForBundleTransport;
/***/ public String pushNotPermitted;
/***/ public String rawLogMessageDoesNotParseAsLogEntry;
@@ -590,7 +595,6 @@
/***/ public String sequenceTooLargeForDiffAlgorithm;
/***/ public String serviceNotEnabledNoName;
/***/ public String serviceNotPermitted;
- /***/ public String serviceNotPermittedNoName;
/***/ public String shallowCommitsAlreadyInitialized;
/***/ public String shortCompressedStreamAt;
/***/ public String shortReadOfBlock;
@@ -620,6 +624,9 @@
/***/ public String stashFailed;
/***/ public String stashResolveFailed;
/***/ public String statelessRPCRequiresOptionToBeEnabled;
+ /***/ public String storePushCertMultipleRefs;
+ /***/ public String storePushCertOneRef;
+ /***/ public String storePushCertReflog;
/***/ public String submoduleExists;
/***/ public String submodulesNotSupported;
/***/ public String submoduleParentRemoteUrlInvalid;
@@ -661,6 +668,7 @@
/***/ public String unableToCreateNewObject;
/***/ public String unableToStore;
/***/ public String unableToWrite;
+ /***/ public String unauthorized;
/***/ public String unencodeableFile;
/***/ public String unexpectedCompareResult;
/***/ public String unexpectedEndOfConfigFile;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
index de66292..faf27e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -72,6 +72,7 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.util.io.CountingOutputStream;
/** Repack and garbage collect a repository. */
@@ -84,7 +85,7 @@
private final List<DfsPackDescription> newPackDesc;
- private final List<PackWriter.Statistics> newPackStats;
+ private final List<PackStatistics> newPackStats;
private final List<PackWriter.ObjectIdSet> newPackObj;
@@ -115,7 +116,7 @@
refdb = repo.getRefDatabase();
objdb = repo.getObjectDatabase();
newPackDesc = new ArrayList<DfsPackDescription>(4);
- newPackStats = new ArrayList<PackWriter.Statistics>(4);
+ newPackStats = new ArrayList<PackStatistics>(4);
newPackObj = new ArrayList<PackWriter.ObjectIdSet>(4);
packConfig = new PackConfig(repo);
@@ -258,7 +259,7 @@
}
/** @return statistics corresponding to the {@link #getNewPacks()}. */
- public List<PackWriter.Statistics> getNewPackStatistics() {
+ public List<PackStatistics> getNewPackStatistics() {
return newPackStats;
}
@@ -396,7 +397,7 @@
}
});
- PackWriter.Statistics stats = pw.getStatistics();
+ PackStatistics stats = pw.getStatistics();
pack.setPackStats(stats);
newPackStats.add(stats);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index dbe72b2..7073763 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -67,6 +67,7 @@
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.io.CountingOutputStream;
@@ -94,7 +95,7 @@
private final List<DfsPackDescription> newPacks;
- private final List<PackWriter.Statistics> newStats;
+ private final List<PackStatistics> newStats;
private int autoAddSize;
@@ -114,7 +115,7 @@
srcPacks = new ArrayList<DfsPackFile>();
exclude = new ArrayList<PackWriter.ObjectIdSet>(4);
newPacks = new ArrayList<DfsPackDescription>(1);
- newStats = new ArrayList<PackWriter.Statistics>(1);
+ newStats = new ArrayList<PackStatistics>(1);
}
/**
@@ -231,7 +232,7 @@
writePack(objdb, pack, pw, pm);
writeIndex(objdb, pack, pw);
- PackWriter.Statistics stats = pw.getStatistics();
+ PackStatistics stats = pw.getStatistics();
pw.close();
pw = null;
@@ -264,7 +265,7 @@
}
/** @return statistics corresponding to the {@link #getNewPacks()}. */
- public List<PackWriter.Statistics> getNewPackStatistics() {
+ public List<PackStatistics> getNewPackStatistics() {
return newStats;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
index fba5157..2b9d0e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
@@ -50,7 +50,7 @@
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.pack.PackExt;
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.storage.pack.PackStatistics;
/**
* Description of a DFS stored pack/index file.
@@ -75,7 +75,7 @@
private long deltaCount;
- private PackWriter.Statistics stats;
+ private PackStatistics stats;
private int extensions;
@@ -225,11 +225,11 @@
* DfsGarbageCollector or DfsPackCompactor, and only when the pack
* is being committed to the repository.
*/
- public PackWriter.Statistics getPackStats() {
+ public PackStatistics getPackStats() {
return stats;
}
- DfsPackDescription setPackStats(PackWriter.Statistics stats) {
+ DfsPackDescription setPackStats(PackStatistics stats) {
this.stats = stats;
setFileSize(PACK, stats.getTotalBytes());
setObjectCount(stats.getTotalObjects());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index 75b0646..96f1d54 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -533,7 +533,6 @@
return ByteBuffer.wrap(copyBuf, 0, bs);
}
- @SuppressWarnings("null")
void copyAsIs(PackOutputStream out, DfsObjectToPack src,
boolean validate, DfsReader ctx) throws IOException,
StoredObjectRepresentationNotAvailableException {
@@ -567,22 +566,26 @@
c = buf[headerCnt++] & 0xff;
} while ((c & 128) != 0);
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
} else if (typeCode == Constants.OBJ_REF_DELTA) {
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
readFully(src.offset + headerCnt, buf, 0, 20, ctx);
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, 20);
crc2.update(buf, 0, 20);
}
headerCnt += 20;
} else if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
@@ -599,6 +602,7 @@
quickCopy = ctx.quickCopy(this, dataOffset, dataLength);
if (validate && idx(ctx).hasCRC32Support()) {
+ assert(crc1 != null);
// Index has the CRC32 code cached, validate the object.
//
expectedCRC = idx(ctx).findCRC32(src);
@@ -622,6 +626,7 @@
Long.valueOf(src.offset), getPackName()));
}
} else if (validate) {
+ assert(crc1 != null);
// We don't have a CRC32 code in the index, so compute it
// now while inflating the raw data to get zlib to tell us
// whether or not the data is safe.
@@ -709,16 +714,21 @@
while (cnt > 0) {
final int n = (int) Math.min(cnt, buf.length);
readFully(pos, buf, 0, n, ctx);
- if (validate)
+ if (validate) {
+ assert(crc2 != null);
crc2.update(buf, 0, n);
+ }
out.write(buf, 0, n);
pos += n;
cnt -= n;
}
- if (validate && crc2.getValue() != expectedCRC) {
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackName()));
+ if (validate) {
+ assert(crc2 != null);
+ if (crc2.getValue() != expectedCRC) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackName()));
+ }
}
}
}
@@ -837,7 +847,6 @@
return buf.position();
}
- @SuppressWarnings("null")
ObjectLoader load(DfsReader ctx, long pos)
throws IOException {
try {
@@ -934,6 +943,7 @@
if (data == null)
throw new LargeObjectException();
+ assert(delta != null);
do {
// Cache only the base immediately before desired object.
if (cached)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index ed8acd5..a1035a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -91,6 +91,13 @@
}
@Override
+ public Ref exactRef(String name) throws IOException {
+ RefCache curr = read();
+ Ref ref = curr.ids.get(name);
+ return ref != null ? resolve(ref, 0, curr.ids) : null;
+ }
+
+ @Override
public Ref getRef(String needle) throws IOException {
RefCache curr = read();
for (String prefix : SEARCH_PATH) {
@@ -103,14 +110,6 @@
return null;
}
- private Ref getOneRef(String refName) throws IOException {
- RefCache curr = read();
- Ref ref = curr.ids.get(refName);
- if (ref != null)
- return resolve(ref, 0, curr.ids);
- return ref;
- }
-
@Override
public List<Ref> getAdditionalRefs() {
return Collections.emptyList();
@@ -212,7 +211,7 @@
public RefUpdate newUpdate(String refName, boolean detach)
throws IOException {
boolean detachingSymbolicRef = false;
- Ref ref = getOneRef(refName);
+ Ref ref = exactRef(refName);
if (ref == null)
ref = new ObjectIdRef.Unpeeled(NEW, refName, null);
else
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 796109a..e7ef127 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -114,8 +114,6 @@
/** Maximum number of candidates offered as resolutions of abbreviation. */
private static final int RESOLVE_ABBREV_LIMIT = 256;
- private static final String STALE_FILE_HANDLE_MSG = "stale file handle"; //$NON-NLS-1$
-
private final Config config;
private final File objects;
@@ -565,8 +563,7 @@
} else if (e instanceof FileNotFoundException) {
warnTmpl = JGitText.get().packWasDeleted;
removePack(p);
- } else if (e.getMessage() != null
- && e.getMessage().toLowerCase().contains(STALE_FILE_HANDLE_MSG)) {
+ } else if (FileUtils.isStaleFileHandle(e)) {
warnTmpl = JGitText.get().packHandleIsStale;
removePack(p);
}
@@ -602,7 +599,7 @@
}
final File dst = fileFor(id);
- if (fs.exists(dst)) {
+ if (dst.exists()) {
// We want to be extra careful and avoid replacing an object
// that already exists. We can't be sure renameTo() would
// fail on all platforms if dst exists, so we check first.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
index 05cd100..93f8918 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
@@ -44,7 +44,7 @@
package org.eclipse.jgit.internal.storage.file;
import java.text.MessageFormat;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -73,7 +73,7 @@
private final EWAHCompressedBitmap trees;
private final EWAHCompressedBitmap blobs;
private final EWAHCompressedBitmap tags;
- private final ObjectToPack[] byOffset;
+ private final BlockList<PositionEntry> byOffset;
private final BlockList<StoredBitmap>
byAddOrder = new BlockList<StoredBitmap>();
private final ObjectIdOwnerMap<PositionEntry>
@@ -83,20 +83,25 @@
* Creates a PackBitmapIndex used for building the contents of an index
* file.
*
- * @param byName
- * objects sorted by name.
+ * @param objects
+ * objects sorted by name. The list must be initially sorted by
+ * ObjectId (name); it will be resorted in place.
*/
- public PackBitmapIndexBuilder(List<ObjectToPack> byName) {
+ public PackBitmapIndexBuilder(List<ObjectToPack> objects) {
super(new ObjectIdOwnerMap<StoredBitmap>());
- byOffset = sortByOffset(byName);
+ byOffset = new BlockList<>(objects.size());
+ sortByOffsetAndIndex(byOffset, positionEntries, objects);
- int sizeInWords = Math.max(byOffset.length / 64, 4);
+ // 64 objects fit in a single long word (64 bits).
+ // On average a repository is 30% commits, 30% trees, 30% blobs.
+ // Initialize bitmap capacity for worst case to minimize growing.
+ int sizeInWords = Math.max(4, byOffset.size() / 64 / 3);
commits = new EWAHCompressedBitmap(sizeInWords);
trees = new EWAHCompressedBitmap(sizeInWords);
blobs = new EWAHCompressedBitmap(sizeInWords);
tags = new EWAHCompressedBitmap(sizeInWords);
- for (int i = 0; i < byOffset.length; i++) {
- int type = byOffset[i].getType();
+ for (int i = 0; i < objects.size(); i++) {
+ int type = objects.get(i).getType();
switch (type) {
case Constants.OBJ_COMMIT:
commits.set(i);
@@ -115,22 +120,39 @@
JGitText.get().badObjectType, String.valueOf(type)));
}
}
+ commits.trim();
+ trees.trim();
+ blobs.trim();
+ tags.trim();
}
- private ObjectToPack[] sortByOffset(List<ObjectToPack> entries) {
- ObjectToPack[] result = new ObjectToPack[entries.size()];
- for (int i = 0; i < result.length; i++) {
- result[i] = entries.get(i);
- positionEntries.add(new PositionEntry(result[i], i));
+ private static void sortByOffsetAndIndex(BlockList<PositionEntry> byOffset,
+ ObjectIdOwnerMap<PositionEntry> positionEntries,
+ List<ObjectToPack> entries) {
+ for (int i = 0; i < entries.size(); i++) {
+ positionEntries.add(new PositionEntry(entries.get(i), i));
}
- Arrays.sort(result, new Comparator<ObjectToPack>() {
+ Collections.sort(entries, new Comparator<ObjectToPack>() {
public int compare(ObjectToPack a, ObjectToPack b) {
return Long.signum(a.getOffset() - b.getOffset());
}
});
- for (int i = 0; i < result.length; i++)
- positionEntries.get(result[i]).offsetPosition = i;
- return result;
+ for (int i = 0; i < entries.size(); i++) {
+ PositionEntry e = positionEntries.get(entries.get(i));
+ e.offsetPosition = i;
+ byOffset.add(e);
+ }
+ }
+
+ /** @return set of objects included in the pack. */
+ public ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> getObjectSet() {
+ ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> r = new ObjectIdOwnerMap<>();
+ for (PositionEntry e : byOffset) {
+ r.add(new ObjectIdOwnerMap.Entry(e) {
+ // A new entry that copies the ObjectId
+ });
+ }
+ return r;
}
/**
@@ -168,6 +190,7 @@
*/
public void addBitmap(
AnyObjectId objectId, EWAHCompressedBitmap bitmap, int flags) {
+ bitmap.trim();
StoredBitmap result = new StoredBitmap(objectId, bitmap, null, flags);
getBitmaps().add(result);
byAddOrder.add(result);
@@ -199,7 +222,7 @@
@Override
public ObjectId getObject(int position) throws IllegalArgumentException {
- ObjectId objectId = byOffset[position];
+ ObjectId objectId = byOffset.get(position);
if (objectId == null)
throw new IllegalArgumentException();
return objectId;
@@ -243,7 +266,7 @@
@Override
public int getObjectCount() {
- return byOffset.length;
+ return byOffset.size();
}
/** @return an iterator over the xor compressed entries. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
index 6d944fd..a38a26d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
@@ -60,8 +60,7 @@
import org.eclipse.jgit.util.NB;
/**
- * Support for the pack bitmap index v1 format, which contains experimental
- * support for bitmaps.
+ * Support for the pack bitmap index v1 format.
*
* @see PackBitmapIndex
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index b29966e..589a811 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -366,7 +366,6 @@
}
}
- @SuppressWarnings("null")
private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
boolean validate, WindowCursor curs) throws IOException,
StoredObjectRepresentationNotAvailableException {
@@ -393,22 +392,26 @@
c = buf[headerCnt++] & 0xff;
} while ((c & 128) != 0);
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
} else if (typeCode == Constants.OBJ_REF_DELTA) {
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
readFully(src.offset + headerCnt, buf, 0, 20, curs);
if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, 20);
crc2.update(buf, 0, 20);
}
headerCnt += 20;
} else if (validate) {
+ assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
@@ -425,6 +428,7 @@
quickCopy = curs.quickCopy(this, dataOffset, dataLength);
if (validate && idx().hasCRC32Support()) {
+ assert(crc1 != null);
// Index has the CRC32 code cached, validate the object.
//
expectedCRC = idx().findCRC32(src);
@@ -457,6 +461,7 @@
if (quickCopy != null) {
quickCopy.check(inf, tmp, dataOffset, (int) dataLength);
} else {
+ assert(crc1 != null);
long pos = dataOffset;
long cnt = dataLength;
while (cnt > 0) {
@@ -476,6 +481,7 @@
JGitText.get().shortCompressedStreamAt,
Long.valueOf(src.offset)));
}
+ assert(crc1 != null);
expectedCRC = crc1.getValue();
} else {
expectedCRC = -1;
@@ -535,16 +541,21 @@
while (cnt > 0) {
final int n = (int) Math.min(cnt, buf.length);
readFully(pos, buf, 0, n, curs);
- if (validate)
+ if (validate) {
+ assert(crc2 != null);
crc2.update(buf, 0, n);
+ }
out.write(buf, 0, n);
pos += n;
cnt -= n;
}
- if (validate && crc2.getValue() != expectedCRC) {
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()));
+ if (validate) {
+ assert(crc2 != null);
+ if (crc2.getValue() != expectedCRC) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()));
+ }
}
}
}
@@ -712,7 +723,6 @@
, getPackFile()));
}
- @SuppressWarnings("null")
ObjectLoader load(final WindowCursor curs, long pos)
throws IOException, LargeObjectException {
try {
@@ -811,6 +821,7 @@
if (data == null)
throw new IOException(JGitText.get().inMemoryBufferLimitExceeded);
+ assert(delta != null);
do {
// Cache only the base immediately before desired object.
if (cached)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 6d6d0ca..bb5b044 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -98,6 +98,8 @@
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.RefList;
import org.eclipse.jgit.util.RefMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Traditional file system based {@link RefDatabase}.
@@ -115,6 +117,9 @@
* overall size of a Git repository on disk.
*/
public class RefDirectory extends RefDatabase {
+ private final static Logger LOG = LoggerFactory
+ .getLogger(RefDirectory.class);
+
/** Magic string denoting the start of a symbolic reference file. */
public static final String SYMREF = "ref: "; //$NON-NLS-1$
@@ -257,6 +262,30 @@
}
@Override
+ public Ref exactRef(String name) throws IOException {
+ RefList<Ref> packed = getPackedRefs();
+ Ref ref;
+ try {
+ ref = readRef(name, packed);
+ if (ref != null) {
+ ref = resolve(ref, 0, null, null, packed);
+ }
+ } catch (IOException e) {
+ if (name.contains("/") //$NON-NLS-1$
+ || !(e.getCause() instanceof InvalidObjectIdException)) {
+ throw e;
+ }
+
+ // While looking for a ref outside of refs/ (e.g., 'config'), we
+ // found a non-ref file (e.g., a config file) instead. Treat this
+ // as a ref-not-found condition.
+ ref = null;
+ }
+ fireRefsChanged();
+ return ref;
+ }
+
+ @Override
public Ref getRef(final String needle) throws IOException {
final RefList<Ref> packed = getPackedRefs();
Ref ref = null;
@@ -746,22 +775,37 @@
}
private PackedRefList readPackedRefs() throws IOException {
- final FileSnapshot snapshot = FileSnapshot.save(packedRefsFile);
- final BufferedReader br;
- final MessageDigest digest = Constants.newMessageDigest();
- try {
- br = new BufferedReader(new InputStreamReader(
- new DigestInputStream(new FileInputStream(packedRefsFile),
- digest), CHARSET));
- } catch (FileNotFoundException noPackedRefs) {
- // Ignore it and leave the new list empty.
- return PackedRefList.NO_PACKED_REFS;
- }
- try {
- return new PackedRefList(parsePackedRefs(br), snapshot,
- ObjectId.fromRaw(digest.digest()));
- } finally {
- br.close();
+ int maxStaleRetries = 5;
+ int retries = 0;
+ while (true) {
+ final FileSnapshot snapshot = FileSnapshot.save(packedRefsFile);
+ final BufferedReader br;
+ final MessageDigest digest = Constants.newMessageDigest();
+ try {
+ br = new BufferedReader(new InputStreamReader(
+ new DigestInputStream(new FileInputStream(packedRefsFile),
+ digest), CHARSET));
+ } catch (FileNotFoundException noPackedRefs) {
+ // Ignore it and leave the new list empty.
+ return PackedRefList.NO_PACKED_REFS;
+ }
+ try {
+ return new PackedRefList(parsePackedRefs(br), snapshot,
+ ObjectId.fromRaw(digest.digest()));
+ } catch (IOException e) {
+ if (FileUtils.isStaleFileHandle(e) && retries < maxStaleRetries) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(MessageFormat.format(
+ JGitText.get().packedRefsHandleIsStale,
+ Integer.valueOf(retries)), e);
+ }
+ retries++;
+ continue;
+ }
+ throw e;
+ } finally {
+ br.close();
+ }
}
}
@@ -881,7 +925,6 @@
return n;
}
- @SuppressWarnings("null")
private LooseRef scanRef(LooseRef ref, String name) throws IOException {
final File path = fileFor(name);
FileSnapshot currentSnapshot = null;
@@ -920,6 +963,7 @@
final String target = RawParseUtils.decode(buf, 5, n);
if (ref != null && ref.isSymbolic()
&& ref.getTarget().getName().equals(target)) {
+ assert(currentSnapshot != null);
currentSnapshot.setClean(otherSnapshot);
return ref;
}
@@ -934,6 +978,7 @@
id = ObjectId.fromString(buf, 0);
if (ref != null && !ref.isSymbolic()
&& ref.getTarget().getObjectId().equals(id)) {
+ assert(currentSnapshot != null);
currentSnapshot.setClean(otherSnapshot);
return ref;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index adc6bf1..683d1cd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -114,6 +114,9 @@
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
+import org.eclipse.jgit.transport.ObjectCountCallback;
+import org.eclipse.jgit.transport.WriteAbortedException;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.TemporaryBuffer;
@@ -133,12 +136,14 @@
* order of objects in pack</li>
* </ul>
* <p>
- * Typical usage consists of creating instance intended for some pack,
- * configuring options, preparing the list of objects by calling
- * {@link #preparePack(Iterator)} or
- * {@link #preparePack(ProgressMonitor, Set, Set)}, and finally producing the
- * stream with
- * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}.
+ * Typical usage consists of creating an instance, configuring options,
+ * preparing the list of objects by calling {@link #preparePack(Iterator)} or
+ * {@link #preparePack(ProgressMonitor, Set, Set)}, and streaming with
+ * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}. If the
+ * pack is being stored as a file the matching index can be written out after
+ * writing the pack by {@link #writeIndex(OutputStream)}. An optional bitmap
+ * index can be made by calling {@link #prepareBitmapIndex(ProgressMonitor)}
+ * followed by {@link #writeBitmapIndex(OutputStream)}.
* </p>
* <p>
* Class provide set of configurable options and {@link ProgressMonitor}
@@ -147,9 +152,10 @@
* relies only on deltas and objects reuse.
* </p>
* <p>
- * This class is not thread safe, it is intended to be used in one thread, with
- * one instance per created pack. Subsequent calls to writePack result in
- * undefined behavior.
+ * This class is not thread safe. It is intended to be used in one thread as a
+ * single pass to produce one pack. Invoking methods multiple times or out of
+ * order is not supported as internal data structures are destroyed during
+ * certain phases to save memory when packing large repositories.
* </p>
*/
public class PackWriter implements AutoCloseable {
@@ -212,7 +218,7 @@
}
@SuppressWarnings("unchecked")
- private final BlockList<ObjectToPack> objectsLists[] = new BlockList[OBJ_TAG + 1];
+ private BlockList<ObjectToPack> objectsLists[] = new BlockList[OBJ_TAG + 1];
{
objectsLists[OBJ_COMMIT] = new BlockList<ObjectToPack>();
objectsLists[OBJ_TREE] = new BlockList<ObjectToPack>();
@@ -220,7 +226,7 @@
objectsLists[OBJ_TAG] = new BlockList<ObjectToPack>();
}
- private final ObjectIdOwnerMap<ObjectToPack> objectsMap = new ObjectIdOwnerMap<ObjectToPack>();
+ private ObjectIdOwnerMap<ObjectToPack> objectsMap = new ObjectIdOwnerMap<ObjectToPack>();
// edge objects for thin packs
private List<ObjectToPack> edgeObjects = new BlockList<ObjectToPack>();
@@ -245,13 +251,13 @@
private final PackConfig config;
- private final Statistics stats;
+ private final PackStatistics.Accumulator stats;
private final MutableState state;
private final WeakReference<PackWriter> selfRef;
- private Statistics.ObjectType typeStats;
+ private PackStatistics.ObjectType.Accumulator typeStats;
private List<ObjectToPack> sortedByName;
@@ -289,6 +295,8 @@
private CRC32 crc32;
+ private ObjectCountCallback callback;
+
/**
* Create writer for specified repository.
* <p>
@@ -352,13 +360,42 @@
deltaBaseAsOffset = config.isDeltaBaseAsOffset();
reuseDeltas = config.isReuseDeltas();
reuseValidate = true; // be paranoid by default
- stats = new Statistics();
+ stats = new PackStatistics.Accumulator();
state = new MutableState();
selfRef = new WeakReference<PackWriter>(this);
instances.put(selfRef, Boolean.TRUE);
}
/**
+ * Set the {@code ObjectCountCallback}.
+ * <p>
+ * It should be set before calling
+ * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}.
+ *
+ * @param callback
+ * the callback to set
+ *
+ * @return this object for chaining.
+ * @since 4.1
+ */
+ public PackWriter setObjectCountCallback(ObjectCountCallback callback) {
+ this.callback = callback;
+ return this;
+ }
+
+ /**
+ * Records the set of shallow commits in the client.
+ *
+ * @param clientShallowCommits
+ * the shallow commits in the client
+ * @since 4.1
+ */
+ public void setClientShallowCommits(Set<ObjectId> clientShallowCommits) {
+ stats.clientShallowCommits = Collections
+ .unmodifiableSet(new HashSet<ObjectId>(clientShallowCommits));
+ }
+
+ /**
* Check whether writer can store delta base as an offset (new style
* reducing pack size) or should store it as an object id (legacy style,
* compatible with old readers).
@@ -571,12 +608,12 @@
/**
* Returns the object ids in the pack file that was created by this writer.
- *
+ * <p>
* This method can only be invoked after
* {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)} has
* been invoked and completed successfully.
*
- * @return number of objects in pack.
+ * @return set of objects in pack.
* @throws IOException
* a cached pack cannot supply its object ids.
*/
@@ -586,17 +623,20 @@
throw new IOException(
JGitText.get().cachedPacksPreventsListingObjects);
- ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> objs = new ObjectIdOwnerMap<
- ObjectIdOwnerMap.Entry>();
+ if (writeBitmaps != null) {
+ return writeBitmaps.getObjectSet();
+ }
+
+ ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> r = new ObjectIdOwnerMap<>();
for (BlockList<ObjectToPack> objList : objectsLists) {
if (objList != null) {
for (ObjectToPack otp : objList)
- objs.add(new ObjectIdOwnerMap.Entry(otp) {
+ r.add(new ObjectIdOwnerMap.Entry(otp) {
// A new entry that copies the ObjectId
});
}
}
- return objs;
+ return r;
}
/**
@@ -784,10 +824,11 @@
/**
* Create an index file to match the pack file just written.
* <p>
- * This method can only be invoked after
- * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)} has
- * been invoked and completed successfully. Writing a corresponding index is
- * an optional feature that not all pack users may require.
+ * Called after
+ * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}.
+ * <p>
+ * Writing an index is only required for local pack storage. Packs sent on
+ * the network do not need to create an index.
*
* @param indexStream
* output for the index data. Caller is responsible for closing
@@ -809,10 +850,7 @@
/**
* Create a bitmap index file to match the pack file just written.
* <p>
- * This method can only be invoked after
- * {@link #prepareBitmapIndex(ProgressMonitor)} has been invoked and
- * completed successfully. Writing a corresponding bitmap index is an
- * optional feature that not all pack users may require.
+ * Called after {@link #prepareBitmapIndex(ProgressMonitor)}.
*
* @param bitmapIndexStream
* output for the bitmap index data. Caller is responsible for
@@ -886,14 +924,13 @@
/**
* Write the prepared pack to the supplied stream.
* <p>
- * At first, this method collects and sorts objects to pack, then deltas
- * search is performed if set up accordingly, finally pack stream is
- * written.
- * </p>
+ * Called after {@link #preparePack(ProgressMonitor, ObjectWalk, Set, Set)}
+ * or {@link #preparePack(ProgressMonitor, Set, Set)}.
+ * <p>
+ * Performs delta search if enabled and writes the pack stream.
* <p>
* All reused objects data checksum (Adler32/CRC32) is computed and
* validated against existing checksum.
- * </p>
*
* @param compressMonitor
* progress monitor to report object compression work.
@@ -906,6 +943,9 @@
* an error occurred reading a local object's data to include in
* the pack, or writing compressed object data to the output
* stream.
+ * @throws WriteAbortedException
+ * the write operation is aborted by {@link ObjectCountCallback}
+ * .
*/
public void writePack(ProgressMonitor compressMonitor,
ProgressMonitor writeMonitor, OutputStream packStream)
@@ -947,6 +987,8 @@
long objCnt = getObjectCount();
stats.totalObjects = objCnt;
+ if (callback != null)
+ callback.setObjectCount(objCnt);
beginPhase(PackingPhase.WRITING, writeMonitor, objCnt);
long writeStart = System.currentTimeMillis();
try {
@@ -955,7 +997,7 @@
writeObjects(out);
if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty()) {
- for (Statistics.ObjectType typeStat : stats.objectTypes) {
+ for (PackStatistics.ObjectType.Accumulator typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
stats.thinPackBytes += typeStat.bytes;
@@ -976,7 +1018,7 @@
stats.timeWriting = System.currentTimeMillis() - writeStart;
stats.depth = depth;
- for (Statistics.ObjectType typeStat : stats.objectTypes) {
+ for (PackStatistics.ObjectType.Accumulator typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
typeStat.cntDeltas += typeStat.reusedDeltas;
@@ -993,11 +1035,11 @@
/**
* @return description of what this PackWriter did in order to create the
- * final pack stream. The object is only available to callers after
- * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}
+ * final pack stream. This should only be invoked after the calls to
+ * create the pack/index/bitmap have completed.
*/
- public Statistics getStatistics() {
- return stats;
+ public PackStatistics getStatistics() {
+ return new PackStatistics(stats);
}
/** @return snapshot of the current state of this PackWriter. */
@@ -1676,6 +1718,7 @@
final int maxBases = config.getDeltaSearchWindowSize();
Set<RevTree> baseTrees = new HashSet<RevTree>();
BlockList<RevCommit> commits = new BlockList<RevCommit>();
+ Set<ObjectId> roots = new HashSet<>();
RevCommit c;
while ((c = walker.next()) != null) {
if (exclude(c))
@@ -1687,8 +1730,12 @@
}
commits.add(c);
+ if (c.getParentCount() == 0) {
+ roots.add(c.copy());
+ }
countingMonitor.update(1);
}
+ stats.rootCommits = Collections.unmodifiableSet(roots);
if (shallowPack) {
for (RevCommit cmit : commits) {
@@ -1764,6 +1811,7 @@
countingMonitor.update((int) pack.getObjectCount());
endPhase(countingMonitor);
stats.timeCounting = System.currentTimeMillis() - countingStart;
+ stats.bitmapIndexMisses = -1;
}
private void findObjectsToPackUsingBitmaps(
@@ -1932,14 +1980,17 @@
}
/**
- * Prepares the bitmaps to be written to the pack index. Bitmaps can be used
- * to speed up fetches and clones by storing the entire object graph at
- * selected commits.
- *
- * This method can only be invoked after
- * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)} has
- * been invoked and completed successfully. Writing a corresponding bitmap
- * index is an optional feature that not all pack users may require.
+ * Prepares the bitmaps to be written to the bitmap index file.
+ * <p>
+ * Bitmaps can be used to speed up fetches and clones by storing the entire
+ * object graph at selected commits. Writing a bitmap index is an optional
+ * feature that not all pack users may require.
+ * <p>
+ * Called after {@link #writeIndex(OutputStream)}.
+ * <p>
+ * To reduce memory internal state is cleared during this method, rendering
+ * the PackWriter instance useless for anything further than a call to write
+ * out the new bitmaps with {@link #writeBitmapIndex(OutputStream)}.
*
* @param pm
* progress monitor to report bitmap building work.
@@ -1955,11 +2006,17 @@
if (pm == null)
pm = NullProgressMonitor.INSTANCE;
- writeBitmaps = new PackBitmapIndexBuilder(sortByName());
+ int numCommits = objectsLists[OBJ_COMMIT].size();
+ List<ObjectToPack> byName = sortByName();
+ sortedByName = null;
+ objectsLists = null;
+ objectsMap = null;
+ writeBitmaps = new PackBitmapIndexBuilder(byName);
+ byName = null;
+
PackWriterBitmapPreparer bitmapPreparer = new PackWriterBitmapPreparer(
reader, writeBitmaps, pm, stats.interestingObjects);
- int numCommits = objectsLists[OBJ_COMMIT].size();
Collection<PackWriterBitmapPreparer.BitmapCommit> selectedCommits =
bitmapPreparer.doCommitSelection(numCommits);
@@ -2001,28 +2058,36 @@
return true;
}
- /** Summary of how PackWriter created the pack. */
+ /**
+ * Summary of how PackWriter created the pack.
+ *
+ * @deprecated Use {@link PackStatistics} instead.
+ */
+ @Deprecated
public static class Statistics {
/** Statistics about a single class of object. */
public static class ObjectType {
- long cntObjects;
+ // All requests are forwarded to this object.
+ private PackStatistics.ObjectType objectType;
- long cntDeltas;
-
- long reusedObjects;
-
- long reusedDeltas;
-
- long bytes;
-
- long deltaBytes;
+ /**
+ * Wraps an
+ * {@link org.eclipse.jgit.storage.pack.PackStatistics.ObjectType}
+ * instance to maintain backwards compatibility with existing API.
+ *
+ * @param type
+ * the wrapped instance
+ */
+ public ObjectType(PackStatistics.ObjectType type) {
+ objectType = type;
+ }
/**
* @return total number of objects output. This total includes the
* value of {@link #getDeltas()}.
*/
public long getObjects() {
- return cntObjects;
+ return objectType.getObjects();
}
/**
@@ -2030,7 +2095,7 @@
* actual number of deltas if a cached pack was reused.
*/
public long getDeltas() {
- return cntDeltas;
+ return objectType.getDeltas();
}
/**
@@ -2039,7 +2104,7 @@
* {@link #getReusedDeltas()}.
*/
public long getReusedObjects() {
- return reusedObjects;
+ return objectType.getReusedObjects();
}
/**
@@ -2050,7 +2115,7 @@
* was reused.
*/
public long getReusedDeltas() {
- return reusedDeltas;
+ return objectType.getReusedDeltas();
}
/**
@@ -2059,7 +2124,7 @@
* also includes all of {@link #getDeltaBytes()}.
*/
public long getBytes() {
- return bytes;
+ return objectType.getBytes();
}
/**
@@ -2067,54 +2132,22 @@
* object headers for the delta objects.
*/
public long getDeltaBytes() {
- return deltaBytes;
+ return objectType.getDeltaBytes();
}
}
- Set<ObjectId> interestingObjects;
+ // All requests are forwarded to this object.
+ private PackStatistics statistics;
- Set<ObjectId> uninterestingObjects;
-
- Collection<CachedPack> reusedPacks;
-
- int depth;
-
- int deltaSearchNonEdgeObjects;
-
- int deltasFound;
-
- long totalObjects;
-
- long bitmapIndexMisses;
-
- long totalDeltas;
-
- long reusedObjects;
-
- long reusedDeltas;
-
- long totalBytes;
-
- long thinPackBytes;
-
- long timeCounting;
-
- long timeSearchingForReuse;
-
- long timeSearchingForSizes;
-
- long timeCompressing;
-
- long timeWriting;
-
- ObjectType[] objectTypes;
-
- {
- objectTypes = new ObjectType[5];
- objectTypes[OBJ_COMMIT] = new ObjectType();
- objectTypes[OBJ_TREE] = new ObjectType();
- objectTypes[OBJ_BLOB] = new ObjectType();
- objectTypes[OBJ_TAG] = new ObjectType();
+ /**
+ * Wraps a {@link PackStatistics} object to maintain backwards
+ * compatibility with existing API.
+ *
+ * @param stats
+ * the wrapped PackStatitics object
+ */
+ public Statistics(PackStatistics stats) {
+ statistics = stats;
}
/**
@@ -2123,7 +2156,7 @@
* test.
*/
public Set<ObjectId> getInterestingObjects() {
- return interestingObjects;
+ return statistics.getInterestingObjects();
}
/**
@@ -2132,7 +2165,7 @@
* has these objects.
*/
public Set<ObjectId> getUninterestingObjects() {
- return uninterestingObjects;
+ return statistics.getUninterestingObjects();
}
/**
@@ -2140,7 +2173,7 @@
* in the output, if any were selected for reuse.
*/
public Collection<CachedPack> getReusedPacks() {
- return reusedPacks;
+ return statistics.getReusedPacks();
}
/**
@@ -2148,7 +2181,7 @@
* delta search process in order to find a potential delta base.
*/
public int getDeltaSearchNonEdgeObjects() {
- return deltaSearchNonEdgeObjects;
+ return statistics.getDeltaSearchNonEdgeObjects();
}
/**
@@ -2157,7 +2190,7 @@
* {@link #getDeltaSearchNonEdgeObjects()}.
*/
public int getDeltasFound() {
- return deltasFound;
+ return statistics.getDeltasFound();
}
/**
@@ -2165,17 +2198,18 @@
* of {@link #getTotalDeltas()}.
*/
public long getTotalObjects() {
- return totalObjects;
+ return statistics.getTotalObjects();
}
/**
* @return the count of objects that needed to be discovered through an
* object walk because they were not found in bitmap indices.
+ * Returns -1 if no bitmap indices were found.
*
* @since 4.0
*/
public long getBitmapIndexMisses() {
- return bitmapIndexMisses;
+ return statistics.getBitmapIndexMisses();
}
/**
@@ -2183,7 +2217,7 @@
* actual number of deltas if a cached pack was reused.
*/
public long getTotalDeltas() {
- return totalDeltas;
+ return statistics.getTotalDeltas();
}
/**
@@ -2191,7 +2225,7 @@
* the output. This count includes {@link #getReusedDeltas()}.
*/
public long getReusedObjects() {
- return reusedObjects;
+ return statistics.getReusedObjects();
}
/**
@@ -2201,7 +2235,7 @@
* actual number of reused deltas if a cached pack was reused.
*/
public long getReusedDeltas() {
- return reusedDeltas;
+ return statistics.getReusedDeltas();
}
/**
@@ -2209,7 +2243,7 @@
* header, trailer, thin pack, and reused cached pack(s).
*/
public long getTotalBytes() {
- return totalBytes;
+ return statistics.getTotalBytes();
}
/**
@@ -2221,7 +2255,7 @@
* pack header or trailer.
*/
public long getThinPackBytes() {
- return thinPackBytes;
+ return statistics.getThinPackBytes();
}
/**
@@ -2230,17 +2264,17 @@
* @return information about this type of object in the pack.
*/
public ObjectType byObjectType(int typeCode) {
- return objectTypes[typeCode];
+ return new ObjectType(statistics.byObjectType(typeCode));
}
/** @return true if the resulting pack file was a shallow pack. */
public boolean isShallow() {
- return depth > 0;
+ return statistics.isShallow();
}
/** @return depth (in commits) the pack includes if shallow. */
public int getDepth() {
- return depth;
+ return statistics.getDepth();
}
/**
@@ -2249,7 +2283,7 @@
* that occur when a cached pack is selected for reuse.
*/
public long getTimeCounting() {
- return timeCounting;
+ return statistics.getTimeCounting();
}
/**
@@ -2258,7 +2292,7 @@
* can be assumed to already have.
*/
public long getTimeSearchingForReuse() {
- return timeSearchingForReuse;
+ return statistics.getTimeSearchingForReuse();
}
/**
@@ -2268,7 +2302,7 @@
* together and improve delta compression ratios.
*/
public long getTimeSearchingForSizes() {
- return timeSearchingForSizes;
+ return statistics.getTimeSearchingForSizes();
}
/**
@@ -2278,7 +2312,7 @@
* delta compression.
*/
public long getTimeCompressing() {
- return timeCompressing;
+ return statistics.getTimeCompressing();
}
/**
@@ -2288,16 +2322,12 @@
* value.
*/
public long getTimeWriting() {
- return timeWriting;
+ return statistics.getTimeWriting();
}
/** @return total time spent processing this pack. */
public long getTimeTotal() {
- return timeCounting
- + timeSearchingForReuse
- + timeSearchingForSizes
- + timeCompressing
- + timeWriting;
+ return statistics.getTimeTotal();
}
/**
@@ -2305,14 +2335,12 @@
* {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
*/
public double getTransferRate() {
- return getTotalBytes() / (getTimeWriting() / 1000.0);
+ return statistics.getTransferRate();
}
/** @return formatted message string for display to clients. */
public String getMessage() {
- return MessageFormat.format(JGitText.get().packWriterStatistics, //
- Long.valueOf(totalObjects), Long.valueOf(totalDeltas), //
- Long.valueOf(reusedObjects), Long.valueOf(reusedDeltas));
+ return statistics.getMessage();
}
}
@@ -2345,11 +2373,14 @@
State snapshot() {
long objCnt = 0;
- objCnt += objectsLists[OBJ_COMMIT].size();
- objCnt += objectsLists[OBJ_TREE].size();
- objCnt += objectsLists[OBJ_BLOB].size();
- objCnt += objectsLists[OBJ_TAG].size();
- // Exclude CachedPacks.
+ BlockList<ObjectToPack>[] lists = objectsLists;
+ if (lists != null) {
+ objCnt += lists[OBJ_COMMIT].size();
+ objCnt += lists[OBJ_TREE].size();
+ objCnt += lists[OBJ_BLOB].size();
+ objCnt += lists[OBJ_TAG].size();
+ // Exclude CachedPacks.
+ }
long bytesUsed = OBJECT_TO_PACK_SIZE * objCnt;
PackingPhase curr = phase;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
index fca9063..756d4b0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
@@ -114,6 +114,7 @@
IOException {
pm.beginTask(JGitText.get().selectingCommits, ProgressMonitor.UNKNOWN);
RevWalk rw = new RevWalk(reader);
+ rw.setRetainBody(false);
WalkResult result = findPaths(rw, expectedNumCommits);
pm.endTask();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
index 73850b7..d7e9308 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -59,6 +59,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.PushCertificate;
import org.eclipse.jgit.transport.ReceiveCommand;
/**
@@ -85,6 +86,9 @@
/** Should the result value be appended to {@link #refLogMessage}. */
private boolean refLogIncludeResult;
+ /** Push certificate associated with this update. */
+ private PushCertificate pushCert;
+
/**
* Initialize a new batch update.
*
@@ -195,6 +199,33 @@
return refLogMessage == null;
}
+ /**
+ * Set a push certificate associated with this update.
+ * <p>
+ * This usually includes commands to update the refs in this batch, but is not
+ * required to.
+ *
+ * @param cert
+ * push certificate, may be null.
+ * @since 4.1
+ */
+ public void setPushCertificate(PushCertificate cert) {
+ pushCert = cert;
+ }
+
+ /**
+ * Set the push certificate associated with this update.
+ * <p>
+ * This usually includes commands to update the refs in this batch, but is not
+ * required to.
+ *
+ * @return push certificate, may be null.
+ * @since 4.1
+ */
+ protected PushCertificate getPushCertificate() {
+ return pushCert;
+ }
+
/** @return commands this update will process. */
public List<ReceiveCommand> getCommands() {
return Collections.unmodifiableList(commands);
@@ -377,6 +408,7 @@
ru.setRefLogIdent(refLogIdent);
ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
}
+ ru.setPushCertificate(pushCert);
switch (cmd.getType()) {
case DELETE:
if (!ObjectId.zeroId().equals(cmd.getOldId()))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index 22337e8..e48386d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -1200,8 +1200,6 @@
for (;;) {
int c = in.read();
if (c < 0) {
- if (value.length() == 0)
- throw new ConfigInvalidException(JGitText.get().unexpectedEndOfConfigFile);
break;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 33c65ab..a7a67a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -618,8 +618,9 @@
default:
return false;
}
+ default:
+ return false;
}
- break;
case (byte) 0xef: // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65024
checkTruncatedIgnorableUTF8(raw, ptr, end);
// U+FEFF 0xefbbbf ZERO WIDTH NO-BREAK SPACE
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
index bdbffee..4edb38c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -45,7 +45,6 @@
package org.eclipse.jgit.lib;
import org.eclipse.jgit.errors.InvalidObjectIdException;
-import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.RawParseUtils;
@@ -53,7 +52,6 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.text.MessageFormat;
/**
* A SHA-1 abstraction.
@@ -113,16 +111,16 @@
}
/**
- * Compare to object identifier byte sequences for equality.
+ * Compare two object identifier byte sequences for equality.
*
* @param firstBuffer
* the first buffer to compare against. Must have at least 20
- * bytes from position ai through the end of the buffer.
+ * bytes from position fi through the end of the buffer.
* @param fi
* first offset within firstBuffer to begin testing.
* @param secondBuffer
- * the second buffer to compare against. Must have at least 2
- * bytes from position bi through the end of the buffer.
+ * the second buffer to compare against. Must have at least 20
+ * bytes from position si through the end of the buffer.
* @param si
* first offset within secondBuffer to begin testing.
* @return true if the two identifiers are the same.
@@ -230,9 +228,9 @@
* @return the converted object id.
*/
public static ObjectId fromString(final String str) {
- if (str.length() != Constants.OBJECT_ID_STRING_LENGTH)
- throw new IllegalArgumentException(
- MessageFormat.format(JGitText.get().invalidId, str));
+ if (str.length() != Constants.OBJECT_ID_STRING_LENGTH) {
+ throw new InvalidObjectIdException(str);
+ }
return fromHexString(Constants.encodeASCII(str), 0);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
index e859119..2ecc60c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -63,6 +63,54 @@
public class PersonIdent implements Serializable {
private static final long serialVersionUID = 1L;
+ /**
+ * @param tzOffset
+ * timezone offset as in {@link #getTimeZoneOffset()}.
+ * @return time zone object for the given offset.
+ * @since 4.1
+ */
+ public static TimeZone getTimeZone(int tzOffset) {
+ StringBuilder tzId = new StringBuilder(8);
+ tzId.append("GMT"); //$NON-NLS-1$
+ appendTimezone(tzId, tzOffset);
+ return TimeZone.getTimeZone(tzId.toString());
+ }
+
+ /**
+ * Format a timezone offset.
+ *
+ * @param r
+ * string builder to append to.
+ * @param offset
+ * timezone offset as in {@link #getTimeZoneOffset()}.
+ * @since 4.1
+ */
+ public static void appendTimezone(StringBuilder r, int offset) {
+ final char sign;
+ final int offsetHours;
+ final int offsetMins;
+
+ if (offset < 0) {
+ sign = '-';
+ offset = -offset;
+ } else {
+ sign = '+';
+ }
+
+ offsetHours = offset / 60;
+ offsetMins = offset % 60;
+
+ r.append(sign);
+ if (offsetHours < 10) {
+ r.append('0');
+ }
+ r.append(offsetHours);
+ if (offsetMins < 10) {
+ r.append('0');
+ }
+ r.append(offsetMins);
+ }
+
private final String name;
private final String emailAddress;
@@ -217,10 +265,7 @@
* @return this person's declared time zone; null if time zone is unknown.
*/
public TimeZone getTimeZone() {
- StringBuilder tzId = new StringBuilder(8);
- tzId.append("GMT"); //$NON-NLS-1$
- appendTimezone(tzId);
- return TimeZone.getTimeZone(tzId.toString());
+ return getTimeZone(tzOffset);
}
/**
@@ -261,37 +306,10 @@
r.append("> "); //$NON-NLS-1$
r.append(when / 1000);
r.append(' ');
- appendTimezone(r);
+ appendTimezone(r, tzOffset);
return r.toString();
}
- private void appendTimezone(final StringBuilder r) {
- int offset = tzOffset;
- final char sign;
- final int offsetHours;
- final int offsetMins;
-
- if (offset < 0) {
- sign = '-';
- offset = -offset;
- } else {
- sign = '+';
- }
-
- offsetHours = offset / 60;
- offsetMins = offset % 60;
-
- r.append(sign);
- if (offsetHours < 10) {
- r.append('0');
- }
- r.append(offsetHours);
- if (offsetMins < 10) {
- r.append('0');
- }
- r.append(offsetMins);
- }
-
@SuppressWarnings("nls")
public String toString() {
final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index 7fea880..b62033c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -47,6 +47,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -211,6 +212,9 @@
* Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
* able to more quickly resolve a single reference name than obtaining the
* complete namespace by {@code getRefs(ALL).get(name)}.
+ * <p>
+ * To read a specific reference without using @{link #SEARCH_PATH}, see
+ * {@link #exactRef(String)}.
*
* @param name
* the name of the reference. May be a short name which must be
@@ -222,6 +226,76 @@
public abstract Ref getRef(String name) throws IOException;
/**
+ * Read a single reference.
+ * <p>
+ * Unlike {@link #getRef}, this method expects an unshortened reference
+ * name and does not search using the standard {@link #SEARCH_PATH}.
+ *
+ * @param name
+ * the unabbreviated name of the reference.
+ * @return the reference (if it exists); else {@code null}.
+ * @throws IOException
+ * the reference space cannot be accessed.
+ * @since 4.1
+ */
+ public Ref exactRef(String name) throws IOException {
+ Ref ref = getRef(name);
+ if (ref == null || !name.equals(ref.getName())) {
+ return null;
+ }
+ return ref;
+ }
+
+ /**
+ * Read the specified references.
+ * <p>
+ * This method expects a list of unshortened reference names and returns
+ * a map from reference names to refs. Any named references that do not
+ * exist will not be included in the returned map.
+ *
+ * @param refs
+ * the unabbreviated names of references to look up.
+ * @return modifiable map describing any refs that exist among the ref
+ * ref names supplied. The map can be an unsorted map.
+ * @throws IOException
+ * the reference space cannot be accessed.
+ * @since 4.1
+ */
+ public Map<String, Ref> exactRef(String... refs) throws IOException {
+ Map<String, Ref> result = new HashMap<>(refs.length);
+ for (String name : refs) {
+ Ref ref = exactRef(name);
+ if (ref != null) {
+ result.put(name, ref);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find the first named reference.
+ * <p>
+ * This method expects a list of unshortened reference names and returns
+ * the first that exists.
+ *
+ * @param refs
+ * the unabbreviated names of references to look up.
+ * @return the first named reference that exists (if any); else {@code null}.
+ * @throws IOException
+ * the reference space cannot be accessed.
+ * @since 4.1
+ */
+ public Ref firstExactRef(String... refs) throws IOException {
+ for (String name : refs) {
+ Ref ref = exactRef(name);
+ if (ref != null) {
+ return ref;
+ }
+ }
+ return null;
+ }
+
+ /**
* Get a section of the reference namespace.
*
* @param prefix
@@ -242,6 +316,7 @@
* The result list includes non-ref items such as MERGE_HEAD and
* FETCH_RESULT cast to be refs. The names of these refs are not returned by
* <code>getRefs(ALL)</code> but are accepted by {@link #getRef(String)}
+ * and {@link #exactRef(String)}.
*
* @return a list of additional refs
* @throws IOException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
index aeef9f0..4316cd0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -52,6 +52,7 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.PushCertificate;
/**
* Creates, updates or deletes any reference.
@@ -165,6 +166,9 @@
/** Result of the update operation. */
private Result result = Result.NOT_ATTEMPTED;
+ /** Push certificate associated with this update. */
+ private PushCertificate pushCert;
+
private final Ref ref;
/**
@@ -414,6 +418,31 @@
}
/**
+ * Set a push certificate associated with this update.
+ * <p>
+ * This usually includes a command to update this ref, but is not required to.
+ *
+ * @param cert
+ * push certificate, may be null.
+ * @since 4.1
+ */
+ public void setPushCertificate(PushCertificate cert) {
+ pushCert = cert;
+ }
+
+ /**
+ * Set the push certificate associated with this update.
+ * <p>
+ * This usually includes a command to update this ref, but is not required to.
+ *
+ * @return push certificate, may be null.
+ * @since 4.1
+ */
+ protected PushCertificate getPushCertificate() {
+ return pushCert;
+ }
+
+ /**
* Get the status of this update.
* <p>
* The same value that was previously returned from an update method.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index fc7dca2..d4c72cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -849,8 +849,9 @@
* Except when HEAD is detached, in which case this method returns the
* current ObjectId in hexadecimal string format.
*
- * @return name of current branch (for example {@code refs/heads/master}) or
- * an ObjectId in hex format if the current branch is detached.
+ * @return name of current branch (for example {@code refs/heads/master}),
+ * an ObjectId in hex format if the current branch is detached,
+ * or null if the repository is corrupt and has no HEAD reference.
* @throws IOException
*/
public String getFullBranch() throws IOException {
@@ -871,8 +872,9 @@
* leading prefix {@code refs/heads/} is removed from the reference before
* it is returned to the caller.
*
- * @return name of current branch (for example {@code master}), or an
- * ObjectId in hex format if the current branch is detached.
+ * @return name of current branch (for example {@code master}), an
+ * ObjectId in hex format if the current branch is detached,
+ * or null if the repository is corrupt and has no HEAD reference.
* @throws IOException
*/
public String getBranch() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
index 0c58a0b..23cc264 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -47,6 +47,8 @@
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -143,6 +145,28 @@
}
}
+ /**
+ * Remove a repository from the cache.
+ * <p>
+ * Removes a repository from the cache, if it is still registered here,
+ * permitting it to close.
+ *
+ * @param location
+ * location of the repository to remove.
+ * @since 4.1
+ */
+ public static void unregister(Key location) {
+ cache.unregisterRepository(location);
+ }
+
+ /**
+ * @return the locations of all repositories registered in the cache.
+ * @since 4.1
+ */
+ public static Collection<Key> getRegisteredKeys() {
+ return cache.getKeys();
+ }
+
/** Unregister all repositories from the cache. */
public static void clear() {
cache.clearAll();
@@ -195,6 +219,10 @@
oldDb.close();
}
+ private Collection<Key> getKeys() {
+ return new ArrayList<Key>(cacheMap.keySet());
+ }
+
private void clearAll() {
for (int stage = 0; stage < 2; stage++) {
for (Iterator<Map.Entry<Key, Reference<Repository>>> i = cacheMap
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 3654ffd..8a6343c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -525,10 +525,11 @@
}
}
- if (nonTree(modeO) && modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
+ if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
// THEIRS was not changed compared to BASE. All changes must be in
// OURS. OURS is chosen. We can keep the existing entry.
- keep(ourDce);
+ if (ourDce != null)
+ keep(ourDce);
// no checkout needed!
return true;
}
@@ -549,11 +550,12 @@
if (e != null)
toBeCheckedOut.put(tw.getPathString(), e);
return true;
- } else if (modeT == 0 && modeB != 0) {
- // we want THEIRS ... but THEIRS contains the deletion of the
- // file. Also, do not complain if the file is already deleted
- // locally. This complements the test in isWorktreeDirty() for
- // the same case.
+ } else {
+ // we want THEIRS ... but THEIRS contains a folder or the
+ // deletion of the path. Delete what's in the workingtree (the
+ // workingtree is clean) but do not complain if the file is
+ // already deleted locally. This complements the test in
+ // isWorktreeDirty() for the same case.
if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0)
return true;
toBeDeleted.add(tw.getPathString());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java
index ea904cd..79fbb09 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java
@@ -260,8 +260,8 @@
}
ObjectId getTreeId() {
- try {
- return new ObjectInserter.Formatter().idFor(build(false, null));
+ try (ObjectInserter.Formatter f = new ObjectInserter.Formatter()) {
+ return f.idFor(build(false, null));
} catch (IOException e) {
// should never happen as we are not inserting
throw new RuntimeException(e);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index afb208e..1176d95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -1406,6 +1406,8 @@
/**
* Assume additional commits are shallow (have no parents).
+ * <p>
+ * This method is a No-op if the collection is empty.
*
* @param ids
* commits that should be treated as shallow commits, in addition
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
new file mode 100644
index 0000000..a811fe3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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.storage.pack;
+
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.CachedPack;
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * Statistics about {@link org.eclipse.jgit.internal.storage.pack.PackWriter}
+ * pack creation.
+ *
+ * @since 4.1
+ */
+public class PackStatistics {
+ /**
+ * Statistics about a single type of object (commits, tags, trees and
+ * blobs).
+ */
+ public static class ObjectType {
+ /**
+ * POJO for accumulating the ObjectType statistics.
+ */
+ public static class Accumulator {
+ /** Count of objects of this type. */
+ public long cntObjects;
+
+ /** Count of deltas of this type. */
+ public long cntDeltas;
+
+ /** Count of reused objects of this type. */
+ public long reusedObjects;
+
+ /** Count of reused deltas of this type. */
+ public long reusedDeltas;
+
+ /** Count of bytes for all objects of this type. */
+ public long bytes;
+
+ /** Count of delta bytes for objects of this type. */
+ public long deltaBytes;
+ }
+
+ private ObjectType.Accumulator objectType;
+
+ /**
+ * Creates a new {@link ObjectType} object from the accumulator.
+ *
+ * @param accumulator
+ * the accumulator of the statistics
+ */
+ public ObjectType(ObjectType.Accumulator accumulator) {
+ /*
+ * For efficiency this wraps and serves up the Accumulator object
+ * rather than making a deep clone. Normal usage of PackWriter is to
+ * create a single pack/index/bitmap and only call getStatistics()
+ * after all work is complete.
+ */
+ objectType = accumulator;
+ }
+
+ /**
+ * @return total number of objects output. This total includes the value
+ * of {@link #getDeltas()}.
+ */
+ public long getObjects() {
+ return objectType.cntObjects;
+ }
+
+ /**
+ * @return total number of deltas output. This may be lower than the
+ * actual number of deltas if a cached pack was reused.
+ */
+ public long getDeltas() {
+ return objectType.cntDeltas;
+ }
+
+ /**
+ * @return number of objects whose existing representation was reused in
+ * the output. This count includes {@link #getReusedDeltas()}.
+ */
+ public long getReusedObjects() {
+ return objectType.reusedObjects;
+ }
+
+ /**
+ * @return number of deltas whose existing representation was reused in
+ * the output, as their base object was also output or was
+ * assumed present for a thin pack. This may be lower than the
+ * actual number of reused deltas if a cached pack was reused.
+ */
+ public long getReusedDeltas() {
+ return objectType.reusedDeltas;
+ }
+
+ /**
+ * @return total number of bytes written. This size includes the object
+ * headers as well as the compressed data. This size also
+ * includes all of {@link #getDeltaBytes()}.
+ */
+ public long getBytes() {
+ return objectType.bytes;
+ }
+
+ /**
+ * @return number of delta bytes written. This size includes the object
+ * headers for the delta objects.
+ */
+ public long getDeltaBytes() {
+ return objectType.deltaBytes;
+ }
+ }
+
+ /**
+ * POJO for accumulating the statistics.
+ */
+ public static class Accumulator {
+ /** The set of objects to be included in the pack. */
+ public Set<ObjectId> interestingObjects;
+
+ /** The set of objects to be excluded from the pack. */
+ public Set<ObjectId> uninterestingObjects;
+
+ /** The set of shallow commits on the client. */
+ public Set<ObjectId> clientShallowCommits;
+
+ /** The collection of reused packs in the upload. */
+ public List<CachedPack> reusedPacks;
+
+ /** Commits with no parents. */
+ public Set<ObjectId> rootCommits;
+
+ /** If a shallow pack, the depth in commits. */
+ public int depth;
+
+ /**
+ * The count of objects in the pack that went through the delta search
+ * process in order to find a potential delta base.
+ */
+ public int deltaSearchNonEdgeObjects;
+
+ /**
+ * The count of objects in the pack that went through delta base search
+ * and found a suitable base. This is a subset of
+ * deltaSearchNonEdgeObjects.
+ */
+ public int deltasFound;
+
+ /** The total count of objects in the pack. */
+ public long totalObjects;
+
+ /**
+ * The count of objects that needed to be discovered through an object
+ * walk because they were not found in bitmap indices.
+ */
+ public long bitmapIndexMisses;
+
+ /** The total count of deltas output. */
+ public long totalDeltas;
+
+ /** The count of reused objects in the pack. */
+ public long reusedObjects;
+
+ /** The count of reused deltas in the pack. */
+ public long reusedDeltas;
+
+ /** The count of total bytes in the pack. */
+ public long totalBytes;
+
+ /** The size of the thin pack in bytes, if a thin pack was generated. */
+ public long thinPackBytes;
+
+ /** Time in ms spent counting the objects that will go into the pack. */
+ public long timeCounting;
+
+ /** Time in ms spent searching for objects to reuse. */
+ public long timeSearchingForReuse;
+
+ /** Time in ms spent searching for sizes of objects. */
+ public long timeSearchingForSizes;
+
+ /** Time in ms spent compressing the pack. */
+ public long timeCompressing;
+
+ /** Time in ms spent writing the pack. */
+ public long timeWriting;
+
+ /**
+ * Statistics about each object type in the pack (commits, tags, trees
+ * and blobs.)
+ */
+ public ObjectType.Accumulator[] objectTypes;
+
+ {
+ objectTypes = new ObjectType.Accumulator[5];
+ objectTypes[OBJ_COMMIT] = new ObjectType.Accumulator();
+ objectTypes[OBJ_TREE] = new ObjectType.Accumulator();
+ objectTypes[OBJ_BLOB] = new ObjectType.Accumulator();
+ objectTypes[OBJ_TAG] = new ObjectType.Accumulator();
+ }
+ }
+
+ private Accumulator statistics;
+
+ /**
+ * Creates a new {@link PackStatistics} object from the accumulator.
+ *
+ * @param accumulator
+ * the accumulator of the statistics
+ */
+ public PackStatistics(Accumulator accumulator) {
+ /*
+ * For efficiency this wraps and serves up the Accumulator object rather
+ * than making a deep clone. Normal usage of PackWriter is to create a
+ * single pack/index/bitmap and only call getStatistics() after all work
+ * is complete.
+ */
+ statistics = accumulator;
+ }
+
+ /**
+ * @return unmodifiable collection of objects to be included in the pack.
+ * May be {@code null} if the pack was hand-crafted in a unit test.
+ */
+ public Set<ObjectId> getInterestingObjects() {
+ return statistics.interestingObjects;
+ }
+
+ /**
+ * @return unmodifiable collection of objects that should be excluded from
+ * the pack, as the peer that will receive the pack already has
+ * these objects.
+ */
+ public Set<ObjectId> getUninterestingObjects() {
+ return statistics.uninterestingObjects;
+ }
+
+ /**
+ * @return unmodifiable collection of objects that were shallow commits on
+ * the client.
+ */
+ public Set<ObjectId> getClientShallowCommits() {
+ return statistics.clientShallowCommits;
+ }
+
+ /**
+ * @return unmodifiable list of the cached packs that were reused in the
+ * output, if any were selected for reuse.
+ */
+ public List<CachedPack> getReusedPacks() {
+ return statistics.reusedPacks;
+ }
+
+ /** @return unmodifiable collection of the root commits of the history. */
+ public Set<ObjectId> getRootCommits() {
+ return statistics.rootCommits;
+ }
+
+ /**
+ * @return number of objects in the output pack that went through the delta
+ * search process in order to find a potential delta base.
+ */
+ public int getDeltaSearchNonEdgeObjects() {
+ return statistics.deltaSearchNonEdgeObjects;
+ }
+
+ /**
+ * @return number of objects in the output pack that went through delta base
+ * search and found a suitable base. This is a subset of
+ * {@link #getDeltaSearchNonEdgeObjects()}.
+ */
+ public int getDeltasFound() {
+ return statistics.deltasFound;
+ }
+
+ /**
+ * @return total number of objects output. This total includes the value of
+ * {@link #getTotalDeltas()}.
+ */
+ public long getTotalObjects() {
+ return statistics.totalObjects;
+ }
+
+ /**
+ * @return the count of objects that needed to be discovered through an
+ * object walk because they were not found in bitmap indices.
+ * Returns -1 if no bitmap indices were found.
+ */
+ public long getBitmapIndexMisses() {
+ return statistics.bitmapIndexMisses;
+ }
+
+ /**
+ * @return total number of deltas output. This may be lower than the actual
+ * number of deltas if a cached pack was reused.
+ */
+ public long getTotalDeltas() {
+ return statistics.totalDeltas;
+ }
+
+ /**
+ * @return number of objects whose existing representation was reused in the
+ * output. This count includes {@link #getReusedDeltas()}.
+ */
+ public long getReusedObjects() {
+ return statistics.reusedObjects;
+ }
+
+ /**
+ * @return number of deltas whose existing representation was reused in the
+ * output, as their base object was also output or was assumed
+ * present for a thin pack. This may be lower than the actual number
+ * of reused deltas if a cached pack was reused.
+ */
+ public long getReusedDeltas() {
+ return statistics.reusedDeltas;
+ }
+
+ /**
+ * @return total number of bytes written. This size includes the pack
+ * header, trailer, thin pack, and reused cached pack(s).
+ */
+ public long getTotalBytes() {
+ return statistics.totalBytes;
+ }
+
+ /**
+ * @return size of the thin pack in bytes, if a thin pack was generated. A
+ * thin pack is created when the client already has objects and some
+ * deltas are created against those objects, or if a cached pack is
+ * being used and some deltas will reference objects in the cached
+ * pack. This size does not include the pack header or trailer.
+ */
+ public long getThinPackBytes() {
+ return statistics.thinPackBytes;
+ }
+
+ /**
+ * @param typeCode
+ * object type code, e.g. OBJ_COMMIT or OBJ_TREE.
+ * @return information about this type of object in the pack.
+ */
+ public ObjectType byObjectType(int typeCode) {
+ return new ObjectType(statistics.objectTypes[typeCode]);
+ }
+
+ /** @return true if the resulting pack file was a shallow pack. */
+ public boolean isShallow() {
+ return statistics.depth > 0;
+ }
+
+ /** @return depth (in commits) the pack includes if shallow. */
+ public int getDepth() {
+ return statistics.depth;
+ }
+
+ /**
+ * @return time in milliseconds spent enumerating the objects that need to
+ * be included in the output. This time includes any restarts that
+ * occur when a cached pack is selected for reuse.
+ */
+ public long getTimeCounting() {
+ return statistics.timeCounting;
+ }
+
+ /**
+ * @return time in milliseconds spent matching existing representations
+ * against objects that will be transmitted, or that the client can
+ * be assumed to already have.
+ */
+ public long getTimeSearchingForReuse() {
+ return statistics.timeSearchingForReuse;
+ }
+
+ /**
+ * @return time in milliseconds spent finding the sizes of all objects that
+ * will enter the delta compression search window. The sizes need to
+ * be known to better match similar objects together and improve
+ * delta compression ratios.
+ */
+ public long getTimeSearchingForSizes() {
+ return statistics.timeSearchingForSizes;
+ }
+
+ /**
+ * @return time in milliseconds spent on delta compression. This is observed
+ * wall-clock time and does not accurately track CPU time used when
+ * multiple threads were used to perform the delta compression.
+ */
+ public long getTimeCompressing() {
+ return statistics.timeCompressing;
+ }
+
+ /**
+ * @return time in milliseconds spent writing the pack output, from start of
+ * header until end of trailer. The transfer speed can be
+ * approximated by dividing {@link #getTotalBytes()} by this value.
+ */
+ public long getTimeWriting() {
+ return statistics.timeWriting;
+ }
+
+ /** @return total time spent processing this pack. */
+ public long getTimeTotal() {
+ return statistics.timeCounting + statistics.timeSearchingForReuse
+ + statistics.timeSearchingForSizes + statistics.timeCompressing
+ + statistics.timeWriting;
+ }
+
+ /**
+ * @return get the average output speed in terms of bytes-per-second.
+ * {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
+ */
+ public double getTransferRate() {
+ return getTotalBytes() / (getTimeWriting() / 1000.0);
+ }
+
+ /** @return formatted message string for display to clients. */
+ public String getMessage() {
+ return MessageFormat.format(JGitText.get().packWriterStatistics,
+ Long.valueOf(statistics.totalObjects),
+ Long.valueOf(statistics.totalDeltas),
+ Long.valueOf(statistics.reusedObjects),
+ Long.valueOf(statistics.reusedDeltas));
+ }
+
+ /** @return a map containing ObjectType statistics. */
+ public Map<Integer, ObjectType> getObjectTypes() {
+ HashMap<Integer, ObjectType> map = new HashMap<>();
+ map.put(Integer.valueOf(OBJ_BLOB), new ObjectType(
+ statistics.objectTypes[OBJ_BLOB]));
+ map.put(Integer.valueOf(OBJ_COMMIT), new ObjectType(
+ statistics.objectTypes[OBJ_COMMIT]));
+ map.put(Integer.valueOf(OBJ_TAG), new ObjectType(
+ statistics.objectTypes[OBJ_TAG]));
+ map.put(Integer.valueOf(OBJ_TREE), new ObjectType(
+ statistics.objectTypes[OBJ_TREE]));
+ return map;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index 7d9bca0..6263d4b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -451,13 +451,14 @@
}
/**
- * Checks whether the working tree (or the index in case of a bare repo)
- * contains a .gitmodules file. That's a hint that the repo contains
- * submodules.
+ * Checks whether the working tree contains a .gitmodules file. That's a
+ * hint that the repo contains submodules.
*
* @param repository
* the repository to check
- * @return <code>true</code> if the repo contains a .gitmodules file
+ * @return <code>true</code> if the working tree contains a .gitmodules file,
+ * <code>false</code> otherwise. Always returns <code>false</code>
+ * for bare repositories.
* @throws IOException
* @throws CorruptObjectException
* @since 3.6
@@ -465,8 +466,7 @@
public static boolean containsGitModulesFile(Repository repository)
throws IOException {
if (repository.isBare()) {
- DirCache dc = repository.readDirCache();
- return (dc.findEntry(Constants.DOT_GIT_MODULES) >= 0);
+ return false;
}
File modulesFile = new File(repository.getWorkTree(),
Constants.DOT_GIT_MODULES);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index a6fc633..cf13582 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -193,6 +193,13 @@
*/
public static final String OPTION_ALLOW_TIP_SHA1_IN_WANT = GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
+ /**
+ * The client supports fetching objects that are reachable from a tip of a
+ * ref that is allowed to fetch.
+ * @since 4.1
+ */
+ public static final String OPTION_ALLOW_REACHABLE_SHA1_IN_WANT = GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
+
private final RevWalk walk;
/** All commits that are immediately reachable by a local ref. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index 9112ecb..776a9f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -252,13 +252,35 @@
/** The size of the received pack, including index size */
private Long packSize;
- PushCertificateParser pushCertificateParser;
+ private PushCertificateParser pushCertificateParser;
+ private SignedPushConfig signedPushConfig;
+ private PushCertificate pushCert;
/**
- * @return the push certificate used to verify the pushers identity.
+ * Get the push certificate used to verify the pusher's identity.
+ * <p>
+ * Only valid after commands are read from the wire.
+ *
+ * @return the parsed certificate, or null if push certificates are disabled
+ * or no cert was presented by the client.
+ * @since 4.1
*/
- PushCertificate getPushCertificate() {
- return pushCertificateParser;
+ public PushCertificate getPushCertificate() {
+ return pushCert;
+ }
+
+ /**
+ * Set the push certificate used to verify the pusher's identity.
+ * <p>
+ * Should only be called if reconstructing an instance without going through
+ * the normal {@link #recvCommands()} flow.
+ *
+ * @param cert
+ * the push certificate to set.
+ * @since 4.1
+ */
+ public void setPushCertificate(PushCertificate cert) {
+ pushCert = cert;
}
/**
@@ -282,7 +304,7 @@
refFilter = RefFilter.DEFAULT;
advertisedHaves = new HashSet<ObjectId>();
clientShallowCommits = new HashSet<ObjectId>();
- pushCertificateParser = new PushCertificateParser(db, cfg);
+ signedPushConfig = cfg.signedPush;
}
/** Configuration for receive operations. */
@@ -304,8 +326,7 @@
final boolean allowNonFastForwards;
final boolean allowOfsDelta;
- final String certNonceSeed;
- final int certNonceSlopLimit;
+ final SignedPushConfig signedPush;
ReceiveConfig(final Config config) {
checkReceivedObjects = config.getBoolean(
@@ -326,8 +347,7 @@
"denynonfastforwards", false); //$NON-NLS-1$
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
true);
- certNonceSeed = config.getString("receive", null, "certnonceseed"); //$NON-NLS-1$ //$NON-NLS-2$
- certNonceSlopLimit = config.getInt("receive", "certnonceslop", 0); //$NON-NLS-1$ //$NON-NLS-2$
+ signedPush = SignedPushConfig.KEY.parse(config);
}
ObjectChecker newObjectChecker() {
@@ -784,6 +804,26 @@
}
/**
+ * Set the configuration for push certificate verification.
+ *
+ * @param cfg
+ * new configuration; if this object is null or its {@link
+ * SignedPushConfig#getCertNonceSeed()} is null, push certificate
+ * verification will be disabled.
+ * @since 4.1
+ */
+ public void setSignedPushConfig(SignedPushConfig cfg) {
+ signedPushConfig = cfg;
+ }
+
+ private PushCertificateParser getPushCertificateParser() {
+ if (pushCertificateParser == null) {
+ pushCertificateParser = new PushCertificateParser(db, signedPushConfig);
+ }
+ return pushCertificateParser;
+ }
+
+ /**
* Get the user agent of the client.
* <p>
* If the client is new enough to use {@code agent=} capability that value
@@ -1014,9 +1054,10 @@
adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
if (allowQuiet)
adv.advertiseCapability(CAPABILITY_QUIET);
- if (pushCertificateParser.enabled())
- adv.advertiseCapability(
- pushCertificateParser.getAdvertiseNonce());
+ String nonce = getPushCertificateParser().getAdvertiseNonce();
+ if (nonce != null) {
+ adv.advertiseCapability(nonce);
+ }
if (db.getRefDatabase().performsAtomicTransactions())
adv.advertiseCapability(CAPABILITY_ATOMIC);
if (allowOfsDelta)
@@ -1036,58 +1077,90 @@
* @throws IOException
*/
protected void recvCommands() throws IOException {
- for (;;) {
- String line;
- try {
- line = pckIn.readStringRaw();
- } catch (EOFException eof) {
- if (commands.isEmpty())
- return;
- throw eof;
+ PushCertificateParser certParser = getPushCertificateParser();
+ FirstLine firstLine = null;
+ try {
+ for (;;) {
+ String line;
+ try {
+ line = pckIn.readString();
+ } catch (EOFException eof) {
+ if (commands.isEmpty())
+ return;
+ throw eof;
+ }
+ if (line == PacketLineIn.END) {
+ break;
+ }
+
+ if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$
+ clientShallowCommits.add(ObjectId.fromString(line.substring(8, 48)));
+ continue;
+ }
+
+ if (firstLine == null) {
+ firstLine = new FirstLine(line);
+ enabledCapabilities = firstLine.getCapabilities();
+ line = firstLine.getLine();
+
+ if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) {
+ certParser.receiveHeader(pckIn, !isBiDirectionalPipe());
+ continue;
+ }
+ }
+
+ if (line.equals(PushCertificateParser.BEGIN_SIGNATURE)) {
+ certParser.receiveSignature(pckIn);
+ continue;
+ }
+
+ ReceiveCommand cmd;
+ try {
+ cmd = parseCommand(line);
+ } catch (PackProtocolException e) {
+ sendError(e.getMessage());
+ throw e;
+ }
+ if (cmd.getRefName().equals(Constants.HEAD)) {
+ cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
+ } else {
+ cmd.setRef(refs.get(cmd.getRefName()));
+ }
+ commands.add(cmd);
+ if (certParser.enabled()) {
+ certParser.addCommand(cmd);
+ }
}
- if (line == PacketLineIn.END)
- break;
-
- if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$
- clientShallowCommits.add(ObjectId.fromString(line.substring(8, 48)));
- continue;
- }
-
- if (commands.isEmpty()) {
- final FirstLine firstLine = new FirstLine(line);
- enabledCapabilities = firstLine.getCapabilities();
- line = firstLine.getLine();
-
- if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT))
- pushCertificateParser.receiveHeader(pckIn,
- !isBiDirectionalPipe());
- }
-
- if (line.equals("-----BEGIN PGP SIGNATURE-----\n")) //$NON-NLS-1$
- pushCertificateParser.receiveSignature(pckIn);
-
- if (pushCertificateParser.enabled())
- pushCertificateParser.addCommand(line);
-
- if (line.length() < 83) {
- final String m = JGitText.get().errorInvalidProtocolWantedOldNewRef;
- sendError(m);
- throw new PackProtocolException(m);
- }
-
- final ObjectId oldId = ObjectId.fromString(line.substring(0, 40));
- final ObjectId newId = ObjectId.fromString(line.substring(41, 81));
- final String name = line.substring(82);
- final ReceiveCommand cmd = new ReceiveCommand(oldId, newId, name);
- if (name.equals(Constants.HEAD)) {
- cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
- } else {
- cmd.setRef(refs.get(cmd.getRefName()));
- }
- commands.add(cmd);
+ pushCert = certParser.build();
+ } catch (PackProtocolException e) {
+ sendError(e.getMessage());
+ throw e;
}
}
+ static ReceiveCommand parseCommand(String line) throws PackProtocolException {
+ if (line == null || line.length() < 83) {
+ throw new PackProtocolException(
+ JGitText.get().errorInvalidProtocolWantedOldNewRef);
+ }
+ String oldStr = line.substring(0, 40);
+ String newStr = line.substring(41, 81);
+ ObjectId oldId, newId;
+ try {
+ oldId = ObjectId.fromString(oldStr);
+ newId = ObjectId.fromString(newStr);
+ } catch (IllegalArgumentException e) {
+ throw new PackProtocolException(
+ JGitText.get().errorInvalidProtocolWantedOldNewRef, e);
+ }
+ String name = line.substring(82);
+ if (!Repository.isValidRefName(name)) {
+ throw new PackProtocolException(
+ JGitText.get().errorInvalidProtocolWantedOldNewRef);
+ }
+ return new ReceiveCommand(oldId, newId, name);
+ }
+
/** Enable capabilities based on a previously read capabilities line. */
protected void enableCapabilities() {
sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
@@ -1432,6 +1505,7 @@
batch.setRefLogMessage("push", true); //$NON-NLS-1$
batch.addCommand(toApply);
try {
+ batch.setPushCertificate(getPushCertificate());
batch.execute(walk, updating);
} catch (IOException err) {
for (ReceiveCommand cmd : toApply) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index 81ad981..ca624c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -92,6 +92,8 @@
private PackConfig packConfig;
+ private ObjectCountCallback callback;
+
/**
* Create a writer for a bundle.
*
@@ -188,6 +190,9 @@
* an error occurred reading a local object's data to include in
* the bundle, or writing compressed object data to the output
* stream.
+ * @throws WriteAbortedException
+ * the write operation is aborted by
+ * {@link ObjectCountCallback}.
*/
public void writeBundle(ProgressMonitor monitor, OutputStream os)
throws IOException {
@@ -195,6 +200,8 @@
if (pc == null)
pc = new PackConfig(db);
try (PackWriter packWriter = new PackWriter(pc, db.newObjectReader())) {
+ packWriter.setObjectCountCallback(callback);
+
final HashSet<ObjectId> inc = new HashSet<ObjectId>();
final HashSet<ObjectId> exc = new HashSet<ObjectId>();
inc.addAll(include.values());
@@ -234,4 +241,24 @@
packWriter.writePack(monitor, monitor, os);
}
}
+
+ /**
+ * Set the {@link ObjectCountCallback}.
+ * <p>
+ * It should be set before calling
+ * {@link #writeBundle(ProgressMonitor, OutputStream)}.
+ * <p>
+ * This callback will be passed on to
+ * {@link PackWriter#setObjectCountCallback}.
+ *
+ * @param callback
+ * the callback to set
+ *
+ * @return this object for chaining.
+ * @since 4.1
+ */
+ public BundleWriter setObjectCountCallback(ObjectCountCallback callback) {
+ this.callback = callback;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index 8d2d554..efde062 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -130,6 +130,14 @@
public static final String OPTION_ALLOW_TIP_SHA1_IN_WANT = "allow-tip-sha1-in-want"; //$NON-NLS-1$
/**
+ * The client supports fetching objects that are reachable from a tip of a
+ * ref that is allowed to fetch.
+ *
+ * @since 4.1
+ */
+ public static final String OPTION_ALLOW_REACHABLE_SHA1_IN_WANT = "allow-reachable-sha1-in-want"; //$NON-NLS-1$
+
+ /**
* Symbolic reference support for better negotiation.
*
* @since 3.6
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
index 222ca55..7e9434a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
@@ -105,36 +105,42 @@
@Override
public NonceStatus verify(String received, String sent,
Repository db, boolean allowSlop, int slop) {
- if (received.isEmpty())
+ if (received.isEmpty()) {
return NonceStatus.MISSING;
- else if (sent.isEmpty())
+ } else if (sent.isEmpty()) {
return NonceStatus.UNSOLICITED;
- else if (received.equals(sent))
+ } else if (received.equals(sent)) {
return NonceStatus.OK;
+ }
- if (!allowSlop)
+ if (!allowSlop) {
return NonceStatus.BAD;
+ }
/* nonce is concat(<seconds-since-epoch>, "-", <hmac>) */
int idxSent = sent.indexOf('-');
int idxRecv = received.indexOf('-');
- if (idxSent == -1 || idxRecv == -1)
+ if (idxSent == -1 || idxRecv == -1) {
return NonceStatus.BAD;
+ }
+ String signedStampStr = received.substring(0, idxRecv);
+ String advertisedStampStr = sent.substring(0, idxSent);
long signedStamp;
long advertisedStamp;
try {
- signedStamp = Long.parseLong(received.substring(0, idxRecv));
- advertisedStamp = Long.parseLong(sent.substring(0, idxSent));
- } catch (Exception e) {
+ signedStamp = Long.parseLong(signedStampStr);
+ advertisedStamp = Long.parseLong(advertisedStampStr);
+ } catch (IllegalArgumentException e) {
return NonceStatus.BAD;
}
// what we would have signed earlier
String expect = createNonce(db, signedStamp);
- if (!expect.equals(received))
+ if (!expect.equals(received)) {
return NonceStatus.BAD;
+ }
long nonceStampSlop = Math.abs(advertisedStamp - signedStamp);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java
new file mode 100644
index 0000000..cf81adb
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectCountCallback.java
@@ -0,0 +1,74 @@
+/*
+ * 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 java.io.OutputStream;
+
+import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.lib.ProgressMonitor;
+
+/**
+ * A callback to tell caller the count of objects ASAP.
+ *
+ * @since 4.1
+ */
+public interface ObjectCountCallback {
+ /**
+ * Invoked when the {@link PackWriter} has counted the objects to be
+ * written to pack.
+ * <p>
+ * An {@code ObjectCountCallback} can use this information to decide
+ * whether the
+ * {@link PackWriter#writePack(ProgressMonitor, ProgressMonitor, OutputStream)}
+ * operation should be aborted.
+ * <p>
+ * This callback will be called exactly once.
+ *
+ * @param objectCount
+ * the count of the objects.
+ * @throws WriteAbortedException
+ * to indicate that the write operation should be aborted.
+ */
+ void setObjectCount(long objectCount) throws WriteAbortedException;
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 04abe22..918df94 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -135,6 +135,8 @@
private boolean allowThin;
+ private boolean checkObjectCollisions;
+
private boolean needBaseObjectIds;
private boolean checkEofAfterPackFooter;
@@ -204,6 +206,7 @@
objectDigest = Constants.newMessageDigest();
tempObjectId = new MutableObjectId();
packDigest = Constants.newMessageDigest();
+ checkObjectCollisions = true;
}
/** @return true if a thin pack (missing base objects) is permitted. */
@@ -225,6 +228,39 @@
}
/**
+ * @return if true received objects are verified to prevent collisions.
+ * @since 4.1
+ */
+ protected boolean isCheckObjectCollisions() {
+ return checkObjectCollisions;
+ }
+
+ /**
+ * Enable checking for collisions with existing objects.
+ * <p>
+ * By default PackParser looks for each received object in the repository.
+ * If the object already exists, the existing object is compared
+ * byte-for-byte with the newly received copy to ensure they are identical.
+ * The receive is aborted with an exception if any byte differs. This check
+ * is necessary to prevent an evil attacker from supplying a replacement
+ * object into this repository in the event that a discovery enabling SHA-1
+ * collisions is made.
+ * <p>
+ * This check may be very costly to perform, and some repositories may have
+ * other ways to segregate newly received object data. The check is enabled
+ * by default, but can be explicitly disabled if the implementation can
+ * provide the same guarantee, or is willing to accept the risks associated
+ * with bypassing the check.
+ *
+ * @param check
+ * true to enable collision checking (strongly encouraged).
+ * @since 4.1
+ */
+ protected void setCheckObjectCollisions(boolean check) {
+ checkObjectCollisions = check;
+ }
+
+ /**
* Configure this index pack instance to keep track of new objects.
* <p>
* By default an index pack doesn't save the new objects that were created
@@ -988,7 +1024,8 @@
}
inf.close();
tempObjectId.fromRaw(objectDigest.digest(), 0);
- checkContentLater = readCurs.has(tempObjectId);
+ checkContentLater = isCheckObjectCollisions()
+ && readCurs.has(tempObjectId);
data = null;
} else {
@@ -1022,17 +1059,19 @@
}
}
- try {
- final ObjectLoader ldr = readCurs.open(id, type);
- final byte[] existingData = ldr.getCachedBytes(data.length);
- if (!Arrays.equals(data, existingData)) {
- throw new IOException(MessageFormat.format(
- JGitText.get().collisionOn, id.name()));
+ if (isCheckObjectCollisions()) {
+ try {
+ final ObjectLoader ldr = readCurs.open(id, type);
+ final byte[] existingData = ldr.getCachedBytes(data.length);
+ if (!Arrays.equals(data, existingData)) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().collisionOn, id.name()));
+ }
+ } catch (MissingObjectException notLocal) {
+ // This is OK, we don't have a copy of the object locally
+ // but the API throws when we try to read it as usually its
+ // an error to read something that doesn't exist.
}
- } catch (MissingObjectException notLocal) {
- // This is OK, we don't have a copy of the object locally
- // but the API throws when we try to read it as usually its
- // an error to read something that doesn't exist.
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java
new file mode 100644
index 0000000..53eeab1
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHook.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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 org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.storage.pack.PackStatistics;
+
+/**
+ * Hook invoked by {@link UploadPack} after the pack has been uploaded.
+ * <p>
+ * Implementors of the interface are responsible for associating the current
+ * thread to a particular connection, if they need to also include connection
+ * information. One method is to use a {@link java.lang.ThreadLocal} to remember
+ * the connection information before invoking UploadPack.
+ *
+ * @since 4.1
+ */
+public interface PostUploadHook {
+ /** A simple no-op hook. */
+ public static final PostUploadHook NULL = new PostUploadHook() {
+ public void onPostUpload(PackStatistics stats) {
+ // Do nothing.
+ }
+ };
+
+ /**
+ * Notifies the hook that a pack has been sent.
+ *
+ * @param stats
+ * the statistics gathered by {@link PackWriter} for the uploaded
+ * pack
+ */
+ public void onPostUpload(PackStatistics stats);
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
new file mode 100644
index 0000000..4e2eaea
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PostUploadHookChain.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * 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 java.util.List;
+
+import org.eclipse.jgit.storage.pack.PackStatistics;
+
+/**
+ * {@link PostUploadHook} that delegates to a list of other hooks.
+ * <p>
+ * Hooks are run in the order passed to the constructor.
+ *
+ * @since 4.1
+ */
+public class PostUploadHookChain implements PostUploadHook {
+ private final PostUploadHook[] hooks;
+ private final int count;
+
+ /**
+ * Create a new hook chaining the given hooks together.
+ *
+ * @param hooks
+ * hooks to execute, in order.
+ * @return a new chain of the given hooks.
+ */
+ public static PostUploadHook newChain(List<? extends PostUploadHook> hooks) {
+ PostUploadHook[] newHooks = new PostUploadHook[hooks.size()];
+ int i = 0;
+ for (PostUploadHook hook : hooks)
+ if (hook != PostUploadHook.NULL)
+ newHooks[i++] = hook;
+ if (i == 0)
+ return PostUploadHook.NULL;
+ else if (i == 1)
+ return newHooks[0];
+ else
+ return new PostUploadHookChain(newHooks, i);
+ }
+
+ public void onPostUpload(PackStatistics stats) {
+ for (int i = 0; i < count; i++)
+ hooks[i].onPostUpload(stats);
+ }
+
+ private PostUploadHookChain(PostUploadHook[] hooks, int count) {
+ this.hooks = hooks;
+ this.count = count;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
index 8ee4c17..e450345 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
@@ -43,21 +43,26 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.PushCertificateParser.NONCE;
+import static org.eclipse.jgit.transport.PushCertificateParser.PUSHEE;
+import static org.eclipse.jgit.transport.PushCertificateParser.PUSHER;
+import static org.eclipse.jgit.transport.PushCertificateParser.VERSION;
+
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.jgit.internal.JGitText;
+
/**
* The required information to verify the push.
+ * <p>
+ * A valid certificate will not return null from any getter methods; callers may
+ * assume that any null value indicates a missing or invalid certificate.
*
* @since 4.0
*/
public class PushCertificate {
- /** The tuple "name <email>" as presented in the push certificate. */
- String pusher;
-
- /** The remote URL the signed push goes to. */
- String pushee;
-
- /** What we think about the returned signed nonce. */
- NonceStatus nonceStatus;
-
/** Verification result of the nonce returned during push. */
public enum NonceStatus {
/** Nonce was not expected, yet client sent one anyway. */
@@ -66,47 +71,206 @@
BAD,
/** Nonce is required, but was not sent by client. */
MISSING,
- /** Received nonce is valid. */
+ /**
+ * Received nonce matches sent nonce, or is valid within the accepted slop
+ * window.
+ */
OK,
- /** Received nonce is valid and within the accepted slop window. */
+ /** Received nonce is valid, but outside the accepted slop window. */
SLOP
}
- String commandList;
- String signature;
+ private final String version;
+ private final PushCertificateIdent pusher;
+ private final String pushee;
+ private final String nonce;
+ private final NonceStatus nonceStatus;
+ private final List<ReceiveCommand> commands;
+ private final String signature;
+
+ PushCertificate(String version, PushCertificateIdent pusher, String pushee,
+ String nonce, NonceStatus nonceStatus, List<ReceiveCommand> commands,
+ String signature) {
+ if (version == null || version.isEmpty()) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField, VERSION));
+ }
+ if (pusher == null) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField, PUSHER));
+ }
+ if (nonce == null || nonce.isEmpty()) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField, NONCE));
+ }
+ if (nonceStatus == null) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField,
+ "nonce status")); //$NON-NLS-1$
+ }
+ if (commands == null || commands.isEmpty()) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField,
+ "command")); //$NON-NLS-1$
+ }
+ if (signature == null || signature.isEmpty()) {
+ throw new IllegalArgumentException(
+ JGitText.get().pushCertificateInvalidSignature);
+ }
+ if (!signature.startsWith(PushCertificateParser.BEGIN_SIGNATURE)
+ || !signature.endsWith(PushCertificateParser.END_SIGNATURE + '\n')) {
+ throw new IllegalArgumentException(
+ JGitText.get().pushCertificateInvalidSignature);
+ }
+ this.version = version;
+ this.pusher = pusher;
+ this.pushee = pushee;
+ this.nonce = nonce;
+ this.nonceStatus = nonceStatus;
+ this.commands = commands;
+ this.signature = signature;
+ }
/**
- * @return the signature, consisting of the lines received between the lines
- * '----BEGIN GPG SIGNATURE-----\n' and the '----END GPG
- * SIGNATURE-----\n'
+ * @return the certificate version string.
+ * @since 4.1
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * @return the raw line that signed the cert, as a string.
+ * @since 4.0
+ */
+ public String getPusher() {
+ return pusher.getRaw();
+ }
+
+ /**
+ * @return identity of the pusher who signed the cert.
+ * @since 4.1
+ */
+ public PushCertificateIdent getPusherIdent() {
+ return pusher;
+ }
+
+ /**
+ * @return URL of the repository the push was originally sent to.
+ * @since 4.0
+ */
+ public String getPushee() {
+ return pushee;
+ }
+
+ /**
+ * @return the raw nonce value that was presented by the pusher.
+ * @since 4.1
+ */
+ public String getNonce() {
+ return nonce;
+ }
+
+ /**
+ * @return verification status of the nonce embedded in the certificate.
+ * @since 4.0
+ */
+ public NonceStatus getNonceStatus() {
+ return nonceStatus;
+ }
+
+ /**
+ * @return the list of commands as one string to be feed into the signature
+ * verifier.
+ * @since 4.1
+ */
+ public List<ReceiveCommand> getCommands() {
+ return commands;
+ }
+
+ /**
+ * @return the raw signature, consisting of the lines received between the
+ * lines {@code "----BEGIN GPG SIGNATURE-----\n"} and
+ * {@code "----END GPG SIGNATURE-----\n}", inclusive.
+ * @since 4.0
*/
public String getSignature() {
return signature;
}
/**
- * @return the list of commands as one string to be feed into the signature
- * verifier.
+ * @return text payload of the certificate for the signature verifier.
+ * @since 4.1
*/
- public String getCommandList() {
- return commandList;
+ public String toText() {
+ return toStringBuilder().toString();
}
/**
- * @return the tuple "name <email>" as presented by the client in the
- * push certificate.
+ * @return original text payload plus signature; the final output will be
+ * valid as input to {@link PushCertificateParser#fromString(String)}.
+ * @since 4.1
*/
- public String getPusher() {
- return pusher;
+ public String toTextWithSignature() {
+ return toStringBuilder().append(signature).toString();
}
- /** @return URL of the repository the push was originally sent to. */
- public String getPushee() {
- return pushee;
+ private StringBuilder toStringBuilder() {
+ StringBuilder sb = new StringBuilder()
+ .append(VERSION).append(' ').append(version).append('\n')
+ .append(PUSHER).append(' ').append(getPusher())
+ .append('\n');
+ if (pushee != null) {
+ sb.append(PUSHEE).append(' ').append(pushee).append('\n');
+ }
+ sb.append(NONCE).append(' ').append(nonce).append('\n')
+ .append('\n');
+ for (ReceiveCommand cmd : commands) {
+ sb.append(cmd.getOldId().name())
+ .append(' ').append(cmd.getNewId().name())
+ .append(' ').append(cmd.getRefName()).append('\n');
+ }
+ return sb;
}
- /** @return verification status of the nonce embedded in the certificate. */
- public NonceStatus getNonceStatus() {
- return nonceStatus;
+ @Override
+ public int hashCode() {
+ return signature.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PushCertificate)) {
+ return false;
+ }
+ PushCertificate p = (PushCertificate) o;
+ return version.equals(p.version)
+ && pusher.equals(p.pusher)
+ && Objects.equals(pushee, p.pushee)
+ && nonceStatus == p.nonceStatus
+ && signature.equals(p.signature)
+ && commandsEqual(this, p);
+ }
+
+ private static boolean commandsEqual(PushCertificate c1, PushCertificate c2) {
+ if (c1.commands.size() != c2.commands.size()) {
+ return false;
+ }
+ for (int i = 0; i < c1.commands.size(); i++) {
+ ReceiveCommand cmd1 = c1.commands.get(i);
+ ReceiveCommand cmd2 = c2.commands.get(i);
+ if (!cmd1.getOldId().equals(cmd2.getOldId())
+ || !cmd1.getNewId().equals(cmd2.getNewId())
+ || !cmd1.getRefName().equals(cmd2.getRefName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + '['
+ + toTextWithSignature() + ']';
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
new file mode 100644
index 0000000..871a6f7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateIdent.java
@@ -0,0 +1,269 @@
+/*
+ * 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 java.nio.charset.StandardCharsets.UTF_8;
+
+import static org.eclipse.jgit.util.RawParseUtils.lastIndexOfTrim;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.util.MutableInteger;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * Identity in a push certificate.
+ * <p>
+ * This is similar to a {@link PersonIdent} in that it contains a name,
+ * timestamp, and timezone offset, but differs in the following ways:
+ * <ul>
+ * <li>It is always parsed from a UTF-8 string, rather than a raw commit
+ * buffer.</li>
+ * <li>It is not guaranteed to contain a name and email portion, since any UTF-8
+ * string is a valid OpenPGP User ID (RFC4880 5.1.1). The raw User ID is
+ * always available as {@link #getUserId()}, but {@link #getEmailAddress()}
+ * may return null.</li>
+ * <li>The raw text from which the identity was parsed is available with {@link
+ * #getRaw()}. This is necessary for losslessly reconstructing the signed push
+ * certificate payload.</li>
+ * <li>
+ * </ul>
+ *
+ * @since 4.1
+ */
+public class PushCertificateIdent {
+ /**
+ * Parse an identity from a string.
+ * <p>
+ * Spaces are trimmed when parsing the timestamp and timezone offset, with one
+ * exception. The timestamp must be preceded by a single space, and the rest
+ * of the string prior to that space (including any additional whitespace) is
+ * treated as the OpenPGP User ID.
+ * <p>
+ * If either the timestamp or timezone offsets are missing, mimics {@link
+ * RawParseUtils#parsePersonIdent(String)} behavior and sets them both to
+ * zero.
+ *
+ * @param str
+ * string to parse.
+ * @return identity, never null.
+ */
+ public static PushCertificateIdent parse(String str) {
+ MutableInteger p = new MutableInteger();
+ byte[] raw = str.getBytes(UTF_8);
+ int tzBegin = raw.length - 1;
+ tzBegin = lastIndexOfTrim(raw, ' ', tzBegin);
+ if (tzBegin < 0 || raw[tzBegin] != ' ') {
+ return new PushCertificateIdent(str, str, 0, 0);
+ }
+ int whenBegin = tzBegin++;
+ int tz = RawParseUtils.parseTimeZoneOffset(raw, tzBegin, p);
+ boolean hasTz = p.value != tzBegin;
+
+ whenBegin = lastIndexOfTrim(raw, ' ', whenBegin);
+ if (whenBegin < 0 || raw[whenBegin] != ' ') {
+ return new PushCertificateIdent(str, str, 0, 0);
+ }
+ int idEnd = whenBegin++;
+ long when = RawParseUtils.parseLongBase10(raw, whenBegin, p);
+ boolean hasWhen = p.value != whenBegin;
+
+ if (hasTz && hasWhen) {
+ idEnd = whenBegin - 1;
+ } else {
+ // If either tz or when are non-numeric, mimic parsePersonIdent behavior and
+ // set them both to zero.
+ tz = 0;
+ when = 0;
+ if (hasTz && !hasWhen) {
+ // Only one trailing numeric field; assume User ID ends before this
+ // field, but discard its value.
+ idEnd = tzBegin - 1;
+ } else {
+ // No trailing numeric fields; User ID is whole raw value.
+ idEnd = raw.length;
+ }
+ }
+ String id = new String(raw, 0, idEnd, UTF_8);
+
+ return new PushCertificateIdent(str, id, when * 1000L, tz);
+ }
+
+ private final String raw;
+ private final String userId;
+ private final long when;
+ private final int tzOffset;
+
+ /**
+ * Construct a new identity from an OpenPGP User ID.
+ *
+ * @param userId
+ * OpenPGP User ID; any UTF-8 string.
+ * @param when
+ * local time.
+ * @param tzOffset
+ * timezone offset; see {@link #getTimeZoneOffset()}.
+ */
+ public PushCertificateIdent(String userId, long when, int tzOffset) {
+ this.userId = userId;
+ this.when = when;
+ this.tzOffset = tzOffset;
+ StringBuilder sb = new StringBuilder(userId).append(' ').append(when / 1000)
+ .append(' ');
+ PersonIdent.appendTimezone(sb, tzOffset);
+ raw = sb.toString();
+ }
+
+ private PushCertificateIdent(String raw, String userId, long when,
+ int tzOffset) {
+ this.raw = raw;
+ this.userId = userId;
+ this.when = when;
+ this.tzOffset = tzOffset;
+ }
+
+ /**
+ * Get the raw string from which this identity was parsed.
+ * <p>
+ * If the string was constructed manually, a suitable canonical string is
+ * returned.
+ * <p>
+ * For the purposes of bytewise comparisons with other OpenPGP IDs, the string
+ * must be encoded as UTF-8.
+ *
+ * @return the raw string.
+ */
+ public String getRaw() {
+ return raw;
+ }
+
+ /** @return the OpenPGP User ID, which may be any string. */
+ public String getUserId() {
+ return userId;
+ }
+
+ /**
+ * @return the name portion of the User ID. If no email address would be
+ * parsed by {@link #getEmailAddress()}, returns the full User ID with
+ * spaces trimmed.
+ */
+ public String getName() {
+ int nameEnd = userId.indexOf('<');
+ if (nameEnd < 0 || userId.indexOf('>', nameEnd) < 0) {
+ nameEnd = userId.length();
+ }
+ nameEnd--;
+ while (nameEnd >= 0 && userId.charAt(nameEnd) == ' ') {
+ nameEnd--;
+ }
+ int nameBegin = 0;
+ while (nameBegin < nameEnd && userId.charAt(nameBegin) == ' ') {
+ nameBegin++;
+ }
+ return userId.substring(nameBegin, nameEnd + 1);
+ }
+
+ /**
+ * @return the email portion of the User ID, if one was successfully parsed
+ * from {@link #getUserId()}, or null.
+ */
+ public String getEmailAddress() {
+ int emailBegin = userId.indexOf('<');
+ if (emailBegin < 0) {
+ return null;
+ }
+ int emailEnd = userId.indexOf('>', emailBegin);
+ if (emailEnd < 0) {
+ return null;
+ }
+ return userId.substring(emailBegin + 1, emailEnd);
+ }
+
+ /** @return the timestamp of the identity. */
+ public Date getWhen() {
+ return new Date(when);
+ }
+
+ /**
+ * @return this person's declared time zone; null if the timezone is unknown.
+ */
+ public TimeZone getTimeZone() {
+ return PersonIdent.getTimeZone(tzOffset);
+ }
+
+ /**
+ * @return this person's declared time zone as minutes east of UTC. If the
+ * timezone is to the west of UTC it is negative.
+ */
+ public int getTimeZoneOffset() {
+ return tzOffset;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof PushCertificateIdent)
+ && raw.equals(((PushCertificateIdent) o).raw);
+ }
+
+ @Override
+ public int hashCode() {
+ return raw.hashCode();
+ }
+
+ @SuppressWarnings("nls")
+ @Override
+ public String toString() {
+ SimpleDateFormat fmt;
+ fmt = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy Z", Locale.US);
+ fmt.setTimeZone(getTimeZone());
+ return getClass().getSimpleName()
+ + "[raw=\"" + raw + "\","
+ + " userId=\"" + userId + "\","
+ + " " + fmt.format(Long.valueOf(when)) + "]";
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
index 4bb3d6b..5174f85 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
@@ -40,98 +40,305 @@
* 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.BaseReceivePack.parseCommand;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_CERT;
import java.io.EOFException;
import java.io.IOException;
+import java.io.Reader;
import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.BaseReceivePack.ReceiveConfig;
+import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
+import org.eclipse.jgit.util.IO;
/**
- * Parser for Push certificates
+ * Parser for signed push certificates.
*
* @since 4.0
*/
-public class PushCertificateParser extends PushCertificate {
+public class PushCertificateParser {
+ static final String BEGIN_SIGNATURE =
+ "-----BEGIN PGP SIGNATURE-----"; //$NON-NLS-1$
+ static final String END_SIGNATURE =
+ "-----END PGP SIGNATURE-----"; //$NON-NLS-1$
- private static final String VERSION = "version "; //$NON-NLS-1$
+ static final String VERSION = "certificate version"; //$NON-NLS-1$
- private static final String PUSHER = "pusher"; //$NON-NLS-1$
+ static final String PUSHER = "pusher"; //$NON-NLS-1$
- private static final String PUSHEE = "pushee"; //$NON-NLS-1$
+ static final String PUSHEE = "pushee"; //$NON-NLS-1$
- private static final String NONCE = "nonce"; //$NON-NLS-1$
+ static final String NONCE = "nonce"; //$NON-NLS-1$
- /** The individual certificate which is presented to the client */
+ static final String END_CERT = "push-cert-end"; //$NON-NLS-1$
+
+ private static final String VERSION_0_1 = "0.1"; //$NON-NLS-1$
+
+ private static interface StringReader {
+ /**
+ * @return the next string from the input, up to an optional newline, with
+ * newline stripped if present
+ *
+ * @throws EOFException
+ * if EOF was reached.
+ * @throws IOException
+ * if an error occurred during reading.
+ */
+ String read() throws EOFException, IOException;
+ }
+
+ private static class PacketLineReader implements StringReader {
+ private final PacketLineIn pckIn;
+
+ private PacketLineReader(PacketLineIn pckIn) {
+ this.pckIn = pckIn;
+ }
+
+ @Override
+ public String read() throws IOException {
+ return pckIn.readString();
+ }
+ }
+
+ private static class StreamReader implements StringReader {
+ private final Reader reader;
+
+ private StreamReader(Reader reader) {
+ this.reader = reader;
+ }
+
+ @Override
+ public String read() throws IOException {
+ // Presize for a command containing 2 SHA-1s and some refname.
+ String line = IO.readLine(reader, 41 * 2 + 64);
+ if (line.isEmpty()) {
+ throw new EOFException();
+ } else if (line.charAt(line.length() - 1) == '\n') {
+ line = line.substring(0, line.length() - 1);
+ }
+ return line;
+ }
+ }
+
+ /**
+ * Parse a push certificate from a reader.
+ * <p>
+ * Differences from the {@link PacketLineIn} receiver methods:
+ * <ul>
+ * <li>Does not use pkt-line framing.</li>
+ * <li>Reads an entire cert in one call rather than depending on a loop in
+ * the caller.</li>
+ * <li>Does not assume a {@code "push-cert-end"} line.</li>
+ * </ul>
+ *
+ * @param r
+ * input reader; consumed only up until the end of the next
+ * signature in the input.
+ * @return the parsed certificate, or null if the reader was at EOF.
+ * @throws PackProtocolException
+ * if the certificate is malformed.
+ * @throws IOException
+ * if there was an error reading from the input.
+ * @since 4.1
+ */
+ public static PushCertificate fromReader(Reader r)
+ throws PackProtocolException, IOException {
+ return new PushCertificateParser().parse(r);
+ }
+
+ /**
+ * Parse a push certificate from a string.
+ *
+ * @see #fromReader(Reader)
+ * @param str
+ * input string.
+ * @return the parsed certificate.
+ * @throws PackProtocolException
+ * if the certificate is malformed.
+ * @throws IOException
+ * if there was an error reading from the input.
+ * @since 4.1
+ */
+ public static PushCertificate fromString(String str)
+ throws PackProtocolException, IOException {
+ return fromReader(new java.io.StringReader(str));
+ }
+
+ private boolean received;
+ private String version;
+ private PushCertificateIdent pusher;
+ private String pushee;
+
+ /** The nonce that was sent to the client. */
private String sentNonce;
/**
- * The nonce the pusher signed. This may vary from pushCertNonce See
- * git-core documentation for reasons.
+ * The nonce the pusher signed.
+ * <p>
+ * This may vary from {@link #sentNonce}; see git-core documentation for
+ * reasons.
*/
private String receivedNonce;
+ private NonceStatus nonceStatus;
+ private String signature;
+
+ /** Database we write the push certificate into. */
+ private final Repository db;
+
/**
* The maximum time difference which is acceptable between advertised nonce
* and received signed nonce.
*/
- private int nonceSlopLimit;
+ private final int nonceSlopLimit;
- NonceGenerator nonceGenerator;
+ private final boolean enabled;
+ private final NonceGenerator nonceGenerator;
+ private final List<ReceiveCommand> commands = new ArrayList<>();
/**
- * used to build up commandlist
+ * @param into
+ * destination repository for the push.
+ * @param cfg
+ * configuration for signed push.
+ * @since 4.1
*/
- StringBuilder commandlistBuilder;
-
- /** Database we write the push certificate into. */
- private Repository db;
-
- PushCertificateParser(Repository into, ReceiveConfig cfg) {
- nonceSlopLimit = cfg.certNonceSlopLimit;
- nonceGenerator = cfg.certNonceSeed != null
- ? new HMACSHA1NonceGenerator(cfg.certNonceSeed)
- : null;
+ public PushCertificateParser(Repository into, SignedPushConfig cfg) {
+ if (cfg != null) {
+ nonceSlopLimit = cfg.getCertNonceSlopLimit();
+ nonceGenerator = cfg.getNonceGenerator();
+ } else {
+ nonceSlopLimit = 0;
+ nonceGenerator = null;
+ }
db = into;
+ enabled = nonceGenerator != null;
+ }
+
+ private PushCertificateParser() {
+ db = null;
+ nonceSlopLimit = 0;
+ nonceGenerator = null;
+ enabled = true;
}
/**
- * @return if the server is configured to use signed pushes.
+ * Parse a push certificate from a reader.
+ *
+ * @see #fromReader(Reader)
+ * @param r
+ * input reader; consumed only up until the end of the next
+ * signature in the input.
+ * @return the parsed certificate, or null if the reader was at EOF.
+ * @throws PackProtocolException
+ * if the certificate is malformed.
+ * @throws IOException
+ * if there was an error reading from the input.
+ * @since 4.1
+ */
+ public PushCertificate parse(Reader r)
+ throws PackProtocolException, IOException {
+ StreamReader reader = new StreamReader(r);
+ receiveHeader(reader, true);
+ String line;
+ try {
+ while (!(line = reader.read()).isEmpty()) {
+ if (line.equals(BEGIN_SIGNATURE)) {
+ receiveSignature(reader);
+ break;
+ }
+ addCommand(line);
+ }
+ } catch (EOFException e) {
+ // EOF reached, but might have been at a valid state. Let build call below
+ // sort it out.
+ }
+ return build();
+ }
+
+ /**
+ * @return the parsed certificate, or null if push certificates are disabled.
+ * @throws IOException
+ * if the push certificate has missing or invalid fields.
+ * @since 4.1
+ */
+ public PushCertificate build() throws IOException {
+ if (!received || !enabled) {
+ return null;
+ }
+ try {
+ return new PushCertificate(version, pusher, pushee, receivedNonce,
+ nonceStatus, Collections.unmodifiableList(commands), signature);
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * @return if the repository is configured to use signed pushes in this
+ * context.
+ * @since 4.0
*/
public boolean enabled() {
- return nonceGenerator != null;
+ return enabled;
}
/**
* @return the whole string for the nonce to be included into the capability
- * advertisement.
+ * advertisement, or null if push certificates are disabled.
+ * @since 4.0
*/
public String getAdvertiseNonce() {
- sentNonce = nonceGenerator.createNonce(db,
- TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
- return CAPABILITY_PUSH_CERT + "=" + sentNonce; //$NON-NLS-1$
+ String nonce = sentNonce();
+ if (nonce == null) {
+ return null;
+ }
+ return CAPABILITY_PUSH_CERT + '=' + nonce;
}
- private String parseNextLine(PacketLineIn pckIn, String startingWith)
+ private String sentNonce() {
+ if (sentNonce == null && nonceGenerator != null) {
+ sentNonce = nonceGenerator.createNonce(db,
+ TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
+ }
+ return sentNonce;
+ }
+
+ private static String parseHeader(StringReader reader, String header)
throws IOException {
- String s = pckIn.readString();
- if (!s.startsWith(startingWith))
- throw new IOException(MessageFormat.format(
- JGitText.get().errorInvalidPushCert,
- "expected " + startingWith)); //$NON-NLS-1$
- return s.substring(startingWith.length());
+ return parseHeader(reader.read(), header);
+ }
+
+ private static String parseHeader(String s, String header)
+ throws IOException {
+ if (s.isEmpty()) {
+ throw new EOFException();
+ }
+ if (s.length() <= header.length()
+ || !s.startsWith(header)
+ || s.charAt(header.length()) != ' ') {
+ throw new PackProtocolException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidField, header));
+ }
+ return s.substring(header.length() + 1);
}
/**
* Receive a list of commands from the input encapsulated in a push
- * certificate. This method doesn't parse the first line "push-cert \NUL
- * <capabilities>", but assumes the first line including the
+ * certificate.
+ * <p>
+ * This method doesn't parse the first line {@code "push-cert \NUL
+ * <capabilities>"}, but assumes the first line including the
* capabilities has already been handled by the caller.
*
* @param pckIn
@@ -144,62 +351,115 @@
* @throws IOException
* if the certificate from the client is badly malformed or the
* client disconnects before sending the entire certificate.
+ * @since 4.0
*/
public void receiveHeader(PacketLineIn pckIn, boolean stateless)
throws IOException {
+ receiveHeader(new PacketLineReader(pckIn), stateless);
+ }
+
+ private void receiveHeader(StringReader reader, boolean stateless)
+ throws IOException {
try {
- String version = parseNextLine(pckIn, VERSION);
- if (!version.equals("0.1")) { //$NON-NLS-1$
- throw new IOException(MessageFormat.format(
- JGitText.get().errorInvalidPushCert,
- "version not supported")); //$NON-NLS-1$
+ try {
+ version = parseHeader(reader, VERSION);
+ } catch (EOFException e) {
+ return;
}
- pusher = parseNextLine(pckIn, PUSHER);
- pushee = parseNextLine(pckIn, PUSHEE);
- receivedNonce = parseNextLine(pckIn, NONCE);
- // an empty line
- if (!pckIn.readString().isEmpty()) {
- throw new IOException(MessageFormat.format(
- JGitText.get().errorInvalidPushCert,
- "expected empty line after header")); //$NON-NLS-1$
+ received = true;
+ if (!version.equals(VERSION_0_1)) {
+ throw new PackProtocolException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidFieldValue, VERSION, version));
+ }
+ String rawPusher = parseHeader(reader, PUSHER);
+ pusher = PushCertificateIdent.parse(rawPusher);
+ if (pusher == null) {
+ throw new PackProtocolException(MessageFormat.format(
+ JGitText.get().pushCertificateInvalidFieldValue,
+ PUSHER, rawPusher));
+ }
+ String next = reader.read();
+ if (next.startsWith(PUSHEE)) {
+ pushee = parseHeader(next, PUSHEE);
+ receivedNonce = parseHeader(reader, NONCE);
+ } else {
+ receivedNonce = parseHeader(next, NONCE);
+ }
+ nonceStatus = nonceGenerator != null
+ ? nonceGenerator.verify(
+ receivedNonce, sentNonce(), db, stateless, nonceSlopLimit)
+ : NonceStatus.UNSOLICITED;
+ // An empty line.
+ if (!reader.read().isEmpty()) {
+ throw new PackProtocolException(
+ JGitText.get().pushCertificateInvalidHeader);
}
} catch (EOFException eof) {
- throw new IOException(MessageFormat.format(
- JGitText.get().errorInvalidPushCert,
- "broken push certificate header")); //$NON-NLS-1$
+ throw new PackProtocolException(
+ JGitText.get().pushCertificateInvalidHeader, eof);
}
- nonceStatus = nonceGenerator.verify(receivedNonce, sentNonce, db,
- stateless, nonceSlopLimit);
}
/**
- * Reads the gpg signature. This method assumes the line "-----BEGIN PGP
- * SIGNATURE-----\n" has already been parsed and continues parsing until an
- * "-----END PGP SIGNATURE-----\n" is found.
+ * Read the PGP signature.
+ * <p>
+ * This method assumes the line
+ * {@code "-----BEGIN PGP SIGNATURE-----"} has already been parsed,
+ * and continues parsing until an {@code "-----END PGP SIGNATURE-----"} is
+ * found, followed by {@code "push-cert-end"}.
*
* @param pckIn
* where we read the signature from.
* @throws IOException
+ * if the signature is invalid.
+ * @since 4.0
*/
public void receiveSignature(PacketLineIn pckIn) throws IOException {
+ StringReader reader = new PacketLineReader(pckIn);
+ receiveSignature(reader);
+ if (!reader.read().equals(END_CERT)) {
+ throw new PackProtocolException(
+ JGitText.get().pushCertificateInvalidSignature);
+ }
+ }
+
+ private void receiveSignature(StringReader reader) throws IOException {
+ received = true;
try {
- StringBuilder sig = new StringBuilder();
- String line = pckIn.readStringRaw();
- while (!line.equals("-----END PGP SIGNATURE-----\n")) //$NON-NLS-1$
- sig.append(line);
- signature = sig.toString();
- commandList = commandlistBuilder.toString();
+ StringBuilder sig = new StringBuilder(BEGIN_SIGNATURE).append('\n');
+ String line;
+ while (!(line = reader.read()).equals(END_SIGNATURE)) {
+ sig.append(line).append('\n');
+ }
+ signature = sig.append(END_SIGNATURE).append('\n').toString();
} catch (EOFException eof) {
- throw new IOException(MessageFormat.format(
- JGitText.get().errorInvalidPushCert,
- "broken push certificate signature")); //$NON-NLS-1$
+ throw new PackProtocolException(
+ JGitText.get().pushCertificateInvalidSignature, eof);
}
}
/**
- * @param rawLine
+ * Add a command to the signature.
+ *
+ * @param cmd
+ * the command.
+ * @since 4.1
*/
- public void addCommand(String rawLine) {
- commandlistBuilder.append(rawLine);
+ public void addCommand(ReceiveCommand cmd) {
+ commands.add(cmd);
+ }
+
+ /**
+ * Add a command to the signature.
+ *
+ * @param line
+ * the line read from the wire that produced this
+ * command, with optional trailing newline already trimmed.
+ * @throws PackProtocolException
+ * if the raw line cannot be parsed to a command.
+ * @since 4.0
+ */
+ public void addCommand(String line) throws PackProtocolException {
+ commands.add(parseCommand(line));
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
new file mode 100644
index 0000000..d8672d5
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
@@ -0,0 +1,552 @@
+/*
+ * 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 java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.FileMode.TYPE_FILE;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+
+/**
+ * Storage for recorded push certificates.
+ * <p>
+ * Push certificates are stored in a special ref {@code refs/meta/push-certs}.
+ * The filenames in the tree are ref names followed by the special suffix
+ * <code>@{cert}</code>, and the contents are the latest push cert affecting
+ * that ref. The special suffix allows storing certificates for both refs/foo
+ * and refs/foo/bar in case those both existed at some point.
+ *
+ * @since 4.1
+ */
+public class PushCertificateStore implements AutoCloseable {
+ /** Ref name storing push certificates. */
+ static final String REF_NAME =
+ Constants.R_REFS + "meta/push-certs"; //$NON-NLS-1$
+
+ private static class PendingCert {
+ private PushCertificate cert;
+ private PersonIdent ident;
+ private Collection<ReceiveCommand> matching;
+
+ private PendingCert(PushCertificate cert, PersonIdent ident,
+ Collection<ReceiveCommand> matching) {
+ this.cert = cert;
+ this.ident = ident;
+ this.matching = matching;
+ }
+ }
+
+ private final Repository db;
+ private final List<PendingCert> pending;
+ private ObjectReader reader;
+ private RevCommit commit;
+
+ /**
+ * Create a new store backed by the given repository.
+ *
+ * @param db
+ * the repository.
+ */
+ public PushCertificateStore(Repository db) {
+ this.db = db;
+ pending = new ArrayList<>();
+ }
+
+ /**
+ * Close resources opened by this store.
+ * <p>
+ * If {@link #get(String)} was called, closes the cached object reader created
+ * by that method. Does not close the underlying repository.
+ */
+ public void close() {
+ if (reader != null) {
+ reader.close();
+ reader = null;
+ commit = null;
+ }
+ }
+
+ /**
+ * Get latest push certificate associated with a ref.
+ * <p>
+ * Lazily opens {@code refs/meta/push-certs} and reads from the repository as
+ * necessary. The state is cached between calls to {@code get}; to reread the,
+ * call {@link #close()} first.
+ *
+ * @param refName
+ * the ref name to get the certificate for.
+ * @return last certificate affecting the ref, or null if no cert was recorded
+ * for the last update to this ref.
+ * @throws IOException
+ * if a problem occurred reading the repository.
+ */
+ public PushCertificate get(String refName) throws IOException {
+ if (reader == null) {
+ load();
+ }
+ try (TreeWalk tw = newTreeWalk(refName)) {
+ return read(tw);
+ }
+ }
+
+ /**
+ * Iterate over all push certificates affecting a ref.
+ * <p>
+ * Only includes push certificates actually stored in the tree; see class
+ * Javadoc for conditions where this might not include all push certs ever
+ * seen for this ref.
+ * <p>
+ * The returned iterable may be iterated multiple times, and push certs will
+ * be re-read from the current state of the store on each call to {@link
+ * Iterable#iterator()}. However, method calls on the returned iterator may
+ * fail if {@code save} or {@code close} is called on the enclosing store
+ * during iteration.
+ *
+ * @param refName
+ * the ref name to get certificates for.
+ * @return iterable over certificates; must be fully iterated in order to
+ * close resources.
+ */
+ public Iterable<PushCertificate> getAll(final String refName) {
+ return new Iterable<PushCertificate>() {
+ @Override
+ public Iterator<PushCertificate> iterator() {
+ return new Iterator<PushCertificate>() {
+ private final String path = pathName(refName);
+ private PushCertificate next;
+
+ private RevWalk rw;
+ {
+ try {
+ if (reader == null) {
+ load();
+ }
+ if (commit != null) {
+ rw = new RevWalk(reader);
+ rw.setTreeFilter(AndTreeFilter.create(
+ PathFilterGroup.create(
+ Collections.singleton(PathFilter.create(path))),
+ TreeFilter.ANY_DIFF));
+ rw.setRewriteParents(false);
+ rw.markStart(rw.parseCommit(commit));
+ } else {
+ rw = null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ try {
+ if (next == null) {
+ if (rw == null) {
+ return false;
+ }
+ try {
+ RevCommit c = rw.next();
+ if (c != null) {
+ try (TreeWalk tw = TreeWalk.forPath(
+ rw.getObjectReader(), path, c.getTree())) {
+ next = read(tw);
+ }
+ } else {
+ next = null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return next != null;
+ } finally {
+ if (next == null && rw != null) {
+ rw.close();
+ rw = null;
+ }
+ }
+ }
+
+ @Override
+ public PushCertificate next() {
+ hasNext();
+ PushCertificate n = next;
+ if (n == null) {
+ throw new NoSuchElementException();
+ }
+ next = null;
+ return n;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ private void load() throws IOException {
+ close();
+ reader = db.newObjectReader();
+ Ref ref = db.getRefDatabase().exactRef(REF_NAME);
+ if (ref == null) {
+ // No ref, same as empty.
+ return;
+ }
+ try (RevWalk rw = new RevWalk(reader)) {
+ commit = rw.parseCommit(ref.getObjectId());
+ }
+ }
+
+ private static PushCertificate read(TreeWalk tw) throws IOException {
+ if (tw == null || (tw.getRawMode(0) & TYPE_FILE) != TYPE_FILE) {
+ return null;
+ }
+ ObjectLoader loader =
+ tw.getObjectReader().open(tw.getObjectId(0), OBJ_BLOB);
+ try (InputStream in = loader.openStream();
+ Reader r = new BufferedReader(new InputStreamReader(in, UTF_8))) {
+ return PushCertificateParser.fromReader(r);
+ }
+ }
+
+ /**
+ * Put a certificate to be saved to the store.
+ * <p>
+ * Writes the contents of this certificate for each ref mentioned. It is up to
+ * the caller to ensure this certificate accurately represents the state of
+ * the ref.
+ * <p>
+ * Pending certificates added to this method are not returned by {@link
+ * #get(String)} and {@link #getAll(String)} until after calling {@link
+ * #save()}.
+ *
+ * @param cert
+ * certificate to store.
+ * @param ident
+ * identity for the commit that stores this certificate. Pending
+ * certificates are sorted by identity timestamp during {@link
+ * #save()}.
+ */
+ public void put(PushCertificate cert, PersonIdent ident) {
+ put(cert, ident, null);
+ }
+
+ /**
+ * Put a certificate to be saved to the store, matching a set of commands.
+ * <p>
+ * Like {@link #put(PushCertificate, PersonIdent)}, except a value is only
+ * stored for a push certificate if there is a corresponding command in the
+ * list that exactly matches the old/new values mentioned in the push
+ * certificate.
+ * <p>
+ * Pending certificates added to this method are not returned by {@link
+ * #get(String)} and {@link #getAll(String)} until after calling {@link
+ * #save()}.
+ *
+ * @param cert
+ * certificate to store.
+ * @param ident
+ * identity for the commit that stores this certificate. Pending
+ * certificates are sorted by identity timestamp during {@link
+ * #save()}.
+ * @param matching
+ * only store certs for the refs listed in this list whose values
+ * match the commands in the cert.
+ */
+ public void put(PushCertificate cert, PersonIdent ident,
+ Collection<ReceiveCommand> matching) {
+ pending.add(new PendingCert(cert, ident, matching));
+ }
+
+ /**
+ * Save pending certificates to the store.
+ * <p>
+ * One commit is created per certificate added with {@link
+ * #put(PushCertificate, PersonIdent)}, in order of identity timestamps, and
+ * a single ref update is performed.
+ * <p>
+ * The pending list is cleared if and only the ref update fails, which allows
+ * for easy retries in case of lock failure.
+ *
+ * @return the result of attempting to update the ref.
+ * @throws IOException
+ * if there was an error reading from or writing to the
+ * repository.
+ */
+ public RefUpdate.Result save() throws IOException {
+ ObjectId newId = write();
+ if (newId == null) {
+ return RefUpdate.Result.NO_CHANGE;
+ }
+ try (ObjectInserter inserter = db.newObjectInserter()) {
+ RefUpdate.Result result = updateRef(newId);
+ switch (result) {
+ case FAST_FORWARD:
+ case NEW:
+ case NO_CHANGE:
+ pending.clear();
+ break;
+ default:
+ break;
+ }
+ return result;
+ } finally {
+ close();
+ }
+ }
+
+ /**
+ * Save pending certificates to the store in an existing batch ref update.
+ * <p>
+ * One commit is created per certificate added with {@link
+ * #put(PushCertificate, PersonIdent)}, in order of identity timestamps, all
+ * commits are flushed, and a single command is added to the batch.
+ * <p>
+ * The cached ref value and pending list are <em>not</em> cleared. If the ref
+ * update succeeds, the caller is responsible for calling {@link #close()}
+ * and/or {@link #clear()}.
+ *
+ * @param batch
+ * update to save to.
+ * @return whether a command was added to the batch.
+ * @throws IOException
+ * if there was an error reading from or writing to the
+ * repository.
+ */
+ public boolean save(BatchRefUpdate batch) throws IOException {
+ ObjectId newId = write();
+ if (newId == null || newId.equals(commit)) {
+ return false;
+ }
+ batch.addCommand(new ReceiveCommand(
+ commit != null ? commit : ObjectId.zeroId(), newId, REF_NAME));
+ return true;
+ }
+
+ /**
+ * Clear pending certificates added with {@link #put(PushCertificate,
+ * PersonIdent)}.
+ */
+ public void clear() {
+ pending.clear();
+ }
+
+ private ObjectId write() throws IOException {
+ if (pending.isEmpty()) {
+ return null;
+ }
+ if (reader == null) {
+ load();
+ }
+ sortPending(pending);
+
+ ObjectId curr = commit;
+ DirCache dc = newDirCache();
+ try (ObjectInserter inserter = db.newObjectInserter()) {
+ for (PendingCert pc : pending) {
+ curr = saveCert(inserter, dc, pc, curr);
+ }
+ inserter.flush();
+ return curr;
+ }
+ }
+
+ private static void sortPending(List<PendingCert> pending) {
+ Collections.sort(pending, new Comparator<PendingCert>() {
+ @Override
+ public int compare(PendingCert a, PendingCert b) {
+ return Long.signum(
+ a.ident.getWhen().getTime() - b.ident.getWhen().getTime());
+ }
+ });
+ }
+
+ private DirCache newDirCache() throws IOException {
+ DirCache dc = DirCache.newInCore();
+ if (commit != null) {
+ DirCacheBuilder b = dc.builder();
+ b.addTree(new byte[0], DirCacheEntry.STAGE_0, reader, commit.getTree());
+ b.finish();
+ }
+ return dc;
+ }
+
+ private ObjectId saveCert(ObjectInserter inserter, DirCache dc,
+ PendingCert pc, ObjectId curr) throws IOException {
+ Map<String, ReceiveCommand> byRef;
+ if (pc.matching != null) {
+ byRef = new HashMap<>();
+ for (ReceiveCommand cmd : pc.matching) {
+ if (byRef.put(cmd.getRefName(), cmd) != null) {
+ throw new IllegalStateException();
+ }
+ }
+ } else {
+ byRef = null;
+ }
+
+ DirCacheEditor editor = dc.editor();
+ String certText = pc.cert.toText() + pc.cert.getSignature();
+ final ObjectId certId = inserter.insert(OBJ_BLOB, certText.getBytes(UTF_8));
+ boolean any = false;
+ for (ReceiveCommand cmd : pc.cert.getCommands()) {
+ if (byRef != null && !commandsEqual(cmd, byRef.get(cmd.getRefName()))) {
+ continue;
+ }
+ any = true;
+ editor.add(new PathEdit(pathName(cmd.getRefName())) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.REGULAR_FILE);
+ ent.setObjectId(certId);
+ }
+ });
+ }
+ if (!any) {
+ return curr;
+ }
+ editor.finish();
+ CommitBuilder cb = new CommitBuilder();
+ cb.setAuthor(pc.ident);
+ cb.setCommitter(pc.ident);
+ cb.setTreeId(dc.writeTree(inserter));
+ if (curr != null) {
+ cb.setParentId(curr);
+ } else {
+ cb.setParentIds(Collections.<ObjectId> emptyList());
+ }
+ cb.setMessage(buildMessage(pc.cert));
+ return inserter.insert(OBJ_COMMIT, cb.build());
+ }
+
+ private static boolean commandsEqual(ReceiveCommand c1, ReceiveCommand c2) {
+ if (c1 == null || c2 == null) {
+ return c1 == c2;
+ }
+ return c1.getRefName().equals(c2.getRefName())
+ && c1.getOldId().equals(c2.getOldId())
+ && c1.getNewId().equals(c2.getNewId());
+ }
+
+ private RefUpdate.Result updateRef(ObjectId newId) throws IOException {
+ RefUpdate ru = db.updateRef(REF_NAME);
+ ru.setExpectedOldObjectId(commit != null ? commit : ObjectId.zeroId());
+ ru.setNewObjectId(newId);
+ ru.setRefLogIdent(pending.get(pending.size() - 1).ident);
+ ru.setRefLogMessage(JGitText.get().storePushCertReflog, false);
+ try (RevWalk rw = new RevWalk(reader)) {
+ return ru.update(rw);
+ }
+ }
+
+ private TreeWalk newTreeWalk(String refName) throws IOException {
+ if (commit == null) {
+ return null;
+ }
+ return TreeWalk.forPath(reader, pathName(refName), commit.getTree());
+ }
+
+ private static String pathName(String refName) {
+ return refName + "@{cert}"; //$NON-NLS-1$
+ }
+
+ private static String buildMessage(PushCertificate cert) {
+ StringBuilder sb = new StringBuilder();
+ if (cert.getCommands().size() == 1) {
+ sb.append(MessageFormat.format(
+ JGitText.get().storePushCertOneRef,
+ cert.getCommands().get(0).getRefName()));
+ } else {
+ sb.append(MessageFormat.format(
+ JGitText.get().storePushCertMultipleRefs,
+ Integer.valueOf(cert.getCommands().size())));
+ }
+ return sb.append('\n').toString();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 44b8778..6ed9bc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -246,6 +246,7 @@
try {
postReceive.onPostReceive(this, filterCommands(Result.OK));
} catch (Throwable e) {
+ // empty
}
throw new UnpackException(unpackError);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java
new file mode 100644
index 0000000..942e7d7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SignedPushConfig.java
@@ -0,0 +1,146 @@
+/*
+ * 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 org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Config.SectionParser;
+
+/**
+ * Configuration for server-side signed push verification.
+ *
+ * @since 4.1
+ */
+public class SignedPushConfig {
+ /** Key for {@link Config#get(SectionParser)}. */
+ public static final SectionParser<SignedPushConfig> KEY =
+ new SectionParser<SignedPushConfig>() {
+ public SignedPushConfig parse(Config cfg) {
+ return new SignedPushConfig(cfg);
+ }
+ };
+
+ private String certNonceSeed;
+ private int certNonceSlopLimit;
+ private NonceGenerator nonceGenerator;
+
+ /** Create a new config with default values disabling push verification. */
+ public SignedPushConfig() {
+ }
+
+ SignedPushConfig(Config cfg) {
+ setCertNonceSeed(cfg.getString("receive", null, "certnonceseed")); //$NON-NLS-1$ //$NON-NLS-2$
+ certNonceSlopLimit = cfg.getInt("receive", "certnonceslop", 0); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Set the seed used by the nonce verifier.
+ * <p>
+ * Setting this to a non-null value enables push certificate verification
+ * using the default {@link HMACSHA1NonceGenerator} implementation, if a
+ * different implementation was not set using {@link
+ * #setNonceGenerator(NonceGenerator)}.
+ *
+ * @param seed
+ * new seed value.
+ */
+ public void setCertNonceSeed(String seed) {
+ certNonceSeed = seed;
+ }
+
+ /** @return the configured seed. */
+ public String getCertNonceSeed() {
+ return certNonceSeed;
+ }
+
+ /**
+ * Set the nonce slop limit.
+ * <p>
+ * Old but valid nonces within this limit will be accepted.
+ *
+ * @param limit
+ * new limit in seconds.
+ */
+ public void setCertNonceSlopLimit(int limit) {
+ certNonceSlopLimit = limit;
+ }
+
+ /** @return the configured nonce slop limit. */
+ public int getCertNonceSlopLimit() {
+ return certNonceSlopLimit;
+ }
+
+ /**
+ * Set the {@link NonceGenerator} used for signed pushes.
+ * <p>
+ * Setting this to a non-null value enables push certificate verification. If
+ * this method is called, this implementation will be used instead of the
+ * default {@link HMACSHA1NonceGenerator} even if {@link
+ * #setCertNonceSeed(String)} was called.
+ *
+ * @param generator
+ * new nonce generator.
+ */
+ public void setNonceGenerator(NonceGenerator generator) {
+ nonceGenerator = generator;
+ }
+
+ /**
+ * Get the {@link NonceGenerator} used for signed pushes.
+ * <p>
+ * If {@link #setNonceGenerator(NonceGenerator)} was used to set a non-null
+ * implementation, that will be returned. If no custom implementation was set
+ * but {@link #setCertNonceSeed(String)} was called, returns a newly-created
+ * {@link HMACSHA1NonceGenerator}.
+ *
+ * @return the configured nonce generator.
+ */
+ public NonceGenerator getNonceGenerator() {
+ if (nonceGenerator != null) {
+ return nonceGenerator;
+ } else if (certNonceSeed != null) {
+ return new HMACSHA1NonceGenerator(certNonceSeed);
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 138002e..f4de821 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -71,6 +71,7 @@
private final boolean safeForWindows;
private final boolean safeForMacOS;
private final boolean allowTipSha1InWant;
+ private final boolean allowReachableSha1InWant;
private final String[] hideRefs;
TransferConfig(final Repository db) {
@@ -94,6 +95,8 @@
allowTipSha1InWant = rc.getBoolean(
"uploadpack", "allowtipsha1inwant", false); //$NON-NLS-1$ //$NON-NLS-2$
+ allowReachableSha1InWant = rc.getBoolean(
+ "uploadpack", "allowreachablesha1inwant", false); //$NON-NLS-1$ //$NON-NLS-2$
hideRefs = rc.getStringList("uploadpack", null, "hiderefs"); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -121,6 +124,14 @@
}
/**
+ * @return allow clients to request non-tip SHA-1s?
+ * @since 4.1
+ */
+ public boolean isAllowReachableSha1InWant() {
+ return allowReachableSha1InWant;
+ }
+
+ /**
* @return {@link RefFilter} respecting configured hidden refs.
* @since 3.1
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
index afaaa69..745cdb7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
@@ -148,7 +148,7 @@
super(local, uri);
Properties props = loadProperties();
- if (!props.contains("tmpdir") && local.getDirectory() != null) //$NON-NLS-1$
+ if (!props.containsKey("tmpdir") && local.getDirectory() != null) //$NON-NLS-1$
props.put("tmpdir", local.getDirectory().getPath()); //$NON-NLS-1$
s3 = new AmazonS3(props);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
index 91e212b..3700b49 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -4,6 +4,7 @@
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2013, Robin Stocker <robin@nibor.org>
+ * Copyright (C) 2015, Patrick Steinhardt <ps@pks.im>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -134,11 +135,11 @@
+ OPT_USER_PWD_P //
+ HOST_P //
+ OPT_PORT_P //
- + "(" // open a catpuring group the the user-home-dir part //$NON-NLS-1$
- + (USER_HOME_P + "?") // //$NON-NLS-1$
- + "[\\\\/])" // //$NON-NLS-1$
+ + "(" // open a group capturing the user-home-dir-part //$NON-NLS-1$
+ + (USER_HOME_P + "?") //$NON-NLS-1$
+ + "[\\\\/])" //$NON-NLS-1$
+ ")?" // close the optional group containing hostname //$NON-NLS-1$
- + "(.+)?" // //$NON-NLS-1$
+ + "(.+)?" //$NON-NLS-1$
+ "$"); //$NON-NLS-1$
/**
@@ -690,6 +691,10 @@
* <td><code>/path/to/repo/</code></td>
* </tr>
* <tr>
+ * <td><code>localhost</code></td>
+ * <td><code>ssh://localhost/</code></td>
+ * </tr>
+ * <tr>
* <td><code>/path//to</code></td>
* <td>an empty string</td>
* </tr>
@@ -703,9 +708,12 @@
* @see #getPath
*/
public String getHumanishName() throws IllegalArgumentException {
- if ("".equals(getPath()) || getPath() == null) //$NON-NLS-1$
- throw new IllegalArgumentException();
String s = getPath();
+ if ("/".equals(s)) //$NON-NLS-1$
+ s = getHost();
+ if ("".equals(s) || s == null) //$NON-NLS-1$
+ throw new IllegalArgumentException();
+
String[] elements;
if ("file".equals(scheme) || LOCAL_FILE.matcher(s).matches()) //$NON-NLS-1$
elements = s.split("[\\" + File.separatorChar + "/]"); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 753277d..101057f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -46,6 +46,7 @@
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_REACHABLE_SHA1_IN_WANT;
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_DETAILED;
@@ -93,6 +94,7 @@
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.GitProtocolConstants.MultiAck;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.util.io.InterruptTimer;
@@ -252,6 +254,9 @@
/** Hook handling the various upload phases. */
private PreUploadHook preUploadHook = PreUploadHook.NULL;
+ /** Hook for taking post upload actions. */
+ private PostUploadHook postUploadHook = PostUploadHook.NULL;
+
/** Capabilities requested by the client. */
private Set<String> options;
String userAgent;
@@ -305,7 +310,7 @@
private boolean noDone;
- private PackWriter.Statistics statistics;
+ private PackStatistics statistics;
private UploadPackLogger logger = UploadPackLogger.NULL;
@@ -518,7 +523,7 @@
this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
}
- /** @return the configured upload hook. */
+ /** @return the configured pre upload hook. */
public PreUploadHook getPreUploadHook() {
return preUploadHook;
}
@@ -534,6 +539,25 @@
}
/**
+ * @return the configured post upload hook.
+ * @since 4.1
+ */
+ public PostUploadHook getPostUploadHook() {
+ return postUploadHook;
+ }
+
+ /**
+ * Set the hook for post upload actions (logging, repacking).
+ *
+ * @param hook
+ * the hook; if null no special actions are taken.
+ * @since 4.1
+ */
+ public void setPostUploadHook(PostUploadHook hook) {
+ postUploadHook = hook != null ? hook : PostUploadHook.NULL;
+ }
+
+ /**
* Set the configuration used by the pack generator.
*
* @param pc
@@ -552,11 +576,21 @@
*/
public void setTransferConfig(TransferConfig tc) {
this.transferConfig = tc != null ? tc : new TransferConfig(db);
- setRequestPolicy(transferConfig.isAllowTipSha1InWant()
- ? RequestPolicy.TIP : RequestPolicy.ADVERTISED);
+ if (transferConfig.isAllowTipSha1InWant()) {
+ setRequestPolicy(transferConfig.isAllowReachableSha1InWant()
+ ? RequestPolicy.REACHABLE_COMMIT_TIP : RequestPolicy.TIP);
+ } else {
+ setRequestPolicy(transferConfig.isAllowReachableSha1InWant()
+ ? RequestPolicy.REACHABLE_COMMIT : RequestPolicy.ADVERTISED);
+ }
}
- /** @return the configured logger. */
+ /**
+ * @return the configured logger.
+ *
+ * @deprecated Use {@link #getPreUploadHook()}.
+ */
+ @Deprecated
public UploadPackLogger getLogger() {
return logger;
}
@@ -566,7 +600,9 @@
*
* @param logger
* the logger instance. If null, no logging occurs.
+ * @deprecated Use {@link #setPreUploadHook(PreUploadHook)}.
*/
+ @Deprecated
public void setLogger(UploadPackLogger logger) {
this.logger = logger;
}
@@ -648,8 +684,23 @@
* was sent, such as during the negotation phase of a smart HTTP
* connection, or if the client was already up-to-date.
* @since 3.0
+ * @deprecated Use {@link #getStatistics()}.
*/
+ @Deprecated
public PackWriter.Statistics getPackStatistics() {
+ return statistics == null ? null
+ : new PackWriter.Statistics(statistics);
+ }
+
+ /**
+ * Get the PackWriter's statistics if a pack was sent to the client.
+ *
+ * @return statistics about pack output, if a pack was sent. Null if no pack
+ * was sent, such as during the negotation phase of a smart HTTP
+ * connection, or if the client was already up-to-date.
+ * @since 4.1
+ */
+ public PackStatistics getStatistics() {
return statistics;
}
@@ -684,6 +735,8 @@
else
multiAck = MultiAck.OFF;
+ if (!clientShallowCommits.isEmpty())
+ verifyClientShallow();
if (depth != 0)
processShallow();
if (!clientShallowCommits.isEmpty())
@@ -769,6 +822,35 @@
pckOut.end();
}
+ private void verifyClientShallow()
+ throws IOException, PackProtocolException {
+ AsyncRevObjectQueue q = walk.parseAny(clientShallowCommits, true);
+ try {
+ for (;;) {
+ try {
+ // Shallow objects named by the client must be commits.
+ RevObject o = q.next();
+ if (o == null) {
+ break;
+ }
+ if (!(o instanceof RevCommit)) {
+ throw new PackProtocolException(
+ MessageFormat.format(
+ JGitText.get().invalidShallowObject,
+ o.name()));
+ }
+ } catch (MissingObjectException notCommit) {
+ // shallow objects not known at the server are ignored
+ // by git-core upload-pack, match that behavior.
+ clientShallowCommits.remove(notCommit.getObjectId());
+ continue;
+ }
+ }
+ } finally {
+ q.release();
+ }
+ }
+
/**
* Generate an advertisement of available refs and capabilities.
*
@@ -808,6 +890,10 @@
|| policy == RequestPolicy.REACHABLE_COMMIT_TIP
|| policy == null)
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
+ if (policy == RequestPolicy.REACHABLE_COMMIT
+ || policy == RequestPolicy.REACHABLE_COMMIT_TIP
+ || policy == null)
+ adv.advertiseCapability(OPTION_ALLOW_REACHABLE_SHA1_IN_WANT);
adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
adv.setDerefTags(true);
Map<String, Ref> advertisedOrDefaultRefs = getAdvertisedOrDefaultRefs();
@@ -1389,6 +1475,7 @@
pw.setIndexDisabled(true);
pw.setUseCachedPacks(true);
pw.setUseBitmaps(depth == 0 && clientShallowCommits.isEmpty());
+ pw.setClientShallowCommits(clientShallowCommits);
pw.setReuseDeltaCommits(true);
pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
pw.setThin(options.contains(OPTION_THIN_PACK));
@@ -1458,8 +1545,10 @@
} finally {
statistics = pw.getStatistics();
- if (statistics != null)
- logger.onPackStatistics(statistics);
+ if (statistics != null) {
+ postUploadHook.onPostUpload(statistics);
+ logger.onPackStatistics(new PackWriter.Statistics(statistics));
+ }
pw.close();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
index 99fa6e0..85ebecc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLogger.java
@@ -52,7 +52,10 @@
* thread to a particular connection, if they need to also include connection
* information. One method is to use a {@link java.lang.ThreadLocal} to remember
* the connection information before invoking UploadPack.
+ *
+ * @deprecated use {@link PostUploadHook} instead
*/
+@Deprecated
public interface UploadPackLogger {
/** A simple no-op logger. */
public static final UploadPackLogger NULL = new UploadPackLogger() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
index 3f14cc6..4ea0319 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPackLoggerChain.java
@@ -48,10 +48,13 @@
import org.eclipse.jgit.internal.storage.pack.PackWriter;
/**
- * {@link UploadPackLogger} that delegates to a list of other loggers.
+ * UploadPackLogger that delegates to a list of other loggers.
* <p>
* loggers are run in the order passed to the constructor.
+ *
+ * @deprecated Use {@link PostUploadHookChain} instead.
*/
+@Deprecated
public class UploadPackLoggerChain implements UploadPackLogger {
private final UploadPackLogger[] loggers;
private final int count;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java
new file mode 100644
index 0000000..267bf7a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WriteAbortedException.java
@@ -0,0 +1,85 @@
+/*
+ * 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 java.io.IOException;
+
+/**
+ * An exception to be thrown when the write operation is aborted.
+ * <p>
+ * That can be thrown inside
+ * {@link ObjectCountCallback#setObjectCount(long)}.
+ *
+ * @since 4.1
+ */
+public class WriteAbortedException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a {@code WriteAbortedException}.
+ */
+ public WriteAbortedException() {
+ }
+
+ /**
+ * Construct a {@code WriteAbortedException}.
+ *
+ * @param s message describing the issue
+ */
+ public WriteAbortedException(String s) {
+ super(s);
+ }
+
+ /**
+ * Construct a {@code WriteAbortedException}.
+ *
+ * @param s
+ * message describing the issue
+ * @param why
+ * a lower level implementation specific issue.
+ */
+ public WriteAbortedException(String s, Throwable why) {
+ super(s, why);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
index a2c6edc..57a6192 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotAuthorizedException.java
@@ -45,12 +45,35 @@
import org.eclipse.jgit.internal.JGitText;
-/** Indicates the request service is not authorized for current user. */
+/**
+ * Indicates that the requested service requires authentication that
+ * the current user has not provided.
+ * <p>
+ * This corresponds to response code
+ * {@code HttpServletResponse.SC_UNAUTHORIZED}.
+ */
public class ServiceNotAuthorizedException extends Exception {
private static final long serialVersionUID = 1L;
- /** Indicates the request service is not available. */
+ /**
+ * @param message
+ * @param cause
+ * @since 4.1
+ */
+ public ServiceNotAuthorizedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
+ * @since 4.1
+ */
+ public ServiceNotAuthorizedException(String message) {
+ super(message);
+ }
+
+ /** Indicates that the requested service requires authentication. */
public ServiceNotAuthorizedException() {
- super(JGitText.get().serviceNotPermittedNoName);
+ super(JGitText.get().unauthorized);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
index d0fa758..78ae303 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/ServiceNotEnabledException.java
@@ -49,6 +49,23 @@
public class ServiceNotEnabledException extends Exception {
private static final long serialVersionUID = 1L;
+ /**
+ * @param message
+ * @param cause
+ * @since 4.1
+ */
+ public ServiceNotEnabledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
+ * @since 4.1
+ */
+ public ServiceNotEnabledException(String message) {
+ super(message);
+ }
+
/** Indicates the request service is not available. */
public ServiceNotEnabledException() {
super(JGitText.get().serviceNotEnabledNoName);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index d7c93d1..73ab04f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -596,7 +596,7 @@
* a relevant ignore rule file exists but cannot be read.
*/
protected boolean isEntryIgnored(final int pLen) throws IOException {
- return isEntryIgnored(pLen, false);
+ return isEntryIgnored(pLen, mode, false);
}
/**
@@ -605,13 +605,16 @@
*
* @param pLen
* the length of the path in the path buffer.
+ * @param fileMode
+ * the original iterator file mode
* @param negatePrevious
* true if the previous matching iterator rule was negation
* @return true if the entry is ignored by an ignore rule.
* @throws IOException
* a relevant ignore rule file exists but cannot be read.
*/
- private boolean isEntryIgnored(final int pLen, boolean negatePrevious)
+ private boolean isEntryIgnored(final int pLen, int fileMode,
+ boolean negatePrevious)
throws IOException {
IgnoreNode rules = getIgnoreNode();
if (rules != null) {
@@ -623,7 +626,7 @@
if (0 < pOff)
pOff--;
String p = TreeWalk.pathOf(path, pOff, pLen);
- switch (rules.isIgnored(p, FileMode.TREE.equals(mode),
+ switch (rules.isIgnored(p, FileMode.TREE.equals(fileMode),
negatePrevious)) {
case IGNORED:
return true;
@@ -638,7 +641,7 @@
}
}
if (parent instanceof WorkingTreeIterator)
- return ((WorkingTreeIterator) parent).isEntryIgnored(pLen,
+ return ((WorkingTreeIterator) parent).isEntryIgnored(pLen, fileMode,
negatePrevious);
return false;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 12dfe96..e5219b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -67,7 +67,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jgit.api.errors.JGitInternalException;
-import org.eclipse.jgit.errors.SymlinksNotSupportedException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -248,7 +247,7 @@
* @since 3.0
*/
public long lastModified(File f) throws IOException {
- return f.lastModified();
+ return FileUtils.lastModified(f);
}
/**
@@ -261,7 +260,7 @@
* @since 3.0
*/
public void setLastModified(File f, long time) throws IOException {
- f.setLastModified(time);
+ FileUtils.setLastModified(f, time);
}
/**
@@ -274,7 +273,7 @@
* @since 3.0
*/
public long length(File path) throws IOException {
- return path.length();
+ return FileUtils.getLength(path);
}
/**
@@ -286,9 +285,7 @@
* @since 3.3
*/
public void delete(File f) throws IOException {
- if (!f.delete())
- throw new IOException(MessageFormat.format(
- JGitText.get().deleteFileFailed, f.getAbsolutePath()));
+ FileUtils.delete(f);
}
/**
@@ -623,8 +620,7 @@
* @since 3.0
*/
public String readSymLink(File path) throws IOException {
- throw new SymlinksNotSupportedException(
- JGitText.get().errorSymlinksNotSupported);
+ return FileUtils.readSymLink(path);
}
/**
@@ -634,7 +630,7 @@
* @since 3.0
*/
public boolean isSymLink(File path) throws IOException {
- return false;
+ return FileUtils.isSymlink(path);
}
/**
@@ -646,7 +642,7 @@
* @since 3.0
*/
public boolean exists(File path) {
- return path.exists();
+ return FileUtils.exists(path);
}
/**
@@ -658,7 +654,7 @@
* @since 3.0
*/
public boolean isDirectory(File path) {
- return path.isDirectory();
+ return FileUtils.isDirectory(path);
}
/**
@@ -670,7 +666,7 @@
* @since 3.0
*/
public boolean isFile(File path) {
- return path.isFile();
+ return FileUtils.isFile(path);
}
/**
@@ -681,7 +677,7 @@
* @since 3.0
*/
public boolean isHidden(File path) throws IOException {
- return path.isHidden();
+ return FileUtils.isHidden(path);
}
/**
@@ -693,9 +689,7 @@
* @since 3.0
*/
public void setHidden(File path, boolean hidden) throws IOException {
- if (!path.getName().startsWith(".")) //$NON-NLS-1$
- throw new IllegalArgumentException(
- JGitText.get().hiddenFilesStartWithDot);
+ FileUtils.setHidden(path, hidden);
}
/**
@@ -707,8 +701,7 @@
* @since 3.0
*/
public void createSymLink(File path, String target) throws IOException {
- throw new SymlinksNotSupportedException(
- JGitText.get().errorSymlinksNotSupported);
+ FileUtils.createSymLink(path, target);
}
/**
@@ -866,7 +859,10 @@
* @since 4.0
*/
public File findHook(Repository repository, final String hookName) {
- final File hookFile = new File(new File(repository.getDirectory(),
+ File gitDir = repository.getDirectory();
+ if (gitDir == null)
+ return null;
+ final File hookFile = new File(new File(gitDir,
Constants.HOOKS), hookName);
return hookFile.isFile() ? hookFile : null;
}
@@ -1067,28 +1063,28 @@
return lastModifiedTime;
}
- private boolean isDirectory;
+ private final boolean isDirectory;
- private boolean isSymbolicLink;
+ private final boolean isSymbolicLink;
- private boolean isRegularFile;
+ private final boolean isRegularFile;
- private long creationTime;
+ private final long creationTime;
- private long lastModifiedTime;
+ private final long lastModifiedTime;
- private boolean isExecutable;
+ private final boolean isExecutable;
- private File file;
+ private final File file;
- private boolean exists;
+ private final boolean exists;
/**
* file length
*/
protected long length = -1;
- FS fs;
+ final FS fs;
Attributes(FS fs, File file, boolean exists, boolean isDirectory,
boolean isExecutable, boolean isSymbolicLink,
@@ -1107,14 +1103,14 @@
}
/**
- * Constructor when there are issues with reading
+ * Constructor when there are issues with reading. All attributes except
+ * given will be set to the default values.
*
* @param fs
* @param path
*/
public Attributes(File path, FS fs) {
- this.file = path;
- this.fs = fs;
+ this(fs, path, false, false, false, false, false, 0L, 0L, 0L);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index b07f859..779b10e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -168,7 +168,7 @@
@Override
public boolean canExecute(File f) {
- return FileUtil.canExecute(f);
+ return FileUtils.canExecute(f);
}
@Override
@@ -246,71 +246,16 @@
}
@Override
- public boolean isSymLink(File path) throws IOException {
- return FileUtil.isSymlink(path);
- }
-
- @Override
- public long lastModified(File path) throws IOException {
- return FileUtil.lastModified(path);
- }
-
- @Override
- public void setLastModified(File path, long time) throws IOException {
- FileUtil.setLastModified(path, time);
- }
-
- @Override
- public void delete(File path) throws IOException {
- FileUtil.delete(path);
- }
-
- @Override
- public long length(File f) throws IOException {
- return FileUtil.getLength(f);
- }
-
- @Override
- public boolean exists(File path) {
- return FileUtil.exists(path);
- }
-
- @Override
- public boolean isDirectory(File path) {
- return FileUtil.isDirectory(path);
- }
-
- @Override
- public boolean isFile(File path) {
- return FileUtil.isFile(path);
- }
-
- @Override
- public boolean isHidden(File path) throws IOException {
- return FileUtil.isHidden(path);
- }
-
- @Override
public void setHidden(File path, boolean hidden) throws IOException {
// no action on POSIX
}
- @Override
- public String readSymLink(File path) throws IOException {
- return FileUtil.readSymlink(path);
- }
-
- @Override
- public void createSymLink(File path, String target) throws IOException {
- FileUtil.createSymLink(path, target);
- }
-
/**
* @since 3.3
*/
@Override
public Attributes getAttributes(File path) {
- return FileUtil.getFileAttributesPosix(this, path);
+ return FileUtils.getFileAttributesPosix(this, path);
}
/**
@@ -318,7 +263,7 @@
*/
@Override
public File normalize(File file) {
- return FileUtil.normalize(file);
+ return FileUtils.normalize(file);
}
/**
@@ -326,7 +271,7 @@
*/
@Override
public String normalize(String name) {
- return FileUtil.normalize(name);
+ return FileUtils.normalize(name);
}
/**
@@ -335,6 +280,9 @@
@Override
public File findHook(Repository repository, String hookName) {
final File gitdir = repository.getDirectory();
+ if (gitdir == null) {
+ return null;
+ }
final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
.resolve(hookName);
if (Files.isExecutable(hookPath))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index 5c652be..f0a2e72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -168,7 +168,7 @@
try {
tempFile = File.createTempFile("tempsymlinktarget", ""); //$NON-NLS-1$ //$NON-NLS-2$
File linkName = new File(tempFile.getParentFile(), "tempsymlink"); //$NON-NLS-1$
- FileUtil.createSymLink(linkName, tempFile.getPath());
+ createSymLink(linkName, tempFile.getPath());
supportSymlinks = Boolean.TRUE;
linkName.delete();
} catch (IOException | UnsupportedOperationException e) {
@@ -183,71 +183,11 @@
}
}
- @Override
- public boolean isSymLink(File path) throws IOException {
- return FileUtil.isSymlink(path);
- }
-
- @Override
- public long lastModified(File path) throws IOException {
- return FileUtil.lastModified(path);
- }
-
- @Override
- public void setLastModified(File path, long time) throws IOException {
- FileUtil.setLastModified(path, time);
- }
-
- @Override
- public void delete(File path) throws IOException {
- FileUtil.delete(path);
- }
-
- @Override
- public long length(File f) throws IOException {
- return FileUtil.getLength(f);
- }
-
- @Override
- public boolean exists(File path) {
- return FileUtil.exists(path);
- }
-
- @Override
- public boolean isDirectory(File path) {
- return FileUtil.isDirectory(path);
- }
-
- @Override
- public boolean isFile(File path) {
- return FileUtil.isFile(path);
- }
-
- @Override
- public boolean isHidden(File path) throws IOException {
- return FileUtil.isHidden(path);
- }
-
- @Override
- public void setHidden(File path, boolean hidden) throws IOException {
- FileUtil.setHidden(path, hidden);
- }
-
- @Override
- public String readSymLink(File path) throws IOException {
- return FileUtil.readSymlink(path);
- }
-
- @Override
- public void createSymLink(File path, String target) throws IOException {
- FileUtil.createSymLink(path, target);
- }
-
/**
* @since 3.3
*/
@Override
public Attributes getAttributes(File path) {
- return FileUtil.getFileAttributesBasic(this, path);
+ return FileUtils.getFileAttributesBasic(this, path);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
index 3c3b2eb..2450be4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -44,7 +44,6 @@
package org.eclipse.jgit.util;
import java.io.File;
-import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -168,74 +167,6 @@
return true;
}
- @Override
- public boolean isSymLink(File path) throws IOException {
- return FileUtil.isSymlink(path);
- }
-
- @Override
- public long lastModified(File path) throws IOException {
- return FileUtil.lastModified(path);
- }
-
- @Override
- public void setLastModified(File path, long time) throws IOException {
- FileUtil.setLastModified(path, time);
- }
-
- @Override
- public void delete(File path) throws IOException {
- FileUtil.delete(path);
- }
-
- @Override
- public long length(File f) throws IOException {
- return FileUtil.getLength(f);
- }
-
- @Override
- public boolean exists(File path) {
- return FileUtil.exists(path);
- }
-
- @Override
- public boolean isDirectory(File path) {
- return FileUtil.isDirectory(path);
- }
-
- @Override
- public boolean isFile(File path) {
- return FileUtil.isFile(path);
- }
-
- @Override
- public boolean isHidden(File path) throws IOException {
- return FileUtil.isHidden(path);
- }
-
- @Override
- public void setHidden(File path, boolean hidden) throws IOException {
- FileUtil.setHidden(path, hidden);
- }
-
- @Override
- public String readSymLink(File path) throws IOException {
- return FileUtil.readSymlink(path);
- }
-
- @Override
- public void createSymLink(File path, String target) throws IOException {
- FileUtil.createSymLink(path, target);
- }
-
- /**
- * @since 3.3
- */
- @Override
- public Attributes getAttributes(File path) {
- return FileUtil.getFileAttributesBasic(this, path);
- }
-
/**
* @since 3.7
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
index f5babed..b87b9a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtil.java
@@ -46,51 +46,24 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributeView;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.PosixFileAttributeView;
-import java.nio.file.attribute.PosixFileAttributes;
-import java.nio.file.attribute.PosixFilePermission;
-import java.text.Normalizer;
-import java.text.Normalizer.Form;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.FS.Attributes;
/**
* File utilities using Java 7 NIO2
*/
+@Deprecated
public class FileUtil {
- static class Java7BasicAttributes extends Attributes {
-
- Java7BasicAttributes(FS fs, File fPath, boolean exists,
- boolean isDirectory, boolean isExecutable,
- boolean isSymbolicLink, boolean isRegularFile,
- long creationTime, long lastModifiedTime, long length) {
- super(fs, fPath, exists, isDirectory, isExecutable, isSymbolicLink,
- isRegularFile, creationTime, lastModifiedTime, length);
- }
- }
-
/**
* @param path
* @return target path of the symlink
* @throws IOException
+ * @deprecated use {@link FileUtils#readSymLink(File)} instead
*/
+ @Deprecated
public static String readSymlink(File path) throws IOException {
- Path nioPath = path.toPath();
- Path target = Files.readSymbolicLink(nioPath);
- String targetString = target.toString();
- if (SystemReader.getInstance().isWindows())
- targetString = targetString.replace('\\', '/');
- else if (SystemReader.getInstance().isMacOS())
- targetString = Normalizer.normalize(targetString, Form.NFC);
- return targetString;
+ return FileUtils.readSymLink(path);
}
/**
@@ -99,218 +72,168 @@
* @param target
* target of the symlink to be created
* @throws IOException
+ * @deprecated use {@link FileUtils#createSymLink(File, String)} instead
*/
+ @Deprecated
public static void createSymLink(File path, String target)
throws IOException {
- Path nioPath = path.toPath();
- if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS))
- Files.delete(nioPath);
- if (SystemReader.getInstance().isWindows())
- target = target.replace('/', '\\');
- Path nioTarget = new File(target).toPath();
- Files.createSymbolicLink(nioPath, nioTarget);
+ FileUtils.createSymLink(path, target);
}
/**
* @param path
* @return {@code true} if the passed path is a symlink
+ * @deprecated Use {@link Files#isSymbolicLink(java.nio.file.Path)} instead
*/
+ @Deprecated
public static boolean isSymlink(File path) {
- Path nioPath = path.toPath();
- return Files.isSymbolicLink(nioPath);
+ return FileUtils.isSymlink(path);
}
/**
* @param path
* @return lastModified attribute for given path
* @throws IOException
+ * @deprecated Use
+ * {@link Files#getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...)}
+ * instead
*/
+ @Deprecated
public static long lastModified(File path) throws IOException {
- Path nioPath = path.toPath();
- return Files.getLastModifiedTime(nioPath, LinkOption.NOFOLLOW_LINKS)
- .toMillis();
+ return FileUtils.lastModified(path);
}
/**
* @param path
* @param time
* @throws IOException
+ * @deprecated Use
+ * {@link Files#setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime)}
+ * instead
*/
+ @Deprecated
public static void setLastModified(File path, long time) throws IOException {
- Path nioPath = path.toPath();
- Files.setLastModifiedTime(nioPath, FileTime.fromMillis(time));
+ FileUtils.setLastModified(path, time);
}
/**
* @param path
* @return {@code true} if the given path exists
+ * @deprecated Use
+ * {@link Files#exists(java.nio.file.Path, java.nio.file.LinkOption...)}
+ * instead
*/
+ @Deprecated
public static boolean exists(File path) {
- Path nioPath = path.toPath();
- return Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS);
+ return FileUtils.exists(path);
}
/**
* @param path
* @return {@code true} if the given path is hidden
* @throws IOException
+ * @deprecated Use {@link Files#isHidden(java.nio.file.Path)} instead
*/
+ @Deprecated
public static boolean isHidden(File path) throws IOException {
- Path nioPath = path.toPath();
- return Files.isHidden(nioPath);
+ return FileUtils.isHidden(path);
}
/**
* @param path
* @param hidden
* @throws IOException
+ * @deprecated Use {@link FileUtils#setHidden(File,boolean)} instead
*/
+ @Deprecated
public static void setHidden(File path, boolean hidden) throws IOException {
- Path nioPath = path.toPath();
- Files.setAttribute(nioPath, "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
- LinkOption.NOFOLLOW_LINKS);
+ FileUtils.setHidden(path, hidden);
}
/**
* @param path
* @return length of the given file
* @throws IOException
+ * @deprecated Use {@link FileUtils#getLength(File)} instead
*/
+ @Deprecated
public static long getLength(File path) throws IOException {
- Path nioPath = path.toPath();
- if (Files.isSymbolicLink(nioPath))
- return Files.readSymbolicLink(nioPath).toString()
- .getBytes(Constants.CHARSET).length;
- return Files.size(nioPath);
+ return FileUtils.getLength(path);
}
/**
* @param path
* @return {@code true} if the given file a directory
+ * @deprecated Use
+ * {@link Files#isDirectory(java.nio.file.Path, java.nio.file.LinkOption...)}
+ * instead
*/
+ @Deprecated
public static boolean isDirectory(File path) {
- Path nioPath = path.toPath();
- return Files.isDirectory(nioPath, LinkOption.NOFOLLOW_LINKS);
+ return FileUtils.isDirectory(path);
}
/**
* @param path
* @return {@code true} if the given file is a file
+ * @deprecated Use
+ * {@link Files#isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...)}
+ * instead
*/
+ @Deprecated
public static boolean isFile(File path) {
- Path nioPath = path.toPath();
- return Files.isRegularFile(nioPath, LinkOption.NOFOLLOW_LINKS);
+ return FileUtils.isFile(path);
}
/**
* @param path
* @return {@code true} if the given file can be executed
+ * @deprecated Use {@link FileUtils#canExecute(File)} instead
*/
+ @Deprecated
public static boolean canExecute(File path) {
- if (!isFile(path))
- return false;
- return path.canExecute();
+ return FileUtils.canExecute(path);
}
/**
* @param path
* @throws IOException
+ * @deprecated use {@link FileUtils#delete(File)}
*/
+ @Deprecated
public static void delete(File path) throws IOException {
- Path nioPath = path.toPath();
- Files.delete(nioPath);
- }
-
- static Attributes getFileAttributesBasic(FS fs, File path) {
- try {
- Path nioPath = path.toPath();
- BasicFileAttributes readAttributes = nioPath
- .getFileSystem()
- .provider()
- .getFileAttributeView(nioPath,
- BasicFileAttributeView.class,
- LinkOption.NOFOLLOW_LINKS).readAttributes();
- Attributes attributes = new FileUtil.Java7BasicAttributes(fs, path,
- true,
- readAttributes.isDirectory(),
- fs.supportsExecute() ? path.canExecute() : false,
- readAttributes.isSymbolicLink(),
- readAttributes.isRegularFile(), //
- readAttributes.creationTime().toMillis(), //
- readAttributes.lastModifiedTime().toMillis(),
- readAttributes.isSymbolicLink() ? Constants
- .encode(FileUtils.readSymLink(path)).length
- : readAttributes.size());
- return attributes;
- } catch (NoSuchFileException e) {
- return new FileUtil.Java7BasicAttributes(fs, path, false, false,
- false, false, false, 0L, 0L, 0L);
- } catch (IOException e) {
- return new Attributes(path, fs);
- }
+ FileUtils.delete(path);
}
/**
* @param fs
* @param path
* @return file system attributes for the given file
+ * @deprecated Use {@link FileUtils#getFileAttributesPosix(FS,File)} instead
*/
+ @Deprecated
public static Attributes getFileAttributesPosix(FS fs, File path) {
- try {
- Path nioPath = path.toPath();
- PosixFileAttributes readAttributes = nioPath
- .getFileSystem()
- .provider()
- .getFileAttributeView(nioPath,
- PosixFileAttributeView.class,
- LinkOption.NOFOLLOW_LINKS).readAttributes();
- Attributes attributes = new FileUtil.Java7BasicAttributes(
- fs,
- path,
- true, //
- readAttributes.isDirectory(), //
- readAttributes.permissions().contains(
- PosixFilePermission.OWNER_EXECUTE),
- readAttributes.isSymbolicLink(),
- readAttributes.isRegularFile(), //
- readAttributes.creationTime().toMillis(), //
- readAttributes.lastModifiedTime().toMillis(),
- readAttributes.size());
- return attributes;
- } catch (NoSuchFileException e) {
- return new FileUtil.Java7BasicAttributes(fs, path, false, false,
- false, false, false, 0L, 0L, 0L);
- } catch (IOException e) {
- return new Attributes(path, fs);
- }
+ return FileUtils.getFileAttributesPosix(fs, path);
}
/**
* @param file
* @return on Mac: NFC normalized {@link File}, otherwise the passed file
+ * @deprecated Use {@link FileUtils#normalize(File)} instead
*/
+ @Deprecated
public static File normalize(File file) {
- if (SystemReader.getInstance().isMacOS()) {
- // TODO: Would it be faster to check with isNormalized first
- // assuming normalized paths are much more common
- String normalized = Normalizer.normalize(file.getPath(),
- Normalizer.Form.NFC);
- return new File(normalized);
- }
- return file;
+ return FileUtils.normalize(file);
}
/**
* @param name
* @return on Mac: NFC normalized form of given name
+ * @deprecated Use {@link FileUtils#normalize(String)} instead
*/
+ @Deprecated
public static String normalize(String name) {
- if (SystemReader.getInstance().isMacOS()) {
- if (name == null)
- return null;
- return Normalizer.normalize(name, Normalizer.Form.NFC);
- }
- return name;
+ return FileUtils.normalize(name);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 1e58245..548d239 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -48,12 +48,28 @@
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileLock;
+import java.nio.file.AtomicMoveNotSupportedException;
+import java.nio.file.CopyOption;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
import java.text.MessageFormat;
+import java.text.Normalizer;
+import java.text.Normalizer.Form;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.FS.Attributes;
/**
* File Utilities
@@ -207,30 +223,68 @@
*/
public static void rename(final File src, final File dst)
throws IOException {
+ rename(src, dst, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ /**
+ * Rename a file or folder using the passed {@link CopyOption}s. If the
+ * rename fails and if we are running on a filesystem where it makes sense
+ * to repeat a failing rename then repeat the rename operation up to 9 times
+ * with 100ms sleep time between two calls. Furthermore if the destination
+ * exists and is a directory hierarchy with only directories in it, the
+ * whole directory hierarchy will be deleted. If the target represents a
+ * non-empty directory structure, empty subdirectories within that structure
+ * may or may not be deleted even if the method fails. Furthermore if the
+ * destination exists and is a file then the file will be replaced if
+ * {@link StandardCopyOption#REPLACE_EXISTING} has been set. If
+ * {@link StandardCopyOption#ATOMIC_MOVE} has been set the rename will be
+ * done atomically or fail with an {@link AtomicMoveNotSupportedException}
+ *
+ * @param src
+ * the old file
+ * @param dst
+ * the new file
+ * @param options
+ * options to pass to
+ * {@link Files#move(java.nio.file.Path, java.nio.file.Path, CopyOption...)}
+ * @throws AtomicMoveNotSupportedException
+ * if file cannot be moved as an atomic file system operation
+ * @throws IOException
+ * @since 4.1
+ */
+ public static void rename(final File src, final File dst,
+ CopyOption... options)
+ throws AtomicMoveNotSupportedException, IOException {
int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
while (--attempts >= 0) {
- if (src.renameTo(dst))
- return;
try {
- if (!dst.delete())
- delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
- // On *nix there is no try, you do or do not
- if (src.renameTo(dst))
- return;
+ Files.move(src.toPath(), dst.toPath(), options);
+ return;
+ } catch (AtomicMoveNotSupportedException e) {
+ throw e;
} catch (IOException e) {
- // ignore and continue retry
+ try {
+ if (!dst.delete()) {
+ delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
+ }
+ // On *nix there is no try, you do or do not
+ Files.move(src.toPath(), dst.toPath(), options);
+ return;
+ } catch (IOException e2) {
+ // ignore and continue retry
+ }
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
- throw new IOException(MessageFormat.format(
- JGitText.get().renameFileFailed, src.getAbsolutePath(),
- dst.getAbsolutePath()));
+ throw new IOException(
+ MessageFormat.format(JGitText.get().renameFileFailed,
+ src.getAbsolutePath(), dst.getAbsolutePath()));
}
}
- throw new IOException(MessageFormat.format(
- JGitText.get().renameFileFailed, src.getAbsolutePath(),
- dst.getAbsolutePath()));
+ throw new IOException(
+ MessageFormat.format(JGitText.get().renameFileFailed,
+ src.getAbsolutePath(), dst.getAbsolutePath()));
}
/**
@@ -350,18 +404,33 @@
*/
public static void createSymLink(File path, String target)
throws IOException {
- FS.DETECTED.createSymLink(path, target);
+ Path nioPath = path.toPath();
+ if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
+ Files.delete(nioPath);
+ }
+ if (SystemReader.getInstance().isWindows()) {
+ target = target.replace('/', '\\');
+ }
+ Path nioTarget = new File(target).toPath();
+ Files.createSymbolicLink(nioPath, nioTarget);
}
/**
* @param path
- * @return the target of the symbolic link, or null if it is not a symbolic
- * link
+ * @return target path of the symlink, or null if it is not a symbolic link
* @throws IOException
* @since 3.0
*/
public static String readSymLink(File path) throws IOException {
- return FS.DETECTED.readSymLink(path);
+ Path nioPath = path.toPath();
+ Path target = Files.readSymbolicLink(nioPath);
+ String targetString = target.toString();
+ if (SystemReader.getInstance().isWindows()) {
+ targetString = targetString.replace('\\', '/');
+ } else if (SystemReader.getInstance().isMacOS()) {
+ targetString = Normalizer.normalize(targetString, Form.NFC);
+ }
+ return targetString;
}
/**
@@ -453,4 +522,212 @@
}
return builder.toString();
}
+
+ /**
+ * Determine if an IOException is a Stale NFS File Handle
+ *
+ * @param ioe
+ * @return a boolean true if the IOException is a Stale NFS FIle Handle
+ * @since 4.1
+ */
+ public static boolean isStaleFileHandle(IOException ioe) {
+ String msg = ioe.getMessage();
+ return msg != null
+ && msg.toLowerCase().matches("stale .*file .*handle"); //$NON-NLS-1$
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the passed file is a symbolic link
+ */
+ static boolean isSymlink(File file) {
+ return Files.isSymbolicLink(file.toPath());
+ }
+
+ /**
+ * @param file
+ * @return lastModified attribute for given file, not following symbolic
+ * links
+ * @throws IOException
+ */
+ static long lastModified(File file) throws IOException {
+ return Files.getLastModifiedTime(file.toPath(), LinkOption.NOFOLLOW_LINKS)
+ .toMillis();
+ }
+
+ /**
+ * @param file
+ * @param time
+ * @throws IOException
+ */
+ static void setLastModified(File file, long time) throws IOException {
+ Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(time));
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the given file exists, not following symbolic
+ * links
+ */
+ static boolean exists(File file) {
+ return Files.exists(file.toPath(), LinkOption.NOFOLLOW_LINKS);
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the given file is hidden
+ * @throws IOException
+ */
+ static boolean isHidden(File file) throws IOException {
+ return Files.isHidden(file.toPath());
+ }
+
+ /**
+ * @param file
+ * @param hidden
+ * @throws IOException
+ * @since 4.1
+ */
+ public static void setHidden(File file, boolean hidden) throws IOException {
+ Files.setAttribute(file.toPath(), "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
+ LinkOption.NOFOLLOW_LINKS);
+ }
+
+ /**
+ * @param file
+ * @return length of the given file
+ * @throws IOException
+ * @since 4.1
+ */
+ public static long getLength(File file) throws IOException {
+ Path nioPath = file.toPath();
+ if (Files.isSymbolicLink(nioPath))
+ return Files.readSymbolicLink(nioPath).toString()
+ .getBytes(Constants.CHARSET).length;
+ return Files.size(nioPath);
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the given file is a directory, not following
+ * symbolic links
+ */
+ static boolean isDirectory(File file) {
+ return Files.isDirectory(file.toPath(), LinkOption.NOFOLLOW_LINKS);
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the given file is a file, not following symbolic
+ * links
+ */
+ static boolean isFile(File file) {
+ return Files.isRegularFile(file.toPath(), LinkOption.NOFOLLOW_LINKS);
+ }
+
+ /**
+ * @param file
+ * @return {@code true} if the given file can be executed
+ * @since 4.1
+ */
+ public static boolean canExecute(File file) {
+ if (!isFile(file)) {
+ return false;
+ }
+ return Files.isExecutable(file.toPath());
+ }
+
+ /**
+ * @param fs
+ * @param file
+ * @return non null attributes object
+ */
+ static Attributes getFileAttributesBasic(FS fs, File file) {
+ try {
+ Path nioPath = file.toPath();
+ BasicFileAttributes readAttributes = nioPath
+ .getFileSystem()
+ .provider()
+ .getFileAttributeView(nioPath,
+ BasicFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS).readAttributes();
+ Attributes attributes = new Attributes(fs, file,
+ true,
+ readAttributes.isDirectory(),
+ fs.supportsExecute() ? file.canExecute() : false,
+ readAttributes.isSymbolicLink(),
+ readAttributes.isRegularFile(), //
+ readAttributes.creationTime().toMillis(), //
+ readAttributes.lastModifiedTime().toMillis(),
+ readAttributes.isSymbolicLink() ? Constants
+ .encode(readSymLink(file)).length
+ : readAttributes.size());
+ return attributes;
+ } catch (IOException e) {
+ return new Attributes(file, fs);
+ }
+ }
+
+ /**
+ * @param fs
+ * @param file
+ * @return file system attributes for the given file
+ * @since 4.1
+ */
+ public static Attributes getFileAttributesPosix(FS fs, File file) {
+ try {
+ Path nioPath = file.toPath();
+ PosixFileAttributes readAttributes = nioPath
+ .getFileSystem()
+ .provider()
+ .getFileAttributeView(nioPath,
+ PosixFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS).readAttributes();
+ Attributes attributes = new Attributes(
+ fs,
+ file,
+ true, //
+ readAttributes.isDirectory(), //
+ readAttributes.permissions().contains(
+ PosixFilePermission.OWNER_EXECUTE),
+ readAttributes.isSymbolicLink(),
+ readAttributes.isRegularFile(), //
+ readAttributes.creationTime().toMillis(), //
+ readAttributes.lastModifiedTime().toMillis(),
+ readAttributes.size());
+ return attributes;
+ } catch (IOException e) {
+ return new Attributes(file, fs);
+ }
+ }
+
+ /**
+ * @param file
+ * @return on Mac: NFC normalized {@link File}, otherwise the passed file
+ * @since 4.1
+ */
+ public static File normalize(File file) {
+ if (SystemReader.getInstance().isMacOS()) {
+ // TODO: Would it be faster to check with isNormalized first
+ // assuming normalized paths are much more common
+ String normalized = Normalizer.normalize(file.getPath(),
+ Normalizer.Form.NFC);
+ return new File(normalized);
+ }
+ return file;
+ }
+
+ /**
+ * @param name
+ * @return on Mac: NFC normalized form of given name
+ * @since 4.1
+ */
+ public static String normalize(String name) {
+ if (SystemReader.getInstance().isMacOS()) {
+ if (name == null)
+ return null;
+ return Normalizer.normalize(name, Normalizer.Form.NFC);
+ }
+ return name;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
index c817c47..0d283fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
@@ -51,6 +51,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.text.MessageFormat;
@@ -371,6 +372,75 @@
return l;
}
+ /**
+ * Read the next line from a reader.
+ * <p>
+ * Like {@link java.io.BufferedReader#readLine()}, but only treats
+ * {@code \n} as end-of-line, and includes the trailing newline.
+ *
+ * @param in
+ * the reader to read from.
+ * @param sizeHint
+ * hint for buffer sizing; 0 or negative for default.
+ * @return the next line from the input, always ending in {@code \n} unless
+ * EOF was reached.
+ * @throws IOException
+ * there was an error reading from the stream.
+ * @since 4.1
+ */
+ public static String readLine(Reader in, int sizeHint) throws IOException {
+ if (in.markSupported()) {
+ if (sizeHint <= 0) {
+ sizeHint = 1024;
+ }
+ StringBuilder sb = new StringBuilder(sizeHint);
+ char[] buf = new char[sizeHint];
+ while (true) {
+ in.mark(sizeHint);
+ int n = in.read(buf);
+ if (n < 0) {
+ in.reset();
+ return sb.toString();
+ }
+ for (int i = 0; i < n; i++) {
+ if (buf[i] == '\n') {
+ resetAndSkipFully(in, ++i);
+ sb.append(buf, 0, i);
+ return sb.toString();
+ }
+ }
+ if (n > 0) {
+ sb.append(buf, 0, n);
+ }
+ resetAndSkipFully(in, n);
+ }
+ } else {
+ StringBuilder buf = sizeHint > 0
+ ? new StringBuilder(sizeHint)
+ : new StringBuilder();
+ int i;
+ while ((i = in.read()) != -1) {
+ char c = (char) i;
+ buf.append(c);
+ if (c == '\n') {
+ break;
+ }
+ }
+ return buf.toString();
+ }
+ }
+
+ private static void resetAndSkipFully(Reader fd, long toSkip) throws IOException {
+ fd.reset();
+ while (toSkip > 0) {
+ long r = fd.skip(toSkip);
+ if (r <= 0) {
+ throw new EOFException(JGitText.get().shortSkipOfBlock);
+ }
+ toSkip -= r;
+ }
+ }
+
private IO() {
// Don't create instances of a static only utility.
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index 3c2460c..45c339f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -390,7 +390,28 @@
* @return the timez