Merge changes I424295df,Ib003f7c8
* changes:
Treat RawText of binary data as file with one single line.
Trim boilerplate in RawParseUtils_LineMapTest.
diff --git a/WORKSPACE b/WORKSPACE
index efa161b..8251578 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -105,46 +105,46 @@
sha1 = "a60a5e993c98c864010053cb901b7eab25306568",
)
-JETTY_VER = "9.3.17.v20170317"
+JETTY_VER = "9.4.5.v20170502"
maven_jar(
name = "jetty_servlet",
artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
- sha1 = "ed6986b0d0ca7b9b0f9015c9efb80442e3043a8e",
- src_sha1 = "ee6b4784a00a92e5c1b6111033b7ae41ac6052a3",
+ sha1 = "394a535b76ca7399b25be3266f06f614e020517e",
+ src_sha1 = "4e85803c8d539aa0a8389e113095ef86032ac425",
)
maven_jar(
name = "jetty_security",
artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
- sha1 = "ca52535569445682d42aaa97c7039442719a0507",
- src_sha1 = "2ff9f4fb18b320fd5a0272a427bacc4d5fe7bc86",
+ sha1 = "4f4fc4cbe3504b6c91143ee37b38a1f3de2dcc72",
+ src_sha1 = "2124a757c87eacea7ad6507be6a415b5b51139b5",
)
maven_jar(
name = "jetty_server",
artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
- sha1 = "194e9a02e6ba249ef4a3f4bd56b4993087992299",
- src_sha1 = "0c9bd572f530c411592aefb71781ecca0b3719a9",
+ sha1 = "b4d30340213c3d2a5f908860ba170c5a697829be",
+ src_sha1 = "295d873f609a0e2863f33b5dbc8906ca348f1107",
)
maven_jar(
name = "jetty_http",
artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
- sha1 = "6c02d728e15d4868486254039c867a1ac3e4a52e",
- src_sha1 = "3c0a2a82792f268631b4fefd77be9f126ec974b1",
+ sha1 = "c51b8a6a67d64672889249dd958edd77bff8fc0c",
+ src_sha1 = "c1bee39aeb565a4f26852b1851192d98ab611dbc",
)
maven_jar(
name = "jetty_io",
artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
- sha1 = "756a8cd2a1cbfb84a94973b6332dd3eccd47c0cd",
- src_sha1 = "a9afa99cccb19b441364fa805d027f457cbbb136",
+ sha1 = "76086f955d4e943396b8f340fd5bae3ce4da19d9",
+ src_sha1 = "8d41e410b2f0dd284a6e199ed08f45ef7ab2acf1",
)
maven_jar(
name = "jetty_util",
artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
- sha1 = "b8512ab02819de01f0f5a5c6026163041f579beb",
- src_sha1 = "96f8e3dcdc3660a5c91f19c46695daa70ac95625",
+ sha1 = "5fd36dfcf39110b809bd9b20cec62706ab694711",
+ src_sha1 = "629fcda1e4eecfd795e24cc07715ab9797970980",
)
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 83361e5..b1360ea 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+ org.eclipse.jgit.ant.tasks;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
org.hamcrest.core;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 63021ae..2de42d4 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 6f59d0b..7e18d16 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)"
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.8.0";
+Export-Package: org.eclipse.jgit.ant.tasks;version="4.9.0";
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 9965cde..419dc19 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index ccbbb71..466fea4 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -12,15 +12,15 @@
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.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+ org.eclipse.jgit.api;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.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.8.0";
+Export-Package: org.eclipse.jgit.archive;version="4.9.0";
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 6f25f24..29fafd6 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.8.0.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.8.0.qualifier";roots="."
+Bundle-Version: 4.9.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.9.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 56a5b96..947e59c 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 01ade87..33ee095 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
@@ -22,10 +22,10 @@
org.apache.http.impl.client;version="[4.3.0,5.0.0)",
org.apache.http.impl.conn;version="[4.3.0,5.0.0)",
org.apache.http.params;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.8.0";
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.9.0";
uses:="org.apache.http.client,
org.eclipse.jgit.transport.http,
org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 214f4ac..3a1434e 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 3e6b667..ae05d78 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.8.0",
- org.eclipse.jgit.http.server.glue;version="4.8.0";
+Export-Package: org.eclipse.jgit.http.server;version="4.9.0",
+ org.eclipse.jgit.http.server.glue;version="4.9.0";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.8.0";
+ org.eclipse.jgit.http.server.resolver;version="4.9.0";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -17,12 +17,12 @@
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
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.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.resolver;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)"
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 3c995b4..3dc3148 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
index 9c3ed50..47443f5 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java
@@ -60,4 +60,4 @@
* the servlet to execute on this path.
*/
public void with(HttpServlet servlet);
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index a7f7169..421fa8a 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -2,44 +2,44 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.http.server;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.http.server.glue;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.resolver;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+ org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.io;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security.authentication;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.handler;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.nio;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.servlet;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.component;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.http.server;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
org.hamcrest.core;version="[1.1.0,2.0.0)",
org.junit;version="[4.0.0,5.0.0)",
org.junit.runner;version="[4.0.0,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index c1edbe8..7d9c17f 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index c611b31..dd6cb48 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
@@ -10,26 +10,26 @@
Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
javax.servlet.http;version="[2.5.0,3.2.0)",
org.apache.commons.logging;version="[1.1.1,2.0.0)",
- org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.http.server;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.resolver;version="[4.8.0,4.9.0)",
+ org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security.authentication;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.handler;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.nio;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.servlet;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.component;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.http.server;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.9.0,4.10.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.8.0";
+Export-Package: org.eclipse.jgit.junit.http;version="4.9.0";
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 4ec39b1..c6ad848 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 9ef4068..28c0f21 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
@@ -46,25 +46,25 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.eclipse.jetty.security.AbstractLoginService;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.security.MappedLoginService;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.security.Constraint;
@@ -168,38 +168,41 @@
return ctx;
}
- static class TestMappedLoginService extends MappedLoginService {
+ static class TestMappedLoginService extends AbstractLoginService {
private String role;
+ protected final ConcurrentMap<String, UserPrincipal> users = new ConcurrentHashMap<>();
+
TestMappedLoginService(String role) {
this.role = role;
}
@Override
- protected UserIdentity loadUser(String who) {
- return null;
+ protected void doStart() throws Exception {
+ UserPrincipal p = new UserPrincipal(username,
+ new Password(password));
+ users.put(username, p);
+ super.doStart();
}
@Override
- protected void loadUsers() throws IOException {
- putUser(username, new Password(password), new String[] { role });
+ protected String[] loadRoleInfo(UserPrincipal user) {
+ if (users.get(user.getName()) == null)
+ return null;
+ else
+ return new String[] { role };
}
@Override
- protected String[] loadRoleInfo(KnownUser user) {
- return null;
- }
-
- @Override
- protected KnownUser loadUserInfo(String usrname) {
- return null;
+ protected UserPrincipal loadUserInfo(String user) {
+ return users.get(user);
}
}
private void auth(ServletContextHandler ctx, Authenticator authType) {
final String role = "can-access";
- MappedLoginService users = new TestMappedLoginService(role);
+ AbstractLoginService 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/MockServletConfig.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
index 9defcd9..03c0816 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
@@ -88,4 +88,4 @@
public ServletContext getServletContext() {
return null;
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
index 415398d..4e35ff6 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/RecordingLogger.java
@@ -161,6 +161,12 @@
@Override
public void warn(String msg, Object... args) {
synchronized (warnings) {
+ int i = 0;
+ int index = msg.indexOf("{}");
+ while (index >= 0) {
+ msg = msg.replaceFirst("\\{\\}", "{" + i++ + "}");
+ index = msg.indexOf("{}");
+ }
warnings.add(new Warning(MessageFormat.format(msg, args)));
}
}
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 8910659..e077f3f 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,31 +2,31 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.api.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.dircache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.merge;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.io;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.time;version="[4.8.0,4.9.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.api.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.dircache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.merge;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.io;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.time;version="[4.9.0,4.10.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.8.0";
+Export-Package: org.eclipse.jgit.junit;version="4.9.0";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
@@ -35,4 +35,4 @@
org.eclipse.jgit.util,
org.eclipse.jgit.storage.file,
org.eclipse.jgit.api",
- org.eclipse.jgit.junit.time;version="4.8.0"
+ org.eclipse.jgit.junit.time;version="4.9.0"
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index fb37640..b4cbc2e 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
index 2962e71..5bf61f0 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
@@ -258,4 +258,27 @@
target);
}
+ /**
+ * Concatenate byte arrays.
+ *
+ * @param b
+ * byte arrays to combine together.
+ * @return a single byte array that contains all bytes copied from input
+ * byte arrays.
+ * @since 4.9
+ */
+ public static byte[] concat(byte[]... b) {
+ int n = 0;
+ for (byte[] a : b) {
+ n += a.length;
+ }
+
+ byte[] data = new byte[n];
+ n = 0;
+ for (byte[] a : b) {
+ System.arraycopy(a, 0, data, n, a.length);
+ n += a.length;
+ }
+ return data;
+ }
}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 933faf9..6ace9fc 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -62,6 +62,7 @@
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
@@ -121,6 +122,12 @@
mockSystemReader = new MockSystemReader();
mockSystemReader.userGitConfig = new FileBasedConfig(new File(tmp,
"usergitconfig"), FS.DETECTED);
+ // We have to set autoDetach to false for tests, because tests expect to be able
+ // to clean up by recursively removing the repository, and background GC might be
+ // in the middle of writing or deleting files, which would disrupt this.
+ mockSystemReader.userGitConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTODETACH, false);
+ mockSystemReader.userGitConfig.save();
ceilTestDirectories(getCeilings());
SystemReader.setInstance(mockSystemReader);
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
index 22b5007..a3c869f 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java
@@ -50,4 +50,4 @@
@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
index 75e1a67..4230073 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java
@@ -128,4 +128,4 @@
}
return result;
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackKey.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
similarity index 73%
rename from org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackKey.java
rename to org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
index 98a2a94..22b69a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackKey.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, Google Inc.
+ * Copyright (C) 2017 Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,20 +41,38 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.eclipse.jgit.internal.storage.dfs;
+package org.eclipse.jgit.junit;
-import java.util.concurrent.atomic.AtomicLong;
+import static org.junit.Assert.assertEquals;
-final class DfsPackKey {
- final int hash;
+import org.eclipse.jgit.lib.ProgressMonitor;
- final AtomicLong cachedSize;
+public final class StrictWorkMonitor implements ProgressMonitor {
+ private int lastWork, totalWork;
- DfsPackKey() {
- // Multiply by 31 here so we can more directly combine with another
- // value without doing the multiply there.
- //
- hash = System.identityHashCode(this) * 31;
- cachedSize = new AtomicLong();
+ @Override
+ public void start(int totalTasks) {
+ // empty
+ }
+
+ @Override
+ public void beginTask(String title, int total) {
+ this.totalWork = total;
+ lastWork = 0;
+ }
+
+ @Override
+ public void update(int completed) {
+ lastWork += completed;
+ }
+
+ @Override
+ public void endTask() {
+ assertEquals("Units of work recorded", totalWork, lastWork);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
}
}
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 f78e812..683e337 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -13,25 +13,25 @@
org.apache.http.client.methods;version="[4.3.0,5.0.0)",
org.apache.http.entity;version="[4.3.0,5.0.0)",
org.apache.http.impl.client;version="[4.3.0,5.0.0)",
- org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
- org.eclipse.jgit.junit.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.test;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+ org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.io;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security.authentication;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.handler;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.nio;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.servlet;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.component;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
+ org.eclipse.jgit.junit.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.test;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.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 0d10fc7..7539940 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java
index e10660d..5da502e 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
@@ -265,4 +265,4 @@
}
return Files.size(f);
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index d13ec99..1ec0cfb 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs.server;version="4.8.0";
+Export-Package: org.eclipse.jgit.lfs.server;version="4.9.0";
uses:="javax.servlet.http,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="4.8.0";
+ org.eclipse.jgit.lfs.server.fs;version="4.9.0";
uses:="javax.servlet,
javax.servlet.http,
org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="4.8.0";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="4.8.0";
+ org.eclipse.jgit.lfs.server.internal;version="4.9.0";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="4.9.0";
uses:="org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -24,14 +24,14 @@
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.8.0,4.9.0)",
- org.eclipse.jgit.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+ org.eclipse.jgit.annotations;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 9d487ae..1f03ae7 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.server</artifactId>
@@ -140,25 +140,6 @@
</archive>
</configuration>
</plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
</project>
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java
index 86ca2d3..4fea92e 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java
@@ -164,4 +164,4 @@
}
abstract Response.Body process() throws IOException;
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index 78dc263..b9ecf90 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -2,23 +2,23 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
+Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.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.8.0";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="4.9.0";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 8268c85..bf0d5d6 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index daf4a56..bf94686 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -2,20 +2,20 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.lfs;version="4.8.0",
- org.eclipse.jgit.lfs.errors;version="4.8.0",
- org.eclipse.jgit.lfs.internal;version="4.8.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="4.8.0"
+Export-Package: org.eclipse.jgit.lfs;version="4.9.0",
+ org.eclipse.jgit.lfs.errors;version="4.9.0",
+ org.eclipse.jgit.lfs.internal;version="4.9.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="4.9.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.annotations;version="[4.8.0,4.9.0)";resolution:=optional,
- org.eclipse.jgit.attributes;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)"
+Import-Package: org.eclipse.jgit.annotations;version="[4.9.0,4.10.0)";resolution:=optional,
+ org.eclipse.jgit.attributes;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)"
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index f2ec75c..f3616c3 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs</artifactId>
@@ -116,25 +116,6 @@
</archive>
</configuration>
</plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
</project>
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
index 867cca5..1598b9e 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/AtomicObjectOutputStream.java
@@ -146,4 +146,4 @@
locked.unlock();
aborted = true;
}
-}
\ 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 4ea616f..46b9895 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.8.0.qualifier"
+ version="4.9.0.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 92b9a5f..356b407 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 b7dc997..2a82d35 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.8.0.qualifier"
+ version="4.9.0.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 dfbc5ce..4318e2b 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 429877c..7ff5a24 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.8.0.qualifier"
+ version="4.9.0.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 e3ebb83..cdbc48b 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 2453965..d064c9a 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.8.0.qualifier"
+ version="4.9.0.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 eacab7b..3ce89d5 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 a7af646..d28f0c6 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.8.0.qualifier"
+ version="4.9.0.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.8.0" match="equivalent"/>
- <import feature="org.eclipse.jgit.lfs" version="4.8.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="4.9.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit.lfs" version="4.9.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 d1498e8..8feceb0 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 a1f9098..e59e738 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.8.0.qualifier"
+ version="4.9.0.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 ac6f987..4ba3edc 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index ed9446a..7784c0b 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 65301d6..6b6a18d 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.8.0.qualifier"
+ version="4.9.0.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 857d9e5..a4fb063 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 ceaf8b8..38d7805 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
index 1d537e6..b2099ae 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.5" sequenceNumber="1491140572">
+<target name="jgit-4.5" sequenceNumber="1496008880">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
- <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
+ <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.4.v201504302020"/>
@@ -98,7 +98,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/S20170306214312/repository"/>
+ <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/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/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
index ea4f5f6..f9653b2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
@@ -1,8 +1,8 @@
target "jgit-4.5" with source configurePhase
-include "projects/jetty-9.3.17.tpd"
+include "projects/jetty-9.4.5.tpd"
include "orbit/R20160221192158-Mars.tpd"
-include "orbit/S20170306214312-Oxygen.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
location "http://download.eclipse.org/releases/mars/" {
org.eclipse.osgi lazy
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 babcf09..e4baa5d 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,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.6" sequenceNumber="1491140561">
+<target name="jgit-4.6" sequenceNumber="1496008884">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
- <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
+ <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.6.v201510161327"/>
@@ -60,7 +60,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/S20170306214312/repository"/>
+ <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/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/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index b699452..9ddba2d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
target "jgit-4.6" with source configurePhase
-include "projects/jetty-9.3.17.tpd"
-include "orbit/S20170306214312-Oxygen.tpd"
+include "projects/jetty-9.4.5.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
location "http://download.eclipse.org/releases/neon/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 5e4f555..9a15741 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.7" sequenceNumber="1491140544">
+<target name="jgit-4.7" sequenceNumber="1496008862">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.client.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.http.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.io.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.security.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.server.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util" version="9.3.17.v20170317"/>
- <unit id="org.eclipse.jetty.util.source" version="9.3.17.v20170317"/>
- <repository id="jetty-9.3.17" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.5.v20170502"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.5.v20170502"/>
+ <repository id="jetty-9.4.5" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.apache.ant" version="1.9.6.v201510161327"/>
@@ -60,7 +60,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/S20170306214312/repository"/>
+ <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/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/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index 624b119..4185079 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,8 +1,8 @@
target "jgit-4.7" with source configurePhase
-include "projects/jetty-9.3.17.tpd"
-include "orbit/S20170306214312-Oxygen.tpd"
+include "projects/jetty-9.4.5.tpd"
+include "orbit/R20170516192513-Oxygen.tpd"
location "http://download.eclipse.org/releases/oxygen/" {
org.eclipse.osgi lazy
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170306214312-Oxygen.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
similarity index 96%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170306214312-Oxygen.tpd
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
index 25722bf..ef19fa6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20170306214312-Oxygen.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20170516192513-Oxygen.tpd
@@ -1,7 +1,7 @@
-target "S20170306214312-Oxygen" with source configurePhase
+target "R20170516192513-Oxygen" with source configurePhase
// see http://download.eclipse.org/tools/orbit/downloads/
-location "http://download.eclipse.org/tools/orbit/downloads/drops/S20170306214312/repository" {
+location "http://download.eclipse.org/tools/orbit/downloads/drops/R20170516192513/repository" {
org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
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 2ef4d49..721fe9b 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd
deleted file mode 100644
index 662df09..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.17.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.3.17" with source configurePhase
-
-location jetty-9.3.17 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.17.v20170317/" {
- org.eclipse.jetty.client [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.client.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.continuation [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.continuation.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.http [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.http.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.io [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.io.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.security [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.security.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.server [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.server.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.servlet [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.servlet.source [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.util [9.3.17.v20170317,9.3.17.v20170317]
- org.eclipse.jetty.util.source [9.3.17.v20170317,9.3.17.v20170317]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.9.tpd
deleted file mode 100644
index d5621a0..0000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.3.9.tpd
+++ /dev/null
@@ -1,20 +0,0 @@
-target "jetty-9.4.3" with source configurePhase
-
-location jetty-9.4.3 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.3.9.v20160517/" {
- org.eclipse.jetty.client [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.client.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.continuation [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.continuation.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.http [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.http.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.io [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.io.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.security [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.security.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.server [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.server.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.servlet [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.servlet.source [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.util [9.3.9.v20160517,9.3.9.v20160517]
- org.eclipse.jetty.util.source [9.3.9.v20160517,9.3.9.v20160517]
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd
new file mode 100644
index 0000000..363c600
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.5.tpd
@@ -0,0 +1,20 @@
+target "jetty-9.4.5" with source configurePhase
+
+location jetty-9.4.5 "http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.5.v20170502/" {
+ org.eclipse.jetty.client [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.client.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.continuation [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.continuation.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.http [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.http.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.io [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.io.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.security [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.security.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.server [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.server.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.servlet [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.servlet.source [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.util [9.4.5.v20170502,9.4.5.v20170502]
+ org.eclipse.jetty.util.source [9.4.5.v20170502,9.4.5.v20170502]
+}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 000bcd5..deda4d0 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 381e272..44864c3 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.api.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.diff;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.dircache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="4.8.0",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.merge;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.pgm;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.pgm.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.pgm.opt;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.io;version="[4.8.0,4.9.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.api.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.diff;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.dircache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="4.9.0",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.merge;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.pgm;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.io;version="[4.9.0,4.10.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 d9c7d1d..68b4c92 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index 18c49ea..6f32bfa 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -348,7 +348,7 @@
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=zip master", db).outBytes();
- String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
+ String[] expect = { "x/", "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listZipEntries(result);
Arrays.sort(expect);
@@ -361,7 +361,7 @@
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=tar master", db).outBytes();
- String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
+ String[] expect = { "x/", "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listTarEntries(result);
Arrays.sort(expect);
@@ -380,7 +380,7 @@
commitFoo();
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=zip master", db).outBytes();
- String[] expect = { "x//foo" };
+ String[] expect = { "x/", "x//foo" };
assertArrayEquals(expect, listZipEntries(result));
}
@@ -389,7 +389,7 @@
commitFoo();
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=tar master", db).outBytes();
- String[] expect = { "x//foo" };
+ String[] expect = { "x/", "x//foo" };
assertArrayEquals(expect, listTarEntries(result));
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
index c43accd..0ce6451 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
@@ -74,6 +74,7 @@
String[] output = execute("git config --list");
List<String> expect = new ArrayList<>();
+ expect.add("gc.autoDetach=false");
expect.add("core.filemode=" + !isWindows);
expect.add("core.logallrefupdates=true");
if (isMac)
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
index 086e72e..e97762d 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
@@ -46,6 +46,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.util.Arrays;
@@ -71,6 +72,12 @@
git.tag().setName("v1.0").call();
}
+ private void secondCommit() throws Exception {
+ writeTrashFile("greeting", "Hello, world!");
+ git.add().addFilepattern("greeting").call();
+ git.commit().setMessage("2nd commit").call();
+ }
+
@Test
public void testNoHead() throws Exception {
assertEquals(CLIText.fatalError(CLIText.get().noNamesFound),
@@ -94,9 +101,7 @@
@Test
public void testDescribeCommit() throws Exception {
initialCommitAndTag();
- writeTrashFile("greeting", "Hello, world!");
- git.add().addFilepattern("greeting").call();
- git.commit().setMessage("2nd commit").call();
+ secondCommit();
assertArrayEquals(new String[] { "v1.0-1-g56f6ceb", "" },
execute("git describe"));
}
@@ -109,6 +114,47 @@
}
@Test
+ public void testDescribeCommitMatch() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ assertArrayEquals(new String[] { "v1.0-1-g56f6ceb", "" },
+ execute("git describe --match v1.*"));
+ }
+
+ @Test
+ public void testDescribeCommitMatch2() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ git.tag().setName("v2.0").call();
+ assertArrayEquals(new String[] { "v1.0-1-g56f6ceb", "" },
+ execute("git describe --match v1.*"));
+ }
+
+ @Test
+ public void testDescribeCommitMultiMatch() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ git.tag().setName("v2.0.0").call();
+ git.tag().setName("v2.1.1").call();
+ assertArrayEquals("git yields v2.0.0", new String[] { "v2.0.0", "" },
+ execute("git describe --match v2.0* --match v2.1.*"));
+ }
+
+ @Test
+ public void testDescribeCommitNoMatch() throws Exception {
+ initialCommitAndTag();
+ writeTrashFile("greeting", "Hello, world!");
+ secondCommit();
+ try {
+ execute("git describe --match 1.*");
+ fail("git describe should not find any tag matching 1.*");
+ } catch (Die e) {
+ assertEquals("No names found, cannot describe anything.",
+ e.getMessage());
+ }
+ }
+
+ @Test
public void testHelpArgumentBeforeUnknown() throws Exception {
String[] output = execute("git describe -h -XYZ");
String all = Arrays.toString(output);
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
index 7330ee9..bf6bacb 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
@@ -80,4 +80,4 @@
"" }, execute("git reflog refs/heads/side"));
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index df3406c..e73b352 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
@@ -13,60 +13,60 @@
org.apache.commons.compress.archivers.tar;version="[1.3,2.0)",
org.apache.commons.compress.archivers.zip;version="[1.3,2.0)",
org.apache.commons.logging;version="1.1.1",
- org.eclipse.jetty.continuation;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.http;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.io;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.security.authentication;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.handler;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.server.nio;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.servlet;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.component;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.log;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.security;version="[9.0.0,9.4.0)",
- org.eclipse.jetty.util.thread;version="[9.0.0,9.4.0)",
- org.eclipse.jgit.api;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.api.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.archive;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.awtui;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.blame;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.diff;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.dircache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.gitrepo;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.ketch;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.server;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.server.fs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs.server.s3;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.merge;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.notes;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revplot;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.pack;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.resolver;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.io;version="[4.8.0,4.9.0)",
+ org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.io;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.security.authentication;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.handler;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.server.nio;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.servlet;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.component;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
+ org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
+ org.eclipse.jgit.api;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.api.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.archive;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.awtui;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.blame;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.diff;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.dircache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.gitrepo;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.ketch;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.server;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.merge;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.notes;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revplot;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.pack;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.io;version="[4.9.0,4.10.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.8.0";
+Export-Package: org.eclipse.jgit.console;version="4.9.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.8.0";
+ org.eclipse.jgit.pgm;version="4.9.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.pgm.opt,
@@ -77,11 +77,11 @@
org.eclipse.jgit.treewalk,
javax.swing,
org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.8.0";
+ org.eclipse.jgit.pgm.debug;version="4.9.0";
uses:="org.eclipse.jgit.util.io,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.8.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.8.0";
+ org.eclipse.jgit.pgm.internal;version="4.9.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.9.0";
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 5b80357..a4099b4 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.8.0.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.8.0.qualifier";roots="."
+Bundle-Version: 4.9.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.9.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 9bb8bfd..d6b78c5 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
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 f630cee..8666c34 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
@@ -67,12 +67,14 @@
failedToLockTag=Failed to lock tag {0}: {1}
fatalError=fatal: {0}
fatalThisProgramWillDestroyTheRepository=fatal: This program will destroy the repository\nfatal:\nfatal:\nfatal: {0}\nfatal:\nfatal: To continue, add {1} to the command line\nfatal:
+fetchingSubmodule=Fetching submodule {0}
fileIsRequired=argument file is required
ffNotPossibleAborting=Not possible to fast-forward, aborting.
forcedUpdate=forced update
fromURI=From {0}
initializedEmptyGitRepositoryIn=Initialized empty Git repository in {0}
invalidHttpProxyOnlyHttpSupported=Invalid http_proxy: {0}: Only http supported.
+invalidRecurseSubmodulesMode=Invalid recurse submodules mode: {0}
jgitVersion=jgit version {0}
lineFormat={0}
listeningOn=Listening on {0}
@@ -127,6 +129,7 @@
metaVar_pass=PASS
metaVar_path=path
metaVar_paths=path ...
+metaVar_pattern=pattern
metaVar_port=PORT
metaVar_ref=REF
metaVar_refs=REFS
@@ -246,6 +249,7 @@
usage_lsRemoteTags=Show only refs starting with refs/tags
usage_LsTree=List the contents of a tree object
usage_MakeCacheTree=Show the current cache tree structure
+usage_Match=Only consider tags matching the given glob(7) pattern or patterns, excluding the "refs/tags/" prefix.
usage_MergeBase=Find as good common ancestors as possible for a merge
usage_MergesTwoDevelopmentHistories=Merges two development histories
usage_PreserveOldPacks=Preserve old pack files by moving them into the preserved subdirectory instead of deleting them after repacking
@@ -285,7 +289,7 @@
usage_addFileContentsToTheIndex=Add file contents to the index
usage_alterTheDetailShown=alter the detail shown
usage_approveDestructionOfRepository=approve destruction of repository
-usage_archive=zip up files from the named tree
+usage_archive=Zip up files from the named tree
usage_archiveFormat=archive format. Currently supported formats: 'tar', 'zip', 'tgz', 'tbz2', 'txz'
usage_archiveOutput=output file to write the archive to
usage_archivePrefix=string to prepend to each pathname in the archive
@@ -359,6 +363,7 @@
usage_noCommit=Don't commit after a successful merge
usage_noPrefix=do not show any source or destination prefix
usage_noRenames=disable rename detection
+usage_noRecurseSubmodules=Disable recursive fetching of submodules (this has the same effect as using the --recurse-submodules=no option)
usage_noShowStandardNotes=Disable showing notes from the standard /refs/notes/commits branch
usage_onlyMatchAgainstAlreadyTrackedFiles=Only match <filepattern> against already tracked files in the index rather than the working tree
usage_outputFile=Output file
@@ -384,7 +389,7 @@
usage_runLfsStore=Run LFS Store in a given directory
usage_S3NoSslVerify=Skip verification of Amazon server certificate and hostname
usage_setTheGitRepositoryToOperateOn=set the git repository to operate on
-usage_show=display one commit
+usage_show=Display one commit
usage_showRefNamesMatchingCommits=Show ref names matching commits
usage_showPatch=display patch
usage_showNotes=Add this ref to the list of note branches from which notes are displayed
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
index 2cee2cb..08ec096 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
@@ -90,6 +90,9 @@
}
}
showRemoteMessages(errw, r.getMessages());
+ for (FetchResult submoduleResult : r.submoduleResults().values()) {
+ showFetchResult(submoduleResult);
+ }
}
static void showRemoteMessages(ThrowingPrintWriter writer, String pkt) throws IOException {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
index faae13a..f5c3f9a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -122,4 +122,4 @@
}
}
}
-}
\ No newline at end of file
+}
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 1008593..ceabe93 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
@@ -204,4 +204,4 @@
}
});
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index ec000f3..eba5a43 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -50,6 +50,9 @@
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
+import java.util.ArrayList;
+import java.util.List;
+
@Command(common = true, usage = "usage_Describe")
class Describe extends TextBuiltin {
@@ -59,6 +62,9 @@
@Option(name = "--long", usage = "usage_LongFormat")
private boolean longDesc;
+ @Option(name = "--match", multiValued = true, usage = "usage_Match", metaVar = "metaVar_pattern")
+ private List<String> patterns = new ArrayList<>();
+
@Override
protected void run() throws Exception {
try (Git git = new Git(db)) {
@@ -66,6 +72,7 @@
if (tree != null)
cmd.setTarget(tree);
cmd.setLong(longDesc);
+ cmd.setMatch(patterns.toArray(new String[patterns.size()]));
String result = null;
try {
result = cmd.call();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
index ed06733..5ed23b9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java
@@ -45,11 +45,15 @@
package org.eclipse.jgit.pgm;
+import java.io.IOException;
+import java.text.MessageFormat;
import java.util.List;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
+import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.RefSpec;
@@ -58,7 +62,7 @@
import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_updateRemoteRefsFromAnotherRepository")
-class Fetch extends AbstractFetchCommand {
+class Fetch extends AbstractFetchCommand implements FetchCommand.Callback {
@Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity")
int timeout = -1;
@@ -96,6 +100,31 @@
tags = Boolean.FALSE;
}
+ private FetchRecurseSubmodulesMode recurseSubmodules;
+
+ @Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules")
+ void recurseSubmodules(String mode) {
+ if (mode == null || mode.isEmpty()) {
+ recurseSubmodules = FetchRecurseSubmodulesMode.YES;
+ } else {
+ for (FetchRecurseSubmodulesMode m : FetchRecurseSubmodulesMode
+ .values()) {
+ if (m.matchConfigValue(mode)) {
+ recurseSubmodules = m;
+ return;
+ }
+ }
+ throw die(MessageFormat
+ .format(CLIText.get().invalidRecurseSubmodulesMode, mode));
+ }
+ }
+
+ @Option(name = "--no-recurse-submodules", usage = "usage_noRecurseSubmodules")
+ void noRecurseSubmodules(@SuppressWarnings("unused")
+ final boolean ignored) {
+ recurseSubmodules = FetchRecurseSubmodulesMode.NO;
+ }
+
@Argument(index = 0, metaVar = "metaVar_uriish")
private String remote = Constants.DEFAULT_REMOTE_NAME;
@@ -124,12 +153,25 @@
fetch.setThin(thin.booleanValue());
if (quiet == null || !quiet.booleanValue())
fetch.setProgressMonitor(new TextProgressMonitor(errw));
+ fetch.setRecurseSubmodules(recurseSubmodules).setCallback(this);
FetchResult result = fetch.call();
- if (result.getTrackingRefUpdates().isEmpty())
+ if (result.getTrackingRefUpdates().isEmpty()
+ && result.submoduleResults().isEmpty())
return;
showFetchResult(result);
}
}
+
+ @Override
+ public void fetchingSubmodule(String name) {
+ try {
+ outw.println(MessageFormat.format(CLIText.get().fetchingSubmodule,
+ name));
+ outw.flush();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index 3addecb..c94ba0b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -44,8 +44,11 @@
package org.eclipse.jgit.pgm;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.File;
import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
@@ -54,6 +57,10 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.awtui.AwtAuthenticator;
import org.eclipse.jgit.awtui.AwtCredentialsProvider;
@@ -95,6 +102,8 @@
PrintWriter writer;
+ private ExecutorService gcExecutor;
+
/**
*
*/
@@ -102,6 +111,17 @@
HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
CleanFilter.register();
SmudgeFilter.register();
+ gcExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ private final ThreadFactory baseFactory = Executors
+ .defaultThreadFactory();
+
+ @Override
+ public Thread newThread(Runnable taskBody) {
+ Thread thr = baseFactory.newThread(taskBody);
+ thr.setName("JGit-autoGc"); //$NON-NLS-1$
+ return thr;
+ }
+ });
}
/**
@@ -189,10 +209,12 @@
// broken pipe
exit(1, null);
}
+ gcExecutor.shutdown();
+ gcExecutor.awaitTermination(10, TimeUnit.MINUTES);
}
PrintWriter createErrorWriter() {
- return new PrintWriter(System.err);
+ return new PrintWriter(new OutputStreamWriter(System.err, UTF_8));
}
private void execute(final String[] argv) throws Exception {
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 e10ecbe..1424dab 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
@@ -143,12 +143,14 @@
/***/ public String failedToLockTag;
/***/ public String fatalError;
/***/ public String fatalThisProgramWillDestroyTheRepository;
+ /***/ public String fetchingSubmodule;
/***/ public String fileIsRequired;
/***/ public String ffNotPossibleAborting;
/***/ public String forcedUpdate;
/***/ public String fromURI;
/***/ public String initializedEmptyGitRepositoryIn;
/***/ public String invalidHttpProxyOnlyHttpSupported;
+ /***/ public String invalidRecurseSubmodulesMode;
/***/ public String jgitVersion;
/***/ public String lfsNoAccessKey;
/***/ public String lfsNoSecretKey;
@@ -194,6 +196,7 @@
/***/ public String metaVar_pass;
/***/ public String metaVar_path;
/***/ public String metaVar_paths;
+ /***/ public String metaVar_pattern;
/***/ public String metaVar_port;
/***/ public String metaVar_ref;
/***/ public String metaVar_refs;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
index c4e8b05..d6ff5f0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java
@@ -111,4 +111,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 4b2e535..670b42b 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,54 +2,55 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
- org.eclipse.jgit.api;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.api.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.attributes;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.awtui;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.blame;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.diff;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.dircache;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.events;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.fnmatch;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.gitrepo;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.hooks;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.ignore;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.ignore.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.junit;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lfs;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.merge;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.notes;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.patch;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.pgm;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.pgm.internal;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revplot;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.file;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.storage.pack;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.submodule;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.http;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport.resolver;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.io;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util.sha1;version="[4.8.0,4.9.0)",
+ org.eclipse.jgit.api;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.api.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.attributes;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.awtui;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.blame;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.diff;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.dircache;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.events;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.fnmatch;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.gitrepo;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.hooks;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.ignore;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.fsck;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.junit;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lfs;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.merge;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.notes;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.patch;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.pgm;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revplot;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.file;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.storage.pack;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.submodule;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.http;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.io;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util.sha1;version="[4.9.0,4.10.0)",
org.junit;version="[4.4.0,5.0.0)",
org.junit.experimental.theories;version="[4.4.0,5.0.0)",
org.junit.rules;version="[4.11.0,5.0.0)",
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index e3b0dcd..dad1e3c 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/disabled_checked.gif b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/disabled_checked.gif
new file mode 100644
index 0000000..47b9e32
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/disabled_checked.gif
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/enabled_checked.gif b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/enabled_checked.gif
new file mode 100644
index 0000000..252f762
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/attributes/merge/enabled_checked.gif
Binary files differ
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 7e657e6..a0834e7 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;
/**
@@ -305,6 +306,7 @@
}
}
+ @Ignore("very flaky when run with Hudson")
@Test
public void commitUpdatesSmudgedEntries() throws Exception {
try (Git git = new Git(db)) {
@@ -361,6 +363,7 @@
}
}
+ @Ignore("very flaky when run with Hudson")
@Test
public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
try (Git git = new Git(db)) {
@@ -554,6 +557,11 @@
} catch (EmtpyCommitException e) {
// expect this exception
}
+
+ // Allow empty commits also when setOnly was set
+ git.commit().setAuthor("New Author", "newauthor@example.org")
+ .setMessage("again no change").setOnly("file1")
+ .setAllowEmpty(true).call();
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
index 1e5d3bc..6a66783 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -54,6 +54,7 @@
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
+import org.eclipse.jgit.errors.InvalidPatternException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Test;
@@ -92,26 +93,65 @@
ObjectId c1 = modify("aaa");
ObjectId c2 = modify("bbb");
- tag("t1");
+ tag("alice-t1");
ObjectId c3 = modify("ccc");
- tag("t2");
+ tag("bob-t2");
ObjectId c4 = modify("ddd");
assertNull(describe(c1));
assertNull(describe(c1, true));
- assertEquals("t1", describe(c2));
- assertEquals("t2", describe(c3));
- assertEquals("t2-0-g44579eb", describe(c3, true));
+ assertNull(describe(c1, "a*", "b*", "c*"));
+
+ assertEquals("alice-t1", describe(c2));
+ assertEquals("alice-t1", describe(c2, "alice*"));
+ assertNull(describe(c2, "bob*"));
+ assertNull(describe(c2, "?ob*"));
+ assertEquals("alice-t1", describe(c2, "a*", "b*", "c*"));
+
+ assertEquals("bob-t2", describe(c3));
+ assertEquals("bob-t2-0-g44579eb", describe(c3, true));
+ assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*"));
+ assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*"));
+ assertEquals("bob-t2", describe(c3, "bob*"));
+ assertEquals("bob-t2", describe(c3, "?ob*"));
+ assertEquals("bob-t2", describe(c3, "a*", "b*", "c*"));
assertNameStartsWith(c4, "3e563c5");
// the value verified with git-describe(1)
- assertEquals("t2-1-g3e563c5", describe(c4));
- assertEquals("t2-1-g3e563c5", describe(c4, true));
+ assertEquals("bob-t2-1-g3e563c5", describe(c4));
+ assertEquals("bob-t2-1-g3e563c5", describe(c4, true));
+ assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*"));
+ assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*"));
+ assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*"));
// test default target
- assertEquals("t2-1-g3e563c5", git.describe().call());
+ assertEquals("bob-t2-1-g3e563c5", git.describe().call());
+ }
+
+ @Test
+ public void testDescribeMultiMatch() throws Exception {
+ ObjectId c1 = modify("aaa");
+ tag("v1.0.0");
+ tag("v1.1.1");
+ ObjectId c2 = modify("bbb");
+
+ // Ensure that if we're interested in any tags, we get the first match as per Git behaviour
+ assertEquals("v1.0.0", describe(c1));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2));
+
+ // Ensure that if we're only interested in one of multiple tags, we get the right match
+ assertEquals("v1.0.0", describe(c1, "v1.0*"));
+ assertEquals("v1.1.1", describe(c1, "v1.1*"));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*"));
+ assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*"));
+
+ // Ensure that ordering of match precedence is preserved as per Git behaviour
+ assertEquals("v1.0.0", describe(c1, "v1.0*", "v1.1*"));
+ assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*"));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*", "v1.1*"));
+ assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*", "v1.0*"));
}
/**
@@ -271,6 +311,10 @@
return describe(c1, false);
}
+ private String describe(ObjectId c1, String... patterns) throws GitAPIException, IOException, InvalidPatternException {
+ return git.describe().setTarget(c1).setMatch(patterns).call();
+ }
+
private static void assertNameStartsWith(ObjectId c4, String prefix) {
assertTrue(c4.name(), c4.name().startsWith(prefix));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
index 38178bf..bd0efad 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogCommandTest.java
@@ -289,4 +289,4 @@
.setMessage("merge s0 with m1").call();
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
index 823516b..a341284 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -620,4 +620,4 @@
fis.close();
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
index 8c613ec..e0c1499 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
@@ -83,6 +83,11 @@
// create other repository
Repository db2 = createWorkRepository();
+ final StoredConfig config2 = db2.getConfig();
+
+ // this tests that this config can be parsed properly
+ config2.setString("fsck", "", "missingEmail", "ignore");
+ config2.save();
// setup the first repository
final StoredConfig config = db.getConfig();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
index ec2370e..f0d3c36 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
@@ -166,6 +166,25 @@
assertAttribute("file.type3", node, asSet(A_UNSET_ATTR, B_SET_ATTR));
}
+ @Test
+ public void testDoubleAsteriskAtEnd() throws IOException {
+ String attributeFileContent = "dir/** \tA -B\tC=value";
+
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("dir", node,
+ asSet(new Attribute[]{}));
+ assertAttribute("dir/", node,
+ asSet(new Attribute[]{}));
+ assertAttribute("dir/file.type1", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ assertAttribute("dir/sub/", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ assertAttribute("dir/sub/file.type1", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ }
+
private void assertAttribute(String path, AttributesNode node,
Attributes attrs) throws IOException {
Attributes attributes = new Attributes();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
new file mode 100644
index 0000000..665f47b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
+ * 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.attributes.merge;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.function.Consumer;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.MergeResult;
+import org.eclipse.jgit.api.MergeResult.MergeStatus;
+import org.eclipse.jgit.api.errors.CheckoutConflictException;
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidMergeHeadsException;
+import org.eclipse.jgit.api.errors.NoFilepatternException;
+import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.api.errors.NoMessageException;
+import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
+import org.eclipse.jgit.attributes.Attribute;
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class MergeGitAttributeTest extends RepositoryTestCase {
+
+ private static final String REFS_HEADS_RIGHT = "refs/heads/right";
+
+ private static final String REFS_HEADS_MASTER = "refs/heads/master";
+
+ private static final String REFS_HEADS_LEFT = "refs/heads/left";
+
+ private static final String DISABLE_CHECK_BRANCH = "refs/heads/disabled_checked";
+
+ private static final String ENABLE_CHECKED_BRANCH = "refs/heads/enabled_checked";
+
+ private static final String ENABLED_CHECKED_GIF = "enabled_checked.gif";
+
+ public Git createRepositoryBinaryConflict(Consumer<Git> initialCommit,
+ Consumer<Git> leftCommit, Consumer<Git> rightCommit)
+ throws NoFilepatternException, GitAPIException, NoWorkTreeException,
+ IOException {
+ // Set up a git whith conflict commits on images
+ Git git = new Git(db);
+
+ // First commit
+ initialCommit.accept(git);
+ git.add().addFilepattern(".").call();
+ RevCommit firstCommit = git.commit().setAll(true)
+ .setMessage("initial commit adding git attribute file").call();
+
+ // Create branch and add an icon Checked_Boxe (enabled_checked)
+ createBranch(firstCommit, REFS_HEADS_LEFT);
+ checkoutBranch(REFS_HEADS_LEFT);
+ leftCommit.accept(git);
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Left").call();
+
+ // Create a second branch from master Unchecked_Boxe
+ checkoutBranch(REFS_HEADS_MASTER);
+ createBranch(firstCommit, REFS_HEADS_RIGHT);
+ checkoutBranch(REFS_HEADS_RIGHT);
+ rightCommit.accept(git);
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Right").call();
+
+ checkoutBranch(REFS_HEADS_LEFT);
+ return git;
+
+ }
+
+ @Test
+ public void mergeTextualFile_NoAttr() throws NoWorkTreeException,
+ NoFilepatternException, GitAPIException, IOException {
+ try (Git git = createRepositoryBinaryConflict(g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "F\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "E\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ })) {
+ checkoutBranch(REFS_HEADS_LEFT);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+
+ MergeResult mergeResult = git.merge()
+ .include(git.getRepository().resolve(REFS_HEADS_RIGHT))
+ .call();
+ assertEquals(MergeStatus.MERGED, mergeResult.getMergeStatus());
+
+ assertNull(mergeResult.getConflicts());
+
+ // Check that the image was not modified (not conflict marker added)
+ String result = read(
+ writeTrashFile("res.cat", "A\n" + "E\n" + "C\n" + "F\n"));
+ assertEquals(result, read(git.getRepository().getWorkTree().toPath()
+ .resolve("main.cat").toFile()));
+ }
+ }
+
+ @Test
+ public void mergeTextualFile_UnsetMerge_Conflict()
+ throws NoWorkTreeException, NoFilepatternException, GitAPIException,
+ IOException {
+ try (Git git = createRepositoryBinaryConflict(g -> {
+ try {
+ writeTrashFile(".gitattributes", "*.cat -merge");
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "F\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "E\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ })) {
+ // Check that the merge attribute is unset
+ assertAddMergeAttributeUnset(REFS_HEADS_LEFT, "main.cat");
+ assertAddMergeAttributeUnset(REFS_HEADS_RIGHT, "main.cat");
+
+ checkoutBranch(REFS_HEADS_LEFT);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+
+ String catContent = read(git.getRepository().getWorkTree().toPath()
+ .resolve("main.cat").toFile());
+
+ MergeResult mergeResult = git.merge()
+ .include(git.getRepository().resolve(REFS_HEADS_RIGHT))
+ .call();
+ assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (not conflict marker added)
+ assertEquals(catContent, read(git.getRepository().getWorkTree()
+ .toPath().resolve("main.cat").toFile()));
+ }
+ }
+
+ @Test
+ public void mergeTextualFile_UnsetMerge_NoConflict()
+ throws NoWorkTreeException, NoFilepatternException, GitAPIException,
+ IOException {
+ try (Git git = createRepositoryBinaryConflict(g -> {
+ try {
+ writeTrashFile(".gitattributes", "*.txt -merge");
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "F\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "E\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ })) {
+ // Check that the merge attribute is unset
+ assertAddMergeAttributeUndefined(REFS_HEADS_LEFT, "main.cat");
+ assertAddMergeAttributeUndefined(REFS_HEADS_RIGHT, "main.cat");
+
+ checkoutBranch(REFS_HEADS_LEFT);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+
+ MergeResult mergeResult = git.merge()
+ .include(git.getRepository().resolve(REFS_HEADS_RIGHT))
+ .call();
+ assertEquals(MergeStatus.MERGED, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (not conflict marker added)
+ String result = read(
+ writeTrashFile("res.cat", "A\n" + "E\n" + "C\n" + "F\n"));
+ assertEquals(result, read(git.getRepository().getWorkTree()
+ .toPath().resolve("main.cat").toFile()));
+ }
+ }
+
+ @Test
+ public void mergeTextualFile_SetBinaryMerge_Conflict()
+ throws NoWorkTreeException, NoFilepatternException, GitAPIException,
+ IOException {
+ try (Git git = createRepositoryBinaryConflict(g -> {
+ try {
+ writeTrashFile(".gitattributes", "*.cat merge=binary");
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "F\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }, g -> {
+ try {
+ writeTrashFile("main.cat", "A\n" + "E\n" + "C\n" + "D\n");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ })) {
+ // Check that the merge attribute is set to binary
+ assertAddMergeAttributeCustom(REFS_HEADS_LEFT, "main.cat",
+ "binary");
+ assertAddMergeAttributeCustom(REFS_HEADS_RIGHT, "main.cat",
+ "binary");
+
+ checkoutBranch(REFS_HEADS_LEFT);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+
+ String catContent = read(git.getRepository().getWorkTree().toPath()
+ .resolve("main.cat").toFile());
+
+ MergeResult mergeResult = git.merge()
+ .include(git.getRepository().resolve(REFS_HEADS_RIGHT))
+ .call();
+ assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (not conflict marker added)
+ assertEquals(catContent, read(git.getRepository().getWorkTree()
+ .toPath().resolve("main.cat").toFile()));
+ }
+ }
+
+ /*
+ * This test is commented because JGit add conflict markers in binary files.
+ * cf. https://www.eclipse.org/forums/index.php/t/1086511/
+ */
+ @Test
+ @Ignore
+ public void mergeBinaryFile_NoAttr_Conflict() throws IllegalStateException,
+ IOException, NoHeadException, ConcurrentRefUpdateException,
+ CheckoutConflictException, InvalidMergeHeadsException,
+ WrongRepositoryStateException, NoMessageException, GitAPIException {
+
+ RevCommit disableCheckedCommit;
+ FileInputStream mergeResultFile = null;
+ // Set up a git with conflict commits on images
+ try (Git git = new Git(db)) {
+ // First commit
+ write(new File(db.getWorkTree(), ".gitattributes"), "");
+ git.add().addFilepattern(".gitattributes").call();
+ RevCommit firstCommit = git.commit()
+ .setMessage("initial commit adding git attribute file")
+ .call();
+
+ // Create branch and add an icon Checked_Boxe (enabled_checked)
+ createBranch(firstCommit, ENABLE_CHECKED_BRANCH);
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ copy(ENABLED_CHECKED_GIF, ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ git.commit().setMessage("enabled_checked commit").call();
+
+ // Create a second branch from master Unchecked_Boxe
+ checkoutBranch(REFS_HEADS_MASTER);
+ createBranch(firstCommit, DISABLE_CHECK_BRANCH);
+ checkoutBranch(DISABLE_CHECK_BRANCH);
+ copy("disabled_checked.gif", ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ disableCheckedCommit = git.commit()
+ .setMessage("disabled_checked commit").call();
+
+ // Check that the merge attribute is unset
+ assertAddMergeAttributeUndefined(ENABLE_CHECKED_BRANCH,
+ ENABLED_CHECKED_GIF);
+ assertAddMergeAttributeUndefined(DISABLE_CHECK_BRANCH,
+ ENABLED_CHECKED_GIF);
+
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+ MergeResult mergeResult = git.merge().include(disableCheckedCommit)
+ .call();
+ assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (no conflict marker added)
+ mergeResultFile = new FileInputStream(
+ db.getWorkTree().toPath().resolve(ENABLED_CHECKED_GIF)
+ .toFile());
+ assertTrue(contentEquals(
+ getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+ mergeResultFile));
+ } finally {
+ if (mergeResultFile != null) {
+ mergeResultFile.close();
+ }
+ }
+ }
+
+ @Test
+ public void mergeBinaryFile_UnsetMerge_Conflict()
+ throws IllegalStateException,
+ IOException, NoHeadException, ConcurrentRefUpdateException,
+ CheckoutConflictException, InvalidMergeHeadsException,
+ WrongRepositoryStateException, NoMessageException, GitAPIException {
+
+ RevCommit disableCheckedCommit;
+ FileInputStream mergeResultFile = null;
+ // Set up a git whith conflict commits on images
+ try (Git git = new Git(db)) {
+ // First commit
+ write(new File(db.getWorkTree(), ".gitattributes"), "*.gif -merge");
+ git.add().addFilepattern(".gitattributes").call();
+ RevCommit firstCommit = git.commit()
+ .setMessage("initial commit adding git attribute file")
+ .call();
+
+ // Create branch and add an icon Checked_Boxe (enabled_checked)
+ createBranch(firstCommit, ENABLE_CHECKED_BRANCH);
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ copy(ENABLED_CHECKED_GIF, ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ git.commit().setMessage("enabled_checked commit").call();
+
+ // Create a second branch from master Unchecked_Boxe
+ checkoutBranch(REFS_HEADS_MASTER);
+ createBranch(firstCommit, DISABLE_CHECK_BRANCH);
+ checkoutBranch(DISABLE_CHECK_BRANCH);
+ copy("disabled_checked.gif", ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ disableCheckedCommit = git.commit()
+ .setMessage("disabled_checked commit").call();
+
+ // Check that the merge attribute is unset
+ assertAddMergeAttributeUnset(ENABLE_CHECKED_BRANCH,
+ ENABLED_CHECKED_GIF);
+ assertAddMergeAttributeUnset(DISABLE_CHECK_BRANCH,
+ ENABLED_CHECKED_GIF);
+
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+ MergeResult mergeResult = git.merge().include(disableCheckedCommit)
+ .call();
+ assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (not conflict marker added)
+ mergeResultFile = new FileInputStream(db.getWorkTree().toPath()
+ .resolve(ENABLED_CHECKED_GIF).toFile());
+ assertTrue(contentEquals(
+ getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+ mergeResultFile));
+ } finally {
+ if (mergeResultFile != null) {
+ mergeResultFile.close();
+ }
+ }
+ }
+
+ @Test
+ public void mergeBinaryFile_SetMerge_Conflict()
+ throws IllegalStateException, IOException, NoHeadException,
+ ConcurrentRefUpdateException, CheckoutConflictException,
+ InvalidMergeHeadsException, WrongRepositoryStateException,
+ NoMessageException, GitAPIException {
+
+ RevCommit disableCheckedCommit;
+ FileInputStream mergeResultFile = null;
+ // Set up a git whith conflict commits on images
+ try (Git git = new Git(db)) {
+ // First commit
+ write(new File(db.getWorkTree(), ".gitattributes"), "*.gif merge");
+ git.add().addFilepattern(".gitattributes").call();
+ RevCommit firstCommit = git.commit()
+ .setMessage("initial commit adding git attribute file")
+ .call();
+
+ // Create branch and add an icon Checked_Boxe (enabled_checked)
+ createBranch(firstCommit, ENABLE_CHECKED_BRANCH);
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ copy(ENABLED_CHECKED_GIF, ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ git.commit().setMessage("enabled_checked commit").call();
+
+ // Create a second branch from master Unchecked_Boxe
+ checkoutBranch(REFS_HEADS_MASTER);
+ createBranch(firstCommit, DISABLE_CHECK_BRANCH);
+ checkoutBranch(DISABLE_CHECK_BRANCH);
+ copy("disabled_checked.gif", ENABLED_CHECKED_GIF, "");
+ git.add().addFilepattern(ENABLED_CHECKED_GIF).call();
+ disableCheckedCommit = git.commit()
+ .setMessage("disabled_checked commit").call();
+
+ // Check that the merge attribute is set
+ assertAddMergeAttributeSet(ENABLE_CHECKED_BRANCH,
+ ENABLED_CHECKED_GIF);
+ assertAddMergeAttributeSet(DISABLE_CHECK_BRANCH,
+ ENABLED_CHECKED_GIF);
+
+ checkoutBranch(ENABLE_CHECKED_BRANCH);
+ // Merge refs/heads/enabled_checked -> refs/heads/disabled_checked
+ MergeResult mergeResult = git.merge().include(disableCheckedCommit)
+ .call();
+ assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus());
+
+ // Check that the image was not modified (not conflict marker added)
+ mergeResultFile = new FileInputStream(db.getWorkTree().toPath()
+ .resolve(ENABLED_CHECKED_GIF).toFile());
+ assertFalse(contentEquals(
+ getClass().getResourceAsStream(ENABLED_CHECKED_GIF),
+ mergeResultFile));
+ } finally {
+ if (mergeResultFile != null) {
+ mergeResultFile.close();
+ }
+ }
+ }
+
+ /*
+ * Copied from org.apache.commons.io.IOUtils
+ */
+ private boolean contentEquals(InputStream input1, InputStream input2)
+ throws IOException {
+ if (input1 == input2) {
+ return true;
+ }
+ if (!(input1 instanceof BufferedInputStream)) {
+ input1 = new BufferedInputStream(input1);
+ }
+ if (!(input2 instanceof BufferedInputStream)) {
+ input2 = new BufferedInputStream(input2);
+ }
+
+ int ch = input1.read();
+ while (-1 != ch) {
+ final int ch2 = input2.read();
+ if (ch != ch2) {
+ return false;
+ }
+ ch = input1.read();
+ }
+
+ final int ch2 = input2.read();
+ return ch2 == -1;
+ }
+
+ private void assertAddMergeAttributeUnset(String branch, String fileName)
+ throws IllegalStateException, IOException {
+ checkoutBranch(branch);
+
+ try (TreeWalk treeWaklEnableChecked = new TreeWalk(db)) {
+ treeWaklEnableChecked.addTree(new FileTreeIterator(db));
+ treeWaklEnableChecked.setFilter(PathFilter.create(fileName));
+
+ assertTrue(treeWaklEnableChecked.next());
+ Attributes attributes = treeWaklEnableChecked.getAttributes();
+ Attribute mergeAttribute = attributes.get("merge");
+ assertNotNull(mergeAttribute);
+ assertEquals(Attribute.State.UNSET, mergeAttribute.getState());
+ }
+ }
+
+ private void assertAddMergeAttributeSet(String branch, String fileName)
+ throws IllegalStateException, IOException {
+ checkoutBranch(branch);
+
+ try (TreeWalk treeWaklEnableChecked = new TreeWalk(db)) {
+ treeWaklEnableChecked.addTree(new FileTreeIterator(db));
+ treeWaklEnableChecked.setFilter(PathFilter.create(fileName));
+
+ assertTrue(treeWaklEnableChecked.next());
+ Attributes attributes = treeWaklEnableChecked.getAttributes();
+ Attribute mergeAttribute = attributes.get("merge");
+ assertNotNull(mergeAttribute);
+ assertEquals(Attribute.State.SET, mergeAttribute.getState());
+ }
+ }
+
+ private void assertAddMergeAttributeUndefined(String branch,
+ String fileName) throws IllegalStateException, IOException {
+ checkoutBranch(branch);
+
+ try (TreeWalk treeWaklEnableChecked = new TreeWalk(db)) {
+ treeWaklEnableChecked.addTree(new FileTreeIterator(db));
+ treeWaklEnableChecked.setFilter(PathFilter.create(fileName));
+
+ assertTrue(treeWaklEnableChecked.next());
+ Attributes attributes = treeWaklEnableChecked.getAttributes();
+ Attribute mergeAttribute = attributes.get("merge");
+ assertNull(mergeAttribute);
+ }
+ }
+
+ private void assertAddMergeAttributeCustom(String branch, String fileName,
+ String value) throws IllegalStateException, IOException {
+ checkoutBranch(branch);
+
+ try (TreeWalk treeWaklEnableChecked = new TreeWalk(db)) {
+ treeWaklEnableChecked.addTree(new FileTreeIterator(db));
+ treeWaklEnableChecked.setFilter(PathFilter.create(fileName));
+
+ assertTrue(treeWaklEnableChecked.next());
+ Attributes attributes = treeWaklEnableChecked.getAttributes();
+ Attribute mergeAttribute = attributes.get("merge");
+ assertNotNull(mergeAttribute);
+ assertEquals(Attribute.State.CUSTOM, mergeAttribute.getState());
+ assertEquals(value, mergeAttribute.getValue());
+ }
+ }
+
+ private void copy(String resourcePath, String resourceNewName,
+ String pathInRepo) throws IOException {
+ InputStream input = getClass().getResourceAsStream(resourcePath);
+ Files.copy(input, db.getWorkTree().toPath().resolve(pathInRepo)
+ .resolve(resourceNewName));
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 24b5ad7..6ed2c21 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -1120,6 +1120,7 @@
testRelative("a/", "a/b", "b");
testRelative("/a/b/c", "/b/c", "../../b/c");
testRelative("/abc", "bcd", "bcd");
+ testRelative("abc", "def", "def");
testRelative("abc", "/bcd", "/bcd");
testRelative("http://a", "a/b", "a/b");
testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
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 1863b80..bcc8f7e 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
@@ -391,7 +391,6 @@
assertMatched("/**/a/b", "c/d/a/b");
assertMatched("/**/**/a/b", "c/d/a/b");
- assertMatched("a/b/**", "a/b");
assertMatched("a/b/**", "a/b/c");
assertMatched("a/b/**", "a/b/c/d/");
assertMatched("a/b/**/**", "a/b/c/d");
@@ -415,6 +414,12 @@
@Test
public void testWildmatchDoNotMatch() {
+ assertNotMatched("a/**", "a/");
+ assertNotMatched("a/b/**", "a/b/");
+ assertNotMatched("a/**", "a");
+ assertNotMatched("a/b/**", "a/b");
+ assertNotMatched("a/b/**/", "a/b");
+ assertNotMatched("a/b/**/**", "a/b");
assertNotMatched("**/a/b", "a/c/b");
assertNotMatched("!/**/*.zip", "c/a/b.zip");
assertNotMatched("!**/*.zip", "c/a/b.zip");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
index 5bef9fa..32d711f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCacheTest.java
@@ -57,13 +57,14 @@
public class DeltaBaseCacheTest {
private static final int SZ = 512;
- private DfsPackKey key;
+ private DfsStreamKey key;
private DeltaBaseCache cache;
private TestRng rng;
@Before
public void setUp() {
- key = new DfsPackKey();
+ DfsRepositoryDescription repo = new DfsRepositoryDescription("test");
+ key = DfsStreamKey.of(repo, "test.key");
cache = new DeltaBaseCache(SZ);
rng = new TestRng(getClass().getSimpleName());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
new file mode 100644
index 0000000..2e3ee45
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.dfs;
+
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jgit.junit.TestRng;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+public class DfsBlockCacheTest {
+ @Rule
+ public TestName testName = new TestName();
+ private TestRng rng;
+ private DfsBlockCache cache;
+
+ @Before
+ public void setUp() {
+ rng = new TestRng(testName.getMethodName());
+ resetCache();
+ }
+
+ @SuppressWarnings("resource")
+ @Test
+ public void streamKeyReusesBlocks() throws Exception {
+ DfsRepositoryDescription repo = new DfsRepositoryDescription("test");
+ InMemoryRepository r1 = new InMemoryRepository(repo);
+ byte[] content = rng.nextBytes(424242);
+ ObjectId id;
+ try (ObjectInserter ins = r1.newObjectInserter()) {
+ id = ins.insert(OBJ_BLOB, content);
+ ins.flush();
+ }
+
+ long oldSize = cache.getCurrentSize();
+ assertTrue(oldSize > 2000);
+ assertEquals(0, cache.getHitCount());
+
+ List<DfsPackDescription> packs = r1.getObjectDatabase().listPacks();
+ InMemoryRepository r2 = new InMemoryRepository(repo);
+ r2.getObjectDatabase().commitPack(packs, Collections.emptyList());
+ try (ObjectReader rdr = r2.newObjectReader()) {
+ byte[] actual = rdr.open(id, OBJ_BLOB).getBytes();
+ assertTrue(Arrays.equals(content, actual));
+ }
+ assertEquals(0, cache.getMissCount());
+ assertEquals(oldSize, cache.getCurrentSize());
+ }
+
+ @SuppressWarnings("resource")
+ @Test
+ public void weirdBlockSize() throws Exception {
+ DfsRepositoryDescription repo = new DfsRepositoryDescription("test");
+ InMemoryRepository r1 = new InMemoryRepository(repo);
+
+ byte[] content1 = rng.nextBytes(4);
+ byte[] content2 = rng.nextBytes(424242);
+ ObjectId id1;
+ ObjectId id2;
+ try (ObjectInserter ins = r1.newObjectInserter()) {
+ id1 = ins.insert(OBJ_BLOB, content1);
+ id2 = ins.insert(OBJ_BLOB, content2);
+ ins.flush();
+ }
+
+ resetCache();
+ List<DfsPackDescription> packs = r1.getObjectDatabase().listPacks();
+
+ InMemoryRepository r2 = new InMemoryRepository(repo);
+ r2.getObjectDatabase().setReadableChannelBlockSizeForTest(500);
+ r2.getObjectDatabase().commitPack(packs, Collections.emptyList());
+ try (ObjectReader rdr = r2.newObjectReader()) {
+ byte[] actual = rdr.open(id1, OBJ_BLOB).getBytes();
+ assertTrue(Arrays.equals(content1, actual));
+ }
+
+ InMemoryRepository r3 = new InMemoryRepository(repo);
+ r3.getObjectDatabase().setReadableChannelBlockSizeForTest(500);
+ r3.getObjectDatabase().commitPack(packs, Collections.emptyList());
+ try (ObjectReader rdr = r3.newObjectReader()) {
+ byte[] actual = rdr.open(id2, OBJ_BLOB).getBytes();
+ assertTrue(Arrays.equals(content2, actual));
+ }
+ }
+
+ private void resetCache() {
+ DfsBlockCache.reconfigure(new DfsBlockCacheConfig()
+ .setBlockSize(512)
+ .setBlockLimit(1 << 20));
+ cache = DfsBlockCache.getInstance();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
new file mode 100644
index 0000000..804d744
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.dfs;
+
+import static org.eclipse.jgit.junit.JGitTestUtil.concat;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.Constants.encodeASCII;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.internal.fsck.FsckError;
+import org.eclipse.jgit.internal.fsck.FsckError.CorruptObject;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectChecker.ErrorType;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DfsFsckTest {
+ private TestRepository<InMemoryRepository> git;
+
+ private InMemoryRepository repo;
+
+ private ObjectInserter ins;
+
+ @Before
+ public void setUp() throws IOException {
+ DfsRepositoryDescription desc = new DfsRepositoryDescription("test");
+ git = new TestRepository<>(new InMemoryRepository(desc));
+ repo = git.getRepository();
+ ins = repo.newObjectInserter();
+ }
+
+ @Test
+ public void testHealthyRepo() throws Exception {
+ RevCommit commit0 = git.commit().message("0").create();
+ RevCommit commit1 = git.commit().message("1").parent(commit0).create();
+ git.update("master", commit1);
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 0);
+ assertEquals(errors.getMissingObjects().size(), 0);
+ assertEquals(errors.getCorruptIndices().size(), 0);
+ }
+
+ @Test
+ public void testCommitWithCorruptAuthor() throws Exception {
+ StringBuilder b = new StringBuilder();
+ b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
+ b.append("author b <b@c> <b@c> 0 +0000\n");
+ b.append("committer <> 0 +0000\n");
+ byte[] data = encodeASCII(b.toString());
+ ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
+ ins.flush();
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 1);
+ CorruptObject o = errors.getCorruptObjects().iterator().next();
+ assertTrue(o.getId().equals(id));
+ assertEquals(o.getErrorType(), ErrorType.BAD_DATE);
+ }
+
+ @Test
+ public void testCommitWithoutTree() throws Exception {
+ StringBuilder b = new StringBuilder();
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+ byte[] data = encodeASCII(b.toString());
+ ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
+ ins.flush();
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 1);
+ CorruptObject o = errors.getCorruptObjects().iterator().next();
+ assertTrue(o.getId().equals(id));
+ assertEquals(o.getErrorType(), ErrorType.MISSING_TREE);
+ }
+
+ @Test
+ public void testTagWithoutObject() throws Exception {
+ StringBuilder b = new StringBuilder();
+ b.append("type commit\n");
+ b.append("tag test-tag\n");
+ b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
+ byte[] data = encodeASCII(b.toString());
+ ObjectId id = ins.insert(Constants.OBJ_TAG, data);
+ ins.flush();
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 1);
+ CorruptObject o = errors.getCorruptObjects().iterator().next();
+ assertTrue(o.getId().equals(id));
+ assertEquals(o.getErrorType(), ErrorType.MISSING_OBJECT);
+ }
+
+ @Test
+ public void testTreeWithNullSha() throws Exception {
+ byte[] data = concat(encodeASCII("100644 A"), new byte[] { '\0' },
+ new byte[OBJECT_ID_LENGTH]);
+ ObjectId id = ins.insert(Constants.OBJ_TREE, data);
+ ins.flush();
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 1);
+ CorruptObject o = errors.getCorruptObjects().iterator().next();
+ assertTrue(o.getId().equals(id));
+ assertEquals(o.getErrorType(), ErrorType.NULL_SHA1);
+ }
+
+ @Test
+ public void testMultipleInvalidObjects() throws Exception {
+ StringBuilder b = new StringBuilder();
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+ b.append("parent ");
+ b.append("\n");
+ byte[] data = encodeASCII(b.toString());
+ ObjectId id1 = ins.insert(Constants.OBJ_COMMIT, data);
+
+ b = new StringBuilder();
+ b.append("100644");
+ data = encodeASCII(b.toString());
+ ObjectId id2 = ins.insert(Constants.OBJ_TREE, data);
+
+ ins.flush();
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+
+ assertEquals(errors.getCorruptObjects().size(), 2);
+ for (CorruptObject o : errors.getCorruptObjects()) {
+ if (o.getId().equals(id1)) {
+ assertEquals(o.getErrorType(), ErrorType.BAD_PARENT_SHA1);
+ } else if (o.getId().equals(id2)) {
+ assertNull(o.getErrorType());
+ } else {
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void testValidConnectivity() throws Exception {
+ ObjectId blobId = ins
+ .insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+
+ byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
+ blobId.copyRawTo(blobIdBytes, 0);
+ byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
+ ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
+ ins.flush();
+
+ RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
+ .create();
+
+ git.update("master", commit);
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+ assertEquals(errors.getMissingObjects().size(), 0);
+ }
+
+ @Test
+ public void testMissingObject() throws Exception {
+ ObjectId blobId = ObjectId
+ .fromString("19102815663d23f8b75a47e7a01965dcdc96468c");
+ byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
+ blobId.copyRawTo(blobIdBytes, 0);
+ byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
+ ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
+ ins.flush();
+
+ RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
+ .create();
+
+ git.update("master", commit);
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+ assertEquals(errors.getMissingObjects().size(), 1);
+ assertEquals(errors.getMissingObjects().iterator().next(), blobId);
+ }
+
+ @Test
+ public void testNonCommitHead() throws Exception {
+ RevCommit commit0 = git.commit().message("0").create();
+ StringBuilder b = new StringBuilder();
+ b.append("object ");
+ b.append(commit0.getName());
+ b.append('\n');
+ b.append("type commit\n");
+ b.append("tag test-tag\n");
+ b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
+
+ byte[] data = encodeASCII(b.toString());
+ ObjectId tagId = ins.insert(Constants.OBJ_TAG, data);
+ ins.flush();
+
+ git.update("master", tagId);
+
+ DfsFsck fsck = new DfsFsck(repo);
+ FsckError errors = fsck.check(null);
+ assertEquals(errors.getCorruptObjects().size(), 0);
+ assertEquals(errors.getNonCommitHeads().size(), 1);
+ assertEquals(errors.getNonCommitHeads().iterator().next(),
+ "refs/heads/master");
+ }
+
+}
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
index 32002fd..e4dcc2e 100644
--- 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
@@ -31,6 +31,7 @@
import org.junit.Before;
import org.junit.Test;
+/** Tests for pack creation and garbage expiration. */
public class DfsGarbageCollectorTest {
private TestRepository<InMemoryRepository> git;
private InMemoryRepository repo;
@@ -632,6 +633,26 @@
}
}
+ @Test
+ public void testSinglePackForAllRefs() throws Exception {
+ RevCommit commit0 = commit().message("0").create();
+ git.update("head", commit0);
+ RevCommit commit1 = commit().message("1").parent(commit0).create();
+ git.update("refs/notes/note1", commit1);
+
+ DfsGarbageCollector gc = new DfsGarbageCollector(repo);
+ gc.setGarbageTtl(0, TimeUnit.MILLISECONDS);
+ gc.getPackConfig().setSinglePack(true);
+ run(gc);
+ assertEquals(1, odb.getPacks().length);
+
+ gc = new DfsGarbageCollector(repo);
+ gc.setGarbageTtl(0, TimeUnit.MILLISECONDS);
+ gc.getPackConfig().setSinglePack(false);
+ run(gc);
+ assertEquals(2, odb.getPacks().length);
+ }
+
private TestRepository<InMemoryRepository>.CommitBuilder commit() {
return git.commit();
}
@@ -674,7 +695,7 @@
private boolean isObjectInPack(AnyObjectId id, DfsPackFile pack)
throws IOException {
- try (DfsReader reader = new DfsReader(odb)) {
+ try (DfsReader reader = odb.newReader()) {
return pack.hasObject(reader, id);
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
new file mode 100644
index 0000000..34f6c71
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
@@ -0,0 +1,915 @@
+/*
+ * Copyright (C) 2017 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.internal.storage.file;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.OK;
+import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.REJECTED_MISSING_OBJECT;
+import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.REJECTED_NONFASTFORWARD;
+import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.TRANSACTION_ABORTED;
+import static org.eclipse.jgit.lib.ObjectId.zeroId;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.CREATE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD;
+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 static org.junit.Assume.assumeTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Predicate;
+
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.junit.StrictWorkMonitor;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.CheckoutEntry;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.lib.ReflogReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@SuppressWarnings("boxing")
+@RunWith(Parameterized.class)
+public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
+ @Parameter
+ public boolean atomic;
+
+ @Parameters(name = "atomic={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{ {Boolean.FALSE}, {Boolean.TRUE} });
+ }
+
+ private Repository diskRepo;
+ private TestRepository<Repository> repo;
+ private RefDirectory refdir;
+ private RevCommit A;
+ private RevCommit B;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ diskRepo = createBareRepository();
+ StoredConfig cfg = diskRepo.getConfig();
+ cfg.load();
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
+ cfg.save();
+
+ refdir = (RefDirectory) diskRepo.getRefDatabase();
+ refdir.setRetrySleepMs(Arrays.asList(0, 0));
+
+ repo = new TestRepository<>(diskRepo);
+ A = repo.commit().create();
+ B = repo.commit(repo.getRevWalk().parseCommit(A));
+ }
+
+ @Test
+ public void simpleNoForce() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+ writeLooseRef("refs/heads/masters", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(B, A, "refs/heads/masters", UPDATE_NONFASTFORWARD));
+ execute(newBatchUpdate(cmds));
+
+ if (atomic) {
+ assertResults(cmds, TRANSACTION_ABORTED, REJECTED_NONFASTFORWARD);
+ assertRefs(
+ "refs/heads/master", A,
+ "refs/heads/masters", B);
+ } else {
+ assertResults(cmds, OK, REJECTED_NONFASTFORWARD);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/masters", B);
+ }
+ }
+
+ @Test
+ public void simpleForce() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+ writeLooseRef("refs/heads/masters", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(B, A, "refs/heads/masters", UPDATE_NONFASTFORWARD));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/masters", A);
+ }
+
+ @Test
+ public void nonFastForwardDoesNotDoExpensiveMergeCheck() throws IOException {
+ writeLooseRef("refs/heads/master", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(B, A, "refs/heads/master", UPDATE_NONFASTFORWARD));
+ try (RevWalk rw = new RevWalk(diskRepo) {
+ @Override
+ public boolean isMergedInto(RevCommit base, RevCommit tip) {
+ throw new AssertionError("isMergedInto() should not be called");
+ }
+ }) {
+ newBatchUpdate(cmds)
+ .setAllowNonFastForwards(true)
+ .execute(rw, new StrictWorkMonitor());
+ }
+
+ assertResults(cmds, OK);
+ assertRefs("refs/heads/master", A);
+ }
+
+ @Test
+ public void fileDirectoryConflict() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+ writeLooseRef("refs/heads/masters", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), A, "refs/heads/master/x", CREATE),
+ new ReceiveCommand(zeroId(), A, "refs/heads", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false);
+
+ if (atomic) {
+ // Atomic update sees that master and master/x are conflicting, then marks
+ // the first one in the list as LOCK_FAILURE and aborts the rest.
+ assertResults(cmds,
+ LOCK_FAILURE, TRANSACTION_ABORTED, TRANSACTION_ABORTED);
+ assertRefs(
+ "refs/heads/master", A,
+ "refs/heads/masters", B);
+ } else {
+ // Non-atomic updates are applied in order: master succeeds, then master/x
+ // fails due to conflict.
+ assertResults(cmds, OK, LOCK_FAILURE, LOCK_FAILURE);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/masters", B);
+ }
+ }
+
+ @Test
+ public void conflictThanksToDelete() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+ writeLooseRef("refs/heads/masters", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), A, "refs/heads/masters/x", CREATE),
+ new ReceiveCommand(B, zeroId(), "refs/heads/masters", DELETE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertResults(cmds, OK, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/masters/x", A);
+ }
+
+ @Test
+ public void updateToMissingObject() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+
+ ObjectId bad =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, bad, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false);
+
+ if (atomic) {
+ assertResults(cmds, REJECTED_MISSING_OBJECT, TRANSACTION_ABORTED);
+ assertRefs("refs/heads/master", A);
+ } else {
+ assertResults(cmds, REJECTED_MISSING_OBJECT, OK);
+ assertRefs(
+ "refs/heads/master", A,
+ "refs/heads/foo2", B);
+ }
+ }
+
+ @Test
+ public void addMissingObject() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+
+ ObjectId bad =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), bad, "refs/heads/foo2", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false);
+
+ if (atomic) {
+ assertResults(cmds, TRANSACTION_ABORTED, REJECTED_MISSING_OBJECT);
+ assertRefs("refs/heads/master", A);
+ } else {
+ assertResults(cmds, OK, REJECTED_MISSING_OBJECT);
+ assertRefs("refs/heads/master", B);
+ }
+ }
+
+ @Test
+ public void oneNonExistentRef() throws IOException {
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/foo1", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ if (atomic) {
+ assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
+ assertRefs();
+ } else {
+ assertResults(cmds, LOCK_FAILURE, OK);
+ assertRefs("refs/heads/foo2", B);
+ }
+ }
+
+ @Test
+ public void oneRefWrongOldValue() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(B, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ if (atomic) {
+ assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
+ assertRefs("refs/heads/master", A);
+ } else {
+ assertResults(cmds, LOCK_FAILURE, OK);
+ assertRefs(
+ "refs/heads/master", A,
+ "refs/heads/foo2", B);
+ }
+ }
+
+ @Test
+ public void nonExistentRef() throws IOException {
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(A, zeroId(), "refs/heads/foo2", DELETE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ if (atomic) {
+ assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
+ assertRefs("refs/heads/master", A);
+ } else {
+ assertResults(cmds, OK, LOCK_FAILURE);
+ assertRefs("refs/heads/master", B);
+ }
+ }
+
+ @Test
+ public void noRefLog() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ Map<String, ReflogEntry> oldLogs =
+ getLastReflogs("refs/heads/master", "refs/heads/branch");
+ assertEquals(Collections.singleton("refs/heads/master"), oldLogs.keySet());
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch", B);
+ assertReflogUnchanged(oldLogs, "refs/heads/master");
+ assertReflogUnchanged(oldLogs, "refs/heads/branch");
+ }
+
+ @Test
+ public void reflogDefaultIdent() throws IOException {
+ writeRef("refs/heads/master", A);
+ writeRef("refs/heads/branch2", A);
+
+ Map<String, ReflogEntry> oldLogs = getLastReflogs(
+ "refs/heads/master", "refs/heads/branch1", "refs/heads/branch2");
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch1", CREATE));
+ execute(
+ newBatchUpdate(cmds)
+ .setAllowNonFastForwards(true)
+ .setRefLogMessage("a reflog", false));
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch1", B,
+ "refs/heads/branch2", A);
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/branch1"));
+ assertReflogUnchanged(oldLogs, "refs/heads/branch2");
+ }
+
+ @Test
+ public void reflogAppendStatusNoMessage() throws IOException {
+ writeRef("refs/heads/master", A);
+ writeRef("refs/heads/branch1", B);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(B, A, "refs/heads/branch1", UPDATE_NONFASTFORWARD),
+ new ReceiveCommand(zeroId(), A, "refs/heads/branch2", CREATE));
+ execute(
+ newBatchUpdate(cmds)
+ .setAllowNonFastForwards(true)
+ .setRefLogMessage(null, true));
+
+ assertResults(cmds, OK, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch1", A,
+ "refs/heads/branch2", A);
+ assertReflogEquals(
+ // Always forced; setAllowNonFastForwards(true) bypasses the check.
+ reflog(A, B, new PersonIdent(diskRepo), "forced-update"),
+ getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(B, A, new PersonIdent(diskRepo), "forced-update"),
+ getLastReflog("refs/heads/branch1"));
+ assertReflogEquals(
+ reflog(zeroId(), A, new PersonIdent(diskRepo), "created"),
+ getLastReflog("refs/heads/branch2"));
+ }
+
+ @Test
+ public void reflogAppendStatusFastForward() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage(null, true));
+
+ assertResults(cmds, OK);
+ assertRefs("refs/heads/master", B);
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "fast-forward"),
+ getLastReflog("refs/heads/master"));
+ }
+
+ @Test
+ public void reflogAppendStatusWithMessage() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), A, "refs/heads/branch", CREATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true));
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch", A);
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "a reflog: fast-forward"),
+ getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(zeroId(), A, new PersonIdent(diskRepo), "a reflog: created"),
+ getLastReflog("refs/heads/branch"));
+ }
+
+ @Test
+ public void reflogCustomIdent() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ PersonIdent ident = new PersonIdent("A Reflog User", "reflog@example.com");
+ execute(
+ newBatchUpdate(cmds)
+ .setRefLogMessage("a reflog", false)
+ .setRefLogIdent(ident));
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch", B);
+ assertReflogEquals(
+ reflog(A, B, ident, "a reflog"),
+ getLastReflog("refs/heads/master"),
+ true);
+ assertReflogEquals(
+ reflog(zeroId(), B, ident, "a reflog"),
+ getLastReflog("refs/heads/branch"),
+ true);
+ }
+
+ @Test
+ public void reflogDelete() throws IOException {
+ writeRef("refs/heads/master", A);
+ writeRef("refs/heads/branch", A);
+ assertEquals(
+ 2, getLastReflogs("refs/heads/master", "refs/heads/branch").size());
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, zeroId(), "refs/heads/master", DELETE),
+ new ReceiveCommand(A, B, "refs/heads/branch", UPDATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+ assertResults(cmds, OK, OK);
+ assertRefs("refs/heads/branch", B);
+ assertNull(getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/branch"));
+ }
+
+ @Test
+ public void reflogFileDirectoryConflict() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, zeroId(), "refs/heads/master", DELETE),
+ new ReceiveCommand(zeroId(), A, "refs/heads/master/x", CREATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+ assertResults(cmds, OK, OK);
+ assertRefs("refs/heads/master/x", A);
+ assertNull(getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(zeroId(), A, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/master/x"));
+ }
+
+ @Test
+ public void reflogOnLockFailure() throws IOException {
+ writeRef("refs/heads/master", A);
+
+ Map<String, ReflogEntry> oldLogs =
+ getLastReflogs("refs/heads/master", "refs/heads/branch");
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(A, B, "refs/heads/branch", UPDATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+ if (atomic) {
+ assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
+ assertReflogUnchanged(oldLogs, "refs/heads/master");
+ assertReflogUnchanged(oldLogs, "refs/heads/branch");
+ } else {
+ assertResults(cmds, OK, LOCK_FAILURE);
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/master"));
+ assertReflogUnchanged(oldLogs, "refs/heads/branch");
+ }
+ }
+
+ @Test
+ public void overrideRefLogMessage() throws Exception {
+ writeRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ cmds.get(0).setRefLogMessage("custom log", false);
+ PersonIdent ident = new PersonIdent(diskRepo);
+ execute(
+ newBatchUpdate(cmds)
+ .setRefLogIdent(ident)
+ .setRefLogMessage("a reflog", true));
+
+ assertResults(cmds, OK, OK);
+ assertReflogEquals(
+ reflog(A, B, ident, "custom log"),
+ getLastReflog("refs/heads/master"),
+ true);
+ assertReflogEquals(
+ reflog(zeroId(), B, ident, "a reflog: created"),
+ getLastReflog("refs/heads/branch"),
+ true);
+ }
+
+ @Test
+ public void overrideDisableRefLog() throws Exception {
+ writeRef("refs/heads/master", A);
+
+ Map<String, ReflogEntry> oldLogs =
+ getLastReflogs("refs/heads/master", "refs/heads/branch");
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ cmds.get(0).disableRefLog();
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true));
+
+ assertResults(cmds, OK, OK);
+ assertReflogUnchanged(oldLogs, "refs/heads/master");
+ assertReflogEquals(
+ reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog: created"),
+ getLastReflog("refs/heads/branch"));
+ }
+
+ @Test
+ public void packedRefsLockFailure() throws Exception {
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+
+ LockFile myLock = refdir.lockPackedRefs();
+ try {
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertFalse(getLockFile("refs/heads/master").exists());
+ assertFalse(getLockFile("refs/heads/branch").exists());
+
+ if (atomic) {
+ assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
+ assertRefs("refs/heads/master", A);
+ } else {
+ // Only operates on loose refs, doesn't care that packed-refs is locked.
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch", B);
+ }
+ } finally {
+ myLock.unlock();
+ }
+ }
+
+ @Test
+ public void oneRefLockFailure() throws Exception {
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE),
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE));
+
+ LockFile myLock = new LockFile(refdir.fileFor("refs/heads/master"));
+ assertTrue(myLock.lock());
+ try {
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertFalse(LockFile.getLockFile(refdir.packedRefsFile).exists());
+ assertFalse(getLockFile("refs/heads/branch").exists());
+
+ if (atomic) {
+ assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
+ assertRefs("refs/heads/master", A);
+ } else {
+ assertResults(cmds, OK, LOCK_FAILURE);
+ assertRefs(
+ "refs/heads/branch", B,
+ "refs/heads/master", A);
+ }
+ } finally {
+ myLock.unlock();
+ }
+ }
+
+ @Test
+ public void singleRefUpdateDoesNotRequirePackedRefsLock() throws Exception {
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE));
+
+ LockFile myLock = refdir.lockPackedRefs();
+ try {
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+
+ assertFalse(getLockFile("refs/heads/master").exists());
+ assertResults(cmds, OK);
+ assertRefs("refs/heads/master", B);
+ } finally {
+ myLock.unlock();
+ }
+ }
+
+ @Test
+ public void atomicUpdateRespectsInProcessLock() throws Exception {
+ assumeTrue(atomic);
+
+ writeLooseRef("refs/heads/master", A);
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+
+ Thread t = new Thread(() -> {
+ try {
+ execute(newBatchUpdate(cmds).setAllowNonFastForwards(true));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ ReentrantLock l = refdir.inProcessPackedRefsLock;
+ l.lock();
+ try {
+ t.start();
+ long timeoutSecs = 10;
+ long startNanos = System.nanoTime();
+
+ // Hold onto the lock until we observe the worker thread has attempted to
+ // acquire it.
+ while (l.getQueueLength() == 0) {
+ long elapsedNanos = System.nanoTime() - startNanos;
+ assertTrue(
+ "timed out waiting for work thread to attempt to acquire lock",
+ NANOSECONDS.toSeconds(elapsedNanos) < timeoutSecs);
+ Thread.sleep(3);
+ }
+
+ // Once we unlock, the worker thread should finish the update promptly.
+ l.unlock();
+ t.join(SECONDS.toMillis(timeoutSecs));
+ assertFalse(t.isAlive());
+ } finally {
+ if (l.isHeldByCurrentThread()) {
+ l.unlock();
+ }
+ }
+
+ assertResults(cmds, OK, OK);
+ assertRefs(
+ "refs/heads/master", B,
+ "refs/heads/branch", B);
+ }
+
+ private void writeLooseRef(String name, AnyObjectId id) throws IOException {
+ write(new File(diskRepo.getDirectory(), name), id.name() + "\n");
+ }
+
+ private void writeRef(String name, AnyObjectId id) throws IOException {
+ RefUpdate u = diskRepo.updateRef(name);
+ u.setRefLogMessage(getClass().getSimpleName(), false);
+ u.setForceUpdate(true);
+ u.setNewObjectId(id);
+ RefUpdate.Result r = u.update();
+ switch (r) {
+ case NEW:
+ case FORCED:
+ return;
+ default:
+ throw new IOException("Got " + r + " while updating " + name);
+ }
+ }
+
+ private BatchRefUpdate newBatchUpdate(List<ReceiveCommand> cmds) {
+ BatchRefUpdate u = refdir.newBatchUpdate();
+ if (atomic) {
+ assertTrue(u.isAtomic());
+ } else {
+ u.setAtomic(false);
+ }
+ u.addCommand(cmds);
+ return u;
+ }
+
+ private void execute(BatchRefUpdate u) throws IOException {
+ execute(u, false);
+ }
+
+ private void execute(BatchRefUpdate u, boolean strictWork) throws IOException {
+ try (RevWalk rw = new RevWalk(diskRepo)) {
+ u.execute(rw,
+ strictWork ? new StrictWorkMonitor() : NullProgressMonitor.INSTANCE);
+ }
+ }
+
+ private void assertRefs(Object... args) throws IOException {
+ if (args.length % 2 != 0) {
+ throw new IllegalArgumentException(
+ "expected even number of args: " + Arrays.toString(args));
+ }
+
+ Map<String, AnyObjectId> expected = new LinkedHashMap<>();
+ for (int i = 0; i < args.length; i += 2) {
+ expected.put((String) args[i], (AnyObjectId) args[i + 1]);
+ }
+
+ Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
+ Ref actualHead = refs.remove(Constants.HEAD);
+ if (actualHead != null) {
+ String actualLeafName = actualHead.getLeaf().getName();
+ assertEquals(
+ "expected HEAD to point to refs/heads/master, got: " + actualLeafName,
+ "refs/heads/master", actualLeafName);
+ AnyObjectId expectedMaster = expected.get("refs/heads/master");
+ assertNotNull("expected master ref since HEAD exists", expectedMaster);
+ assertEquals(expectedMaster, actualHead.getObjectId());
+ }
+
+ Map<String, AnyObjectId> actual = new LinkedHashMap<>();
+ refs.forEach((n, r) -> actual.put(n, r.getObjectId()));
+
+ assertEquals(expected.keySet(), actual.keySet());
+ actual.forEach((n, a) -> assertEquals(n, expected.get(n), a));
+ }
+
+ enum Result {
+ OK(ReceiveCommand.Result.OK),
+ LOCK_FAILURE(ReceiveCommand.Result.LOCK_FAILURE),
+ REJECTED_NONFASTFORWARD(ReceiveCommand.Result.REJECTED_NONFASTFORWARD),
+ REJECTED_MISSING_OBJECT(ReceiveCommand.Result.REJECTED_MISSING_OBJECT),
+ TRANSACTION_ABORTED(ReceiveCommand::isTransactionAborted);
+
+ final Predicate<? super ReceiveCommand> p;
+
+ private Result(Predicate<? super ReceiveCommand> p) {
+ this.p = p;
+ }
+
+ private Result(ReceiveCommand.Result result) {
+ this(c -> c.getResult() == result);
+ }
+ }
+
+ private void assertResults(
+ List<ReceiveCommand> cmds, Result... expected) {
+ if (expected.length != cmds.size()) {
+ throw new IllegalArgumentException(
+ "expected " + cmds.size() + " result args");
+ }
+ for (int i = 0; i < cmds.size(); i++) {
+ ReceiveCommand c = cmds.get(i);
+ Result r = expected[i];
+ assertTrue(
+ String.format(
+ "result of command (%d) should be %s: %s %s%s",
+ Integer.valueOf(i), r, c,
+ c.getResult(),
+ c.getMessage() != null ? " (" + c.getMessage() + ")" : ""),
+ r.p.test(c));
+ }
+ }
+
+ private Map<String, ReflogEntry> getLastReflogs(String... names)
+ throws IOException {
+ Map<String, ReflogEntry> result = new LinkedHashMap<>();
+ for (String name : names) {
+ ReflogEntry e = getLastReflog(name);
+ if (e != null) {
+ result.put(name, e);
+ }
+ }
+ return result;
+ }
+
+ private ReflogEntry getLastReflog(String name) throws IOException {
+ ReflogReader r = diskRepo.getReflogReader(name);
+ if (r == null) {
+ return null;
+ }
+ return r.getLastEntry();
+ }
+
+ private File getLockFile(String refName) {
+ return LockFile.getLockFile(refdir.fileFor(refName));
+ }
+
+ private void assertReflogUnchanged(
+ Map<String, ReflogEntry> old, String name) throws IOException {
+ assertReflogEquals(old.get(name), getLastReflog(name), true);
+ }
+
+ private static void assertReflogEquals(
+ ReflogEntry expected, ReflogEntry actual) {
+ assertReflogEquals(expected, actual, false);
+ }
+
+ private static void assertReflogEquals(
+ ReflogEntry expected, ReflogEntry actual, boolean strictTime) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ assertEquals(expected.getOldId(), actual.getOldId());
+ assertEquals(expected.getNewId(), actual.getNewId());
+ if (strictTime) {
+ assertEquals(expected.getWho(), actual.getWho());
+ } else {
+ assertEquals(expected.getWho().getName(), actual.getWho().getName());
+ assertEquals(
+ expected.getWho().getEmailAddress(),
+ actual.getWho().getEmailAddress());
+ }
+ assertEquals(expected.getComment(), actual.getComment());
+ }
+
+ private static ReflogEntry reflog(ObjectId oldId, ObjectId newId,
+ PersonIdent who, String comment) {
+ return new ReflogEntry() {
+ @Override
+ public ObjectId getOldId() {
+ return oldId;
+ }
+
+ @Override
+ public ObjectId getNewId() {
+ return newId;
+ }
+
+ @Override
+ public PersonIdent getWho() {
+ return who;
+ }
+
+ @Override
+ public String getComment() {
+ return comment;
+ }
+
+ @Override
+ public CheckoutEntry parseCheckout() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
index 11a2a22..c43bdbd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
@@ -43,12 +43,13 @@
package org.eclipse.jgit.internal.storage.file;
-import static java.lang.Integer.valueOf;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
@@ -74,6 +75,7 @@
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test;
+@SuppressWarnings("boxing")
public class GcPackRefsTest extends GcTestCase {
@Test
public void looseRefPacked() throws Exception {
@@ -100,27 +102,23 @@
RevBlob a = tr.blob("a");
tr.lightweightTag("t", a);
- final CyclicBarrier syncPoint = new CyclicBarrier(2);
+ CyclicBarrier syncPoint = new CyclicBarrier(2);
- Callable<Integer> packRefs = new Callable<Integer>() {
-
- /** @return 0 for success, 1 in case of error when writing pack */
- @Override
- public Integer call() throws Exception {
- syncPoint.await();
- try {
- gc.packRefs();
- return valueOf(0);
- } catch (IOException e) {
- return valueOf(1);
- }
+ // Returns 0 for success, 1 in case of error when writing pack.
+ Callable<Integer> packRefs = () -> {
+ syncPoint.await();
+ try {
+ gc.packRefs();
+ return 0;
+ } catch (IOException e) {
+ return 1;
}
};
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
Future<Integer> p1 = pool.submit(packRefs);
Future<Integer> p2 = pool.submit(packRefs);
- assertEquals(1, p1.get().intValue() + p2.get().intValue());
+ assertThat(p1.get() + p2.get(), lessThanOrEqualTo(1));
} finally {
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
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 c817dc3..9b97eb4 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
@@ -711,7 +711,7 @@
}
ObjectWalk ow = walk.toObjectWalkWithSameObjects();
- pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have);
+ pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have, NONE);
String id = pw.computeName().getName();
File packdir = new File(repo.getObjectsDirectory(), "pack");
File packFile = new File(packdir, "pack-" + id + ".pack");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index 53db123..fefccf3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -61,32 +61,27 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.events.RefsChangedListener;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.BatchRefUpdate;
-import org.eclipse.jgit.lib.NullProgressMonitor;
-import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.transport.ReceiveCommand;
-import org.eclipse.jgit.transport.ReceiveCommand.Type;
import org.junit.Before;
import org.junit.Test;
+@SuppressWarnings("boxing")
public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
private Repository diskRepo;
@@ -1293,125 +1288,20 @@
}
@Test
- public void testBatchRefUpdateSimpleNoForce() throws IOException {
+ public void testPackedRefsLockFailure() throws Exception {
writeLooseRef("refs/heads/master", A);
- writeLooseRef("refs/heads/masters", B);
- List<ReceiveCommand> commands = Arrays.asList(
- newCommand(A, B, "refs/heads/master",
- ReceiveCommand.Type.UPDATE),
- newCommand(B, A, "refs/heads/masters",
- ReceiveCommand.Type.UPDATE_NONFASTFORWARD));
- BatchRefUpdate batchUpdate = refdir.newBatchUpdate();
- batchUpdate.addCommand(commands);
- batchUpdate.execute(new RevWalk(diskRepo), new StrictWorkMonitor());
- Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
- assertEquals(ReceiveCommand.Result.OK, commands.get(0).getResult());
- assertEquals(ReceiveCommand.Result.REJECTED_NONFASTFORWARD, commands
- .get(1).getResult());
- assertEquals("[HEAD, refs/heads/master, refs/heads/masters]", refs
- .keySet().toString());
- assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId());
- assertEquals(B.getId(), refs.get("refs/heads/masters").getObjectId());
- }
-
- @Test
- public void testBatchRefUpdateSimpleForce() throws IOException {
- writeLooseRef("refs/heads/master", A);
- writeLooseRef("refs/heads/masters", B);
- List<ReceiveCommand> commands = Arrays.asList(
- newCommand(A, B, "refs/heads/master",
- ReceiveCommand.Type.UPDATE),
- newCommand(B, A, "refs/heads/masters",
- ReceiveCommand.Type.UPDATE_NONFASTFORWARD));
- BatchRefUpdate batchUpdate = refdir.newBatchUpdate();
- batchUpdate.setAllowNonFastForwards(true);
- batchUpdate.addCommand(commands);
- batchUpdate.execute(new RevWalk(diskRepo), new StrictWorkMonitor());
- Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
- assertEquals(ReceiveCommand.Result.OK, commands.get(0).getResult());
- assertEquals(ReceiveCommand.Result.OK, commands.get(1).getResult());
- assertEquals("[HEAD, refs/heads/master, refs/heads/masters]", refs
- .keySet().toString());
- assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId());
- assertEquals(A.getId(), refs.get("refs/heads/masters").getObjectId());
- }
-
- @Test
- public void testBatchRefUpdateNonFastForwardDoesNotDoExpensiveMergeCheck()
- throws IOException {
- writeLooseRef("refs/heads/master", B);
- List<ReceiveCommand> commands = Arrays.asList(
- newCommand(B, A, "refs/heads/master",
- ReceiveCommand.Type.UPDATE_NONFASTFORWARD));
- BatchRefUpdate batchUpdate = refdir.newBatchUpdate();
- batchUpdate.setAllowNonFastForwards(true);
- batchUpdate.addCommand(commands);
- batchUpdate.execute(new RevWalk(diskRepo) {
- @Override
- public boolean isMergedInto(RevCommit base, RevCommit tip) {
- throw new AssertionError("isMergedInto() should not be called");
- }
- }, new StrictWorkMonitor());
- Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
- assertEquals(ReceiveCommand.Result.OK, commands.get(0).getResult());
- assertEquals(A.getId(), refs.get("refs/heads/master").getObjectId());
- }
-
- @Test
- public void testBatchRefUpdateConflict() throws IOException {
- writeLooseRef("refs/heads/master", A);
- writeLooseRef("refs/heads/masters", B);
- List<ReceiveCommand> commands = Arrays.asList(
- newCommand(A, B, "refs/heads/master",
- ReceiveCommand.Type.UPDATE),
- newCommand(null, A, "refs/heads/master/x",
- ReceiveCommand.Type.CREATE),
- newCommand(null, A, "refs/heads", ReceiveCommand.Type.CREATE));
- BatchRefUpdate batchUpdate = refdir.newBatchUpdate();
- batchUpdate.setAllowNonFastForwards(true);
- batchUpdate.addCommand(commands);
- batchUpdate
- .execute(new RevWalk(diskRepo), NullProgressMonitor.INSTANCE);
- Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
- assertEquals(ReceiveCommand.Result.OK, commands.get(0).getResult());
- assertEquals(ReceiveCommand.Result.LOCK_FAILURE, commands.get(1)
- .getResult());
- assertEquals(ReceiveCommand.Result.LOCK_FAILURE, commands.get(2)
- .getResult());
- assertEquals("[HEAD, refs/heads/master, refs/heads/masters]", refs
- .keySet().toString());
- assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId());
- assertEquals(B.getId(), refs.get("refs/heads/masters").getObjectId());
- }
-
- @Test
- public void testBatchRefUpdateConflictThanksToDelete() throws IOException {
- writeLooseRef("refs/heads/master", A);
- writeLooseRef("refs/heads/masters", B);
- List<ReceiveCommand> commands = Arrays.asList(
- newCommand(A, B, "refs/heads/master",
- ReceiveCommand.Type.UPDATE),
- newCommand(null, A, "refs/heads/masters/x",
- ReceiveCommand.Type.CREATE),
- newCommand(B, null, "refs/heads/masters",
- ReceiveCommand.Type.DELETE));
- BatchRefUpdate batchUpdate = refdir.newBatchUpdate();
- batchUpdate.setAllowNonFastForwards(true);
- batchUpdate.addCommand(commands);
- batchUpdate.execute(new RevWalk(diskRepo), new StrictWorkMonitor());
- Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL);
- assertEquals(ReceiveCommand.Result.OK, commands.get(0).getResult());
- assertEquals(ReceiveCommand.Result.OK, commands.get(1).getResult());
- assertEquals(ReceiveCommand.Result.OK, commands.get(2).getResult());
- assertEquals("[HEAD, refs/heads/master, refs/heads/masters/x]", refs
- .keySet().toString());
- assertEquals(A.getId(), refs.get("refs/heads/masters/x").getObjectId());
- }
-
- private static ReceiveCommand newCommand(RevCommit a, RevCommit b,
- String string, Type update) {
- return new ReceiveCommand(a != null ? a.getId() : null,
- b != null ? b.getId() : null, string, update);
+ refdir.setRetrySleepMs(Arrays.asList(0, 0));
+ LockFile myLock = refdir.lockPackedRefs();
+ try {
+ refdir.pack(Arrays.asList("refs/heads/master"));
+ fail("expected LockFailedException");
+ } catch (LockFailedException e) {
+ assertEquals(refdir.packedRefsFile.getPath(), e.getFile().getPath());
+ } finally {
+ myLock.unlock();
+ }
+ Ref ref = refdir.getRef("refs/heads/master");
+ assertEquals(Storage.LOOSE, ref.getStorage());
}
private void writeLooseRef(String name, AnyObjectId id) throws IOException {
@@ -1439,34 +1329,4 @@
File path = new File(diskRepo.getDirectory(), name);
assertTrue("deleted " + name, path.delete());
}
-
- private static final class StrictWorkMonitor implements ProgressMonitor {
- private int lastWork, totalWork;
-
- @Override
- public void start(int totalTasks) {
- // empty
- }
-
- @Override
- public void beginTask(String title, int total) {
- this.totalWork = total;
- lastWork = 0;
- }
-
- @Override
- public void update(int completed) {
- lastWork += completed;
- }
-
- @Override
- public void endTask() {
- assertEquals("Units of work recorded", totalWork, lastWork);
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
- }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
index daef91d..34f9eb9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
@@ -45,6 +45,7 @@
package org.eclipse.jgit.internal.storage.file;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -64,6 +65,7 @@
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefRename;
@@ -240,14 +242,73 @@
@Test
public void testDeleteHeadInBareRepo() throws IOException {
Repository bareRepo = createBareRepository();
+ String master = "refs/heads/master";
+ Ref head = bareRepo.exactRef(Constants.HEAD);
+ assertNotNull(head);
+ assertTrue(head.isSymbolic());
+ assertEquals(master, head.getLeaf().getName());
+ assertNull(head.getObjectId());
+ assertNull(bareRepo.exactRef(master));
+
+ ObjectId blobId;
+ try (ObjectInserter ins = bareRepo.newObjectInserter()) {
+ blobId = ins.insert(Constants.OBJ_BLOB, "contents".getBytes(UTF_8));
+ ins.flush();
+ }
+
+ // Create master via HEAD, so we delete it.
RefUpdate ref = bareRepo.updateRef(Constants.HEAD);
- ref.setNewObjectId(ObjectId
- .fromString("0123456789012345678901234567890123456789"));
- // Create the HEAD ref so we can delete it.
+ ref.setNewObjectId(blobId);
assertEquals(Result.NEW, ref.update());
+
+ head = bareRepo.exactRef(Constants.HEAD);
+ assertTrue(head.isSymbolic());
+ assertEquals(master, head.getLeaf().getName());
+ assertEquals(blobId, head.getLeaf().getObjectId());
+ assertEquals(blobId, bareRepo.exactRef(master).getObjectId());
+
+ // Unlike in a non-bare repo, deleting the HEAD is allowed, and leaves HEAD
+ // back in a dangling state.
ref = bareRepo.updateRef(Constants.HEAD);
- delete(bareRepo, ref, Result.NO_CHANGE, true, true);
+ ref.setExpectedOldObjectId(blobId);
+ ref.setForceUpdate(true);
+ delete(bareRepo, ref, Result.FORCED, true, true);
+
+ head = bareRepo.exactRef(Constants.HEAD);
+ assertNotNull(head);
+ assertTrue(head.isSymbolic());
+ assertEquals(master, head.getLeaf().getName());
+ assertNull(head.getObjectId());
+ assertNull(bareRepo.exactRef(master));
}
+
+ @Test
+ public void testDeleteSymref() throws IOException {
+ RefUpdate dst = updateRef("refs/heads/abc");
+ assertEquals(Result.NEW, dst.update());
+ ObjectId id = dst.getNewObjectId();
+
+ RefUpdate u = db.updateRef("refs/symref");
+ assertEquals(Result.NEW, u.link(dst.getName()));
+
+ Ref ref = db.exactRef(u.getName());
+ assertNotNull(ref);
+ assertTrue(ref.isSymbolic());
+ assertEquals(dst.getName(), ref.getLeaf().getName());
+ assertEquals(id, ref.getLeaf().getObjectId());
+
+ u = db.updateRef(u.getName());
+ u.setDetachingSymbolicRef();
+ u.setForceUpdate(true);
+ assertEquals(Result.FORCED, u.delete());
+
+ assertNull(db.exactRef(u.getName()));
+ ref = db.exactRef(dst.getName());
+ assertNotNull(ref);
+ assertFalse(ref.isSymbolic());
+ assertEquals(id, ref.getObjectId());
+ }
+
/**
* Delete a loose ref and make sure the directory in refs is deleted too,
* and the reflog dir too
@@ -898,6 +959,60 @@
"HEAD").getReverseEntries().get(0).getComment());
}
+ @Test
+ public void testCreateMissingObject() throws IOException {
+ String name = "refs/heads/abc";
+ ObjectId bad =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ RefUpdate ru = db.updateRef(name);
+ ru.setNewObjectId(bad);
+ Result update = ru.update();
+ assertEquals(Result.REJECTED_MISSING_OBJECT, update);
+
+ Ref ref = db.exactRef(name);
+ assertNull(ref);
+ }
+
+ @Test
+ public void testUpdateMissingObject() throws IOException {
+ String name = "refs/heads/abc";
+ RefUpdate ru = updateRef(name);
+ Result update = ru.update();
+ assertEquals(Result.NEW, update);
+ ObjectId oldId = ru.getNewObjectId();
+
+ ObjectId bad =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ ru = db.updateRef(name);
+ ru.setNewObjectId(bad);
+ update = ru.update();
+ assertEquals(Result.REJECTED_MISSING_OBJECT, update);
+
+ Ref ref = db.exactRef(name);
+ assertNotNull(ref);
+ assertEquals(oldId, ref.getObjectId());
+ }
+
+ @Test
+ public void testForceUpdateMissingObject() throws IOException {
+ String name = "refs/heads/abc";
+ RefUpdate ru = updateRef(name);
+ Result update = ru.update();
+ assertEquals(Result.NEW, update);
+ ObjectId oldId = ru.getNewObjectId();
+
+ ObjectId bad =
+ ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
+ ru = db.updateRef(name);
+ ru.setNewObjectId(bad);
+ update = ru.forceUpdate();
+ assertEquals(Result.REJECTED_MISSING_OBJECT, update);
+
+ Ref ref = db.exactRef(name);
+ assertNotNull(ref);
+ assertEquals(oldId, ref.getObjectId());
+ }
+
private static void writeReflog(Repository db, ObjectId newId, String msg,
String refName) throws IOException {
RefDirectory refs = (RefDirectory) db.getRefDatabase();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index ae1e531..9d23d83 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -661,33 +661,39 @@
@Test
public void test028_LockPackedRef() throws IOException {
+ ObjectId id1;
+ ObjectId id2;
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ id1 = ins.insert(
+ Constants.OBJ_BLOB, "contents1".getBytes(Constants.CHARSET));
+ id2 = ins.insert(
+ Constants.OBJ_BLOB, "contents2".getBytes(Constants.CHARSET));
+ ins.flush();
+ }
+
writeTrashFile(".git/packed-refs",
- "7f822839a2fe9760f386cbbbcb3f92c5fe81def7 refs/heads/foobar");
+ id1.name() + " refs/heads/foobar");
writeTrashFile(".git/HEAD", "ref: refs/heads/foobar\n");
BUG_WorkAroundRacyGitIssues("packed-refs");
BUG_WorkAroundRacyGitIssues("HEAD");
ObjectId resolve = db.resolve("HEAD");
- assertEquals("7f822839a2fe9760f386cbbbcb3f92c5fe81def7", resolve.name());
+ assertEquals(id1, resolve);
RefUpdate lockRef = db.updateRef("HEAD");
- ObjectId newId = ObjectId
- .fromString("07f822839a2fe9760f386cbbbcb3f92c5fe81def");
- lockRef.setNewObjectId(newId);
+ lockRef.setNewObjectId(id2);
assertEquals(RefUpdate.Result.FORCED, lockRef.forceUpdate());
assertTrue(new File(db.getDirectory(), "refs/heads/foobar").exists());
- assertEquals(newId, db.resolve("refs/heads/foobar"));
+ assertEquals(id2, db.resolve("refs/heads/foobar"));
// Again. The ref already exists
RefUpdate lockRef2 = db.updateRef("HEAD");
- ObjectId newId2 = ObjectId
- .fromString("7f822839a2fe9760f386cbbbcb3f92c5fe81def7");
- lockRef2.setNewObjectId(newId2);
+ lockRef2.setNewObjectId(id1);
assertEquals(RefUpdate.Result.FORCED, lockRef2.forceUpdate());
assertTrue(new File(db.getDirectory(), "refs/heads/foobar").exists());
- assertEquals(newId2, db.resolve("refs/heads/foobar"));
+ assertEquals(id1, db.resolve("refs/heads/foobar"));
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
index 20b8c51..d9b58e2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
@@ -69,6 +69,15 @@
@Test
public void testBitmapSpansNoMerges() throws Exception {
+ testBitmapSpansNoMerges(false);
+ }
+
+ @Test
+ public void testBitmapSpansNoMergesWithTags() throws Exception {
+ testBitmapSpansNoMerges(true);
+ }
+
+ private void testBitmapSpansNoMerges(boolean withTags) throws Exception {
/*
* Commit counts -> expected bitmap counts for history without merges.
* The top 100 contiguous commits should always have bitmaps, and the
@@ -89,7 +98,10 @@
assertTrue(nextCommitCount > currentCommits); // programming error
for (int i = currentCommits; i < nextCommitCount; i++) {
String str = "A" + i;
- bb.commit().message(str).add(str, str).create();
+ RevCommit rc = bb.commit().message(str).add(str, str).create();
+ if (withTags) {
+ tr.lightweightTag(str, rc);
+ }
}
currentCommits = nextCommitCount;
@@ -233,7 +245,7 @@
m8, m9);
PackWriterBitmapPreparer preparer = newPeparer(m9, commits);
List<BitmapCommit> selection = new ArrayList<>(
- preparer.selectCommits(commits.size()));
+ preparer.selectCommits(commits.size(), PackWriter.NONE));
// Verify that the output is ordered by the separate "chains"
String[] expected = { m0.name(), m1.name(), m2.name(), m4.name(),
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java
index 6529d9e..30a9626 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java
@@ -86,7 +86,6 @@
final ObjectId f = i.toObjectId();
assertNotNull(f);
assertEquals(ObjectId.fromString(s), f);
- assertEquals(f.hashCode(), i.hashCode());
}
@Test
@@ -101,7 +100,6 @@
final ObjectId f = i.toObjectId();
assertNotNull(f);
assertEquals(ObjectId.fromString(s), f);
- assertEquals(f.hashCode(), i.hashCode());
}
@Test
@@ -215,7 +213,7 @@
}
@Test
- public void testEquals_Short() {
+ public void testEquals_Short8() {
final String s = "7b6e8067";
final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
@@ -226,6 +224,18 @@
}
@Test
+ public void testEquals_Short4() {
+ final String s = "7b6e";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+ assertNotSame(a, b);
+ assertTrue(a.hashCode() != 0);
+ assertTrue(a.hashCode() == b.hashCode());
+ assertEquals(b, a);
+ assertEquals(a, b);
+ }
+
+ @Test
public void testEquals_Full() {
final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
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 75b574e..f8c2d45 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
@@ -1672,6 +1672,20 @@
}
}
+ @Test
+ public void testLongFilename() throws Exception {
+ char[] bytes = new char[253];
+ Arrays.fill(bytes, 'f');
+ String longFileName = new String(bytes);
+ // 1
+ doit(mkmap(longFileName, "a"), mkmap(longFileName, "b"),
+ mkmap(longFileName, "a"));
+ writeTrashFile(longFileName, "a");
+ checkout();
+ assertNoConflicts();
+ assertUpdated(longFileName);
+ }
+
public void assertWorkDir(Map<String, String> i)
throws CorruptObjectException,
IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index 43160fb..c8729d9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -45,6 +45,7 @@
package org.eclipse.jgit.lib;
import static java.lang.Integer.valueOf;
+import static org.eclipse.jgit.junit.JGitTestUtil.concat;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
@@ -1054,20 +1055,7 @@
checker.checkTree(data);
}
- private static byte[] concat(byte[]... b) {
- int n = 0;
- for (byte[] a : b) {
- n += a.length;
- }
- byte[] data = new byte[n];
- n = 0;
- for (byte[] a : b) {
- System.arraycopy(a, 0, data, n, a.length);
- n += a.length;
- }
- return data;
- }
@Test
public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd()
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
index 7db9f60..15f28af 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
@@ -179,4 +179,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SubmoduleConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SubmoduleConfigTest.java
new file mode 100644
index 0000000..f5b0c5b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/SubmoduleConfigTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017, 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.lib;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
+import org.junit.Test;
+
+public class SubmoduleConfigTest {
+ @Test
+ public void fetchRecurseMatch() throws Exception {
+ assertTrue(FetchRecurseSubmodulesMode.YES.matchConfigValue("yes"));
+ assertTrue(FetchRecurseSubmodulesMode.YES.matchConfigValue("YES"));
+ assertTrue(FetchRecurseSubmodulesMode.YES.matchConfigValue("true"));
+ assertTrue(FetchRecurseSubmodulesMode.YES.matchConfigValue("TRUE"));
+
+ assertTrue(FetchRecurseSubmodulesMode.ON_DEMAND
+ .matchConfigValue("on-demand"));
+ assertTrue(FetchRecurseSubmodulesMode.ON_DEMAND
+ .matchConfigValue("ON-DEMAND"));
+ assertTrue(FetchRecurseSubmodulesMode.ON_DEMAND
+ .matchConfigValue("on_demand"));
+ assertTrue(FetchRecurseSubmodulesMode.ON_DEMAND
+ .matchConfigValue("ON_DEMAND"));
+
+ assertTrue(FetchRecurseSubmodulesMode.NO.matchConfigValue("no"));
+ assertTrue(FetchRecurseSubmodulesMode.NO.matchConfigValue("NO"));
+ assertTrue(FetchRecurseSubmodulesMode.NO.matchConfigValue("false"));
+ assertTrue(FetchRecurseSubmodulesMode.NO.matchConfigValue("FALSE"));
+ }
+
+ @Test
+ public void fetchRecurseNoMatch() throws Exception {
+ assertFalse(FetchRecurseSubmodulesMode.YES.matchConfigValue("Y"));
+ assertFalse(FetchRecurseSubmodulesMode.NO.matchConfigValue("N"));
+ assertFalse(FetchRecurseSubmodulesMode.ON_DEMAND
+ .matchConfigValue("ONDEMAND"));
+ assertFalse(FetchRecurseSubmodulesMode.YES.matchConfigValue(""));
+ assertFalse(FetchRecurseSubmodulesMode.YES.matchConfigValue(null));
+ }
+
+ @Test
+ public void fetchRecurseToConfigValue() {
+ assertEquals("on-demand",
+ FetchRecurseSubmodulesMode.ON_DEMAND.toConfigValue());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
index 2451c50..077645e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
@@ -171,4 +171,4 @@
assertNull(rw.next());
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/SkipRevFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/SkipRevFilterTest.java
index 353a487..cf02aa8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/SkipRevFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/SkipRevFilterTest.java
@@ -81,4 +81,4 @@
public void testSkipRevFilterNegative() throws Exception {
SkipRevFilter.create(-1);
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
index 5c46659..f42dd02 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
@@ -269,4 +269,4 @@
ConfigConstants.CONFIG_KEY_URL));
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
index 61df9d9..5832518 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleStatusTest.java
@@ -59,11 +59,11 @@
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -256,11 +256,16 @@
}
@Test
- public void repositoryWithInitializedSubmodule() throws IOException,
- GitAPIException {
- final ObjectId id = ObjectId
- .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
- final String path = "sub";
+ public void repositoryWithInitializedSubmodule() throws Exception {
+ String path = "sub";
+ Repository subRepo = Git.init().setBare(false)
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository();
+ assertNotNull(subRepo);
+
+ TestRepository<?> subTr = new TestRepository<>(subRepo);
+ ObjectId id = subTr.branch(Constants.HEAD).commit().create().copy();
+
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
@@ -287,15 +292,6 @@
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
- Repository subRepo = Git.init().setBare(false)
- .setDirectory(new File(db.getWorkTree(), path)).call()
- .getRepository();
- assertNotNull(subRepo);
-
- RefUpdate update = subRepo.updateRef(Constants.HEAD, true);
- update.setNewObjectId(id);
- update.forceUpdate();
-
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
assertNotNull(statuses);
@@ -312,11 +308,16 @@
}
@Test
- public void repositoryWithDifferentRevCheckedOutSubmodule()
- throws IOException, GitAPIException {
- final ObjectId id = ObjectId
- .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
- final String path = "sub";
+ public void repositoryWithDifferentRevCheckedOutSubmodule() throws Exception {
+ String path = "sub";
+ Repository subRepo = Git.init().setBare(false)
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository();
+ assertNotNull(subRepo);
+
+ TestRepository<?> subTr = new TestRepository<>(subRepo);
+ ObjectId id = subTr.branch(Constants.HEAD).commit().create().copy();
+
DirCache cache = db.lockDirCache();
DirCacheEditor editor = cache.editor();
editor.add(new PathEdit(path) {
@@ -343,15 +344,7 @@
ConfigConstants.CONFIG_KEY_URL, url);
modulesConfig.save();
- Repository subRepo = Git.init().setBare(false)
- .setDirectory(new File(db.getWorkTree(), path)).call()
- .getRepository();
- assertNotNull(subRepo);
-
- RefUpdate update = subRepo.updateRef(Constants.HEAD, true);
- update.setNewObjectId(ObjectId
- .fromString("aaaa0000aaaa0000aaaa0000aaaa0000aaaa0000"));
- update.forceUpdate();
+ ObjectId newId = subTr.branch(Constants.HEAD).commit().create().copy();
SubmoduleStatusCommand command = new SubmoduleStatusCommand(db);
Map<String, SubmoduleStatus> statuses = command.call();
@@ -365,7 +358,7 @@
assertNotNull(status);
assertEquals(path, status.getPath());
assertEquals(id, status.getIndexId());
- assertEquals(update.getNewObjectId(), status.getHeadId());
+ assertEquals(newId, status.getHeadId());
assertEquals(SubmoduleStatusType.REV_CHECKED_OUT, status.getType());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
index 4061b56..2c8273d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -172,9 +172,18 @@
FS fs = FS.DETECTED.newInstance();
assumeTrue(fs instanceof FS_POSIX);
- String r = FS.readPipe(fs.userHome(),
- new String[] { "bash", "--login", "-c", "foobar" },
+ FS.readPipe(fs.userHome(),
+ new String[] { "/bin/sh", "-c", "exit 1" },
Charset.defaultCharset().name());
- System.out.println(r);
+ }
+
+ @Test(expected = CommandFailedException.class)
+ public void testReadPipeCommandStartFailure()
+ throws CommandFailedException {
+ FS fs = FS.DETECTED.newInstance();
+
+ FS.readPipe(fs.userHome(),
+ new String[] { "this-command-does-not-exist" },
+ Charset.defaultCharset().name());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java
index c6eca9d..d6ea8c6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -186,6 +187,16 @@
}
@Test
+ public void testContains() {
+ IntList i = new IntList();
+ i.add(1);
+ i.add(4);
+ assertTrue(i.contains(1));
+ assertTrue(i.contains(4));
+ assertFalse(i.contains(2));
+ }
+
+ @Test
public void testToString() {
final IntList i = new IntList();
i.add(1);
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 8ab9024..2a6babd 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.eclipse.jgit.awtui;version="4.8.0"
-Import-Package: org.eclipse.jgit.errors;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.lib;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.nls;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revplot;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.revwalk;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.transport;version="[4.8.0,4.9.0)",
- org.eclipse.jgit.util;version="[4.8.0,4.9.0)"
+Export-Package: org.eclipse.jgit.awtui;version="4.9.0"
+Import-Package: org.eclipse.jgit.errors;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.lib;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.nls;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revplot;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.revwalk;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.transport;version="[4.9.0,4.10.0)",
+ org.eclipse.jgit.util;version="[4.9.0,4.10.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 10b9374..244bd6f 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-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 d359bff..da7c122 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,5 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2">
+ <resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants">
+ <filter id="1141899266">
+ <message_arguments>
+ <message_argument value="4.7"/>
+ <message_argument value="4.8"/>
+ <message_argument value="CONFIG_KEY_AUTODETACH"/>
+ </message_arguments>
+ </filter>
+ <filter id="1141899266">
+ <message_arguments>
+ <message_argument value="4.7"/>
+ <message_argument value="4.8"/>
+ <message_argument value="CONFIG_KEY_LOGEXPIRY"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/merge/MergeStrategy.java" type="org.eclipse.jgit.merge.MergeStrategy">
<filter comment="OSGi semantic versioning allows breaking implementors of an API in a minor version" id="336695337">
<message_arguments>
@@ -8,4 +24,12 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
+ <filter comment="OSGi semantic versioning allows breaking implementors of an API in a minor version" id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
+ <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
+ </message_arguments>
+ </filter>
+ </resource>
</component>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index e4791dc..4719ceb 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.8.0.qualifier
+Bundle-Version: 4.9.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.annotations;version="4.8.0",
- org.eclipse.jgit.api;version="4.8.0";
+Export-Package: org.eclipse.jgit.annotations;version="4.9.0",
+ org.eclipse.jgit.api;version="4.9.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
@@ -21,51 +21,52 @@
org.eclipse.jgit.submodule,
org.eclipse.jgit.transport,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.8.0",
- org.eclipse.jgit.blame;version="4.8.0";
+ org.eclipse.jgit.api.errors;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="4.9.0",
+ org.eclipse.jgit.blame;version="4.9.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.8.0";
+ org.eclipse.jgit.diff;version="4.9.0";
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.8.0";
+ org.eclipse.jgit.dircache;version="4.9.0";
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.8.0";
+ org.eclipse.jgit.errors;version="4.9.0";
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.8.0";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.8.0",
- org.eclipse.jgit.gitrepo;version="4.8.0";
+ org.eclipse.jgit.events;version="4.9.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="4.9.0",
+ org.eclipse.jgit.gitrepo;version="4.9.0";
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.8.0";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.8.0";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.8.0",
- org.eclipse.jgit.ignore.internal;version="4.8.0";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.8.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.ketch;version="4.8.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.dfs;version="4.8.0";
+ org.eclipse.jgit.gitrepo.internal;version="4.9.0";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.9.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="4.9.0",
+ org.eclipse.jgit.ignore.internal;version="4.9.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.9.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.fsck;version="4.9.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal.ketch;version="4.9.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.dfs;version="4.9.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server,
org.eclipse.jgit.http.test,
org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.internal.storage.file;version="4.8.0";
+ org.eclipse.jgit.internal.storage.file;version="4.9.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
@@ -73,9 +74,9 @@
org.eclipse.jgit.lfs,
org.eclipse.jgit.pgm,
org.eclipse.jgit.pgm.test",
- org.eclipse.jgit.internal.storage.pack;version="4.8.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftree;version="4.8.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.8.0";
+ org.eclipse.jgit.internal.storage.pack;version="4.9.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftree;version="4.9.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.9.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
@@ -85,32 +86,33 @@
org.eclipse.jgit.treewalk,
org.eclipse.jgit.transport,
org.eclipse.jgit.submodule",
- org.eclipse.jgit.merge;version="4.8.0";
+ org.eclipse.jgit.lib.internal;version="4.9.0";x-internal:=true,
+ org.eclipse.jgit.merge;version="4.9.0";
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.8.0",
- org.eclipse.jgit.notes;version="4.8.0";
+ org.eclipse.jgit.nls;version="4.9.0",
+ org.eclipse.jgit.notes;version="4.9.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.8.0";
+ org.eclipse.jgit.patch;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="4.9.0";
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.8.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.8.0";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.8.0";
+ org.eclipse.jgit.revwalk.filter;version="4.9.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="4.9.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="4.9.0";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.internal.storage.pack,
@@ -122,24 +124,24 @@
org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.8.0";uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.8.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.8.0";
+ org.eclipse.jgit.transport.http;version="4.9.0";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="4.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="4.9.0";
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.8.0";uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.8.0";
+ org.eclipse.jgit.treewalk.filter;version="4.9.0";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="4.9.0";
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.8.0",
- org.eclipse.jgit.util.sha1;version="4.8.0",
- org.eclipse.jgit.util.time;version="4.8.0"
+ org.eclipse.jgit.util.io;version="4.9.0",
+ org.eclipse.jgit.util.sha1;version="4.9.0",
+ org.eclipse.jgit.util.time;version="4.9.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
com.jcraft.jsch;version="[0.1.37,0.2.0)",
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index bee6802..151278b 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.8.0.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.8.0.qualifier";roots="."
+Bundle-Version: 4.9.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.9.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 849b567..8306eb5 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit</artifactId>
@@ -206,8 +206,8 @@
<pluginManagement>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
+ <groupId>com.github.hazendaz.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 225cb53..fc29f48 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -208,12 +208,14 @@
createBranchFailedUnknownReason=Create branch failed for unknown reason
createBranchUnexpectedResult=Create branch returned unexpected result {0}
createNewFileFailed=Could not create new file {0}
+createRequiresZeroOldId=Create requires old ID to be zero
credentialPassword=Password
credentialUsername=Username
daemonAlreadyRunning=Daemon already running
daysAgo={0} days ago
deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deleteFileFailed=Could not delete file {0}
+deleteRequiresZeroNewId=Delete requires new ID to be zero
deleteTagUnexpectedResult=Delete tag returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
destinationIsNotAWildcard=Destination is not a wildcard.
@@ -242,6 +244,7 @@
encryptionOnlyPBE=Encryption error: only password-based encryption (PBE) algorithms are supported.
endOfFileInEscape=End of file in escape
entryNotFoundByPath=Entry not found by path: {0}
+enumValueNotSupported0=Invalid value: {0}
enumValueNotSupported2=Invalid value: {0}.{1}={2}
enumValueNotSupported3=Invalid value: {0}.{1}.{2}={3}
enumValuesNotAvailable=Enumerated values of type {0} not available
@@ -299,6 +302,8 @@
flagsAlreadyCreated={0} flags already created.
funnyRefname=funny refname
gcFailed=Garbage collection failed.
+gcLogExists=A previous GC run reported an error: ''{0}''. Automatic gc will fail until ''{1}'' is removed.
+gcTooManyUnpruned=Too many loose, unpruneable objects after garbage collection. Consider adjusting gc.auto or gc.pruneExpire.
gitmodulesNotFound=.gitmodules not found in tree.
headRequiredToStash=HEAD required to stash local changes
hoursAgo={0} hours ago
@@ -404,8 +409,11 @@
mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}"
messageAndTaggerNotAllowedInUnannotatedTags = Unannotated tags cannot have a message or tagger
minutesAgo={0} minutes ago
+mismatchOffset=mismatch offset for object {0}
+mismatchCRC=mismatch CRC for object {0}
missingAccesskey=Missing accesskey.
missingConfigurationForKey=No value for key {0} found in configuration
+missingCRC=missing CRC for object {0}
missingDeltaBase=delta base
missingForwardImageInGITBinaryPatch=Missing forward-image in GIT binary patch
missingObject=Missing {0} {1}
@@ -423,6 +431,7 @@
needPackOut=need packOut
needsAtLeastOneEntry=Needs at least one entry
needsWorkdir=Needs workdir
+newIdMustNotBeNull=New ID must not be null
newlineInQuotesNotAllowed=Newline in quotes not allowed
noApplyInDelete=No apply in delete
noClosingBracket=No closing {0} found for {1} at index {2}.
@@ -456,6 +465,7 @@
objectNotFoundIn=Object {0} not found in {1}.
obtainingCommitsForCherryPick=Obtaining commits that need to be cherry-picked
offsetWrittenDeltaBaseForObjectNotFoundInAPack=Offset-written delta base for object not found in a pack
+oldIdMustNotBeNull=Expected old ID must not be null
onlyAlreadyUpToDateAndFastForwardMergesAreAvailable=only already-up-to-date and fast forward merges are available
onlyOneFetchSupported=Only one fetch supported
onlyOneOperationCallPerConnectionIsSupported=Only one operation call per connection is supported.
@@ -660,6 +670,7 @@
unknownHost=unknown host
unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0}
unknownObject=unknown object
+unknownObjectInIndex=unknown object {0} found in index but not in pack file
unknownObjectType=Unknown object type {0}.
unknownObjectType2=unknown
unknownRepositoryFormat=Unknown repository format
@@ -682,6 +693,7 @@
unsupportedPackIndexVersion=Unsupported pack index version {0}
unsupportedPackVersion=Unsupported pack version {0}.
unsupportedRepositoryDescription=Repository description not supported
+updateRequiresOldIdAndNewId=Update requires both old ID and new ID to be nonzero
updatingHeadFailed=Updating HEAD failed
updatingReferences=Updating references
updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
index 0d18eb3..7ea8e73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java
@@ -403,6 +403,12 @@
if (!paths.isEmpty())
walk.setFilter(PathFilterGroup.createFromStrings(paths));
+ // Put base directory into archive
+ if (pfx.endsWith("/")) { //$NON-NLS-1$
+ fmt.putEntry(outa, tree, pfx.replaceAll("[/]+$", "/"), //$NON-NLS-1$ //$NON-NLS-2$
+ FileMode.TREE, null);
+ }
+
while (walk.next()) {
String name = pfx + walk.getPathString();
FileMode mode = walk.getFileMode(0);
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 2deff07..d450c64 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013 Chris Aniszczyk <caniszczyk@gmail.com>
+ * Copyright (C) 2011, 2017 Chris Aniszczyk <caniszczyk@gmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -76,6 +76,8 @@
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.TagOpt;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FileUtils;
/**
* Clone a repository into a new working directory
@@ -109,6 +111,10 @@
private Callback callback;
+ private boolean directoryExistsInitially;
+
+ private boolean gitDirExistsInitially;
+
/**
* Callback for status of clone operation.
*
@@ -167,26 +173,55 @@
@Override
public Git call() throws GitAPIException, InvalidRemoteException,
org.eclipse.jgit.api.errors.TransportException {
- Repository repository = null;
+ URIish u = null;
try {
- URIish u = new URIish(uri);
- repository = init(u);
- FetchResult result = fetch(repository, u);
- if (!noCheckout)
- checkout(repository, result);
- return new Git(repository, true);
+ u = new URIish(uri);
+ verifyDirectories(u);
+ } catch (URISyntaxException e) {
+ throw new InvalidRemoteException(
+ MessageFormat.format(JGitText.get().invalidURL, uri));
+ }
+ Repository repository = null;
+ FetchResult fetchResult = null;
+ Thread cleanupHook = new Thread(() -> cleanup());
+ Runtime.getRuntime().addShutdownHook(cleanupHook);
+ try {
+ repository = init();
+ fetchResult = fetch(repository, u);
} catch (IOException ioe) {
if (repository != null) {
repository.close();
}
+ cleanup();
throw new JGitInternalException(ioe.getMessage(), ioe);
} catch (URISyntaxException e) {
if (repository != null) {
repository.close();
}
+ cleanup();
throw new InvalidRemoteException(MessageFormat.format(
JGitText.get().invalidRemote, remote));
+ } catch (GitAPIException | RuntimeException e) {
+ if (repository != null) {
+ repository.close();
+ }
+ cleanup();
+ throw e;
+ } finally {
+ Runtime.getRuntime().removeShutdownHook(cleanupHook);
}
+ if (!noCheckout) {
+ try {
+ checkout(repository, fetchResult);
+ } catch (IOException ioe) {
+ repository.close();
+ throw new JGitInternalException(ioe.getMessage(), ioe);
+ } catch (GitAPIException | RuntimeException e) {
+ repository.close();
+ throw e;
+ }
+ }
+ return new Git(repository, true);
}
private static boolean isNonEmptyDirectory(File dir) {
@@ -197,12 +232,12 @@
return false;
}
- private Repository init(URIish u) throws GitAPIException {
- InitCommand command = Git.init();
- command.setBare(bare);
+ private void verifyDirectories(URIish u) {
if (directory == null && gitDir == null) {
directory = new File(u.getHumanishName(), Constants.DOT_GIT);
}
+ directoryExistsInitially = directory != null && directory.exists();
+ gitDirExistsInitially = gitDir != null && gitDir.exists();
validateDirs(directory, gitDir, bare);
if (isNonEmptyDirectory(directory)) {
throw new JGitInternalException(MessageFormat.format(
@@ -212,6 +247,11 @@
throw new JGitInternalException(MessageFormat.format(
JGitText.get().cloneNonEmptyDirectory, gitDir.getName()));
}
+ }
+
+ private Repository init() throws GitAPIException {
+ InitCommand command = Git.init();
+ command.setBare(bare);
if (directory != null) {
command.setDirectory(directory);
}
@@ -571,10 +611,12 @@
*
* @param callback
* the callback
+ * @return {@code this}
* @since 4.8
*/
- public void setCallback(Callback callback) {
+ public CloneCommand setCallback(Callback callback) {
this.callback = callback;
+ return this;
}
private static void validateDirs(File directory, File gitDir, boolean bare)
@@ -602,4 +644,38 @@
}
}
}
+
+ private void cleanup() {
+ try {
+ if (directory != null) {
+ if (!directoryExistsInitially) {
+ FileUtils.delete(directory, FileUtils.RECURSIVE
+ | FileUtils.SKIP_MISSING | FileUtils.IGNORE_ERRORS);
+ } else {
+ deleteChildren(directory);
+ }
+ }
+ if (gitDir != null) {
+ if (!gitDirExistsInitially) {
+ FileUtils.delete(gitDir, FileUtils.RECURSIVE
+ | FileUtils.SKIP_MISSING | FileUtils.IGNORE_ERRORS);
+ } else {
+ deleteChildren(directory);
+ }
+ }
+ } catch (IOException e) {
+ // Ignore; this is a best-effort cleanup in error cases, and
+ // IOException should not be raised anyway
+ }
+ }
+
+ private void deleteChildren(File file) throws IOException {
+ if (!FS.DETECTED.isDirectory(file)) {
+ return;
+ }
+ for (File child : file.listFiles()) {
+ FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING
+ | FileUtils.IGNORE_ERRORS);
+ }
+ }
}
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 274ece6..e29fc05 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -482,7 +482,7 @@
JGitText.get().entryNotFoundByPath, only.get(i)));
// there must be at least one change
- if (emptyCommit)
+ if (emptyCommit && !allowEmpty.booleanValue())
// Would like to throw a EmptyCommitException. But this would break the API
// TODO(ch): Change this in the next release
throw new JGitInternalException(JGitText.get().emptyCommit);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 389c511..d365171 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -47,17 +47,22 @@
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.InvalidPatternException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.ignore.internal.IMatcher;
+import org.eclipse.jgit.ignore.internal.PathMatcher;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -94,6 +99,11 @@
private boolean longDesc;
/**
+ * Pattern matchers to be applied to tags under consideration
+ */
+ private List<IMatcher> matchers = new ArrayList<>();
+
+ /**
*
* @param repo
*/
@@ -170,6 +180,54 @@
}
/**
+ * Sets one or more {@code glob(7)} patterns that tags must match to be considered.
+ * If multiple patterns are provided, tags only need match one of them.
+ *
+ * @param patterns the {@code glob(7)} pattern or patterns
+ * @return {@code this}
+ * @throws InvalidPatternException if the pattern passed in was invalid.
+ *
+ * @see <a
+ * href="https://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
+ * >Git documentation about describe</a>
+ * @since 4.9
+ */
+ public DescribeCommand setMatch(String... patterns) throws InvalidPatternException {
+ for (String p : patterns) {
+ matchers.add(PathMatcher.createPathMatcher(p, null, false));
+ }
+ return this;
+ }
+
+ private Optional<Ref> getBestMatch(List<Ref> tags) {
+ if (tags == null || tags.size() == 0) {
+ return Optional.empty();
+ } else if (matchers.size() == 0) {
+ // No matchers, simply return the first tag entry
+ return Optional.of(tags.get(0));
+ } else {
+ // Find the first tag that matches one of the matchers; precedence according to matcher definition order
+ for (IMatcher matcher : matchers) {
+ Optional<Ref> match = tags.stream()
+ .filter(tag -> matcher.matches(tag.getName(), false))
+ .findFirst();
+ if (match.isPresent()) {
+ return match;
+ }
+ }
+ return Optional.empty();
+ }
+ }
+
+ private ObjectId getObjectIdFromRef(Ref r) {
+ ObjectId key = repo.peel(r).getPeeledObjectId();
+ if (key == null) {
+ key = r.getObjectId();
+ }
+ return key;
+ }
+
+ /**
* Describes the specified commit. Target defaults to HEAD if no commit was
* set explicitly.
*
@@ -189,14 +247,9 @@
if (target == null)
setTarget(Constants.HEAD);
- Map<ObjectId, Ref> tags = new HashMap<>();
-
- for (Ref r : repo.getRefDatabase().getRefs(R_TAGS).values()) {
- ObjectId key = repo.peel(r).getPeeledObjectId();
- if (key == null)
- key = r.getObjectId();
- tags.put(key, r);
- }
+ Collection<Ref> tagList = repo.getRefDatabase().getRefs(R_TAGS).values();
+ Map<ObjectId, List<Ref>> tags = tagList.stream()
+ .collect(Collectors.groupingBy(this::getObjectIdFromRef));
// combined flags of all the candidate instances
final RevFlagSet allFlags = new RevFlagSet();
@@ -242,11 +295,11 @@
}
List<Candidate> candidates = new ArrayList<>(); // all the candidates we find
- // is the target already pointing to a tag? if so, we are done!
- Ref lucky = tags.get(target);
- if (lucky != null) {
- return longDesc ? longDescription(lucky, 0, target) : lucky
- .getName().substring(R_TAGS.length());
+ // is the target already pointing to a suitable tag? if so, we are done!
+ Optional<Ref> bestMatch = getBestMatch(tags.get(target));
+ if (bestMatch.isPresent()) {
+ return longDesc ? longDescription(bestMatch.get(), 0, target) :
+ bestMatch.get().getName().substring(R_TAGS.length());
}
w.markStart(target);
@@ -258,9 +311,9 @@
// if a tag already dominates this commit,
// then there's no point in picking a tag on this commit
// since the one that dominates it is always more preferable
- Ref t = tags.get(c);
- if (t != null) {
- Candidate cd = new Candidate(c, t);
+ bestMatch = getBestMatch(tags.get(c));
+ if (bestMatch.isPresent()) {
+ Candidate cd = new Candidate(c, bestMatch.get());
candidates.add(cd);
cd.depth = seen;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
index cc3302b..4853159 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -48,6 +48,7 @@
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidConfigurationException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -99,6 +100,24 @@
private FetchRecurseSubmodulesMode submoduleRecurseMode = null;
+ private Callback callback;
+
+ /**
+ * Callback for status of fetch operation.
+ *
+ * @since 4.8
+ *
+ */
+ public interface Callback {
+ /**
+ * Notify fetching a submodule.
+ *
+ * @param name
+ * the submodule name.
+ */
+ void fetchingSubmodule(String name);
+ }
+
/**
* @param repo
*/
@@ -173,6 +192,9 @@
.setThin(thin).setRefSpecs(refSpecs)
.setDryRun(dryRun)
.setRecurseSubmodules(recurseMode);
+ if (callback != null) {
+ callback.fetchingSubmodule(walk.getPath());
+ }
results.addSubmodule(walk.getPath(), f.call());
}
}
@@ -237,11 +259,19 @@
* Set the mode to be used for recursing into submodules.
*
* @param recurse
+ * corresponds to the
+ * --recurse-submodules/--no-recurse-submodules options. If
+ * {@code null} use the value of the
+ * {@code submodule.name.fetchRecurseSubmodules} option
+ * configured per submodule. If not specified there, use the
+ * value of the {@code fetch.recurseSubmodules} option configured
+ * in git config. If not configured in either, "on-demand" is the
+ * built-in default.
* @return {@code this}
* @since 4.7
*/
public FetchCommand setRecurseSubmodules(
- FetchRecurseSubmodulesMode recurse) {
+ @Nullable FetchRecurseSubmodulesMode recurse) {
checkCallable();
submoduleRecurseMode = recurse;
return this;
@@ -434,4 +464,17 @@
this.tagOption = tagOpt;
return this;
}
+
+ /**
+ * Register a progress callback.
+ *
+ * @param callback
+ * the callback
+ * @return {@code this}
+ * @since 4.8
+ */
+ public FetchCommand setCallback(Callback callback) {
+ this.callback = callback;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index b5d9e8a..bae54ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -53,6 +53,7 @@
import java.util.Locale;
import java.util.Map;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
@@ -554,12 +555,15 @@
* Sets the fast forward mode.
*
* @param fastForwardMode
- * corresponds to the --ff/--no-ff/--ff-only options. --ff is the
- * default option.
+ * corresponds to the --ff/--no-ff/--ff-only options. If
+ * {@code null} use the value of the {@code merge.ff} option
+ * configured in git config. If this option is not configured
+ * --ff is the built-in default.
* @return {@code this}
* @since 2.2
*/
- public MergeCommand setFastForward(FastForwardMode fastForwardMode) {
+ public MergeCommand setFastForward(
+ @Nullable FastForwardMode fastForwardMode) {
checkCallable();
this.fastForwardMode = fastForwardMode;
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 9c5ae43..aa97996 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -47,6 +47,9 @@
import java.io.IOException;
import java.text.MessageFormat;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
+import org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge;
import org.eclipse.jgit.api.RebaseCommand.Operation;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.DetachedHeadException;
@@ -96,6 +99,8 @@
private TagOpt tagOption;
+ private FastForwardMode fastForwardMode;
+
private FetchRecurseSubmodulesMode submoduleRecurseMode = null;
/**
@@ -347,10 +352,9 @@
result = new PullResult(fetchRes, remote, rebaseRes);
} else {
MergeCommand merge = new MergeCommand(repo);
- merge.include(upstreamName, commitToMerge);
- merge.setStrategy(strategy);
- merge.setProgressMonitor(monitor);
- MergeResult mergeRes = merge.call();
+ MergeResult mergeRes = merge.include(upstreamName, commitToMerge)
+ .setStrategy(strategy).setProgressMonitor(monitor)
+ .setFastForward(getFastForwardMode()).call();
monitor.update(1);
result = new PullResult(fetchRes, remote, mergeRes);
}
@@ -433,14 +437,36 @@
}
/**
+ * Sets the fast forward mode. It is used if pull is configured to do a
+ * merge as opposed to rebase. If non-{@code null} takes precedence over the
+ * fast-forward mode configured in git config.
+ *
+ * @param fastForwardMode
+ * corresponds to the --ff/--no-ff/--ff-only options. If
+ * {@code null} use the value of {@code pull.ff} configured in
+ * git config. If {@code pull.ff} is not configured fall back to
+ * the value of {@code merge.ff}. If {@code merge.ff} is not
+ * configured --ff is the built-in default.
+ * @return {@code this}
+ * @since 4.9
+ */
+ public PullCommand setFastForward(
+ @Nullable FastForwardMode fastForwardMode) {
+ checkCallable();
+ this.fastForwardMode = fastForwardMode;
+ return this;
+ }
+
+ /**
* Set the mode to be used for recursing into submodules.
*
* @param recurse
* @return {@code this}
* @since 4.7
+ * @see FetchCommand#setRecurseSubmodules(FetchRecurseSubmodulesMode)
*/
public PullCommand setRecurseSubmodules(
- FetchRecurseSubmodulesMode recurse) {
+ @Nullable FetchRecurseSubmodulesMode recurse) {
this.submoduleRecurseMode = recurse;
return this;
}
@@ -470,4 +496,15 @@
}
return mode;
}
+
+ private FastForwardMode getFastForwardMode() {
+ if (fastForwardMode != null) {
+ return fastForwardMode;
+ }
+ Config config = repo.getConfig();
+ Merge ffMode = config.getEnum(Merge.values(),
+ ConfigConstants.CONFIG_PULL_SECTION, null,
+ ConfigConstants.CONFIG_KEY_FF, null);
+ return ffMode != null ? FastForwardMode.valueOf(ffMode) : null;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
index 04caa0f..394bea5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
@@ -109,4 +109,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
index f97dce9..b5c0b15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -162,4 +162,4 @@
throw new JGitInternalException(e.getMessage(), e);
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
index 34bfbe7..4d3dff0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -240,9 +240,11 @@
*
* @param callback
* the callback
+ * @return {@code this}
* @since 4.8
*/
- public void setCallback(CloneCommand.Callback callback) {
+ public SubmoduleUpdateCommand setCallback(CloneCommand.Callback callback) {
this.callback = callback;
+ return this;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
index 08c25c2..b841f57 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
@@ -38,7 +38,8 @@
package org.eclipse.jgit.api.errors;
/**
- * Exception thrown when the server rejected a too large pack
+ * Exception thrown when PackParser finds an object larger than a predefined
+ * limit
*
* @since 4.4
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
index 905ad76..c256b73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
@@ -193,4 +193,4 @@
return key + "=" + value; //$NON-NLS-1$
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
index 0810e31..d3826b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>,
+ * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
@@ -48,6 +49,7 @@
import java.util.Map;
import org.eclipse.jgit.attributes.Attribute.State;
+import org.eclipse.jgit.lib.Constants;
/**
* Represents a set of attributes for a path
@@ -170,6 +172,26 @@
return a != null ? a.getValue() : null;
}
+ /**
+ * Test if the given attributes implies to handle the related entry as a
+ * binary file (i.e. if the entry has an -merge or a merge=binary attribute)
+ * or if it can be content merged.
+ *
+ * @return <code>true</code> if the entry can be content merged,
+ * <code>false</code> otherwise
+ * @since 4.9
+ */
+ public boolean canBeContentMerged() {
+ if (isUnset(Constants.ATTR_MERGE)) {
+ return false;
+ } else if (isCustom(Constants.ATTR_MERGE)
+ && getValue(Constants.ATTR_MERGE)
+ .equals(Constants.ATTR_BUILTIN_BINARY_MERGER)) {
+ return false;
+ }
+ return true;
+ }
+
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
index c9c69db..b88a16e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
@@ -225,4 +225,4 @@
return sb.toString();
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
index e1dfcff..5eb1942 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
@@ -525,4 +525,4 @@
buf.append("]");
return buf.toString();
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
index bc52473..d899429 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
@@ -220,7 +220,9 @@
* must be allocated, and 1,000,000 file compares may need to be performed.
*
* @param limit
- * new file limit.
+ * new file limit. 0 means no limit; a negative number means no
+ * inexact rename detection will be performed, only exact rename
+ * detection.
*/
public void setRenameLimit(int limit) {
renameLimit = limit;
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 84f0da9..aed76ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -1299,8 +1299,13 @@
return;
}
+ String name = f.getName();
+ if (name.length() > 200) {
+ name = name.substring(0, 200);
+ }
File tmpFile = File.createTempFile(
- "._" + f.getName(), null, parentDir); //$NON-NLS-1$
+ "._" + name, null, parentDir); //$NON-NLS-1$
+
EolStreamType nonNullEolStreamType;
if (checkoutMetadata.eolStreamType != null) {
nonNullEolStreamType = checkoutMetadata.eolStreamType;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptPackIndexException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptPackIndexException.java
new file mode 100644
index 0000000..65d83b3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptPackIndexException.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017, 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.errors;
+
+import org.eclipse.jgit.annotations.Nullable;
+
+/**
+ * Exception thrown when encounters a corrupt pack index file.
+ *
+ * @since 4.9
+ */
+public class CorruptPackIndexException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ /** The error type of a corrupt index file. */
+ public enum ErrorType {
+ /** Offset does not match index in pack file. */
+ MISMATCH_OFFSET,
+ /** CRC does not match CRC of the object data in pack file. */
+ MISMATCH_CRC,
+ /** CRC is not present in index file. */
+ MISSING_CRC,
+ /** Object in pack is not present in index file. */
+ MISSING_OBJ,
+ /** Object in index file is not present in pack file. */
+ UNKNOWN_OBJ,
+ }
+
+ private ErrorType errorType;
+
+ /**
+ * Report a specific error condition discovered in an index file.
+ *
+ * @param message
+ * the error message.
+ * @param errorType
+ * the error type of corruption.
+ */
+ public CorruptPackIndexException(String message, ErrorType errorType) {
+ super(message);
+ this.errorType = errorType;
+ }
+
+ /**
+ * Specific the reason of the corrupt index file.
+ *
+ * @return error condition or null.
+ */
+ @Nullable
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
index b5b1af5..ece76ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
@@ -92,4 +92,4 @@
public TooLargeObjectInPackException(URIish uri, String s) {
super(uri.setPass(null) + ": " + s); //$NON-NLS-1$
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
index 4f297b9..6cb332d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TranslationBundleLoadingException.java
@@ -69,4 +69,4 @@
+ bundleClass.getName() + ", " + locale.toString() + "]", //$NON-NLS-1$ //$NON-NLS-2$
bundleClass, locale, cause);
}
-}
\ No newline at end of file
+}
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 6669c9c..1de8a0b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -731,7 +731,9 @@
* Returns the child if either base or child is not a bare path. This provides a missing feature in
* java.net.URI (see http://bugs.java.com/view_bug.do?bug_id=6226081).
*/
+ private static final String SLASH = "/"; //$NON-NLS-1$
static URI relativize(URI current, URI target) {
+
// We only handle bare paths for now.
if (!target.toString().equals(target.getPath())) {
return target;
@@ -744,37 +746,46 @@
String dest = target.normalize().getPath();
// TODO(hanwen): maybe (absolute, relative) should throw an exception.
- if (cur.startsWith("/") != dest.startsWith("/")) { //$NON-NLS-1$//$NON-NLS-2$
+ if (cur.startsWith(SLASH) != dest.startsWith(SLASH)) {
return target;
}
- while (cur.startsWith("/")) { //$NON-NLS-1$
+ while (cur.startsWith(SLASH)) {
cur = cur.substring(1);
}
- while (dest.startsWith("/")) { //$NON-NLS-1$
+ while (dest.startsWith(SLASH)) {
dest = dest.substring(1);
}
- if (!cur.endsWith("/")) { //$NON-NLS-1$
+ if (cur.indexOf('/') == -1 || dest.indexOf('/') == -1) {
+ // Avoid having to special-casing in the next two ifs.
+ String prefix = "prefix/"; //$NON-NLS-1$
+ cur = prefix + cur;
+ dest = prefix + dest;
+ }
+
+ if (!cur.endsWith(SLASH)) {
// The current file doesn't matter.
- cur = cur.substring(0, cur.lastIndexOf('/'));
+ int lastSlash = cur.lastIndexOf('/');
+ cur = cur.substring(0, lastSlash);
}
String destFile = ""; //$NON-NLS-1$
- if (!dest.endsWith("/")) { //$NON-NLS-1$
+ if (!dest.endsWith(SLASH)) {
// We always have to provide the destination file.
- destFile = dest.substring(dest.lastIndexOf('/') + 1, dest.length());
+ int lastSlash = dest.lastIndexOf('/');
+ destFile = dest.substring(lastSlash + 1, dest.length());
dest = dest.substring(0, dest.lastIndexOf('/'));
}
- String[] cs = cur.split("/"); //$NON-NLS-1$
- String[] ds = dest.split("/"); //$NON-NLS-1$
+ String[] cs = cur.split(SLASH);
+ String[] ds = dest.split(SLASH);
int common = 0;
while (common < cs.length && common < ds.length && cs[common].equals(ds[common])) {
common++;
}
- StringJoiner j = new StringJoiner("/"); //$NON-NLS-1$
+ StringJoiner j = new StringJoiner(SLASH);
for (int i = common; i < cs.length; i++) {
j.add(".."); //$NON-NLS-1$
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
index c1aca6a..b684dd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java
@@ -42,9 +42,12 @@
*/
package org.eclipse.jgit.hooks;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
import java.util.concurrent.Callable;
import org.eclipse.jgit.api.errors.AbortedByHookException;
@@ -147,14 +150,21 @@
*/
protected void doRun() throws AbortedByHookException {
final ByteArrayOutputStream errorByteArray = new ByteArrayOutputStream();
- final PrintStream hookErrRedirect = new PrintStream(errorByteArray);
+ PrintStream hookErrRedirect = null;
+ try {
+ hookErrRedirect = new PrintStream(errorByteArray, false,
+ UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ // UTF-8 is guaranteed to be available
+ }
ProcessResult result = FS.DETECTED.runHookIfPresent(getRepository(),
getHookName(), getParameters(), getOutputStream(),
hookErrRedirect, getStdinArgs());
if (result.isExecutedWithError()) {
- throw new AbortedByHookException(errorByteArray.toString(),
+ throw new AbortedByHookException(
+ new String(errorByteArray.toByteArray(), UTF_8),
getHookName(), result.getExitCode());
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
index 65224ea..ce9ad80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java
@@ -227,29 +227,30 @@
int left = right;
right = path.indexOf(slash, right);
if (right == -1) {
- if (left < endExcl)
+ if (left < endExcl) {
match = matches(matcher, path, left, endExcl,
assumeDirectory);
+ } else {
+ // a/** should not match a/ or a
+ match = match && matchers.get(matcher) != WILD;
+ }
if (match) {
- if (matcher == matchers.size() - 2
- && matchers.get(matcher + 1) == WILD)
- // ** can match *nothing*: a/b/** match also a/b
- return true;
if (matcher < matchers.size() - 1
&& matchers.get(matcher) == WILD) {
// ** can match *nothing*: a/**/b match also a/b
matcher++;
match = matches(matcher, path, left, endExcl,
assumeDirectory);
- } else if (dirOnly && !assumeDirectory)
+ } else if (dirOnly && !assumeDirectory) {
// Directory expectations not met
return false;
+ }
}
return match && matcher + 1 == matchers.size();
}
- if (right - left > 0)
+ if (right - left > 0) {
match = matches(matcher, path, left, right, assumeDirectory);
- else {
+ } else {
// path starts with slash???
right++;
continue;
@@ -261,12 +262,14 @@
right = left - 1;
}
matcher++;
- if (matcher == matchers.size())
+ if (matcher == matchers.size()) {
return true;
- } else if (lastWildmatch != -1)
+ }
+ } else if (lastWildmatch != -1) {
matcher = lastWildmatch + 1;
- else
+ } else {
return false;
+ }
right++;
}
}
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 b2c59a3..a68f839 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -267,12 +267,14 @@
/***/ public String createBranchFailedUnknownReason;
/***/ public String createBranchUnexpectedResult;
/***/ public String createNewFileFailed;
+ /***/ public String createRequiresZeroOldId;
/***/ public String credentialPassword;
/***/ public String credentialUsername;
/***/ public String daemonAlreadyRunning;
/***/ public String daysAgo;
/***/ public String deleteBranchUnexpectedResult;
/***/ public String deleteFileFailed;
+ /***/ public String deleteRequiresZeroNewId;
/***/ public String deleteTagUnexpectedResult;
/***/ public String deletingNotSupported;
/***/ public String destinationIsNotAWildcard;
@@ -301,6 +303,7 @@
/***/ public String encryptionOnlyPBE;
/***/ public String endOfFileInEscape;
/***/ public String entryNotFoundByPath;
+ /***/ public String enumValueNotSupported0;
/***/ public String enumValueNotSupported2;
/***/ public String enumValueNotSupported3;
/***/ public String enumValuesNotAvailable;
@@ -358,6 +361,8 @@
/***/ public String flagsAlreadyCreated;
/***/ public String funnyRefname;
/***/ public String gcFailed;
+ /***/ public String gcLogExists;
+ /***/ public String gcTooManyUnpruned;
/***/ public String gitmodulesNotFound;
/***/ public String headRequiredToStash;
/***/ public String hoursAgo;
@@ -463,8 +468,11 @@
/***/ public String mergeRecursiveTooManyMergeBasesFor;
/***/ public String messageAndTaggerNotAllowedInUnannotatedTags;
/***/ public String minutesAgo;
+ /***/ public String mismatchOffset;
+ /***/ public String mismatchCRC;
/***/ public String missingAccesskey;
/***/ public String missingConfigurationForKey;
+ /***/ public String missingCRC;
/***/ public String missingDeltaBase;
/***/ public String missingForwardImageInGITBinaryPatch;
/***/ public String missingObject;
@@ -482,6 +490,7 @@
/***/ public String needPackOut;
/***/ public String needsAtLeastOneEntry;
/***/ public String needsWorkdir;
+ /***/ public String newIdMustNotBeNull;
/***/ public String newlineInQuotesNotAllowed;
/***/ public String noApplyInDelete;
/***/ public String noClosingBracket;
@@ -515,6 +524,7 @@
/***/ public String objectNotFoundIn;
/***/ public String obtainingCommitsForCherryPick;
/***/ public String offsetWrittenDeltaBaseForObjectNotFoundInAPack;
+ /***/ public String oldIdMustNotBeNull;
/***/ public String onlyAlreadyUpToDateAndFastForwardMergesAreAvailable;
/***/ public String onlyOneFetchSupported;
/***/ public String onlyOneOperationCallPerConnectionIsSupported;
@@ -719,6 +729,7 @@
/***/ public String unknownHost;
/***/ public String unknownIndexVersionOrCorruptIndex;
/***/ public String unknownObject;
+ /***/ public String unknownObjectInIndex;
/***/ public String unknownObjectType;
/***/ public String unknownObjectType2;
/***/ public String unknownRepositoryFormat;
@@ -741,6 +752,7 @@
/***/ public String unsupportedPackIndexVersion;
/***/ public String unsupportedPackVersion;
/***/ public String unsupportedRepositoryDescription;
+ /***/ public String updateRequiresOldIdAndNewId;
/***/ public String updatingHeadFailed;
/***/ public String updatingReferences;
/***/ public String updatingRefFailed;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
new file mode 100644
index 0000000..588ed9b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckError.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2017, 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.internal.fsck;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.CorruptPackIndexException;
+import org.eclipse.jgit.errors.CorruptPackIndexException.ErrorType;
+import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.lib.ObjectId;
+
+/** Holds all fsck errors of a git repository. */
+public class FsckError {
+ /** Represents a corrupt object. */
+ public static class CorruptObject {
+ final ObjectId id;
+
+ final int type;
+
+ ObjectChecker.ErrorType errorType;
+
+ /**
+ * @param id
+ * the object identifier.
+ * @param type
+ * type of the object.
+ */
+ public CorruptObject(ObjectId id, int type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ void setErrorType(ObjectChecker.ErrorType errorType) {
+ this.errorType = errorType;
+ }
+
+ /** @return identifier of the object. */
+ public ObjectId getId() {
+ return id;
+ }
+
+ /** @return type of the object. */
+ public int getType() {
+ return type;
+ }
+
+ /** @return error type of the corruption. */
+ @Nullable
+ public ObjectChecker.ErrorType getErrorType() {
+ return errorType;
+ }
+ }
+
+ /** Represents a corrupt pack index file. */
+ public static class CorruptIndex {
+ String fileName;
+
+ CorruptPackIndexException.ErrorType errorType;
+
+ /**
+ * @param fileName
+ * the file name of the pack index.
+ * @param errorType
+ * the type of error as reported in
+ * {@link CorruptPackIndexException}.
+ */
+ public CorruptIndex(String fileName, ErrorType errorType) {
+ this.fileName = fileName;
+ this.errorType = errorType;
+ }
+
+ /** @return the file name of the index file. */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /** @return the error type of the corruption. */
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+ }
+
+ private final Set<CorruptObject> corruptObjects = new HashSet<>();
+
+ private final Set<ObjectId> missingObjects = new HashSet<>();
+
+ private final Set<CorruptIndex> corruptIndices = new HashSet<>();
+
+ private final Set<String> nonCommitHeads = new HashSet<>();
+
+ /** @return corrupt objects from all pack files. */
+ public Set<CorruptObject> getCorruptObjects() {
+ return corruptObjects;
+ }
+
+ /** @return missing objects that should present in pack files. */
+ public Set<ObjectId> getMissingObjects() {
+ return missingObjects;
+ }
+
+ /** @return corrupt index files associated with the packs. */
+ public Set<CorruptIndex> getCorruptIndices() {
+ return corruptIndices;
+ }
+
+ /** @return refs/heads/* point to non-commit object. */
+ public Set<String> getNonCommitHeads() {
+ return nonCommitHeads;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java
new file mode 100644
index 0000000..e6ec681
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/FsckPackParser.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2017, 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.internal.fsck;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.CRC32;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.CorruptPackIndexException;
+import org.eclipse.jgit.errors.CorruptPackIndexException.ErrorType;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.fsck.FsckError.CorruptObject;
+import org.eclipse.jgit.internal.storage.dfs.ReadableChannel;
+import org.eclipse.jgit.internal.storage.file.PackIndex;
+import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.lib.ObjectDatabase;
+import org.eclipse.jgit.transport.PackParser;
+import org.eclipse.jgit.transport.PackedObjectInfo;
+
+/** A read-only pack parser for object validity checking. */
+public class FsckPackParser extends PackParser {
+ private final CRC32 crc;
+
+ private final ReadableChannel channel;
+
+ private final Set<CorruptObject> corruptObjects = new HashSet<>();
+
+ private long expectedObjectCount = -1L;
+
+ private long offset;
+
+ private int blockSize;
+
+ /**
+ * @param db
+ * the object database which stores repository's data.
+ * @param channel
+ * readable channel of the pack file.
+ */
+ public FsckPackParser(ObjectDatabase db, ReadableChannel channel) {
+ super(db, Channels.newInputStream(channel));
+ this.channel = channel;
+ setCheckObjectCollisions(false);
+ this.crc = new CRC32();
+ this.blockSize = channel.blockSize() > 0 ? channel.blockSize() : 65536;
+ }
+
+ @Override
+ protected void onPackHeader(long objCnt) throws IOException {
+ if (expectedObjectCount >= 0) {
+ // Some DFS pack files don't contain the correct object count, e.g.
+ // INSERT/RECEIVE packs don't always contain the correct object
+ // count in their headers. Overwrite the expected object count
+ // after parsing the pack header.
+ setExpectedObjectCount(expectedObjectCount);
+ }
+ }
+
+ @Override
+ protected void onBeginWholeObject(long streamPosition, int type,
+ long inflatedSize) throws IOException {
+ crc.reset();
+ }
+
+ @Override
+ protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
+ throws IOException {
+ crc.update(raw, pos, len);
+ }
+
+ @Override
+ protected void onObjectData(Source src, byte[] raw, int pos, int len)
+ throws IOException {
+ crc.update(raw, pos, len);
+ }
+
+ @Override
+ protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
+ info.setCRC((int) crc.getValue());
+ }
+
+ @Override
+ protected void onBeginOfsDelta(long deltaStreamPosition,
+ long baseStreamPosition, long inflatedSize) throws IOException {
+ crc.reset();
+ }
+
+ @Override
+ protected void onBeginRefDelta(long deltaStreamPosition, AnyObjectId baseId,
+ long inflatedSize) throws IOException {
+ crc.reset();
+ }
+
+ @Override
+ protected UnresolvedDelta onEndDelta() throws IOException {
+ UnresolvedDelta delta = new UnresolvedDelta();
+ delta.setCRC((int) crc.getValue());
+ return delta;
+ }
+
+ @Override
+ protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
+ byte[] data) throws IOException {
+ // FsckPackParser ignores this event.
+ }
+
+ @Override
+ protected void verifySafeObject(final AnyObjectId id, final int type,
+ final byte[] data) {
+ try {
+ super.verifySafeObject(id, type, data);
+ } catch (CorruptObjectException e) {
+ // catch the exception and continue parse the pack file
+ CorruptObject o = new CorruptObject(id.toObjectId(), type);
+ if (e.getErrorType() != null) {
+ o.setErrorType(e.getErrorType());
+ }
+ corruptObjects.add(o);
+ }
+ }
+
+ @Override
+ protected void onPackFooter(byte[] hash) throws IOException {
+ }
+
+ @Override
+ protected boolean onAppendBase(int typeCode, byte[] data,
+ PackedObjectInfo info) throws IOException {
+ // Do nothing.
+ return false;
+ }
+
+ @Override
+ protected void onEndThinPack() throws IOException {
+ }
+
+ @Override
+ protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
+ ObjectTypeAndSize info) throws IOException {
+ crc.reset();
+ offset = obj.getOffset();
+ return readObjectHeader(info);
+ }
+
+ @Override
+ protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
+ ObjectTypeAndSize info) throws IOException {
+ crc.reset();
+ offset = delta.getOffset();
+ return readObjectHeader(info);
+ }
+
+ @Override
+ protected int readDatabase(byte[] dst, int pos, int cnt)
+ throws IOException {
+ // read from input instead of database.
+ int n = read(offset, dst, pos, cnt);
+ if (n > 0) {
+ offset += n;
+ }
+ return n;
+ }
+
+ int read(long channelPosition, byte[] dst, int pos, int cnt)
+ throws IOException {
+ long block = channelPosition / blockSize;
+ byte[] bytes = readFromChannel(block);
+ if (bytes == null) {
+ return -1;
+ }
+ int offset = (int) (channelPosition - block * blockSize);
+ int bytesToCopy = Math.min(cnt, bytes.length - offset);
+ if (bytesToCopy < 1) {
+ return -1;
+ }
+ System.arraycopy(bytes, offset, dst, pos, bytesToCopy);
+ return bytesToCopy;
+ }
+
+ private byte[] readFromChannel(long block) throws IOException {
+ channel.position(block * blockSize);
+ ByteBuffer buf = ByteBuffer.allocate(blockSize);
+ int totalBytesRead = 0;
+ while (totalBytesRead < blockSize) {
+ int bytesRead = channel.read(buf);
+ if (bytesRead == -1) {
+ if (totalBytesRead == 0) {
+ return null;
+ }
+ return Arrays.copyOf(buf.array(), totalBytesRead);
+ }
+ totalBytesRead += bytesRead;
+ }
+ return buf.array();
+ }
+
+ @Override
+ protected boolean checkCRC(int oldCRC) {
+ return oldCRC == (int) crc.getValue();
+ }
+
+ @Override
+ protected void onStoreStream(byte[] raw, int pos, int len)
+ throws IOException {
+ }
+
+ /**
+ * @return corrupt objects that reported by {@link ObjectChecker}.
+ */
+ public Set<CorruptObject> getCorruptObjects() {
+ return corruptObjects;
+ }
+
+ /**
+ * Verify the existing index file with all objects from the pack.
+ *
+ * @param entries
+ * all the entries that are expected in the index file
+ * @param idx
+ * index file associate with the pack
+ * @throws CorruptPackIndexException
+ * when the index file is corrupt.
+ */
+ public void verifyIndex(List<PackedObjectInfo> entries, PackIndex idx)
+ throws CorruptPackIndexException {
+ Set<String> all = new HashSet<>();
+ for (PackedObjectInfo entry : entries) {
+ all.add(entry.getName());
+ long offset = idx.findOffset(entry);
+ if (offset == -1) {
+ throw new CorruptPackIndexException(
+ MessageFormat.format(JGitText.get().missingObject,
+ entry.getType(), entry.getName()),
+ ErrorType.MISSING_OBJ);
+ } else if (offset != entry.getOffset()) {
+ throw new CorruptPackIndexException(MessageFormat
+ .format(JGitText.get().mismatchOffset, entry.getName()),
+ ErrorType.MISMATCH_OFFSET);
+ }
+
+ try {
+ if (idx.hasCRC32Support()
+ && (int) idx.findCRC32(entry) != entry.getCRC()) {
+ throw new CorruptPackIndexException(
+ MessageFormat.format(JGitText.get().mismatchCRC,
+ entry.getName()),
+ ErrorType.MISMATCH_CRC);
+ }
+ } catch (MissingObjectException e) {
+ throw new CorruptPackIndexException(MessageFormat
+ .format(JGitText.get().missingCRC, entry.getName()),
+ ErrorType.MISSING_CRC);
+ }
+ }
+
+ for (MutableEntry entry : idx) {
+ if (!all.contains(entry.name())) {
+ throw new CorruptPackIndexException(MessageFormat.format(
+ JGitText.get().unknownObjectInIndex, entry.name()),
+ ErrorType.UNKNOWN_OBJ);
+ }
+ }
+ }
+
+ /**
+ * Set the object count for overwriting the expected object count from pack
+ * header.
+ *
+ * @param expectedObjectCount
+ * the actual expected object count.
+ */
+ public void overwriteObjectCount(long expectedObjectCount) {
+ this.expectedObjectCount = expectedObjectCount;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/package-info.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/package-info.java
new file mode 100644
index 0000000..361b61f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/fsck/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Git fsck support.
+ */
+package org.eclipse.jgit.internal.fsck;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
new file mode 100644
index 0000000..813e7f4
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.dfs;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.PackInvalidException;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+
+/** Block based file stored in {@link DfsBlockCache}. */
+public abstract class BlockBasedFile {
+ /** Cache that owns this file and its data. */
+ final DfsBlockCache cache;
+
+ /** Unique identity of this file while in-memory. */
+ final DfsStreamKey key;
+
+ /** Description of the associated pack file's storage. */
+ final DfsPackDescription desc;
+ final PackExt ext;
+
+ /**
+ * Preferred alignment for loading blocks from the backing file.
+ * <p>
+ * It is initialized to 0 and filled in on the first read made from the
+ * file. Block sizes may be odd, e.g. 4091, caused by the underling DFS
+ * storing 4091 user bytes and 5 bytes block metadata into a lower level
+ * 4096 byte block on disk.
+ */
+ volatile int blockSize;
+
+ /**
+ * Total number of bytes in this pack file.
+ * <p>
+ * This field initializes to -1 and gets populated when a block is loaded.
+ */
+ volatile long length;
+
+ /** True once corruption has been detected that cannot be worked around. */
+ volatile boolean invalid;
+
+ BlockBasedFile(DfsBlockCache cache, DfsPackDescription desc, PackExt ext) {
+ this.cache = cache;
+ this.key = desc.getStreamKey(ext);
+ this.desc = desc;
+ this.ext = ext;
+ }
+
+ String getFileName() {
+ return desc.getFileName(ext);
+ }
+
+ boolean invalid() {
+ return invalid;
+ }
+
+ void setInvalid() {
+ invalid = true;
+ }
+
+ void setBlockSize(int newSize) {
+ blockSize = newSize;
+ }
+
+ long alignToBlock(long pos) {
+ int size = blockSize;
+ if (size == 0)
+ size = cache.getBlockSize();
+ return (pos / size) * size;
+ }
+
+ int blockSize(ReadableChannel rc) {
+ // If the block alignment is not yet known, discover it. Prefer the
+ // larger size from either the cache or the file itself.
+ int size = blockSize;
+ if (size == 0) {
+ size = rc.blockSize();
+ if (size <= 0)
+ size = cache.getBlockSize();
+ else if (size < cache.getBlockSize())
+ size = (cache.getBlockSize() / size) * size;
+ blockSize = size;
+ }
+ return size;
+ }
+
+ DfsBlock readOneBlock(long pos, DfsReader ctx,
+ @Nullable ReadableChannel fileChannel) throws IOException {
+ if (invalid)
+ throw new PackInvalidException(getFileName());
+
+ ctx.stats.readBlock++;
+ long start = System.nanoTime();
+ ReadableChannel rc = fileChannel != null ? fileChannel
+ : ctx.db.openFile(desc, ext);
+ try {
+ int size = blockSize(rc);
+ pos = (pos / size) * size;
+
+ // If the size of the file is not yet known, try to discover it.
+ // Channels may choose to return -1 to indicate they don't
+ // know the length yet, in this case read up to the size unit
+ // given by the caller, then recheck the length.
+ long len = length;
+ if (len < 0) {
+ len = rc.size();
+ if (0 <= len)
+ length = len;
+ }
+
+ if (0 <= len && len < pos + size)
+ size = (int) (len - pos);
+ if (size <= 0)
+ throw new EOFException(MessageFormat.format(
+ DfsText.get().shortReadOfBlock, Long.valueOf(pos),
+ getFileName(), Long.valueOf(0), Long.valueOf(0)));
+
+ byte[] buf = new byte[size];
+ rc.position(pos);
+ int cnt = read(rc, ByteBuffer.wrap(buf, 0, size));
+ ctx.stats.readBlockBytes += cnt;
+ if (cnt != size) {
+ if (0 <= len) {
+ throw new EOFException(MessageFormat.format(
+ DfsText.get().shortReadOfBlock, Long.valueOf(pos),
+ getFileName(), Integer.valueOf(size),
+ Integer.valueOf(cnt)));
+ }
+
+ // Assume the entire thing was read in a single shot, compact
+ // the buffer to only the space required.
+ byte[] n = new byte[cnt];
+ System.arraycopy(buf, 0, n, 0, n.length);
+ buf = n;
+ } else if (len < 0) {
+ // With no length at the start of the read, the channel should
+ // have the length available at the end.
+ length = len = rc.size();
+ }
+
+ return new DfsBlock(key, pos, buf);
+ } finally {
+ if (rc != fileChannel) {
+ rc.close();
+ }
+ ctx.stats.readBlockMicros += elapsedMicros(start);
+ }
+ }
+
+ static int read(ReadableChannel rc, ByteBuffer buf) throws IOException {
+ int n;
+ do {
+ n = rc.read(buf);
+ } while (0 < n && buf.hasRemaining());
+ return buf.position();
+ }
+
+ static long elapsedMicros(long start) {
+ return (System.nanoTime() - start) / 1000L;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java
index 64a63d7..bd4b4d2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java
@@ -75,7 +75,7 @@
table = new Entry[1 << TABLE_BITS];
}
- Entry get(DfsPackKey key, long position) {
+ Entry get(DfsStreamKey key, long position) {
Entry e = table[hash(position)];
for (; e != null; e = e.tableNext) {
if (e.offset == position && key.equals(e.pack)) {
@@ -86,7 +86,7 @@
return null;
}
- void put(DfsPackKey key, long offset, int objectType, byte[] data) {
+ void put(DfsStreamKey key, long offset, int objectType, byte[] data) {
if (data.length > maxByteCount)
return; // Too large to cache.
@@ -189,7 +189,7 @@
}
static class Entry {
- final DfsPackKey pack;
+ final DfsStreamKey pack;
final long offset;
final int type;
final byte[] data;
@@ -198,7 +198,7 @@
Entry lruPrev;
Entry lruNext;
- Entry(DfsPackKey key, long offset, int type, byte[] data) {
+ Entry(DfsStreamKey key, long offset, int type, byte[] data) {
this.pack = key;
this.offset = offset;
this.type = type;
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 4a33fb8..dae922e 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
@@ -52,9 +52,9 @@
import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
-/** A cached slice of a {@link DfsPackFile}. */
+/** A cached slice of a {@link BlockBasedFile}. */
final class DfsBlock {
- final DfsPackKey pack;
+ final DfsStreamKey stream;
final long start;
@@ -62,8 +62,8 @@
private final byte[] block;
- DfsBlock(DfsPackKey p, long pos, byte[] buf) {
- pack = p;
+ DfsBlock(DfsStreamKey p, long pos, byte[] buf) {
+ stream = p;
start = pos;
end = pos + buf.length;
block = buf;
@@ -73,8 +73,8 @@
return block.length;
}
- boolean contains(DfsPackKey want, long pos) {
- return pack == want && start <= pos && pos < end;
+ boolean contains(DfsStreamKey want, long pos) {
+ return stream.equals(want) && start <= pos && pos < end;
}
int copy(long pos, byte[] dstbuf, int dstoff, int cnt) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
index ef0b80c..45202b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
@@ -45,23 +45,20 @@
package org.eclipse.jgit.internal.storage.dfs;
import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.locks.ReentrantLock;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText;
/**
- * Caches slices of a {@link DfsPackFile} in memory for faster read access.
+ * Caches slices of a {@link BlockBasedFile} in memory for faster read access.
* <p>
* The DfsBlockCache serves as a Java based "buffer cache", loading segments of
- * a DfsPackFile into the JVM heap prior to use. As JGit often wants to do reads
- * of only tiny slices of a file, the DfsBlockCache tries to smooth out these
- * tiny reads into larger block-sized IO operations.
+ * a BlockBasedFile into the JVM heap prior to use. As JGit often wants to do
+ * reads of only tiny slices of a file, the DfsBlockCache tries to smooth out
+ * these tiny reads into larger block-sized IO operations.
* <p>
* Whenever a cache miss occurs, loading is invoked by exactly one thread for
* the given <code>(DfsPackKey,position)</code> key tuple. This is ensured by an
@@ -108,14 +105,7 @@
* settings, usually too low of a limit.
*/
public static void reconfigure(DfsBlockCacheConfig cfg) {
- DfsBlockCache nc = new DfsBlockCache(cfg);
- DfsBlockCache oc = cache;
- cache = nc;
-
- if (oc != null) {
- for (DfsPackFile pack : oc.getPackFiles())
- pack.key.cachedSize.set(0);
- }
+ cache = new DfsBlockCache(cfg);
}
/** @return the currently active DfsBlockCache. */
@@ -153,12 +143,6 @@
/** As {@link #blockSize} is a power of 2, bits to shift for a / blockSize. */
private final int blockSizeShift;
- /** Cache of pack files, indexed by description. */
- private final Map<DfsPackDescription, DfsPackFile> packCache;
-
- /** View of pack files in the pack cache. */
- private final Collection<DfsPackFile> packFiles;
-
/** Number of times a block was found in the cache. */
private final AtomicLong statHit;
@@ -194,13 +178,12 @@
blockSizeShift = Integer.numberOfTrailingZeros(blockSize);
clockLock = new ReentrantLock(true /* fair */);
- clockHand = new Ref<>(new DfsPackKey(), -1, 0, null);
+ String none = ""; //$NON-NLS-1$
+ clockHand = new Ref<>(
+ DfsStreamKey.of(new DfsRepositoryDescription(none), none),
+ -1, 0, null);
clockHand.next = clockHand;
- packCache = new ConcurrentHashMap<>(
- 16, 0.75f, 1);
- packFiles = Collections.unmodifiableCollection(packCache.values());
-
statHit = new AtomicLong();
statMiss = new AtomicLong();
}
@@ -249,38 +232,6 @@
return statEvict;
}
- /**
- * Get the pack files stored in this cache.
- *
- * @return a collection of pack files, some of which may not actually be
- * present; the caller should check the pack's cached size.
- */
- public Collection<DfsPackFile> getPackFiles() {
- return packFiles;
- }
-
- DfsPackFile getOrCreate(DfsPackDescription dsc, DfsPackKey key) {
- // TODO This table grows without bound. It needs to clean up
- // entries that aren't in cache anymore, and aren't being used
- // by a live DfsObjDatabase reference.
-
- DfsPackFile pack = packCache.get(dsc);
- if (pack != null && !pack.invalid()) {
- return pack;
- }
-
- // 'pack' either didn't exist or was invalid. Compute a new
- // entry atomically (guaranteed by ConcurrentHashMap).
- return packCache.compute(dsc, (k, v) -> {
- if (v != null && !v.invalid()) { // valid value added by
- return v; // another thread
- } else {
- return new DfsPackFile(
- this, dsc, key != null ? key : new DfsPackKey());
- }
- });
- }
-
private int hash(int packHash, long off) {
return packHash + (int) (off >>> blockSizeShift);
}
@@ -302,26 +253,29 @@
/**
* Lookup a cached object, creating and loading it if it doesn't exist.
*
- * @param pack
+ * @param file
* the pack that "contains" the cached object.
* @param position
* offset within <code>pack</code> of the object.
* @param ctx
* current thread's reader.
+ * @param fileChannel
+ * optional channel to read {@code pack}.
* @return the object reference.
* @throws IOException
* the reference was not in the cache and could not be loaded.
*/
- DfsBlock getOrLoad(DfsPackFile pack, long position, DfsReader ctx)
- throws IOException {
+ DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx,
+ @Nullable ReadableChannel fileChannel) throws IOException {
final long requestedPosition = position;
- position = pack.alignToBlock(position);
+ position = file.alignToBlock(position);
- DfsPackKey key = pack.key;
+ DfsStreamKey key = file.key;
int slot = slot(key, position);
HashEntry e1 = table.get(slot);
DfsBlock v = scan(e1, key, position);
- if (v != null) {
+ if (v != null && v.contains(key, requestedPosition)) {
+ ctx.stats.blockCacheHit++;
statHit.incrementAndGet();
return v;
}
@@ -334,6 +288,7 @@
if (e2 != e1) {
v = scan(e2, key, position);
if (v != null) {
+ ctx.stats.blockCacheHit++;
statHit.incrementAndGet();
creditSpace(blockSize);
return v;
@@ -343,7 +298,7 @@
statMiss.incrementAndGet();
boolean credit = true;
try {
- v = pack.readOneBlock(position, ctx);
+ v = file.readOneBlock(requestedPosition, ctx, fileChannel);
credit = false;
} finally {
if (credit)
@@ -356,7 +311,6 @@
e2 = table.get(slot);
}
- key.cachedSize.addAndGet(v.size());
Ref<DfsBlock> ref = new Ref<>(key, position, v.size(), v);
ref.hot = true;
for (;;) {
@@ -372,9 +326,9 @@
// If the block size changed from the default, it is possible the block
// that was loaded is the wrong block for the requested position.
- if (v.contains(pack.key, requestedPosition))
+ if (v.contains(file.key, requestedPosition))
return v;
- return getOrLoad(pack, requestedPosition, ctx);
+ return getOrLoad(file, requestedPosition, ctx, fileChannel);
}
@SuppressWarnings("unchecked")
@@ -404,7 +358,6 @@
dead.next = null;
dead.value = null;
live -= dead.size;
- dead.pack.cachedSize.addAndGet(-dead.size);
statEvict++;
} while (maxBytes < live);
clockHand = prev;
@@ -437,10 +390,14 @@
}
void put(DfsBlock v) {
- put(v.pack, v.start, v.size(), v);
+ put(v.stream, v.start, v.size(), v);
}
- <T> Ref<T> put(DfsPackKey key, long pos, int size, T v) {
+ <T> Ref<T> putRef(DfsStreamKey key, long size, T v) {
+ return put(key, 0, (int) Math.min(size, Integer.MAX_VALUE), v);
+ }
+
+ <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) {
int slot = slot(key, pos);
HashEntry e1 = table.get(slot);
Ref<T> ref = scanRef(e1, key, pos);
@@ -460,7 +417,6 @@
}
}
- key.cachedSize.addAndGet(size);
ref = new Ref<>(key, pos, size, v);
ref.hot = true;
for (;;) {
@@ -476,12 +432,12 @@
return ref;
}
- boolean contains(DfsPackKey key, long position) {
+ boolean contains(DfsStreamKey key, long position) {
return scan(table.get(slot(key, position)), key, position) != null;
}
@SuppressWarnings("unchecked")
- <T> T get(DfsPackKey key, long position) {
+ <T> T get(DfsStreamKey key, long position) {
T val = (T) scan(table.get(slot(key, position)), key, position);
if (val == null)
statMiss.incrementAndGet();
@@ -490,31 +446,36 @@
return val;
}
- private <T> T scan(HashEntry n, DfsPackKey pack, long position) {
- Ref<T> r = scanRef(n, pack, position);
+ private <T> T scan(HashEntry n, DfsStreamKey key, long position) {
+ Ref<T> r = scanRef(n, key, position);
return r != null ? r.get() : null;
}
+ <T> Ref<T> getRef(DfsStreamKey key) {
+ Ref<T> r = scanRef(table.get(slot(key, 0)), key, 0);
+ if (r != null)
+ statHit.incrementAndGet();
+ else
+ statMiss.incrementAndGet();
+ return r;
+ }
+
@SuppressWarnings("unchecked")
- private <T> Ref<T> scanRef(HashEntry n, DfsPackKey pack, long position) {
+ private <T> Ref<T> scanRef(HashEntry n, DfsStreamKey key, long position) {
for (; n != null; n = n.next) {
Ref<T> r = n.ref;
- if (r.pack == pack && r.position == position)
+ if (r.position == position && r.key.equals(key))
return r.get() != null ? r : null;
}
return null;
}
- void remove(DfsPackFile pack) {
- packCache.remove(pack.getPackDescription());
+ private int slot(DfsStreamKey key, long position) {
+ return (hash(key.hash, position) >>> 1) % tableSize;
}
- private int slot(DfsPackKey pack, long position) {
- return (hash(pack.hash, position) >>> 1) % tableSize;
- }
-
- private ReentrantLock lockFor(DfsPackKey pack, long position) {
- return loadLocks[(hash(pack.hash, position) >>> 1) % loadLocks.length];
+ private ReentrantLock lockFor(DfsStreamKey key, long position) {
+ return loadLocks[(hash(key.hash, position) >>> 1) % loadLocks.length];
}
private static HashEntry clean(HashEntry top) {
@@ -540,15 +501,15 @@
}
static final class Ref<T> {
- final DfsPackKey pack;
+ final DfsStreamKey key;
final long position;
final int size;
volatile T value;
Ref next;
volatile boolean hot;
- Ref(DfsPackKey pack, long position, int size, T v) {
- this.pack = pack;
+ Ref(DfsStreamKey key, long position, int size, T v) {
+ this.key = key;
this.position = position;
this.size = size;
this.value = v;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
new file mode 100644
index 0000000..f90ba7d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.dfs;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.jgit.errors.CorruptPackIndexException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.fsck.FsckError;
+import org.eclipse.jgit.internal.fsck.FsckError.CorruptIndex;
+import org.eclipse.jgit.internal.fsck.FsckPackParser;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.transport.PackedObjectInfo;
+
+/** Verify the validity and connectivity of a DFS repository. */
+public class DfsFsck {
+ private final DfsRepository repo;
+
+ private final DfsObjDatabase objdb;
+
+ private final DfsReader ctx;
+
+ private ObjectChecker objChecker = new ObjectChecker();
+
+ /**
+ * Initialize DFS fsck.
+ *
+ * @param repository
+ * the dfs repository to check.
+ */
+ public DfsFsck(DfsRepository repository) {
+ repo = repository;
+ objdb = repo.getObjectDatabase();
+ ctx = objdb.newReader();
+ }
+
+
+ /**
+ * Verify the integrity and connectivity of all objects in the object
+ * database.
+ *
+ * @param pm
+ * callback to provide progress feedback during the check.
+ * @return all errors about the repository.
+ * @throws IOException
+ * if encounters IO errors during the process.
+ */
+ public FsckError check(ProgressMonitor pm) throws IOException {
+ FsckError errors = new FsckError();
+ try {
+ for (DfsPackFile pack : objdb.getPacks()) {
+ DfsPackDescription packDesc = pack.getPackDescription();
+ try (ReadableChannel channel = repo.getObjectDatabase()
+ .openFile(packDesc, PackExt.PACK)) {
+ List<PackedObjectInfo> objectsInPack;
+ FsckPackParser parser = new FsckPackParser(
+ repo.getObjectDatabase(), channel);
+ parser.setObjectChecker(objChecker);
+ parser.overwriteObjectCount(packDesc.getObjectCount());
+ parser.parse(pm);
+ errors.getCorruptObjects()
+ .addAll(parser.getCorruptObjects());
+ objectsInPack = parser.getSortedObjectList(null);
+ parser.verifyIndex(objectsInPack, pack.getPackIndex(ctx));
+ } catch (MissingObjectException e) {
+ errors.getMissingObjects().add(e.getObjectId());
+ } catch (CorruptPackIndexException e) {
+ errors.getCorruptIndices().add(new CorruptIndex(
+ pack.getPackDescription()
+ .getFileName(PackExt.INDEX),
+ e.getErrorType()));
+ }
+ }
+
+ try (ObjectWalk ow = new ObjectWalk(ctx)) {
+ for (Ref r : repo.getAllRefs().values()) {
+ try {
+ RevObject tip = ow.parseAny(r.getObjectId());
+ if (r.getLeaf().getName().startsWith(Constants.R_HEADS)) {
+ // check if heads point to a commit object
+ if (tip.getType() != Constants.OBJ_COMMIT) {
+ errors.getNonCommitHeads()
+ .add(r.getLeaf().getName());
+ }
+ }
+ ow.markStart(tip);
+ ow.checkConnectivity();
+ ow.markUninteresting(tip);
+ } catch (MissingObjectException e) {
+ errors.getMissingObjects().add(e.getObjectId());
+ }
+ }
+ }
+ } finally {
+ ctx.close();
+ }
+ return errors;
+ }
+
+ /**
+ * Use a customized object checker instead of the default one. Caller can
+ * specify a skip list to ignore some errors.
+ *
+ * @param objChecker
+ * A customized object checker.
+ */
+ public void setObjectChecker(ObjectChecker objChecker) {
+ this.objChecker = objChecker;
+ }
+}
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 de447de..ce2b053 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
@@ -53,6 +53,7 @@
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
+import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
import java.io.IOException;
import java.util.ArrayList;
@@ -111,7 +112,8 @@
private List<DfsPackFile> packsBefore;
private List<DfsPackFile> expiredGarbagePacks;
- private Set<ObjectId> allHeads;
+ private Set<ObjectId> allHeadsAndTags;
+ private Set<ObjectId> allTags;
private Set<ObjectId> nonHeads;
private Set<ObjectId> txnHeads;
private Set<ObjectId> tagTargets;
@@ -233,7 +235,7 @@
JGitText.get().supportOnlyPackIndexVersion2);
startTimeMillis = SystemReader.getInstance().getCurrentTime();
- ctx = (DfsReader) objdb.newReader();
+ ctx = objdb.newReader();
try {
refdb.refresh();
objdb.clearCache();
@@ -241,23 +243,42 @@
Collection<Ref> refsBefore = getAllRefs();
readPacksBefore();
- allHeads = new HashSet<>();
+ Set<ObjectId> allHeads = new HashSet<>();
+ allHeadsAndTags = new HashSet<>();
+ allTags = new HashSet<>();
nonHeads = new HashSet<>();
txnHeads = new HashSet<>();
tagTargets = new HashSet<>();
for (Ref ref : refsBefore) {
- if (ref.isSymbolic() || ref.getObjectId() == null)
+ if (ref.isSymbolic() || ref.getObjectId() == null) {
continue;
- if (isHead(ref) || isTag(ref))
+ }
+ if (isHead(ref)) {
allHeads.add(ref.getObjectId());
- else if (RefTreeNames.isRefTree(refdb, ref.getName()))
+ } else if (isTag(ref)) {
+ allTags.add(ref.getObjectId());
+ } else if (RefTreeNames.isRefTree(refdb, ref.getName())) {
txnHeads.add(ref.getObjectId());
- else
+ } else {
nonHeads.add(ref.getObjectId());
- if (ref.getPeeledObjectId() != null)
+ }
+ if (ref.getPeeledObjectId() != null) {
tagTargets.add(ref.getPeeledObjectId());
+ }
}
- tagTargets.addAll(allHeads);
+ // Don't exclude tags that are also branch tips.
+ allTags.removeAll(allHeads);
+ allHeadsAndTags.addAll(allHeads);
+ allHeadsAndTags.addAll(allTags);
+
+ // Hoist all branch tips and tags earlier in the pack file
+ tagTargets.addAll(allHeadsAndTags);
+
+ // Combine the GC_REST objects into the GC pack if requested
+ if (packConfig.getSinglePack()) {
+ allHeadsAndTags.addAll(nonHeads);
+ nonHeads.clear();
+ }
boolean rollback = true;
try {
@@ -413,12 +434,12 @@
}
private void packHeads(ProgressMonitor pm) throws IOException {
- if (allHeads.isEmpty())
+ if (allHeadsAndTags.isEmpty())
return;
try (PackWriter pw = newPackWriter()) {
pw.setTagTargets(tagTargets);
- pw.preparePack(pm, allHeads, PackWriter.NONE);
+ pw.preparePack(pm, allHeadsAndTags, NONE, NONE, allTags);
if (0 < pw.getObjectCount())
writePack(GC, pw, pm,
estimateGcPackSize(INSERT, RECEIVE, COMPACT, GC));
@@ -432,7 +453,7 @@
try (PackWriter pw = newPackWriter()) {
for (ObjectIdSet packedObjs : newPackObj)
pw.excludeObjects(packedObjs);
- pw.preparePack(pm, nonHeads, allHeads);
+ pw.preparePack(pm, nonHeads, allHeadsAndTags);
if (0 < pw.getObjectCount())
writePack(GC_REST, pw, pm,
estimateGcPackSize(INSERT, RECEIVE, COMPACT, GC_REST));
@@ -446,7 +467,7 @@
try (PackWriter pw = newPackWriter()) {
for (ObjectIdSet packedObjs : newPackObj)
pw.excludeObjects(packedObjs);
- pw.preparePack(pm, txnHeads, PackWriter.NONE);
+ pw.preparePack(pm, txnHeads, NONE);
if (0 < pw.getObjectCount())
writePack(GC_TXN, pw, pm, 0 /* unknown pack size */);
}
@@ -542,22 +563,25 @@
try (DfsOutputStream out = objdb.writeFile(pack, PACK)) {
pw.writePack(pm, pm, out);
pack.addFileExt(PACK);
+ pack.setBlockSize(PACK, out.blockSize());
}
- try (CountingOutputStream cnt =
- new CountingOutputStream(objdb.writeFile(pack, INDEX))) {
+ try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) {
+ CountingOutputStream cnt = new CountingOutputStream(out);
pw.writeIndex(cnt);
pack.addFileExt(INDEX);
pack.setFileSize(INDEX, cnt.getCount());
+ pack.setBlockSize(INDEX, out.blockSize());
pack.setIndexVersion(pw.getIndexVersion());
}
if (pw.prepareBitmapIndex(pm)) {
- try (CountingOutputStream cnt = new CountingOutputStream(
- objdb.writeFile(pack, BITMAP_INDEX))) {
+ try (DfsOutputStream out = objdb.writeFile(pack, BITMAP_INDEX)) {
+ CountingOutputStream cnt = new CountingOutputStream(out);
pw.writeBitmapIndex(cnt);
pack.addFileExt(BITMAP_INDEX);
pack.setFileSize(BITMAP_INDEX, cnt.getCount());
+ pack.setBlockSize(BITMAP_INDEX, out.blockSize());
}
}
@@ -566,8 +590,6 @@
pack.setLastModified(startTimeMillis);
newPackStats.add(stats);
newPackObj.add(pw.getObjectSet());
-
- DfsBlockCache.getInstance().getOrCreate(pack, null);
return pack;
}
}
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 fd72756..01654d4 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
@@ -104,7 +104,7 @@
ObjectIdOwnerMap<PackedObjectInfo> objectMap;
DfsBlockCache cache;
- DfsPackKey packKey;
+ DfsStreamKey packKey;
DfsPackDescription packDsc;
PackStream packOut;
private boolean rollback;
@@ -221,7 +221,7 @@
db.commitPack(Collections.singletonList(packDsc), null);
rollback = false;
- DfsPackFile p = cache.getOrCreate(packDsc, packKey);
+ DfsPackFile p = new DfsPackFile(cache, packDsc);
if (index != null)
p.setPackIndex(index);
db.addPack(p);
@@ -281,8 +281,10 @@
rollback = true;
packDsc = db.newPack(DfsObjDatabase.PackSource.INSERT);
- packOut = new PackStream(db.writeFile(packDsc, PACK));
- packKey = new DfsPackKey();
+ DfsOutputStream dfsOut = db.writeFile(packDsc, PACK);
+ packDsc.setBlockSize(PACK, dfsOut.blockSize());
+ packOut = new PackStream(dfsOut);
+ packKey = packDsc.getStreamKey(PACK);
// Write the header as though it were a single object pack.
byte[] buf = packOut.hdrBuf;
@@ -312,13 +314,14 @@
packIndex = PackIndex.read(buf.openInputStream());
}
- DfsOutputStream os = db.writeFile(pack, INDEX);
- try (CountingOutputStream cnt = new CountingOutputStream(os)) {
+ try (DfsOutputStream os = db.writeFile(pack, INDEX)) {
+ CountingOutputStream cnt = new CountingOutputStream(os);
if (buf != null)
buf.writeTo(cnt, null);
else
index(cnt, packHash, list);
pack.addFileExt(INDEX);
+ pack.setBlockSize(INDEX, os.blockSize());
pack.setFileSize(INDEX, cnt.getCount());
} finally {
if (buf != null) {
@@ -530,7 +533,7 @@
}
private class Reader extends ObjectReader {
- private final DfsReader ctx = new DfsReader(db);
+ private final DfsReader ctx = db.newReader();
@Override
public ObjectReader newReader() {
@@ -633,11 +636,11 @@
private final int type;
private final long size;
- private final DfsPackKey srcPack;
+ private final DfsStreamKey srcPack;
private final long pos;
StreamLoader(ObjectId id, int type, long sz,
- DfsPackKey key, long pos) {
+ DfsStreamKey key, long pos) {
this.id = id;
this.type = type;
this.size = sz;
@@ -647,7 +650,7 @@
@Override
public ObjectStream openStream() throws IOException {
- final DfsReader ctx = new DfsReader(db);
+ final DfsReader ctx = db.newReader();
if (srcPack != packKey) {
try {
// Post DfsInserter.flush() use the normal code path.
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 b1cb72d..76189c1 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
@@ -170,7 +170,7 @@
}
@Override
- public ObjectReader newReader() {
+ public DfsReader newReader() {
return new DfsReader(this);
}
@@ -464,8 +464,8 @@
DfsPackFile oldPack = forReuse.remove(dsc);
if (oldPack != null) {
list.add(oldPack);
- } else {
- list.add(cache.getOrCreate(dsc, null));
+ } else if (dsc.hasFileExt(PackExt.PACK)) {
+ list.add(new DfsPackFile(cache, dsc));
foundNew = true;
}
}
@@ -482,8 +482,7 @@
}
private static Map<DfsPackDescription, DfsPackFile> reuseMap(PackList old) {
- Map<DfsPackDescription, DfsPackFile> forReuse
- = new HashMap<>();
+ Map<DfsPackDescription, DfsPackFile> forReuse = new HashMap<>();
for (DfsPackFile p : old.packs) {
if (p.invalid()) {
// The pack instance is corrupted, and cannot be safely used
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index 0a29ac5..ac14c0b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -201,7 +201,7 @@
pm = NullProgressMonitor.INSTANCE;
DfsObjDatabase objdb = repo.getObjectDatabase();
- try (DfsReader ctx = (DfsReader) objdb.newReader()) {
+ try (DfsReader ctx = objdb.newReader()) {
PackConfig pc = new PackConfig(repo);
pc.setIndexVersion(2);
pc.setDeltaCompress(false);
@@ -370,27 +370,23 @@
private static void writePack(DfsObjDatabase objdb,
DfsPackDescription pack,
PackWriter pw, ProgressMonitor pm) throws IOException {
- DfsOutputStream out = objdb.writeFile(pack, PACK);
- try {
+ try (DfsOutputStream out = objdb.writeFile(pack, PACK)) {
pw.writePack(pm, pm, out);
pack.addFileExt(PACK);
- } finally {
- out.close();
+ pack.setBlockSize(PACK, out.blockSize());
}
}
private static void writeIndex(DfsObjDatabase objdb,
DfsPackDescription pack,
PackWriter pw) throws IOException {
- DfsOutputStream out = objdb.writeFile(pack, INDEX);
- try {
+ try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) {
CountingOutputStream cnt = new CountingOutputStream(out);
pw.writeIndex(cnt);
pack.addFileExt(INDEX);
pack.setFileSize(INDEX, cnt.getCount());
+ pack.setBlockSize(INDEX, out.blockSize());
pack.setIndexVersion(pw.getIndexVersion());
- } finally {
- out.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
index e825f1a..58a006e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java
@@ -45,8 +45,7 @@
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Arrays;
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.pack.PackExt;
@@ -62,25 +61,16 @@
*/
public class DfsPackDescription implements Comparable<DfsPackDescription> {
private final DfsRepositoryDescription repoDesc;
-
private final String packName;
-
private PackSource packSource;
-
private long lastModified;
-
- private final Map<PackExt, Long> sizeMap;
-
+ private long[] sizeMap;
+ private int[] blockSizeMap;
private long objectCount;
-
private long deltaCount;
-
private PackStatistics stats;
-
private int extensions;
-
private int indexVersion;
-
private long estimatedPackSize;
/**
@@ -102,7 +92,10 @@
this.repoDesc = repoDesc;
int dot = name.lastIndexOf('.');
this.packName = (dot < 0) ? name : name.substring(0, dot);
- this.sizeMap = new HashMap<>(PackExt.values().length * 2);
+
+ int extCnt = PackExt.values().length;
+ sizeMap = new long[extCnt];
+ blockSizeMap = new int[extCnt];
}
/** @return description of the repository. */
@@ -138,6 +131,15 @@
return packName + '.' + ext.getExtension();
}
+ /**
+ * @param ext
+ * the file extension.
+ * @return cache key for use by the block cache.
+ */
+ public DfsStreamKey getStreamKey(PackExt ext) {
+ return DfsStreamKey.of(getRepositoryDescription(), getFileName(ext));
+ }
+
/** @return the source of the pack. */
public PackSource getPackSource() {
return packSource;
@@ -177,7 +179,11 @@
* @return {@code this}
*/
public DfsPackDescription setFileSize(PackExt ext, long bytes) {
- sizeMap.put(ext, Long.valueOf(Math.max(0, bytes)));
+ int i = ext.getPosition();
+ if (i >= sizeMap.length) {
+ sizeMap = Arrays.copyOf(sizeMap, i + 1);
+ }
+ sizeMap[i] = Math.max(0, bytes);
return this;
}
@@ -187,8 +193,36 @@
* @return size of the file, in bytes. If 0 the file size is not yet known.
*/
public long getFileSize(PackExt ext) {
- Long size = sizeMap.get(ext);
- return size == null ? 0 : size.longValue();
+ int i = ext.getPosition();
+ return i < sizeMap.length ? sizeMap[i] : 0;
+ }
+
+ /**
+ * @param ext
+ * the file extension.
+ * @return blockSize of the file, in bytes. If 0 the blockSize size is not
+ * yet known and may be discovered when opening the file.
+ */
+ public int getBlockSize(PackExt ext) {
+ int i = ext.getPosition();
+ return i < blockSizeMap.length ? blockSizeMap[i] : 0;
+ }
+
+ /**
+ * @param ext
+ * the file extension.
+ * @param blockSize
+ * blockSize of the file, in bytes. If 0 the blockSize is not
+ * known and will be determined on first read.
+ * @return {@code this}
+ */
+ public DfsPackDescription setBlockSize(PackExt ext, int blockSize) {
+ int i = ext.getPosition();
+ if (i >= blockSizeMap.length) {
+ blockSizeMap = Arrays.copyOf(blockSizeMap, i + 1);
+ }
+ blockSizeMap[i] = Math.max(0, blockSize);
+ return this;
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index f15d427..2326219 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -72,7 +72,6 @@
import org.eclipse.jgit.internal.storage.file.PackIndex;
import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
-import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
@@ -88,53 +87,7 @@
* delta packed format yielding high compression of lots of object where some
* objects are similar.
*/
-public final class DfsPackFile {
- /**
- * File offset used to cache {@link #index} in {@link DfsBlockCache}.
- * <p>
- * To better manage memory, the forward index is stored as a single block in
- * the block cache under this file position. A negative value is used
- * because it cannot occur in a normal pack file, and it is less likely to
- * collide with a valid data block from the file as the high bits will all
- * be set when treated as an unsigned long by the cache code.
- */
- private static final long POS_INDEX = -1;
-
- /** Offset used to cache {@link #reverseIndex}. See {@link #POS_INDEX}. */
- private static final long POS_REVERSE_INDEX = -2;
-
- /** Offset used to cache {@link #bitmapIndex}. See {@link #POS_INDEX}. */
- private static final long POS_BITMAP_INDEX = -3;
-
- /** Cache that owns this pack file and its data. */
- private final DfsBlockCache cache;
-
- /** Description of the pack file's storage. */
- private final DfsPackDescription packDesc;
-
- /** Unique identity of this pack while in-memory. */
- final DfsPackKey key;
-
- /**
- * Total number of bytes in this pack file.
- * <p>
- * This field initializes to -1 and gets populated when a block is loaded.
- */
- volatile long length;
-
- /**
- * Preferred alignment for loading blocks from the backing file.
- * <p>
- * It is initialized to 0 and filled in on the first read made from the
- * file. Block sizes may be odd, e.g. 4091, caused by the underling DFS
- * storing 4091 user bytes and 5 bytes block metadata into a lower level
- * 4096 byte block on disk.
- */
- private volatile int blockSize;
-
- /** True once corruption has been detected that cannot be worked around. */
- private volatile boolean invalid;
-
+public final class DfsPackFile extends BlockBasedFile {
/**
* Lock for initialization of {@link #index} and {@link #corruptObjects}.
* <p>
@@ -167,22 +120,22 @@
* cache that owns the pack data.
* @param desc
* description of the pack within the DFS.
- * @param key
- * interned key used to identify blocks in the block cache.
*/
- DfsPackFile(DfsBlockCache cache, DfsPackDescription desc, DfsPackKey key) {
- this.cache = cache;
- this.packDesc = desc;
- this.key = key;
+ DfsPackFile(DfsBlockCache cache, DfsPackDescription desc) {
+ super(cache, desc, PACK);
- length = desc.getFileSize(PACK);
- if (length <= 0)
- length = -1;
+ int bs = desc.getBlockSize(PACK);
+ if (bs > 0) {
+ setBlockSize(bs);
+ }
+
+ long sz = desc.getFileSize(PACK);
+ length = sz > 0 ? sz : -1;
}
/** @return description that was originally used to configure this pack file. */
public DfsPackDescription getPackDescription() {
- return packDesc;
+ return desc;
}
/**
@@ -193,24 +146,11 @@
return idxref != null && idxref.has();
}
- /** @return bytes cached in memory for this pack, excluding the index. */
- public long getCachedSize() {
- return key.cachedSize.get();
- }
-
- String getPackName() {
- return packDesc.getFileName(PACK);
- }
-
- void setBlockSize(int newSize) {
- blockSize = newSize;
- }
-
void setPackIndex(PackIndex idx) {
long objCnt = idx.getObjectCount();
int recSize = Constants.OBJECT_ID_LENGTH + 8;
- int sz = (int) Math.min(objCnt * recSize, Integer.MAX_VALUE);
- index = cache.put(key, POS_INDEX, sz, idx);
+ long sz = objCnt * recSize;
+ index = cache.putRef(desc.getStreamKey(INDEX), sz, idx);
}
/**
@@ -236,7 +176,7 @@
}
if (invalid)
- throw new PackInvalidException(getPackName());
+ throw new PackInvalidException(getFileName());
Repository.getGlobalListenerList()
.dispatch(new BeforeDfsPackIndexLoadedEvent(this));
@@ -249,9 +189,21 @@
return idx;
}
+ DfsStreamKey idxKey = desc.getStreamKey(INDEX);
+ idxref = cache.getRef(idxKey);
+ if (idxref != null) {
+ PackIndex idx = idxref.get();
+ if (idx != null) {
+ index = idxref;
+ return idx;
+ }
+ }
+
PackIndex idx;
try {
- ReadableChannel rc = ctx.db.openFile(packDesc, INDEX);
+ ctx.stats.readIdx++;
+ long start = System.nanoTime();
+ ReadableChannel rc = ctx.db.openFile(desc, INDEX);
try {
InputStream in = Channels.newInputStream(rc);
int wantSize = 8192;
@@ -260,25 +212,22 @@
bs = (wantSize / bs) * bs;
else if (bs <= 0)
bs = wantSize;
- in = new BufferedInputStream(in, bs);
- idx = PackIndex.read(in);
+ idx = PackIndex.read(new BufferedInputStream(in, bs));
+ ctx.stats.readIdxBytes += rc.position();
} finally {
rc.close();
+ ctx.stats.readIdxMicros += elapsedMicros(start);
}
} catch (EOFException e) {
invalid = true;
- IOException e2 = new IOException(MessageFormat.format(
+ throw new IOException(MessageFormat.format(
DfsText.get().shortReadOfIndex,
- packDesc.getFileName(INDEX)));
- e2.initCause(e);
- throw e2;
+ desc.getFileName(INDEX)), e);
} catch (IOException e) {
invalid = true;
- IOException e2 = new IOException(MessageFormat.format(
+ throw new IOException(MessageFormat.format(
DfsText.get().cannotReadIndex,
- packDesc.getFileName(INDEX)));
- e2.initCause(e);
- throw e2;
+ desc.getFileName(INDEX)), e);
}
setPackIndex(idx);
@@ -287,12 +236,13 @@
}
final boolean isGarbage() {
- return packDesc.getPackSource() == UNREACHABLE_GARBAGE;
+ return desc.getPackSource() == UNREACHABLE_GARBAGE;
}
PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
- if (invalid || isGarbage())
+ if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX))
return null;
+
DfsBlockCache.Ref<PackBitmapIndex> idxref = bitmapIndex;
if (idxref != null) {
PackBitmapIndex idx = idxref.get();
@@ -300,9 +250,6 @@
return idx;
}
- if (!packDesc.hasFileExt(PackExt.BITMAP_INDEX))
- return null;
-
synchronized (initLock) {
idxref = bitmapIndex;
if (idxref != null) {
@@ -311,10 +258,22 @@
return idx;
}
+ DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
+ idxref = cache.getRef(bitmapKey);
+ if (idxref != null) {
+ PackBitmapIndex idx = idxref.get();
+ if (idx != null) {
+ bitmapIndex = idxref;
+ return idx;
+ }
+ }
+
long size;
PackBitmapIndex idx;
try {
- ReadableChannel rc = ctx.db.openFile(packDesc, BITMAP_INDEX);
+ ctx.stats.readBitmap++;
+ long start = System.nanoTime();
+ ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX);
try {
InputStream in = Channels.newInputStream(rc);
int wantSize = 8192;
@@ -329,23 +288,20 @@
} finally {
size = rc.position();
rc.close();
+ ctx.stats.readIdxBytes += size;
+ ctx.stats.readIdxMicros += elapsedMicros(start);
}
} catch (EOFException e) {
- IOException e2 = new IOException(MessageFormat.format(
+ throw new IOException(MessageFormat.format(
DfsText.get().shortReadOfIndex,
- packDesc.getFileName(BITMAP_INDEX)));
- e2.initCause(e);
- throw e2;
+ desc.getFileName(BITMAP_INDEX)), e);
} catch (IOException e) {
- IOException e2 = new IOException(MessageFormat.format(
+ throw new IOException(MessageFormat.format(
DfsText.get().cannotReadIndex,
- packDesc.getFileName(BITMAP_INDEX)));
- e2.initCause(e);
- throw e2;
+ desc.getFileName(BITMAP_INDEX)), e);
}
- bitmapIndex = cache.put(key, POS_BITMAP_INDEX,
- (int) Math.min(size, Integer.MAX_VALUE), idx);
+ bitmapIndex = cache.putRef(bitmapKey, size, idx);
return idx;
}
}
@@ -366,11 +322,21 @@
return revidx;
}
+ DfsStreamKey revKey =
+ new DfsStreamKey.ForReverseIndex(desc.getStreamKey(INDEX));
+ revref = cache.getRef(revKey);
+ if (revref != null) {
+ PackReverseIndex idx = revref.get();
+ if (idx != null) {
+ reverseIndex = revref;
+ return idx;
+ }
+ }
+
PackIndex idx = idx(ctx);
PackReverseIndex revidx = new PackReverseIndex(idx);
- int sz = (int) Math.min(
- idx.getObjectCount() * 8, Integer.MAX_VALUE);
- reverseIndex = cache.put(key, POS_REVERSE_INDEX, sz, revidx);
+ long cnt = idx.getObjectCount();
+ reverseIndex = cache.putRef(revKey, cnt * 8, revidx);
return revidx;
}
}
@@ -421,7 +387,6 @@
/** Release all memory used by this DfsPackFile instance. */
public void close() {
- cache.remove(this);
index = null;
reverseIndex = null;
}
@@ -478,21 +443,42 @@
private void copyPackThroughCache(PackOutputStream out, DfsReader ctx)
throws IOException {
- long position = 12;
- long remaining = length - (12 + 20);
- while (0 < remaining) {
- DfsBlock b = cache.getOrLoad(this, position, ctx);
- int ptr = (int) (position - b.start);
- int n = (int) Math.min(b.size() - ptr, remaining);
- b.write(out, position, n);
- position += n;
- remaining -= n;
+ ReadableChannel rc = null;
+ try {
+ long position = 12;
+ long remaining = length - (12 + 20);
+ while (0 < remaining) {
+ DfsBlock b;
+ if (rc != null) {
+ b = cache.getOrLoad(this, position, ctx, rc);
+ } else {
+ b = cache.get(key, alignToBlock(position));
+ if (b == null) {
+ rc = ctx.db.openFile(desc, PACK);
+ int sz = ctx.getOptions().getStreamPackBufferSize();
+ if (sz > 0) {
+ rc.setReadAheadBytes(sz);
+ }
+ b = cache.getOrLoad(this, position, ctx, rc);
+ }
+ }
+
+ int ptr = (int) (position - b.start);
+ int n = (int) Math.min(b.size() - ptr, remaining);
+ b.write(out, position, n);
+ position += n;
+ remaining -= n;
+ }
+ } finally {
+ if (rc != null) {
+ rc.close();
+ }
}
}
private long copyPackBypassCache(PackOutputStream out, DfsReader ctx)
throws IOException {
- try (ReadableChannel rc = ctx.db.openFile(packDesc, PACK)) {
+ try (ReadableChannel rc = ctx.db.openFile(desc, PACK)) {
ByteBuffer buf = newCopyBuffer(out, rc);
if (ctx.getOptions().getStreamPackBufferSize() > 0)
rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize());
@@ -631,7 +617,7 @@
setCorrupt(src.offset);
throw new CorruptObjectException(MessageFormat.format(
JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackName()));
+ Long.valueOf(src.offset), getFileName()));
}
} else if (validate) {
assert(crc1 != null);
@@ -673,7 +659,7 @@
CorruptObjectException corruptObject = new CorruptObjectException(
MessageFormat.format(
JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackName()));
+ Long.valueOf(src.offset), getFileName()));
corruptObject.initCause(dataFormat);
StoredObjectRepresentationNotAvailableException gone;
@@ -735,24 +721,16 @@
if (crc2.getValue() != expectedCRC) {
throw new CorruptObjectException(MessageFormat.format(
JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackName()));
+ Long.valueOf(src.offset), getFileName()));
}
}
}
}
- boolean invalid() {
- return invalid;
- }
-
- void setInvalid() {
- invalid = true;
- }
-
private IOException packfileIsTruncated() {
invalid = true;
return new IOException(MessageFormat.format(
- JGitText.get().packfileIsTruncated, getPackName()));
+ JGitText.get().packfileIsTruncated, getFileName()));
}
private void readFully(long position, byte[] dstbuf, int dstoff, int cnt,
@@ -761,98 +739,8 @@
throw new EOFException();
}
- long alignToBlock(long pos) {
- int size = blockSize;
- if (size == 0)
- size = cache.getBlockSize();
- return (pos / size) * size;
- }
-
DfsBlock getOrLoadBlock(long pos, DfsReader ctx) throws IOException {
- return cache.getOrLoad(this, pos, ctx);
- }
-
- DfsBlock readOneBlock(long pos, DfsReader ctx)
- throws IOException {
- if (invalid)
- throw new PackInvalidException(getPackName());
-
- ReadableChannel rc = ctx.db.openFile(packDesc, PACK);
- try {
- int size = blockSize(rc);
- pos = (pos / size) * size;
-
- // If the size of the file is not yet known, try to discover it.
- // Channels may choose to return -1 to indicate they don't
- // know the length yet, in this case read up to the size unit
- // given by the caller, then recheck the length.
- long len = length;
- if (len < 0) {
- len = rc.size();
- if (0 <= len)
- length = len;
- }
-
- if (0 <= len && len < pos + size)
- size = (int) (len - pos);
- if (size <= 0)
- throw new EOFException(MessageFormat.format(
- DfsText.get().shortReadOfBlock, Long.valueOf(pos),
- getPackName(), Long.valueOf(0), Long.valueOf(0)));
-
- byte[] buf = new byte[size];
- rc.position(pos);
- int cnt = read(rc, ByteBuffer.wrap(buf, 0, size));
- if (cnt != size) {
- if (0 <= len) {
- throw new EOFException(MessageFormat.format(
- DfsText.get().shortReadOfBlock,
- Long.valueOf(pos),
- getPackName(),
- Integer.valueOf(size),
- Integer.valueOf(cnt)));
- }
-
- // Assume the entire thing was read in a single shot, compact
- // the buffer to only the space required.
- byte[] n = new byte[cnt];
- System.arraycopy(buf, 0, n, 0, n.length);
- buf = n;
- } else if (len < 0) {
- // With no length at the start of the read, the channel should
- // have the length available at the end.
- length = len = rc.size();
- }
-
- DfsBlock v = new DfsBlock(key, pos, buf);
- return v;
- } finally {
- rc.close();
- }
- }
-
- private int blockSize(ReadableChannel rc) {
- // If the block alignment is not yet known, discover it. Prefer the
- // larger size from either the cache or the file itself.
- int size = blockSize;
- if (size == 0) {
- size = rc.blockSize();
- if (size <= 0)
- size = cache.getBlockSize();
- else if (size < cache.getBlockSize())
- size = (cache.getBlockSize() / size) * size;
- blockSize = size;
- }
- return size;
- }
-
- private static int read(ReadableChannel rc, ByteBuffer buf)
- throws IOException {
- int n;
- do {
- n = rc.read(buf);
- } while (0 < n && buf.hasRemaining());
- return buf.position();
+ return cache.getOrLoad(this, pos, ctx, null);
}
ObjectLoader load(DfsReader ctx, long pos)
@@ -991,7 +879,7 @@
CorruptObjectException coe = new CorruptObjectException(
MessageFormat.format(
JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
- getPackName()));
+ getFileName()));
coe.initCause(dfe);
throw coe;
}
@@ -1139,7 +1027,7 @@
CorruptObjectException coe = new CorruptObjectException(
MessageFormat.format(
JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
- getPackName()));
+ getFileName()));
coe.initCause(dfe);
throw coe;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
index 6430ea9..fd99db1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackParser.java
@@ -94,7 +94,7 @@
private DfsPackDescription packDsc;
/** Key used during delta resolution reading delta chains. */
- private DfsPackKey packKey;
+ private DfsStreamKey packKey;
/** If the index was small enough, the entire index after writing. */
private PackIndex packIndex;
@@ -150,12 +150,13 @@
readBlock = null;
packDsc.addFileExt(PACK);
packDsc.setFileSize(PACK, packEnd);
+ packDsc.setBlockSize(PACK, blockSize);
writePackIndex();
objdb.commitPack(Collections.singletonList(packDsc), null);
rollback = false;
- DfsPackFile p = blockCache.getOrCreate(packDsc, packKey);
+ DfsPackFile p = new DfsPackFile(blockCache, packDsc);
p.setBlockSize(blockSize);
if (packIndex != null)
p.setPackIndex(packIndex);
@@ -206,9 +207,9 @@
}
packDsc = objdb.newPack(DfsObjDatabase.PackSource.RECEIVE);
- packKey = new DfsPackKey();
-
out = objdb.writeFile(packDsc, PACK);
+ packKey = packDsc.getStreamKey(PACK);
+
int size = out.blockSize();
if (size <= 0)
size = blockCache.getBlockSize();
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 755b163..4b0d583 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
@@ -95,7 +95,7 @@
* See the base {@link ObjectReader} documentation for details. Notably, a
* reader is not thread safe.
*/
-public final class DfsReader extends ObjectReader implements ObjectReuseAsIs {
+public 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. */
@@ -104,17 +104,21 @@
/** Database this reader loads objects from. */
final DfsObjDatabase db;
+ final DfsReaderIoStats.Accumulator stats = new DfsReaderIoStats.Accumulator();
+
private Inflater inf;
-
private DfsBlock block;
-
private DeltaBaseCache baseCache;
-
private DfsPackFile last;
-
private boolean avoidUnreachable;
- DfsReader(DfsObjDatabase db) {
+ /**
+ * Initialize a new DfsReader
+ *
+ * @param db
+ * parent DfsObjDatabase.
+ */
+ protected DfsReader(DfsObjDatabase db) {
this.db = db;
this.streamFileThreshold = db.getReaderOptions().getStreamFileThreshold();
}
@@ -131,7 +135,7 @@
@Override
public ObjectReader newReader() {
- return new DfsReader(db);
+ return db.newReader();
}
@Override
@@ -170,6 +174,7 @@
PackList packList = db.getPackList();
resolveImpl(packList, id, matches);
if (matches.size() < MAX_RESOLVE_MATCHES && packList.dirty()) {
+ stats.scanPacks++;
resolveImpl(db.scanPacks(packList), id, matches);
}
return matches;
@@ -198,6 +203,7 @@
if (hasImpl(packList, objectId)) {
return true;
} else if (packList.dirty()) {
+ stats.scanPacks++;
return hasImpl(db.scanPacks(packList), objectId);
}
return false;
@@ -234,6 +240,7 @@
return checkType(ldr, objectId, typeHint);
}
if (packList.dirty()) {
+ stats.scanPacks++;
ldr = openImpl(db.scanPacks(packList), objectId);
if (ldr != null) {
return checkType(ldr, objectId, typeHint);
@@ -316,6 +323,7 @@
List<FoundObject<T>> r = new ArrayList<>();
findAllImpl(packList, pending, r);
if (!pending.isEmpty() && packList.dirty()) {
+ stats.scanPacks++;
findAllImpl(db.scanPacks(packList), pending, r);
}
for (T t : pending) {
@@ -452,7 +460,6 @@
final IOException findAllError = error;
return new AsyncObjectSizeQueue<T>() {
private FoundObject<T> cur;
-
private long sz;
@Override
@@ -718,9 +725,10 @@
for (int dstoff = 0;;) {
int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
dstoff += n;
- if (inf.finished() || (headerOnly && dstoff == dstbuf.length))
+ if (inf.finished() || (headerOnly && dstoff == dstbuf.length)) {
+ stats.inflatedBytes += dstoff;
return dstoff;
- if (inf.needsInput()) {
+ } else if (inf.needsInput()) {
pin(pack, position);
position += block.setInput(position, inf);
} else if (n == 0)
@@ -749,8 +757,7 @@
}
void pin(DfsPackFile pack, long position) throws IOException {
- DfsBlock b = block;
- if (b == null || !b.contains(pack.key, position)) {
+ if (block == null || !block.contains(pack.key, position)) {
// If memory is low, we may need what is in our window field to
// be cleaned up by the GC during the get for the next window.
// So we always clear it, even though we are just going to set
@@ -764,6 +771,11 @@
block = null;
}
+ /** @return IO statistics accumulated by this reader. */
+ public DfsReaderIoStats getIoStats() {
+ return new DfsReaderIoStats(stats);
+ }
+
/** Release the current window cursor. */
@Override
public void close() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
new file mode 100644
index 0000000..9a174c8
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.dfs;
+
+/** IO statistics for a {@link DfsReader}. */
+public class DfsReaderIoStats {
+ /** POJO to accumulate IO statistics. */
+ public static class Accumulator {
+ /** Number of times the reader explicitly called scanPacks. */
+ long scanPacks;
+
+ /** Total number of complete pack indexes read into memory. */
+ long readIdx;
+
+ /** Total number of complete bitmap indexes read into memory. */
+ long readBitmap;
+
+ /** Total number of bytes read from indexes. */
+ long readIdxBytes;
+
+ /** Total microseconds spent reading pack or bitmap indexes. */
+ long readIdxMicros;
+
+ /** Total number of block cache hits. */
+ long blockCacheHit;
+
+ /** Total number of discrete blocks read from pack file(s). */
+ long readBlock;
+
+ /** Total number of compressed bytes read as block sized units. */
+ long readBlockBytes;
+
+ /** Total microseconds spent reading {@link #readBlock} blocks. */
+ long readBlockMicros;
+
+ /** Total number of bytes decompressed. */
+ long inflatedBytes;
+
+ Accumulator() {
+ }
+ }
+
+ private final Accumulator stats;
+
+ DfsReaderIoStats(Accumulator stats) {
+ this.stats = stats;
+ }
+
+ /** @return number of times the reader explicitly called scanPacks. */
+ public long getScanPacks() {
+ return stats.scanPacks;
+ }
+
+ /** @return total number of complete pack indexes read into memory. */
+ public long getReadPackIndexCount() {
+ return stats.readIdx;
+ }
+
+ /** @return total number of complete bitmap indexes read into memory. */
+ public long getReadBitmapIndexCount() {
+ return stats.readBitmap;
+ }
+
+ /** @return total number of bytes read from indexes. */
+ public long getReadIndexBytes() {
+ return stats.readIdxBytes;
+ }
+
+ /** @return total microseconds spent reading pack or bitmap indexes. */
+ public long getReadIndexMicros() {
+ return stats.readIdxMicros;
+ }
+
+ /** @return total number of block cache hits. */
+ public long getBlockCacheHits() {
+ return stats.blockCacheHit;
+ }
+
+ /** @return total number of discrete blocks read from pack file(s). */
+ public long getReadBlocksCount() {
+ return stats.readBlock;
+ }
+
+ /** @return total number of compressed bytes read as block sized units. */
+ public long getReadBlocksBytes() {
+ return stats.readBlockBytes;
+ }
+
+ /** @return total microseconds spent reading blocks. */
+ public long getReadBlocksMicros() {
+ return stats.readBlockMicros;
+ }
+
+ /** @return total number of bytes decompressed. */
+ public long getInflatedBytes() {
+ return stats.inflatedBytes;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java
new file mode 100644
index 0000000..54a7489
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsStreamKey.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011, 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.internal.storage.dfs;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.util.Arrays;
+
+/** Key used by {@link DfsBlockCache} to disambiguate streams. */
+public abstract class DfsStreamKey {
+ /**
+ * @param repo
+ * description of the containing repository.
+ * @param name
+ * compute the key from a string name.
+ * @return key for {@code name}
+ */
+ public static DfsStreamKey of(DfsRepositoryDescription repo, String name) {
+ return new ByteArrayDfsStreamKey(repo, name.getBytes(UTF_8));
+ }
+
+ final int hash;
+
+ /**
+ * @param hash
+ * hash of the other identifying components of the key.
+ */
+ protected DfsStreamKey(int hash) {
+ // Multiply by 31 here so we can more directly combine with another
+ // value without doing the multiply there.
+ this.hash = hash * 31;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public abstract boolean equals(Object o);
+
+ @SuppressWarnings("boxing")
+ @Override
+ public String toString() {
+ return String.format("DfsStreamKey[hash=%08x]", hash); //$NON-NLS-1$
+ }
+
+ private static final class ByteArrayDfsStreamKey extends DfsStreamKey {
+ private final DfsRepositoryDescription repo;
+ private final byte[] name;
+
+ ByteArrayDfsStreamKey(DfsRepositoryDescription repo, byte[] name) {
+ super(repo.hashCode() * 31 + Arrays.hashCode(name));
+ this.repo = repo;
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ByteArrayDfsStreamKey) {
+ ByteArrayDfsStreamKey k = (ByteArrayDfsStreamKey) o;
+ return hash == k.hash
+ && repo.equals(k.repo)
+ && Arrays.equals(name, k.name);
+ }
+ return false;
+ }
+ }
+
+ static final class ForReverseIndex extends DfsStreamKey {
+ private final DfsStreamKey idxKey;
+
+ ForReverseIndex(DfsStreamKey idxKey) {
+ super(idxKey.hash + 1);
+ this.idxKey = idxKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof ForReverseIndex
+ && idxKey.equals(((ForReverseIndex) o).idxKey);
+ }
+ }
+}
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 527e46b..383ed3d 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
@@ -53,7 +53,7 @@
static final AtomicInteger packId = new AtomicInteger();
- private final DfsObjDatabase objdb;
+ private final MemObjDatabase objdb;
private final RefDatabase refdb;
private String gitwebDescription;
private boolean performsAtomicTransactions = true;
@@ -75,7 +75,7 @@
}
@Override
- public DfsObjDatabase getObjectDatabase() {
+ public MemObjDatabase getObjectDatabase() {
return objdb;
}
@@ -106,13 +106,23 @@
gitwebDescription = d;
}
- private class MemObjDatabase extends DfsObjDatabase {
+ /** DfsObjDatabase used by InMemoryRepository. */
+ public class MemObjDatabase extends DfsObjDatabase {
private List<DfsPackDescription> packs = new ArrayList<>();
+ private int blockSize;
MemObjDatabase(DfsRepository repo) {
super(repo, new DfsReaderOptions());
}
+ /**
+ * @param blockSize
+ * force a different block size for testing.
+ */
+ public void setReadableChannelBlockSizeForTest(int blockSize) {
+ this.blockSize = blockSize;
+ }
+
@Override
protected synchronized List<DfsPackDescription> listPacks() {
return packs;
@@ -152,7 +162,7 @@
byte[] file = memPack.fileMap.get(ext);
if (file == null)
throw new FileNotFoundException(desc.getFileName(ext));
- return new ByteArrayReadableChannel(file);
+ return new ByteArrayReadableChannel(file, blockSize);
}
@Override
@@ -216,13 +226,13 @@
private static class ByteArrayReadableChannel implements ReadableChannel {
private final byte[] data;
-
+ private final int blockSize;
private int position;
-
private boolean open = true;
- ByteArrayReadableChannel(byte[] buf) {
+ ByteArrayReadableChannel(byte[] buf, int blockSize) {
data = buf;
+ this.blockSize = blockSize;
}
@Override
@@ -262,7 +272,7 @@
@Override
public int blockSize() {
- return 0;
+ return blockSize;
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
index 6d40a75..73a93e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
@@ -99,7 +99,7 @@
@Override
public ObjectStream openStream() throws MissingObjectException, IOException {
- DfsReader ctx = new DfsReader(db);
+ DfsReader ctx = db.newReader();
InputStream in;
try {
in = new PackInputStream(pack, objectOffset + headerLength, ctx);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
index 4b4337d..2eacb7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CheckoutEntryImpl.java
@@ -74,4 +74,4 @@
public String getToBranch() {
return to;
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 2fd4961..6a674aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -637,12 +637,18 @@
}
+ private boolean shouldAutoDetach() {
+ return getConfig().getBoolean(ConfigConstants.CONFIG_GC_SECTION,
+ ConfigConstants.CONFIG_KEY_AUTODETACH, true);
+ }
+
@Override
public void autoGC(ProgressMonitor monitor) {
GC gc = new GC(this);
gc.setPackConfig(new PackConfig(this));
gc.setProgressMonitor(monitor);
gc.setAuto(true);
+ gc.setBackground(shouldAutoDetach());
try {
gc.gc();
} catch (ParseException | IOException e) {
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 c68e5f7..45ecd32 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
@@ -50,6 +50,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.file.DirectoryStream;
@@ -73,11 +75,16 @@
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CancelledException;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -99,6 +106,7 @@
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
+import org.eclipse.jgit.lib.internal.WorkQueue;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.ReflogReader;
@@ -143,6 +151,20 @@
private static final int DEFAULT_AUTOLIMIT = 6700;
+ private static volatile ExecutorService executor;
+
+ /**
+ * Set the executor for running auto-gc in the background. If no executor is
+ * set JGit's own WorkQueue will be used.
+ *
+ * @param e
+ * the executor to be used for running auto-gc
+ * @since 4.8
+ */
+ public static void setExecutor(ExecutorService e) {
+ executor = e;
+ }
+
private final FileRepository repo;
private ProgressMonitor pm;
@@ -178,6 +200,11 @@
private boolean automatic;
/**
+ * Whether to run gc in a background thread
+ */
+ private boolean background;
+
+ /**
* Creates a new garbage collector with default values. An expirationTime of
* two weeks and <code>null</code> as progress monitor will be used.
*
@@ -202,13 +229,77 @@
* first check whether any housekeeping is required; if not, it exits
* without performing any work.
*
+ * If {@link #setBackground(boolean)} was set to {@code true}
+ * {@code collectGarbage} will start the gc in the background, and then
+ * return immediately. In this case, errors will not be reported except in
+ * gc.log.
+ *
* @return the collection of {@link PackFile}'s which are newly created
* @throws IOException
* @throws ParseException
* If the configuration parameter "gc.pruneexpire" couldn't be
* parsed
*/
+ // TODO(ms): in 5.0 change signature and return Future<Collection<PackFile>>
public Collection<PackFile> gc() throws IOException, ParseException {
+ final GcLog gcLog = background ? new GcLog(repo) : null;
+ if (gcLog != null && !gcLog.lock(background)) {
+ // there is already a background gc running
+ return Collections.emptyList();
+ }
+
+ Callable<Collection<PackFile>> gcTask = () -> {
+ try {
+ Collection<PackFile> newPacks = doGc();
+ if (automatic && tooManyLooseObjects() && gcLog != null) {
+ String message = JGitText.get().gcTooManyUnpruned;
+ gcLog.write(message);
+ gcLog.commit();
+ }
+ return newPacks;
+ } catch (IOException | ParseException e) {
+ if (background) {
+ if (gcLog == null) {
+ // Lacking a log, there's no way to report this.
+ return Collections.emptyList();
+ }
+ try {
+ gcLog.write(e.getMessage());
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ gcLog.write(sw.toString());
+ gcLog.commit();
+ } catch (IOException e2) {
+ e2.addSuppressed(e);
+ LOG.error(e2.getMessage(), e2);
+ }
+ } else {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ } finally {
+ if (gcLog != null) {
+ gcLog.unlock();
+ }
+ }
+ return Collections.emptyList();
+ };
+ Future<Collection<PackFile>> result = executor().submit(gcTask);
+ if (background) {
+ // TODO(ms): in 5.0 change signature and return the Future
+ return Collections.emptyList();
+ }
+ try {
+ return result.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private ExecutorService executor() {
+ return (executor != null) ? executor : WorkQueue.getExecutor();
+ }
+
+ private Collection<PackFile> doGc() throws IOException, ParseException {
if (automatic && !needGc()) {
return Collections.emptyList();
}
@@ -729,7 +820,9 @@
long time = System.currentTimeMillis();
Collection<Ref> refsBefore = getAllRefs();
+ Set<ObjectId> allHeadsAndTags = new HashSet<>();
Set<ObjectId> allHeads = new HashSet<>();
+ Set<ObjectId> allTags = new HashSet<>();
Set<ObjectId> nonHeads = new HashSet<>();
Set<ObjectId> txnHeads = new HashSet<>();
Set<ObjectId> tagTargets = new HashSet<>();
@@ -739,16 +832,21 @@
for (Ref ref : refsBefore) {
checkCancelled();
nonHeads.addAll(listRefLogObjects(ref, 0));
- if (ref.isSymbolic() || ref.getObjectId() == null)
+ if (ref.isSymbolic() || ref.getObjectId() == null) {
continue;
- if (isHead(ref) || isTag(ref))
+ }
+ if (isHead(ref)) {
allHeads.add(ref.getObjectId());
- else if (RefTreeNames.isRefTree(refdb, ref.getName()))
+ } else if (isTag(ref)) {
+ allTags.add(ref.getObjectId());
+ } else if (RefTreeNames.isRefTree(refdb, ref.getName())) {
txnHeads.add(ref.getObjectId());
- else
+ } else {
nonHeads.add(ref.getObjectId());
- if (ref.getPeeledObjectId() != null)
+ }
+ if (ref.getPeeledObjectId() != null) {
tagTargets.add(ref.getPeeledObjectId());
+ }
}
List<ObjectIdSet> excluded = new LinkedList<>();
@@ -758,13 +856,25 @@
excluded.add(f.getIndex());
}
- tagTargets.addAll(allHeads);
+ // Don't exclude tags that are also branch tips
+ allTags.removeAll(allHeads);
+ allHeadsAndTags.addAll(allHeads);
+ allHeadsAndTags.addAll(allTags);
+
+ // Hoist all branch tips and tags earlier in the pack file
+ tagTargets.addAll(allHeadsAndTags);
nonHeads.addAll(indexObjects);
+ // Combine the GC_REST objects into the GC pack if requested
+ if (pconfig != null && pconfig.getSinglePack()) {
+ allHeadsAndTags.addAll(nonHeads);
+ nonHeads.clear();
+ }
+
List<PackFile> ret = new ArrayList<>(2);
PackFile heads = null;
- if (!allHeads.isEmpty()) {
- heads = writePack(allHeads, Collections.<ObjectId> emptySet(),
+ if (!allHeadsAndTags.isEmpty()) {
+ heads = writePack(allHeadsAndTags, PackWriter.NONE, allTags,
tagTargets, excluded);
if (heads != null) {
ret.add(heads);
@@ -772,12 +882,14 @@
}
}
if (!nonHeads.isEmpty()) {
- PackFile rest = writePack(nonHeads, allHeads, tagTargets, excluded);
+ PackFile rest = writePack(nonHeads, allHeadsAndTags, PackWriter.NONE,
+ tagTargets, excluded);
if (rest != null)
ret.add(rest);
}
if (!txnHeads.isEmpty()) {
- PackFile txn = writePack(txnHeads, PackWriter.NONE, null, excluded);
+ PackFile txn = writePack(txnHeads, PackWriter.NONE, PackWriter.NONE,
+ null, excluded);
if (txn != null)
ret.add(txn);
}
@@ -961,8 +1073,9 @@
}
private PackFile writePack(@NonNull Set<? extends ObjectId> want,
- @NonNull Set<? extends ObjectId> have, Set<ObjectId> tagTargets,
- List<ObjectIdSet> excludeObjects) throws IOException {
+ @NonNull Set<? extends ObjectId> have, @NonNull Set<ObjectId> tags,
+ Set<ObjectId> tagTargets, List<ObjectIdSet> excludeObjects)
+ throws IOException {
checkCancelled();
File tmpPack = null;
Map<PackExt, File> tmpExts = new TreeMap<>(
@@ -988,12 +1101,13 @@
// prepare the PackWriter
pw.setDeltaBaseAsOffset(true);
pw.setReuseDeltaCommits(false);
- if (tagTargets != null)
+ if (tagTargets != null) {
pw.setTagTargets(tagTargets);
+ }
if (excludeObjects != null)
for (ObjectIdSet idx : excludeObjects)
pw.excludeObjects(idx);
- pw.preparePack(pm, want, have);
+ pw.preparePack(pm, want, have, PackWriter.NONE, tags);
if (pw.getObjectCount() == 0)
return null;
checkCancelled();
@@ -1348,6 +1462,14 @@
this.automatic = auto;
}
+ /**
+ * @param background
+ * whether to run the gc in a background thread.
+ */
+ void setBackground(boolean background) {
+ this.background = background;
+ }
+
private boolean needGc() {
if (tooManyPacks()) {
addRepackAllOption();
@@ -1386,8 +1508,7 @@
* @return {@code true} if number of loose objects > gc.auto (default 6700)
*/
boolean tooManyLooseObjects() {
- int auto = repo.getConfig().getInt(ConfigConstants.CONFIG_GC_SECTION,
- ConfigConstants.CONFIG_KEY_AUTO, DEFAULT_AUTOLIMIT);
+ int auto = getLooseObjectLimit();
if (auto <= 0) {
return false;
}
@@ -1419,4 +1540,9 @@
}
return false;
}
+
+ private int getLooseObjectLimit() {
+ return repo.getConfig().getInt(ConfigConstants.CONFIG_GC_SECTION,
+ ConfigConstants.CONFIG_KEY_AUTO, DEFAULT_AUTOLIMIT);
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
new file mode 100644
index 0000000..9ea77cc
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2017 Two Sigma Open Source
+ * 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.internal.storage.file;
+
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.util.GitDateParser;
+import org.eclipse.jgit.util.SystemReader;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.attribute.FileTime;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.time.Instant;
+
+/**
+ * This class manages the gc.log file for a {@link FileRepository}.
+ */
+class GcLog {
+ private final FileRepository repo;
+
+ private final File logFile;
+
+ private final LockFile lock;
+
+ private Instant gcLogExpire;
+
+ private static final String LOG_EXPIRY_DEFAULT = "1.day.ago"; //$NON-NLS-1$
+
+ private boolean nonEmpty = false;
+
+ /**
+ * Construct a GcLog object for a {@link FileRepository}
+ *
+ * @param repo
+ * the repository
+ */
+ GcLog(FileRepository repo) {
+ this.repo = repo;
+ logFile = new File(repo.getDirectory(), "gc.log"); //$NON-NLS-1$
+ lock = new LockFile(logFile);
+ }
+
+ private Instant getLogExpiry() throws ParseException {
+ if (gcLogExpire == null) {
+ String logExpiryStr = repo.getConfig().getString(
+ ConfigConstants.CONFIG_GC_SECTION, null,
+ ConfigConstants.CONFIG_KEY_LOGEXPIRY);
+ if (logExpiryStr == null) {
+ logExpiryStr = LOG_EXPIRY_DEFAULT;
+ }
+ gcLogExpire = GitDateParser.parse(logExpiryStr, null,
+ SystemReader.getInstance().getLocale()).toInstant();
+ }
+ return gcLogExpire;
+ }
+
+ private boolean autoGcBlockedByOldLockFile(boolean background) {
+ try {
+ FileTime lastModified = Files.getLastModifiedTime(logFile.toPath());
+ if (lastModified.toInstant().compareTo(getLogExpiry()) > 0) {
+ // There is an existing log file, which is too recent to ignore
+ if (!background) {
+ try (BufferedReader reader = Files
+ .newBufferedReader(logFile.toPath())) {
+ char[] buf = new char[1000];
+ int len = reader.read(buf, 0, 1000);
+ String oldError = new String(buf, 0, len);
+
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().gcLogExists, oldError, logFile));
+ }
+ }
+ return true;
+ }
+ } catch (NoSuchFileException e) {
+ // No existing log file, OK.
+ } catch (IOException | ParseException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ return false;
+ }
+
+ /**
+ * Lock the GC log file for updates
+ *
+ * @param background
+ * If true, and if gc.log already exists, unlock and return false
+ * @return {@code true} if we hold the lock
+ */
+ boolean lock(boolean background) {
+ try {
+ if (!lock.lock()) {
+ return false;
+ }
+ } catch (IOException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ if (autoGcBlockedByOldLockFile(background)) {
+ lock.unlock();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Unlock (roll back) the GC log lock
+ */
+ void unlock() {
+ lock.unlock();
+ }
+
+ /**
+ * Commit changes to the gc log, if there have been any writes. Otherwise,
+ * just unlock and delete the existing file (if any)
+ *
+ * @return true if committing (or unlocking/deleting) succeeds.
+ */
+ boolean commit() {
+ if (nonEmpty) {
+ return lock.commit();
+ } else {
+ logFile.delete();
+ lock.unlock();
+ return true;
+ }
+ }
+
+ /**
+ * Write to the pending gc log. Content will be committed upon a call to
+ * commit()
+ *
+ * @param content
+ * The content to write
+ * @throws IOException
+ */
+ void write(String content) throws IOException {
+ if (content.length() > 0) {
+ nonEmpty = true;
+ }
+ lock.write(content.getBytes(UTF_8));
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
index bda5cbe..3f82e2a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -78,4 +78,4 @@
return r.getRules().isEmpty() ? null : r;
}
-}
\ No newline at end of file
+}
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 d2fcacf..6221cfa 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
@@ -374,7 +374,7 @@
};
}
- private void requireLock() {
+ void requireLock() {
if (os == null) {
unlock();
throw new IllegalStateException(MessageFormat.format(JGitText.get().lockOnNotHeld, ref));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
index 154809b..962f765 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
@@ -82,4 +82,4 @@
public void close() {
wc.close();
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
new file mode 100644
index 0000000..b661ae7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2017, 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.internal.storage.file;
+
+import static java.util.stream.Collectors.toList;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.LockFailedException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.file.RefDirectory.PackedRefList;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.RefList;
+
+/**
+ * Implementation of {@link BatchRefUpdate} that uses the {@code packed-refs}
+ * file to support atomically updating multiple refs.
+ * <p>
+ * The algorithm is designed to be compatible with traditional single ref
+ * updates operating on single refs only. Regardless of success or failure, the
+ * results are atomic: from the perspective of any reader, either all updates in
+ * the batch will be visible, or none will. In the case of process failure
+ * during any of the following steps, removal of stale lock files is always
+ * safe, and will never result in an inconsistent state, although the update may
+ * or may not have been applied.
+ * <p>
+ * The algorithm is:
+ * <ol>
+ * <li>Pack loose refs involved in the transaction using the normal pack-refs
+ * operation. This ensures that creating lock files in the following step
+ * succeeds even if a batch contains both a delete of {@code refs/x} (loose) and
+ * a create of {@code refs/x/y}.</li>
+ * <li>Create locks for all loose refs involved in the transaction, even if they
+ * are not currently loose.</li>
+ * <li>Pack loose refs again, this time while holding all lock files (see {@link
+ * RefDirectory#pack(Map)}), without deleting them afterwards. This covers a
+ * potential race where new loose refs were created after the initial packing
+ * step. If no new loose refs were created during this race, this step does not
+ * modify any files on disk. Keep the merged state in memory.</li>
+ * <li>Update the in-memory packed refs with the commands in the batch, possibly
+ * failing the whole batch if any old ref values do not match.</li>
+ * <li>If the update succeeds, lock {@code packed-refs} and commit by atomically
+ * renaming the lock file.</li>
+ * <li>Delete loose ref lock files.</li>
+ * </ol>
+ *
+ * Because the packed-refs file format is a sorted list, this algorithm is
+ * linear in the total number of refs, regardless of the batch size. This can be
+ * a significant slowdown on repositories with large numbers of refs; callers
+ * that prefer speed over atomicity should use {@code setAtomic(false)}. As an
+ * optimization, an update containing a single ref update does not use the
+ * packed-refs protocol.
+ */
+class PackedBatchRefUpdate extends BatchRefUpdate {
+ private RefDirectory refdb;
+
+ PackedBatchRefUpdate(RefDirectory refdb) {
+ super(refdb);
+ this.refdb = refdb;
+ }
+
+ @Override
+ public void execute(RevWalk walk, ProgressMonitor monitor,
+ List<String> options) throws IOException {
+ if (!isAtomic()) {
+ // Use default one-by-one implementation.
+ super.execute(walk, monitor, options);
+ return;
+ }
+ List<ReceiveCommand> pending =
+ ReceiveCommand.filter(getCommands(), NOT_ATTEMPTED);
+ if (pending.isEmpty()) {
+ return;
+ }
+ if (pending.size() == 1) {
+ // Single-ref updates are always atomic, no need for packed-refs.
+ super.execute(walk, monitor, options);
+ return;
+ }
+
+ // Required implementation details copied from super.execute.
+ if (!blockUntilTimestamps(MAX_WAIT)) {
+ return;
+ }
+ if (options != null) {
+ setPushOptions(options);
+ }
+ // End required implementation details.
+
+ // Check for conflicting names before attempting to acquire locks, since
+ // lockfile creation may fail on file/directory conflicts.
+ if (!checkConflictingNames(pending)) {
+ return;
+ }
+
+ if (!checkObjectExistence(walk, pending)) {
+ return;
+ }
+
+ if (!checkNonFastForwards(walk, pending)) {
+ return;
+ }
+
+ // Pack refs normally, so we can create lock files even in the case where
+ // refs/x is deleted and refs/x/y is created in this batch.
+ try {
+ refdb.pack(
+ pending.stream().map(ReceiveCommand::getRefName).collect(toList()));
+ } catch (LockFailedException e) {
+ lockFailure(pending.get(0), pending);
+ return;
+ }
+
+ Map<String, LockFile> locks = null;
+ refdb.inProcessPackedRefsLock.lock();
+ try {
+ locks = lockLooseRefs(pending);
+ if (locks == null) {
+ return;
+ }
+ PackedRefList oldPackedList = refdb.pack(locks);
+ RefList<Ref> newRefs = applyUpdates(walk, oldPackedList, pending);
+ if (newRefs == null) {
+ return;
+ }
+ LockFile packedRefsLock = refdb.lockPackedRefs();
+ if (packedRefsLock == null) {
+ lockFailure(pending.get(0), pending);
+ return;
+ }
+ // commitPackedRefs removes lock file (by renaming over real file).
+ refdb.commitPackedRefs(packedRefsLock, newRefs, oldPackedList);
+ } finally {
+ try {
+ unlockAll(locks);
+ } finally {
+ refdb.inProcessPackedRefsLock.unlock();
+ }
+ }
+
+ refdb.fireRefsChanged();
+ pending.forEach(c -> c.setResult(ReceiveCommand.Result.OK));
+ writeReflog(pending);
+ }
+
+ private boolean checkConflictingNames(List<ReceiveCommand> commands)
+ throws IOException {
+ Set<String> takenNames = new HashSet<>();
+ Set<String> takenPrefixes = new HashSet<>();
+ Set<String> deletes = new HashSet<>();
+ for (ReceiveCommand cmd : commands) {
+ if (cmd.getType() != ReceiveCommand.Type.DELETE) {
+ takenNames.add(cmd.getRefName());
+ addPrefixesTo(cmd.getRefName(), takenPrefixes);
+ } else {
+ deletes.add(cmd.getRefName());
+ }
+ }
+ Set<String> initialRefs = refdb.getRefs(RefDatabase.ALL).keySet();
+ for (String name : initialRefs) {
+ if (!deletes.contains(name)) {
+ takenNames.add(name);
+ addPrefixesTo(name, takenPrefixes);
+ }
+ }
+
+ for (ReceiveCommand cmd : commands) {
+ if (cmd.getType() != ReceiveCommand.Type.DELETE &&
+ takenPrefixes.contains(cmd.getRefName())) {
+ // This ref is a prefix of some other ref. This check doesn't apply when
+ // this command is a delete, because if the ref is deleted nobody will
+ // ever be creating a loose ref with that name.
+ lockFailure(cmd, commands);
+ return false;
+ }
+ for (String prefix : getPrefixes(cmd.getRefName())) {
+ if (takenNames.contains(prefix)) {
+ // A prefix of this ref is already a refname. This check does apply
+ // when this command is a delete, because we would need to create the
+ // refname as a directory in order to create a lockfile for the
+ // to-be-deleted ref.
+ lockFailure(cmd, commands);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean checkObjectExistence(RevWalk walk,
+ List<ReceiveCommand> commands) throws IOException {
+ for (ReceiveCommand cmd : commands) {
+ try {
+ if (!cmd.getNewId().equals(ObjectId.zeroId())) {
+ walk.parseAny(cmd.getNewId());
+ }
+ } catch (MissingObjectException e) {
+ // ReceiveCommand#setResult(Result) converts REJECTED to
+ // REJECTED_NONFASTFORWARD, even though that result is also used for a
+ // missing object. Eagerly handle this case so we can set the right
+ // result.
+ reject(cmd, ReceiveCommand.Result.REJECTED_MISSING_OBJECT, commands);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean checkNonFastForwards(RevWalk walk,
+ List<ReceiveCommand> commands) throws IOException {
+ if (isAllowNonFastForwards()) {
+ return true;
+ }
+ for (ReceiveCommand cmd : commands) {
+ cmd.updateType(walk);
+ if (cmd.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD) {
+ reject(cmd, REJECTED_NONFASTFORWARD, commands);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Lock loose refs corresponding to a list of commands.
+ *
+ * @param commands
+ * commands that we intend to execute.
+ * @return map of ref name in the input commands to lock file. Always contains
+ * one entry for each ref in the input list. All locks are acquired
+ * before returning. If any lock was not able to be acquired: the
+ * return value is null; no locks are held; and all commands that were
+ * pending are set to fail with {@code LOCK_FAILURE}.
+ * @throws IOException
+ * an error occurred other than a failure to acquire; no locks are
+ * held if this exception is thrown.
+ */
+ @Nullable
+ private Map<String, LockFile> lockLooseRefs(List<ReceiveCommand> commands)
+ throws IOException {
+ ReceiveCommand failed = null;
+ Map<String, LockFile> locks = new HashMap<>();
+ try {
+ RETRY: for (int ms : refdb.getRetrySleepMs()) {
+ failed = null;
+ // Release all locks before trying again, to prevent deadlock.
+ unlockAll(locks);
+ locks.clear();
+ RefDirectory.sleep(ms);
+
+ for (ReceiveCommand c : commands) {
+ String name = c.getRefName();
+ LockFile lock = new LockFile(refdb.fileFor(name));
+ if (locks.put(name, lock) != null) {
+ throw new IOException(
+ MessageFormat.format(JGitText.get().duplicateRef, name));
+ }
+ if (!lock.lock()) {
+ failed = c;
+ continue RETRY;
+ }
+ }
+ Map<String, LockFile> result = locks;
+ locks = null;
+ return result;
+ }
+ } finally {
+ unlockAll(locks);
+ }
+ lockFailure(failed != null ? failed : commands.get(0), commands);
+ return null;
+ }
+
+ private static RefList<Ref> applyUpdates(RevWalk walk, RefList<Ref> refs,
+ List<ReceiveCommand> commands) throws IOException {
+ int nDeletes = 0;
+ List<ReceiveCommand> adds = new ArrayList<>(commands.size());
+ for (ReceiveCommand c : commands) {
+ if (c.getType() == ReceiveCommand.Type.CREATE) {
+ adds.add(c);
+ } else if (c.getType() == ReceiveCommand.Type.DELETE) {
+ nDeletes++;
+ }
+ }
+ int addIdx = 0;
+
+ // Construct a new RefList by linearly scanning the old list, and merging in
+ // any updates.
+ Map<String, ReceiveCommand> byName = byName(commands);
+ RefList.Builder<Ref> b =
+ new RefList.Builder<>(refs.size() - nDeletes + adds.size());
+ for (Ref ref : refs) {
+ String name = ref.getName();
+ ReceiveCommand cmd = byName.remove(name);
+ if (cmd == null) {
+ b.add(ref);
+ continue;
+ }
+ if (!cmd.getOldId().equals(ref.getObjectId())) {
+ lockFailure(cmd, commands);
+ return null;
+ }
+
+ // Consume any adds between the last and current ref.
+ while (addIdx < adds.size()) {
+ ReceiveCommand currAdd = adds.get(addIdx);
+ if (currAdd.getRefName().compareTo(name) < 0) {
+ b.add(peeledRef(walk, currAdd));
+ byName.remove(currAdd.getRefName());
+ } else {
+ break;
+ }
+ addIdx++;
+ }
+
+ if (cmd.getType() != ReceiveCommand.Type.DELETE) {
+ b.add(peeledRef(walk, cmd));
+ }
+ }
+
+ // All remaining adds are valid, since the refs didn't exist.
+ while (addIdx < adds.size()) {
+ ReceiveCommand cmd = adds.get(addIdx++);
+ byName.remove(cmd.getRefName());
+ b.add(peeledRef(walk, cmd));
+ }
+
+ // Any remaining updates/deletes do not correspond to any existing refs, so
+ // they are lock failures.
+ if (!byName.isEmpty()) {
+ lockFailure(byName.values().iterator().next(), commands);
+ return null;
+ }
+
+ return b.toRefList();
+ }
+
+ private void writeReflog(List<ReceiveCommand> commands) {
+ PersonIdent ident = getRefLogIdent();
+ if (ident == null) {
+ ident = new PersonIdent(refdb.getRepository());
+ }
+ ReflogWriter w = refdb.getLogWriter();
+ for (ReceiveCommand cmd : commands) {
+ // Assume any pending commands have already been executed atomically.
+ if (cmd.getResult() != ReceiveCommand.Result.OK) {
+ continue;
+ }
+ String name = cmd.getRefName();
+
+ if (cmd.getType() == ReceiveCommand.Type.DELETE) {
+ try {
+ RefDirectory.delete(w.logFor(name), RefDirectory.levelsIn(name));
+ } catch (IOException e) {
+ // Ignore failures, see below.
+ }
+ continue;
+ }
+
+ if (isRefLogDisabled(cmd)) {
+ continue;
+ }
+
+ String msg = getRefLogMessage(cmd);
+ if (isRefLogIncludingResult(cmd)) {
+ String strResult = toResultString(cmd);
+ if (strResult != null) {
+ msg = msg.isEmpty()
+ ? strResult : msg + ": " + strResult; //$NON-NLS-1$
+ }
+ }
+ try {
+ w.log(name, cmd.getOldId(), cmd.getNewId(), ident, msg);
+ } catch (IOException e) {
+ // Ignore failures, but continue attempting to write more reflogs.
+ //
+ // In this storage format, it is impossible to atomically write the
+ // reflog with the ref updates, so we have to choose between:
+ // a. Propagating this exception and claiming failure, even though the
+ // actual ref updates succeeded.
+ // b. Ignoring failures writing the reflog, so we claim success if and
+ // only if the ref updates succeeded.
+ // We choose (b) in order to surprise callers the least.
+ //
+ // Possible future improvements:
+ // * Log a warning to a logger.
+ // * Retry a fixed number of times in case the error was transient.
+ }
+ }
+ }
+
+ private String toResultString(ReceiveCommand cmd) {
+ switch (cmd.getType()) {
+ case CREATE:
+ return ReflogEntry.PREFIX_CREATED;
+ case UPDATE:
+ // Match the behavior of a single RefUpdate. In that case, setting the
+ // force bit completely bypasses the potentially expensive isMergedInto
+ // check, by design, so the reflog message may be inaccurate.
+ //
+ // Similarly, this class bypasses the isMergedInto checks when the force
+ // bit is set, meaning we can't actually distinguish between UPDATE and
+ // UPDATE_NONFASTFORWARD when isAllowNonFastForwards() returns true.
+ return isAllowNonFastForwards()
+ ? ReflogEntry.PREFIX_FORCED_UPDATE : ReflogEntry.PREFIX_FAST_FORWARD;
+ case UPDATE_NONFASTFORWARD:
+ return ReflogEntry.PREFIX_FORCED_UPDATE;
+ default:
+ return null;
+ }
+ }
+
+ private static Map<String, ReceiveCommand> byName(
+ List<ReceiveCommand> commands) {
+ Map<String, ReceiveCommand> ret = new LinkedHashMap<>();
+ for (ReceiveCommand cmd : commands) {
+ ret.put(cmd.getRefName(), cmd);
+ }
+ return ret;
+ }
+
+ private static Ref peeledRef(RevWalk walk, ReceiveCommand cmd)
+ throws IOException {
+ ObjectId newId = cmd.getNewId().copy();
+ RevObject obj = walk.parseAny(newId);
+ if (obj instanceof RevTag) {
+ return new ObjectIdRef.PeeledTag(
+ Ref.Storage.PACKED, cmd.getRefName(), newId, walk.peel(obj).copy());
+ }
+ return new ObjectIdRef.PeeledNonTag(
+ Ref.Storage.PACKED, cmd.getRefName(), newId);
+ }
+
+ private static void unlockAll(@Nullable Map<?, LockFile> locks) {
+ if (locks != null) {
+ locks.values().forEach(LockFile::unlock);
+ }
+ }
+
+ private static void lockFailure(ReceiveCommand cmd,
+ List<ReceiveCommand> commands) {
+ reject(cmd, LOCK_FAILURE, commands);
+ }
+
+ private static void reject(ReceiveCommand cmd, ReceiveCommand.Result result,
+ List<ReceiveCommand> commands) {
+ cmd.setResult(result);
+ for (ReceiveCommand c2 : commands) {
+ if (c2.getResult() == ReceiveCommand.Result.OK) {
+ // Undo OK status so ReceiveCommand#abort aborts it. Assumes this method
+ // is always called before committing any updates to disk.
+ c2.setResult(ReceiveCommand.Result.NOT_ATTEMPTED);
+ }
+ }
+ ReceiveCommand.abort(commands);
+ }
+}
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 24d51a5..ecf7ef9 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
@@ -63,17 +63,22 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.MessageFormat;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.InvalidObjectIdException;
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -135,6 +140,10 @@
Constants.MERGE_HEAD, Constants.FETCH_HEAD, Constants.ORIG_HEAD,
Constants.CHERRY_PICK_HEAD };
+ @SuppressWarnings("boxing")
+ private static final List<Integer> RETRY_SLEEP_MS =
+ Collections.unmodifiableList(Arrays.asList(0, 100, 200, 400, 800, 1600));
+
private final FileRepository parent;
private final File gitDir;
@@ -143,7 +152,7 @@
private final ReflogWriter logWriter;
- private final File packedRefsFile;
+ final File packedRefsFile;
/**
* Immutable sorted list of loose references.
@@ -159,6 +168,22 @@
final AtomicReference<PackedRefList> packedRefs = new AtomicReference<>();
/**
+ * Lock for coordinating operations within a single process that may contend
+ * on the {@code packed-refs} file.
+ * <p>
+ * All operations that write {@code packed-refs} must still acquire a
+ * {@link LockFile} on {@link #packedRefsFile}, even after they have acquired
+ * this lock, since there may be multiple {@link RefDirectory} instances or
+ * other processes operating on the same repo on disk.
+ * <p>
+ * This lock exists so multiple threads in the same process can wait in a fair
+ * queue without trying, failing, and retrying to acquire the on-disk lock. If
+ * {@code RepositoryCache} is used, this lock instance will be used by all
+ * threads.
+ */
+ final ReentrantLock inProcessPackedRefsLock = new ReentrantLock(true);
+
+ /**
* Number of modifications made to this database.
* <p>
* This counter is incremented when a change is made, or detected from the
@@ -174,6 +199,8 @@
*/
private final AtomicInteger lastNotifiedModCnt = new AtomicInteger();
+ private List<Integer> retrySleepMs = RETRY_SLEEP_MS;
+
RefDirectory(final FileRepository db) {
final FS fs = db.getFS();
parent = db;
@@ -183,7 +210,7 @@
packedRefsFile = fs.resolve(gitDir, PACKED_REFS);
looseRefs.set(RefList.<LooseRef> emptyList());
- packedRefs.set(PackedRefList.NO_PACKED_REFS);
+ packedRefs.set(NO_PACKED_REFS);
}
Repository getRepository() {
@@ -209,7 +236,7 @@
private void clearReferences() {
looseRefs.set(RefList.<LooseRef> emptyList());
- packedRefs.set(PackedRefList.NO_PACKED_REFS);
+ packedRefs.set(NO_PACKED_REFS);
}
@Override
@@ -562,6 +589,16 @@
return new RefDirectoryRename(from, to);
}
+ @Override
+ public PackedBatchRefUpdate newBatchUpdate() {
+ return new PackedBatchRefUpdate(this);
+ }
+
+ @Override
+ public boolean performsAtomicTransactions() {
+ return true;
+ }
+
void stored(RefDirectoryUpdate update, FileSnapshot snapshot) {
final ObjectId target = update.getNewObjectId().copy();
final Ref leaf = update.getRef().getLeaf();
@@ -580,6 +617,9 @@
void delete(RefDirectoryUpdate update) throws IOException {
Ref dst = update.getRef();
+ if (!update.isDetachingSymbolicRef()) {
+ dst = dst.getLeaf();
+ }
String name = dst.getName();
// Write the packed-refs file using an atomic update. We might
@@ -587,16 +627,19 @@
// we don't miss an edit made externally.
final PackedRefList packed = getPackedRefs();
if (packed.contains(name)) {
- LockFile lck = new LockFile(packedRefsFile);
- if (!lck.lock())
- throw new LockFailedException(packedRefsFile);
+ inProcessPackedRefsLock.lock();
try {
- PackedRefList cur = readPackedRefs();
- int idx = cur.find(name);
- if (0 <= idx)
- commitPackedRefs(lck, cur.remove(idx), packed);
+ LockFile lck = lockPackedRefsOrThrow();
+ try {
+ PackedRefList cur = readPackedRefs();
+ int idx = cur.find(name);
+ if (0 <= idx)
+ commitPackedRefs(lck, cur.remove(idx), packed);
+ } finally {
+ lck.unlock();
+ }
} finally {
- lck.unlock();
+ inProcessPackedRefsLock.unlock();
}
}
@@ -632,75 +675,144 @@
* @throws IOException
*/
public void pack(List<String> refs) throws IOException {
- if (refs.size() == 0)
- return;
+ pack(refs, Collections.emptyMap());
+ }
+
+ PackedRefList pack(Map<String, LockFile> heldLocks) throws IOException {
+ return pack(heldLocks.keySet(), heldLocks);
+ }
+
+ private PackedRefList pack(Collection<String> refs,
+ Map<String, LockFile> heldLocks) throws IOException {
+ for (LockFile ol : heldLocks.values()) {
+ ol.requireLock();
+ }
+ if (refs.size() == 0) {
+ return null;
+ }
FS fs = parent.getFS();
// Lock the packed refs file and read the content
- LockFile lck = new LockFile(packedRefsFile);
- if (!lck.lock())
- throw new IOException(MessageFormat.format(
- JGitText.get().cannotLock, packedRefsFile));
-
+ inProcessPackedRefsLock.lock();
try {
- final PackedRefList packed = getPackedRefs();
- RefList<Ref> cur = readPackedRefs();
+ LockFile lck = lockPackedRefsOrThrow();
+ try {
+ final PackedRefList packed = getPackedRefs();
+ RefList<Ref> cur = readPackedRefs();
- // Iterate over all refs to be packed
- for (String refName : refs) {
- Ref ref = readRef(refName, cur);
- if (ref.isSymbolic())
- continue; // can't pack symbolic refs
- // Add/Update it to packed-refs
- int idx = cur.find(refName);
- if (idx >= 0)
- cur = cur.set(idx, peeledPackedRef(ref));
- else
- cur = cur.add(idx, peeledPackedRef(ref));
- }
-
- // The new content for packed-refs is collected. Persist it.
- commitPackedRefs(lck, cur, packed);
-
- // Now delete the loose refs which are now packed
- for (String refName : refs) {
- // Lock the loose ref
- File refFile = fileFor(refName);
- if (!fs.exists(refFile))
- continue;
- LockFile rLck = new LockFile(refFile);
- if (!rLck.lock())
- continue;
- try {
- LooseRef currentLooseRef = scanRef(null, refName);
- if (currentLooseRef == null || currentLooseRef.isSymbolic())
- continue;
- Ref packedRef = cur.get(refName);
- ObjectId clr_oid = currentLooseRef.getObjectId();
- if (clr_oid != null
- && clr_oid.equals(packedRef.getObjectId())) {
- RefList<LooseRef> curLoose, newLoose;
- do {
- curLoose = looseRefs.get();
- int idx = curLoose.find(refName);
- if (idx < 0)
- break;
- newLoose = curLoose.remove(idx);
- } while (!looseRefs.compareAndSet(curLoose, newLoose));
- int levels = levelsIn(refName) - 2;
- delete(refFile, levels, rLck);
+ // Iterate over all refs to be packed
+ boolean dirty = false;
+ for (String refName : refs) {
+ Ref oldRef = readRef(refName, cur);
+ if (oldRef == null) {
+ continue; // A non-existent ref is already correctly packed.
}
- } finally {
- rLck.unlock();
+ if (oldRef.isSymbolic()) {
+ continue; // can't pack symbolic refs
+ }
+ // Add/Update it to packed-refs
+ Ref newRef = peeledPackedRef(oldRef);
+ if (newRef == oldRef) {
+ // No-op; peeledPackedRef returns the input ref only if it's already
+ // packed, and readRef returns a packed ref only if there is no
+ // loose ref.
+ continue;
+ }
+
+ dirty = true;
+ int idx = cur.find(refName);
+ if (idx >= 0) {
+ cur = cur.set(idx, newRef);
+ } else {
+ cur = cur.add(idx, newRef);
+ }
}
+ if (!dirty) {
+ // All requested refs were already packed accurately
+ return packed;
+ }
+
+ // The new content for packed-refs is collected. Persist it.
+ PackedRefList result = commitPackedRefs(lck, cur, packed);
+
+ // Now delete the loose refs which are now packed
+ for (String refName : refs) {
+ // Lock the loose ref
+ File refFile = fileFor(refName);
+ if (!fs.exists(refFile)) {
+ continue;
+ }
+
+ LockFile rLck = heldLocks.get(refName);
+ boolean shouldUnlock;
+ if (rLck == null) {
+ rLck = new LockFile(refFile);
+ if (!rLck.lock()) {
+ continue;
+ }
+ shouldUnlock = true;
+ } else {
+ shouldUnlock = false;
+ }
+
+ try {
+ LooseRef currentLooseRef = scanRef(null, refName);
+ if (currentLooseRef == null || currentLooseRef.isSymbolic()) {
+ continue;
+ }
+ Ref packedRef = cur.get(refName);
+ ObjectId clr_oid = currentLooseRef.getObjectId();
+ if (clr_oid != null
+ && clr_oid.equals(packedRef.getObjectId())) {
+ RefList<LooseRef> curLoose, newLoose;
+ do {
+ curLoose = looseRefs.get();
+ int idx = curLoose.find(refName);
+ if (idx < 0) {
+ break;
+ }
+ newLoose = curLoose.remove(idx);
+ } while (!looseRefs.compareAndSet(curLoose, newLoose));
+ int levels = levelsIn(refName) - 2;
+ delete(refFile, levels, rLck);
+ }
+ } finally {
+ if (shouldUnlock) {
+ rLck.unlock();
+ }
+ }
+ }
+ // Don't fire refsChanged. The refs have not change, only their
+ // storage.
+ return result;
+ } finally {
+ lck.unlock();
}
- // Don't fire refsChanged. The refs have not change, only their
- // storage.
} finally {
- lck.unlock();
+ inProcessPackedRefsLock.unlock();
}
}
+ @Nullable
+ LockFile lockPackedRefs() throws IOException {
+ LockFile lck = new LockFile(packedRefsFile);
+ for (int ms : getRetrySleepMs()) {
+ sleep(ms);
+ if (lck.lock()) {
+ return lck;
+ }
+ }
+ return null;
+ }
+
+ private LockFile lockPackedRefsOrThrow() throws IOException {
+ LockFile lck = lockPackedRefs();
+ if (lck == null) {
+ throw new LockFailedException(packedRefsFile);
+ }
+ return lck;
+ }
+
/**
* Make sure a ref is peeled and has the Storage PACKED. If the given ref
* has this attributes simply return it. Otherwise create a new peeled
@@ -794,7 +906,7 @@
throw noPackedRefs;
}
// Ignore it and leave the new list empty.
- return PackedRefList.NO_PACKED_REFS;
+ return NO_PACKED_REFS;
}
try {
return new PackedRefList(parsePackedRefs(br), snapshot,
@@ -875,8 +987,11 @@
return new StringBuilder(end - off).append(src, off, end).toString();
}
- private void commitPackedRefs(final LockFile lck, final RefList<Ref> refs,
+ PackedRefList commitPackedRefs(final LockFile lck, final RefList<Ref> refs,
final PackedRefList oldPackedList) throws IOException {
+ // Can't just return packedRefs.get() from this method; it might have been
+ // updated again after writePackedRefs() returns.
+ AtomicReference<PackedRefList> result = new AtomicReference<>();
new RefWriter(refs) {
@Override
protected void writeFile(String name, byte[] content)
@@ -898,10 +1013,28 @@
throw new ObjectWritingException(MessageFormat.format(JGitText.get().unableToWrite, name));
byte[] digest = Constants.newMessageDigest().digest(content);
- packedRefs.compareAndSet(oldPackedList, new PackedRefList(refs,
- lck.getCommitSnapshot(), ObjectId.fromRaw(digest)));
+ PackedRefList newPackedList = new PackedRefList(
+ refs, lck.getCommitSnapshot(), ObjectId.fromRaw(digest));
+
+ // This thread holds the file lock, so no other thread or process should
+ // be able to modify the packed-refs file on disk. If the list changed,
+ // it means something is very wrong, so throw an exception.
+ //
+ // However, we can't use a naive compareAndSet to check whether the
+ // update was successful, because another thread might _read_ the
+ // packed refs file that was written out by this thread while holding
+ // the lock, and update the packedRefs reference to point to that. So
+ // compare the actual contents instead.
+ PackedRefList afterUpdate = packedRefs.updateAndGet(
+ p -> p.id.equals(oldPackedList.id) ? newPackedList : p);
+ if (!afterUpdate.id.equals(newPackedList.id)) {
+ throw new ObjectWritingException(
+ MessageFormat.format(JGitText.get().unableToWrite, name));
+ }
+ result.set(newPackedList);
}
}.writePackedRefs();
+ return result.get();
}
private Ref readRef(String name, RefList<Ref> packed) throws IOException {
@@ -1023,7 +1156,7 @@
}
/** If the parent should fire listeners, fires them. */
- private void fireRefsChanged() {
+ void fireRefsChanged() {
final int last = lastNotifiedModCnt.get();
final int curr = modCnt.get();
if (last != curr && lastNotifiedModCnt.compareAndSet(last, curr) && last != 0)
@@ -1090,22 +1223,80 @@
}
}
- private static class PackedRefList extends RefList<Ref> {
- static final PackedRefList NO_PACKED_REFS = new PackedRefList(
- RefList.emptyList(), FileSnapshot.MISSING_FILE,
- ObjectId.zeroId());
+ /**
+ * Get times to sleep while retrying a possibly contentious operation.
+ * <p>
+ * For retrying an operation that might have high contention, such as locking
+ * the {@code packed-refs} file, the caller may implement a retry loop using
+ * the returned values:
+ *
+ * <pre>
+ * for (int toSleepMs : getRetrySleepMs()) {
+ * sleep(toSleepMs);
+ * if (isSuccessful(doSomething())) {
+ * return success;
+ * }
+ * }
+ * return failure;
+ * </pre>
+ *
+ * The first value in the returned iterable is 0, and the caller should treat
+ * a fully-consumed iterator as a timeout.
+ *
+ * @return iterable of times, in milliseconds, that the caller should sleep
+ * before attempting an operation.
+ */
+ Iterable<Integer> getRetrySleepMs() {
+ return retrySleepMs;
+ }
- final FileSnapshot snapshot;
+ void setRetrySleepMs(List<Integer> retrySleepMs) {
+ if (retrySleepMs == null || retrySleepMs.isEmpty()
+ || retrySleepMs.get(0).intValue() != 0) {
+ throw new IllegalArgumentException();
+ }
+ this.retrySleepMs = retrySleepMs;
+ }
- final ObjectId id;
+ /**
+ * Sleep with {@link Thread#sleep(long)}, converting {@link
+ * InterruptedException} to {@link InterruptedIOException}.
+ *
+ * @param ms
+ * time to sleep, in milliseconds; zero or negative is a no-op.
+ * @throws InterruptedIOException
+ * if sleeping was interrupted.
+ */
+ static void sleep(long ms) throws InterruptedIOException {
+ if (ms <= 0) {
+ return;
+ }
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException e) {
+ InterruptedIOException ie = new InterruptedIOException();
+ ie.initCause(e);
+ throw ie;
+ }
+ }
- PackedRefList(RefList<Ref> src, FileSnapshot s, ObjectId i) {
+ static class PackedRefList extends RefList<Ref> {
+
+ private final FileSnapshot snapshot;
+
+ private final ObjectId id;
+
+ private PackedRefList(RefList<Ref> src, FileSnapshot s, ObjectId i) {
super(src);
snapshot = s;
id = i;
}
}
+ private static final PackedRefList NO_PACKED_REFS = new PackedRefList(
+ RefList.emptyList(), FileSnapshot.MISSING_FILE,
+ ObjectId.zeroId());
+
private static LooseSymbolicRef newSymbolicRef(FileSnapshot snapshot,
String name, String target) {
Ref dst = new ObjectIdRef.Unpeeled(NEW, target, null);
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 3c1916b..1105352 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
@@ -50,6 +50,7 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.Repository;
/** Updates any reference stored by {@link RefDirectory}. */
@@ -127,14 +128,14 @@
return status;
}
- private String toResultString(final Result status) {
+ private String toResultString(Result status) {
switch (status) {
case FORCED:
- return "forced-update"; //$NON-NLS-1$
+ return ReflogEntry.PREFIX_FORCED_UPDATE;
case FAST_FORWARD:
- return "fast forward"; //$NON-NLS-1$
+ return ReflogEntry.PREFIX_FAST_FORWARD;
case NEW:
- return "created"; //$NON-NLS-1$
+ return ReflogEntry.PREFIX_CREATED;
default:
return null;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
index 16b2a46..8723a8b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
@@ -139,4 +139,4 @@
else
return null;
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
index 24d2c79..9873798 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java
@@ -287,4 +287,4 @@
|| refName.startsWith(R_REMOTES) //
|| refName.equals(R_STASH);
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
index 373a494..5fe0429 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SimpleDataOutput.java
@@ -136,4 +136,4 @@
public void writeUTF(String s) throws IOException {
throw new UnsupportedOperationException();
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
index 7e10878..969d02b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java
@@ -127,4 +127,4 @@
sz <<= 1;
return sz;
}
-}
\ No newline at end of file
+}
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 8810a9f..7271560 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
@@ -233,7 +233,9 @@
private List<CachedPack> cachedPacks = new ArrayList<>(2);
- private Set<ObjectId> tagTargets = Collections.emptySet();
+ private Set<ObjectId> tagTargets = NONE;
+
+ private Set<? extends ObjectId> excludeFromBitmapSelection = NONE;
private ObjectIdSet[] excludeInPacks;
@@ -712,8 +714,7 @@
public void preparePack(ProgressMonitor countingMonitor,
@NonNull Set<? extends ObjectId> want,
@NonNull Set<? extends ObjectId> have) throws IOException {
- preparePack(countingMonitor,
- want, have, Collections.<ObjectId> emptySet());
+ preparePack(countingMonitor, want, have, NONE, NONE);
}
/**
@@ -721,9 +722,9 @@
* <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.
+ * 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.
@@ -731,27 +732,67 @@
* 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}.
+ * 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}.
+ * {@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.
+ * an I/O problem occurred while reading objects.
*/
public void preparePack(ProgressMonitor countingMonitor,
@NonNull Set<? extends ObjectId> want,
@NonNull Set<? extends ObjectId> have,
@NonNull Set<? extends ObjectId> shallow) throws IOException {
+ preparePack(countingMonitor, want, have, shallow, NONE);
+ }
+
+ /**
+ * 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}.
+ * @param noBitmaps
+ * collection of objects to be excluded from bitmap commit
+ * selection.
+ * @throws IOException
+ * an I/O problem occurred while reading objects.
+ */
+ public void preparePack(ProgressMonitor countingMonitor,
+ @NonNull Set<? extends ObjectId> want,
+ @NonNull Set<? extends ObjectId> have,
+ @NonNull Set<? extends ObjectId> shallow,
+ @NonNull Set<? extends ObjectId> noBitmaps) throws IOException {
try (ObjectWalk ow = getObjectWalk()) {
ow.assumeShallow(shallow);
- preparePack(countingMonitor, ow, want, have);
+ preparePack(countingMonitor, ow, want, have, noBitmaps);
}
}
@@ -784,13 +825,17 @@
* points of graph traversal). Pass {@link #NONE} if all objects
* reachable from {@code want} are desired, such as when serving
* a clone.
+ * @param noBitmaps
+ * collection of objects to be excluded from bitmap commit
+ * selection.
* @throws IOException
* when some I/O problem occur during reading objects.
*/
public void preparePack(ProgressMonitor countingMonitor,
@NonNull ObjectWalk walk,
@NonNull Set<? extends ObjectId> interestingObjects,
- @NonNull Set<? extends ObjectId> uninterestingObjects)
+ @NonNull Set<? extends ObjectId> uninterestingObjects,
+ @NonNull Set<? extends ObjectId> noBitmaps)
throws IOException {
if (countingMonitor == null)
countingMonitor = NullProgressMonitor.INSTANCE;
@@ -798,7 +843,7 @@
throw new IllegalArgumentException(
JGitText.get().shallowPacksRequireDepthWalk);
findObjectsToPack(countingMonitor, walk, interestingObjects,
- uninterestingObjects);
+ uninterestingObjects, noBitmaps);
}
/**
@@ -965,8 +1010,9 @@
/**
* Write the prepared pack to the supplied stream.
* <p>
- * Called after {@link #preparePack(ProgressMonitor, ObjectWalk, Set, Set)}
- * or {@link #preparePack(ProgressMonitor, Set, Set)}.
+ * Called after
+ * {@link #preparePack(ProgressMonitor, ObjectWalk, Set, Set, Set)} or
+ * {@link #preparePack(ProgressMonitor, Set, Set)}.
* <p>
* Performs delta search if enabled and writes the pack stream.
* <p>
@@ -1652,12 +1698,14 @@
private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
@NonNull ObjectWalk walker, @NonNull Set<? extends ObjectId> want,
- @NonNull Set<? extends ObjectId> have) throws IOException {
+ @NonNull Set<? extends ObjectId> have,
+ @NonNull Set<? extends ObjectId> noBitmaps) throws IOException {
final long countingStart = System.currentTimeMillis();
beginPhase(PackingPhase.COUNTING, countingMonitor, ProgressMonitor.UNKNOWN);
stats.interestingObjects = Collections.unmodifiableSet(new HashSet<ObjectId>(want));
stats.uninterestingObjects = Collections.unmodifiableSet(new HashSet<ObjectId>(have));
+ excludeFromBitmapSelection = noBitmaps;
canBuildBitmaps = config.isBuildBitmaps()
&& !shallowPack
@@ -2070,8 +2118,8 @@
PackWriterBitmapPreparer bitmapPreparer = new PackWriterBitmapPreparer(
reader, writeBitmaps, pm, stats.interestingObjects, config);
- Collection<PackWriterBitmapPreparer.BitmapCommit> selectedCommits =
- bitmapPreparer.selectCommits(numCommits);
+ Collection<PackWriterBitmapPreparer.BitmapCommit> selectedCommits = bitmapPreparer
+ .selectCommits(numCommits, excludeFromBitmapSelection);
beginPhase(PackingPhase.BUILDING_BITMAPS, pm, selectedCommits.size());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
index 07a03b4..8bedddb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
@@ -141,6 +141,8 @@
*
* @param expectedCommitCount
* count of commits in the pack
+ * @param excludeFromBitmapSelection
+ * commits that should be excluded from bitmap selection
* @return commit objects for which bitmap indices should be built
* @throws IncorrectObjectTypeException
* if any of the processed objects is not a commit
@@ -149,7 +151,8 @@
* @throws MissingObjectException
* if an expected object is missing
*/
- Collection<BitmapCommit> selectCommits(int expectedCommitCount)
+ Collection<BitmapCommit> selectCommits(int expectedCommitCount,
+ Set<? extends ObjectId> excludeFromBitmapSelection)
throws IncorrectObjectTypeException, IOException,
MissingObjectException {
/*
@@ -164,7 +167,7 @@
RevWalk rw = new RevWalk(reader);
rw.setRetainBody(false);
CommitSelectionHelper selectionHelper = setupTipCommitBitmaps(rw,
- expectedCommitCount);
+ expectedCommitCount, excludeFromBitmapSelection);
pm.endTask();
int totCommits = selectionHelper.getCommitCount();
@@ -363,6 +366,8 @@
* @param expectedCommitCount
* expected count of commits. The actual count may be less due to
* unreachable garbage.
+ * @param excludeFromBitmapSelection
+ * commits that should be excluded from bitmap selection
* @return a {@link CommitSelectionHelper} containing bitmaps for the tip
* commits
* @throws IncorrectObjectTypeException
@@ -373,8 +378,10 @@
* if an expected object is missing
*/
private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw,
- int expectedCommitCount) throws IncorrectObjectTypeException,
- IOException, MissingObjectException {
+ int expectedCommitCount,
+ Set<? extends ObjectId> excludeFromBitmapSelection)
+ throws IncorrectObjectTypeException, IOException,
+ MissingObjectException {
BitmapBuilder reuse = commitBitmapIndex.newBitmapBuilder();
List<BitmapCommit> reuseCommits = new ArrayList<>();
for (PackBitmapIndexRemapper.Entry entry : bitmapRemapper) {
@@ -403,7 +410,8 @@
Set<RevCommit> peeledWant = new HashSet<>(want.size());
for (AnyObjectId objectId : want) {
RevObject ro = rw.peel(rw.parseAny(objectId));
- if (!(ro instanceof RevCommit) || reuse.contains(ro)) {
+ if (!(ro instanceof RevCommit) || reuse.contains(ro)
+ || excludeFromBitmapSelection.contains(ro)) {
continue;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
index 29a379e..0567051 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbreviatedObjectId.java
@@ -336,7 +336,7 @@
@Override
public int hashCode() {
- return w2;
+ return w1;
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index de1003b..825c1f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -738,4 +738,4 @@
protected final B self() {
return (B) this;
}
-}
\ No newline at end of file
+}
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 3f6995d..956607c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -58,6 +58,8 @@
import java.util.List;
import java.util.concurrent.TimeoutException;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -80,8 +82,10 @@
* clock skew between machines on the same LAN using an NTP server also on
* the same LAN should be under 5 seconds. 5 seconds is also not that long
* for a large `git push` operation to complete.
+ *
+ * @since 4.9
*/
- private static final Duration MAX_WAIT = Duration.ofSeconds(5);
+ protected static final Duration MAX_WAIT = Duration.ofSeconds(5);
private final RefDatabase refdb;
@@ -173,25 +177,36 @@
* @return message the caller wants to include in the reflog; null if the
* update should not be logged.
*/
+ @Nullable
public String getRefLogMessage() {
return refLogMessage;
}
- /** @return {@code true} if the ref log message should show the result. */
+ /**
+ * Check whether the reflog message should include the result of the update,
+ * such as fast-forward or force-update.
+ * <p>
+ * Describes the default for commands in this batch that do not override it
+ * with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
+ *
+ * @return true if the message should include the result.
+ */
public boolean isRefLogIncludingResult() {
return refLogIncludeResult;
}
/**
* Set the message to include in the reflog.
+ * <p>
+ * Describes the default for commands in this batch that do not override it
+ * with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
*
* @param msg
- * the message to describe this change. It may be null if
- * appendStatus is null in order not to append to the reflog
+ * the message to describe this change. If null and appendStatus is
+ * false, the reflog will not be updated.
* @param appendStatus
* true if the status of the ref change (fast-forward or
- * forced-update) should be appended to the user supplied
- * message.
+ * forced-update) should be appended to the user supplied message.
* @return {@code this}.
*/
public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) {
@@ -209,6 +224,8 @@
/**
* Don't record this update in the ref's associated reflog.
+ * <p>
+ * Equivalent to {@code setRefLogMessage(null, false)}.
*
* @return {@code this}.
*/
@@ -218,7 +235,11 @@
return this;
}
- /** @return true if log has been disabled by {@link #disableRefLog()}. */
+ /**
+ * Check whether log has been disabled by {@link #disableRefLog()}.
+ *
+ * @return true if disabled.
+ */
public boolean isRefLogDisabled() {
return refLogMessage == null;
}
@@ -323,14 +344,29 @@
/**
* Gets the list of option strings associated with this update.
*
- * @return pushOptions
+ * @return push options that were passed to {@link #execute}; prior to calling
+ * {@link #execute}, always returns null.
* @since 4.5
*/
+ @Nullable
public List<String> getPushOptions() {
return pushOptions;
}
/**
+ * Set push options associated with this update.
+ * <p>
+ * Implementations must call this at the top of {@link #execute(RevWalk,
+ * ProgressMonitor, List)}.
+ *
+ * @param options options passed to {@code execute}.
+ * @since 4.9
+ */
+ protected void setPushOptions(List<String> options) {
+ pushOptions = options;
+ }
+
+ /**
* @return list of timestamps the batch must wait for.
* @since 4.6
*/
@@ -396,7 +432,7 @@
}
if (options != null) {
- pushOptions = options;
+ setPushOptions(options);
}
monitor.beginTask(JGitText.get().updatingReferences, commands.size());
@@ -407,6 +443,11 @@
for (ReceiveCommand cmd : commands) {
try {
if (cmd.getResult() == NOT_ATTEMPTED) {
+ if (isMissing(walk, cmd.getOldId())
+ || isMissing(walk, cmd.getNewId())) {
+ cmd.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT);
+ continue;
+ }
cmd.updateType(walk);
switch (cmd.getType()) {
case CREATE:
@@ -462,7 +503,7 @@
break SWITCH;
}
ru.setCheckConflicting(false);
- addRefToPrefixes(takenPrefixes, cmd.getRefName());
+ takenPrefixes.addAll(getPrefixes(cmd.getRefName()));
takenNames.add(cmd.getRefName());
cmd.setResult(ru.update(walk));
}
@@ -478,6 +519,19 @@
monitor.endTask();
}
+ private static boolean isMissing(RevWalk walk, ObjectId id)
+ throws IOException {
+ if (id.equals(ObjectId.zeroId())) {
+ return false; // Explicit add or delete is not missing.
+ }
+ try {
+ walk.parseAny(id);
+ return false;
+ } catch (MissingObjectException e) {
+ return true;
+ }
+ }
+
/**
* Wait for timestamps to be in the past, aborting commands on timeout.
*
@@ -523,29 +577,45 @@
execute(walk, monitor, null);
}
- private static Collection<String> getTakenPrefixes(
- final Collection<String> names) {
+ private static Collection<String> getTakenPrefixes(Collection<String> names) {
Collection<String> ref = new HashSet<>();
- for (String name : names)
- ref.addAll(getPrefixes(name));
+ for (String name : names) {
+ addPrefixesTo(name, ref);
+ }
return ref;
}
- private static void addRefToPrefixes(Collection<String> prefixes,
- String name) {
- for (String prefix : getPrefixes(name)) {
- prefixes.add(prefix);
- }
+ /**
+ * Get all path prefixes of a ref name.
+ *
+ * @param name
+ * ref name.
+ * @return path prefixes of the ref name. For {@code refs/heads/foo}, returns
+ * {@code refs} and {@code refs/heads}.
+ * @since 4.9
+ */
+ protected static Collection<String> getPrefixes(String name) {
+ Collection<String> ret = new HashSet<>();
+ addPrefixesTo(name, ret);
+ return ret;
}
- static Collection<String> getPrefixes(String s) {
- Collection<String> ret = new HashSet<>();
- int p1 = s.indexOf('/');
+ /**
+ * Add prefixes of a ref name to an existing collection.
+ *
+ * @param name
+ * ref name.
+ * @param out
+ * path prefixes of the ref name. For {@code refs/heads/foo},
+ * returns {@code refs} and {@code refs/heads}.
+ * @since 4.9
+ */
+ protected static void addPrefixesTo(String name, Collection<String> out) {
+ int p1 = name.indexOf('/');
while (p1 > 0) {
- ret.add(s.substring(0, p1));
- p1 = s.indexOf('/', p1 + 1);
+ out.add(name.substring(0, p1));
+ p1 = name.indexOf('/', p1 + 1);
}
- return ret;
}
/**
@@ -560,11 +630,11 @@
*/
protected RefUpdate newUpdate(ReceiveCommand cmd) throws IOException {
RefUpdate ru = refdb.newUpdate(cmd.getRefName(), false);
- if (isRefLogDisabled())
+ if (isRefLogDisabled(cmd)) {
ru.disableRefLog();
- else {
+ } else {
ru.setRefLogIdent(refLogIdent);
- ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
+ ru.setRefLogMessage(getRefLogMessage(cmd), isRefLogIncludingResult(cmd));
}
ru.setPushCertificate(pushCert);
switch (cmd.getType()) {
@@ -585,6 +655,47 @@
}
}
+ /**
+ * Check whether reflog is disabled for a command.
+ *
+ * @param cmd
+ * specific command.
+ * @return whether the reflog is disabled, taking into account the state from
+ * this instance as well as overrides in the given command.
+ * @since 4.9
+ */
+ protected boolean isRefLogDisabled(ReceiveCommand cmd) {
+ return cmd.hasCustomRefLog() ? cmd.isRefLogDisabled() : isRefLogDisabled();
+ }
+
+ /**
+ * Get reflog message for a command.
+ *
+ * @param cmd
+ * specific command.
+ * @return reflog message, taking into account the state from this instance as
+ * well as overrides in the given command.
+ * @since 4.9
+ */
+ protected String getRefLogMessage(ReceiveCommand cmd) {
+ return cmd.hasCustomRefLog() ? cmd.getRefLogMessage() : getRefLogMessage();
+ }
+
+ /**
+ * Check whether the reflog message for a command should include the result.
+ *
+ * @param cmd
+ * specific command.
+ * @return whether the reflog message should show the result, taking into
+ * account the state from this instance as well as overrides in the
+ * given command.
+ * @since 4.9
+ */
+ protected boolean isRefLogIncludingResult(ReceiveCommand cmd) {
+ return cmd.hasCustomRefLog()
+ ? cmd.isRefLogIncludingResult() : isRefLogIncludingResult();
+ }
+
@Override
public String toString() {
StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
index 54c8052..a75293d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
@@ -46,6 +46,8 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.lib.internal.WorkQueue;
+
/** ProgressMonitor that batches update events. */
public abstract class BatchingProgressMonitor implements ProgressMonitor {
private long delayStartTime;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
index 345016c..4e0dc2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapObject.java
@@ -62,4 +62,4 @@
* @return unique hash of this object.
*/
public abstract ObjectId getObjectId();
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
index d6608cd..34d0b14 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CheckoutEntry.java
@@ -17,4 +17,4 @@
*/
public abstract String getToBranch();
-}
\ No newline at end of file
+}
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 74fc706..ad5b106 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -108,6 +108,12 @@
public static final String CONFIG_PULL_SECTION = "pull";
/**
+ * The "merge" section
+ * @since 4.9
+ */
+ public static final String CONFIG_MERGE_SECTION = "merge";
+
+ /**
* The "filter" section
* @since 4.6
*/
@@ -291,6 +297,20 @@
public static final String CONFIG_KEY_PRUNEPACKEXPIRE = "prunepackexpire";
/**
+ * The "logexpiry" key
+ *
+ * @since 4.7
+ */
+ public static final String CONFIG_KEY_LOGEXPIRY = "logExpiry";
+
+ /**
+ * The "autodetach" key
+ *
+ * @since 4.7
+ */
+ public static final String CONFIG_KEY_AUTODETACH = "autoDetach";
+
+ /**
* The "aggressiveDepth" key
* @since 3.6
*/
@@ -351,6 +371,13 @@
public static final String CONFIG_KEY_RENAMES = "renames";
/**
+ * The "inCoreLimit" key in the "merge section". It's a size limit (bytes) used to
+ * control a file to be stored in {@code Heap} or {@code LocalFile} during the merge.
+ * @since 4.9
+ */
+ public static final String CONFIG_KEY_IN_CORE_LIMIT = "inCoreLimit";
+
+ /**
* The "prune" key
* @since 3.3
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index ff80672..bb7316d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2006-2017, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -429,6 +429,20 @@
public static final String HOOKS = "hooks";
/**
+ * Merge attribute.
+ *
+ * @since 4.9
+ */
+ public static final String ATTR_MERGE = "merge"; //$NON-NLS-1$
+
+ /**
+ * Binary value for custom merger.
+ *
+ * @since 4.9
+ */
+ public static final String ATTR_BUILTIN_BINARY_MERGER = "binary"; //$NON-NLS-1$
+
+ /**
* Create a new digest function for objects.
*
* @return a new digest object.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
index 1047a6d..c4923a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
@@ -43,6 +43,8 @@
package org.eclipse.jgit.lib;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -177,8 +179,8 @@
while (tokenCount < 3 && nextSpace < lineEnd) {
switch (tokenCount) {
case 0:
- String actionToken = new String(buf, tokenBegin, nextSpace
- - tokenBegin - 1);
+ String actionToken = new String(buf, tokenBegin,
+ nextSpace - tokenBegin - 1, UTF_8);
tokenBegin = nextSpace;
action = RebaseTodoLine.Action.parse(actionToken);
if (action == null)
@@ -186,14 +188,14 @@
break;
case 1:
nextSpace = RawParseUtils.next(buf, tokenBegin, ' ');
- String commitToken = new String(buf, tokenBegin, nextSpace
- - tokenBegin - 1);
+ String commitToken = new String(buf, tokenBegin,
+ nextSpace - tokenBegin - 1, UTF_8);
tokenBegin = nextSpace;
commit = AbbreviatedObjectId.fromString(commitToken);
break;
case 2:
- return new RebaseTodoLine(action, commit, RawParseUtils.decode(
- buf, tokenBegin, 1 + lineEnd));
+ return new RebaseTodoLine(action, commit,
+ RawParseUtils.decode(buf, tokenBegin, 1 + lineEnd));
}
tokenCount++;
}
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 fc334f0..0778645 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -58,7 +58,13 @@
* Creates, updates or deletes any reference.
*/
public abstract class RefUpdate {
- /** Status of an update request. */
+ /**
+ * Status of an update request.
+ * <p>
+ * New values may be added to this enum in the future. Callers may assume that
+ * unknown values are failures, and may generally treat them the same as
+ * {@link #REJECTED_OTHER_REASON}.
+ */
public static enum Result {
/** The ref update/delete has not been attempted by the caller. */
NOT_ATTEMPTED,
@@ -114,6 +120,10 @@
* merged into the new value. The configuration did not allow a forced
* update/delete to take place, so ref still contains the old value. No
* previous history was lost.
+ * <p>
+ * <em>Note:</em> Despite the general name, this result only refers to the
+ * non-fast-forward case. For more general errors, see {@link
+ * #REJECTED_OTHER_REASON}.
*/
REJECTED,
@@ -139,7 +149,25 @@
* The ref was renamed from another name
* <p>
*/
- RENAMED
+ RENAMED,
+
+ /**
+ * One or more objects aren't in the repository.
+ * <p>
+ * This is severe indication of either repository corruption on the
+ * server side, or a bug in the client wherein the client did not supply
+ * all required objects during the pack transfer.
+ *
+ * @since 4.9
+ */
+ REJECTED_MISSING_OBJECT,
+
+ /**
+ * Rejected for some other reason not covered by another enum value.
+ *
+ * @since 4.9
+ */
+ REJECTED_OTHER_REASON;
}
/** New value the caller wants this ref to have. */
@@ -278,6 +306,16 @@
}
/**
+ * Return whether this update is actually detaching a symbolic ref.
+ *
+ * @return true if detaching a symref.
+ * @since 4.9
+ */
+ public boolean isDetachingSymbolicRef() {
+ return detachingSymbolicRef;
+ }
+
+ /**
* Set the new value the ref will update to.
*
* @param id
@@ -627,34 +665,47 @@
RevObject oldObj;
// don't make expensive conflict check if this is an existing Ref
- if (oldValue == null && checkConflicting && getRefDatabase().isNameConflicting(getName()))
+ if (oldValue == null && checkConflicting
+ && getRefDatabase().isNameConflicting(getName())) {
return Result.LOCK_FAILURE;
+ }
try {
// 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))
+ if (!tryLock(!detachingSymbolicRef)) {
return Result.LOCK_FAILURE;
+ }
if (expValue != null) {
final ObjectId o;
o = oldValue != null ? oldValue : ObjectId.zeroId();
- if (!AnyObjectId.equals(expValue, o))
+ if (!AnyObjectId.equals(expValue, o)) {
return Result.LOCK_FAILURE;
+ }
}
- if (oldValue == null)
+ try {
+ newObj = safeParseNew(walk, newValue);
+ } catch (MissingObjectException e) {
+ return Result.REJECTED_MISSING_OBJECT;
+ }
+
+ if (oldValue == null) {
return store.execute(Result.NEW);
+ }
- newObj = safeParse(walk, newValue);
- oldObj = safeParse(walk, oldValue);
- if (newObj == oldObj && !detachingSymbolicRef)
+ oldObj = safeParseOld(walk, oldValue);
+ if (newObj == oldObj && !detachingSymbolicRef) {
return store.execute(Result.NO_CHANGE);
+ }
- if (isForceUpdate())
+ if (isForceUpdate()) {
return store.execute(Result.FORCED);
+ }
if (newObj instanceof RevCommit && oldObj instanceof RevCommit) {
- if (walk.isMergedInto((RevCommit) oldObj, (RevCommit) newObj))
+ if (walk.isMergedInto((RevCommit) oldObj, (RevCommit) newObj)) {
return store.execute(Result.FAST_FORWARD);
+ }
}
return Result.REJECTED;
@@ -674,16 +725,23 @@
checkConflicting = check;
}
- private static RevObject safeParse(final RevWalk rw, final AnyObjectId id)
+ private static RevObject safeParseNew(RevWalk rw, AnyObjectId newId)
+ throws IOException {
+ if (newId == null || ObjectId.zeroId().equals(newId)) {
+ return null;
+ }
+ return rw.parseAny(newId);
+ }
+
+ private static RevObject safeParseOld(RevWalk rw, AnyObjectId oldId)
throws IOException {
try {
- return id != null ? rw.parseAny(id) : null;
+ return oldId != null ? rw.parseAny(oldId) : null;
} catch (MissingObjectException e) {
- // We can expect some objects to be missing, like if we are
- // trying to force a deletion of a branch and the object it
- // points to has been pruned from the database due to freak
- // corruption accidents (it happens with 'git new-work-dir').
- //
+ // We can expect some old objects to be missing, like if we are trying to
+ // force a deletion of a branch and the object it points to has been
+ // pruned from the database due to freak corruption accidents (it happens
+ // with 'git new-work-dir').
return null;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
index 0504646..afa6521 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogEntry.java
@@ -50,6 +50,39 @@
public interface ReflogEntry {
/**
+ * Prefix used in reflog messages when the ref was first created.
+ * <p>
+ * Does not have a corresponding constant in C git, but is untranslated like
+ * the other constants.
+ *
+ * @since 4.9
+ */
+ public static final String PREFIX_CREATED = "created"; //$NON-NLS-1$
+
+ /**
+ * Prefix used in reflog messages when the ref was updated with a fast
+ * forward.
+ * <p>
+ * Untranslated, and exactly matches the
+ * <a href="https://git.kernel.org/pub/scm/git/git.git/tree/builtin/fetch.c?id=f3da2b79be9565779e4f76dc5812c68e156afdf0#n680">
+ * untranslated string in C git</a>.
+ *
+ * @since 4.9
+ */
+ public static final String PREFIX_FAST_FORWARD = "fast-forward"; //$NON-NLS-1$
+
+ /**
+ * Prefix used in reflog messages when the ref was force updated.
+ * <p>
+ * Untranslated, and exactly matches the
+ * <a href="https://git.kernel.org/pub/scm/git/git.git/tree/builtin/fetch.c?id=f3da2b79be9565779e4f76dc5812c68e156afdf0#n695">
+ * untranslated string in C git</a>.
+ *
+ * @since 4.9
+ */
+ public static final String PREFIX_FORCED_UPDATE = "forced-update"; //$NON-NLS-1$
+
+ /**
* @return the commit id before the change
*/
public abstract ObjectId getOldId();
@@ -75,4 +108,4 @@
*/
public abstract CheckoutEntry parseCheckout();
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
index fdab883..d3f2536 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ReflogReader.java
@@ -86,4 +86,4 @@
public abstract List<ReflogEntry> getReverseEntries(int max)
throws IOException;
-}
\ No newline at end of file
+}
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 baa5286..53e9fe3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -55,6 +55,7 @@
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.internal.WorkQueue;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SubmoduleConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SubmoduleConfig.java
index 3126160..12f7b82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SubmoduleConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SubmoduleConfig.java
@@ -43,6 +43,10 @@
package org.eclipse.jgit.lib;
+import java.util.Locale;
+
+import org.eclipse.jgit.util.StringUtils;
+
/**
* Submodule section of a Git configuration file.
*
@@ -75,12 +79,17 @@
@Override
public String toConfigValue() {
- return configValue;
+ return name().toLowerCase(Locale.ROOT).replace('_', '-');
}
@Override
public boolean matchConfigValue(String s) {
- return configValue.equals(s);
+ if (StringUtils.isEmptyOrNull(s)) {
+ return false;
+ }
+ s = s.replace('-', '_');
+ return name().equalsIgnoreCase(s)
+ || configValue.equalsIgnoreCase(s);
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
index 7675fcc..c31c3c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TextProgressMonitor.java
@@ -44,7 +44,10 @@
package org.eclipse.jgit.lib;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
@@ -56,7 +59,7 @@
/** Initialize a new progress monitor. */
public TextProgressMonitor() {
- this(new PrintWriter(System.err));
+ this(new PrintWriter(new OutputStreamWriter(System.err, UTF_8)));
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
similarity index 95%
rename from org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkQueue.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
index 07b87f5..3303f47 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkQueue.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/WorkQueue.java
@@ -41,7 +41,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.eclipse.jgit.lib;
+package org.eclipse.jgit.lib.internal;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -50,7 +50,7 @@
/**
* Simple work queue to run tasks in the background
*/
-class WorkQueue {
+public class WorkQueue {
private static final ScheduledThreadPoolExecutor executor;
static final Object executorKiller;
@@ -94,7 +94,10 @@
};
}
- static ScheduledThreadPoolExecutor getExecutor() {
+ /**
+ * @return the WorkQueue's executor
+ */
+ public static ScheduledThreadPoolExecutor getExecutor() {
return executor;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java
index 0345921..060f068 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatterPass.java
@@ -143,4 +143,4 @@
if (out.isBeginln())
out.write('\n');
}
-}
\ No newline at end of file
+}
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 1aac352..92c2bb3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -2,6 +2,7 @@
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
* Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com>
* Copyright (C) 2012, Research In Motion Limited
+ * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -67,6 +68,7 @@
import java.util.List;
import java.util.Map;
+import org.eclipse.jgit.attributes.Attributes;
import org.eclipse.jgit.diff.DiffAlgorithm;
import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
import org.eclipse.jgit.diff.RawText;
@@ -83,6 +85,7 @@
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -270,6 +273,12 @@
*/
protected MergeAlgorithm mergeAlgorithm;
+ /**
+ * The size limit (bytes) which controls a file to be stored in {@code Heap} or
+ * {@code LocalFile} during the merge.
+ */
+ private int inCoreLimit;
+
private static MergeAlgorithm getMergeAlgorithm(Config config) {
SupportedAlgorithm diffAlg = config.getEnum(
CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
@@ -277,6 +286,11 @@
return new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
}
+ private static int getInCoreLimit(Config config) {
+ return config.getInt(
+ ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20);
+ }
+
private static String[] defaultCommitNames() {
return new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@@ -287,7 +301,9 @@
*/
protected ResolveMerger(Repository local, boolean inCore) {
super(local);
- mergeAlgorithm = getMergeAlgorithm(local.getConfig());
+ Config config = local.getConfig();
+ mergeAlgorithm = getMergeAlgorithm(config);
+ inCoreLimit = getInCoreLimit(config);
commitNames = defaultCommitNames();
this.inCore = inCore;
@@ -429,9 +445,10 @@
}
/**
- * Processes one path and tries to merge. This method will do all do all
- * trivial (not content) merges and will also detect if a merge will fail.
- * The merge will fail when one of the following is true
+ * Processes one path and tries to merge taking git attributes in account.
+ * This method will do all trivial (not content) merges and will also detect
+ * if a merge will fail. The merge will fail when one of the following is
+ * true
* <ul>
* <li>the index entry does not match the entry in ours. When merging one
* branch into the current HEAD, ours will point to HEAD and theirs will
@@ -463,6 +480,8 @@
* @param ignoreConflicts
* see
* {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
+ * @param attributes
+ * the attributes defined for this entry
* @return <code>false</code> if the merge will fail because the index entry
* didn't match ours or the working-dir file was dirty and a
* conflict occurred
@@ -470,12 +489,12 @@
* @throws IncorrectObjectTypeException
* @throws CorruptObjectException
* @throws IOException
- * @since 3.5
+ * @since 4.9
*/
protected boolean processEntry(CanonicalTreeParser base,
CanonicalTreeParser ours, CanonicalTreeParser theirs,
DirCacheBuildIterator index, WorkingTreeIterator work,
- boolean ignoreConflicts)
+ boolean ignoreConflicts, Attributes attributes)
throws MissingObjectException, IncorrectObjectTypeException,
CorruptObjectException, IOException {
enterSubtree = true;
@@ -627,7 +646,8 @@
return false;
// Don't attempt to resolve submodule link conflicts
- if (isGitLink(modeO) || isGitLink(modeT)) {
+ if (isGitLink(modeO) || isGitLink(modeT)
+ || !attributes.canBeContentMerged()) {
add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
@@ -636,8 +656,9 @@
}
MergeResult<RawText> result = contentMerge(base, ours, theirs);
- if (ignoreConflicts)
+ if (ignoreConflicts) {
result.setContainsConflicts(false);
+ }
updateIndex(base, ours, theirs, result);
if (result.containsConflicts() && !ignoreConflicts)
unmergedPaths.add(tw.getPathString());
@@ -760,6 +781,7 @@
MergeResult<RawText> result) throws FileNotFoundException,
IOException {
File mergedFile = !inCore ? writeMergedFile(result) : null;
+
if (result.containsConflicts()) {
// A conflict occurred, the file will contain conflict markers
// the index will be populated with the three stages and the
@@ -827,7 +849,7 @@
private ObjectId insertMergeResult(MergeResult<RawText> result)
throws IOException {
TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
- db != null ? nonNullRepo().getDirectory() : null, 10 << 20);
+ db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
try {
new MergeFormatter().formatMerge(buf, result,
Arrays.asList(commitNames), CHARACTER_ENCODING);
@@ -1091,6 +1113,8 @@
protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
throws IOException {
boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
+ boolean hasAttributeNodeProvider = treeWalk
+ .getAttributesNodeProvider() != null;
while (treeWalk.next()) {
if (!processEntry(
treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
@@ -1098,7 +1122,9 @@
treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
- WorkingTreeIterator.class) : null, ignoreConflicts)) {
+ WorkingTreeIterator.class) : null,
+ ignoreConflicts, hasAttributeNodeProvider
+ ? treeWalk.getAttributes() : new Attributes())) {
cleanUp();
return false;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java b/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
index c85c179..bde69c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/nls/TranslationBundle.java
@@ -184,4 +184,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
index e230c9b..51dd2ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/SkipRevFilter.java
@@ -91,4 +91,4 @@
public RevFilter clone() {
return new SkipRevFilter(skip);
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index c64aa2d..4f2374f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -260,6 +260,8 @@
private boolean cutDeltaChains;
+ private boolean singlePack;
+
/** Create a default configuration. */
public PackConfig() {
// Fields are initialized to defaults.
@@ -320,6 +322,7 @@
this.bitmapExcessiveBranchCount = cfg.bitmapExcessiveBranchCount;
this.bitmapInactiveBranchAgeInDays = cfg.bitmapInactiveBranchAgeInDays;
this.cutDeltaChains = cfg.cutDeltaChains;
+ this.singlePack = cfg.singlePack;
}
/**
@@ -555,6 +558,30 @@
}
/**
+ * @return true if all of refs/* should be packed in a single pack. Default
+ * is false, packing a separate GC_REST pack for references outside
+ * of refs/heads/* and refs/tags/*.
+ * @since 4.9
+ */
+ public boolean getSinglePack() {
+ return singlePack;
+ }
+
+ /**
+ * If {@code true}, packs a single GC pack for all objects reachable from
+ * refs/*. Otherwise packs the GC pack with objects reachable from
+ * refs/heads/* and refs/tags/*, and a GC_REST pack with the remaining
+ * reachable objects. Disabled by default, packing GC and GC_REST.
+ *
+ * @param single
+ * true to pack a single GC pack rather than GC and GC_REST packs
+ * @since 4.9
+ */
+ public void setSinglePack(boolean single) {
+ singlePack = single;
+ }
+
+ /**
* Get the number of objects to try when looking for a delta base.
*
* This limit is per thread, if 4 threads are used the actual memory used
@@ -1026,6 +1053,8 @@
rc.getBoolean("pack", "deltacompression", isDeltaCompress())); //$NON-NLS-1$ //$NON-NLS-2$
setCutDeltaChains(
rc.getBoolean("pack", "cutdeltachains", getCutDeltaChains())); //$NON-NLS-1$ //$NON-NLS-2$
+ setSinglePack(
+ rc.getBoolean("pack", "singlepack", getSinglePack())); //$NON-NLS-1$ //$NON-NLS-2$
setBuildBitmaps(
rc.getBoolean("pack", "buildbitmaps", isBuildBitmaps())); //$NON-NLS-1$ //$NON-NLS-2$
setBitmapContiguousCommitCount(
@@ -1073,6 +1102,7 @@
.append(getBitmapExcessiveBranchCount());
b.append(", bitmapInactiveBranchAge=") //$NON-NLS-1$
.append(getBitmapInactiveBranchAgeInDays());
+ b.append(", singlePack=").append(getSinglePack()); //$NON-NLS-1$
return b.toString();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 280e6d4..dd26fe5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -74,6 +74,7 @@
import org.eclipse.jgit.lib.BatchingProgressMonitor;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
@@ -360,12 +361,19 @@
private void expandSingle(final RefSpec spec, final Set<Ref> matched)
throws TransportException {
- final Ref src = conn.getRef(spec.getSource());
- if (src == null) {
- throw new TransportException(MessageFormat.format(JGitText.get().remoteDoesNotHaveSpec, spec.getSource()));
+ String want = spec.getSource();
+ if (ObjectId.isId(want)) {
+ want(ObjectId.fromString(want));
+ return;
}
- if (matched.add(src))
+
+ Ref src = conn.getRef(want);
+ if (src == null) {
+ throw new TransportException(MessageFormat.format(JGitText.get().remoteDoesNotHaveSpec, want));
+ }
+ if (matched.add(src)) {
want(src, spec);
+ }
}
private Collection<Ref> expandAutoFollowTags() throws TransportException {
@@ -440,6 +448,11 @@
fetchHeadUpdates.add(fhr);
}
+ private void want(ObjectId id) {
+ askFor.put(id,
+ new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, id.name(), id));
+ }
+
private TrackingRefUpdate createUpdate(RefSpec spec, ObjectId newId)
throws TransportException {
Ref ref = localRefs().get(spec.getDestination());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index f445bcb..82d6ed4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -229,4 +229,4 @@
return exitValue();
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
index bab5bf0..5727b03 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
@@ -317,4 +317,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index c82b389..db3578b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -143,7 +143,7 @@
private boolean expectDataAfterPackFooter;
- private long objectCount;
+ private long expectedObjectCount;
private PackedObjectInfo[] entries;
@@ -173,8 +173,8 @@
private LongMap<UnresolvedDelta> baseByPos;
- /** Blobs whose contents need to be double-checked after indexing. */
- private BlockList<PackedObjectInfo> deferredCheckBlobs;
+ /** Objects need to be double-checked for collision after indexing. */
+ private BlockList<PackedObjectInfo> collisionCheckObjs;
private MessageDigest packDigest;
@@ -525,15 +525,15 @@
try {
readPackHeader();
- entries = new PackedObjectInfo[(int) objectCount];
+ entries = new PackedObjectInfo[(int) expectedObjectCount];
baseById = new ObjectIdOwnerMap<>();
baseByPos = new LongMap<>();
- deferredCheckBlobs = new BlockList<>();
+ collisionCheckObjs = new BlockList<>();
receiving.beginTask(JGitText.get().receivingObjects,
- (int) objectCount);
+ (int) expectedObjectCount);
try {
- for (int done = 0; done < objectCount; done++) {
+ for (int done = 0; done < expectedObjectCount; done++) {
indexOneObject();
receiving.update(1);
if (receiving.isCancelled())
@@ -545,32 +545,12 @@
receiving.endTask();
}
- if (!deferredCheckBlobs.isEmpty())
- doDeferredCheckBlobs();
+ if (!collisionCheckObjs.isEmpty()) {
+ checkObjectCollision();
+ }
+
if (deltaCount > 0) {
- if (resolving instanceof BatchingProgressMonitor) {
- ((BatchingProgressMonitor) resolving).setDelayStart(
- 1000,
- TimeUnit.MILLISECONDS);
- }
- resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
- resolveDeltas(resolving);
- if (entryCount < objectCount) {
- if (!isAllowThin()) {
- throw new IOException(MessageFormat.format(
- JGitText.get().packHasUnresolvedDeltas,
- Long.valueOf(objectCount - entryCount)));
- }
-
- resolveDeltasWithExternalBases(resolving);
-
- if (entryCount < objectCount) {
- throw new IOException(MessageFormat.format(
- JGitText.get().packHasUnresolvedDeltas,
- Long.valueOf(objectCount - entryCount)));
- }
- }
- resolving.endTask();
+ processDeltas(resolving);
}
packDigest = null;
@@ -593,6 +573,31 @@
return null; // By default there is no locking.
}
+ private void processDeltas(ProgressMonitor resolving) throws IOException {
+ if (resolving instanceof BatchingProgressMonitor) {
+ ((BatchingProgressMonitor) resolving).setDelayStart(1000,
+ TimeUnit.MILLISECONDS);
+ }
+ resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
+ resolveDeltas(resolving);
+ if (entryCount < expectedObjectCount) {
+ if (!isAllowThin()) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().packHasUnresolvedDeltas,
+ Long.valueOf(expectedObjectCount - entryCount)));
+ }
+
+ resolveDeltasWithExternalBases(resolving);
+
+ if (entryCount < expectedObjectCount) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().packHasUnresolvedDeltas,
+ Long.valueOf(expectedObjectCount - entryCount)));
+ }
+ }
+ resolving.endTask();
+ }
+
private void resolveDeltas(final ProgressMonitor progress)
throws IOException {
final int last = entryCount;
@@ -675,10 +680,14 @@
objectDigest.digest(tempObjectId);
verifySafeObject(tempObjectId, type, visit.data);
+ if (isCheckObjectCollisions() && readCurs.has(tempObjectId)) {
+ checkObjectCollision(tempObjectId, type, visit.data);
+ }
PackedObjectInfo oe;
oe = newInfo(tempObjectId, visit.delta, visit.parent.id);
oe.setOffset(visit.delta.position);
+ oe.setType(type);
onInflatedObjectData(oe, type, visit.data);
addObjectAndTrack(oe);
visit.id = oe;
@@ -849,10 +858,9 @@
visit.id = baseId;
final int typeCode = ldr.getType();
final PackedObjectInfo oe = newInfo(baseId, null, null);
-
+ oe.setType(typeCode);
if (onAppendBase(typeCode, visit.data, oe))
entries[entryCount++] = oe;
-
visit.nextChild = firstChildOf(oe);
resolveDeltas(visit.next(), typeCode,
new ObjectTypeAndSize(), progress);
@@ -873,7 +881,7 @@
private void growEntries(int extraObjects) {
final PackedObjectInfo[] ne;
- ne = new PackedObjectInfo[(int) objectCount + extraObjects];
+ ne = new PackedObjectInfo[(int) expectedObjectCount + extraObjects];
System.arraycopy(entries, 0, ne, 0, entryCount);
entries = ne;
}
@@ -896,9 +904,9 @@
if (vers != 2 && vers != 3)
throw new IOException(MessageFormat.format(
JGitText.get().unsupportedPackVersion, Long.valueOf(vers)));
- objectCount = NB.decodeUInt32(buf, p + 8);
+ final long objectCount = NB.decodeUInt32(buf, p + 8);
use(hdrln);
-
+ setExpectedObjectCount(objectCount);
onPackHeader(objectCount);
}
@@ -1031,7 +1039,6 @@
objectDigest.update((byte) 0);
final byte[] data;
- boolean checkContentLater = false;
if (type == Constants.OBJ_BLOB) {
byte[] readBuffer = buffer();
InputStream inf = inflate(Source.INPUT, sz);
@@ -1045,10 +1052,7 @@
}
inf.close();
objectDigest.digest(tempObjectId);
- checkContentLater = isCheckObjectCollisions()
- && readCurs.has(tempObjectId);
data = null;
-
} else {
data = inflateAndReturn(Source.INPUT, sz);
objectDigest.update(data);
@@ -1058,16 +1062,32 @@
PackedObjectInfo obj = newInfo(tempObjectId, null, null);
obj.setOffset(pos);
+ obj.setType(type);
onEndWholeObject(obj);
if (data != null)
onInflatedObjectData(obj, type, data);
addObjectAndTrack(obj);
- if (checkContentLater)
- deferredCheckBlobs.add(obj);
+
+ if (isCheckObjectCollisions()) {
+ collisionCheckObjs.add(obj);
+ }
}
- private void verifySafeObject(final AnyObjectId id, final int type,
- final byte[] data) throws IOException {
+ /**
+ * Verify the integrity of the object.
+ *
+ * @param id
+ * identity of the object to be checked.
+ * @param type
+ * the type of the object.
+ * @param data
+ * raw content of the object.
+ * @throws CorruptObjectException
+ * @since 4.9
+ *
+ */
+ protected void verifySafeObject(final AnyObjectId id, final int type,
+ final byte[] data) throws CorruptObjectException {
if (objCheck != null) {
try {
objCheck.check(id, type, data);
@@ -1075,65 +1095,73 @@
if (e.getErrorType() != null) {
throw e;
}
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().invalidObject,
- Constants.typeString(type),
- readCurs.abbreviate(id, 10).name(),
- e.getMessage()), e);
- }
- }
-
- if (isCheckObjectCollisions()) {
- try {
- final ObjectLoader ldr = readCurs.open(id, type);
- final byte[] existingData = ldr.getCachedBytes(data.length);
- if (!Arrays.equals(data, existingData)) {
- throw new IOException(MessageFormat.format(
- JGitText.get().collisionOn, id.name()));
- }
- } catch (MissingObjectException notLocal) {
- // This is OK, we don't have a copy of the object locally
- // but the API throws when we try to read it as usually its
- // an error to read something that doesn't exist.
+ throw new CorruptObjectException(
+ MessageFormat.format(JGitText.get().invalidObject,
+ Constants.typeString(type), id.name(),
+ e.getMessage()),
+ e);
}
}
}
- private void doDeferredCheckBlobs() throws IOException {
+ private void checkObjectCollision() throws IOException {
+ for (PackedObjectInfo obj : collisionCheckObjs) {
+ if (!readCurs.has(obj)) {
+ continue;
+ }
+ checkObjectCollision(obj);
+ }
+ }
+
+ private void checkObjectCollision(PackedObjectInfo obj)
+ throws IOException {
+ ObjectTypeAndSize info = openDatabase(obj, new ObjectTypeAndSize());
final byte[] readBuffer = buffer();
final byte[] curBuffer = new byte[readBuffer.length];
- ObjectTypeAndSize info = new ObjectTypeAndSize();
-
- for (PackedObjectInfo obj : deferredCheckBlobs) {
- info = openDatabase(obj, info);
-
- if (info.type != Constants.OBJ_BLOB)
+ long sz = info.size;
+ InputStream pck = null;
+ try (ObjectStream cur = readCurs.open(obj, info.type).openStream()) {
+ if (cur.getSize() != sz) {
throw new IOException(MessageFormat.format(
- JGitText.get().unknownObjectType,
- Integer.valueOf(info.type)));
-
- ObjectStream cur = readCurs.open(obj, info.type).openStream();
- try {
- long sz = info.size;
- if (cur.getSize() != sz)
- throw new IOException(MessageFormat.format(
- JGitText.get().collisionOn, obj.name()));
- InputStream pck = inflate(Source.DATABASE, sz);
- while (0 < sz) {
- int n = (int) Math.min(readBuffer.length, sz);
- IO.readFully(cur, curBuffer, 0, n);
- IO.readFully(pck, readBuffer, 0, n);
- for (int i = 0; i < n; i++) {
- if (curBuffer[i] != readBuffer[i])
- throw new IOException(MessageFormat.format(JGitText
- .get().collisionOn, obj.name()));
- }
- sz -= n;
- }
- pck.close();
- } finally {
- cur.close();
+ JGitText.get().collisionOn, obj.name()));
}
+ pck = inflate(Source.DATABASE, sz);
+ while (0 < sz) {
+ int n = (int) Math.min(readBuffer.length, sz);
+ IO.readFully(cur, curBuffer, 0, n);
+ IO.readFully(pck, readBuffer, 0, n);
+ for (int i = 0; i < n; i++) {
+ if (curBuffer[i] != readBuffer[i]) {
+ throw new IOException(MessageFormat.format(JGitText
+ .get().collisionOn, obj.name()));
+ }
+ }
+ sz -= n;
+ }
+ } catch (MissingObjectException notLocal) {
+ // This is OK, we don't have a copy of the object locally
+ // but the API throws when we try to read it as usually its
+ // an error to read something that doesn't exist.
+ } finally {
+ if (pck != null) {
+ pck.close();
+ }
+ }
+ }
+
+ private void checkObjectCollision(AnyObjectId obj, int type, byte[] data)
+ throws IOException {
+ try {
+ final ObjectLoader ldr = readCurs.open(obj, type);
+ final byte[] existingData = ldr.getCachedBytes(data.length);
+ if (!Arrays.equals(data, existingData)) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().collisionOn, obj.name()));
+ }
+ } catch (MissingObjectException notLocal) {
+ // This is OK, we don't have a copy of the object locally
+ // but the API throws when we try to read it as usually its
+ // an error to read something that doesn't exist.
}
}
@@ -1250,6 +1278,23 @@
}
/**
+ * Set the expected number of objects in the pack stream.
+ * <p>
+ * The object count in the pack header is not always correct for some Dfs
+ * pack files. e.g. INSERT pack always assume 1 object in the header since
+ * the actual object count is unknown when the pack is written.
+ * <p>
+ * If external implementation wants to overwrite the expectedObjectCount,
+ * they should call this method during {@link #onPackHeader(long)}.
+ *
+ * @param expectedObjectCount
+ * @since 4.9
+ */
+ protected void setExpectedObjectCount(long expectedObjectCount) {
+ this.expectedObjectCount = expectedObjectCount;
+ }
+
+ /**
* Store bytes received from the raw stream.
* <p>
* This method is invoked during {@link #parse(ProgressMonitor)} as data is
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
index 6da1c57..381c228 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
@@ -45,6 +45,7 @@
package org.eclipse.jgit.transport;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
/**
@@ -59,6 +60,8 @@
private int crc;
+ private int type = Constants.OBJ_BAD;
+
PackedObjectInfo(final long headerOffset, final int packedCRC,
final AnyObjectId id) {
super(id);
@@ -112,4 +115,24 @@
public void setCRC(final int crc) {
this.crc = crc;
}
+
+ /**
+ * @return the object type. The default type is OBJ_BAD, which is considered
+ * as unknown or invalid type.
+ * @since 4.9
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Record the object type if applicable.
+ *
+ * @param type
+ * the object type.
+ * @since 4.9
+ */
+ public void setType(int type) {
+ this.type = type;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
index 2b21c4a..14b35c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
@@ -52,6 +52,7 @@
import java.util.Collection;
import java.util.List;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
@@ -190,6 +191,20 @@
}
}
+ /**
+ * Check whether a command failed due to transaction aborted.
+ *
+ * @param cmd
+ * command.
+ * @return whether the command failed due to transaction aborted, as in {@link
+ * #abort(Iterable)}.
+ * @since 4.9
+ */
+ public static boolean isTransactionAborted(ReceiveCommand cmd) {
+ return cmd.getResult() == REJECTED_OTHER_REASON
+ && cmd.getMessage().equals(JGitText.get().transactionAborted);
+ }
+
private final ObjectId oldId;
private final ObjectId newId;
@@ -204,13 +219,19 @@
private String message;
+ private boolean customRefLog;
+
+ private String refLogMessage;
+
+ private boolean refLogIncludeResult;
+
private boolean typeIsCorrect;
/**
* Create a new command for {@link BaseReceivePack}.
*
* @param oldId
- * the old object id; must not be null. Use
+ * the expected old object id; must not be null. Use
* {@link ObjectId#zeroId()} to indicate a ref creation.
* @param newId
* the new object id; must not be null. Use
@@ -220,15 +241,23 @@
*/
public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
final String name) {
+ if (oldId == null) {
+ throw new IllegalArgumentException(JGitText.get().oldIdMustNotBeNull);
+ }
+ if (newId == null) {
+ throw new IllegalArgumentException(JGitText.get().newIdMustNotBeNull);
+ }
this.oldId = oldId;
this.newId = newId;
this.name = name;
type = Type.UPDATE;
- if (ObjectId.zeroId().equals(oldId))
+ if (ObjectId.zeroId().equals(oldId)) {
type = Type.CREATE;
- if (ObjectId.zeroId().equals(newId))
+ }
+ if (ObjectId.zeroId().equals(newId)) {
type = Type.DELETE;
+ }
}
/**
@@ -243,14 +272,45 @@
* @param name
* name of the ref being affected.
* @param type
- * type of the command.
+ * type of the command. Must be {@link Type#CREATE} if {@code
+ * oldId} is zero, or {@link Type#DELETE} if {@code newId} is zero.
* @since 2.0
*/
public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
final String name, final Type type) {
+ if (oldId == null) {
+ throw new IllegalArgumentException(JGitText.get().oldIdMustNotBeNull);
+ }
+ if (newId == null) {
+ throw new IllegalArgumentException(JGitText.get().newIdMustNotBeNull);
+ }
this.oldId = oldId;
this.newId = newId;
this.name = name;
+ switch (type) {
+ case CREATE:
+ if (!ObjectId.zeroId().equals(oldId)) {
+ throw new IllegalArgumentException(
+ JGitText.get().createRequiresZeroOldId);
+ }
+ break;
+ case DELETE:
+ if (!ObjectId.zeroId().equals(newId)) {
+ throw new IllegalArgumentException(
+ JGitText.get().deleteRequiresZeroNewId);
+ }
+ break;
+ case UPDATE:
+ case UPDATE_NONFASTFORWARD:
+ if (ObjectId.zeroId().equals(newId)
+ || ObjectId.zeroId().equals(oldId)) {
+ throw new IllegalArgumentException(
+ JGitText.get().updateRequiresOldIdAndNewId);
+ }
+ break;
+ default:
+ throw new IllegalStateException(JGitText.get().enumValueNotSupported0);
+ }
this.type = type;
}
@@ -290,6 +350,90 @@
}
/**
+ * Set the message to include in the reflog.
+ * <p>
+ * Overrides the default set by {@code setRefLogMessage} on any containing
+ * {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+ *
+ * @param msg
+ * the message to describe this change. If null and appendStatus is
+ * false, the reflog will not be updated.
+ * @param appendStatus
+ * true if the status of the ref change (fast-forward or
+ * forced-update) should be appended to the user supplied message.
+ * @since 4.9
+ */
+ public void setRefLogMessage(String msg, boolean appendStatus) {
+ customRefLog = true;
+ if (msg == null && !appendStatus) {
+ disableRefLog();
+ } else if (msg == null && appendStatus) {
+ refLogMessage = ""; //$NON-NLS-1$
+ refLogIncludeResult = true;
+ } else {
+ refLogMessage = msg;
+ refLogIncludeResult = appendStatus;
+ }
+ }
+
+ /**
+ * Don't record this update in the ref's associated reflog.
+ * <p>
+ * Equivalent to {@code setRefLogMessage(null, false)}.
+ *
+ * @since 4.9
+ */
+ public void disableRefLog() {
+ customRefLog = true;
+ refLogMessage = null;
+ refLogIncludeResult = false;
+ }
+
+ /**
+ * Check whether this command has a custom reflog setting that should override
+ * defaults in any containing {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+ *
+ * @return whether a custom reflog is set.
+ * @since 4.9
+ */
+ public boolean hasCustomRefLog() {
+ return customRefLog;
+ }
+
+ /**
+ * Check whether log has been disabled by {@link #disableRefLog()}.
+ *
+ * @return true if disabled.
+ * @since 4.9
+ */
+ public boolean isRefLogDisabled() {
+ return refLogMessage == null;
+ }
+
+ /**
+ * Get the message to include in the reflog.
+ *
+ * @return message the caller wants to include in the reflog; null if the
+ * update should not be logged.
+ * @since 4.9
+ */
+ @Nullable
+ public String getRefLogMessage() {
+ return refLogMessage;
+ }
+
+ /**
+ * Check whether the reflog message should include the result of the update,
+ * such as fast-forward or force-update.
+ *
+ * @return true if the message should include the result.
+ * @since 4.9
+ */
+ public boolean isRefLogIncludingResult() {
+ return refLogIncludeResult;
+ }
+
+ /**
* Set the status of this command.
*
* @param s
@@ -355,6 +499,7 @@
try {
final RefUpdate ru = rp.getRepository().updateRef(getRefName());
ru.setRefLogIdent(rp.getRefLogIdent());
+ ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
switch (getType()) {
case DELETE:
if (!ObjectId.zeroId().equals(getOldId())) {
@@ -428,6 +573,14 @@
setResult(Result.REJECTED_CURRENT_BRANCH);
break;
+ case REJECTED_MISSING_OBJECT:
+ setResult(Result.REJECTED_MISSING_OBJECT);
+ break;
+
+ case REJECTED_OTHER_REASON:
+ setResult(Result.REJECTED_OTHER_REASON);
+ break;
+
default:
setResult(Result.REJECTED_OTHER_REASON, r.name());
break;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
index 5a73cf5..d6a2fe6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
@@ -83,4 +83,4 @@
* Disconnect the remote session
*/
public void disconnect();
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 2198b50..d4cd1c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -76,8 +76,24 @@
}
};
- enum FsckMode {
- ERROR, WARN, IGNORE;
+ /**
+ * A git configuration value for how to handle a fsck failure of a particular kind.
+ * Used in e.g. fsck.missingEmail.
+ * @since 4.9
+ */
+ public enum FsckMode {
+ /**
+ * Treat it as an error (the default).
+ */
+ ERROR,
+ /**
+ * Issue a warning (in fact, jgit treats this like IGNORE, but git itself does warn).
+ */
+ WARN,
+ /**
+ * Ignore the error.
+ */
+ IGNORE;
}
private final boolean fetchFsck;
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 ddb2fbf..17af0b9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -1523,7 +1523,7 @@
walk.reset();
ObjectWalk ow = rw.toObjectWalkWithSameObjects();
- pw.preparePack(pm, ow, wantAll, commonBase);
+ pw.preparePack(pm, ow, wantAll, commonBase, PackWriter.NONE);
rw = ow;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
index 1719416..2ea8228 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilter.java
@@ -102,4 +102,4 @@
public String toString() {
return "INTERINDEX_DIFF"; //$NON-NLS-1$
}
-}
\ No newline at end of file
+}
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 229355c..1cc39bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -497,7 +497,13 @@
if (env != null) {
pb.environment().putAll(env);
}
- Process p = pb.start();
+ Process p;
+ try {
+ p = pb.start();
+ } catch (IOException e) {
+ // Process failed to start
+ throw new CommandFailedException(-1, e.getMessage(), e);
+ }
p.getOutputStream().close();
GobblerThread gobbler = new GobblerThread(p, command, dir);
gobbler.start();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
index 658dd06..0a3c846 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
@@ -71,6 +71,21 @@
}
/**
+ * Check if an entry appears in this collection.
+ *
+ * @param value
+ * the value to search for.
+ * @return true of {@code value} appears in this list.
+ * @since 4.9
+ */
+ public boolean contains(int value) {
+ for (int i = 0; i < count; i++)
+ if (entries[i] == value)
+ return true;
+ return false;
+ }
+
+ /**
* @param i
* index to read, must be in the range [0, {@link #size()}).
* @return the number at the specified index
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
index 1597817..ce4b7c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
@@ -338,10 +338,11 @@
* Create an empty list with at least the specified capacity.
*
* @param capacity
- * the new capacity.
+ * the new capacity; if zero or negative, behavior is the same as
+ * {@link #Builder()}.
*/
public Builder(int capacity) {
- list = new Ref[capacity];
+ list = new Ref[Math.max(capacity, 16)];
}
/** @return number of items in this builder's internal collection. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
index 3cb3749..21a55a6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
@@ -140,4 +140,4 @@
long rounded = (n + unit / 2) / unit;
return rounded;
}
-}
\ No newline at end of file
+}
diff --git a/pom.xml b/pom.xml
index b26af96..3e6c55b 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.8.0-SNAPSHOT</version>
+ <version>4.9.0-SNAPSHOT</version>
<name>JGit - Parent</name>
<url>${jgit-url}</url>
@@ -70,6 +70,10 @@
<connection>scm:git:https://git.eclipse.org/r/jgit/jgit</connection>
</scm>
+ <prerequisites>
+ <maven>3.3.1</maven>
+ </prerequisites>
+
<ciManagement>
<system>hudson</system>
<url>https://hudson.eclipse.org/jgit/</url>
@@ -200,15 +204,15 @@
<commons-compress-version>1.6</commons-compress-version>
<osgi-core-version>4.3.1</osgi-core-version>
<servlet-api-version>3.1.0</servlet-api-version>
- <jetty-version>9.3.17.v20170317</jetty-version>
- <japicmp-version>0.8.1</japicmp-version>
+ <jetty-version>9.4.5.v20170502</jetty-version>
+ <japicmp-version>0.10.0</japicmp-version>
<httpclient-version>4.3.6</httpclient-version>
<slf4j-version>1.7.2</slf4j-version>
<log4j-version>1.2.15</log4j-version>
<maven-javadoc-plugin-version>2.10.4</maven-javadoc-plugin-version>
<tycho-extras-version>1.0.0</tycho-extras-version>
<gson-version>2.2.4</gson-version>
- <findbugs-maven-plugin-version>3.0.4</findbugs-maven-plugin-version>
+ <spotbugs-maven-plugin-version>3.0.6</spotbugs-maven-plugin-version>
<maven-surefire-report-plugin-version>2.20</maven-surefire-report-plugin-version>
<!-- Properties to enable jacoco code coverage analysis -->
@@ -367,9 +371,9 @@
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
- <version>${findbugs-maven-plugin-version}</version>
+ <groupId>com.github.hazendaz.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>${spotbugs-maven-plugin-version}</version>
<configuration>
<findbugsXmlOutput>true</findbugsXmlOutput>
<failOnError>false</failOnError>
@@ -386,7 +390,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
- <version>3.7</version>
+ <version>3.8</version>
<configuration>
<sourceEncoding>utf-8</sourceEncoding>
<minimumTokens>100</minimumTokens>
@@ -575,9 +579,9 @@
<version>2.5</version>
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
- <version>${findbugs-maven-plugin-version}</version>
+ <groupId>com.github.hazendaz.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>${spotbugs-maven-plugin-version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -747,8 +751,8 @@
<build>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>findbugs-maven-plugin</artifactId>
+ <groupId>com.github.hazendaz.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>