Merge branch 'stable-4.4' into stable-4.5
* stable-4.4:
Prepare 4.4.2-SNAPSHOT builds
JGit v4.0.3.201509231615-r
Change-Id: Icd66a796b0cce93c75a52cc77fec8f9df3eeccb4
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
diff --git a/.mailmap b/.mailmap
index 8f11a1c..ab4c963 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,3 +1,4 @@
+Mark Ingram <markdingram@gmail.com> markdingram <markdingram@gmail.com>
Roberto Tyley <roberto.tyley@guardian.co.uk> roberto <roberto.tyley@guardian.co.uk>
Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
diff --git a/README.md b/README.md
index 333fa28..9aca10f 100644
--- a/README.md
+++ b/README.md
@@ -18,10 +18,6 @@
All portions of JGit are covered by the EDL. Absolutely no GPL,
LGPL or EPL contributions are accepted within this package.
-- org.eclipse.jgit.java7
-
- Extensions for users of Java 7.
-
- org.eclipse.jgit.ant
Ant tasks based on JGit.
@@ -59,10 +55,6 @@
Unit tests for org.eclipse.jgit
-- org.eclipse.jgit.java7.test
-
- Unit tests for Java 7 specific features
-
- org.eclipse.jgit.ant.test
- org.eclipse.jgit.pgm.test
- org.eclipse.jgit.http.test
@@ -73,11 +65,9 @@
Warnings/Caveats
----------------
-- Native smbolic links are supported, but only if you are using Java 7
- or newer and include the org.eclipse.jgit.java7 jar/bundle in the
- classpath, provided the file system supports them. For Windows you
- must have Windows Vista/Windows 2008 or newer, use a
- non-administrator account and have the SeCreateSymbolicLinkPrivilege.
+- Native smbolic links are supported, provided the file system supports
+ them. For Windows you must have Windows Vista/Windows 2008 or newer,
+ use a non-administrator account and have the SeCreateSymbolicLinkPrivilege.
- Only the timestamp of the index is used by jgit if the index is
dirty.
@@ -153,12 +143,6 @@
* Assorted set of command line utilities. Mostly for ad-hoc testing of jgit
log, glog, fetch etc.
-- org.eclipse.jgit.java7/
-
- * Support for symbolic links.
-
- * Optimizations for reading file system attributes
-
- org.eclipse.jgit.ant/
* Ant tasks
diff --git a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 371c66f..4eeaf47 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.ant.tasks;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.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 a4f4355..37e71d7 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
index 13a031a..cd620c3 100644
--- a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 4ae7d7b..8a4c823 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)"
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.4.2";
+Export-Package: org.eclipse.jgit.ant.tasks;version="4.5.5";
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 6f21e4d..38c70cc 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant</artifactId>
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 45d6d2c..bfaf736 100644
--- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 2b960ae..c9b4863 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -12,14 +12,14 @@
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.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.api;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.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.4.2";
+Export-Package: org.eclipse.jgit.archive;version="4.5.5";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.api,
org.apache.commons.compress.archivers,
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index b4a519c..a82400f 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.4.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.4.2.qualifier";roots="."
+Bundle-Version: 4.5.5.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.5.5.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 0df67f8..5a444c8 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,11 +50,11 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.archive</artifactId>
- <name>JGit Archive Formats</name>
+ <name>JGit - Archive Formats</name>
<description>
Support for archiving a Git tree in formats such as zip and tar.
diff --git a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
index 13a031a..cd620c3 100644
--- a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 200e0ce..906b76e 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
@@ -19,10 +19,10 @@
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.4.2,4.5.0)",
- org.eclipse.jgit.transport.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.4.2";
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.5.5";
uses:="org.eclipse.jgit.transport.http,
javax.net.ssl,
org.apache.http.client,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 45bb22e..f250eb2 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
index a0eeef8..2d9d17a 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
@@ -226,17 +226,25 @@
}
private void execute() throws IOException, ClientProtocolException {
- if (resp == null)
- if (entity != null) {
- if (req instanceof HttpEntityEnclosingRequest) {
- HttpEntityEnclosingRequest eReq = (HttpEntityEnclosingRequest) req;
- eReq.setEntity(entity);
- }
- resp = getClient().execute(req);
- entity.getBuffer().close();
- entity = null;
- } else
- resp = getClient().execute(req);
+ if (resp != null) {
+ return;
+ }
+
+ if (entity == null) {
+ resp = getClient().execute(req);
+ return;
+ }
+
+ try {
+ if (req instanceof HttpEntityEnclosingRequest) {
+ HttpEntityEnclosingRequest eReq = (HttpEntityEnclosingRequest) req;
+ eReq.setEntity(entity);
+ }
+ resp = getClient().execute(req);
+ } finally {
+ entity.close();
+ entity = null;
+ }
}
public Map<String, List<String>> getHeaderFields() {
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
index 1ff168e..377e5ca 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java
@@ -55,7 +55,8 @@
*
* @since 3.3
*/
-public class TemporaryBufferEntity extends AbstractHttpEntity {
+public class TemporaryBufferEntity extends AbstractHttpEntity
+ implements AutoCloseable {
private TemporaryBuffer buffer;
private Integer contentLength;
@@ -106,4 +107,16 @@
public void setContentLength(int contentLength) {
this.contentLength = new Integer(contentLength);
}
+
+ /**
+ * Close destroys the associated buffer used to buffer the entity
+ *
+ * @since 4.5
+ */
+ @Override
+ public void close() {
+ if (buffer != null) {
+ buffer.destroy();
+ }
+ }
}
diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
index 13a031a..cd620c3 100644
--- a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index d28ac28..18f31d3 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.4.2",
- org.eclipse.jgit.http.server.glue;version="4.4.2";
+Export-Package: org.eclipse.jgit.http.server;version="4.5.5",
+ org.eclipse.jgit.http.server.glue;version="4.5.5";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.4.2";
+ org.eclipse.jgit.http.server.resolver;version="4.5.5";
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.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.resolver;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)"
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 6c5db67..5f8376c 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
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 a021c1f..b3fad3d 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
@@ -143,7 +143,7 @@
res.sendError(SC_UNAUTHORIZED, e.getMessage());
return;
} catch (ServiceMayNotContinueException e) {
- sendError(req, res, SC_FORBIDDEN, e.getMessage());
+ sendError(req, res, e.getStatusCode(), e.getMessage());
return;
}
try {
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 7d4f21b..a06bb1e 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
@@ -139,7 +139,7 @@
if (e.isOutput())
buf.close();
else
- sendError(req, res, SC_FORBIDDEN, e.getMessage());
+ sendError(req, res, e.getStatusCode(), e.getMessage());
}
}
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 8c27b71..a9a0c5b 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
@@ -197,7 +197,7 @@
out.close();
} else if (!rsp.isCommitted()) {
rsp.reset();
- sendError(req, rsp, SC_FORBIDDEN, e.getMessage());
+ sendError(req, rsp, e.getStatusCode(), e.getMessage());
}
return;
diff --git a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 90ee569..af492c1 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -22,24 +22,24 @@
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.4.2,4.5.0)",
- org.eclipse.jgit.http.server;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.http.server.glue;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.junit.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.resolver;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.http.server;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.junit.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.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/build.properties b/org.eclipse.jgit.http.test/build.properties
index 9ffa0ca..e8bacac 100644
--- a/org.eclipse.jgit.http.test/build.properties
+++ b/org.eclipse.jgit.http.test/build.properties
@@ -1,4 +1,5 @@
-source.. = tst/
+source.. = tst/,\
+ src/
output.. = bin/
bin.includes = META-INF/,\
.,\
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index c39817f..16c4d66 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index 073c751..2b9105c 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -610,7 +610,7 @@
fsck(remoteRepository, Q);
final ReflogReader log = remoteRepository.getReflogReader(dstName);
- assertNotNull("has log for " + dstName);
+ assertNotNull("has log for " + dstName, log);
final ReflogEntry last = log.getLastEntry();
assertNotNull("has last entry", last);
diff --git a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index c406a14..29dd705 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
@@ -20,16 +20,16 @@
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.4.2,4.5.0)",
- org.eclipse.jgit.http.server;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.resolver;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.http.server;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.5.5,4.6.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.4.2";
+Export-Package: org.eclipse.jgit.junit.http;version="4.5.5";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.junit,
javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index 201998f..1f2ee88 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
index c36c297..cca4f43 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -168,21 +168,38 @@
return ctx;
}
+ static class TestMappedLoginService extends MappedLoginService {
+ private String role;
+
+ TestMappedLoginService(String role) {
+ this.role = role;
+ }
+
+ @Override
+ protected UserIdentity loadUser(String who) {
+ return null;
+ }
+
+ @Override
+ protected void loadUsers() throws IOException {
+ putUser(username, new Password(password), new String[] { role });
+ }
+
+ protected String[] loadRoleInfo(
+ @SuppressWarnings("unused") KnownUser user) {
+ return null;
+ }
+
+ protected KnownUser loadUserInfo(
+ @SuppressWarnings("unused") String usrname) {
+ return null;
+ }
+ }
+
private void auth(ServletContextHandler ctx, Authenticator authType) {
final String role = "can-access";
- MappedLoginService users = new MappedLoginService() {
- @Override
- protected UserIdentity loadUser(String who) {
- return null;
- }
-
- @Override
- protected void loadUsers() throws IOException {
- putUser(username, new Password(password), new String[] { role });
- }
- };
-
+ MappedLoginService users = new TestMappedLoginService(role);
ConstraintMapping cm = new ConstraintMapping();
cm.setConstraint(new Constraint());
cm.getConstraint().setAuthenticate(true);
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
index 84bb888..ab5d3e1 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
@@ -117,7 +117,9 @@
protected static void fsck(Repository db, RevObject... tips)
throws Exception {
- new TestRepository(db).fsck(tips);
+ TestRepository<? extends Repository> tr =
+ new TestRepository<Repository>(db);
+ tr.fsck(tips);
}
protected static Set<RefSpec> mirror(String... refs) {
diff --git a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 0202328..7bddadb 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,27 +2,30 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.api.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.dircache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.merge;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util.io;version="[4.4.2,4.5.0)",
- org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="4.4.2";
+Import-Package: org.eclipse.jgit.api;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.api.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.dircache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.merge;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util.io;version="[4.5.5,4.6.0)",
+ org.junit;version="[4.0.0,5.0.0)",
+ org.junit.rules;version="[4.9.0,5.0.0)",
+ org.junit.runner;version="[4.0.0,5.0.0)",
+ org.junit.runners.model;version="[4.5.0,5.0.0)"
+Export-Package: org.eclipse.jgit.junit;version="4.5.5";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index 90dd865..184d72c 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
new file mode 100644
index 0000000..22b5007
--- /dev/null
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.junit;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ java.lang.annotation.ElementType.METHOD })
+public @interface Repeat {
+ public abstract int n();
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
new file mode 100644
index 0000000..75e1a67
--- /dev/null
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.junit;
+
+import java.text.MessageFormat;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * {@link TestRule} which enables to run the same JUnit test repeatedly. Add
+ * this rule to the test class
+ *
+ * <pre>
+ * public class MyTest {
+ * @Rule
+ * public RepeatRule repeatRule = new RepeatRule();
+ * ...
+ * }
+ * </pre>
+ *
+ * and annotate the test to be repeated with the
+ * {@code @Repeat(n=<repetitions>)} annotation
+ *
+ * <pre>
+ * @Test
+ * @Repeat(n = 100)
+ * public void test() {
+ * ...
+ * }
+ * </pre>
+ *
+ * then this test will be repeated 100 times. If any test execution fails test
+ * repetition will be stopped.
+ */
+public class RepeatRule implements TestRule {
+
+ private static Logger LOG = Logger
+ .getLogger(RepeatRule.class.getName());
+
+ public static class RepeatedTestException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public RepeatedTestException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private static class RepeatStatement extends Statement {
+
+ private final int repetitions;
+
+ private final Statement statement;
+
+ private RepeatStatement(int repetitions, Statement statement) {
+ this.repetitions = repetitions;
+ this.statement = statement;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ for (int i = 0; i < repetitions; i++) {
+ try {
+ statement.evaluate();
+ } catch (Throwable e) {
+ RepeatedTestException ex = new RepeatedTestException(
+ MessageFormat.format(
+ "Repeated test failed when run for the {0}. time",
+ Integer.valueOf(i + 1)),
+ e);
+ LOG.log(Level.SEVERE, ex.getMessage(), ex);
+ throw ex;
+ }
+ }
+ }
+ }
+
+ @Override
+ public Statement apply(Statement statement, Description description) {
+ Statement result = statement;
+ Repeat repeat = description.getAnnotation(Repeat.class);
+ if (repeat != null) {
+ int n = repeat.n();
+ result = new RepeatStatement(n, statement);
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
index 7ef63d8..71de1cd 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -27,11 +27,11 @@
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.junit.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.test;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.junit.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.test;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.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.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index bf975c0..f844abc 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
index 6c4f3cb..f92e638 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com>
+ * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -42,6 +42,8 @@
*/
package org.eclipse.jgit.lfs.server.fs;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -72,13 +74,15 @@
public void testDownloadInvalidPathInfo()
throws ClientProtocolException, IOException {
String TEXT = "test";
- AnyLongObjectId id = putContent(TEXT);
+ String id = putContent(TEXT).name().substring(0, 60);
Path f = Paths.get(getTempDirectory().toString(), "download");
try {
- getContent(id.name().substring(0, 60), f);
+ getContent(id, f);
fail("expected RuntimeException");
} catch (RuntimeException e) {
- assertEquals("Status: 400 Bad Request",
+ String error = String.format(
+ "Invalid pathInfo '/%s' does not match '/{SHA-256}'", id);
+ assertEquals(formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error),
e.getMessage());
}
}
@@ -87,13 +91,14 @@
public void testDownloadInvalidId()
throws ClientProtocolException, IOException {
String TEXT = "test";
- AnyLongObjectId id = putContent(TEXT);
+ String id = putContent(TEXT).name().replace('f', 'z');
Path f = Paths.get(getTempDirectory().toString(), "download");
try {
- getContent(id.name().replace('f', 'z'), f);
+ getContent(id, f);
fail("expected RuntimeException");
} catch (RuntimeException e) {
- assertEquals("Status: 400 Bad Request",
+ String error = String.format("Invalid id: : %s", id);
+ assertEquals(formatErrorMessage(SC_UNPROCESSABLE_ENTITY, error),
e.getMessage());
}
}
@@ -108,7 +113,8 @@
getContent(id, f);
fail("expected RuntimeException");
} catch (RuntimeException e) {
- assertEquals("Status: 404 Not Found",
+ String error = String.format("Object '%s' not found", id.getName());
+ assertEquals(formatErrorMessage(SC_NOT_FOUND, error),
e.getMessage());
}
}
@@ -129,4 +135,10 @@
FileUtils.delete(f.toFile(), FileUtils.RETRY);
}
+
+ @SuppressWarnings("boxing")
+ private String formatErrorMessage(int status, String message) {
+ return String.format("Status: %d {\n \"message\": \"%s\"\n}", status,
+ message);
+ }
}
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
index 8c266d4..4d948b9 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com>
+ * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.lfs.server.fs;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import java.io.BufferedInputStream;
@@ -79,6 +80,7 @@
import org.eclipse.jgit.lfs.lib.LongObjectId;
import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.IO;
import org.junit.After;
import org.junit.Before;
@@ -186,8 +188,23 @@
StatusLine statusLine = response.getStatusLine();
int status = statusLine.getStatusCode();
if (statusLine.getStatusCode() >= 400) {
- throw new RuntimeException("Status: " + status + " "
- + statusLine.getReasonPhrase());
+ String error;
+ try {
+ ByteBuffer buf = IO.readWholeStream(new BufferedInputStream(
+ response.getEntity().getContent()), 1024);
+ if (buf.hasArray()) {
+ error = new String(buf.array(),
+ buf.arrayOffset() + buf.position(), buf.remaining(),
+ UTF_8);
+ } else {
+ final byte[] b = new byte[buf.remaining()];
+ buf.duplicate().get(b);
+ error = new String(b, UTF_8);
+ }
+ } catch (IOException e) {
+ error = statusLine.getReasonPhrase();
+ }
+ throw new RuntimeException("Status: " + status + " " + error);
}
assertEquals(200, status);
}
diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
index 1fb91bd..8a8f49c 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/UploadTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com>
+ * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
diff --git a/org.eclipse.jgit.lfs.server/.settings/.api_filters b/org.eclipse.jgit.lfs.server/.settings/.api_filters
new file mode 100644
index 0000000..e662937
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server/.settings/.api_filters
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.lfs.server" version="2">
+ <resource path="src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java" type="org.eclipse.jgit.lfs.server.LfsProtocolServlet">
+ <filter comment="breaking implementors only which is ok under OSGi semver rules" id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lfs.server.LfsProtocolServlet"/>
+ <message_argument value="getLargeFileRepository(LfsProtocolServlet.LfsRequest, String)"/>
+ </message_arguments>
+ </filter>
+ <filter comment="breaking implementors only which is ok under OSGi semver rules" id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lfs.server.LfsProtocolServlet"/>
+ <message_argument value="getLargeFileRepository()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
index ff39d16..1ce7cd0 100644
--- a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 5688ea1..8e6ab94 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -2,19 +2,19 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="4.4.2";
+Export-Package: org.eclipse.jgit.lfs.server;version="4.5.5";
uses:="javax.servlet.http,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="4.4.2";
+ org.eclipse.jgit.lfs.server.fs;version="4.5.5";
uses:="javax.servlet,
javax.servlet.http,
org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="4.4.2";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="4.4.2";
+ org.eclipse.jgit.lfs.server.internal;version="4.5.5";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="4.5.5";
uses:="org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -24,12 +24,12 @@
javax.servlet.http;version="[3.1.0,4.0.0)",
org.apache.http;version="[4.3.0,5.0.0)",
org.apache.http.client;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)"
+ org.eclipse.jgit.annotations;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)"
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 71b05ea..5c81ae6 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties b/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
index 451064d..f97acac 100644
--- a/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
+++ b/org.eclipse.jgit.lfs.server/resources/org/eclipse/jgit/lfs/server/internal/LfsServerText.properties
@@ -2,11 +2,11 @@
failedToCalcSignature=Failed to calculate a request signature: {0}
invalidPathInfo=Invalid pathInfo ''{0}'' does not match ''/'{'SHA-256'}'''
objectNotFound=Object ''{0}'' not found
-undefinedS3AccessKey=S3 configuration: ''accessKey'' is undefined
-undefinedS3Bucket=S3 configuration: ''bucket'' is undefined
-undefinedS3Region=S3 configuration: ''region'' is undefined
-undefinedS3SecretKey=S3 configuration: ''secretKey'' is undefined
-undefinedS3StorageClass=S3 configuration: ''storageClass'' is undefined
+undefinedS3AccessKey=S3 configuration: 'accessKey' is undefined
+undefinedS3Bucket=S3 configuration: 'bucket' is undefined
+undefinedS3Region=S3 configuration: 'region' is undefined
+undefinedS3SecretKey=S3 configuration: 'secretKey' is undefined
+undefinedS3StorageClass=S3 configuration: 'storageClass' is undefined
unparsableEndpoint=Unable to parse service endpoint: {0}
unsupportedOperation=Operation ''{0}'' is not supported
unsupportedUtf8=UTF-8 encoding is not supported.
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
index 30ba22e..4d97502 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java
@@ -42,7 +42,26 @@
*/
package org.eclipse.jgit.lfs.server;
-class LfsObject {
+/**
+ * LFS object.
+ *
+ * @since 4.5
+ */
+public class LfsObject {
String oid;
long size;
+
+ /**
+ * @return the object ID.
+ */
+ public String getOid() {
+ return oid;
+ }
+
+ /**
+ * @return the object size.
+ */
+ public long getSize() {
+ return size;
+ }
}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
index 394137c..eb49ff0 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java
@@ -43,8 +43,13 @@
package org.eclipse.jgit.lfs.server;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static javax.servlet.http.HttpServletResponse.SC_OK;
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static org.apache.http.HttpStatus.SC_FORBIDDEN;
+import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
+import static org.apache.http.HttpStatus.SC_INSUFFICIENT_STORAGE;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+import static org.apache.http.HttpStatus.SC_OK;
+import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
+import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -60,6 +65,15 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jgit.lfs.errors.LfsBandwidthLimitExceeded;
+import org.eclipse.jgit.lfs.errors.LfsException;
+import org.eclipse.jgit.lfs.errors.LfsInsufficientStorage;
+import org.eclipse.jgit.lfs.errors.LfsRateLimitExceeded;
+import org.eclipse.jgit.lfs.errors.LfsRepositoryNotFound;
+import org.eclipse.jgit.lfs.errors.LfsRepositoryReadOnly;
+import org.eclipse.jgit.lfs.errors.LfsUnavailable;
+import org.eclipse.jgit.lfs.errors.LfsValidationError;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -67,7 +81,7 @@
/**
* LFS protocol handler implementing the LFS batch API [1]
*
- * [1] https://github.com/github/git-lfs/blob/master/docs/api/http-v1-batch.md
+ * [1] https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md
*
* @since 4.3
*/
@@ -75,52 +89,143 @@
private static final long serialVersionUID = 1L;
- private static final String CONTENTTYPE_VND_GIT_LFS_JSON = "application/vnd.git-lfs+json"; //$NON-NLS-1$
+ private static final String CONTENTTYPE_VND_GIT_LFS_JSON =
+ "application/vnd.git-lfs+json; charset=utf-8"; //$NON-NLS-1$
+
+ private static final int SC_RATE_LIMIT_EXCEEDED = 429;
+
+ private static final int SC_BANDWIDTH_LIMIT_EXCEEDED = 509;
private Gson gson = createGson();
/**
- * Get the large file repository
+ * Get the large file repository for the given request and path.
*
- * @return the large file repository storing large files
+ * @param request
+ * the request
+ * @param path
+ * the path
+ *
+ * @return the large file repository storing large files.
+ * @throws LfsException
+ * implementations should throw more specific exceptions to
+ * signal which type of error occurred:
+ * <dl>
+ * <dt>{@link LfsValidationError}</dt>
+ * <dd>when there is a validation error with one or more of the
+ * objects in the request</dd>
+ * <dt>{@link LfsRepositoryNotFound}</dt>
+ * <dd>when the repository does not exist for the user</dd>
+ * <dt>{@link LfsRepositoryReadOnly}</dt>
+ * <dd>when the user has read, but not write access. Only
+ * applicable when the operation in the request is "upload"</dd>
+ * <dt>{@link LfsRateLimitExceeded}</dt>
+ * <dd>when the user has hit a rate limit with the server</dd>
+ * <dt>{@link LfsBandwidthLimitExceeded}</dt>
+ * <dd>when the bandwidth limit for the user or repository has
+ * been exceeded</dd>
+ * <dt>{@link LfsInsufficientStorage}</dt>
+ * <dd>when there is insufficient storage on the server</dd>
+ * <dt>{@link LfsUnavailable}</dt>
+ * <dd>when LFS is not available</dd>
+ * <dt>{@link LfsException}</dt>
+ * <dd>when an unexpected internal server error occurred</dd>
+ * </dl>
+ * @since 4.5
*/
- protected abstract LargeFileRepository getLargeFileRepository();
+ protected abstract LargeFileRepository getLargeFileRepository(
+ LfsRequest request, String path) throws LfsException;
+
+ /**
+ * LFS request.
+ *
+ * @since 4.5
+ */
+ protected static class LfsRequest {
+ private String operation;
+
+ private List<LfsObject> objects;
+
+ /**
+ * Get the LFS operation.
+ *
+ * @return the operation
+ */
+ public String getOperation() {
+ return operation;
+ }
+
+ /**
+ * Get the LFS objects.
+ *
+ * @return the objects
+ */
+ public List<LfsObject> getObjects() {
+ return objects;
+ }
+ }
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
- res.setStatus(SC_OK);
- res.setContentType(CONTENTTYPE_VND_GIT_LFS_JSON);
-
Writer w = new BufferedWriter(
new OutputStreamWriter(res.getOutputStream(), UTF_8));
- Reader r = new BufferedReader(new InputStreamReader(req.getInputStream(), UTF_8));
+ Reader r = new BufferedReader(
+ new InputStreamReader(req.getInputStream(), UTF_8));
LfsRequest request = gson.fromJson(r, LfsRequest.class);
+ String path = req.getPathInfo();
- LargeFileRepository repo = getLargeFileRepository();
- if (repo == null) {
- res.setStatus(SC_SERVICE_UNAVAILABLE);
- return;
+ res.setContentType(CONTENTTYPE_VND_GIT_LFS_JSON);
+ LargeFileRepository repo = null;
+ try {
+ repo = getLargeFileRepository(request, path);
+ if (repo == null) {
+ throw new LfsException("unexpected error"); //$NON-NLS-1$
+ }
+ res.setStatus(SC_OK);
+ TransferHandler handler = TransferHandler
+ .forOperation(request.operation, repo, request.objects);
+ gson.toJson(handler.process(), w);
+ } catch (LfsValidationError e) {
+ sendError(res, w, SC_UNPROCESSABLE_ENTITY, e.getMessage());
+ } catch (LfsRepositoryNotFound e) {
+ sendError(res, w, SC_NOT_FOUND, e.getMessage());
+ } catch (LfsRepositoryReadOnly e) {
+ sendError(res, w, SC_FORBIDDEN, e.getMessage());
+ } catch (LfsRateLimitExceeded e) {
+ sendError(res, w, SC_RATE_LIMIT_EXCEEDED, e.getMessage());
+ } catch (LfsBandwidthLimitExceeded e) {
+ sendError(res, w, SC_BANDWIDTH_LIMIT_EXCEEDED, e.getMessage());
+ } catch (LfsInsufficientStorage e) {
+ sendError(res, w, SC_INSUFFICIENT_STORAGE, e.getMessage());
+ } catch (LfsUnavailable e) {
+ sendError(res, w, SC_SERVICE_UNAVAILABLE, e.getMessage());
+ } catch (LfsException e) {
+ sendError(res, w, SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ } finally {
+ w.flush();
}
-
- TransferHandler handler = TransferHandler
- .forOperation(request.operation, repo, request.objects);
- gson.toJson(handler.process(), w);
- w.flush();
}
- private static class LfsRequest {
- String operation;
+ static class Error {
+ String message;
- List<LfsObject> objects;
+ Error(String m) {
+ this.message = m;
+ }
}
- private static Gson createGson() {
- GsonBuilder gb = new GsonBuilder()
- .setFieldNamingPolicy(
- FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .setPrettyPrinting().disableHtmlEscaping();
- return gb.create();
+ private void sendError(HttpServletResponse rsp, Writer writer, int status,
+ String message) {
+ rsp.setStatus(status);
+ gson.toJson(new Error(message), writer);
+ }
+
+ private Gson createGson() {
+ return new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .disableHtmlEscaping()
+ .create();
}
}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
index 8864af8..2ecba6d 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.lfs.server.fs;
import java.io.IOException;
+import java.io.PrintWriter;
import java.text.MessageFormat;
import javax.servlet.AsyncContext;
@@ -59,6 +60,10 @@
import org.eclipse.jgit.lfs.lib.LongObjectId;
import org.eclipse.jgit.lfs.server.internal.LfsServerText;
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
/**
* Servlet supporting upload and download of large objects as defined by the
* GitHub Large File Storage extension API extending git to allow separate
@@ -76,6 +81,8 @@
private final long timeout;
+ private static Gson gson = createGson();
+
/**
* @param repository
* the repository storing the large objects
@@ -106,7 +113,8 @@
if (obj != null) {
if (repository.getSize(obj) == -1) {
sendError(rsp, HttpStatus.SC_NOT_FOUND, MessageFormat
- .format(LfsServerText.get().objectNotFound, obj));
+ .format(LfsServerText.get().objectNotFound,
+ obj.getName()));
return;
}
AsyncContext context = req.startAsync();
@@ -120,15 +128,16 @@
private AnyLongObjectId getObjectToTransfer(HttpServletRequest req,
HttpServletResponse rsp) throws IOException {
String info = req.getPathInfo();
- if (info.length() != 1 + Constants.LONG_OBJECT_ID_STRING_LENGTH) {
- sendError(rsp, HttpStatus.SC_BAD_REQUEST, MessageFormat
+ int length = 1 + Constants.LONG_OBJECT_ID_STRING_LENGTH;
+ if (info.length() != length) {
+ sendError(rsp, HttpStatus.SC_UNPROCESSABLE_ENTITY, MessageFormat
.format(LfsServerText.get().invalidPathInfo, info));
return null;
}
try {
- return LongObjectId.fromString(info.substring(1, 65));
+ return LongObjectId.fromString(info.substring(1, length));
} catch (InvalidLongObjectIdException e) {
- sendError(rsp, HttpStatus.SC_BAD_REQUEST, e.getMessage());
+ sendError(rsp, HttpStatus.SC_UNPROCESSABLE_ENTITY, e.getMessage());
return null;
}
}
@@ -157,11 +166,29 @@
}
}
+ static class Error {
+ String message;
+
+ Error(String m) {
+ this.message = m;
+ }
+ }
+
static void sendError(HttpServletResponse rsp, int status, String message)
throws IOException {
rsp.setStatus(status);
- // TODO return message in response body in json format as specified in
- // https://github.com/github/git-lfs/blob/master/docs/api/http-v1-batch.md
+ PrintWriter writer = rsp.getWriter();
+ gson.toJson(new Error(message), writer);
+ writer.flush();
+ writer.close();
rsp.flushBuffer();
}
+
+ private static Gson createGson() {
+ GsonBuilder gb = new GsonBuilder()
+ .setFieldNamingPolicy(
+ FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .setPrettyPrinting().disableHtmlEscaping();
+ return gb.create();
+ }
}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
index bfdea4f..f179b6c 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com>
+ * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
index e524ac6..d44b3db 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com>
+ * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
diff --git a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index f0ecdef..c47a675 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -2,18 +2,18 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
+Import-Package: org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.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)",
org.junit.runners;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="4.4.2";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="4.5.5";x-friends:="org.eclipse.jgit.lfs.server.test"
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index 782c63e..9eeb65a 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
index ff39d16..1ce7cd0 100644
--- a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 77b6fce..f9564d3 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -2,14 +2,14 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.errors;version="4.4.2",
- org.eclipse.jgit.lfs.internal;version="4.4.2";x-friends:="org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.lfs.lib;version="4.4.2"
+Export-Package: org.eclipse.jgit.lfs.errors;version="4.5.5",
+ org.eclipse.jgit.lfs.internal;version="4.5.5";x-friends:="org.eclipse.jgit.lfs.test",
+ org.eclipse.jgit.lfs.lib;version="4.5.5"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)"
+Import-Package: org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index 1e6fd7d..fcc74ab 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
index 700e2d5..7c3aea2 100644
--- a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
+++ b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
@@ -1,4 +1,7 @@
incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
invalidLongId=Invalid id: {0}
invalidLongIdLength=Invalid id length {0}; should be {1}
-requiredHashFunctionNotAvailable=Required hash function {0} not available.
\ No newline at end of file
+requiredHashFunctionNotAvailable=Required hash function {0} not available.
+repositoryNotFound=Repository {0} not found
+repositoryReadOnly=Repository {0} is read-only
+lfsUnavailable=LFS is not available for repository {0}
\ No newline at end of file
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java
new file mode 100644
index 0000000..1b1baec
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsBandwidthLimitExceeded.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+/**
+ * Thrown when the bandwidth limit for the user or repository has been exceeded.
+ *
+ * @since 4.5
+ *
+ */
+public class LfsBandwidthLimitExceeded extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * error message, which may be shown to an end-user.
+ */
+ public LfsBandwidthLimitExceeded(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java
new file mode 100644
index 0000000..3b83639
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+/**
+ * Thrown when an error occurs during LFS operation.
+ *
+ * @since 4.5
+ */
+public class LfsException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * error message, which may be shown to an end-user.
+ */
+ public LfsException(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java
new file mode 100644
index 0000000..4faace9
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsInsufficientStorage.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+/**
+ * Thrown when there is insufficient storage on the server.
+ *
+ * @since 4.5
+ *
+ */
+public class LfsInsufficientStorage extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * error message, which may be shown to an end-user.
+ */
+ public LfsInsufficientStorage(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java
new file mode 100644
index 0000000..606783041
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRateLimitExceeded.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+/**
+ * Thrown when the user has hit a rate limit with the server.
+ *
+ * @since 4.5
+ *
+ */
+public class LfsRateLimitExceeded extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * error message, which may be shown to an end-user.
+ */
+ public LfsRateLimitExceeded(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java
new file mode 100644
index 0000000..52c932a
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryNotFound.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.internal.LfsText;
+
+/**
+ * Thrown when the repository does not exist for the user.
+ *
+ * @since 4.5
+ */
+public class LfsRepositoryNotFound extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param name
+ * the repository name.
+ *
+ */
+ public LfsRepositoryNotFound(String name) {
+ super(MessageFormat.format(LfsText.get().repositoryNotFound, name));
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java
new file mode 100644
index 0000000..3610377
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsRepositoryReadOnly.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.internal.LfsText;
+
+/**
+ * Thrown when the user has read, but not write access. Only applicable when the
+ * operation in the request is "upload".
+ *
+ * @since 4.5
+ */
+public class LfsRepositoryReadOnly extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param name
+ * the repository name.
+ */
+ public LfsRepositoryReadOnly(String name) {
+ super(MessageFormat.format(LfsText.get().repositoryReadOnly, name));
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java
new file mode 100644
index 0000000..ecb5e9e
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnavailable.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.internal.LfsText;
+
+/**
+ * Thrown when LFS is not available.
+ *
+ * @since 4.5
+ */
+public class LfsUnavailable extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param name
+ * the repository name.
+ */
+ public LfsUnavailable(String name) {
+ super(MessageFormat.format(LfsText.get().lfsUnavailable, name));
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java
new file mode 100644
index 0000000..5e445ec
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsValidationError.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016, David Pursehouse <david.pursehouse@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.errors;
+
+/**
+ * Thrown when there is a validation error with one or more of the objects in
+ * the request.
+ *
+ * @since 4.5
+ */
+public class LfsValidationError extends LfsException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * error message, which may be shown to an end-user.
+ */
+ public LfsValidationError(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
index eaffcc9..365eaa1 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
@@ -62,4 +62,7 @@
/***/ public String invalidLongId;
/***/ public String invalidLongIdLength;
/***/ public String requiredHashFunctionNotAvailable;
+ /***/ public String repositoryNotFound;
+ /***/ public String repositoryReadOnly;
+ /***/ public String lfsUnavailable;
}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
index 3cadbf7..d246412 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
@@ -102,7 +102,7 @@
/**
* Content type used by LFS REST API as defined in
- * {@link "https://github.com/github/git-lfs/blob/master/docs/api/http-v1-batch.md"}
+ * {@link "https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md"}
*/
public static String CONTENT_TYPE_GIT_LFS_JSON = "application/vnd.git-lfs+json";
@@ -111,4 +111,4 @@
* {@link "https://www.ietf.org/rfc/rfc2046.txt"}
*/
public static String HDR_APPLICATION_OCTET_STREAM = "application/octet-stream";
-}
\ No newline at end of file
+}
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 5af0b63..cd27138 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.4.2.qualifier"
+ version="4.5.5.qualifier"
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 c91a46d..a2a86b2 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 f94dce8..f1fae01 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.4.2.qualifier"
+ version="4.5.5.qualifier"
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 4f1cc80..7b7e626 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 0014f60..a3bd7c9 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.4.2.qualifier"
+ version="4.5.5.qualifier"
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 a4c763b..296d3c5 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index 4f0ada2..a7ce75e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.lfs"
label="%featureName"
- version="4.4.2.qualifier"
+ version="4.5.5.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
index 154df15..e7bbe2e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 a6ae6d3..60ca4ab 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.4.2.qualifier"
+ version="4.5.5.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -31,8 +31,8 @@
version="0.0.0"/>
<requires>
- <import feature="org.eclipse.jgit" version="4.4.1" match="equivalent"/>
- <import feature="org.eclipse.jgit.lfs" version="4.4.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="4.5.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit.lfs" version="4.5.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 2013fc4..c42fd96 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 cc52233..39feedf 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.4.2.qualifier"
+ version="4.5.5.qualifier"
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 a295873..eed1686 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
index c2bfc92..15d10e6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
@@ -24,9 +24,6 @@
<feature url="features/org.eclipse.jgit.lfs_0.0.0.qualifier.jar" id="org.eclipse.jgit.lfs" version="0.0.0">
<category name="JGit"/>
</feature>
- <feature url="features/org.eclipse.jgit.lfs_0.0.0.qualifier.jar" id="org.eclipse.jgit.lfs" version="0.0.0">
- <category name="JGit"/>
- </feature>
<category-def name="JGit" label="JGit">
<description>
JGit
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 43e15e5..7a6d7ed 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 4f99110..c63047c 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.4.2.qualifier"
+ version="4.5.5.qualifier"
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 f737251..2f07639 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 a4ba267..c1615cd 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index f7d5622..a1f5abf 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.6" sequenceNumber="1463612069">
+<target name="jgit-4.6" sequenceNumber="1465553981">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
@@ -58,7 +58,7 @@
<unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
<unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
<unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
- <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20160518051658/repository/"/>
+ <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20160520211859/repository/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="0.0.0"/>
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 cd6b4a3..0c77c0e 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 71b859d..ef9fb98 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 66d010c..e1eaf4a 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,28 +2,28 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.api.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.diff;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.dircache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="4.4.2",
- org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.merge;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.pgm;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.pgm.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.pgm.opt;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util.io;version="[4.4.2,4.5.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.api.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.diff;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.dircache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="4.5.5",
+ org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.merge;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.pgm;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util.io;version="[4.5.5,4.6.0)",
org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.junit;version="[4.11.0,5.0.0)",
org.junit.rules;version="[4.11.0,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index eeccff4..1cde872 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</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 e690ad6..3651542 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
@@ -47,6 +47,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.File;
import java.nio.file.Files;
@@ -236,8 +237,8 @@
* <li>Checkout branch '1'
* </ol>
* <p>
- * The working tree should contain 'a' with FileMode.REGULAR_FILE after the
- * checkout.
+ * The checkout has to delete folder but the workingtree contains a dirty
+ * file at this path. The checkout should fail like in native git.
*
* @throws Exception
*/
@@ -266,11 +267,15 @@
db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
-
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ try {
+ git.checkout().setName(branch_1.getName()).call();
+ fail("Don't get the expected conflict");
+ } catch (CheckoutConflictException e) {
+ assertEquals("[a]", e.getConflictingPaths().toString());
+ entry = new FileTreeIterator.FileEntry(
+ new File(db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ }
}
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java
new file mode 100644
index 0000000..bbac296
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CleanTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016, Ned Twigg <ned.twigg@diffplug.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.junit.Test;
+import static org.eclipse.jgit.junit.JGitTestUtil.check;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class CleanTest extends CLIRepositoryTestCase {
+ @Test
+ public void testCleanRequiresForce() throws Exception {
+ try (Git git = new Git(db)) {
+ assertArrayOfLinesEquals(
+ new String[] { "Removing a", "Removing b" },
+ execute("git clean"));
+ } catch (Die e) {
+ // TODO: should be "fatal: clean.requireForce defaults to true and
+ // neither -i, -n, nor -f given; refusing to clean" but we don't
+ // support -i yet. Fix this when/if we add support for -i.
+ assertEquals(
+ "fatal: clean.requireForce defaults to true and neither -n nor -f given; refusing to clean",
+ e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCleanRequiresForceConfig() throws Exception {
+ try (Git git = new Git(db)) {
+ git.getRepository().getConfig().setBoolean("clean", null,
+ "requireForce", false);
+ assertArrayOfLinesEquals(
+ new String[] { "" },
+ execute("git clean"));
+ }
+ }
+
+ @Test
+ public void testCleanLeaveDirs() throws Exception {
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+
+ writeTrashFile("dir/file", "someData");
+ writeTrashFile("a", "someData");
+ writeTrashFile("b", "someData");
+
+ // all these files should be there
+ assertTrue(check(db, "a"));
+ assertTrue(check(db, "b"));
+ assertTrue(check(db, "dir/file"));
+
+ // dry run should make no change
+ assertArrayOfLinesEquals(
+ new String[] { "Removing a", "Removing b" },
+ execute("git clean -n"));
+ assertTrue(check(db, "a"));
+ assertTrue(check(db, "b"));
+ assertTrue(check(db, "dir/file"));
+
+ // force should make a change
+ assertArrayOfLinesEquals(
+ new String[] { "Removing a", "Removing b" },
+ execute("git clean -f"));
+ assertFalse(check(db, "a"));
+ assertFalse(check(db, "b"));
+ assertTrue(check(db, "dir/file"));
+ }
+ }
+
+ @Test
+ public void testCleanDeleteDirs() throws Exception {
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+
+ writeTrashFile("dir/file", "someData");
+ writeTrashFile("a", "someData");
+ writeTrashFile("b", "someData");
+
+ // all these files should be there
+ assertTrue(check(db, "a"));
+ assertTrue(check(db, "b"));
+ assertTrue(check(db, "dir/file"));
+
+ assertArrayOfLinesEquals(
+ new String[] { "Removing a", "Removing b",
+ "Removing dir/" },
+ execute("git clean -d -f"));
+ assertFalse(check(db, "a"));
+ assertFalse(check(db, "b"));
+ assertFalse(check(db, "dir/file"));
+ }
+ }
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
index fe80388..2c0abd7 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -135,6 +135,7 @@
assertEquals("expected 1 branch", 1, branches.size());
}
+ @Test
public void testCloneBare() throws Exception {
createInitialCommit();
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
index 0fe25f5..03391a0 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
@@ -46,6 +46,7 @@
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.eclipse.jgit.lib.Ref;
import org.junit.Before;
import org.junit.Test;
@@ -70,4 +71,26 @@
assertEquals("fatal: tag 'test' already exists",
executeUnchecked("git tag test")[0]);
}
+
+ @Test
+ public void testTagDelete() throws Exception {
+ git.tag().setName("test").call();
+
+ Ref ref = git.getRepository().getTags().get("test");
+ assertEquals("refs/tags/test", ref.getName());
+
+ assertEquals("", executeUnchecked("git tag -d test")[0]);
+ Ref deletedRef = git.getRepository().getTags().get("test");
+ assertEquals(null, deletedRef);
+ }
+
+ @Test
+ public void testTagDeleteFail() throws Exception {
+ try {
+ assertEquals("fatal: error: tag 'test' not found.",
+ executeUnchecked("git tag -d test")[0]);
+ } catch (Die e) {
+ assertEquals("fatal: error: tag 'test' not found", e.getMessage());
+ }
+ }
}
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 45d6d2c..bfaf736 100644
--- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index cf2a03e..f31e63f 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
@@ -26,45 +26,45 @@
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.api;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.api.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.archive;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.awtui;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.blame;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.diff;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.dircache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.gitrepo;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.ketch;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.server;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lfs.server.s3;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.merge;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.notes;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revplot;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.pack;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.resolver;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util.io;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.api;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.api.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.archive;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.awtui;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.blame;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.diff;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.dircache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.gitrepo;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.ketch;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.server;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.merge;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.notes;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revplot;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.pack;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util.io;version="[4.5.5,4.6.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)",
org.kohsuke.args4j.spi;version="[2.0.15,2.1.0)"
-Export-Package: org.eclipse.jgit.console;version="4.4.2";
+Export-Package: org.eclipse.jgit.console;version="4.5.5";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.4.2";
+ org.eclipse.jgit.pgm;version="4.5.5";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.pgm.opt,
@@ -75,11 +75,11 @@
org.eclipse.jgit.treewalk,
javax.swing,
org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.4.2";
+ org.eclipse.jgit.pgm.debug;version="4.5.5";
uses:="org.eclipse.jgit.util.io,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.4.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.4.2";
+ org.eclipse.jgit.pgm.internal;version="4.5.5";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.5.5";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.kohsuke.args4j.spi,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index aeb8b37..3f395ad 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.4.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.4.2.qualifier";roots="."
+Bundle-Version: 4.5.5.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.5.5.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index c159f7d..5495be6 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -4,6 +4,7 @@
org.eclipse.jgit.pgm.Blame
org.eclipse.jgit.pgm.Branch
org.eclipse.jgit.pgm.Checkout
+org.eclipse.jgit.pgm.Clean
org.eclipse.jgit.pgm.Clone
org.eclipse.jgit.pgm.Commit
org.eclipse.jgit.pgm.Config
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index f469cc2..a8537b9 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
@@ -129,17 +129,6 @@
</dependency>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.eclipse.jgit</groupId>
- <artifactId>org.eclipse.jgit.junit.http</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs</artifactId>
<version>${project.version}</version>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index abe04b8..1d4bf76 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -46,6 +46,7 @@
changesToBeCommitted=Changes to be committed:
checkoutConflict=error: Your local changes to the following files would be overwritten by checkout:
checkoutConflictPathLine=\t{0}
+cleanRequireForce=clean.requireForce defaults to true and neither -n nor -f given; refusing to clean
clonedEmptyRepository=warning: You appear to have cloned an empty repository.
cloningInto=Cloning into ''{0}''...
commitLabel=commit
@@ -113,6 +114,7 @@
metaVar_filepattern=filepattern
metaVar_gitDir=GIT_DIR
metaVar_hostName=HOSTNAME
+metaVar_ketchServerType=SERVERTYPE
metaVar_lfsStorage=STORAGE
metaVar_linesOfContext=lines
metaVar_message=message
@@ -177,6 +179,7 @@
remoteMessage=remote: {0}
remoteRefObjectChangedIsNotExpectedOne=remote ref object changed - is not expected one {0}
remoteSideDoesNotSupportDeletingRefs=remote side does not support deleting refs
+removing=Removing {0}
repaint=Repaint
s3InvalidBucket=Invalid S3 bucket ''{0}''
serviceNotSupported=Service ''{0}'' not supported
@@ -198,6 +201,7 @@
switchedToBranch=Switched to branch ''{0}''
tagAlreadyExists=tag ''{0}'' already exists
tagLabel=tag
+tagNotFound=error: tag ''{0}'' not found.
taggerInfo=Tagger: {0} <{1}>
timeInMilliSeconds={0} ms
treeIsRequired=argument tree is required
@@ -212,6 +216,7 @@
usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR.
usage_Blame=Show what revision and author last modified each line
+usage_Clean=Remove untracked files from the working tree
usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CommitAll=commit all modified and deleted files
usage_CommitAuthor=Override the author name used in the commit. You can use the standard A U Thor <author@example.com> format.
@@ -228,6 +233,7 @@
usage_Gc=Cleanup unnecessary files and optimize the local repository
usage_Glog=View commit history as a graph
usage_IndexPack=Build pack index file for an existing packed archive
+usage_ketchServerType=Ketch server type
usage_LFSDirectory=Directory to store large objects
usage_LFSPort=Server http port
usage_LFSRunStore=Store (fs | s3), store lfs objects in file system or Amazon S3
@@ -323,6 +329,7 @@
usage_fixAThinPackToBeComplete=fix a thin pack to be complete
usage_forEachRefOutput=for-each-ref output
usage_forceCheckout=when switching branches, proceed even if the index or the working tree differs from HEAD
+usage_forceClean=required to delete files or directories
usage_forceCreateBranchEvenExists=force create branch even exists
usage_forceReplacingAnExistingTag=force replacing an existing tag
usage_getAndSetOptions=Get and set repository or global options
@@ -362,6 +369,7 @@
usage_quiet=don't show progress messages
usage_recordChangesToRepository=Record changes to the repository
usage_recurseIntoSubtrees=recurse into subtrees
+usage_removeUntrackedDirectories=remove untracked directories
usage_renameLimit=limit size of rename matrix
usage_reset=Reset current HEAD to the specified state
usage_resetReference=Reset to given reference name
@@ -381,6 +389,7 @@
usage_symbolicVersionForTheProject=Symbolic version for the project
usage_tags=fetch all tags
usage_notags=do not fetch tags
+usage_tagDelete=delete tag
usage_tagMessage=tag message
usage_untrackedFilesMode=show untracked files
usage_updateRef=reference to update
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
new file mode 100644
index 0000000..ce4faf8
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016, Ned Twigg <ned.twigg@diffplug.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.pgm;
+
+import java.text.MessageFormat;
+import java.util.Set;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.kohsuke.args4j.Option;
+
+@Command(common = true, usage = "usage_Clean")
+class Clean extends TextBuiltin {
+ @Option(name = "-d", usage = "usage_removeUntrackedDirectories")
+ private boolean dirs = false;
+
+ @Option(name = "--force", aliases = {
+ "-f" }, usage = "usage_forceClean")
+ private boolean force = false;
+
+ @Option(name = "--dryRun", aliases = { "-n" })
+ private boolean dryRun = false;
+
+ @Override
+ protected void run() throws Exception {
+ try (Git git = new Git(db)) {
+ boolean requireForce = git.getRepository().getConfig()
+ .getBoolean("clean", "requireForce", true); //$NON-NLS-1$ //$NON-NLS-2$
+ if (requireForce && !(force || dryRun)) {
+ throw die(CLIText.fatalError(CLIText.get().cleanRequireForce));
+ }
+ // Note that CleanCommand's setForce(true) will delete
+ // .git folders. In the cgit cli, this behavior
+ // requires setting "-f" twice, not sure how to do
+ // this with args4j, so this feature is unimplemented
+ // for now.
+ Set<String> removedFiles = git.clean().setCleanDirectories(dirs)
+ .setDryRun(dryRun).call();
+ for (String removedFile : removedFiles) {
+ outw.println(MessageFormat.format(CLIText.get().removing,
+ removedFile));
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
index 03f3fac..a7bdde9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
@@ -101,7 +101,7 @@
@Option(name = "--export-all", usage = "usage_exportWithoutGitDaemonExportOk")
boolean exportAll;
- @Option(name = "--ketch")
+ @Option(name = "--ketch", metaVar = "metaVar_ketchServerType", usage = "usage_ketchServerType")
KetchServerType ketchServerType;
enum KetchServerType {
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 33ea1de..98af186 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
@@ -108,6 +108,9 @@
@Option(name = "--dry-run")
private boolean dryRun;
+ @Option(name = "--push-option", aliases = { "-t" })
+ private List<String> pushOptions = new ArrayList<>();
+
private boolean shownURI;
@Override
@@ -127,6 +130,9 @@
push.setThin(thin);
push.setAtomic(atomic);
push.setTimeout(timeout);
+ if (!pushOptions.isEmpty()) {
+ push.setPushOptions(pushOptions);
+ }
Iterable<PushResult> results = push.call();
for (PushResult result : results) {
try (ObjectReader reader = db.newObjectReader()) {
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 45fceb5..dc4b037 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
@@ -68,6 +68,9 @@
@Option(name = "-f", usage = "usage_forceReplacingAnExistingTag")
private boolean force;
+ @Option(name = "-d", usage = "usage_tagDelete")
+ private boolean delete;
+
@Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage")
private String message = ""; //$NON-NLS-1$
@@ -81,19 +84,28 @@
protected void run() throws Exception {
try (Git git = new Git(db)) {
if (tagName != null) {
- TagCommand command = git.tag().setForceUpdate(force)
- .setMessage(message).setName(tagName);
-
- if (object != null) {
- try (RevWalk walk = new RevWalk(db)) {
- command.setObjectId(walk.parseAny(object));
+ if (delete) {
+ List<String> deletedTags = git.tagDelete().setTags(tagName)
+ .call();
+ if (deletedTags.isEmpty()) {
+ throw die(MessageFormat
+ .format(CLIText.get().tagNotFound, tagName));
}
- }
- try {
- command.call();
- } catch (RefAlreadyExistsException e) {
- throw die(MessageFormat.format(CLIText.get().tagAlreadyExists,
- tagName));
+ } else {
+ TagCommand command = git.tag().setForceUpdate(force)
+ .setMessage(message).setName(tagName);
+
+ 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();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
index 00bea86..c4d9548 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java
@@ -253,10 +253,10 @@
private static final long serialVersionUID = 1L;
@Override
- protected LargeFileRepository getLargeFileRepository() {
+ protected LargeFileRepository getLargeFileRepository(
+ LfsRequest request, String path) {
return repository;
}
-
};
app.addServlet(new ServletHolder(protocol), PROTOCOL_PATH);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
index e99fe00..90c03e9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -125,6 +125,7 @@
/***/ public String changesToBeCommitted;
/***/ public String checkoutConflict;
/***/ public String checkoutConflictPathLine;
+ /***/ public String cleanRequireForce;
/***/ public String clonedEmptyRepository;
/***/ public String cloningInto;
/***/ public String commitLabel;
@@ -246,6 +247,7 @@
/***/ public String remoteMessage;
/***/ public String remoteRefObjectChangedIsNotExpectedOne;
/***/ public String remoteSideDoesNotSupportDeletingRefs;
+ /***/ public String removing;
/***/ public String repaint;
/***/ public String s3InvalidBucket;
/***/ public String serviceNotSupported;
@@ -267,6 +269,7 @@
/***/ public String switchedToBranch;
/***/ public String tagAlreadyExists;
/***/ public String tagLabel;
+ /***/ public String tagNotFound;
/***/ public String taggerInfo;
/***/ public String timeInMilliSeconds;
/***/ public String tooManyRefsGiven;
diff --git a/org.eclipse.jgit.test/.project b/org.eclipse.jgit.test/.project
index a7ac51e..80bb7da 100644
--- a/org.eclipse.jgit.test/.project
+++ b/org.eclipse.jgit.test/.project
@@ -2,9 +2,6 @@
<projectDescription>
<name>org.eclipse.jgit.test</name>
<comment></comment>
- <projects>
- <project>org.eclipse.jgit.java7</project>
- </projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
index dcc0d3a..87210fb 100644
--- a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 12620de..a7b1fa8 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,52 +2,52 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
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.4.2,4.5.0)",
- org.eclipse.jgit.api.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.attributes;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.awtui;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.blame;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.diff;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.dircache;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.events;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.fnmatch;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.gitrepo;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.hooks;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.ignore;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.ignore.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.junit;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.merge;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.notes;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.patch;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.pgm;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.pgm.internal;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revplot;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.file;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.storage.pack;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.submodule;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.http;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport.resolver;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util.io;version="[4.4.2,4.5.0)",
+ org.eclipse.jgit.api;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.api.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.attributes;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.awtui;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.blame;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.diff;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.dircache;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.events;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.fnmatch;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.gitrepo;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.hooks;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.ignore;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.junit;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.merge;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.notes;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.patch;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.pgm;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revplot;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.file;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.storage.pack;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.submodule;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.http;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util.io;version="[4.5.5,4.6.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/build.properties b/org.eclipse.jgit.test/build.properties
index 786046c..e7b3b99 100644
--- a/org.eclipse.jgit.test/build.properties
+++ b/org.eclipse.jgit.test/build.properties
@@ -1,7 +1,9 @@
source.. = tst/,\
tst-rsrc/,\
- exttst/
+ exttst/,\
+ src/
bin.includes = META-INF/,\
.,\
plugin.properties
-additional.bundles = org.apache.log4j
+additional.bundles = org.apache.log4j,\
+ org.slf4j.impl.log4j12
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch"
new file mode 100644
index 0000000..86446f9
--- /dev/null
+++ "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051 \050de\051.launch"
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test/tst"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="2"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<mapAttribute key="org.eclipse.debug.core.environmentVariables">
+<mapEntry key="LANG" value="de_DE.UTF-8"/>
+</mapAttribute>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.test"/> </runtimeClasspathEntry> "/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 81a3b09..cd4b853 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java
index 7316857..4454e1a 100644
--- a/org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/lib/Sets.java
@@ -47,6 +47,7 @@
import java.util.Set;
public class Sets {
+ @SafeVarargs
public static <T> Set<T> of(T... elements) {
Set<T> ret = new HashSet<T>();
for (T element : elements)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 126ca5c..42601aa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -45,7 +45,6 @@
import static org.eclipse.jgit.util.FileUtils.RECURSIVE;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -136,6 +135,29 @@
}
@Test
+ public void testAttributesWithTreeWalkFilter()
+ throws IOException, GitAPIException {
+ writeTrashFile(".gitattributes", "*.txt filter=lfs");
+ writeTrashFile("src/a.tmp", "foo");
+ writeTrashFile("src/a.txt", "foo\n");
+ File script = writeTempFile("sed s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "lfs", "clean",
+ "sh " + slashify(script.getPath()));
+ config.save();
+
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("attr").call();
+ git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
+ .addFilepattern(".gitattributes").call();
+ git.commit().setMessage("c1").call();
+ assertTrue(git.status().call().isClean());
+ }
+ }
+
+ @Test
public void testCleanFilterEnvironment()
throws IOException, GitAPIException {
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
@@ -932,7 +954,11 @@
}
public boolean canExecute(File f) {
- return true;
+ try {
+ return read(f).startsWith("binary:");
+ } catch (IOException e) {
+ return false;
+ }
}
@Override
@@ -943,61 +969,40 @@
Git git = Git.open(db.getDirectory(), executableFs);
String path = "a.txt";
+ String path2 = "a.sh";
writeTrashFile(path, "content");
- git.add().addFilepattern(path).call();
+ writeTrashFile(path2, "binary: content");
+ git.add().addFilepattern(path).addFilepattern(path2).call();
RevCommit commit1 = git.commit().setMessage("commit").call();
- TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree());
- assertNotNull(walk);
- assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
-
- FS nonExecutableFs = new FS() {
-
- public boolean supportsExecute() {
- return false;
- }
-
- public boolean setExecute(File f, boolean canExec) {
- return false;
- }
-
- public ProcessBuilder runInShell(String cmd, String[] args) {
- return null;
- }
-
- public boolean retryFailedLockFileCommit() {
- return false;
- }
-
- public FS newInstance() {
- return this;
- }
-
- protected File discoverGitExe() {
- return null;
- }
-
- public boolean canExecute(File f) {
- return false;
- }
-
- @Override
- public boolean isCaseSensitive() {
- return false;
- }
- };
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(commit1.getTree());
+ walk.next();
+ assertEquals(path2, walk.getPathString());
+ assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
+ walk.next();
+ assertEquals(path, walk.getPathString());
+ assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
+ }
config = db.getConfig();
config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_FILEMODE, false);
config.save();
- Git git2 = Git.open(db.getDirectory(), nonExecutableFs);
- writeTrashFile(path, "content2");
- git2.add().addFilepattern(path).call();
+ Git git2 = Git.open(db.getDirectory(), executableFs);
+ writeTrashFile(path2, "content2");
+ writeTrashFile(path, "binary: content2");
+ git2.add().addFilepattern(path).addFilepattern(path2).call();
RevCommit commit2 = git2.commit().setMessage("commit2").call();
- walk = TreeWalk.forPath(db, path, commit2.getTree());
- assertNotNull(walk);
- assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(commit2.getTree());
+ walk.next();
+ assertEquals(path2, walk.getPathString());
+ assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
+ walk.next();
+ assertEquals(path, walk.getPathString());
+ assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
+ }
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
index 7cca4b9..68f5dd1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
@@ -45,13 +45,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
+import java.io.File;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
import org.junit.Before;
import org.junit.Test;
@@ -227,4 +230,69 @@
assertTrue(cleanedFiles.contains("ignored-dir/"));
}
+ @Test
+ public void testCleanDirsWithSubmodule() throws Exception {
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ command.setPath(path);
+ String uri = db.getDirectory().toURI().toString();
+ command.setURI(uri);
+ Repository repo = command.call();
+ repo.close();
+
+ Status beforeCleanStatus = git.status().call();
+ assertTrue(beforeCleanStatus.getAdded().contains(DOT_GIT_MODULES));
+ assertTrue(beforeCleanStatus.getAdded().contains(path));
+
+ Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
+
+ // The submodule should not be cleaned.
+ assertTrue(!cleanedFiles.contains(path + "/"));
+
+ assertTrue(cleanedFiles.contains("File2.txt"));
+ assertTrue(cleanedFiles.contains("File3.txt"));
+ assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+ assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+ assertTrue(cleanedFiles.contains("sub-clean/"));
+ assertTrue(cleanedFiles.size() == 4);
+ }
+
+ @Test
+ public void testCleanDirsWithRepository() throws Exception {
+ // Set up a repository inside the outer repository
+ String innerRepoName = "inner-repo";
+ File innerDir = new File(trash, innerRepoName);
+ innerDir.mkdir();
+ InitCommand initRepoCommand = new InitCommand();
+ initRepoCommand.setDirectory(innerDir);
+ initRepoCommand.call();
+
+ Status beforeCleanStatus = git.status().call();
+ Set<String> untrackedFolders = beforeCleanStatus.getUntrackedFolders();
+ Set<String> untrackedFiles = beforeCleanStatus.getUntracked();
+
+ // The inner repository should be listed as an untracked file
+ assertTrue(untrackedFiles.contains(innerRepoName));
+
+ // The inner repository should not be listed as an untracked folder
+ assertTrue(!untrackedFolders.contains(innerRepoName));
+
+ Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
+
+ // The inner repository should not be cleaned.
+ assertTrue(!cleanedFiles.contains(innerRepoName + "/"));
+
+ assertTrue(cleanedFiles.contains("File2.txt"));
+ assertTrue(cleanedFiles.contains("File3.txt"));
+ assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+ assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+ assertTrue(cleanedFiles.contains("sub-clean/"));
+ assertTrue(cleanedFiles.size() == 4);
+
+ Set<String> forceCleanedFiles = git.clean().setCleanDirectories(true)
+ .setForce(true).call();
+
+ // The inner repository should be cleaned this time
+ assertTrue(forceCleanedFiles.contains(innerRepoName + "/"));
+ }
}
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 ce11e1b..8a728ca 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
@@ -62,6 +62,7 @@
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -605,11 +606,10 @@
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertFalse(git2
- .getRepository()
- .getConfig()
- .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
- ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertNull(git2.getRepository().getConfig().getEnum(
+ BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, "test",
+ ConfigConstants.CONFIG_KEY_REBASE, null));
FileBasedConfig userConfig = SystemReader.getInstance().openUserConfig(
null, git.getRepository().getFS());
@@ -623,11 +623,12 @@
command.setURI(fileUri());
git2 = command.call();
addRepoToClose(git2.getRepository());
- assertTrue(git2
- .getRepository()
- .getConfig()
- .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
- ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertEquals(BranchRebaseMode.REBASE,
+ git2.getRepository().getConfig().getEnum(
+ BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, "test",
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
@@ -639,11 +640,12 @@
command.setURI(fileUri());
git2 = command.call();
addRepoToClose(git2.getRepository());
- assertTrue(git2
- .getRepository()
- .getConfig()
- .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
- ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertEquals(BranchRebaseMode.REBASE,
+ git2.getRepository().getConfig().getEnum(
+ BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, "test",
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 8a07118..ba84081 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -76,6 +76,7 @@
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.FS;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -291,6 +292,7 @@
}
}
+ @Ignore("very flaky when run with Hudson")
@Test
public void commitUpdatesSmudgedEntries() throws Exception {
try (Git git = new Git(db)) {
@@ -347,6 +349,7 @@
}
}
+ @Ignore("very flaky when run with Hudson")
@Test
public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
try (Git git = new Git(db)) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
index 3343af0..1250773 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
@@ -271,6 +271,7 @@
}
}
+ @Test
public void testCheckoutMixedNewlines() throws Exception {
// "git config core.autocrlf true"
StoredConfig config = git.getRepository().getConfig();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
index 181e4a1..4c09a82 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
@@ -43,11 +43,14 @@
package org.eclipse.jgit.api;
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.assertTrue;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.StoredConfig;
@@ -98,32 +101,40 @@
@Test
public void renameBranchSingleConfigValue() throws Exception {
StoredConfig config = git.getRepository().getConfig();
- config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, true);
+ config.setEnum(ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.REBASE);
config.save();
String branch = "b1";
- assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, true));
- assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- branch, ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertEquals(BranchRebaseMode.REBASE,
+ config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
+ assertNull(config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, branch,
+ ConfigConstants.CONFIG_KEY_REBASE, null));
assertNotNull(git.branchRename().setNewName(branch).call());
config = git.getRepository().getConfig();
- assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, false));
- assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- branch, ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertNull(config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE, null));
+ assertEquals(BranchRebaseMode.REBASE,
+ config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, branch,
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
}
@Test
public void renameBranchExistingSection() throws Exception {
String branch = "b1";
StoredConfig config = git.getRepository().getConfig();
- config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, true);
+ config.setEnum(ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.REBASE);
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
Constants.MASTER, "a", "a");
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branch, "a",
@@ -140,18 +151,22 @@
@Test
public void renameBranchMultipleConfigValues() throws Exception {
StoredConfig config = git.getRepository().getConfig();
- config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, true);
+ config.setEnum(ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.REBASE);
config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
Constants.MASTER, ConfigConstants.CONFIG_KEY_MERGE, true);
config.save();
String branch = "b1";
- assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, true));
- assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- branch, ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertEquals(BranchRebaseMode.REBASE,
+ config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
+ assertNull(config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, branch,
+ ConfigConstants.CONFIG_KEY_REBASE, null));
assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
Constants.MASTER, ConfigConstants.CONFIG_KEY_MERGE, true));
assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
@@ -160,10 +175,14 @@
assertNotNull(git.branchRename().setNewName(branch).call());
config = git.getRepository().getConfig();
- assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, false));
- assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- branch, ConfigConstants.CONFIG_KEY_REBASE, false));
+ assertNull(config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER,
+ ConfigConstants.CONFIG_KEY_REBASE, null));
+ assertEquals(BranchRebaseMode.REBASE,
+ config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, branch,
+ ConfigConstants.CONFIG_KEY_REBASE,
+ BranchRebaseMode.NONE));
assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
Constants.MASTER, ConfigConstants.CONFIG_KEY_MERGE, false));
assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index a4a699e..ba51881 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -157,6 +157,28 @@
}
@Test
+ public void testHardResetReflogDisabled() throws Exception {
+ setupRepository();
+ ObjectId prevHead = db.resolve(Constants.HEAD);
+ ResetCommand reset = git.reset();
+ assertSameAsHead(reset.setMode(ResetType.HARD)
+ .setRef(initialCommit.getName()).disableRefLog(true).call());
+ assertTrue("reflog should be disabled", reset.isReflogDisabled());
+ // check if HEAD points to initial commit now
+ ObjectId head = db.resolve(Constants.HEAD);
+ assertEquals(initialCommit, head);
+ // check if files were removed
+ assertFalse(indexFile.exists());
+ assertTrue(untrackedFile.exists());
+ // fileInIndex must no longer be in HEAD and in the index
+ String fileInIndexPath = indexFile.getAbsolutePath();
+ assertFalse(inHead(fileInIndexPath));
+ assertFalse(inIndex(indexFile.getName()));
+ assertReflogDisabled(head);
+ assertEquals(prevHead, db.readOrigHead());
+ }
+
+ @Test
public void testHardResetWithConflicts_DoOverWriteUntrackedFile()
throws JGitInternalException,
AmbiguousObjectException, IOException, GitAPIException {
@@ -562,6 +584,24 @@
.getName());
}
+ private void assertReflogDisabled(ObjectId head)
+ throws IOException {
+ // Check the reflog for HEAD
+ String actualHeadMessage = db.getReflogReader(Constants.HEAD)
+ .getLastEntry().getComment();
+ String expectedHeadMessage = "commit: adding a.txt and dir/b.txt";
+ assertEquals(expectedHeadMessage, actualHeadMessage);
+ assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
+ .getLastEntry().getOldId().getName());
+
+ // The reflog for master contains the same as the one for HEAD
+ String actualMasterMessage = db.getReflogReader("refs/heads/master")
+ .getLastEntry().getComment();
+ String expectedMasterMessage = "commit: adding a.txt and dir/b.txt";
+ assertEquals(expectedMasterMessage, actualMasterMessage);
+ assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
+ .getLastEntry().getOldId().getName());
+ }
/**
* Checks if a file with the given path exists in the HEAD tree
*
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java
index d8a6174..a6e48fe 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java
@@ -47,6 +47,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import org.eclipse.jgit.ignore.internal.Strings;
import org.junit.Test;
public class BasicRuleTest {
@@ -73,4 +74,31 @@
assertNotEquals(rule1.toString(), rule3.toString());
}
+ @Test
+ public void testDirectoryPattern() {
+ assertTrue(Strings.isDirectoryPattern("/"));
+ assertTrue(Strings.isDirectoryPattern("/ "));
+ assertTrue(Strings.isDirectoryPattern("/ "));
+ assertFalse(Strings.isDirectoryPattern(" "));
+ assertFalse(Strings.isDirectoryPattern(""));
+ }
+
+ @Test
+ public void testStripTrailingChar() {
+ assertEquals("", Strings.stripTrailing("/", '/'));
+ assertEquals("", Strings.stripTrailing("///", '/'));
+ assertEquals("a", Strings.stripTrailing("a/", '/'));
+ assertEquals("a", Strings.stripTrailing("a///", '/'));
+ assertEquals("a/ ", Strings.stripTrailing("a/ ", '/'));
+ }
+
+ @Test
+ public void testStripTrailingWhitespace() {
+ assertEquals("", Strings.stripTrailingWhitespace(""));
+ assertEquals("", Strings.stripTrailingWhitespace(" "));
+ assertEquals("a", Strings.stripTrailingWhitespace("a"));
+ assertEquals("a", Strings.stripTrailingWhitespace("a "));
+ assertEquals("a", Strings.stripTrailingWhitespace("a "));
+ assertEquals("a", Strings.stripTrailingWhitespace("a \t"));
+ }
}
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 480e326..1863b80 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
@@ -123,6 +123,17 @@
}
@Test
+ public void testTrailingSpaces() {
+ assertMatched("a ", "a");
+ assertMatched("a/ ", "a/");
+ assertMatched("a/ ", "a/b");
+ assertMatched("a/\\ ", "a/ ");
+ assertNotMatched("a/\\ ", "a/");
+ assertNotMatched("a/\\ ", "a/b");
+ assertNotMatched("/ ", "a");
+ }
+
+ @Test
public void testAsteriskDot() {
assertMatched("*.a", ".a");
assertMatched("*.a", "/.a");
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 c026efc..4a7dcd5 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
@@ -480,8 +480,9 @@
writeTrashFile("a/a", "");
writeTrashFile("a/a ", "");
writeTrashFile("a/a ", "");
+ writeTrashFile("b/c", "");
- writeIgnoreFile(".gitignore", "a\\ ", "a \\ ");
+ writeIgnoreFile(".gitignore", "a\\ ", "a \\ ", "b/ ");
beginWalk();
assertEntry(F, tracked, ".gitignore");
@@ -497,6 +498,8 @@
assertEntry(F, tracked, "a/a");
assertEntry(F, ignored, "a/a ");
assertEntry(F, ignored, "a/a ");
+ assertEntry(D, ignored, "b");
+ assertEntry(F, ignored, "b/c");
endWalk();
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
new file mode 100644
index 0000000..c7125bb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
@@ -0,0 +1,239 @@
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE;
+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.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DfsGarbageCollectorTest {
+ private TestRepository<InMemoryRepository> git;
+ private InMemoryRepository repo;
+ private DfsObjDatabase odb;
+
+ @Before
+ public void setUp() throws IOException {
+ DfsRepositoryDescription desc = new DfsRepositoryDescription("test");
+ git = new TestRepository<>(new InMemoryRepository(desc));
+ repo = git.getRepository();
+ odb = repo.getObjectDatabase();
+ }
+
+ @Test
+ public void testCollectionWithNoGarbage() throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("master", commit1);
+
+ assertTrue("commit0 reachable", isReachable(repo, commit0));
+ assertTrue("commit1 reachable", isReachable(repo, commit1));
+
+ // Packs start out as INSERT.
+ assertEquals(2, odb.getPacks().length);
+ for (DfsPackFile pack : odb.getPacks()) {
+ assertEquals(INSERT, pack.getPackDescription().getPackSource());
+ }
+
+ gcNoTtl();
+
+ // Single GC pack present with all objects.
+ assertEquals(1, odb.getPacks().length);
+ DfsPackFile pack = odb.getPacks()[0];
+ assertEquals(GC, pack.getPackDescription().getPackSource());
+ assertTrue("commit0 in pack", isObjectInPack(commit0, pack));
+ assertTrue("commit1 in pack", isObjectInPack(commit1, pack));
+ }
+
+ @Test
+ public void testCollectionWithGarbage() throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("master", commit0);
+
+ assertTrue("commit0 reachable", isReachable(repo, commit0));
+ assertFalse("commit1 garbage", isReachable(repo, commit1));
+ gcNoTtl();
+
+ assertEquals(2, odb.getPacks().length);
+ DfsPackFile gc = null;
+ DfsPackFile garbage = null;
+ for (DfsPackFile pack : odb.getPacks()) {
+ DfsPackDescription d = pack.getPackDescription();
+ if (d.getPackSource() == GC) {
+ gc = pack;
+ } else if (d.getPackSource() == UNREACHABLE_GARBAGE) {
+ garbage = pack;
+ } else {
+ fail("unexpected " + d.getPackSource());
+ }
+ }
+
+ assertNotNull("created GC pack", gc);
+ assertTrue(isObjectInPack(commit0, gc));
+
+ assertNotNull("created UNREACHABLE_GARBAGE pack", garbage);
+ assertTrue(isObjectInPack(commit1, garbage));
+ }
+
+ @Test
+ public void testCollectionWithGarbageAndGarbagePacksPurged()
+ throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("master", commit0);
+
+ gcNoTtl();
+ gcWithTtl();
+
+ // The repository has an UNREACHABLE_GARBAGE pack that could have
+ // expired, but since we never purge the most recent UNREACHABLE_GARBAGE
+ // pack, it must have survived the GC.
+ boolean commit1Found = false;
+ for (DfsPackFile pack : odb.getPacks()) {
+ DfsPackDescription d = pack.getPackDescription();
+ if (d.getPackSource() == GC) {
+ assertTrue("has commit0", isObjectInPack(commit0, pack));
+ assertFalse("no commit1", isObjectInPack(commit1, pack));
+ } else if (d.getPackSource() == UNREACHABLE_GARBAGE) {
+ commit1Found |= isObjectInPack(commit1, pack);
+ } else {
+ fail("unexpected " + d.getPackSource());
+ }
+ }
+ assertTrue("garbage commit1 still readable", commit1Found);
+
+ // Find oldest UNREACHABLE_GARBAGE; it will be pruned by next GC.
+ DfsPackDescription oldestGarbagePack = null;
+ for (DfsPackFile pack : odb.getPacks()) {
+ DfsPackDescription d = pack.getPackDescription();
+ if (d.getPackSource() == UNREACHABLE_GARBAGE) {
+ oldestGarbagePack = oldestPack(oldestGarbagePack, d);
+ }
+ }
+ assertNotNull("has UNREACHABLE_GARBAGE", oldestGarbagePack);
+
+ gcWithTtl();
+ assertTrue("has packs", odb.getPacks().length > 0);
+ for (DfsPackFile pack : odb.getPacks()) {
+ assertNotEquals(oldestGarbagePack, pack.getPackDescription());
+ }
+ }
+
+ @Test
+ public void testCollectionWithGarbageCoalescence() throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("master", commit0);
+
+ for (int i = 0; i < 3; i++) {
+ commit1 = commit().message("g" + i).parent(commit1).create();
+
+ // Make sure we don't have more than 1 UNREACHABLE_GARBAGE pack
+ // because they're coalesced.
+ gcNoTtl();
+ assertEquals(1, countPacks(UNREACHABLE_GARBAGE));
+ }
+ }
+
+ @Test
+ public void testCollectionWithGarbageNoCoalescence() throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("master", commit0);
+
+ for (int i = 0; i < 3; i++) {
+ commit1 = commit().message("g" + i).parent(commit1).create();
+
+ DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+ gc.setCoalesceGarbageLimit(0);
+ gc.setGarbageTtl(0, TimeUnit.MILLISECONDS);
+ run(gc);
+ assertEquals(1 + i, countPacks(UNREACHABLE_GARBAGE));
+ }
+ }
+
+ private TestRepository<InMemoryRepository>.CommitBuilder commit() {
+ return git.commit();
+ }
+
+ private void gcNoTtl() throws IOException {
+ DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+ gc.setGarbageTtl(0, TimeUnit.MILLISECONDS); // disable TTL
+ run(gc);
+ }
+
+ private void gcWithTtl() throws InterruptedException, IOException {
+ // Wait for the system clock to move by at least 1 millisecond.
+ // This allows the DfsGarbageCollector to recognize the boundary.
+ long start = System.currentTimeMillis();
+ do {
+ Thread.sleep(10);
+ } while (System.currentTimeMillis() <= start);
+
+ DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+ gc.setGarbageTtl(1, TimeUnit.MILLISECONDS);
+ run(gc);
+ }
+
+ private void run(DfsGarbageCollector gc) throws IOException {
+ assertTrue("gc repacked", gc.pack(null));
+ odb.clearCache();
+ }
+
+ private static boolean isReachable(Repository repo, AnyObjectId id)
+ throws IOException {
+ try (RevWalk rw = new RevWalk(repo)) {
+ for (Ref ref : repo.getAllRefs().values()) {
+ rw.markStart(rw.parseCommit(ref.getObjectId()));
+ }
+ for (RevCommit next; (next = rw.next()) != null;) {
+ if (AnyObjectId.equals(next, id)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isObjectInPack(AnyObjectId id, DfsPackFile pack)
+ throws IOException {
+ try (DfsReader reader = new DfsReader(odb)) {
+ return pack.hasObject(reader, id);
+ }
+ }
+
+ private static DfsPackDescription oldestPack(DfsPackDescription a,
+ DfsPackDescription b) {
+ if (a != null && a.getLastModified() < b.getLastModified()) {
+ return a;
+ }
+ return b;
+ }
+
+ private int countPacks(PackSource source) throws IOException {
+ int cnt = 0;
+ for (DfsPackFile pack : odb.getPacks()) {
+ if (pack.getPackDescription().getPackSource() == source) {
+ cnt++;
+ }
+ }
+ return cnt;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
index 74790f7..b738f7e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
@@ -219,6 +219,37 @@
assertTrue(pack_sources.contains(PackSource.INSERT));
}
+ @Test
+ public void testNoCheckExisting() throws IOException {
+ byte[] contents = Constants.encode("foo");
+ ObjectId fooId;
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ fooId = ins.insert(Constants.OBJ_BLOB, contents);
+ ins.flush();
+ }
+ assertEquals(1, db.getObjectDatabase().listPacks().size());
+
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ ((DfsInserter) ins).checkExisting(false);
+ assertEquals(fooId, ins.insert(Constants.OBJ_BLOB, contents));
+ ins.flush();
+ }
+ assertEquals(2, db.getObjectDatabase().listPacks().size());
+
+ // Verify that we have a foo in both INSERT packs.
+ DfsReader reader = new DfsReader(db.getObjectDatabase());
+ DfsPackFile packs[] = db.getObjectDatabase().getPacks();
+
+ assertEquals(2, packs.length);
+ DfsPackFile p1 = packs[0];
+ assertEquals(PackSource.INSERT, p1.getPackDescription().getPackSource());
+ assertTrue(p1.hasObject(reader, fooId));
+
+ DfsPackFile p2 = packs[1];
+ assertEquals(PackSource.INSERT, p2.getPackDescription().getPackSource());
+ assertTrue(p2.hasObject(reader, fooId));
+ }
+
private static String readString(ObjectLoader loader) throws IOException {
return RawParseUtils.decode(readStream(loader));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
index 07a7be7..776226b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
@@ -45,8 +45,12 @@
import static java.lang.Integer.valueOf;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
@@ -56,8 +60,14 @@
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.EmptyProgressMonitor;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
public class GcConcurrentTest extends GcTestCase {
@@ -116,4 +126,97 @@
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
}
+
+ @Test
+ public void repackAndGetStats() throws Exception {
+ TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
+ test.commit().add("a", "a").create();
+ GC gc1 = new GC(tr.getRepository());
+ gc1.setPackExpireAgeMillis(0);
+ gc1.gc();
+ test.commit().add("b", "b").create();
+
+ // Create a new Repository instance and trigger a gc
+ // from that instance. Reusing the existing repo instance
+ // tr.getRepository() would not show the problem.
+ FileRepository r2 = new FileRepository(
+ tr.getRepository().getDirectory());
+ GC gc2 = new GC(r2);
+ gc2.setPackExpireAgeMillis(0);
+ gc2.gc();
+
+ new GC(tr.getRepository()).getStatistics();
+ }
+
+ @Test
+ public void repackAndUploadPack() throws Exception {
+ TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
+ // RevCommit a = test.commit().add("a", "a").create();
+ test.commit().add("a", "a").create();
+
+ GC gc1 = new GC(tr.getRepository());
+ gc1.setPackExpireAgeMillis(0);
+ gc1.gc();
+
+ RevCommit b = test.commit().add("b", "b").create();
+
+ FileRepository r2 = new FileRepository(
+ tr.getRepository().getDirectory());
+ GC gc2 = new GC(r2);
+ gc2.setPackExpireAgeMillis(0);
+ gc2.gc();
+
+ // Simulate parts of an UploadPack. This is the situation on
+ // server side (e.g. gerrit) when when clients are
+ // cloning/fetching while the server side repo's
+ // are gc'ed by an external process (e.g. scheduled
+ // native git gc)
+ try (PackWriter pw = new PackWriter(tr.getRepository())) {
+ pw.setUseBitmaps(true);
+ pw.preparePack(NullProgressMonitor.INSTANCE, Sets.of(b),
+ Collections.<ObjectId> emptySet());
+ new GC(tr.getRepository()).getStatistics();
+ }
+ }
+
+ PackFile getSinglePack(FileRepository r) {
+ Collection<PackFile> packs = r.getObjectDatabase().getPacks();
+ assertEquals(1, packs.size());
+ return packs.iterator().next();
+ }
+
+ @Test
+ public void repackAndCheckBitmapUsage() throws Exception {
+ // create a test repository with one commit and pack all objects. After
+ // packing create loose objects to trigger creation of a new packfile on
+ // the next gc
+ TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
+ test.commit().add("a", "a").create();
+ FileRepository repository = tr.getRepository();
+ GC gc1 = new GC(repository);
+ gc1.setPackExpireAgeMillis(0);
+ gc1.gc();
+ String oldPackName = getSinglePack(repository).getPackName();
+ RevCommit b = test.commit().add("b", "b").create();
+
+ // start the garbage collection on a new repository instance,
+ FileRepository repository2 = new FileRepository(repository.getDirectory());
+ GC gc2 = new GC(repository2);
+ gc2.setPackExpireAgeMillis(0);
+ gc2.gc();
+ String newPackName = getSinglePack(repository2).getPackName();
+ // make sure gc() has caused creation of a new packfile
+ assertNotEquals(oldPackName, newPackName);
+
+ // Even when asking again for the set of packfiles outdated data
+ // will be returned. As long as the repository can work on cached data
+ // it will do so and not detect that a new packfile exists.
+ assertNotEquals(getSinglePack(repository).getPackName(), newPackName);
+
+ // Only when accessing object content it is required to rescan the pack
+ // directory and the new packfile will be detected.
+ repository.getObjectDatabase().open(b).getSize();
+ assertEquals(getSinglePack(repository).getPackName(), newPackName);
+ assertNotNull(getSinglePack(repository).getBitmapIndex());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
index 5abf625..e463285 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
@@ -105,8 +105,9 @@
return tip;
}
- protected long lastModified(AnyObjectId objectId) {
- return repo.getObjectDatabase().fileFor(objectId).lastModified();
+ protected long lastModified(AnyObjectId objectId) throws IOException {
+ return repo.getFS().lastModified(
+ repo.getObjectDatabase().fileFor(objectId));
}
protected static void fsTick() throws InterruptedException, IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 63a3072..3cb4c39 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -75,6 +75,10 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Sets;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.DepthWalk;
+import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
@@ -92,6 +96,9 @@
private static final List<RevObject> EMPTY_LIST_REVS = Collections
.<RevObject> emptyList();
+ private static final Set<ObjectIdSet> EMPTY_ID_SET = Collections
+ .<ObjectIdSet> emptySet();
+
private PackConfig config;
private PackWriter writer;
@@ -104,6 +111,26 @@
private FileRepository dst;
+ private RevBlob contentA;
+
+ private RevBlob contentB;
+
+ private RevBlob contentC;
+
+ private RevBlob contentD;
+
+ private RevBlob contentE;
+
+ private RevCommit c1;
+
+ private RevCommit c2;
+
+ private RevCommit c3;
+
+ private RevCommit c4;
+
+ private RevCommit c5;
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -202,8 +229,7 @@
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
try {
- createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
- false, false);
+ createVerifyOpenPack(NONE, haves(nonExisting), false, false);
fail("Should have thrown MissingObjectException");
} catch (MissingObjectException x) {
// expected
@@ -219,8 +245,7 @@
public void testIgnoreNonExistingObjects() throws IOException {
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
- createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
- false, true);
+ createVerifyOpenPack(NONE, haves(nonExisting), false, true);
// shouldn't throw anything
}
@@ -238,8 +263,7 @@
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
new GC(db).gc();
- createVerifyOpenPack(NONE, Collections.singleton(nonExisting), false,
- true, true);
+ createVerifyOpenPack(NONE, haves(nonExisting), false, true, true);
// shouldn't throw anything
}
@@ -513,20 +537,18 @@
TestRepository<FileRepository> testRepo = new TestRepository<FileRepository>(
repo);
BranchBuilder bb = testRepo.branch("refs/heads/master");
- RevBlob contentA = testRepo.blob("A");
- RevCommit c1 = bb.commit().add("f", contentA).create();
+ contentA = testRepo.blob("A");
+ c1 = bb.commit().add("f", contentA).create();
testRepo.getRevWalk().parseHeaders(c1);
- PackIndex pf1 = writePack(repo, Collections.singleton(c1),
- Collections.<ObjectIdSet> emptySet());
+ PackIndex pf1 = writePack(repo, wants(c1), EMPTY_ID_SET);
assertContent(
pf1,
Arrays.asList(c1.getId(), c1.getTree().getId(),
contentA.getId()));
- RevBlob contentB = testRepo.blob("B");
- RevCommit c2 = bb.commit().add("f", contentB).create();
+ contentB = testRepo.blob("B");
+ c2 = bb.commit().add("f", contentB).create();
testRepo.getRevWalk().parseHeaders(c2);
- PackIndex pf2 = writePack(repo, Collections.singleton(c2),
- Collections.<ObjectIdSet> singleton(pf1));
+ PackIndex pf2 = writePack(repo, wants(c2), Sets.of((ObjectIdSet) pf1));
assertContent(
pf2,
Arrays.asList(c2.getId(), c2.getTree().getId(),
@@ -543,15 +565,149 @@
expected.contains(pi.getObjectId(i)));
}
+ @Test
+ public void testShallowIsMinimalDepth1() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 1, wants(c2), NONE, NONE);
+ assertContent(idx, Arrays.asList(c2.getId(), c2.getTree().getId(),
+ contentA.getId(), contentB.getId()));
+
+ // Client already has blobs A and B, verify those are not packed.
+ idx = writeShallowPack(repo, 1, wants(c5), haves(c2), shallows(c2));
+ assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(),
+ contentC.getId(), contentD.getId(), contentE.getId()));
+ }
+
+ @Test
+ public void testShallowIsMinimalDepth2() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 2, wants(c2), NONE, NONE);
+ assertContent(idx,
+ Arrays.asList(c1.getId(), c2.getId(), c1.getTree().getId(),
+ c2.getTree().getId(), contentA.getId(),
+ contentB.getId()));
+
+ // Client already has blobs A and B, verify those are not packed.
+ idx = writeShallowPack(repo, 2, wants(c5), haves(c1, c2), shallows(c1));
+ assertContent(idx,
+ Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
+ c5.getTree().getId(), contentC.getId(),
+ contentD.getId(), contentE.getId()));
+ }
+
+ @Test
+ public void testShallowFetchShallowParentDepth1() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE);
+ assertContent(idx,
+ Arrays.asList(c5.getId(), c5.getTree().getId(),
+ contentA.getId(), contentB.getId(), contentC.getId(),
+ contentD.getId(), contentE.getId()));
+
+ idx = writeShallowPack(repo, 1, wants(c4), haves(c5), shallows(c5));
+ assertContent(idx, Arrays.asList(c4.getId(), c4.getTree().getId()));
+ }
+
+ @Test
+ public void testShallowFetchShallowParentDepth2() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE);
+ assertContent(idx,
+ Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
+ c5.getTree().getId(), contentA.getId(),
+ contentB.getId(), contentC.getId(), contentD.getId(),
+ contentE.getId()));
+
+ idx = writeShallowPack(repo, 2, wants(c3), haves(c4, c5), shallows(c4));
+ assertContent(idx, Arrays.asList(c2.getId(), c3.getId(),
+ c2.getTree().getId(), c3.getTree().getId()));
+ }
+
+ @Test
+ public void testShallowFetchShallowAncestorDepth1() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE);
+ assertContent(idx,
+ Arrays.asList(c5.getId(), c5.getTree().getId(),
+ contentA.getId(), contentB.getId(), contentC.getId(),
+ contentD.getId(), contentE.getId()));
+
+ idx = writeShallowPack(repo, 1, wants(c3), haves(c5), shallows(c5));
+ assertContent(idx, Arrays.asList(c3.getId(), c3.getTree().getId()));
+ }
+
+ @Test
+ public void testShallowFetchShallowAncestorDepth2() throws Exception {
+ FileRepository repo = setupRepoForShallowFetch();
+
+ PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE);
+ assertContent(idx,
+ Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(),
+ c5.getTree().getId(), contentA.getId(),
+ contentB.getId(), contentC.getId(), contentD.getId(),
+ contentE.getId()));
+
+ idx = writeShallowPack(repo, 2, wants(c2), haves(c4, c5), shallows(c4));
+ assertContent(idx, Arrays.asList(c1.getId(), c2.getId(),
+ c1.getTree().getId(), c2.getTree().getId()));
+ }
+
+ private FileRepository setupRepoForShallowFetch() throws Exception {
+ FileRepository repo = createBareRepository();
+ TestRepository<Repository> r = new TestRepository<Repository>(repo);
+ BranchBuilder bb = r.branch("refs/heads/master");
+ contentA = r.blob("A");
+ contentB = r.blob("B");
+ contentC = r.blob("C");
+ contentD = r.blob("D");
+ contentE = r.blob("E");
+ c1 = bb.commit().add("a", contentA).create();
+ c2 = bb.commit().add("b", contentB).create();
+ c3 = bb.commit().add("c", contentC).create();
+ c4 = bb.commit().add("d", contentD).create();
+ c5 = bb.commit().add("e", contentE).create();
+ r.getRevWalk().parseHeaders(c5); // fully initialize the tip RevCommit
+ return repo;
+ }
+
private static PackIndex writePack(FileRepository repo,
Set<? extends ObjectId> want, Set<ObjectIdSet> excludeObjects)
- throws IOException {
+ throws IOException {
+ RevWalk walk = new RevWalk(repo);
+ return writePack(repo, walk, 0, want, NONE, excludeObjects);
+ }
+
+ private static PackIndex writeShallowPack(FileRepository repo, int depth,
+ Set<? extends ObjectId> want, Set<? extends ObjectId> have,
+ Set<? extends ObjectId> shallow) throws IOException {
+ // During negotiation, UploadPack would have set up a DepthWalk and
+ // marked the client's "shallow" commits. Emulate that here.
+ DepthWalk.RevWalk walk = new DepthWalk.RevWalk(repo, depth - 1);
+ walk.assumeShallow(shallow);
+ return writePack(repo, walk, depth, want, have, EMPTY_ID_SET);
+ }
+
+ private static PackIndex writePack(FileRepository repo, RevWalk walk,
+ int depth, Set<? extends ObjectId> want,
+ Set<? extends ObjectId> have, Set<ObjectIdSet> excludeObjects)
+ throws IOException {
try (PackWriter pw = new PackWriter(repo)) {
pw.setDeltaBaseAsOffset(true);
pw.setReuseDeltaCommits(false);
- for (ObjectIdSet idx : excludeObjects)
+ for (ObjectIdSet idx : excludeObjects) {
pw.excludeObjects(idx);
- pw.preparePack(NullProgressMonitor.INSTANCE, want, NONE);
+ }
+ if (depth > 0) {
+ pw.setShallowPack(depth, null);
+ }
+ ObjectWalk ow = walk.toObjectWalkWithSameObjects();
+
+ pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have);
String id = pw.computeName().getName();
File packdir = new File(repo.getObjectsDirectory(), "pack");
File packFile = new File(packdir, "pack-" + id + ".pack");
@@ -730,4 +886,16 @@
assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId());
}
}
+
+ private static Set<ObjectId> haves(ObjectId... objects) {
+ return Sets.of(objects);
+ }
+
+ private static Set<ObjectId> wants(ObjectId... objects) {
+ return Sets.of(objects);
+ }
+
+ private static Set<ObjectId> shallows(ObjectId... objects) {
+ return Sets.of(objects);
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
index 8b54dab..b7027f3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
@@ -62,6 +62,7 @@
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
@@ -374,6 +375,44 @@
assertEquals(head, repo.exactRef("HEAD").getObjectId());
}
+ @Test
+ public void reattachToMaster_Race() throws Exception {
+ RevCommit commit = tr.branch("master").commit().create();
+ tr.branch("master").update(commit);
+ tr.branch("other").update(commit);
+ repo.updateRef("HEAD").link("refs/heads/master");
+
+ // Create a detached HEAD that is not an .
+ tr.reset(commit);
+ Ref head = repo.exactRef("HEAD");
+ assertEquals(commit, head.getObjectId());
+ assertFalse(head.isSymbolic());
+
+ // Try to reattach to master.
+ RefUpdate refUpdate = repo.updateRef("HEAD");
+
+ // Make a change during reattachment.
+ repo.updateRef("HEAD").link("refs/heads/other");
+
+ assertEquals(
+ RefUpdate.Result.LOCK_FAILURE, refUpdate.link("refs/heads/master"));
+ }
+
+ @Test
+ public void nonRacingChange() throws Exception {
+ tr.branch("master").update(tr.branch("master").commit().create());
+ tr.branch("other").update(tr.branch("other").commit().create());
+ repo.updateRef("HEAD").link("refs/heads/master");
+
+ // Try to update HEAD.
+ RefUpdate refUpdate = repo.updateRef("HEAD");
+
+ // Proceed a master. This should not affect changing HEAD.
+ tr.branch("master").update(tr.branch("master").commit().create());
+
+ assertEquals(RefUpdate.Result.FORCED, refUpdate.link("refs/heads/other"));
+ }
+
private String blobAsString(AnyObjectId treeish, String path)
throws Exception {
RevObject obj = tr.get(rw.parseTree(treeish), path);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index fbe7dd0..bb553a4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -1614,6 +1614,64 @@
assertNotNull(git.checkout().setName(Constants.MASTER).call());
}
+ @Test(expected = CheckoutConflictException.class)
+ public void testFolderFileConflict() throws Exception {
+ RevCommit headCommit = commitFile("f/a", "initial content", "master");
+ RevCommit checkoutCommit = commitFile("f/a", "side content", "side");
+ FileUtils.delete(new File(db.getWorkTree(), "f"), FileUtils.RECURSIVE);
+ writeTrashFile("f", "file instead of folder");
+ new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
+ checkoutCommit.getTree()).checkout();
+ }
+
+ @Test
+ public void testMultipleContentConflicts() throws Exception {
+ commitFile("a", "initial content", "master");
+ RevCommit headCommit = commitFile("b", "initial content", "master");
+ commitFile("a", "side content", "side");
+ RevCommit checkoutCommit = commitFile("b", "side content", "side");
+ writeTrashFile("a", "changed content");
+ writeTrashFile("b", "changed content");
+
+ try {
+ new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
+ checkoutCommit.getTree()).checkout();
+ fail();
+ } catch (CheckoutConflictException expected) {
+ assertEquals(2, expected.getConflictingFiles().length);
+ assertTrue(Arrays.asList(expected.getConflictingFiles())
+ .contains("a"));
+ assertTrue(Arrays.asList(expected.getConflictingFiles())
+ .contains("b"));
+ assertEquals("changed content", read("a"));
+ assertEquals("changed content", read("b"));
+ }
+ }
+
+ @Test
+ public void testFolderFileAndContentConflicts() throws Exception {
+ RevCommit headCommit = commitFile("f/a", "initial content", "master");
+ commitFile("b", "side content", "side");
+ RevCommit checkoutCommit = commitFile("f/a", "side content", "side");
+ FileUtils.delete(new File(db.getWorkTree(), "f"), FileUtils.RECURSIVE);
+ writeTrashFile("f", "file instead of a folder");
+ writeTrashFile("b", "changed content");
+
+ try {
+ new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
+ checkoutCommit.getTree()).checkout();
+ fail();
+ } catch (CheckoutConflictException expected) {
+ assertEquals(2, expected.getConflictingFiles().length);
+ assertTrue(Arrays.asList(expected.getConflictingFiles())
+ .contains("b"));
+ assertTrue(Arrays.asList(expected.getConflictingFiles())
+ .contains("f"));
+ assertEquals("file instead of a folder", read("f"));
+ assertEquals("changed content", read("b"));
+ }
+ }
+
public void assertWorkDir(Map<String, String> i)
throws CorruptObjectException,
IOException {
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 6bea320..b44b4c3 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
@@ -210,6 +210,27 @@
}
@Test
+ public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
+ throws Exception {
+ Repository repoA = createBareRepository();
+ RepositoryCache.register(repoA);
+
+ assertEquals(1, RepositoryCache.getRegisteredKeys().size());
+ assertTrue(RepositoryCache.isCached(repoA));
+
+ // close the repo twice to make usage count negative
+ repoA.close();
+ repoA.close();
+ // fake that repoA was closed more than 1 hour ago (default expiration
+ // time)
+ repoA.closedAt.set(System.currentTimeMillis() - 65 * 60 * 1000);
+
+ RepositoryCache.clearExpired();
+
+ assertEquals(0, RepositoryCache.getRegisteredKeys().size());
+ }
+
+ @Test
public void testRepositoryUnregisteringWhenExpired() throws Exception {
Repository repoA = createBareRepository();
Repository repoB = createBareRepository();
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 55bb93a..a08dbbc 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
@@ -62,6 +62,7 @@
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Assert;
import org.junit.experimental.theories.DataPoint;
@@ -694,7 +695,7 @@
// Create initial content and remember when the last file was written.
f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
- lastTs4 = f.lastModified();
+ lastTs4 = FS.DETECTED.lastModified(f);
// add all files, commit and check this doesn't update any working tree
// files and that the index is in a new file system timer tick. Make
@@ -707,8 +708,8 @@
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "2", "3", "4", "<.git/index");
assertEquals("Commit should not touch working tree file 4", lastTs4,
- new File(db.getWorkTree(), "4").lastModified());
- lastTsIndex = indexFile.lastModified();
+ FS.DETECTED.lastModified(new File(db.getWorkTree(), "4")));
+ lastTsIndex = FS.DETECTED.lastModified(indexFile);
// Do modifications on the master branch. Then add and commit. This
// should touch only "0", "2 and "3"
@@ -722,7 +723,7 @@
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<0", "2", "3", "<.git/index");
- lastTsIndex = indexFile.lastModified();
+ lastTsIndex = FS.DETECTED.lastModified(indexFile);
// Checkout a side branch. This should touch only "0", "2 and "3"
fsTick(indexFile);
@@ -731,7 +732,7 @@
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<0", "2", "3", ".git/index");
- lastTsIndex = indexFile.lastModified();
+ lastTsIndex = FS.DETECTED.lastModified(indexFile);
// This checkout may have populated worktree and index so fast that we
// may have smudged entries now. Check that we have the right content
@@ -744,13 +745,13 @@
indexState(CONTENT));
fsTick(indexFile);
f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
- lastTs4 = f.lastModified();
+ lastTs4 = FS.DETECTED.lastModified(f);
fsTick(f);
git.add().addFilepattern(".").call();
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("*" + lastTsIndex, "<0", "1", "2", "3",
"4", "<.git/index");
- lastTsIndex = indexFile.lastModified();
+ lastTsIndex = FS.DETECTED.lastModified(indexFile);
// Do modifications on the side branch. Touch only "1", "2 and "3"
fsTick(indexFile);
@@ -761,7 +762,7 @@
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("0", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<1", "2", "3", "<.git/index");
- lastTsIndex = indexFile.lastModified();
+ lastTsIndex = FS.DETECTED.lastModified(indexFile);
// merge master and side. Should only touch "0," "2" and "3"
fsTick(indexFile);
@@ -789,7 +790,7 @@
"IndexEntry with path "
+ path
+ " has lastmodified with is different from the worktree file",
- new File(workTree, path).lastModified(), dc.getEntry(path)
+ FS.DETECTED.lastModified(new File(workTree, path)), dc.getEntry(path)
.getLastModified());
}
@@ -799,14 +800,15 @@
// then this file must be younger then file i. A path "*<modtime>"
// represents a file with a modification time of <modtime>
// E.g. ("a", "b", "<c", "f/a.txt") means: a<=b<c<=f/a.txt
- private void checkModificationTimeStampOrder(String... pathes) {
+ private void checkModificationTimeStampOrder(String... pathes)
+ throws IOException {
long lastMod = Long.MIN_VALUE;
for (String p : pathes) {
boolean strong = p.startsWith("<");
boolean fixed = p.charAt(strong ? 1 : 0) == '*';
p = p.substring((strong ? 1 : 0) + (fixed ? 1 : 0));
- long curMod = fixed ? Long.valueOf(p).longValue() : new File(
- db.getWorkTree(), p).lastModified();
+ long curMod = fixed ? Long.valueOf(p).longValue()
+ : FS.DETECTED.lastModified(new File(db.getWorkTree(), p));
if (strong)
assertTrue("path " + p + " is not younger than predecesssor",
curMod > lastMod);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
index 47b08a7..325c9e2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
@@ -449,11 +449,13 @@
assertEquals("empty tree", empty, n.getTree());
}
+ @Test
public void testIteratorEmptyMap() {
Iterator<Note> it = NoteMap.newEmptyMap().iterator();
assertFalse(it.hasNext());
}
+ @Test
public void testIteratorFlatTree() throws Exception {
RevBlob a = tr.blob("a");
RevBlob b = tr.blob("b");
@@ -472,6 +474,7 @@
assertEquals(2, count(it));
}
+ @Test
public void testIteratorFanoutTree2_38() throws Exception {
RevBlob a = tr.blob("a");
RevBlob b = tr.blob("b");
@@ -490,6 +493,7 @@
assertEquals(2, count(it));
}
+ @Test
public void testIteratorFanoutTree2_2_36() throws Exception {
RevBlob a = tr.blob("a");
RevBlob b = tr.blob("b");
@@ -508,6 +512,7 @@
assertEquals(2, count(it));
}
+ @Test
public void testIteratorFullyFannedOut() throws Exception {
RevBlob a = tr.blob("a");
RevBlob b = tr.blob("b");
@@ -526,12 +531,13 @@
assertEquals(2, count(it));
}
+ @Test
public void testShorteningNoteRefName() throws Exception {
String expectedShortName = "review";
String noteRefName = Constants.R_NOTES + expectedShortName;
assertEquals(expectedShortName, NoteMap.shortenRefName(noteRefName));
String nonNoteRefName = Constants.R_HEADS + expectedShortName;
- assertEquals(nonNoteRefName, NoteMap.shortenRefName(expectedShortName));
+ assertEquals(nonNoteRefName, NoteMap.shortenRefName(nonNoteRefName));
}
private RevCommit commitNoteMap(NoteMap map) throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCarryFlagsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCarryFlagsTest.java
new file mode 100644
index 0000000..66814b3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCarryFlagsTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class RevWalkCarryFlagsTest extends RevWalkTestCase {
+ /**
+ * Test that the uninteresting flag is carried over correctly. Every commit
+ * should have the uninteresting flag resulting in a RevWalk returning no
+ * commit.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRevWalkCarryUninteresting_fastClock() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d = commit(c);
+ final RevCommit e = commit(b, d);
+
+ markStart(d);
+ markUninteresting(e);
+ assertNull("Found an unexpected commit", rw.next());
+ }
+
+ /**
+ * Similar to {@link #testRevWalkCarryUninteresting_fastClock()} but the
+ * last merge commit is created so fast that he has the same creationdate as
+ * the previous commit. This will cause the underlying {@link DateRevQueue}
+ * is not able to sort the commits in a way matching the topology. A parent
+ * (one of the commits which are merged) is handled before the child (the
+ * merge commit). This makes carrying over flags more complicated
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRevWalkCarryUninteresting_SlowClock() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d = commit(c);
+ final RevCommit e = commit(0, b, d);
+
+ markStart(d);
+ markUninteresting(e);
+ assertNull("Found an unexpected commit", rw.next());
+ }
+
+ /**
+ * Similar to {@link #testRevWalkCarryUninteresting_SlowClock()} but the
+ * last merge commit is created with a inconsistent creationdate. The merge
+ * commit has a older creationdate then one of the commits he is merging.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRevWalkCarryUninteresting_WrongClock() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d = commit(c);
+ final RevCommit e = commit(-1, b, d);
+
+ markStart(d);
+ markUninteresting(e);
+ assertNull("Found an unexpected commit", rw.next());
+ }
+
+ /**
+ * Same as {@link #testRevWalkCarryUninteresting_SlowClock()} but this time
+ * we focus on the carrying over a custom flag.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRevWalkCarryCustom_SlowClock() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d = commit(c);
+ final RevCommit e = commit(0, b, d);
+
+ markStart(d);
+ markStart(e);
+ RevFlag customFlag = rw.newFlag("CUSTOM");
+ e.flags |= customFlag.mask;
+ rw.carry(customFlag);
+
+ // the merge commit has the flag and it should be carried over -> every
+ // commit should have this flag
+ int count = 0;
+ for (RevCommit cm : rw) {
+ assertTrue(
+ "Found a commit which doesn't have the custom flag: " + cm,
+ cm.has(customFlag));
+ count++;
+ }
+ assertTrue("Didn't walked over all commits", count == 5);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
index 5233013..3dc022d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
@@ -100,7 +100,7 @@
} catch (IOException e) {
fail("Couldn't instantiate AuthHeadersResponse: " + e.toString());
}
- HttpAuthMethod authMethod = HttpAuthMethod.scanResponse(response);
+ HttpAuthMethod authMethod = HttpAuthMethod.scanResponse(response, null);
if (!expectedAuthMethod.equals(getAuthMethodName(authMethod))) {
fail("Wrong authentication method: expected " + expectedAuthMethod
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
index a3b4134..33a9105 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
@@ -43,13 +43,18 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_REPORT_STATUS;
+import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import java.io.IOException;
+import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
+import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.Constants;
@@ -125,19 +130,47 @@
Map<String, RemoteRefUpdate> updates = new HashMap<>();
updates.put(rru.getRemoteName(), rru);
- Transport tn = testProtocol.open(uri, client, "server");
- try {
- PushConnection connection = tn.openPush();
- try {
- connection.push(NullProgressMonitor.INSTANCE, updates);
- } finally {
- connection.close();
- }
- } finally {
- tn.close();
+ try (Transport tn = testProtocol.open(uri, client, "server");
+ PushConnection connection = tn.openPush()) {
+ connection.push(NullProgressMonitor.INSTANCE, updates);
}
assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
assertEquals("invalid old id sent", rru.getMessage());
}
+
+ @Test
+ public void invalidCommand() throws IOException {
+ try (Transport tn = testProtocol.open(uri, client, "server");
+ InternalPushConnection c = (InternalPushConnection) tn.openPush()) {
+ StringWriter msgs = new StringWriter();
+ PacketLineOut pckOut = c.pckOut;
+
+ @SuppressWarnings("resource")
+ SideBandInputStream in = new SideBandInputStream(c.in,
+ NullProgressMonitor.INSTANCE, msgs, null);
+
+ // Explicitly invalid command, but sane enough capabilities.
+ StringBuilder buf = new StringBuilder();
+ buf.append("42");
+ buf.append(' ');
+ buf.append(obj2.name());
+ buf.append(' ');
+ buf.append("refs/heads/A" + obj2.name());
+ buf.append('\0').append(CAPABILITY_SIDE_BAND_64K);
+ buf.append(' ').append(CAPABILITY_REPORT_STATUS);
+ buf.append('\n');
+ pckOut.writeString(buf.toString());
+ pckOut.end();
+
+ try {
+ in.read();
+ fail("expected TransportException");
+ } catch (TransportException e) {
+ assertEquals(
+ "remote: error: invalid protocol: wanted 'old new ref'",
+ e.getMessage());
+ }
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java
new file mode 100644
index 0000000..c346d79
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2016, 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PushCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.NoFilepatternException;
+import org.eclipse.jgit.api.errors.TransportException;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PushOptionsTest extends RepositoryTestCase {
+ private URIish uri;
+ private TestProtocol<Object> testProtocol;
+ private Object ctx = new Object();
+ private InMemoryRepository server;
+ private InMemoryRepository client;
+ private ObjectId obj1;
+ private ObjectId obj2;
+ private ReceivePack receivePack;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ server = newRepo("server");
+ client = newRepo("client");
+
+ testProtocol = new TestProtocol<>(null,
+ new ReceivePackFactory<Object>() {
+ @Override
+ public ReceivePack create(Object req, Repository git)
+ throws ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ receivePack = new ReceivePack(git);
+ receivePack.setAllowPushOptions(true);
+ receivePack.setAtomic(true);
+ return receivePack;
+ }
+ });
+
+ uri = testProtocol.register(ctx, server);
+
+ try (ObjectInserter ins = client.newObjectInserter()) {
+ obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
+ obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
+ ins.flush();
+ }
+ }
+
+ @After
+ public void tearDown() {
+ Transport.unregister(testProtocol);
+ }
+
+ private static InMemoryRepository newRepo(String name) {
+ return new InMemoryRepository(new DfsRepositoryDescription(name));
+ }
+
+ private List<RemoteRefUpdate> commands(boolean atomicSafe)
+ throws IOException {
+ List<RemoteRefUpdate> cmds = new ArrayList<>();
+ cmds.add(new RemoteRefUpdate(null, null, obj1, "refs/heads/one",
+ true /* force update */, null /* no local tracking ref */,
+ ObjectId.zeroId()));
+ cmds.add(new RemoteRefUpdate(null, null, obj2, "refs/heads/two",
+ true /* force update */, null /* no local tracking ref */,
+ atomicSafe ? ObjectId.zeroId() : obj1));
+ return cmds;
+ }
+
+ private void connectLocalToRemote(Git local, Git remote)
+ throws URISyntaxException, IOException {
+ StoredConfig config = local.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ remoteConfig.addURI(new URIish(
+ remote.getRepository().getDirectory().toURI().toURL()));
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+ }
+
+ private RevCommit addCommit(Git git)
+ throws IOException, NoFilepatternException, GitAPIException {
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ return git.commit().setMessage("adding f").call();
+ }
+
+ @Test
+ public void testNonAtomicPushWithOptions() throws Exception {
+ PushResult r;
+ server.setPerformsAtomicTransactions(false);
+ List<String> pushOptions = Arrays.asList("Hello", "World!");
+
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(false);
+ tn.setPushOptions(pushOptions);
+
+ r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+
+ assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
+ assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ two.getStatus());
+ assertEquals(pushOptions, receivePack.getPushOptions());
+ }
+
+ @Test
+ public void testAtomicPushWithOptions() throws Exception {
+ PushResult r;
+ server.setPerformsAtomicTransactions(true);
+ List<String> pushOptions = Arrays.asList("Hello", "World!");
+
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(true);
+ tn.setPushOptions(pushOptions);
+
+ r = tn.push(NullProgressMonitor.INSTANCE, commands(true));
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+
+ assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
+ assertSame(RemoteRefUpdate.Status.OK, two.getStatus());
+ assertEquals(pushOptions, receivePack.getPushOptions());
+ }
+
+ @Test
+ public void testFailedAtomicPushWithOptions() throws Exception {
+ PushResult r;
+ server.setPerformsAtomicTransactions(true);
+ List<String> pushOptions = Arrays.asList("Hello", "World!");
+
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(true);
+ tn.setPushOptions(pushOptions);
+
+ r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+
+ assertSame(RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
+ one.getStatus());
+ assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ two.getStatus());
+ assertNull(receivePack.getPushOptions());
+ }
+
+ @Test
+ public void testThinPushWithOptions() throws Exception {
+ PushResult r;
+ List<String> pushOptions = Arrays.asList("Hello", "World!");
+
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushThin(true);
+ tn.setPushOptions(pushOptions);
+
+ r = tn.push(NullProgressMonitor.INSTANCE, commands(false));
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+
+ assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
+ assertSame(RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ two.getStatus());
+ assertEquals(pushOptions, receivePack.getPushOptions());
+ }
+
+ @Test
+ public void testPushWithoutOptions() throws Exception {
+ try (Git local = new Git(db);
+ Git remote = new Git(createBareRepository())) {
+ connectLocalToRemote(local, remote);
+
+ final StoredConfig config2 = remote.getRepository().getConfig();
+ config2.setBoolean("receive", null, "pushoptions", true);
+ config2.save();
+
+ RevCommit commit = addCommit(local);
+
+ local.checkout().setName("not-pushed").setCreateBranch(true).call();
+ local.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+
+ PushCommand pushCommand = local.push().setRemote("test");
+ pushCommand.call();
+
+ assertEquals(commit.getId(),
+ remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+ }
+ }
+
+ @Test
+ public void testPushWithEmptyOptions() throws Exception {
+ try (Git local = new Git(db);
+ Git remote = new Git(createBareRepository())) {
+ connectLocalToRemote(local, remote);
+
+ final StoredConfig config2 = remote.getRepository().getConfig();
+ config2.setBoolean("receive", null, "pushoptions", true);
+ config2.save();
+
+ RevCommit commit = addCommit(local);
+
+ local.checkout().setName("not-pushed").setCreateBranch(true).call();
+ local.checkout().setName("branchtopush").setCreateBranch(true).call();
+ assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+
+ List<String> pushOptions = new ArrayList<>();
+ PushCommand pushCommand = local.push().setRemote("test")
+ .setPushOptions(pushOptions);
+ pushCommand.call();
+
+ assertEquals(commit.getId(),
+ remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+ }
+ }
+
+ @Test
+ public void testAdvertisedButUnusedPushOptions() throws Exception {
+ try (Git local = new Git(db);
+ Git remote = new Git(createBareRepository())) {
+ connectLocalToRemote(local, remote);
+
+ final StoredConfig config2 = remote.getRepository().getConfig();
+ config2.setBoolean("receive", null, "pushoptions", true);
+ config2.save();
+
+ RevCommit commit = addCommit(local);
+
+ local.checkout().setName("not-pushed").setCreateBranch(true).call();
+ local.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+
+ PushCommand pushCommand = local.push().setRemote("test")
+ .setPushOptions(null);
+ pushCommand.call();
+
+ assertEquals(commit.getId(),
+ remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+ }
+ }
+
+ @Test(expected = TransportException.class)
+ public void testPushOptionsNotSupported() throws Exception {
+ try (Git local = new Git(db);
+ Git remote = new Git(createBareRepository())) {
+ connectLocalToRemote(local, remote);
+
+ final StoredConfig config2 = remote.getRepository().getConfig();
+ config2.setBoolean("receive", null, "pushoptions", false);
+ config2.save();
+
+ addCommit(local);
+
+ local.checkout().setName("not-pushed").setCreateBranch(true).call();
+ local.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ assertNull(remote.getRepository().resolve("refs/heads/branchtopush"));
+ assertNull(remote.getRepository().resolve("refs/heads/not-pushed"));
+ assertNull(remote.getRepository().resolve("refs/heads/master"));
+
+ List<String> pushOptions = new ArrayList<>();
+ PushCommand pushCommand = local.push().setRemote("test")
+ .setPushOptions(pushOptions);
+ pushCommand.call();
+
+ fail("should already have thrown TransportException");
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java
new file mode 100644
index 0000000..ce69adf
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefAdvertiserTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016, 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
+import org.eclipse.jgit.util.NB;
+import org.junit.Test;
+
+public class RefAdvertiserTest {
+ @Test
+ public void advertiser() throws IOException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ PacketLineOut pckOut = new PacketLineOut(buf);
+ PacketLineOutRefAdvertiser adv = new PacketLineOutRefAdvertiser(pckOut);
+
+ // Advertisement of capability and id both happen in order of call,
+ // which may not match Git standards. Callers are responsible for
+ // making calls in the correct ordering. Here in this test we do them
+ // in a "wrong" order to assert the method just writes to the network.
+
+ adv.advertiseCapability("test-1");
+ adv.advertiseCapability("sideband");
+ adv.advertiseId(id(1), "refs/heads/master");
+ adv.advertiseId(id(4), "refs/" + padStart("F", 987));
+ adv.advertiseId(id(2), "refs/heads/next");
+ adv.advertiseId(id(3), "refs/Iñtërnâtiônàlizætiøn☃💩");
+ adv.end();
+ assertFalse(adv.isEmpty());
+
+ PacketLineIn pckIn = new PacketLineIn(
+ new ByteArrayInputStream(buf.toByteArray()));
+ String s = pckIn.readStringRaw();
+ assertEquals(id(1).name() + " refs/heads/master\0 test-1 sideband\n",
+ s);
+
+ s = pckIn.readStringRaw();
+ assertEquals(id(4).name() + " refs/" + padStart("F", 987) + '\n', s);
+
+ s = pckIn.readStringRaw();
+ assertEquals(id(2).name() + " refs/heads/next\n", s);
+
+ s = pckIn.readStringRaw();
+ assertEquals(id(3).name() + " refs/Iñtërnâtiônàlizætiøn☃💩\n", s);
+
+ s = pckIn.readStringRaw();
+ assertSame(PacketLineIn.END, s);
+ }
+
+ private static ObjectId id(int i) {
+ try (ObjectInserter.Formatter f = new ObjectInserter.Formatter()) {
+ byte[] tmp = new byte[4];
+ NB.encodeInt32(tmp, 0, i);
+ return f.idFor(Constants.OBJ_BLOB, tmp);
+ }
+ }
+
+ private static String padStart(String s, int len) {
+ StringBuilder b = new StringBuilder(len);
+ for (int i = s.length(); i < len; i++) {
+ b.append((char) ('a' + (i % 26)));
+ }
+ return b.append(s).toString();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
index 4f83350..c9e44e7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
@@ -55,6 +55,7 @@
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.transport.RefSpec.WildcardMode;
import org.junit.Test;
public class RefSpecTest {
@@ -409,6 +410,16 @@
}
@Test(expected = IllegalArgumentException.class)
+ public void invalidWhenSourceEndsWithSlash() {
+ assertNotNull(new RefSpec("refs/heads/"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidWhenDestinationEndsWithSlash() {
+ assertNotNull(new RefSpec("refs/heads/master:refs/heads/"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
public void invalidWhenSourceOnlyAndWildcard() {
assertNotNull(new RefSpec("refs/heads/*"));
}
@@ -464,4 +475,28 @@
RefSpec a = new RefSpec("refs/heads/*:refs/remotes/origin/*");
a.setDestination("refs/remotes/origin/*/*");
}
+
+ @Test
+ public void sourceOnlywithWildcard() {
+ RefSpec a = new RefSpec("refs/heads/*",
+ WildcardMode.ALLOW_MISMATCH);
+ assertTrue(a.matchSource("refs/heads/master"));
+ assertNull(a.getDestination());
+ }
+
+ @Test
+ public void destinationWithWildcard() {
+ RefSpec a = new RefSpec("refs/heads/master:refs/heads/*",
+ WildcardMode.ALLOW_MISMATCH);
+ assertTrue(a.matchSource("refs/heads/master"));
+ assertTrue(a.matchDestination("refs/heads/master"));
+ assertTrue(a.matchDestination("refs/heads/foo"));
+ }
+
+ @Test
+ public void onlyWildCard() {
+ RefSpec a = new RefSpec("*", WildcardMode.ALLOW_MISMATCH);
+ assertTrue(a.matchSource("refs/heads/master"));
+ assertNull(a.getDestination());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index bf1d0e6..ef0f2d9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -99,7 +99,7 @@
for (int i = paths.length - 1; i >= 0; i--) {
final String s = paths[i];
writeTrashFile(s, s);
- mtime[i] = new File(trash, s).lastModified();
+ mtime[i] = FS.DETECTED.lastModified(new File(trash, s));
}
}
@@ -286,7 +286,7 @@
@Test
public void testTreewalkEnterSubtree() throws Exception {
- try (Git git = new Git(db)) {
+ try (Git git = new Git(db); TreeWalk tw = new TreeWalk(db)) {
writeTrashFile("b/c", "b/c");
writeTrashFile("z/.git", "gitdir: /tmp/somewhere");
git.add().addFilepattern(".").call();
@@ -297,7 +297,6 @@
FileUtils.delete(new File(db.getWorkTree(), "b"),
FileUtils.RECURSIVE);
- TreeWalk tw = new TreeWalk(db);
tw.addTree(new DirCacheIterator(db.readDirCache()));
tw.addTree(new FileTreeIterator(db));
assertTrue(tw.next());
@@ -617,39 +616,41 @@
public void testCustomFileModeStrategy() throws Exception {
Repository nestedRepo = createNestedRepo();
- Git git = new Git(nestedRepo);
- // validate that our custom strategy is honored
- WorkingTreeIterator customIterator =
- new FileTreeIterator(nestedRepo, NO_GITLINKS_STRATEGY);
- git.add().setWorkingTreeIterator(customIterator)
- .addFilepattern(".").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/nested/b.txt, mode:100644, content:content b]",
- indexState(nestedRepo, CONTENT));
-
+ try (Git git = new Git(nestedRepo)) {
+ // validate that our custom strategy is honored
+ WorkingTreeIterator customIterator = new FileTreeIterator(
+ nestedRepo, NO_GITLINKS_STRATEGY);
+ git.add().setWorkingTreeIterator(customIterator).addFilepattern(".")
+ .call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]"
+ + "[sub/nested/b.txt, mode:100644, content:content b]",
+ indexState(nestedRepo, CONTENT));
+ }
}
@Test
public void testCustomFileModeStrategyFromParentIterator() throws Exception {
Repository nestedRepo = createNestedRepo();
- Git git = new Git(nestedRepo);
+ try (Git git = new Git(nestedRepo)) {
+ FileTreeIterator customIterator = new FileTreeIterator(nestedRepo,
+ NO_GITLINKS_STRATEGY);
+ File r = new File(nestedRepo.getWorkTree(), "sub");
- FileTreeIterator customIterator =
- new FileTreeIterator(nestedRepo, NO_GITLINKS_STRATEGY);
- File r = new File(nestedRepo.getWorkTree(), "sub");
-
- // here we want to validate that if we create a new iterator using the
- // constructor that accepts a parent iterator, that the child iterator
- // correctly inherits the FileModeStrategy from the parent iterator.
- FileTreeIterator childIterator =
- new FileTreeIterator(customIterator, r, nestedRepo.getFS());
- git.add().setWorkingTreeIterator(childIterator).addFilepattern(".").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/nested/b.txt, mode:100644, content:content b]",
- indexState(nestedRepo, CONTENT));
+ // here we want to validate that if we create a new iterator using
+ // the constructor that accepts a parent iterator, that the child
+ // iterator correctly inherits the FileModeStrategy from the parent
+ // iterator.
+ FileTreeIterator childIterator = new FileTreeIterator(
+ customIterator, r, nestedRepo.getFS());
+ git.add().setWorkingTreeIterator(childIterator).addFilepattern(".")
+ .call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]"
+ + "[sub/nested/b.txt, mode:100644, content:content b]",
+ indexState(nestedRepo, CONTENT));
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
similarity index 92%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
index 53b6fec..4061b56 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -50,18 +50,20 @@
import java.io.File;
import java.io.IOException;
+import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
+import org.eclipse.jgit.errors.CommandFailedException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
-public class FSJava7Test {
+public class FSTest {
private File trash;
@Before
@@ -164,4 +166,15 @@
.readAttributes().permissions();
}
+ @Test(expected = CommandFailedException.class)
+ public void testReadPipePosixCommandFailure()
+ throws CommandFailedException {
+ FS fs = FS.DETECTED.newInstance();
+ assumeTrue(fs instanceof FS_POSIX);
+
+ String r = FS.readPipe(fs.userHome(),
+ new String[] { "bash", "--login", "-c", "foobar" },
+ Charset.defaultCharset().name());
+ System.out.println(r);
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
index e07076e..a680ef9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
@@ -54,6 +54,7 @@
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.hooks.CommitMsgHook;
+import org.eclipse.jgit.hooks.PostCommitHook;
import org.eclipse.jgit.hooks.PreCommitHook;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
@@ -76,6 +77,18 @@
}
@Test
+ public void testFindPostCommitHook() throws Exception {
+ assumeSupportedPlatform();
+
+ assertNull("no hook should be installed",
+ FS.DETECTED.findHook(db, PostCommitHook.NAME));
+ File hookFile = writeHookFile(PostCommitHook.NAME,
+ "#!/bin/bash\necho \"test $1 $2\"");
+ assertEquals("expected to find post-commit hook", hookFile,
+ FS.DETECTED.findHook(db, PostCommitHook.NAME));
+ }
+
+ @Test
public void testFailedCommitMsgHookBlocksCommit() throws Exception {
assumeSupportedPlatform();
@@ -133,6 +146,55 @@
}
@Test
+ public void testPostCommitRunHook() throws Exception {
+ assumeSupportedPlatform();
+
+ writeHookFile(PostCommitHook.NAME,
+ "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\necho 1>&2 \"stderr\"");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ ProcessResult res = FS.DETECTED.runHookIfPresent(db,
+ PostCommitHook.NAME,
+ new String[] {
+ "arg1", "arg2" },
+ new PrintStream(out), new PrintStream(err), "stdin");
+
+ assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n",
+ out.toString("UTF-8"));
+ assertEquals("unexpected output on stderr stream", "stderr\n",
+ err.toString("UTF-8"));
+ assertEquals("unexpected exit code", 0, res.getExitCode());
+ assertEquals("unexpected process status", ProcessResult.Status.OK,
+ res.getStatus());
+ }
+
+ @Test
+ public void testAllCommitHooks() throws Exception {
+ assumeSupportedPlatform();
+
+ writeHookFile(PreCommitHook.NAME,
+ "#!/bin/sh\necho \"test pre-commit\"\n\necho 1>&2 \"stderr pre-commit\"\nexit 0");
+ writeHookFile(CommitMsgHook.NAME,
+ "#!/bin/sh\necho \"test commit-msg $1\"\n\necho 1>&2 \"stderr commit-msg\"\nexit 0");
+ writeHookFile(PostCommitHook.NAME,
+ "#!/bin/sh\necho \"test post-commit\"\necho 1>&2 \"stderr post-commit\"\nexit 0");
+ Git git = Git.wrap(db);
+ String path = "a.txt";
+ writeTrashFile(path, "content");
+ git.add().addFilepattern(path).call();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ git.commit().setMessage("commit")
+ .setHookOutputStream(new PrintStream(out)).call();
+ } catch (AbortedByHookException e) {
+ fail("unexpected hook failure");
+ }
+ assertEquals("unexpected hook output",
+ "test pre-commit\ntest commit-msg .git/COMMIT_EDITMSG\ntest post-commit\n",
+ out.toString("UTF-8"));
+ }
+
+ @Test
public void testRunHook() throws Exception {
assumeSupportedPlatform();
diff --git a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
index ff39d16..1ce7cd0 100644
--- a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 4d864d6..bac4ac9 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.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Export-Package: org.eclipse.jgit.awtui;version="4.4.2"
-Import-Package: org.eclipse.jgit.errors;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.lib;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.nls;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revplot;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.revwalk;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.transport;version="[4.4.2,4.5.0)",
- org.eclipse.jgit.util;version="[4.4.2,4.5.0)"
+Export-Package: org.eclipse.jgit.awtui;version="4.5.5"
+Import-Package: org.eclipse.jgit.errors;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.lib;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.nls;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revplot;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.revwalk;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.transport;version="[4.5.5,4.6.0)",
+ org.eclipse.jgit.util;version="[4.5.5,4.6.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index a8d9b5d..4208d95 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index bacfb33..3830563 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -3,45 +3,8 @@
<resource path="META-INF/MANIFEST.MF">
<filter id="924844039">
<message_arguments>
- <message_argument value="4.4.1"/>
- <message_argument value="4.4.0"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/attributes/AttributesNode.java" type="org.eclipse.jgit.attributes.AttributesNode">
- <filter comment="moved to new AttributesManager" id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.attributes.AttributesNode"/>
- <message_argument value="getAttributes(String, boolean, Attributes)"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/attributes/AttributesRule.java" type="org.eclipse.jgit.attributes.AttributesRule">
- <filter comment="used only in tests: bean naming" id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.attributes.AttributesRule"/>
- <message_argument value="dirOnly()"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="src/org/eclipse/jgit/dircache/DirCacheCheckout.java" type="org.eclipse.jgit.dircache.DirCacheCheckout">
- <filter comment="add eol stream type conversion" id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.dircache.DirCacheCheckout"/>
- <message_argument value="checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean)"/>
- </message_arguments>
- </filter>
- <filter comment="add eol stream type conversion" id="338792546">
- <message_arguments>
- <message_argument value="org.eclipse.jgit.dircache.DirCacheCheckout"/>
- <message_argument value="checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, String)"/>
- </message_arguments>
- </filter>
- <filter comment="add eol stream type conversion" id="1141899266">
- <message_arguments>
- <message_argument value="4.2"/>
- <message_argument value="4.3"/>
- <message_argument value="checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, DirCacheCheckout.CheckoutMetadata)"/>
+ <message_argument value="4.5.4"/>
+ <message_argument value="4.5.0"/>
</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 45d6d2c..bfaf736 100644
--- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -99,6 +99,7 @@
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=error
org.eclipse.jdt.core.compiler.problem.unusedLabel=error
org.eclipse.jdt.core.compiler.problem.unusedLocal=error
diff --git a/org.eclipse.jgit/BUCK b/org.eclipse.jgit/BUCK
index 73e2080..2bae6dc 100644
--- a/org.eclipse.jgit/BUCK
+++ b/org.eclipse.jgit/BUCK
@@ -9,6 +9,7 @@
'//lib:javaewah',
'//lib:jsch',
'//lib:httpcomponents',
+ '//lib:servlet-api',
'//lib:slf4j-api',
],
visibility = ['PUBLIC'],
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 82b27bf..aedf26a 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,12 +2,12 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.4.2.qualifier
+Bundle-Version: 4.5.5.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="4.4.2",
- org.eclipse.jgit.api;version="4.4.2";
+Export-Package: org.eclipse.jgit.annotations;version="4.5.5",
+ org.eclipse.jgit.api;version="4.5.5";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
@@ -21,50 +21,50 @@
org.eclipse.jgit.submodule,
org.eclipse.jgit.transport,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.4.2",
- org.eclipse.jgit.blame;version="4.4.2";
+ org.eclipse.jgit.api.errors;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="4.5.5",
+ org.eclipse.jgit.blame;version="4.5.5";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.4.2";
+ org.eclipse.jgit.diff;version="4.5.5";
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.4.2";
+ org.eclipse.jgit.dircache;version="4.5.5";
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.4.2";
+ org.eclipse.jgit.errors;version="4.5.5";
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.4.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.4.2",
- org.eclipse.jgit.gitrepo;version="4.4.2";
+ org.eclipse.jgit.events;version="4.5.5";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="4.5.5",
+ org.eclipse.jgit.gitrepo;version="4.5.5";
uses:="org.eclipse.jgit.api,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.xml.sax.helpers,
org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="4.4.2";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.4.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.4.2",
- org.eclipse.jgit.ignore.internal;version="4.4.2";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.4.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.ketch;version="4.4.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.dfs;version="4.4.2";
+ org.eclipse.jgit.gitrepo.internal;version="4.5.5";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.5.5";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="4.5.5",
+ org.eclipse.jgit.ignore.internal;version="4.5.5";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.5.5";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.ketch;version="4.5.5";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.dfs;version="4.5.5";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server,
org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.storage.file;version="4.4.2";
+ org.eclipse.jgit.internal.storage.file;version="4.5.5";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
@@ -72,9 +72,9 @@
org.eclipse.jgit.lfs.server,
org.eclipse.jgit.pgm,
org.eclipse.jgit.pgm.test",
- org.eclipse.jgit.internal.storage.pack;version="4.4.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="4.4.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.4.2";
+ org.eclipse.jgit.internal.storage.pack;version="4.5.5";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftree;version="4.5.5";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.5.5";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
@@ -84,32 +84,32 @@
org.eclipse.jgit.treewalk,
org.eclipse.jgit.transport,
org.eclipse.jgit.submodule",
- org.eclipse.jgit.merge;version="4.4.2";
+ org.eclipse.jgit.merge;version="4.5.5";
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.4.2",
- org.eclipse.jgit.notes;version="4.4.2";
+ org.eclipse.jgit.nls;version="4.5.5",
+ org.eclipse.jgit.notes;version="4.5.5";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.4.2";
+ org.eclipse.jgit.patch;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="4.5.5";
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.4.2";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.4.2";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.4.2";
+ org.eclipse.jgit.revwalk.filter;version="4.5.5";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="4.5.5";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="4.5.5";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.internal.storage.pack,
@@ -121,27 +121,28 @@
org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.4.2";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.4.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.4.2";
+ org.eclipse.jgit.transport.http;version="4.5.5";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="4.5.5";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="4.5.5";
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.4.2";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.4.2";
+ org.eclipse.jgit.treewalk.filter;version="4.5.5";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="4.5.5";
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.4.2"
+ org.eclipse.jgit.util.io;version="4.5.5"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
+ com.jcraft.jsch;version="[0.1.37,0.2.0)",
javax.crypto,
javax.net.ssl,
+ javax.servlet.http;version="[2.5.0,3.2.0)",
org.slf4j;version="[1.7.0,2.0.0)",
org.xml.sax,
org.xml.sax.helpers
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index b0365c7..ce5f778 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.4.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.4.2.qualifier";roots="."
+Bundle-Version: 4.5.5.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.5.5.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 77bfba1..a55575f 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.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit</artifactId>
@@ -88,6 +88,12 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
@@ -205,8 +211,8 @@
<pluginManagement>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
<configuration>
<excludeFilterFile>findBugs/FindBugsExcludeFilter.xml</excludeFilterFile>
</configuration>
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 21fbaa4..c949c0a 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -123,6 +123,7 @@
commitOnRepoWithoutHEADCurrentlyNotSupported=Commit on repo without HEAD currently not supported
commitAmendOnInitialNotPossible=Amending is not possible on initial commit.
compressingObjects=Compressing objects
+configHandleIsStale=config file handle is stale, {0}. retry
connectionFailed=connection failed
connectionTimeOut=Connection time out: {0}
contextMustBeNonNegative=context must be >= 0
@@ -264,11 +265,11 @@
exceptionCaughtDuringExecutionOfRevertCommand=Exception caught during execution of revert command. {0}
exceptionCaughtDuringExecutionOfRmCommand=Exception caught during execution of rm command
exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of tag command
-exceptionCaughtDuringExcecutionOfCommand=Exception caught during execution of command {0} in {1}
+exceptionCaughtDuringExcecutionOfCommand=Exception caught during execution of command ''{0}'' in ''{1}'', return code ''{2}'', error message ''{3}''
exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted.
exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command
exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1}
-exceptionWhileReadingPack=ERROR: Exception caught while accessing pack file {0}, the pack file might be corrupt
+exceptionWhileReadingPack=ERROR: Exception caught while accessing pack file {0}, the pack file might be corrupt, {1}. Caught {2} consecutive errors while trying to read this pack.
expectedACKNAKFoundEOF=Expected ACK/NAK, found EOF
expectedACKNAKGot=Expected ACK/NAK, got: {0}
expectedBooleanStringValue=Expected boolean string value
@@ -304,6 +305,7 @@
hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1}
illegalArgumentNotA=Not {0}
illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed
+illegalHookName=Illegal hook name {0}
illegalPackingPhase=Illegal packing phase {0}
illegalStateExists=exists {0}
improperlyPaddedBase64Input=Improperly padded Base64 input.
@@ -332,7 +334,9 @@
invalidChannel=Invalid channel {0}
invalidCharacterInBase64Data=Invalid character in Base64 data.
invalidCommitParentNumber=Invalid commit parent number
+invalidDepth=Invalid depth: {0}
invalidEncryption=Invalid encryption
+invalidExpandWildcard=ExpandFromSource on a refspec that can have mismatched wildcards does not make sense.
invalidGitdirRef = Invalid .git reference in file ''{0}''
invalidGitType=invalid git type: {0}
invalidId=Invalid id: {0}
@@ -466,7 +470,7 @@
packfileIsTruncatedNoParam=Packfile is truncated.
packHandleIsStale=Pack file {0} handle is stale, removing it from pack list
packHasUnresolvedDeltas=pack has unresolved deltas
-packInaccessible=Pack file {0} now inaccessible; removing it from pack list
+packInaccessible=Failed to access pack file {0}, caught {2} consecutive errors while trying to access this pack.
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
packRefs=Pack refs
@@ -498,7 +502,9 @@
pushCertificateInvalidSignature=Push certificate has invalid signature format
pushIsNotSupportedForBundleTransport=Push is not supported for bundle transport
pushNotPermitted=push not permitted
+pushOptionsNotSupported=Push options not supported; received {0}
rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry
+readerIsRequired=Reader is required
readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0}
readTimedOut=Read timed out after {0} ms
receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes.
@@ -527,7 +533,6 @@
renamesRejoiningModifies=Rejoining modified file pairs
repositoryAlreadyExists=Repository already exists: {0}
repositoryConfigFileInvalid=Repository config file {0} invalid {1}
-repositoryIsRequired=Repository is required.
repositoryNotFound=repository not found: {0}
repositoryState_applyMailbox=Apply mailbox
repositoryState_bare=Bare
@@ -555,6 +560,7 @@
serviceNotEnabledNoName=Service not enabled
serviceNotPermitted={0} not permitted
shallowCommitsAlreadyInitialized=Shallow commits have already been initialized
+shallowPacksRequireDepthWalk=Shallow packs require a DepthWalk
shortCompressedStreamAt=Short compressed stream at {0}
shortReadOfBlock=Short read of block.
shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
@@ -591,7 +597,7 @@
submodulesNotSupported=Submodules are not supported
supportOnlyPackIndexVersion2=Only support index version 2
symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java.
-systemConfigFileInvalid=Systen wide config file {0} is invalid {1}
+systemConfigFileInvalid=System wide config file {0} is invalid {1}
tagAlreadyExists=tag ''{0}'' already exists
tagNameInvalid=tag name {0} is invalid
tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
index 5967128..7e331fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
@@ -43,6 +43,8 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.DOT_GIT;
+
import java.io.File;
import java.io.IOException;
import java.util.Collections;
@@ -73,6 +75,8 @@
private boolean ignore = true;
+ private boolean force = false;
+
/**
* @param repo
*/
@@ -121,25 +125,69 @@
for (String file : notIgnoredFiles)
if (paths.isEmpty() || paths.contains(file)) {
- if (!dryRun)
- FileUtils.delete(new File(repo.getWorkTree(), file));
- files.add(file);
+ files = cleanPath(file, files);
}
- if (directories)
- for (String dir : notIgnoredDirs)
- if (paths.isEmpty() || paths.contains(dir)) {
- if (!dryRun)
- FileUtils.delete(new File(repo.getWorkTree(), dir),
- FileUtils.RECURSIVE);
- files.add(dir + "/"); //$NON-NLS-1$
- }
+ for (String dir : notIgnoredDirs)
+ if (paths.isEmpty() || paths.contains(dir)) {
+ files = cleanPath(dir, files);
+ }
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
return files;
}
+ /**
+ * When dryRun is false, deletes the specified path from disk. If dryRun
+ * is true, no paths are actually deleted. In both cases, the paths that
+ * would have been deleted are added to inFiles and returned.
+ *
+ * Paths that are directories are recursively deleted when
+ * {@link #directories} is true.
+ * Paths that are git repositories are recursively deleted when
+ * {@link #directories} and {@link #force} are both true.
+ *
+ * @param path
+ * The path to be cleaned
+ * @param inFiles
+ * A set of strings representing the files that have been cleaned
+ * already, the path to be cleaned will be added to this set
+ * before being returned.
+ *
+ * @return a set of strings with the cleaned path added to it
+ * @throws IOException
+ */
+ private Set<String> cleanPath(String path, Set<String> inFiles)
+ throws IOException {
+ File curFile = new File(repo.getWorkTree(), path);
+ if (curFile.isDirectory()) {
+ if (directories) {
+ // Is this directory a git repository?
+ if (new File(curFile, DOT_GIT).exists()) {
+ if (force) {
+ if (!dryRun) {
+ FileUtils.delete(curFile, FileUtils.RECURSIVE);
+ }
+ inFiles.add(path + "/"); //$NON-NLS-1$
+ }
+ } else {
+ if (!dryRun) {
+ FileUtils.delete(curFile, FileUtils.RECURSIVE);
+ }
+ inFiles.add(path + "/"); //$NON-NLS-1$
+ }
+ }
+ } else {
+ if (!dryRun) {
+ FileUtils.delete(curFile, FileUtils.NONE);
+ }
+ inFiles.add(path);
+ }
+
+ return inFiles;
+ }
+
private Set<String> filterIgnorePaths(Set<String> inputPaths,
Set<String> ignoredNotInIndex, boolean exact) {
if (ignore) {
@@ -196,6 +244,20 @@
}
/**
+ * If force is set, directories that are git repositories will also be
+ * deleted.
+ *
+ * @param force
+ * whether or not to delete git repositories
+ * @return {@code this}
+ * @since 4.5
+ */
+ public CleanCommand setForce(boolean force) {
+ this.force = force;
+ return this;
+ }
+
+ /**
* If dirs is set, in addition to files, also clean directories.
*
* @param dirs
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 ff15fd0..dd5da15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -58,6 +58,7 @@
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -326,9 +327,9 @@
ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE);
if (ConfigConstants.CONFIG_KEY_ALWAYS.equals(autosetupRebase)
|| ConfigConstants.CONFIG_KEY_REMOTE.equals(autosetupRebase))
- clonedRepo.getConfig().setBoolean(
+ clonedRepo.getConfig().setEnum(
ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
- ConfigConstants.CONFIG_KEY_REBASE, true);
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.REBASE);
clonedRepo.getConfig().save();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index 561319c..e1793f3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -48,6 +48,7 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -67,7 +68,10 @@
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.UnmergedPathException;
+import org.eclipse.jgit.hooks.CommitMsgHook;
import org.eclipse.jgit.hooks.Hooks;
+import org.eclipse.jgit.hooks.PostCommitHook;
+import org.eclipse.jgit.hooks.PreCommitHook;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
@@ -131,7 +135,7 @@
*/
private boolean noVerify;
- private PrintStream hookOutRedirect;
+ private HashMap<String, PrintStream> hookOutRedirect = new HashMap<>(3);
private Boolean allowEmpty;
@@ -179,7 +183,8 @@
state.name()));
if (!noVerify) {
- Hooks.preCommit(repo, hookOutRedirect).call();
+ Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME))
+ .call();
}
processOptions(state, rw);
@@ -218,7 +223,9 @@
}
if (!noVerify) {
- message = Hooks.commitMsg(repo, hookOutRedirect)
+ message = Hooks
+ .commitMsg(repo,
+ hookOutRedirect.get(CommitMsgHook.NAME))
.setCommitMessage(message).call();
}
@@ -292,6 +299,9 @@
repo.writeMergeCommitMsg(null);
repo.writeRevertHead(null);
}
+ Hooks.postCommit(repo,
+ hookOutRedirect.get(PostCommitHook.NAME)).call();
+
return revCommit;
}
case REJECTED:
@@ -822,8 +832,9 @@
}
/**
- * Set the output stream for hook scripts executed by this command. If not
- * set it defaults to {@code System.out}.
+ * Set the output stream for all hook scripts executed by this command
+ * (pre-commit, commit-msg, post-commit). If not set it defaults to
+ * {@code System.out}.
*
* @param hookStdOut
* the output stream for hook scripts executed by this command
@@ -831,7 +842,34 @@
* @since 3.7
*/
public CommitCommand setHookOutputStream(PrintStream hookStdOut) {
- this.hookOutRedirect = hookStdOut;
+ setHookOutputStream(PreCommitHook.NAME, hookStdOut);
+ setHookOutputStream(CommitMsgHook.NAME, hookStdOut);
+ setHookOutputStream(PostCommitHook.NAME, hookStdOut);
+ return this;
+ }
+
+ /**
+ * Set the output stream for a selected hook script executed by this command
+ * (pre-commit, commit-msg, post-commit). If not set it defaults to
+ * {@code System.out}.
+ *
+ * @param hookName
+ * name of the hook to set the output stream for
+ * @param hookStdOut
+ * the output stream to use for the selected hook
+ * @return {@code this}
+ * @since 4.5
+ */
+ public CommitCommand setHookOutputStream(String hookName,
+ PrintStream hookStdOut) {
+ if (!(PreCommitHook.NAME.equals(hookName)
+ || CommitMsgHook.NAME.equals(hookName)
+ || PostCommitHook.NAME.equals(hookName))) {
+ throw new IllegalArgumentException(
+ MessageFormat.format(JGitText.get().illegalHookName,
+ hookName));
+ }
+ hookOutRedirect.put(hookName, hookStdOut);
return this;
}
}
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 549ef6c..a4d9ec1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -60,6 +60,7 @@
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
@@ -83,7 +84,7 @@
private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
- private PullRebaseMode pullRebaseMode = null;
+ private BranchRebaseMode pullRebaseMode = null;
private String remote;
@@ -91,33 +92,6 @@
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
- private enum PullRebaseMode implements Config.ConfigEnum {
- REBASE_PRESERVE("preserve", true, true), //$NON-NLS-1$
- REBASE("true", true, false), //$NON-NLS-1$
- NO_REBASE("false", false, false); //$NON-NLS-1$
-
- private final String configValue;
-
- private final boolean rebase;
-
- private final boolean preserveMerges;
-
- PullRebaseMode(String configValue, boolean rebase,
- boolean preserveMerges) {
- this.configValue = configValue;
- this.rebase = rebase;
- this.preserveMerges = preserveMerges;
- }
-
- public String toConfigValue() {
- return configValue;
- }
-
- public boolean matchConfigValue(String in) {
- return in.equals(configValue);
- }
- }
-
/**
* @param repo
*/
@@ -158,7 +132,46 @@
*/
public PullCommand setRebase(boolean useRebase) {
checkCallable();
- pullRebaseMode = useRebase ? PullRebaseMode.REBASE : PullRebaseMode.NO_REBASE;
+ pullRebaseMode = useRebase ? BranchRebaseMode.REBASE
+ : BranchRebaseMode.NONE;
+ return this;
+ }
+
+ /**
+ * Sets the {@link BranchRebaseMode} to use after fetching.
+ *
+ * <dl>
+ * <dt>BranchRebaseMode.REBASE</dt>
+ * <dd>Equivalent to {@code --rebase} on the command line: use rebase
+ * instead of merge after fetching.</dd>
+ * <dt>BranchRebaseMode.PRESERVE</dt>
+ * <dd>Equivalent to {@code --preserve-merges} on the command line: rebase
+ * preserving local merge commits.</dd>
+ * <dt>BranchRebaseMode.INTERACTIVE</dt>
+ * <dd>Equivalent to {@code --interactive} on the command line: use
+ * interactive rebase.</dd>
+ * <dt>BranchRebaseMode.NONE</dt>
+ * <dd>Equivalent to {@code --no-rebase}: merge instead of rebasing.
+ * <dt>{@code null}</dt>
+ * <dd>Use the setting defined in the git configuration, either {@code
+ * branch.[name].rebase} or, if not set, {@code pull.rebase}</dd>
+ * </dl>
+ *
+ * This setting overrides the settings in the configuration file. By
+ * default, the setting in the repository configuration file is used.
+ * <p>
+ * A branch can be configured to use rebase by default. See
+ * {@code branch.[name].rebase}, {@code branch.autosetuprebase}, and
+ * {@code pull.rebase}.
+ *
+ * @param rebaseMode
+ * the {@link BranchRebaseMode} to use
+ * @return {@code this}
+ * @since 4.5
+ */
+ public PullCommand setRebase(BranchRebaseMode rebaseMode) {
+ checkCallable();
+ pullRebaseMode = rebaseMode;
return this;
}
@@ -315,12 +328,13 @@
Repository.shortenRefName(remoteBranchName), remoteUri);
PullResult result;
- if (pullRebaseMode.rebase) {
+ if (pullRebaseMode != BranchRebaseMode.NONE) {
RebaseCommand rebase = new RebaseCommand(repo);
RebaseResult rebaseRes = rebase.setUpstream(commitToMerge)
.setUpstreamName(upstreamName).setProgressMonitor(monitor)
.setOperation(Operation.BEGIN).setStrategy(strategy)
- .setPreserveMerges(pullRebaseMode.preserveMerges)
+ .setPreserveMerges(
+ pullRebaseMode == BranchRebaseMode.PRESERVE)
.call();
result = new PullResult(fetchRes, remote, rebaseRes);
} else {
@@ -397,13 +411,29 @@
return this;
}
- private static PullRebaseMode getRebaseMode(String branchName, Config config) {
- PullRebaseMode mode = config.getEnum(PullRebaseMode.values(),
- ConfigConstants.CONFIG_PULL_SECTION, null,
- ConfigConstants.CONFIG_KEY_REBASE, PullRebaseMode.NO_REBASE);
- mode = config.getEnum(PullRebaseMode.values(),
+ /**
+ * Reads the rebase mode to use for a pull command from the repository
+ * configuration. This is the value defined for the configurations
+ * {@code branch.[branchName].rebase}, or,if not set, {@code pull.rebase}.
+ * If neither is set, yields {@link BranchRebaseMode#NONE}.
+ *
+ * @param branchName
+ * name of the local branch
+ * @param config
+ * the {@link Config} to read the value from
+ * @return the {@link BranchRebaseMode}
+ * @since 4.5
+ */
+ public static BranchRebaseMode getRebaseMode(String branchName,
+ Config config) {
+ BranchRebaseMode mode = config.getEnum(BranchRebaseMode.values(),
ConfigConstants.CONFIG_BRANCH_SECTION,
- branchName, ConfigConstants.CONFIG_KEY_REBASE, mode);
+ branchName, ConfigConstants.CONFIG_KEY_REBASE, null);
+ if (mode == null) {
+ mode = config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_PULL_SECTION, null,
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
+ }
return mode;
}
}
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 0a49f78..bd4521b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -96,6 +96,8 @@
private OutputStream out;
+ private List<String> pushOptions;
+
/**
* @param repo
*/
@@ -149,6 +151,7 @@
if (receivePack != null)
transport.setOptionReceivePack(receivePack);
transport.setDryRun(dryRun);
+ transport.setPushOptions(pushOptions);
configure(transport);
final Collection<RemoteRefUpdate> toPush = transport
@@ -189,7 +192,6 @@
}
return pushResults;
-
}
/**
@@ -453,4 +455,24 @@
this.out = out;
return this;
}
+
+ /**
+ * @return the option strings associated with the push operation
+ * @since 4.5
+ */
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
+
+ /**
+ * Sets the option strings associated with the push operation.
+ *
+ * @param pushOptions
+ * @return {@code this}
+ * @since 4.5
+ */
+ public PushCommand setPushOptions(List<String> pushOptions) {
+ this.pushOptions = pushOptions;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index e385a5d..3ceff84 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -123,6 +123,8 @@
private Collection<String> filepaths = new LinkedList<String>();
+ private boolean isReflogDisabled;
+
/**
*
* @param repo
@@ -181,8 +183,12 @@
ru.setNewObjectId(commitId);
String refName = Repository.shortenRefName(getRefOrHEAD());
- String message = refName + ": updating " + Constants.HEAD; //$NON-NLS-1$
- ru.setRefLogMessage(message, false);
+ if (isReflogDisabled) {
+ ru.disableRefLog();
+ } else {
+ String message = refName + ": updating " + Constants.HEAD; //$NON-NLS-1$
+ ru.setRefLogMessage(message, false);
+ }
if (ru.forceUpdate() == RefUpdate.Result.LOCK_FAILURE)
throw new JGitInternalException(MessageFormat.format(
JGitText.get().cannotLock, ru.getName()));
@@ -289,6 +295,26 @@
return this;
}
+ /**
+ * @param disable
+ * if {@code true} disables writing a reflog entry for this reset
+ * command
+ * @return this instance
+ * @since 4.5
+ */
+ public ResetCommand disableRefLog(boolean disable) {
+ this.isReflogDisabled = disable;
+ return this;
+ }
+
+ /**
+ * @return {@code true} if writing reflog is disabled for this reset command
+ * @since 4.5
+ */
+ public boolean isReflogDisabled() {
+ return this.isReflogDisabled;
+ }
+
private String getRefOrHEAD() {
if (ref != null)
return ref;
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 fc701f3..819442c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -73,6 +73,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -117,10 +118,10 @@
private final OutputStream out;
- private Repository db;
-
private ObjectReader reader;
+ private boolean closeReader;
+
private DiffConfig diffCfg;
private int context = 3;
@@ -172,28 +173,42 @@
* source repository holding referenced objects.
*/
public void setRepository(Repository repository) {
- if (reader != null)
- reader.close();
+ setReader(repository.newObjectReader(), repository.getConfig(), true);
+ }
- db = repository;
- reader = db.newObjectReader();
- diffCfg = db.getConfig().get(DiffConfig.KEY);
+ /**
+ * Set the repository the formatter can load object contents from.
+ *
+ * @param reader
+ * source reader holding referenced objects. Caller is responsible
+ * for closing the reader.
+ * @param cfg
+ * config specifying diff algorithm and rename detection options.
+ * @since 4.5
+ */
+ public void setReader(ObjectReader reader, Config cfg) {
+ setReader(reader, cfg, false);
+ }
+
+ private void setReader(ObjectReader reader, Config cfg, boolean closeReader) {
+ close();
+ this.closeReader = closeReader;
+ this.reader = reader;
+ this.diffCfg = cfg.get(DiffConfig.KEY);
ContentSource cs = ContentSource.create(reader);
source = new ContentSource.Pair(cs, cs);
- DiffConfig dc = db.getConfig().get(DiffConfig.KEY);
- if (dc.isNoPrefix()) {
+ if (diffCfg.isNoPrefix()) {
setOldPrefix(""); //$NON-NLS-1$
setNewPrefix(""); //$NON-NLS-1$
}
- setDetectRenames(dc.isRenameDetectionEnabled());
+ setDetectRenames(diffCfg.isRenameDetectionEnabled());
- diffAlgorithm = DiffAlgorithm.getAlgorithm(db.getConfig().getEnum(
+ diffAlgorithm = DiffAlgorithm.getAlgorithm(cfg.getEnum(
ConfigConstants.CONFIG_DIFF_SECTION, null,
ConfigConstants.CONFIG_KEY_ALGORITHM,
SupportedAlgorithm.HISTOGRAM));
-
}
/**
@@ -330,8 +345,8 @@
*/
public void setDetectRenames(boolean on) {
if (on && renameDetector == null) {
- assertHaveRepository();
- renameDetector = new RenameDetector(db);
+ assertHaveReader();
+ renameDetector = new RenameDetector(reader, diffCfg);
} else if (!on)
renameDetector = null;
}
@@ -387,8 +402,9 @@
*/
@Override
public void close() {
- if (reader != null)
+ if (reader != null && closeReader) {
reader.close();
+ }
}
/**
@@ -412,7 +428,7 @@
*/
public List<DiffEntry> scan(AnyObjectId a, AnyObjectId b)
throws IOException {
- assertHaveRepository();
+ assertHaveReader();
try (RevWalk rw = new RevWalk(reader)) {
RevTree aTree = a != null ? rw.parseTree(a) : null;
@@ -441,7 +457,7 @@
* trees cannot be read or file contents cannot be read.
*/
public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException {
- assertHaveRepository();
+ assertHaveReader();
AbstractTreeIterator aIterator = makeIteratorFromTreeOrNull(a);
AbstractTreeIterator bIterator = makeIteratorFromTreeOrNull(b);
@@ -476,7 +492,7 @@
*/
public List<DiffEntry> scan(AbstractTreeIterator a, AbstractTreeIterator b)
throws IOException {
- assertHaveRepository();
+ assertHaveReader();
TreeWalk walk = new TreeWalk(reader);
walk.addTree(a);
@@ -674,7 +690,7 @@
}
private String format(AbbreviatedObjectId id) {
- if (id.isComplete() && db != null) {
+ if (id.isComplete() && reader != null) {
try {
id = reader.abbreviate(id.toObjectId(), abbreviationLength);
} catch (IOException cannotAbbreviate) {
@@ -940,7 +956,7 @@
type = PatchType.UNIFIED;
} else {
- assertHaveRepository();
+ assertHaveReader();
byte[] aRaw, bRaw;
@@ -987,9 +1003,10 @@
return diffAlgorithm.diff(comparator, a, b);
}
- private void assertHaveRepository() {
- if (db == null)
- throw new IllegalStateException(JGitText.get().repositoryIsRequired);
+ private void assertHaveReader() {
+ if (reader == null) {
+ throw new IllegalStateException(JGitText.get().readerIsRequired);
+ }
}
private byte[] open(DiffEntry.Side side, DiffEntry entry)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 12ceb74..8af7e46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -718,10 +718,23 @@
return;
}
- // if we have no file at all then there is nothing to do
- if ((ffMask & 0x222) == 0
- && (f == null || FileMode.TREE.equals(f.getEntryFileMode())))
- return;
+ if ((ffMask & 0x222) == 0) {
+ // HEAD, MERGE and index don't contain a file (e.g. all contain a
+ // folder)
+ if (f == null || FileMode.TREE.equals(f.getEntryFileMode())) {
+ // the workingtree entry doesn't exist or also contains a folder
+ // -> no problem
+ return;
+ } else {
+ // the workingtree entry exists and is not a folder
+ if (!idEqual(h, m)) {
+ // Because HEAD and MERGE differ we will try to update the
+ // workingtree with a folder -> return a conflict
+ conflict(name, null, null, null);
+ }
+ return;
+ }
+ }
if ((ffMask == 0x00F) && f != null && FileMode.TREE.equals(f.getEntryFileMode())) {
// File/Directory conflict case #20
@@ -1004,6 +1017,17 @@
}
}
+ private static boolean idEqual(AbstractTreeIterator a,
+ AbstractTreeIterator b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return a.getEntryObjectId().equals(b.getEntryObjectId());
+ }
+
/**
* A conflict is detected - add the three different stages to the index
* @param path the path of the conflicting entry
@@ -1355,7 +1379,7 @@
FileUtils.delete(tmpFile);
}
}
- entry.setLastModified(f.lastModified());
+ entry.setLastModified(fs.lastModified(f));
}
@SuppressWarnings("deprecation")
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java
new file mode 100644
index 0000000..93749f5
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CommandFailedException.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.errors;
+
+/**
+ * Thrown when an external command failed
+ *
+ * @since 4.5
+ */
+public class CommandFailedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ private int returnCode;
+
+ /**
+ * @param returnCode
+ * return code returned by the command
+ * @param message
+ * error message
+ */
+ public CommandFailedException(int returnCode, String message) {
+ super(message);
+ this.returnCode = returnCode;
+ }
+
+ /**
+ * @param returnCode
+ * return code returned by the command
+ * @param message
+ * error message
+ * @param cause
+ * exception causing this exception
+ */
+ public CommandFailedException(int returnCode, String message,
+ Throwable cause) {
+ super(message, cause);
+ this.returnCode = returnCode;
+ }
+
+ /**
+ * @return return code returned by the command
+ */
+ public int getReturnCode() {
+ return returnCode;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
new file mode 100644
index 0000000..28e9788
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.errors;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a PackFile is found not to contain the pack signature defined by
+ * git.
+ *
+ * @since 4.5
+ */
+public class NoPackSignatureException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct an exception.
+ *
+ * @param why
+ * description of the type of error.
+ */
+ public NoPackSignatureException(final String why) {
+ super(why);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java
new file mode 100644
index 0000000..0b7ccf5
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.errors;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Thrown when a PackIndex uses an index version not supported by JGit.
+ *
+ * @since 4.5
+ */
+public class UnsupportedPackIndexVersionException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct an exception.
+ *
+ * @param version
+ * pack index version
+ */
+ public UnsupportedPackIndexVersionException(final int version) {
+ super(MessageFormat.format(JGitText.get().unsupportedPackIndexVersion,
+ Integer.valueOf(version)));
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
new file mode 100644
index 0000000..2361186
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.errors;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Thrown when a PackFile uses a pack version not supported by JGit.
+ *
+ * @since 4.5
+ */
+public class UnsupportedPackVersionException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct an exception.
+ *
+ * @param version
+ * pack version
+ */
+ public UnsupportedPackVersionException(final long version) {
+ super(MessageFormat.format(JGitText.get().unsupportedPackVersion,
+ Long.valueOf(version)));
+ }
+}
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 ca976a1..9b7f094 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -107,7 +107,7 @@
public class RepoCommand extends GitCommand<RevCommit> {
private String path;
private String uri;
- private String groups;
+ private String groupsParam;
private String branch;
private String targetBranch = Constants.HEAD;
private boolean recordRemoteBranch = false;
@@ -286,7 +286,7 @@
* @return this command
*/
public RepoCommand setGroups(String groups) {
- this.groups = groups;
+ this.groupsParam = groups;
return this;
}
@@ -478,7 +478,7 @@
git = new Git(repo);
ManifestParser parser = new ManifestParser(
- includedReader, path, branch, uri, groups, repo);
+ includedReader, path, branch, uri, groupsParam, repo);
try {
parser.read(inputStream);
for (RepoProject proj : parser.getFilteredProjects()) {
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 d29f6c0..ff4a3ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -167,14 +167,14 @@
* a SHA-1 or branch name or tag name
* @param remote
* name of the remote definition
- * @param groups
+ * @param groupsParam
* comma separated group list
*/
public RepoProject(String name, String path, String revision,
- String remote, String groups) {
+ String remote, String groupsParam) {
this(name, path, revision, remote, new HashSet<String>(), null);
- if (groups != null && groups.length() > 0)
- this.setGroups(groups);
+ if (groupsParam != null && groupsParam.length() > 0)
+ this.setGroups(groupsParam);
}
/**
@@ -191,14 +191,14 @@
/**
* Set the url of the sub repo.
*
- * @param groups
+ * @param groupsParam
* comma separated group list
* @return this for chaining.
* @since 4.4
*/
- public RepoProject setGroups(String groups) {
+ public RepoProject setGroups(String groupsParam) {
this.groups.clear();
- this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$
+ this.groups.addAll(Arrays.asList(groupsParam.split(","))); //$NON-NLS-1$
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
index 6f7a21a..46e8840 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
@@ -68,6 +68,18 @@
* @param repo
* @param outputStream
* The output stream, or {@code null} to use {@code System.out}
+ * @return The post-commit hook for the given repository.
+ * @since 4.5
+ */
+ public static PostCommitHook postCommit(Repository repo,
+ PrintStream outputStream) {
+ return new PostCommitHook(repo, outputStream);
+ }
+
+ /**
+ * @param repo
+ * @param outputStream
+ * The output stream, or {@code null} to use {@code System.out}
* @return The commit-msg hook for the given repository.
*/
public static CommitMsgHook commitMsg(Repository repo,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
new file mode 100644
index 0000000..70679e0
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 Obeo.
+ * 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.hooks;
+
+import java.io.IOException;
+import java.io.PrintStream;
+
+import org.eclipse.jgit.api.errors.AbortedByHookException;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * The <code>post-commit</code> hook implementation. This hook is run after the
+ * commit was successfully executed.
+ *
+ * @since 4.5
+ */
+public class PostCommitHook extends GitHook<Void> {
+
+ /** The post-commit hook name. */
+ public static final String NAME = "post-commit"; //$NON-NLS-1$
+
+ /**
+ * @param repo
+ * The repository
+ * @param outputStream
+ * The output stream the hook must use. {@code null} is allowed,
+ * in which case the hook will use {@code System.out}.
+ */
+ protected PostCommitHook(Repository repo, PrintStream outputStream) {
+ super(repo, outputStream);
+ }
+
+ @Override
+ public Void call() throws IOException, AbortedByHookException {
+ doRun();
+ return null;
+ }
+
+ @Override
+ public String getHookName() {
+ return NAME;
+ }
+
+}
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 e376cbb..eb081ad 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/FastIgnoreRule.java
@@ -43,6 +43,8 @@
package org.eclipse.jgit.ignore;
import static org.eclipse.jgit.ignore.internal.Strings.stripTrailing;
+import static org.eclipse.jgit.ignore.internal.Strings.stripTrailingWhitespace;
+import static org.eclipse.jgit.ignore.internal.Strings.isDirectoryPattern;
import static org.eclipse.jgit.ignore.internal.IMatcher.NO_MATCH;
import org.eclipse.jgit.errors.InvalidPatternException;
import org.eclipse.jgit.ignore.internal.IMatcher;
@@ -111,8 +113,9 @@
pattern = pattern.substring(1);
}
}
- dirOnly = pattern.charAt(pattern.length() - 1) == PATH_SEPARATOR;
+ dirOnly = isDirectoryPattern(pattern);
if (dirOnly) {
+ pattern = stripTrailingWhitespace(pattern);
pattern = stripTrailing(pattern, PATH_SEPARATOR);
if (pattern.length() == 0) {
this.matcher = NO_MATCH;
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 e354c71..70c5199 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
@@ -76,10 +76,50 @@
* @return new string with all trailing characters removed
*/
public static String stripTrailing(String pattern, char c) {
- while (pattern.length() > 0
- && pattern.charAt(pattern.length() - 1) == c)
- pattern = pattern.substring(0, pattern.length() - 1);
- return pattern;
+ for (int i = pattern.length() - 1; i >= 0; i--) {
+ char charAt = pattern.charAt(i);
+ if (charAt != c) {
+ if (i == pattern.length() - 1) {
+ return pattern;
+ }
+ return pattern.substring(0, i + 1);
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * @param pattern
+ * non null
+ * @return new string with all trailing whitespace removed
+ */
+ public static String stripTrailingWhitespace(String pattern) {
+ for (int i = pattern.length() - 1; i >= 0; i--) {
+ char charAt = pattern.charAt(i);
+ if (!Character.isWhitespace(charAt)) {
+ if (i == pattern.length() - 1) {
+ return pattern;
+ }
+ return pattern.substring(0, i + 1);
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * @param pattern
+ * non null
+ * @return true if the last character, which is not whitespace, is a path
+ * separator
+ */
+ public static boolean isDirectoryPattern(String pattern) {
+ for (int i = pattern.length() - 1; i >= 0; i--) {
+ char charAt = pattern.charAt(i);
+ if (!Character.isWhitespace(charAt)) {
+ return charAt == FastIgnoreRule.PATH_SEPARATOR;
+ }
+ }
+ return false;
}
static int count(String s, char c, boolean ignoreFirstLast) {
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 b7ef085..d32e873 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -182,6 +182,7 @@
/***/ public String commitOnRepoWithoutHEADCurrentlyNotSupported;
/***/ public String commitAmendOnInitialNotPossible;
/***/ public String compressingObjects;
+ /***/ public String configHandleIsStale;
/***/ public String connectionFailed;
/***/ public String connectionTimeOut;
/***/ public String contextMustBeNonNegative;
@@ -363,6 +364,7 @@
/***/ public String hunkHeaderDoesNotMatchBodyLineCountOf;
/***/ public String illegalArgumentNotA;
/***/ public String illegalCombinationOfArguments;
+ /***/ public String illegalHookName;
/***/ public String illegalPackingPhase;
/***/ public String illegalStateExists;
/***/ public String improperlyPaddedBase64Input;
@@ -391,7 +393,9 @@
/***/ public String invalidChannel;
/***/ public String invalidCharacterInBase64Data;
/***/ public String invalidCommitParentNumber;
+ /***/ public String invalidDepth;
/***/ public String invalidEncryption;
+ /***/ public String invalidExpandWildcard;
/***/ public String invalidGitdirRef;
/***/ public String invalidGitType;
/***/ public String invalidId;
@@ -557,7 +561,9 @@
/***/ public String pushCertificateInvalidSignature;
/***/ public String pushIsNotSupportedForBundleTransport;
/***/ public String pushNotPermitted;
+ /***/ public String pushOptionsNotSupported;
/***/ public String rawLogMessageDoesNotParseAsLogEntry;
+ /***/ public String readerIsRequired;
/***/ public String readingObjectsFromLocalRepositoryFailed;
/***/ public String readTimedOut;
/***/ public String receivePackObjectTooLarge1;
@@ -586,7 +592,6 @@
/***/ public String renamesRejoiningModifies;
/***/ public String repositoryAlreadyExists;
/***/ public String repositoryConfigFileInvalid;
- /***/ public String repositoryIsRequired;
/***/ public String repositoryNotFound;
/***/ public String repositoryState_applyMailbox;
/***/ public String repositoryState_bare;
@@ -614,6 +619,7 @@
/***/ public String serviceNotEnabledNoName;
/***/ public String serviceNotPermitted;
/***/ public String shallowCommitsAlreadyInitialized;
+ /***/ public String shallowPacksRequireDepthWalk;
/***/ public String shortCompressedStreamAt;
/***/ public String shortReadOfBlock;
/***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
index 7926536..4a33fb8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlock.java
@@ -88,9 +88,16 @@
return n;
}
- int setInput(long pos, Inflater inf) {
+ int setInput(long pos, Inflater inf) throws DataFormatException {
int ptr = (int) (pos - start);
int cnt = block.length - ptr;
+ if (cnt <= 0) {
+ throw new DataFormatException(cnt + " bytes to inflate:" //$NON-NLS-1$
+ + " at pos=" + pos //$NON-NLS-1$
+ + "; block.start=" + start //$NON-NLS-1$
+ + "; ptr=" + ptr //$NON-NLS-1$
+ + "; block.length=" + block.length); //$NON-NLS-1$
+ }
inf.setInput(block, ptr, cnt);
return cnt;
}
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 dc91a70..6f760ca 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
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.dfs;
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST;
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN;
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE;
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
@@ -53,9 +54,11 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
@@ -92,9 +95,13 @@
private PackConfig packConfig;
+ // See pack(), below, for how these two variables interact.
private long coalesceGarbageLimit = 50 << 20;
+ private long garbageTtlMillis = TimeUnit.DAYS.toMillis(1);
+ private long startTimeMillis;
private List<DfsPackFile> packsBefore;
+ private List<DfsPackFile> expiredGarbagePacks;
private Set<ObjectId> allHeads;
private Set<ObjectId> nonHeads;
@@ -167,6 +174,34 @@
}
/**
+ * @return garbage packs older than this limit (in milliseconds) will be
+ * pruned as part of the garbage collection process if the value is
+ * > 0, otherwise garbage packs are retained.
+ */
+ public long getGarbageTtlMillis() {
+ return garbageTtlMillis;
+ }
+
+ /**
+ * Set the time to live for garbage objects.
+ * <p>
+ * Any UNREACHABLE_GARBAGE older than this limit will be pruned at the end
+ * of the run.
+ * <p>
+ * If timeToLiveMillis is set to 0, UNREACHABLE_GARBAGE purging is disabled.
+ *
+ * @param ttl
+ * Time to live whatever unit is specified.
+ * @param unit
+ * The specified time unit.
+ * @return {@code this}
+ */
+ public DfsGarbageCollector setGarbageTtl(long ttl, TimeUnit unit) {
+ garbageTtlMillis = unit.toMillis(ttl);
+ return this;
+ }
+
+ /**
* Create a single new pack file containing all of the live objects.
* <p>
* This method safely decides which packs can be expired after the new pack
@@ -188,16 +223,28 @@
if (packConfig.getIndexVersion() != 2)
throw new IllegalStateException(
JGitText.get().supportOnlyPackIndexVersion2);
+ if (garbageTtlMillis > 0) {
+ // We disable coalescing because the coalescing step will keep
+ // refreshing the UNREACHABLE_GARBAGE pack and we wouldn't
+ // actually prune anything.
+ coalesceGarbageLimit = 0;
+ }
+ startTimeMillis = System.currentTimeMillis();
ctx = (DfsReader) objdb.newReader();
try {
refdb.refresh();
objdb.clearCache();
Collection<Ref> refsBefore = getAllRefs();
- packsBefore = packsToRebuild();
- if (packsBefore.isEmpty())
+ readPacksBefore();
+
+ if (packsBefore.isEmpty()) {
+ if (!expiredGarbagePacks.isEmpty()) {
+ objdb.commitPack(noPacks(), toPrune());
+ }
return true;
+ }
allHeads = new HashSet<ObjectId>();
nonHeads = new HashSet<ObjectId>();
@@ -252,17 +299,60 @@
return refs;
}
- private List<DfsPackFile> packsToRebuild() throws IOException {
+ private void readPacksBefore() throws IOException {
DfsPackFile[] packs = objdb.getPacks();
- List<DfsPackFile> out = new ArrayList<DfsPackFile>(packs.length);
+ packsBefore = new ArrayList<DfsPackFile>(packs.length);
+ expiredGarbagePacks = new ArrayList<DfsPackFile>(packs.length);
+
+ long mostRecentGC = mostRecentGC(packs);
+ long now = System.currentTimeMillis();
for (DfsPackFile p : packs) {
DfsPackDescription d = p.getPackDescription();
- if (d.getPackSource() != UNREACHABLE_GARBAGE)
- out.add(p);
- else if (d.getFileSize(PackExt.PACK) < coalesceGarbageLimit)
- out.add(p);
+ if (d.getPackSource() != UNREACHABLE_GARBAGE) {
+ packsBefore.add(p);
+ } else if (packIsExpiredGarbage(d, mostRecentGC, now)) {
+ expiredGarbagePacks.add(p);
+ } else if (d.getFileSize(PackExt.PACK) < coalesceGarbageLimit) {
+ packsBefore.add(p);
+ }
}
- return out;
+ }
+
+ private static long mostRecentGC(DfsPackFile[] packs) {
+ long r = 0;
+ for (DfsPackFile p : packs) {
+ DfsPackDescription d = p.getPackDescription();
+ if (d.getPackSource() == GC || d.getPackSource() == GC_REST) {
+ r = Math.max(r, d.getLastModified());
+ }
+ }
+ return r;
+ }
+
+ private boolean packIsExpiredGarbage(DfsPackDescription d,
+ long mostRecentGC, long now) {
+ // It should be safe to remove an UNREACHABLE_GARBAGE pack if it:
+ //
+ // (a) Predates the most recent prior run of this class. This check
+ // ensures the graph traversal algorithm had a chance to consider
+ // all objects in this pack and copied them into a GC or GC_REST
+ // pack if the graph contained live edges to the objects.
+ //
+ // This check is safe because of the ordering of packing; the GC
+ // packs are written first and then the UNREACHABLE_GARBAGE is
+ // constructed. Any UNREACHABLE_GARBAGE dated earlier than the GC
+ // was input to the prior GC's graph traversal.
+ //
+ // (b) Is older than garbagePackTtl. This check gives concurrent
+ // inserter threads sufficient time to identify an object is not
+ // in the graph and should have a new copy written, rather than
+ // relying on something from an UNREACHABLE_GARBAGE pack.
+ //
+ // Both (a) and (b) must be met to safely remove UNREACHABLE_GARBAGE.
+ return d.getPackSource() == UNREACHABLE_GARBAGE
+ && d.getLastModified() < mostRecentGC
+ && garbageTtlMillis > 0
+ && now - d.getLastModified() >= garbageTtlMillis;
}
/** @return all of the source packs that fed into this compaction. */
@@ -283,8 +373,12 @@
private List<DfsPackDescription> toPrune() {
int cnt = packsBefore.size();
List<DfsPackDescription> all = new ArrayList<DfsPackDescription>(cnt);
- for (DfsPackFile pack : packsBefore)
+ for (DfsPackFile pack : packsBefore) {
all.add(pack.getPackDescription());
+ }
+ for (DfsPackFile pack : expiredGarbagePacks) {
+ all.add(pack.getPackDescription());
+ }
return all;
}
@@ -299,6 +393,7 @@
writePack(GC, pw, pm);
}
}
+
private void packRest(ProgressMonitor pm) throws IOException {
if (nonHeads.isEmpty())
return;
@@ -308,7 +403,7 @@
pw.excludeObjects(packedObjs);
pw.preparePack(pm, nonHeads, allHeads);
if (0 < pw.getObjectCount())
- writePack(GC, pw, pm);
+ writePack(GC_REST, pw, pm);
}
}
@@ -326,7 +421,6 @@
}
private void packGarbage(ProgressMonitor pm) throws IOException {
- // TODO(sop) This is ugly. The garbage pack needs to be deleted.
PackConfig cfg = new PackConfig(packConfig);
cfg.setReuseDeltas(true);
cfg.setReuseObjects(true);
@@ -383,47 +477,42 @@
private DfsPackDescription writePack(PackSource source, PackWriter pw,
ProgressMonitor pm) throws IOException {
- DfsOutputStream out;
DfsPackDescription pack = repo.getObjectDatabase().newPack(source);
newPackDesc.add(pack);
- out = objdb.writeFile(pack, PACK);
- try {
+ try (DfsOutputStream out = objdb.writeFile(pack, PACK)) {
pw.writePack(pm, pm, out);
pack.addFileExt(PACK);
- } finally {
- out.close();
}
- out = objdb.writeFile(pack, INDEX);
- try {
- CountingOutputStream cnt = new CountingOutputStream(out);
+ try (CountingOutputStream cnt =
+ new CountingOutputStream(objdb.writeFile(pack, INDEX))) {
pw.writeIndex(cnt);
pack.addFileExt(INDEX);
pack.setFileSize(INDEX, cnt.getCount());
pack.setIndexVersion(pw.getIndexVersion());
- } finally {
- out.close();
}
if (pw.prepareBitmapIndex(pm)) {
- out = objdb.writeFile(pack, BITMAP_INDEX);
- try {
- CountingOutputStream cnt = new CountingOutputStream(out);
+ try (CountingOutputStream cnt = new CountingOutputStream(
+ objdb.writeFile(pack, BITMAP_INDEX))) {
pw.writeBitmapIndex(cnt);
pack.addFileExt(BITMAP_INDEX);
pack.setFileSize(BITMAP_INDEX, cnt.getCount());
- } finally {
- out.close();
}
}
PackStatistics stats = pw.getStatistics();
pack.setPackStats(stats);
+ pack.setLastModified(startTimeMillis);
newPackStats.add(stats);
newPackObj.add(pw.getObjectSet());
DfsBlockCache.getInstance().getOrCreate(pack, null);
return pack;
}
+
+ private static List<DfsPackDescription> noPacks() {
+ return Collections.emptyList();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index f5673e8..a5e920a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -69,6 +69,7 @@
import java.util.zip.InflaterInputStream;
import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.PackIndex;
@@ -106,6 +107,7 @@
DfsPackDescription packDsc;
PackStream packOut;
private boolean rollback;
+ private boolean checkExisting = true;
/**
* Initialize a new inserter.
@@ -117,6 +119,15 @@
this.db = db;
}
+ /**
+ * @param check
+ * if false, will write out possibly-duplicate objects without
+ * first checking whether they exist in the repo; default is true.
+ */
+ public void checkExisting(boolean check) {
+ checkExisting = check;
+ }
+
void setCompressionLevel(int compression) {
this.compression = compression;
}
@@ -138,7 +149,7 @@
if (objectMap != null && objectMap.contains(id))
return id;
// Ignore unreachable (garbage) objects here.
- if (db.has(id, true))
+ if (checkExisting && db.has(id, true))
return id;
long offset = beginObject(type, len);
@@ -474,7 +485,8 @@
}
}
- private int setInput(long pos, Inflater inf) throws IOException {
+ private int setInput(long pos, Inflater inf)
+ throws IOException, DataFormatException {
if (pos < currPos)
return getOrLoadBlock(pos).setInput(pos, inf);
if (pos < currPos + currPtr) {
@@ -559,6 +571,9 @@
if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA)
throw new IOException(MessageFormat.format(
DfsText.get().cannotReadBackDelta, Integer.toString(type)));
+ if (typeHint != OBJ_ANY && type != typeHint) {
+ throw new IncorrectObjectTypeException(objectId.copy(), typeHint);
+ }
long sz = c & 0x0f;
int ptr = 1;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
index 3641560..b1d6c0d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -61,7 +61,22 @@
/** Manages objects stored in {@link DfsPackFile} on a storage system. */
public abstract class DfsObjDatabase extends ObjectDatabase {
- private static final PackList NO_PACKS = new PackList(new DfsPackFile[0]);
+ private static final PackList NO_PACKS = new PackList(new DfsPackFile[0]) {
+ @Override
+ boolean dirty() {
+ return true;
+ }
+
+ @Override
+ void clearDirty() {
+ // Always dirty.
+ }
+
+ @Override
+ public void markDirty() {
+ // Always dirty.
+ }
+ };
/** Sources for a pack file. */
public static enum PackSource {
@@ -80,24 +95,6 @@
RECEIVE(0),
/**
- * Pack was created by Git garbage collection by this implementation.
- * <p>
- * This source is only used by the {@link DfsGarbageCollector} when it
- * builds a pack file by traversing the object graph and copying all
- * reachable objects into a new pack stream.
- *
- * @see DfsGarbageCollector
- */
- GC(1),
-
- /**
- * RefTreeGraph pack was created by Git garbage collection.
- *
- * @see DfsGarbageCollector
- */
- GC_TXN(1),
-
- /**
* The pack was created by compacting multiple packs together.
* <p>
* Packs created by compacting multiple packs together aren't nearly as
@@ -109,13 +106,34 @@
COMPACT(1),
/**
+ * Pack was created by Git garbage collection by this implementation.
+ * <p>
+ * This source is only used by the {@link DfsGarbageCollector} when it
+ * builds a pack file by traversing the object graph and copying all
+ * reachable objects into a new pack stream.
+ *
+ * @see DfsGarbageCollector
+ */
+ GC(2),
+
+ /** Created from non-heads by {@link DfsGarbageCollector}. */
+ GC_REST(3),
+
+ /**
+ * RefTreeGraph pack was created by Git garbage collection.
+ *
+ * @see DfsGarbageCollector
+ */
+ GC_TXN(4),
+
+ /**
* Pack was created by Git garbage collection.
* <p>
* This pack contains only unreachable garbage that was found during the
* last GC pass. It is retained in a new pack until it is safe to prune
* these objects from the repository.
*/
- UNREACHABLE_GARBAGE(2);
+ UNREACHABLE_GARBAGE(5);
final int category;
@@ -170,7 +188,20 @@
* the pack list cannot be initialized.
*/
public DfsPackFile[] getPacks() throws IOException {
- return scanPacks(NO_PACKS).packs;
+ return getPackList().packs;
+ }
+
+ /**
+ * Scan and list all available pack files in the repository.
+ *
+ * @return list of available packs, with some additional metadata. The
+ * returned array is shared with the implementation and must not be
+ * modified by the caller.
+ * @throws IOException
+ * the pack list cannot be initialized.
+ */
+ public PackList getPackList() throws IOException {
+ return scanPacks(NO_PACKS);
}
/** @return repository owning this object database. */
@@ -185,7 +216,18 @@
* implementation and must not be modified by the caller.
*/
public DfsPackFile[] getCurrentPacks() {
- return packList.get().packs;
+ return getCurrentPackList().packs;
+ }
+
+ /**
+ * List currently known pack files in the repository, without scanning.
+ *
+ * @return list of available packs, with some additional metadata. The
+ * returned array is shared with the implementation and must not be
+ * modified by the caller.
+ */
+ public PackList getCurrentPackList() {
+ return packList.get();
}
/**
@@ -360,11 +402,11 @@
DfsPackFile[] packs = new DfsPackFile[1 + o.packs.length];
packs[0] = newPack;
System.arraycopy(o.packs, 0, packs, 1, o.packs.length);
- n = new PackList(packs);
+ n = new PackListImpl(packs);
} while (!packList.compareAndSet(o, n));
}
- private PackList scanPacks(final PackList original) throws IOException {
+ PackList scanPacks(final PackList original) throws IOException {
PackList o, n;
synchronized (packList) {
do {
@@ -405,10 +447,12 @@
for (DfsPackFile p : forReuse.values())
p.close();
if (list.isEmpty())
- return new PackList(NO_PACKS.packs);
- if (!foundNew)
+ return new PackListImpl(NO_PACKS.packs);
+ if (!foundNew) {
+ old.clearDirty();
return old;
- return new PackList(list.toArray(new DfsPackFile[list.size()]));
+ }
+ return new PackListImpl(list.toArray(new DfsPackFile[list.size()]));
}
private static Map<DfsPackDescription, DfsPackFile> reuseMap(PackList old) {
@@ -453,12 +497,62 @@
// p.close();
}
- private static final class PackList {
+ /** Snapshot of packs scanned in a single pass. */
+ public static abstract class PackList {
/** All known packs, sorted. */
- final DfsPackFile[] packs;
+ public final DfsPackFile[] packs;
- PackList(final DfsPackFile[] packs) {
+ private long lastModified = -1;
+
+ PackList(DfsPackFile[] packs) {
this.packs = packs;
}
+
+ /** @return last modified time of all packs, in milliseconds. */
+ public long getLastModified() {
+ if (lastModified < 0) {
+ long max = 0;
+ for (DfsPackFile pack : packs) {
+ max = Math.max(max, pack.getPackDescription().getLastModified());
+ }
+ lastModified = max;
+ }
+ return lastModified;
+ }
+
+ abstract boolean dirty();
+ abstract void clearDirty();
+
+ /**
+ * Mark pack list as dirty.
+ * <p>
+ * Used when the caller knows that new data might have been written to the
+ * repository that could invalidate open readers depending on this pack list,
+ * for example if refs are newly scanned.
+ */
+ public abstract void markDirty();
+ }
+
+ private static final class PackListImpl extends PackList {
+ private volatile boolean dirty;
+
+ PackListImpl(DfsPackFile[] packs) {
+ super(packs);
+ }
+
+ @Override
+ boolean dirty() {
+ return dirty;
+ }
+
+ @Override
+ void clearDirty() {
+ dirty = false;
+ }
+
+ @Override
+ public void markDirty() {
+ dirty = true;
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
index 66421e2..2f61dea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -53,6 +53,7 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.zip.DataFormatException;
@@ -62,6 +63,7 @@
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackList;
import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
import org.eclipse.jgit.internal.storage.file.PackIndex;
@@ -91,6 +93,8 @@
* reader is not thread safe.
*/
public final class DfsReader extends ObjectReader implements ObjectReuseAsIs {
+ private static final int MAX_RESOLVE_MATCHES = 256;
+
/** Temporary buffer large enough for at least one raw object id. */
final byte[] tempId = new byte[OBJECT_ID_LENGTH];
@@ -163,22 +167,44 @@
return Collections.singleton(id.toObjectId());
boolean noGarbage = avoidUnreachable;
HashSet<ObjectId> matches = new HashSet<ObjectId>(4);
- for (DfsPackFile pack : db.getPacks()) {
- if (noGarbage && pack.isGarbage())
- continue;
- pack.resolve(this, matches, id, 256);
- if (256 <= matches.size())
- break;
+ PackList packList = db.getPackList();
+ resolveImpl(packList, id, noGarbage, matches);
+ if (matches.size() < MAX_RESOLVE_MATCHES && packList.dirty()) {
+ resolveImpl(db.scanPacks(packList), id, noGarbage, matches);
}
return matches;
}
+ private void resolveImpl(PackList packList, AbbreviatedObjectId id,
+ boolean noGarbage, HashSet<ObjectId> matches) throws IOException {
+ for (DfsPackFile pack : packList.packs) {
+ if (noGarbage && pack.isGarbage()) {
+ continue;
+ }
+ pack.resolve(this, matches, id, MAX_RESOLVE_MATCHES);
+ if (matches.size() >= MAX_RESOLVE_MATCHES) {
+ break;
+ }
+ }
+ }
+
@Override
public boolean has(AnyObjectId objectId) throws IOException {
if (last != null && last.hasObject(this, objectId))
return true;
boolean noGarbage = avoidUnreachable;
- for (DfsPackFile pack : db.getPacks()) {
+ PackList packList = db.getPackList();
+ if (hasImpl(packList, objectId, noGarbage)) {
+ return true;
+ } else if (packList.dirty()) {
+ return hasImpl(db.scanPacks(packList), objectId, noGarbage);
+ }
+ return false;
+ }
+
+ private boolean hasImpl(PackList packList, AnyObjectId objectId,
+ boolean noGarbage) throws IOException {
+ for (DfsPackFile pack : packList.packs) {
if (pack == last || (noGarbage && pack.isGarbage()))
continue;
if (pack.hasObject(this, objectId)) {
@@ -193,20 +219,24 @@
public ObjectLoader open(AnyObjectId objectId, int typeHint)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
+ ObjectLoader ldr;
if (last != null) {
- ObjectLoader ldr = last.get(this, objectId);
- if (ldr != null)
- return ldr;
+ ldr = last.get(this, objectId);
+ if (ldr != null) {
+ return checkType(ldr, objectId, typeHint);
+ }
}
+ PackList packList = db.getPackList();
boolean noGarbage = avoidUnreachable;
- for (DfsPackFile pack : db.getPacks()) {
- if (pack == last || (noGarbage && pack.isGarbage()))
- continue;
- ObjectLoader ldr = pack.get(this, objectId);
+ ldr = openImpl(packList, objectId, noGarbage);
+ if (ldr != null) {
+ return checkType(ldr, objectId, typeHint);
+ }
+ if (packList.dirty()) {
+ ldr = openImpl(db.scanPacks(packList), objectId, noGarbage);
if (ldr != null) {
- last = pack;
- return ldr;
+ return checkType(ldr, objectId, typeHint);
}
}
@@ -216,6 +246,29 @@
throw new MissingObjectException(objectId.copy(), typeHint);
}
+ private static ObjectLoader checkType(ObjectLoader ldr, AnyObjectId id,
+ int typeHint) throws IncorrectObjectTypeException {
+ if (typeHint != OBJ_ANY && ldr.getType() != typeHint) {
+ throw new IncorrectObjectTypeException(id.copy(), typeHint);
+ }
+ return ldr;
+ }
+
+ private ObjectLoader openImpl(PackList packList, AnyObjectId objectId,
+ boolean noGarbage) throws IOException {
+ for (DfsPackFile pack : packList.packs) {
+ if (pack == last || (noGarbage && pack.isGarbage())) {
+ continue;
+ }
+ ObjectLoader ldr = pack.get(this, objectId);
+ if (ldr != null) {
+ last = pack;
+ return ldr;
+ }
+ }
+ return null;
+ }
+
@Override
public Set<ObjectId> getShallowCommits() {
return Collections.emptySet();
@@ -253,39 +306,58 @@
private <T extends ObjectId> Iterable<FoundObject<T>> findAll(
Iterable<T> objectIds) throws IOException {
- ArrayList<FoundObject<T>> r = new ArrayList<FoundObject<T>>();
- DfsPackFile[] packList = db.getPacks();
- if (packList.length == 0) {
- for (T t : objectIds)
- r.add(new FoundObject<T>(t));
- return r;
+ Collection<T> pending = new LinkedList<>();
+ for (T id : objectIds) {
+ pending.add(id);
}
+ PackList packList = db.getPackList();
+ List<FoundObject<T>> r = new ArrayList<>();
+ findAllImpl(packList, pending, r);
+ if (!pending.isEmpty() && packList.dirty()) {
+ findAllImpl(db.scanPacks(packList), pending, r);
+ }
+ for (T t : pending) {
+ r.add(new FoundObject<T>(t));
+ }
+ Collections.sort(r, FOUND_OBJECT_SORT);
+ return r;
+ }
+
+ private <T extends ObjectId> void findAllImpl(PackList packList,
+ Collection<T> pending, List<FoundObject<T>> r) {
+ DfsPackFile[] packs = packList.packs;
+ if (packs.length == 0) {
+ return;
+ }
int lastIdx = 0;
- DfsPackFile lastPack = packList[lastIdx];
+ DfsPackFile lastPack = packs[lastIdx];
boolean noGarbage = avoidUnreachable;
- OBJECT_SCAN: for (T t : objectIds) {
+ OBJECT_SCAN: for (Iterator<T> it = pending.iterator(); it.hasNext();) {
+ T t = it.next();
try {
long p = lastPack.findOffset(this, t);
if (0 < p) {
r.add(new FoundObject<T>(t, lastIdx, lastPack, p));
+ it.remove();
continue;
}
} catch (IOException e) {
// Fall though and try to examine other packs.
}
- for (int i = 0; i < packList.length; i++) {
+ for (int i = 0; i < packs.length; i++) {
if (i == lastIdx)
continue;
- DfsPackFile pack = packList[i];
+ DfsPackFile pack = packs[i];
if (noGarbage && pack.isGarbage())
continue;
try {
long p = pack.findOffset(this, t);
if (0 < p) {
r.add(new FoundObject<T>(t, i, pack, p));
+ it.remove();
lastIdx = i;
lastPack = pack;
continue OBJECT_SCAN;
@@ -294,13 +366,9 @@
// Examine other packs.
}
}
-
- r.add(new FoundObject<T>(t));
}
- Collections.sort(r, FOUND_OBJECT_SORT);
last = lastPack;
- return r;
}
@Override
@@ -418,24 +486,43 @@
IOException {
if (last != null) {
long sz = last.getObjectSize(this, objectId);
- if (0 <= sz)
+ if (0 <= sz) {
return sz;
+ }
}
- for (DfsPackFile pack : db.getPacks()) {
- if (pack == last)
+ PackList packList = db.getPackList();
+ long sz = getObjectSizeImpl(packList, objectId);
+ if (0 <= sz) {
+ return sz;
+ }
+ if (packList.dirty()) {
+ sz = getObjectSizeImpl(packList, objectId);
+ if (0 <= sz) {
+ return sz;
+ }
+ }
+
+ if (typeHint == OBJ_ANY) {
+ throw new MissingObjectException(objectId.copy(),
+ JGitText.get().unknownObjectType2);
+ }
+ throw new MissingObjectException(objectId.copy(), typeHint);
+ }
+
+ private long getObjectSizeImpl(PackList packList, AnyObjectId objectId)
+ throws IOException {
+ for (DfsPackFile pack : packList.packs) {
+ if (pack == last) {
continue;
+ }
long sz = pack.getObjectSize(this, objectId);
if (0 <= sz) {
last = pack;
return sz;
}
}
-
- if (typeHint == OBJ_ANY)
- throw new MissingObjectException(objectId.copy(),
- JGitText.get().unknownObjectType2);
- throw new MissingObjectException(objectId.copy(), typeHint);
+ return -1;
}
public DfsObjectToPack newObjectToPack(AnyObjectId objectId, int type) {
@@ -451,6 +538,8 @@
public void selectObjectRepresentation(PackWriter packer,
ProgressMonitor monitor, Iterable<ObjectToPack> objects)
throws IOException, MissingObjectException {
+ // Don't check dirty bit on PackList; assume ObjectToPacks all came from the
+ // current list.
for (DfsPackFile pack : db.getPacks()) {
List<DfsObjectToPack> tmp = findAllFromPack(pack, objects);
if (tmp.isEmpty())
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 e5469f6..4ddcec1 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
@@ -217,10 +217,6 @@
else
detachingSymbolicRef = detach && ref.isSymbolic();
- if (detachingSymbolicRef) {
- ref = new ObjectIdRef.Unpeeled(NEW, refName, ref.getObjectId());
- }
-
DfsRefUpdate update = new DfsRefUpdate(this, ref);
if (detachingSymbolicRef)
update.setDetachingSymbolicRef();
@@ -315,6 +311,15 @@
/**
* Compare a reference, and put if it matches.
+ * <p>
+ * Two reference match if and only if they satisfy the following:
+ *
+ * <ul>
+ * <li>If one reference is a symbolic ref, the other one should be a symbolic
+ * ref.
+ * <li>If both are symbolic refs, the target names should be same.
+ * <li>If both are object ID refs, the object IDs should be same.
+ * </ul>
*
* @param oldRef
* old value to compare to. If the reference is expected to not
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index de18ead..6f390a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -24,7 +24,6 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefDatabase;
-import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -310,6 +309,7 @@
}
ids.sort();
sym.sort();
+ objdb.getCurrentPackList().markDirty();
return new RefCache(ids.toRefList(), sym.toRefList());
}
@@ -400,27 +400,8 @@
return refs.putIfAbsent(name, newRef) == null;
Ref cur = refs.get(name);
- Ref toCompare = cur;
- if (toCompare != null) {
- if (toCompare.isSymbolic()) {
- // Arm's-length dereference symrefs before the compare, since
- // DfsRefUpdate#doLink(String) stores them undereferenced.
- Ref leaf = toCompare.getLeaf();
- if (leaf.getObjectId() == null) {
- leaf = refs.get(leaf.getName());
- if (leaf.isSymbolic())
- // Not supported at the moment.
- throw new IllegalArgumentException();
- toCompare = new SymbolicRef(
- name,
- new ObjectIdRef.Unpeeled(
- Storage.NEW,
- leaf.getName(),
- leaf.getObjectId()));
- } else
- toCompare = toCompare.getLeaf();
- }
- if (eq(toCompare, oldRef))
+ if (cur != null) {
+ if (eq(cur, oldRef))
return refs.replace(name, cur, newRef);
}
@@ -451,10 +432,12 @@
private boolean eq(Ref a, Ref b) {
if (!Objects.equals(a.getName(), b.getName()))
return false;
- // Compare leaf object IDs, since the oldRef passed into compareAndPut
- // when detaching a symref is an ObjectIdRef.
- return Objects.equals(a.getLeaf().getObjectId(),
- b.getLeaf().getObjectId());
+ if (a.isSymbolic() != b.isSymbolic())
+ return false;
+ if (a.isSymbolic())
+ return Objects.equals(a.getTarget().getName(), b.getTarget().getName());
+ else
+ return Objects.equals(a.getObjectId(), b.getObjectId());
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
index e3f1e53..8926d79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.file;
import java.io.File;
+import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -102,8 +103,13 @@
* @return the snapshot.
*/
public static FileSnapshot save(File path) {
- final long read = System.currentTimeMillis();
- final long modified = path.lastModified();
+ long read = System.currentTimeMillis();
+ long modified;
+ try {
+ modified = FS.DETECTED.lastModified(path);
+ } catch (IOException e) {
+ modified = path.lastModified();
+ }
return new FileSnapshot(read, modified);
}
@@ -153,7 +159,13 @@
* @return true if the path needs to be read again.
*/
public boolean isModified(File path) {
- return isModified(path.lastModified());
+ long currLastModified;
+ try {
+ currLastModified = FS.DETECTED.lastModified(path);
+ } catch (IOException e) {
+ currLastModified = path.lastModified();
+ }
+ return isModified(currLastModified);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index c998ebe..a3e9430 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -189,9 +189,10 @@
* @param oldPacks
* @param newPacks
* @throws ParseException
+ * @throws IOException
*/
private void deleteOldPacks(Collection<PackFile> oldPacks,
- Collection<PackFile> newPacks) throws ParseException {
+ Collection<PackFile> newPacks) throws ParseException, IOException {
long packExpireDate = getPackExpireDate();
oldPackLoop: for (PackFile oldPack : oldPacks) {
String oldName = oldPack.getPackName();
@@ -202,7 +203,8 @@
continue oldPackLoop;
if (!oldPack.shouldBeKept()
- && oldPack.getPackFile().lastModified() < packExpireDate) {
+ && repo.getFS().lastModified(
+ oldPack.getPackFile()) < packExpireDate) {
oldPack.close();
prunePack(oldName);
}
@@ -338,7 +340,7 @@
String fName = f.getName();
if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2)
continue;
- if (f.lastModified() >= expireDate)
+ if (repo.getFS().lastModified(f) >= expireDate)
continue;
try {
ObjectId id = ObjectId.fromString(d + fName);
@@ -428,9 +430,14 @@
return;
// delete all candidates which have survived: these are unreferenced
- // loose objects
- for (File f : deletionCandidates.values())
- f.delete();
+ // loose objects. Make a last check, though, to avoid deleting objects
+ // that could have been referenced while the candidates list was being
+ // built (by an incoming push, for example).
+ for (File f : deletionCandidates.values()) {
+ if (f.lastModified() < expireDate) {
+ f.delete();
+ }
+ }
repo.getObjectDatabase().close();
}
@@ -889,7 +896,7 @@
* A class holding statistical data for a FileRepository regarding how many
* objects are stored as loose or packed objects
*/
- public class RepoStatistics {
+ public static class RepoStatistics {
/**
* The number of objects stored in pack files. If the same object is
* stored in multiple pack files then it is counted as often as it
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
index ce9677a..51af67e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -168,7 +168,7 @@
*/
public boolean lock() throws IOException {
FileUtils.mkdirs(lck.getParentFile(), true);
- if (lck.createNewFile()) {
+ if (FS.DETECTED.createNewFile(lck)) {
haveLck = true;
try {
os = new FileOutputStream(lck);
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 ea80528..6489415 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
@@ -337,6 +337,7 @@
for (PackFile p : pList.packs) {
try {
p.resolve(matches, id, RESOLVE_ABBREV_LIMIT);
+ p.resetTransientErrorCount();
} catch (IOException e) {
handlePackError(e, p);
}
@@ -418,6 +419,7 @@
for (PackFile p : pList.packs) {
try {
ObjectLoader ldr = p.get(curs, objectId);
+ p.resetTransientErrorCount();
if (ldr != null)
return ldr;
} catch (PackMismatchException e) {
@@ -496,6 +498,7 @@
for (PackFile p : pList.packs) {
try {
long len = p.getObjectSize(curs, id);
+ p.resetTransientErrorCount();
if (0 <= len)
return len;
} catch (PackMismatchException e) {
@@ -535,6 +538,7 @@
for (final PackFile p : pList.packs) {
try {
LocalObjectRepresentation rep = p.representation(curs, otp);
+ p.resetTransientErrorCount();
if (rep != null)
packer.select(otp, rep);
} catch (PackMismatchException e) {
@@ -555,6 +559,8 @@
private void handlePackError(IOException e, PackFile p) {
String warnTmpl = null;
+ int transientErrorCount = 0;
+ String errTmpl = JGitText.get().exceptionWhileReadingPack;
if ((e instanceof CorruptObjectException)
|| (e instanceof PackInvalidException)) {
warnTmpl = JGitText.get().corruptPack;
@@ -562,14 +568,17 @@
removePack(p);
} else if (e instanceof FileNotFoundException) {
if (p.getPackFile().exists()) {
- warnTmpl = JGitText.get().packInaccessible;
+ errTmpl = JGitText.get().packInaccessible;
+ transientErrorCount = p.incrementTransientErrorCount();
} else {
warnTmpl = JGitText.get().packWasDeleted;
+ removePack(p);
}
- removePack(p);
} else if (FileUtils.isStaleFileHandle(e)) {
warnTmpl = JGitText.get().packHandleIsStale;
removePack(p);
+ } else {
+ transientErrorCount = p.incrementTransientErrorCount();
}
if (warnTmpl != null) {
if (LOG.isDebugEnabled()) {
@@ -580,14 +589,25 @@
p.getPackFile().getAbsolutePath()));
}
} else {
- // Don't remove the pack from the list, as the error may be
- // transient.
- LOG.error(MessageFormat.format(
- JGitText.get().exceptionWhileReadingPack, p.getPackFile()
- .getAbsolutePath()), e);
+ if (doLogExponentialBackoff(transientErrorCount)) {
+ // Don't remove the pack from the list, as the error may be
+ // transient.
+ LOG.error(MessageFormat.format(errTmpl,
+ p.getPackFile().getAbsolutePath()),
+ Integer.valueOf(transientErrorCount), e);
+ }
}
}
+ /**
+ * @param n
+ * count of consecutive failures
+ * @return @{code true} if i is a power of 2
+ */
+ private boolean doLogExponentialBackoff(int n) {
+ return (n & (n - 1)) == 0;
+ }
+
@Override
InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id,
boolean createDuplicate) throws IOException {
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 b385b8a..b5889f2 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
@@ -50,17 +50,21 @@
import java.io.EOFException;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel.MapMode;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.NoSuchFileException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -68,9 +72,13 @@
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.NoPackSignatureException;
import org.eclipse.jgit.errors.PackInvalidException;
import org.eclipse.jgit.errors.PackMismatchException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
+import org.eclipse.jgit.errors.UnpackException;
+import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException;
+import org.eclipse.jgit.errors.UnsupportedPackVersionException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
@@ -125,6 +133,8 @@
private boolean invalidBitmap;
+ private AtomicInteger transientErrorCount = new AtomicInteger();
+
private byte[] packChecksum;
private PackIndex loadedIdx;
@@ -568,6 +578,14 @@
invalid = true;
}
+ int incrementTransientErrorCount() {
+ return transientErrorCount.incrementAndGet();
+ }
+
+ void resetTransientErrorCount() {
+ transientErrorCount.set(0);
+ }
+
private void readFully(final long position, final byte[] dstbuf,
int dstoff, final int cnt, final WindowCursor curs)
throws IOException {
@@ -624,15 +642,25 @@
// don't invalidate the pack, we are interrupted from another thread
openFail(false);
throw e;
- } catch (IOException ioe) {
+ } catch (FileNotFoundException fn) {
+ // don't invalidate the pack if opening an existing file failed
+ // since it may be related to a temporary lack of resources (e.g.
+ // max open files)
+ openFail(!packFile.exists());
+ throw fn;
+ } catch (EOFException | AccessDeniedException | NoSuchFileException
+ | CorruptObjectException | NoPackSignatureException
+ | PackMismatchException | UnpackException
+ | UnsupportedPackIndexVersionException
+ | UnsupportedPackVersionException pe) {
+ // exceptions signaling permanent problems with a pack
openFail(true);
- throw ioe;
- } catch (RuntimeException re) {
- openFail(true);
- throw re;
- } catch (Error re) {
- openFail(true);
- throw re;
+ throw pe;
+ } catch (IOException | RuntimeException ge) {
+ // generic exceptions could be transient so we should not mark the
+ // pack invalid to avoid false MissingObjectExceptions
+ openFail(false);
+ throw ge;
}
}
@@ -699,28 +727,31 @@
fd.seek(0);
fd.readFully(buf, 0, 12);
- if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4)
- throw new IOException(JGitText.get().notAPACKFile);
+ if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4) {
+ throw new NoPackSignatureException(JGitText.get().notAPACKFile);
+ }
final long vers = NB.decodeUInt32(buf, 4);
final long packCnt = NB.decodeUInt32(buf, 8);
- if (vers != 2 && vers != 3)
- throw new IOException(MessageFormat.format(
- JGitText.get().unsupportedPackVersion, Long.valueOf(vers)));
+ if (vers != 2 && vers != 3) {
+ throw new UnsupportedPackVersionException(vers);
+ }
- if (packCnt != idx.getObjectCount())
+ if (packCnt != idx.getObjectCount()) {
throw new PackMismatchException(MessageFormat.format(
JGitText.get().packObjectCountMismatch,
Long.valueOf(packCnt), Long.valueOf(idx.getObjectCount()),
getPackFile()));
+ }
fd.seek(length - 20);
fd.readFully(buf, 0, 20);
- if (!Arrays.equals(buf, packChecksum))
+ if (!Arrays.equals(buf, packChecksum)) {
throw new PackMismatchException(MessageFormat.format(
JGitText.get().packObjectCountMismatch
, ObjectId.fromRaw(buf).name()
, ObjectId.fromRaw(idx.packChecksum).name()
, getPackFile()));
+ }
}
ObjectLoader load(final WindowCursor curs, long pos)
@@ -1074,8 +1105,17 @@
if (invalid || invalidBitmap)
return null;
if (bitmapIdx == null && hasExt(BITMAP_INDEX)) {
- final PackBitmapIndex idx = PackBitmapIndex.open(
- extFile(BITMAP_INDEX), idx(), getReverseIdx());
+ final PackBitmapIndex idx;
+ try {
+ idx = PackBitmapIndex.open(extFile(BITMAP_INDEX), idx(),
+ getReverseIdx());
+ } catch (FileNotFoundException e) {
+ // Once upon a time this bitmap file existed. Now it
+ // has been removed. Most likely an external gc has
+ // removed this packfile and the bitmap
+ invalidBitmap = true;
+ return null;
+ }
// At this point, idx() will have set packChecksum.
if (Arrays.equals(packChecksum, idx.packChecksum))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index f36bd4d..5d4a30f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -55,6 +55,7 @@
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
@@ -138,9 +139,7 @@
case 2:
return new PackIndexV2(fd);
default:
- throw new IOException(MessageFormat.format(
- JGitText.get().unsupportedPackIndexVersion,
- Integer.valueOf(v)));
+ throw new UnsupportedPackIndexVersionException(v);
}
}
return new PackIndexV1(fd, hdr);
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 e5ca736..cd98539 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
@@ -80,6 +80,7 @@
import org.eclipse.jgit.errors.ObjectWritingException;
import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
@@ -545,8 +546,6 @@
ref = new ObjectIdRef.Unpeeled(NEW, name, null);
else {
detachingSymbolicRef = detach && ref.isSymbolic();
- if (detachingSymbolicRef)
- ref = new ObjectIdRef.Unpeeled(LOOSE, name, ref.getObjectId());
}
RefDirectoryUpdate refDirUpdate = new RefDirectoryUpdate(this, ref);
if (detachingSymbolicRef)
@@ -579,7 +578,7 @@
}
void delete(RefDirectoryUpdate update) throws IOException {
- Ref dst = update.getRef().getLeaf();
+ Ref dst = update.getRef();
String name = dst.getName();
// Write the packed-refs file using an atomic update. We might
@@ -767,14 +766,20 @@
}
private PackedRefList getPackedRefs() throws IOException {
+ boolean trustFolderStat = getRepository().getConfig().getBoolean(
+ ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
+
final PackedRefList curList = packedRefs.get();
- if (!curList.snapshot.isModified(packedRefsFile))
+ if (trustFolderStat && !curList.snapshot.isModified(packedRefsFile)) {
return curList;
+ }
final PackedRefList newList = readPackedRefs();
if (packedRefs.compareAndSet(curList, newList)
- && !curList.id.equals(newList.id))
+ && !curList.id.equals(newList.id)) {
modCnt.incrementAndGet();
+ }
return newList;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
index 0d16f79..3c1916b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
@@ -56,6 +56,7 @@
class RefDirectoryUpdate extends RefUpdate {
private final RefDirectory database;
+ private boolean shouldDeref;
private LockFile lock;
RefDirectoryUpdate(final RefDirectory r, final Ref ref) {
@@ -75,6 +76,7 @@
@Override
protected boolean tryLock(boolean deref) throws IOException {
+ shouldDeref = deref;
Ref dst = getRef();
if (deref)
dst = dst.getLeaf();
@@ -117,7 +119,7 @@
msg = strResult;
}
}
- database.log(this, msg, true);
+ database.log(this, msg, shouldDeref);
}
if (!lock.commit())
return Result.LOCK_FAILURE;
@@ -140,7 +142,7 @@
@Override
protected Result doDelete(final Result status) throws IOException {
- if (getRef().getLeaf().getStorage() != Ref.Storage.NEW)
+ if (getRef().getStorage() != Ref.Storage.NEW)
database.delete(this);
return status;
}
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 525f9ae..691867a 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
@@ -564,7 +564,8 @@
* Configure this pack for a shallow clone.
*
* @param depth
- * maximum depth to traverse the commit graph
+ * maximum depth of history to return. 1 means return only the
+ * "wants".
* @param unshallow
* objects which used to be shallow on the client, but are being
* extended as part of this fetch
@@ -709,11 +710,52 @@
public void preparePack(ProgressMonitor countingMonitor,
@NonNull Set<? extends ObjectId> want,
@NonNull Set<? extends ObjectId> have) throws IOException {
+ preparePack(countingMonitor,
+ want, have, Collections.<ObjectId> emptySet());
+ }
+
+ /**
+ * Prepare the list of objects to be written to the pack stream.
+ * <p>
+ * Like {@link #preparePack(ProgressMonitor, Set, Set)} but also allows
+ * specifying commits that should not be walked past ("shallow" commits).
+ * The caller is responsible for filtering out commits that should not
+ * be shallow any more ("unshallow" commits as in {@link #setShallowPack})
+ * from the shallow set.
+ *
+ * @param countingMonitor
+ * progress during object enumeration.
+ * @param want
+ * objects of interest, ancestors of which will be included in
+ * the pack. Must not be {@code null}.
+ * @param have
+ * objects whose ancestors (up to and including
+ * {@code shallow} commits) do not need to be included in the
+ * pack because they are already available from elsewhere.
+ * Must not be {@code null}.
+ * @param shallow
+ * commits indicating the boundary of the history marked with
+ * {@code have}. Shallow commits have parents but those
+ * parents are considered not to be already available.
+ * Parents of {@code shallow} commits and earlier generations
+ * will be included in the pack if requested by {@code want}.
+ * Must not be {@code null}.
+ * @throws IOException
+ * an I/O problem occured while reading objects.
+ *
+ * @since 4.5
+ */
+ public void preparePack(ProgressMonitor countingMonitor,
+ @NonNull Set<? extends ObjectId> want,
+ @NonNull Set<? extends ObjectId> have,
+ @NonNull Set<? extends ObjectId> shallow) throws IOException {
ObjectWalk ow;
- if (shallowPack)
- ow = new DepthWalk.ObjectWalk(reader, depth);
- else
+ if (shallowPack) {
+ ow = new DepthWalk.ObjectWalk(reader, depth - 1);
+ } else {
ow = new ObjectWalk(reader);
+ }
+ ow.assumeShallow(shallow);
preparePack(countingMonitor, ow, want, have);
}
@@ -752,7 +794,8 @@
if (countingMonitor == null)
countingMonitor = NullProgressMonitor.INSTANCE;
if (shallowPack && !(walk instanceof DepthWalk.ObjectWalk))
- walk = new DepthWalk.ObjectWalk(reader, depth);
+ throw new IllegalArgumentException(
+ JGitText.get().shallowPacksRequireDepthWalk);
findObjectsToPack(countingMonitor, walk, interestingObjects,
uninterestingObjects);
}
@@ -1653,6 +1696,8 @@
List<RevObject> haveObjs = new ArrayList<RevObject>(haveEst);
List<RevTag> wantTags = new ArrayList<RevTag>(want.size());
+ // Retrieve the RevWalk's versions of "want" and "have" objects to
+ // maintain any state previously set in the RevWalk.
AsyncRevObjectQueue q = walker.parseAny(all, true);
try {
for (;;) {
@@ -1695,11 +1740,25 @@
if (walker instanceof DepthWalk.ObjectWalk) {
DepthWalk.ObjectWalk depthWalk = (DepthWalk.ObjectWalk) walker;
- for (RevObject obj : wantObjs)
+ for (RevObject obj : wantObjs) {
depthWalk.markRoot(obj);
+ }
+ // Mark the tree objects associated with "have" commits as
+ // uninteresting to avoid writing redundant blobs. A normal RevWalk
+ // lazily propagates the "uninteresting" state from a commit to its
+ // tree during the walk, but DepthWalks can terminate early so
+ // preemptively propagate that state here.
+ for (RevObject obj : haveObjs) {
+ if (obj instanceof RevCommit) {
+ RevTree t = ((RevCommit) obj).getTree();
+ depthWalk.markUninteresting(t);
+ }
+ }
+
if (unshallowObjects != null) {
- for (ObjectId id : unshallowObjects)
+ for (ObjectId id : unshallowObjects) {
depthWalk.markUnshallow(walker.parseAny(id));
+ }
}
} else {
for (RevObject obj : wantObjs)
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 35cadd3..8550ec3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -92,6 +92,9 @@
/** Whether updates should be atomic. */
private boolean atomic;
+ /** Push options associated with this update. */
+ private List<String> pushOptions;
+
/**
* Initialize a new batch update.
*
@@ -301,27 +304,40 @@
}
/**
+ * Gets the list of option strings associated with this update.
+ *
+ * @return pushOptions
+ * @since 4.5
+ */
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
+
+ /**
* Execute this batch update.
* <p>
* The default implementation of this method performs a sequential reference
* update over each reference.
* <p>
* Implementations must respect the atomicity requirements of the underlying
- * database as described in {@link #setAtomic(boolean)} and {@link
- * RefDatabase#performsAtomicTransactions()}.
+ * database as described in {@link #setAtomic(boolean)} and
+ * {@link RefDatabase#performsAtomicTransactions()}.
*
* @param walk
* a RevWalk to parse tags in case the storage system wants to
* store them pre-peeled, a common performance optimization.
* @param monitor
* progress monitor to receive update status on.
+ * @param options
+ * a list of option strings; set null to execute without
* @throws IOException
* the database is unable to accept the update. Individual
* command status must be tested to determine if there is a
* partial failure, or a total failure.
+ * @since 4.5
*/
- public void execute(RevWalk walk, ProgressMonitor monitor)
- throws IOException {
+ public void execute(RevWalk walk, ProgressMonitor monitor,
+ List<String> options) throws IOException {
if (atomic && !refdb.performsAtomicTransactions()) {
for (ReceiveCommand c : commands) {
@@ -333,10 +349,13 @@
return;
}
+ if (options != null) {
+ pushOptions = options;
+ }
+
monitor.beginTask(JGitText.get().updatingReferences, commands.size());
List<ReceiveCommand> commands2 = new ArrayList<ReceiveCommand>(
commands.size());
- List<String> namesToCheck = new ArrayList<String>(commands.size());
// First delete refs. This may free the name space for some of the
// updates.
for (ReceiveCommand cmd : commands) {
@@ -345,7 +364,6 @@
cmd.updateType(walk);
switch (cmd.getType()) {
case CREATE:
- namesToCheck.add(cmd.getRefName());
commands2.add(cmd);
break;
case UPDATE:
@@ -414,6 +432,24 @@
monitor.endTask();
}
+ /**
+ * Execute this batch update without option strings.
+ *
+ * @param walk
+ * a RevWalk to parse tags in case the storage system wants to
+ * store them pre-peeled, a common performance optimization.
+ * @param monitor
+ * progress monitor to receive update status on.
+ * @throws IOException
+ * the database is unable to accept the update. Individual
+ * command status must be tested to determine if there is a
+ * partial failure, or a total failure.
+ */
+ public void execute(RevWalk walk, ProgressMonitor monitor)
+ throws IOException {
+ execute(walk, monitor, null);
+ }
+
private static Collection<String> getTakenPrefixes(
final Collection<String> names) {
Collection<String> ref = new HashSet<String>();
@@ -487,7 +523,11 @@
for (ReceiveCommand cmd : commands) {
r.append(" "); //$NON-NLS-1$
r.append(cmd);
- r.append(" (").append(cmd.getResult()).append(")\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ r.append(" (").append(cmd.getResult()); //$NON-NLS-1$
+ if (cmd.getMessage() != null) {
+ r.append(": ").append(cmd.getMessage()); //$NON-NLS-1$
+ }
+ r.append(")\n"); //$NON-NLS-1$
}
return r.append(']').toString();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
index a62f6c3..f1b7fb2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
@@ -55,6 +55,39 @@
public class BranchConfig {
/**
+ * Config values for branch.[name].rebase (and pull.rebase).
+ *
+ * @since 4.5
+ */
+ public enum BranchRebaseMode implements Config.ConfigEnum {
+
+ /** Value for rebasing */
+ REBASE("true"), //$NON-NLS-1$
+ /** Value for rebasing preserving local merge commits */
+ PRESERVE("preserve"), //$NON-NLS-1$
+ /** Value for rebasing interactively */
+ INTERACTIVE("interactive"), //$NON-NLS-1$
+ /** Value for not rebasing at all but merging */
+ NONE("false"); //$NON-NLS-1$
+
+ private final String configValue;
+
+ private BranchRebaseMode(String configValue) {
+ this.configValue = configValue;
+ }
+
+ @Override
+ public String toConfigValue() {
+ return configValue;
+ }
+
+ @Override
+ public boolean matchConfigValue(String s) {
+ return configValue.equals(s);
+ }
+ }
+
+ /**
* The value that means "local repository" for {@link #getRemote()}:
* {@value}
*
@@ -143,8 +176,19 @@
* @since 3.5
*/
public boolean isRebase() {
- return config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
- branchName, ConfigConstants.CONFIG_KEY_REBASE, false);
+ return getRebaseMode() != BranchRebaseMode.NONE;
+ }
+
+ /**
+ * Retrieves the config value of branch.[name].rebase.
+ *
+ * @return the {@link BranchRebaseMode}
+ * @since 4.5
+ */
+ public BranchRebaseMode getRebaseMode() {
+ return config.getEnum(BranchRebaseMode.values(),
+ ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
+ ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
}
/**
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 1e1d147..8fe8a96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -510,7 +510,7 @@
* indication of the units.
* @return the value, or {@code defaultValue} if not set, expressed in
* {@code units}.
- * @since 4.4
+ * @since 4.5
*/
public long getTimeUnit(String section, String subsection, String name,
long defaultValue, TimeUnit wantUnit) {
@@ -835,11 +835,11 @@
final String s;
if (value >= GiB && (value % GiB) == 0)
- s = String.valueOf(value / GiB) + " g"; //$NON-NLS-1$
+ s = String.valueOf(value / GiB) + "g"; //$NON-NLS-1$
else if (value >= MiB && (value % MiB) == 0)
- s = String.valueOf(value / MiB) + " m"; //$NON-NLS-1$
+ s = String.valueOf(value / MiB) + "m"; //$NON-NLS-1$
else if (value >= KiB && (value % KiB) == 0)
- s = String.valueOf(value / KiB) + " k"; //$NON-NLS-1$
+ s = String.valueOf(value / KiB) + "k"; //$NON-NLS-1$
else
s = String.valueOf(value);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 9e3e0b7..e3f8ba5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -290,6 +290,13 @@
public static final String CONFIG_KEY_TRUSTFOLDERSTAT = "trustfolderstat";
/**
+ * The "supportsAtomicFileCreation" key in the "core section"
+ *
+ * @since 4.5
+ */
+ public static final String CONFIG_KEY_SUPPORTSATOMICFILECREATION = "supportsatomicfilecreation";
+
+ /**
* The "noprefix" key in the "diff section"
* @since 3.0
*/
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 c1027f0..fc334f0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -551,7 +551,9 @@
* @throws IOException
*/
public Result delete(final RevWalk walk) throws IOException {
- final String myName = getRef().getLeaf().getName();
+ final String myName = detachingSymbolicRef
+ ? getRef().getName()
+ : getRef().getLeaf().getName();
if (myName.startsWith(Constants.R_HEADS) && !getRepository().isBare()) {
// Don't allow the currently checked out branch to be deleted.
Ref head = getRefDatabase().getRef(Constants.HEAD);
@@ -628,7 +630,10 @@
if (oldValue == null && checkConflicting && getRefDatabase().isNameConflicting(getName()))
return Result.LOCK_FAILURE;
try {
- if (!tryLock(true))
+ // If we're detaching a symbolic reference, we should update the reference
+ // itself. Otherwise, we will update the leaf reference, which should be
+ // an ObjectIdRef.
+ if (!tryLock(!detachingSymbolicRef))
return Result.LOCK_FAILURE;
if (expValue != null) {
final ObjectId o;
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 7ec2499..aba5242 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -880,10 +880,11 @@
} else if (newCount == -1) {
// should not happen, only log when useCnt became negative to
// minimize number of log entries
- LOG.warn(JGitText.get().corruptUseCnt);
if (LOG.isDebugEnabled()) {
IllegalStateException e = new IllegalStateException();
- LOG.debug("", e); //$NON-NLS-1$
+ LOG.debug(JGitText.get().corruptUseCnt, e);
+ } else {
+ LOG.warn(JGitText.get().corruptUseCnt);
}
if (RepositoryCache.isCached(this)) {
closedAt.set(System.currentTimeMillis());
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 29ef084..7a8d246 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -298,18 +298,16 @@
}
private boolean isExpired(Repository db) {
- return db != null && db.useCnt.get() == 0
+ return db != null && db.useCnt.get() <= 0
&& (System.currentTimeMillis() - db.closedAt.get() > expireAfter);
}
private void unregisterAndCloseRepository(final Key location,
Repository db) {
synchronized (lockFor(location)) {
- if (isExpired(db)) {
- Repository oldDb = unregisterRepository(location);
- if (oldDb != null) {
- oldDb.close();
- }
+ Repository oldDb = unregisterRepository(location);
+ if (oldDb != null) {
+ oldDb.doClose();
}
}
}
@@ -328,15 +326,9 @@
}
private void clearAll() {
- for (int stage = 0; stage < 2; stage++) {
- for (Iterator<Map.Entry<Key, Reference<Repository>>> i = cacheMap
- .entrySet().iterator(); i.hasNext();) {
- final Map.Entry<Key, Reference<Repository>> e = i.next();
- final Repository db = e.getValue().get();
- if (db != null)
- db.close();
- i.remove();
- }
+ for (Iterator<Map.Entry<Key, Reference<Repository>>> i = cacheMap
+ .entrySet().iterator(); i.hasNext();) {
+ unregisterAndCloseRepository(i.next().getKey(), null);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
index 977f953..ee6095a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
@@ -102,6 +102,7 @@
* metadata
* @throws IOException
*/
+ @SuppressWarnings("unchecked")
public void formatMerge(OutputStream out, MergeResult res, String baseName,
String oursName, String theirsName, String charsetName) throws IOException {
List<String> names = new ArrayList<String>(3);
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 e224d71..fd5e7ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -761,7 +761,7 @@
: FileMode.fromBits(newMode));
if (mergedFile != null) {
long len = mergedFile.length();
- dce.setLastModified(mergedFile.lastModified());
+ dce.setLastModified(FS.DETECTED.lastModified(mergedFile));
dce.setLength((int) len);
InputStream is = new FileInputStream(mergedFile);
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
index 89d05db..59a360f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
@@ -149,6 +149,17 @@
public RevFlag getReinterestingFlag() {
return REINTERESTING;
}
+
+ /**
+ * @since 4.5
+ */
+ @Override
+ public ObjectWalk toObjectWalkWithSameObjects() {
+ ObjectWalk ow = new ObjectWalk(reader, depth);
+ ow.objects = objects;
+ ow.freeFlags = freeFlags;
+ return ow;
+ }
}
/** Subclass of ObjectWalk that performs depth filtering. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
index e67ada6..1e91006 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
@@ -244,7 +244,7 @@
if ((p.flags & carry) == carry)
continue;
p.flags |= carry;
- FIFORevQueue q = carryFlags1(c, carry, depth + 1);
+ FIFORevQueue q = carryFlags1(p, carry, depth + 1);
if (q != null)
return defer(q, carry, pList, i + 1);
}
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 c850493..a7f7cd4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -172,7 +172,7 @@
ObjectIdOwnerMap<RevObject> objects;
- private int freeFlags = APP_FLAGS;
+ int freeFlags = APP_FLAGS;
private int delayFreeFlags;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index 4b4822c..9a38846 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -65,13 +65,19 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* The configuration file that is stored in the file of the file system.
*/
public class FileBasedConfig extends StoredConfig {
+ private final static Logger LOG = LoggerFactory
+ .getLogger(FileBasedConfig.class);
+
private final File configFile;
private boolean utf8Bom;
@@ -135,41 +141,58 @@
*/
@Override
public void load() throws IOException, ConfigInvalidException {
- final FileSnapshot oldSnapshot = snapshot;
- final FileSnapshot newSnapshot = FileSnapshot.save(getFile());
- try {
- final byte[] in = IO.readFully(getFile());
- final ObjectId newHash = hash(in);
- if (hash.equals(newHash)) {
- if (oldSnapshot.equals(newSnapshot))
- oldSnapshot.setClean(newSnapshot);
- else
- snapshot = newSnapshot;
- } else {
- final String decoded;
- if (isUtf8(in)) {
- decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
- in, 3, in.length);
- utf8Bom = true;
+ final int maxStaleRetries = 5;
+ int retries = 0;
+ while (true) {
+ final FileSnapshot oldSnapshot = snapshot;
+ final FileSnapshot newSnapshot = FileSnapshot.save(getFile());
+ try {
+ final byte[] in = IO.readFully(getFile());
+ final ObjectId newHash = hash(in);
+ if (hash.equals(newHash)) {
+ if (oldSnapshot.equals(newSnapshot)) {
+ oldSnapshot.setClean(newSnapshot);
+ } else {
+ snapshot = newSnapshot;
+ }
} else {
- decoded = RawParseUtils.decode(in);
+ final String decoded;
+ if (isUtf8(in)) {
+ decoded = RawParseUtils.decode(
+ RawParseUtils.UTF8_CHARSET, in, 3, in.length);
+ utf8Bom = true;
+ } else {
+ decoded = RawParseUtils.decode(in);
+ }
+ fromText(decoded);
+ snapshot = newSnapshot;
+ hash = newHash;
}
- fromText(decoded);
+ return;
+ } catch (FileNotFoundException noFile) {
+ if (configFile.exists()) {
+ throw noFile;
+ }
+ clear();
snapshot = newSnapshot;
- hash = newHash;
+ return;
+ } catch (IOException e) {
+ if (FileUtils.isStaleFileHandle(e)
+ && retries < maxStaleRetries) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(MessageFormat.format(
+ JGitText.get().configHandleIsStale,
+ Integer.valueOf(retries)), e);
+ }
+ retries++;
+ continue;
+ }
+ throw new IOException(MessageFormat
+ .format(JGitText.get().cannotReadFile, getFile()), e);
+ } catch (ConfigInvalidException e) {
+ throw new ConfigInvalidException(MessageFormat
+ .format(JGitText.get().cannotReadFile, getFile()), e);
}
- } catch (FileNotFoundException noFile) {
- if (configFile.exists()) {
- throw noFile;
- }
- clear();
- snapshot = newSnapshot;
- } catch (IOException e) {
- final IOException e2 = new IOException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()));
- e2.initCause(e);
- throw e2;
- } catch (ConfigInvalidException e) {
- throw new ConfigInvalidException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()), e);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 9b8ba80..86cc484 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -47,10 +47,12 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -112,14 +114,24 @@
*/
public static final String CAPABILITY_SIDE_BAND_64K = GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
+ /**
+ * The server supports the receiving of push options.
+ * @since 4.5
+ */
+ public static final String CAPABILITY_PUSH_OPTIONS = GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
+
private final boolean thinPack;
private final boolean atomic;
+ /** A list of option strings associated with this push. */
+ private List<String> pushOptions;
+
private boolean capableAtomic;
private boolean capableDeleteRefs;
private boolean capableReport;
private boolean capableSideBand;
private boolean capableOfsDelta;
+ private boolean capablePushOptions;
private boolean sentCommand;
private boolean writePack;
@@ -137,6 +149,7 @@
super(packTransport);
thinPack = transport.isPushThin();
atomic = transport.isPushAtomic();
+ pushOptions = transport.getPushOptions();
}
public void push(final ProgressMonitor monitor,
@@ -196,6 +209,9 @@
OutputStream outputStream) throws TransportException {
try {
writeCommands(refUpdates.values(), monitor, outputStream);
+
+ if (pushOptions != null && capablePushOptions)
+ transmitOptions();
if (writePack)
writePack(refUpdates, monitor);
if (sentCommand) {
@@ -231,6 +247,12 @@
JGitText.get().atomicPushNotSupported);
}
+ if (pushOptions != null && !capablePushOptions) {
+ throw new TransportException(uri,
+ MessageFormat.format(JGitText.get().pushOptionsNotSupported,
+ pushOptions.toString()));
+ }
+
for (final RemoteRefUpdate rru : refUpdates) {
if (!capableDeleteRefs && rru.isDelete()) {
rru.setStatus(Status.REJECTED_NODELETE);
@@ -268,6 +290,14 @@
outNeedsEnd = false;
}
+ private void transmitOptions() throws IOException {
+ for (final String pushOption : pushOptions) {
+ pckOut.writeString(pushOption);
+ }
+
+ pckOut.end();
+ }
+
private String enableCapabilities(final ProgressMonitor monitor,
OutputStream outputStream) {
final StringBuilder line = new StringBuilder();
@@ -277,6 +307,10 @@
capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);
capableOfsDelta = wantCapability(line, CAPABILITY_OFS_DELTA);
+ if (pushOptions != null) {
+ capablePushOptions = wantCapability(line, CAPABILITY_PUSH_OPTIONS);
+ }
+
capableSideBand = wantCapability(line, CAPABILITY_SIDE_BAND_64K);
if (capableSideBand) {
in = new SideBandInputStream(in, monitor, getMessageWriter(),
@@ -317,7 +351,12 @@
writer.setReuseValidatingObjects(false);
writer.setDeltaBaseAsOffset(capableOfsDelta);
writer.preparePack(monitor, newObjects, remoteObjects);
- writer.writePack(monitor, monitor, out);
+
+ OutputStream packOut = out;
+ if (capableSideBand) {
+ packOut = new CheckingSideBandOutputStream(in, out);
+ }
+ writer.writePack(monitor, monitor, packOut);
packTransferTime = writer.getStatistics().getTimeWriting();
}
@@ -327,7 +366,8 @@
throws IOException {
final String unpackLine = readStringLongTimeout();
if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$
- throw new PackProtocolException(uri, MessageFormat.format(JGitText.get().unexpectedReportLine, unpackLine));
+ throw new PackProtocolException(uri, MessageFormat
+ .format(JGitText.get().unexpectedReportLine, unpackLine));
final String unpackStatus = unpackLine.substring("unpack ".length()); //$NON-NLS-1$
if (unpackStatus.startsWith("error Pack exceeds the limit of")) {//$NON-NLS-1$
throw new TooLargePackException(uri,
@@ -397,4 +437,58 @@
timeoutIn.setTimeout(oldTimeout);
}
}
+
+ /**
+ * Gets the list of option strings associated with this push.
+ *
+ * @return pushOptions
+ * @since 4.5
+ */
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
+
+ private static class CheckingSideBandOutputStream extends OutputStream {
+ private final InputStream in;
+ private final OutputStream out;
+
+ CheckingSideBandOutputStream(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ write(new byte[] { (byte) b });
+ }
+
+ @Override
+ public void write(byte[] buf, int ptr, int cnt) throws IOException {
+ try {
+ out.write(buf, ptr, cnt);
+ } catch (IOException e) {
+ throw checkError(e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ out.flush();
+ } catch (IOException e) {
+ throw checkError(e);
+ }
+ }
+
+ private IOException checkError(IOException e1) {
+ try {
+ in.read();
+ } catch (TransportException e2) {
+ return e2;
+ } catch (IOException e2) {
+ return e1;
+ }
+ return e1;
+ }
+ }
}
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 b5f9e2f..0724eac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -46,11 +46,13 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
+import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
@@ -67,6 +69,7 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.errors.InvalidObjectIdException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.errors.TooLargePackException;
@@ -176,6 +179,9 @@
/** Should an incoming transfer permit non-fast-forward requests? */
private boolean allowNonFastForwards;
+ /** Should an incoming transfer permit push options? **/
+ private boolean allowPushOptions;
+
/**
* Should the requested ref updates be performed as a single atomic
* transaction?
@@ -214,6 +220,7 @@
/** Optional message output stream. */
protected OutputStream msgOut;
+ private SideBandOutputStream errOut;
/** Packet line input stream around {@link #rawIn}. */
protected PacketLineIn pckIn;
@@ -308,6 +315,7 @@
allowBranchDeletes = rc.allowDeletes;
allowNonFastForwards = rc.allowNonFastForwards;
allowOfsDelta = rc.allowOfsDelta;
+ allowPushOptions = rc.allowPushOptions;
advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
refFilter = RefFilter.DEFAULT;
advertisedHaves = new HashSet<ObjectId>();
@@ -327,6 +335,8 @@
final boolean allowDeletes;
final boolean allowNonFastForwards;
final boolean allowOfsDelta;
+ final boolean allowPushOptions;
+
final SignedPushConfig signedPush;
ReceiveConfig(final Config config) {
@@ -336,6 +346,8 @@
"denynonfastforwards", false); //$NON-NLS-1$
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
true);
+ allowPushOptions = config.getBoolean("receive", "pushoptions", //$NON-NLS-1$ //$NON-NLS-2$
+ false);
signedPush = SignedPushConfig.KEY.parse(config);
}
}
@@ -757,8 +769,7 @@
* read.
*/
public boolean isSideBand() throws RequestNotYetReadException {
- if (enabledCapabilities == null)
- throw new RequestNotYetReadException();
+ checkRequestWasRead();
return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K);
}
@@ -785,6 +796,25 @@
}
/**
+ * @return true if the server supports receiving push options.
+ * @since 4.5
+ */
+ public boolean isAllowPushOptions() {
+ return allowPushOptions;
+ }
+
+ /**
+ * Configure if the server supports receiving push options.
+ *
+ * @param allow
+ * true to optionally accept option strings from the client.
+ * @since 4.5
+ */
+ public void setAllowPushOptions(boolean allow) {
+ allowPushOptions = allow;
+ }
+
+ /**
* True if the client wants less verbose output.
*
* @return true if the client has requested the server to be less verbose.
@@ -796,8 +826,7 @@
* @since 4.0
*/
public boolean isQuiet() throws RequestNotYetReadException {
- if (enabledCapabilities == null)
- throw new RequestNotYetReadException();
+ checkRequestWasRead();
return quiet;
}
@@ -878,6 +907,19 @@
}
}
+ private void fatalError(String msg) {
+ if (errOut != null) {
+ try {
+ errOut.write(Constants.encode(msg));
+ errOut.flush();
+ } catch (IOException e) {
+ // Ignore write failures
+ }
+ } else {
+ sendError(msg);
+ }
+ }
+
/**
* Send a message to the client, if it supports receiving them.
* <p>
@@ -1060,6 +1102,9 @@
adv.advertiseCapability(CAPABILITY_ATOMIC);
if (allowOfsDelta)
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
+ if (allowPushOptions) {
+ adv.advertiseCapability(CAPABILITY_PUSH_OPTIONS);
+ }
adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
adv.send(getAdvertisedOrDefaultRefs());
for (ObjectId obj : advertisedHaves)
@@ -1076,7 +1121,7 @@
*/
protected void recvCommands() throws IOException {
PushCertificateParser certParser = getPushCertificateParser();
- FirstLine firstLine = null;
+ boolean firstPkt = true;
try {
for (;;) {
String line;
@@ -1092,14 +1137,16 @@
}
if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$
- clientShallowCommits.add(ObjectId.fromString(line.substring(8, 48)));
+ parseShallow(line.substring(8, 48));
continue;
}
- if (firstLine == null) {
- firstLine = new FirstLine(line);
+ if (firstPkt) {
+ firstPkt = false;
+ FirstLine firstLine = new FirstLine(line);
enabledCapabilities = firstLine.getCapabilities();
line = firstLine.getLine();
+ enableCapabilities();
if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) {
certParser.receiveHeader(pckIn, !isBiDirectionalPipe());
@@ -1112,13 +1159,7 @@
continue;
}
- ReceiveCommand cmd;
- try {
- cmd = parseCommand(line);
- } catch (PackProtocolException e) {
- sendError(e.getMessage());
- throw e;
- }
+ ReceiveCommand cmd = parseCommand(line);
if (cmd.getRefName().equals(Constants.HEAD)) {
cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
} else {
@@ -1130,12 +1171,32 @@
}
}
pushCert = certParser.build();
+ if (hasCommands()) {
+ readPostCommands(pckIn);
+ }
} catch (PackProtocolException e) {
- sendError(e.getMessage());
+ if (sideBand) {
+ try {
+ pckIn.discardUntilEnd();
+ } catch (IOException e2) {
+ // Ignore read failures attempting to discard.
+ }
+ }
+ fatalError(e.getMessage());
throw e;
}
}
+ private void parseShallow(String idStr) throws PackProtocolException {
+ ObjectId id;
+ try {
+ id = ObjectId.fromString(idStr);
+ } catch (InvalidObjectIdException e) {
+ throw new PackProtocolException(e.getMessage(), e);
+ }
+ clientShallowCommits.add(id);
+ }
+
static ReceiveCommand parseCommand(String line) throws PackProtocolException {
if (line == null || line.length() < 83) {
throw new PackProtocolException(
@@ -1147,7 +1208,7 @@
try {
oldId = ObjectId.fromString(oldStr);
newId = ObjectId.fromString(newStr);
- } catch (IllegalArgumentException e) {
+ } catch (InvalidObjectIdException e) {
throw new PackProtocolException(
JGitText.get().errorInvalidProtocolWantedOldNewRef, e);
}
@@ -1159,6 +1220,16 @@
return new ReceiveCommand(oldId, newId, name);
}
+ /**
+ * @param in
+ * request stream.
+ * @throws IOException
+ * request line cannot be read.
+ */
+ void readPostCommands(PacketLineIn in) throws IOException {
+ // Do nothing by default.
+ }
+
/** Enable capabilities based on a previously read capabilities line. */
protected void enableCapabilities() {
sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
@@ -1168,6 +1239,7 @@
rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out);
+ errOut = new SideBandOutputStream(CH_ERROR, MAX_BUF, out);
pckOut = new PacketLineOut(rawOut);
pckOut.setFlushOnEnd(false);
@@ -1185,6 +1257,11 @@
return enabledCapabilities.contains(name);
}
+ void checkRequestWasRead() {
+ if (enabledCapabilities == null)
+ throw new RequestNotYetReadException();
+ }
+
/** @return true if a pack is expected based on the list of commands. */
protected boolean needPack() {
for (final ReceiveCommand cmd : commands) {
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 efde062..2031147 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -208,6 +208,13 @@
*/
public static final String OPTION_AGENT = "agent"; //$NON-NLS-1$
+ /**
+ * The server supports the receiving of push options.
+ *
+ * @since 4.5
+ */
+ public static final String CAPABILITY_PUSH_OPTIONS = "push-options"; //$NON-NLS-1$
+
static enum MultiAck {
OFF, CONTINUE, DETAILED;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
index 998f280..81e6904 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
@@ -51,6 +51,7 @@
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -149,9 +150,12 @@
*
* @param conn
* the connection that failed.
+ * @param ignoreTypes
+ * authentication types to be ignored.
* @return new authentication method to try.
*/
- static HttpAuthMethod scanResponse(final HttpConnection conn) {
+ static HttpAuthMethod scanResponse(final HttpConnection conn,
+ Collection<Type> ignoreTypes) {
final Map<String, List<String>> headers = conn.getHeaderFields();
HttpAuthMethod authentication = Type.NONE.method(EMPTY_STRING);
@@ -165,6 +169,12 @@
try {
Type methodType = Type.valueOf(valuePart[0].toUpperCase());
+
+ if ((ignoreTypes != null)
+ && (ignoreTypes.contains(methodType))) {
+ continue;
+ }
+
if (authentication.getType().compareTo(methodType) >= 0) {
continue;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
index 308741e..d1cbd8d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2016, Mark Ingram <markdingram@gmail.com>
* Copyright (C) 2009, Constantine Plotnikov <constantine.plotnikov@gmail.com>
* Copyright (C) 2008-2009, Google Inc.
* Copyright (C) 2009, Google, Inc.
@@ -220,6 +221,19 @@
}
/**
+ * Provide additional configuration for the JSch instance. This method could
+ * be overridden to supply a preferred
+ * {@link com.jcraft.jsch.IdentityRepository}.
+ *
+ * @param jsch
+ * jsch instance
+ * @since 4.5
+ */
+ protected void configureJSch(JSch jsch) {
+ // No additional configuration required.
+ }
+
+ /**
* Provide additional configuration for the session based on the host
* information. This method could be used to supply {@link UserInfo}.
*
@@ -257,6 +271,7 @@
JSch jsch = byIdentityFile.get(identityKey);
if (jsch == null) {
jsch = new JSch();
+ configureJSch(jsch);
jsch.setHostKeyRepository(defaultJSch.getHostKeyRepository());
jsch.addIdentity(identityKey);
byIdentityFile.put(identityKey, jsch);
@@ -274,6 +289,7 @@
*/
protected JSch createDefaultJSch(FS fs) throws JSchException {
final JSch jsch = new JSch();
+ configureJSch(jsch);
knownHosts(jsch, fs);
identities(jsch, fs);
return jsch;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
index e1769f8..e142bab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -55,6 +55,8 @@
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Read Git style pkt-line formatting from an input stream.
@@ -67,6 +69,8 @@
* against the underlying InputStream.
*/
public class PacketLineIn {
+ private static final Logger log = LoggerFactory.getLogger(PacketLineIn.class);
+
/** Magic return from {@link #readString()} when a flush packet is found. */
public static final String END = new StringBuilder(0).toString(); /* must not string pool */
@@ -136,12 +140,16 @@
*/
public String readString() throws IOException {
int len = readLength();
- if (len == 0)
+ if (len == 0) {
+ log.debug("git< 0000"); //$NON-NLS-1$
return END;
+ }
len -= 4; // length header (4 bytes)
- if (len == 0)
+ if (len == 0) {
+ log.debug("git< "); //$NON-NLS-1$
return ""; //$NON-NLS-1$
+ }
byte[] raw;
if (len <= lineBuffer.length)
@@ -152,7 +160,10 @@
IO.readFully(in, raw, 0, len);
if (raw[len - 1] == '\n')
len--;
- return RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
+
+ String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
+ log.debug("git< " + s); //$NON-NLS-1$
+ return s;
}
/**
@@ -167,8 +178,10 @@
*/
public String readStringRaw() throws IOException {
int len = readLength();
- if (len == 0)
+ if (len == 0) {
+ log.debug("git< 0000"); //$NON-NLS-1$
return END;
+ }
len -= 4; // length header (4 bytes)
@@ -179,7 +192,20 @@
raw = new byte[len];
IO.readFully(in, raw, 0, len);
- return RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
+
+ String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
+ log.debug("git< " + s); //$NON-NLS-1$
+ return s;
+ }
+
+ void discardUntilEnd() throws IOException {
+ for (;;) {
+ int n = readLength();
+ if (n == 0) {
+ break;
+ }
+ IO.skipFully(in, n - 4);
+ }
}
int readLength() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
index bb83dce..a6bd342 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
@@ -49,6 +49,9 @@
import java.io.OutputStream;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Write Git style pkt-line formatting to an output stream.
@@ -61,6 +64,8 @@
* against the underlying OutputStream.
*/
public class PacketLineOut {
+ private static final Logger log = LoggerFactory.getLogger(PacketLineOut.class);
+
private final OutputStream out;
private final byte[] lenbuffer;
@@ -113,10 +118,32 @@
* the packet could not be written, the stream is corrupted as
* the packet may have been only partially written.
*/
- public void writePacket(final byte[] packet) throws IOException {
- formatLength(packet.length + 4);
+ public void writePacket(byte[] packet) throws IOException {
+ writePacket(packet, 0, packet.length);
+ }
+
+ /**
+ * Write a binary packet to the stream.
+ *
+ * @param buf
+ * the packet to write
+ * @param pos
+ * first index within {@code buf}.
+ * @param len
+ * number of bytes to write.
+ * @throws IOException
+ * the packet could not be written, the stream is corrupted as
+ * the packet may have been only partially written.
+ * @since 4.5
+ */
+ public void writePacket(byte[] buf, int pos, int len) throws IOException {
+ formatLength(len + 4);
out.write(lenbuffer, 0, 4);
- out.write(packet);
+ out.write(buf, pos, len);
+ if (log.isDebugEnabled()) {
+ String s = RawParseUtils.decode(Constants.CHARSET, buf, pos, len);
+ log.debug("git> " + s); //$NON-NLS-1$
+ }
}
/**
@@ -135,6 +162,7 @@
public void end() throws IOException {
formatLength(0);
out.write(lenbuffer, 0, 4);
+ log.debug("git> 0000"); //$NON-NLS-1$
if (flushOnEnd)
flush();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index 5cea882..5590c2d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -49,6 +49,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -87,6 +88,9 @@
/** an outputstream to write messages to */
private final OutputStream out;
+ /** A list of option strings associated with this push */
+ private List<String> pushOptions;
+
/**
* Create process for specified transport and refs updates specification.
*
@@ -122,6 +126,7 @@
this.transport = transport;
this.toPush = new HashMap<String, RemoteRefUpdate>();
this.out = out;
+ this.pushOptions = transport.getPushOptions();
for (final RemoteRefUpdate rru : toPush) {
if (this.toPush.put(rru.getRemoteName(), rru) != null)
throw new TransportException(MessageFormat.format(
@@ -294,4 +299,14 @@
}
}
}
+
+ /**
+ * Gets the list of option strings associated with this push.
+ *
+ * @return pushOptions
+ * @since 4.5
+ */
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
}
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 f61e93f..cc20d50 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -44,12 +44,17 @@
package org.eclipse.jgit.transport;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.UnpackException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -71,6 +76,10 @@
private boolean echoCommandFailures;
+ /** Whether the client intends to use push options. */
+ private boolean usePushOptions;
+ private List<String> pushOptions;
+
/**
* Create a new pack receive for an open repository.
*
@@ -83,6 +92,42 @@
postReceive = PostReceiveHook.NULL;
}
+ /**
+ * Gets an unmodifiable view of the option strings associated with the push.
+ *
+ * @return an unmodifiable view of pushOptions, or null (if pushOptions is).
+ * @since 4.5
+ */
+ @Nullable
+ public List<String> getPushOptions() {
+ if (isAllowPushOptions() && usePushOptions) {
+ return Collections.unmodifiableList(pushOptions);
+ }
+
+ // The client doesn't support push options. Return null to
+ // distinguish this from the case where the client declared support
+ // for push options and sent an empty list of them.
+ return null;
+ }
+
+ /**
+ * Set the push options supplied by the client.
+ * <p>
+ * Should only be called if reconstructing an instance without going through
+ * the normal {@link #recvCommands()} flow.
+ *
+ * @param options
+ * the list of options supplied by the client. The
+ * {@code ReceivePack} instance takes ownership of this list.
+ * Callers are encouraged to first create a copy if the list may
+ * be modified later.
+ * @since 4.5
+ */
+ public void setPushOptions(@Nullable List<String> options) {
+ usePushOptions = options != null;
+ pushOptions = options;
+ }
+
/** @return the hook invoked before updates occur. */
public PreReceiveHook getPreReceiveHook() {
return preReceive;
@@ -171,9 +216,24 @@
@Override
protected void enableCapabilities() {
reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS);
+ usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS);
super.enableCapabilities();
}
+ @Override
+ void readPostCommands(PacketLineIn in) throws IOException {
+ if (usePushOptions) {
+ pushOptions = new ArrayList<>(4);
+ for (;;) {
+ String option = in.readString();
+ if (option == PacketLineIn.END) {
+ break;
+ }
+ pushOptions.add(option);
+ }
+ }
+ }
+
private void service() throws IOException {
if (isBiDirectionalPipe()) {
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
@@ -184,17 +244,11 @@
return;
recvCommands();
if (hasCommands()) {
- enableCapabilities();
-
Throwable unpackError = null;
if (needPack()) {
try {
receivePackAndCheckConnectivity();
- } catch (IOException err) {
- unpackError = err;
- } catch (RuntimeException err) {
- unpackError = err;
- } catch (Error err) {
+ } catch (IOException | RuntimeException | Error err) {
unpackError = err;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
index f72a4b2..0cd720c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
@@ -43,9 +43,16 @@
package org.eclipse.jgit.transport;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SYMREF;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -64,8 +71,15 @@
public abstract class RefAdvertiser {
/** Advertiser which frames lines in a {@link PacketLineOut} format. */
public static class PacketLineOutRefAdvertiser extends RefAdvertiser {
+ private final CharsetEncoder utf8 = UTF_8.newEncoder();
private final PacketLineOut pckOut;
+ private byte[] binArr = new byte[256];
+ private ByteBuffer binBuf = ByteBuffer.wrap(binArr);
+
+ private char[] chArr = new char[256];
+ private CharBuffer chBuf = CharBuffer.wrap(chArr);
+
/**
* Create a new advertiser for the supplied stream.
*
@@ -77,6 +91,64 @@
}
@Override
+ public void advertiseId(AnyObjectId id, String refName)
+ throws IOException {
+ id.copyTo(binArr, 0);
+ binArr[OBJECT_ID_STRING_LENGTH] = ' ';
+ binBuf.position(OBJECT_ID_STRING_LENGTH + 1);
+ append(refName);
+ if (first) {
+ first = false;
+ if (!capablities.isEmpty()) {
+ append('\0');
+ for (String cap : capablities) {
+ append(' ');
+ append(cap);
+ }
+ }
+ }
+ append('\n');
+ pckOut.writePacket(binArr, 0, binBuf.position());
+ }
+
+ private void append(String str) throws CharacterCodingException {
+ int n = str.length();
+ if (n > chArr.length) {
+ chArr = new char[n + 256];
+ chBuf = CharBuffer.wrap(chArr);
+ }
+ str.getChars(0, n, chArr, 0);
+ chBuf.position(0).limit(n);
+ utf8.reset();
+ for (;;) {
+ CoderResult cr = utf8.encode(chBuf, binBuf, true);
+ if (cr.isOverflow()) {
+ grow();
+ } else if (cr.isUnderflow()) {
+ break;
+ } else {
+ cr.throwException();
+ }
+ }
+ }
+
+ private void append(int b) {
+ if (!binBuf.hasRemaining()) {
+ grow();
+ }
+ binBuf.put((byte) b);
+ }
+
+ private void grow() {
+ int cnt = binBuf.position();
+ byte[] tmp = new byte[binArr.length << 1];
+ System.arraycopy(binArr, 0, tmp, 0, cnt);
+ binArr = tmp;
+ binBuf = ByteBuffer.wrap(binArr);
+ binBuf.position(cnt);
+ }
+
+ @Override
protected void writeOne(final CharSequence line) throws IOException {
pckOut.writeString(line.toString());
}
@@ -91,7 +163,7 @@
private final char[] tmpId = new char[Constants.OBJECT_ID_STRING_LENGTH];
- private final Set<String> capablities = new LinkedHashSet<String>();
+ final Set<String> capablities = new LinkedHashSet<String>();
private final Set<ObjectId> sent = new HashSet<ObjectId>();
@@ -99,7 +171,7 @@
private boolean derefTags;
- private boolean first = true;
+ boolean first = true;
/**
* Initialize this advertiser with a repository for peeling tags.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
index 0e803bd..1440b83 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
@@ -82,6 +82,30 @@
/** Is this specification actually a wildcard match? */
private boolean wildcard;
+ /**
+ * How strict to be about wildcards.
+ *
+ * @since 4.5
+ */
+ public enum WildcardMode {
+ /**
+ * Reject refspecs with an asterisk on the source side and not the
+ * destination side or vice versa. This is the mode used by FetchCommand
+ * and PushCommand to create a one-to-one mapping between source and
+ * destination refs.
+ */
+ REQUIRE_MATCH,
+ /**
+ * Allow refspecs with an asterisk on only one side. This can create a
+ * many-to-one mapping between source and destination refs, so
+ * expandFromSource and expandFromDestination are not usable in this
+ * mode.
+ */
+ ALLOW_MISMATCH
+ }
+ /** Whether a wildcard is allowed on one side but not the other. */
+ private WildcardMode allowMismatchedWildcards;
+
/** Name of the ref(s) we would copy from. */
private String srcName;
@@ -99,6 +123,83 @@
wildcard = false;
srcName = Constants.HEAD;
dstName = null;
+ allowMismatchedWildcards = WildcardMode.REQUIRE_MATCH;
+ }
+
+ /**
+ * Parse a ref specification for use during transport operations.
+ * <p>
+ * Specifications are typically one of the following forms:
+ * <ul>
+ * <li><code>refs/heads/master</code></li>
+ * <li><code>refs/heads/master:refs/remotes/origin/master</code></li>
+ * <li><code>refs/heads/*:refs/remotes/origin/*</code></li>
+ * <li><code>+refs/heads/master</code></li>
+ * <li><code>+refs/heads/master:refs/remotes/origin/master</code></li>
+ * <li><code>+refs/heads/*:refs/remotes/origin/*</code></li>
+ * <li><code>+refs/pull/*/head:refs/remotes/origin/pr/*</code></li>
+ * <li><code>:refs/heads/master</code></li>
+ * </ul>
+ *
+ * If the wildcard mode allows mismatches, then these ref specs are also
+ * valid:
+ * <ul>
+ * <li><code>refs/heads/*</code></li>
+ * <li><code>refs/heads/*:refs/heads/master</code></li>
+ * </ul>
+ *
+ * @param spec
+ * string describing the specification.
+ * @param mode
+ * whether to allow a wildcard on one side without a wildcard on
+ * the other.
+ * @throws IllegalArgumentException
+ * the specification is invalid.
+ * @since 4.5
+ */
+ public RefSpec(String spec, WildcardMode mode) {
+ this.allowMismatchedWildcards = mode;
+ String s = spec;
+ if (s.startsWith("+")) { //$NON-NLS-1$
+ force = true;
+ s = s.substring(1);
+ }
+
+ final int c = s.lastIndexOf(':');
+ if (c == 0) {
+ s = s.substring(1);
+ if (isWildcard(s)) {
+ wildcard = true;
+ if (mode == WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidWildcards, spec));
+ }
+ }
+ dstName = checkValid(s);
+ } else if (c > 0) {
+ String src = s.substring(0, c);
+ String dst = s.substring(c + 1);
+ if (isWildcard(src) && isWildcard(dst)) {
+ // Both contain wildcard
+ wildcard = true;
+ } else if (isWildcard(src) || isWildcard(dst)) {
+ wildcard = true;
+ if (mode == WildcardMode.REQUIRE_MATCH)
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidWildcards, spec));
+ }
+ srcName = checkValid(src);
+ dstName = checkValid(dst);
+ } else {
+ if (isWildcard(s)) {
+ if (mode == WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidWildcards, spec));
+ }
+ wildcard = true;
+ }
+ srcName = checkValid(s);
+ }
}
/**
@@ -122,36 +223,7 @@
* the specification is invalid.
*/
public RefSpec(final String spec) {
- String s = spec;
- if (s.startsWith("+")) { //$NON-NLS-1$
- force = true;
- s = s.substring(1);
- }
-
- final int c = s.lastIndexOf(':');
- if (c == 0) {
- s = s.substring(1);
- if (isWildcard(s))
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
- dstName = checkValid(s);
- } else if (c > 0) {
- String src = s.substring(0, c);
- String dst = s.substring(c + 1);
- if (isWildcard(src) && isWildcard(dst)) {
- // Both contain wildcard
- wildcard = true;
- } else if (isWildcard(src) || isWildcard(dst)) {
- // If either source or destination has wildcard, the other one
- // must have as well.
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
- }
- srcName = checkValid(src);
- dstName = checkValid(dst);
- } else {
- if (isWildcard(s))
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
- srcName = checkValid(s);
- }
+ this(spec, WildcardMode.REQUIRE_MATCH);
}
private RefSpec(final RefSpec p) {
@@ -159,6 +231,7 @@
wildcard = p.isWildcard();
srcName = p.getSource();
dstName = p.getDestination();
+ allowMismatchedWildcards = p.allowMismatchedWildcards;
}
/**
@@ -348,8 +421,15 @@
* @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is
* wildcard.
+ * @throws IllegalStateException
+ * when the RefSpec was constructed with wildcard mode that
+ * doesn't require matching wildcards.
*/
public RefSpec expandFromSource(final String r) {
+ if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalStateException(
+ JGitText.get().invalidExpandWildcard);
+ }
return isWildcard() ? new RefSpec(this).expandFromSourceImp(r) : this;
}
@@ -373,6 +453,9 @@
* @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is
* wildcard.
+ * @throws IllegalStateException
+ * when the RefSpec was constructed with wildcard mode that
+ * doesn't require matching wildcards.
*/
public RefSpec expandFromSource(final Ref r) {
return expandFromSource(r.getName());
@@ -390,8 +473,15 @@
* @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is
* wildcard.
+ * @throws IllegalStateException
+ * when the RefSpec was constructed with wildcard mode that
+ * doesn't require matching wildcards.
*/
public RefSpec expandFromDestination(final String r) {
+ if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalStateException(
+ JGitText.get().invalidExpandWildcard);
+ }
return isWildcard() ? new RefSpec(this).expandFromDstImp(r) : this;
}
@@ -414,6 +504,9 @@
* @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is
* wildcard.
+ * @throws IllegalStateException
+ * when the RefSpec was constructed with wildcard mode that
+ * doesn't require matching wildcards.
*/
public RefSpec expandFromDestination(final Ref r) {
return expandFromDestination(r.getName());
@@ -422,7 +515,7 @@
private boolean match(final String name, final String s) {
if (s == null)
return false;
- if (isWildcard()) {
+ if (isWildcard(s)) {
int wildcardIndex = s.indexOf('*');
String prefix = s.substring(0, wildcardIndex);
String suffix = s.substring(wildcardIndex + 1);
@@ -453,6 +546,8 @@
return false;
if (s.contains("//")) //$NON-NLS-1$
return false;
+ if (s.endsWith("/")) //$NON-NLS-1$
+ return false;
int i = s.indexOf('*');
if (i != -1) {
if (s.indexOf('*', i + 1) > i)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
index e000cfb..ce5ccaa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.transport;
import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.internal.JGitText;
@@ -55,11 +56,13 @@
public class ServiceMayNotContinueException extends IOException {
private static final long serialVersionUID = 1L;
+ private final int statusCode;
private boolean output;
/** Initialize with no message. */
public ServiceMayNotContinueException() {
// Do not set a message.
+ statusCode = HttpServletResponse.SC_FORBIDDEN;
}
/**
@@ -69,6 +72,20 @@
*/
public ServiceMayNotContinueException(String msg) {
super(msg);
+ statusCode = HttpServletResponse.SC_FORBIDDEN;
+ }
+
+ /**
+ * @param msg
+ * a message explaining why it cannot continue. This message may
+ * be shown to an end-user.
+ * @param statusCode
+ * the HTTP status code.
+ * @since 4.5
+ */
+ public ServiceMayNotContinueException(String msg, int statusCode) {
+ super(msg);
+ this.statusCode = statusCode;
}
/**
@@ -80,8 +97,24 @@
* @since 3.2
*/
public ServiceMayNotContinueException(String msg, Throwable cause) {
- super(msg);
- initCause(cause);
+ super(msg, cause);
+ statusCode = HttpServletResponse.SC_FORBIDDEN;
+ }
+
+ /**
+ * @param msg
+ * a message explaining why it cannot continue. This message may
+ * be shown to an end-user.
+ * @param cause
+ * the cause of the exception.
+ * @param statusCode
+ * the HTTP status code.
+ * @since 4.5
+ */
+ public ServiceMayNotContinueException(
+ String msg, Throwable cause, int statusCode) {
+ super(msg, cause);
+ this.statusCode = statusCode;
}
/**
@@ -104,4 +137,12 @@
public void setOutput() {
output = true;
}
+
+ /**
+ * @return true if the message was already output to the client.
+ * @since 4.5
+ */
+ public int getStatusCode() {
+ return statusCode;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 862b3bd..bc4843a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -773,6 +773,9 @@
/** Assists with authentication the connection. */
private CredentialsProvider credentialsProvider;
+ /** The option strings associated with the push operation. */
+ private List<String> pushOptions;
+
private PrintStream hookOutRedirect;
private PrePushHook prePush;
@@ -1121,6 +1124,25 @@
}
/**
+ * @return the option strings associated with the push operation
+ * @since 4.5
+ */
+ public List<String> getPushOptions() {
+ return pushOptions;
+ }
+
+ /**
+ * Sets the option strings associated with the push operation.
+ *
+ * @param pushOptions
+ * null if push options are unsupported
+ * @since 4.5
+ */
+ public void setPushOptions(final List<String> pushOptions) {
+ this.pushOptions = pushOptions;
+ }
+
+ /**
* Fetch objects and refs from the remote repository to the local one.
* <p>
* This is a utility function providing standard fetch behavior. Local
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 414e879..1166080 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -73,6 +73,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -95,6 +96,7 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.transport.HttpAuthMethod.Type;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.util.HttpSupport;
import org.eclipse.jgit.util.IO;
@@ -448,9 +450,11 @@
throw new NotSupportedException(MessageFormat.format(JGitText.get().invalidURL, uri), e);
}
- try {
- int authAttempts = 1;
- for (;;) {
+
+ int authAttempts = 1;
+ Collection<Type> ignoreTypes = null;
+ for (;;) {
+ try {
final HttpConnection conn = httpOpen(u);
if (useSmartHttp) {
String exp = "application/x-" + service + "-advertisement"; //$NON-NLS-1$ //$NON-NLS-2$
@@ -467,7 +471,7 @@
// explicit authentication would be required
if (authMethod.getType() == HttpAuthMethod.Type.NONE
&& conn.getHeaderField(HDR_WWW_AUTHENTICATE) != null)
- authMethod = HttpAuthMethod.scanResponse(conn);
+ authMethod = HttpAuthMethod.scanResponse(conn, ignoreTypes);
return conn;
case HttpConnection.HTTP_NOT_FOUND:
@@ -475,7 +479,7 @@
MessageFormat.format(JGitText.get().uriNotFound, u));
case HttpConnection.HTTP_UNAUTHORIZED:
- authMethod = HttpAuthMethod.scanResponse(conn);
+ authMethod = HttpAuthMethod.scanResponse(conn, ignoreTypes);
if (authMethod.getType() == HttpAuthMethod.Type.NONE)
throw new TransportException(uri, MessageFormat.format(
JGitText.get().authenticationNotSupported, uri));
@@ -501,13 +505,27 @@
String err = status + " " + conn.getResponseMessage(); //$NON-NLS-1$
throw new TransportException(uri, err);
}
+ } catch (NotSupportedException e) {
+ throw e;
+ } catch (TransportException e) {
+ throw e;
+ } catch (IOException e) {
+ if (authMethod.getType() != HttpAuthMethod.Type.NONE) {
+ if (ignoreTypes == null) {
+ ignoreTypes = new HashSet<Type>();
+ }
+
+ ignoreTypes.add(authMethod.getType());
+
+ // reset auth method & attempts for next authentication type
+ authMethod = HttpAuthMethod.Type.NONE.method(null);
+ authAttempts = 1;
+
+ continue;
+ }
+
+ throw new TransportException(uri, MessageFormat.format(JGitText.get().cannotOpenService, service), e);
}
- } catch (NotSupportedException e) {
- throw e;
- } catch (TransportException e) {
- throw e;
- } catch (IOException e) {
- throw new TransportException(uri, MessageFormat.format(JGitText.get().cannotOpenService, service), e);
}
}
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 e49ee87..d1fd67e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -682,7 +682,7 @@
* 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
+ * was sent, such as during the negotiation phase of a smart HTTP
* connection, or if the client was already up-to-date.
* @since 3.0
* @deprecated Use {@link #getStatistics()}.
@@ -697,7 +697,7 @@
* 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
+ * was sent, such as during the negotiation phase of a smart HTTP
* connection, or if the client was already up-to-date.
* @since 4.1
*/
@@ -777,15 +777,22 @@
private static Set<ObjectId> refIdSet(Collection<Ref> refs) {
Set<ObjectId> ids = new HashSet<ObjectId>(refs.size());
for (Ref ref : refs) {
- if (ref.getObjectId() != null)
- ids.add(ref.getObjectId());
+ ObjectId id = ref.getObjectId();
+ if (id != null) {
+ ids.add(id);
+ }
+ id = ref.getPeeledObjectId();
+ if (id != null) {
+ ids.add(id);
+ }
}
return ids;
}
private void processShallow() throws IOException {
+ int walkDepth = depth - 1;
try (DepthWalk.RevWalk depthWalk = new DepthWalk.RevWalk(
- walk.getObjectReader(), depth)) {
+ walk.getObjectReader(), walkDepth)) {
// Find all the commits which will be shallow
for (ObjectId o : wantIds) {
@@ -802,12 +809,14 @@
// Commits at the boundary which aren't already shallow in
// the client need to be marked as such
- if (c.getDepth() == depth && !clientShallowCommits.contains(c))
+ if (c.getDepth() == walkDepth
+ && !clientShallowCommits.contains(c))
pckOut.writeString("shallow " + o.name()); //$NON-NLS-1$
// Commits not on the boundary which are shallow in the client
// need to become unshallowed
- if (c.getDepth() < depth && clientShallowCommits.remove(c)) {
+ if (c.getDepth() < walkDepth
+ && clientShallowCommits.remove(c)) {
unshallowCommits.add(c.copy());
pckOut.writeString("unshallow " + c.name()); //$NON-NLS-1$
}
@@ -942,6 +951,11 @@
if (line.startsWith("deepen ")) { //$NON-NLS-1$
depth = Integer.parseInt(line.substring(7));
+ if (depth <= 0) {
+ throw new PackProtocolException(
+ MessageFormat.format(JGitText.get().invalidDepth,
+ Integer.valueOf(depth)));
+ }
continue;
}
@@ -968,7 +982,8 @@
}
/**
- * Returns the clone/fetch depth. Valid only after calling recvWants().
+ * Returns the clone/fetch depth. Valid only after calling recvWants(). A
+ * depth of 1 means return only the wants.
*
* @return the depth requested by the client, or 0 if unbounded.
* @since 4.0
@@ -1142,7 +1157,6 @@
if (multiAck == MultiAck.DETAILED && !didOkToGiveUp && okToGiveUp()) {
ObjectId id = peerHas.get(peerHas.size() - 1);
- sentReady = true;
pckOut.writeString("ACK " + id.name() + " ready\n"); //$NON-NLS-1$ //$NON-NLS-2$
sentReady = true;
}
@@ -1479,16 +1493,19 @@
pw.setTagTargets(tagTargets);
}
- if (depth > 0)
- pw.setShallowPack(depth, unshallowCommits);
-
RevWalk rw = walk;
+ if (depth > 0) {
+ pw.setShallowPack(depth, unshallowCommits);
+ rw = new DepthWalk.RevWalk(walk.getObjectReader(), depth - 1);
+ rw.assumeShallow(clientShallowCommits);
+ }
+
if (wantAll.isEmpty()) {
- pw.preparePack(pm, wantIds, commonBase);
+ pw.preparePack(pm, wantIds, commonBase, clientShallowCommits);
} else {
walk.reset();
- ObjectWalk ow = walk.toObjectWalkWithSameObjects();
+ ObjectWalk ow = rw.toObjectWalkWithSameObjects();
pw.preparePack(pm, ow, wantAll, commonBase);
rw = ow;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 7dac50a..911b7ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -795,7 +795,6 @@
public boolean next() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
try {
- attrs = null;
if (advance) {
advance = false;
postChildren = false;
@@ -803,6 +802,7 @@
}
for (;;) {
+ attrs = null;
final AbstractTreeIterator t = min();
if (t.eof()) {
if (depth > 0) {
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 c8de3de..9a3fa80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -268,7 +268,9 @@
DirCacheIterator.class);
if (i != null) {
DirCacheEntry ent = i.getDirCacheEntry();
- if (ent != null && compareMetadata(ent) == MetadataDiff.EQUAL) {
+ if (ent != null && compareMetadata(ent) == MetadataDiff.EQUAL
+ && ((ent.getFileMode().getBits()
+ & FileMode.TYPE_MASK) != FileMode.TYPE_GITLINK)) {
contentIdOffset = i.idOffset();
contentIdFromPtr = ptr;
return contentId = i.idBuffer();
@@ -843,10 +845,15 @@
if (entry.isUpdateNeeded())
return MetadataDiff.DIFFER_BY_METADATA;
- if (!entry.isSmudged() && entry.getLength() != (int) getEntryLength())
+ if (isModeDifferent(entry.getRawMode()))
return MetadataDiff.DIFFER_BY_METADATA;
- if (isModeDifferent(entry.getRawMode()))
+ // Don't check for length or lastmodified on folders
+ int type = mode & FileMode.TYPE_MASK;
+ if (type == FileMode.TYPE_TREE || type == FileMode.TYPE_GITLINK)
+ return MetadataDiff.EQUAL;
+
+ if (!entry.isSmudged() && entry.getLength() != (int) getEntryLength())
return MetadataDiff.DIFFER_BY_METADATA;
// Git under windows only stores seconds so we round the timestamp
@@ -915,6 +922,9 @@
// Lets do a content check
return contentCheck(entry, reader);
case EQUAL:
+ if (mode == FileMode.SYMLINK.getBits()) {
+ return contentCheck(entry, reader);
+ }
return false;
case DIFFER_BY_METADATA:
if (mode == FileMode.SYMLINK.getBits())
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 253acbb..e1fd1cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -64,9 +64,11 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.CommandFailedException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -235,6 +237,21 @@
public abstract boolean supportsExecute();
/**
+ * Does this file system support atomic file creation via
+ * java.io.File#createNewFile()? In certain environments (e.g. on NFS) it is
+ * not guaranteed that when two file system clients run createNewFile() in
+ * parallel only one will succeed. In such cases both clients may think they
+ * created a new file.
+ *
+ * @return true if this implementation support atomic creation of new
+ * Files by {@link File#createNewFile()}
+ * @since 4.5
+ */
+ public boolean supportsAtomicCreateNewFile() {
+ return true;
+ }
+
+ /**
* Does this operating system and JRE supports symbolic links. The
* capability to handle symbolic links is detected at runtime.
*
@@ -453,9 +470,12 @@
* to be used to parse the command's output
* @return the one-line output of the command or {@code null} if there is
* none
+ * @throws CommandFailedException
+ * thrown when the command failed (return code was non-zero)
*/
@Nullable
- protected static String readPipe(File dir, String[] command, String encoding) {
+ protected static String readPipe(File dir, String[] command,
+ String encoding) throws CommandFailedException {
return readPipe(dir, command, encoding, null);
}
@@ -473,10 +493,14 @@
* current process
* @return the one-line output of the command or {@code null} if there is
* none
+ * @throws CommandFailedException
+ * thrown when the command failed (return code was non-zero)
* @since 4.0
*/
@Nullable
- protected static String readPipe(File dir, String[] command, String encoding, Map<String, String> env) {
+ protected static String readPipe(File dir, String[] command,
+ String encoding, Map<String, String> env)
+ throws CommandFailedException {
final boolean debug = LOG.isDebugEnabled();
try {
if (debug) {
@@ -512,11 +536,14 @@
gobbler.join();
if (rc == 0 && !gobbler.fail.get()) {
return r;
+ } else {
+ if (debug) {
+ LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$
+ }
+ throw new CommandFailedException(rc,
+ gobbler.errorMessage.get(),
+ gobbler.exception.get());
}
- if (debug) {
- LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$
- }
- break;
} catch (InterruptedException ie) {
// Stop bothering me, I have a zombie to reap.
}
@@ -535,6 +562,8 @@
private final String desc;
private final String dir;
final AtomicBoolean fail = new AtomicBoolean();
+ final AtomicReference<String> errorMessage = new AtomicReference<>();
+ final AtomicReference<Throwable> exception = new AtomicReference<>();
GobblerThread(Process p, String[] command, File dir) {
this.p = p;
@@ -542,6 +571,7 @@
this.dir = Objects.toString(dir);
}
+ @Override
public void run() {
StringBuilder err = new StringBuilder();
try (InputStream is = p.getErrorStream()) {
@@ -551,22 +581,26 @@
}
} catch (IOException e) {
if (p.exitValue() != 0) {
- logError(e);
+ setError(e, e.getMessage());
fail.set(true);
} else {
- // ignore. git terminated faster and stream was just closed
+ // ignore. command terminated faster and stream was just closed
}
} finally {
if (err.length() > 0) {
- LOG.error(err.toString());
+ setError(null, err.toString());
+ if (p.exitValue() != 0) {
+ fail.set(true);
+ }
}
}
}
- private void logError(Throwable t) {
- String msg = MessageFormat.format(
- JGitText.get().exceptionCaughtDuringExcecutionOfCommand, desc, dir);
- LOG.error(msg, t);
+ private void setError(IOException e, String message) {
+ exception.set(e);
+ errorMessage.set(MessageFormat.format(
+ JGitText.get().exceptionCaughtDuringExcecutionOfCommand,
+ desc, dir, Integer.valueOf(p.exitValue()), message));
}
}
@@ -589,10 +623,17 @@
}
// Bug 480782: Check if the discovered git executable is JGit CLI
- String v = readPipe(gitExe.getParentFile(),
+ String v;
+ try {
+ v = readPipe(gitExe.getParentFile(),
new String[] { "git", "--version" }, //$NON-NLS-1$ //$NON-NLS-2$
Charset.defaultCharset().name());
- if (v != null && v.startsWith("jgit")) { //$NON-NLS-1$
+ } catch (CommandFailedException e) {
+ LOG.warn(e.getMessage());
+ return null;
+ }
+ if (StringUtils.isEmptyOrNull(v)
+ || (v != null && v.startsWith("jgit"))) { //$NON-NLS-1$
return null;
}
@@ -601,9 +642,15 @@
Map<String, String> env = new HashMap<>();
env.put("GIT_EDITOR", "echo"); //$NON-NLS-1$ //$NON-NLS-2$
- String w = readPipe(gitExe.getParentFile(),
+ String w;
+ try {
+ w = readPipe(gitExe.getParentFile(),
new String[] { "git", "config", "--system", "--edit" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name(), env);
+ } catch (CommandFailedException e) {
+ LOG.warn(e.getMessage());
+ return null;
+ }
if (StringUtils.isEmptyOrNull(w)) {
return null;
}
@@ -745,6 +792,22 @@
}
/**
+ * Create a new file. See {@link File#createNewFile()}. Subclasses of this
+ * class may take care to provide a safe implementation for this even if
+ * {@link #supportsAtomicCreateNewFile()} is <code>false</code>
+ *
+ * @param path
+ * the file to be created
+ * @return <code>true</code> if the file was created, <code>false</code> if
+ * the file already existed
+ * @throws IOException
+ * @since 4.5
+ */
+ public boolean createNewFile(File path) throws IOException {
+ return path.createNewFile();
+ }
+
+ /**
* See {@link FileUtils#relativize(String, String)}.
*
* @param base
@@ -990,7 +1053,16 @@
new StreamGobbler(inRedirect, outputStream)
.call();
}
- outputStream.close();
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ // When the process exits before consuming the input, the OutputStream
+ // is replaced with the null output stream. This null output stream
+ // throws IOException for all write calls. When StreamGobbler fails to
+ // flush the buffer because of this, this close call tries to flush it
+ // again. This causes another IOException. Since we ignore the
+ // IOException in StreamGobbler, we also ignore the exception here.
+ }
return process.waitFor();
} catch (IOException e) {
ioException = e;
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 b4f12f4..4ecaf9c 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
@@ -50,6 +50,7 @@
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Arrays;
@@ -57,8 +58,14 @@
import java.util.Set;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.CommandFailedException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Base FS for POSIX based systems
@@ -66,9 +73,15 @@
* @since 3.0
*/
public class FS_POSIX extends FS {
+ private final static Logger LOG = LoggerFactory.getLogger(FS_POSIX.class);
+
private static final int DEFAULT_UMASK = 0022;
private volatile int umask = -1;
+ private volatile boolean supportsUnixNLink = true;
+
+ private volatile Boolean supportsAtomicCreateNewFile;
+
/** Default constructor. */
protected FS_POSIX() {
}
@@ -86,6 +99,33 @@
}
}
+ private void determineAtomicFileCreationSupport() {
+ // @TODO: enhance SystemReader to support this without copying code
+ Boolean ret = getAtomicFileCreationSupportOption(
+ SystemReader.getInstance().openUserConfig(null, this));
+ if (ret == null && StringUtils.isEmptyOrNull(SystemReader.getInstance()
+ .getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) {
+ ret = getAtomicFileCreationSupportOption(
+ SystemReader.getInstance().openSystemConfig(null, this));
+ }
+ supportsAtomicCreateNewFile = (ret == null) || ret;
+ }
+
+ private Boolean getAtomicFileCreationSupportOption(FileBasedConfig config) {
+ try {
+ config.load();
+ String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION,
+ null,
+ ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION);
+ if (value == null) {
+ return null;
+ }
+ return Boolean.valueOf(StringUtils.toBoolean(value));
+ } catch (IOException | ConfigInvalidException e) {
+ return Boolean.TRUE;
+ }
+ }
+
@Override
public FS newInstance() {
return new FS_POSIX(this);
@@ -144,11 +184,18 @@
// On MacOSX, PATH is shorter when Eclipse is launched from the
// Finder than from a terminal. Therefore try to launch bash as a
// login shell and search using that.
- String w = readPipe(userHome(),
+ String w;
+ try {
+ w = readPipe(userHome(),
new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name());
- if (!StringUtils.isEmptyOrNull(w))
+ } catch (CommandFailedException e) {
+ LOG.warn(e.getMessage());
+ return null;
+ }
+ if (!StringUtils.isEmptyOrNull(w)) {
gitExe = new File(w);
+ }
}
}
}
@@ -289,4 +336,55 @@
return hookPath.toFile();
return null;
}
+
+ @Override
+ public boolean supportsAtomicCreateNewFile() {
+ if (supportsAtomicCreateNewFile == null) {
+ determineAtomicFileCreationSupport();
+ }
+ return supportsAtomicCreateNewFile.booleanValue();
+ }
+
+ @SuppressWarnings("boxing")
+ /**
+ * An implementation of the File#createNewFile() semantics which works also
+ * on NFS. If the config option
+ * {@code core.supportsAtomicCreateNewFile = true} (which is the default)
+ * then simply File#createNewFile() is called.
+ *
+ * But if {@code core.supportsAtomicCreateNewFile = false} then after
+ * successful creation of the lock file a hardlink to that lock file is
+ * created and the attribute nlink of the lock file is checked to be 2. If
+ * multiple clients manage to create the same lock file nlink would be
+ * greater than 2 showing the error.
+ *
+ * @see https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html
+ * @since 4.5
+ */
+ public boolean createNewFile(File lock) throws IOException {
+ if (!lock.createNewFile()) {
+ return false;
+ }
+ if (supportsAtomicCreateNewFile() || !supportsUnixNLink) {
+ return true;
+ }
+ Path lockPath = lock.toPath();
+ Path link = Files.createLink(Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$
+ lockPath);
+ try {
+ Integer nlink = (Integer) (Files.getAttribute(lockPath,
+ "unix:nlink")); //$NON-NLS-1$
+ if (nlink != 2) {
+ LOG.warn("nlink of link to lock file {0} was not 2 but {1}", //$NON-NLS-1$
+ lock.getPath(), nlink);
+ return false;
+ }
+ return true;
+ } catch (UnsupportedOperationException | IllegalArgumentException e) {
+ supportsUnixNLink = false;
+ return true;
+ } finally {
+ Files.delete(link);
+ }
+ }
}
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 defe14f..0e9172e 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
@@ -51,6 +51,10 @@
import java.util.Arrays;
import java.util.List;
+import org.eclipse.jgit.errors.CommandFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* FS implementation for Windows
@@ -58,6 +62,7 @@
* @since 3.0
*/
public class FS_Win32 extends FS {
+ private final static Logger LOG = LoggerFactory.getLogger(FS_Win32.class);
private volatile Boolean supportSymlinks;
@@ -113,12 +118,19 @@
if (searchPath(path, "bash.exe") != null) { //$NON-NLS-1$
// This isn't likely to work, but its worth trying:
// If bash is in $PATH, git should also be in $PATH.
- String w = readPipe(userHome(),
+ String w;
+ try {
+ w = readPipe(userHome(),
new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name());
- if (!StringUtils.isEmptyOrNull(w))
+ } catch (CommandFailedException e) {
+ LOG.warn(e.getMessage());
+ return null;
+ }
+ if (!StringUtils.isEmptyOrNull(w)) {
// The path may be in cygwin/msys notation so resolve it right away
gitExe = resolve(null, w);
+ }
}
}
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 ec581b3..f8ea5d0 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
@@ -54,8 +54,11 @@
import java.util.List;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.CommandFailedException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* FS implementation for Cygwin on Windows
@@ -63,6 +66,9 @@
* @since 3.0
*/
public class FS_Win32_Cygwin extends FS_Win32 {
+ private final static Logger LOG = LoggerFactory
+ .getLogger(FS_Win32_Cygwin.class);
+
private static String cygpath;
/**
@@ -107,11 +113,18 @@
public File resolve(final File dir, final String pn) {
String useCygPath = System.getProperty("jgit.usecygpath"); //$NON-NLS-1$
if (useCygPath != null && useCygPath.equals("true")) { //$NON-NLS-1$
- String w = readPipe(dir, //
+ String w;
+ try {
+ w = readPipe(dir, //
new String[] { cygpath, "--windows", "--absolute", pn }, // //$NON-NLS-1$ //$NON-NLS-2$
"UTF-8"); //$NON-NLS-1$
- if (w != null)
+ } catch (CommandFailedException e) {
+ LOG.warn(e.getMessage());
+ return null;
+ }
+ if (!StringUtils.isEmptyOrNull(w)) {
return new File(w);
+ }
}
return super.resolve(dir, pn);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index 7cb2bf6..202645b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -190,7 +190,7 @@
return c.getResponseCode();
} catch (ConnectException ce) {
final URL url = c.getURL();
- final String host = (url == null) ? "<null>" : url.getHost();
+ final String host = (url == null) ? "<null>" : url.getHost(); //$NON-NLS-1$
// The standard J2SE error message is not very useful.
//
if ("Connection timed out: connect".equals(ce.getMessage())) //$NON-NLS-1$
@@ -218,7 +218,7 @@
return c.getResponseCode();
} catch (ConnectException ce) {
final URL url = c.getURL();
- final String host = (url == null) ? "<null>" : url.getHost();
+ final String host = (url == null) ? "<null>" : url.getHost(); //$NON-NLS-1$
// The standard J2SE error message is not very useful.
//
if ("Connection timed out: connect".equals(ce.getMessage())) //$NON-NLS-1$
diff --git a/pom.xml b/pom.xml
index d38d156..0afffc1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
<packaging>pom</packaging>
- <version>4.4.2-SNAPSHOT</version>
+ <version>4.5.5-SNAPSHOT</version>
<name>JGit - Parent</name>
<url>${jgit-url}</url>
@@ -210,6 +210,7 @@
<maven-javadoc-plugin-version>2.10.3</maven-javadoc-plugin-version>
<tycho-extras-version>0.25.0</tycho-extras-version>
<gson-version>2.2.4</gson-version>
+ <spotbugs-maven-plugin-version>3.1.6</spotbugs-maven-plugin-version>
<!-- Properties to enable jacoco code coverage analysis -->
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@@ -323,9 +324,9 @@
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
- <version>3.0.3</version>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>${spotbugs-maven-plugin-version}</version>
<configuration>
<findbugsXmlOutput>true</findbugsXmlOutput>
<failOnError>false</failOnError>
@@ -528,9 +529,9 @@
<version>2.5</version>
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
- <version>3.0.3</version>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>${spotbugs-maven-plugin-version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -689,14 +690,25 @@
</plugin>
</plugins>
</build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <additionalparam>-Xdoclint:-missing</additionalparam>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
</profile>
<profile>
<id>static-checks</id>
<build>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>